diff --git a/DEPS b/DEPS index d28c9b0..8567ffa 100644 --- a/DEPS +++ b/DEPS
@@ -253,19 +253,19 @@ # 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': '43557a6d5535b98fefdbbd6ee5687339b900bfdc', + 'skia_revision': '02ea811ce869e8d535bbc117269ba7cad50c0345', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': 'c25a4438c6ac726f8d381a0b02dfe2468410e9ac', + 'v8_revision': '34f5fc47b8fd5d9b482cb438640dbefd477f0bb0', # 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': '09b55fbe98b4d8b32c658fc4d46643dc63137dd6', + 'angle_revision': 'af2e0c01f0664fdbc01d376dc690b22f1bb01b34', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. - 'swiftshader_revision': 'e3d910c94d3334bf47319e0bc2f8d48f16063e42', + 'swiftshader_revision': 'd43f39b388368a303d0202e4042d6b03eab8bc90', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. @@ -328,7 +328,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling devtools-frontend # and whatever else without interference from each other. - 'devtools_frontend_revision': '8363c28e524789a6cdffd79742f6f23694df1ab8', + 'devtools_frontend_revision': '376ee761fb9b925bcc997e1387bdca2e34cb4803', # 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. @@ -368,7 +368,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'dawn_revision': '44beca5b50c41fbbfe83a5a8a23f8ab813a6cf00', + 'dawn_revision': '822672d7d33672781001de309927be5038257d47', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -435,7 +435,7 @@ 'libcxx_revision': '79a2e924d96e2fc1e4b937c42efd08898fa472d7', # GN CIPD package version. - 'gn_version': 'git_revision:4ffb87ad613d822e47ca1e21f9d832055ef95891', + 'gn_version': 'git_revision:f27bae882b2178ccc3c24f314c88db9a34118992', } # Only these hosts are allowed for dependencies in this DEPS file. @@ -809,7 +809,7 @@ 'packages': [ { 'package': 'chromium/rts/model/linux-amd64', - 'version': 'pUqxy9zXMBwoo81TKeO2-d1hB74vdYX9MBykPg0ugXgC', + 'version': 'Cs36UbjGlF-44XDMgKBSc79RKl1DXvsK87SixSKQkk8C', }, ], 'dep_type': 'cipd', @@ -820,7 +820,7 @@ 'packages': [ { 'package': 'chromium/rts/model/mac-amd64', - 'version': 'WszkX4gVkckQFUQqrvQcRL7seb3v95GTyAE8cg-Mm98C', + 'version': '3P9zHykqgezNmEyT1p4jPJaH5DnZNw7qWdYl0zIXTFoC', }, ], 'dep_type': 'cipd', @@ -831,7 +831,7 @@ 'packages': [ { 'package': 'chromium/rts/model/windows-amd64', - 'version': 'PNlh8yQxc1R4aBY5_hoQGsHRJFcFKhk2uSexCq8ZNNIC', + 'version': '1xnqxY0HxsLuxzYbBketQJLD_ARSLgGtjNE4V2K9IDgC', }, ], 'dep_type': 'cipd', @@ -892,7 +892,7 @@ 'packages': [ { 'package': 'chromium/third_party/androidx', - 'version': 'Au8GY56lt8eqtp-di9ooOGsOQprr7zRtGIq2kozVfMcC', + 'version': 'EggJgyI0ja1HtThYH24KsjyfGghSO9o623ONeM4pynIC', }, ], 'condition': 'checkout_android', @@ -932,17 +932,6 @@ 'dep_type': 'cipd', }, - 'src/third_party/android_build_tools/art': { - 'packages': [ - { - 'package': 'chromium/third_party/android_build_tools/art', - 'version': '87169fbc701d244c311e6aa8843591a7f1710bc0', - }, - ], - 'condition': 'checkout_android', - 'dep_type': 'cipd', - }, - 'src/third_party/android_build_tools/bundletool': { 'packages': [ { @@ -1111,7 +1100,7 @@ # Tools used when building Chrome for Chrome OS. This affects both the Simple # Chrome workflow, as well as the chromeos-chrome ebuild. 'src/third_party/chromite': { - 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'e28537f55f1ef2a336513fd94f5c1fd19dfbfe8e', + 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'a032e6c91c727c9d91cdbd6de4fbf6f9e4ea8f04', 'condition': 'checkout_chromeos', }, @@ -1131,7 +1120,7 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '4ca9e1c783b8fa9c8ca39edfcded3028dc7f3e1b', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '1909696991d3e1e689d6d8815bb44fb327527d52', 'src/third_party/devtools-frontend/src': Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), @@ -1592,7 +1581,7 @@ 'packages': [ { 'package': 'fuchsia/third_party/android/aemu/release/linux-amd64', - 'version': '8CsLSLrKIFVCEVTplLND7Rm6k5N-AprYuOSHOINGFdAC' + 'version': 'KZmkd_OKt4CGYzJ1Pwhezx0gCj34wFaldQthjcTArrsC' }, ], 'condition': 'host_os == "linux" and checkout_fuchsia', @@ -1735,7 +1724,7 @@ Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '2860185ed0581ee6b884dfb727a42e82b8b7e7a5', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '03fad386d528822209d084982f58e4fef2519a8b', + Var('webrtc_git') + '/src.git' + '@' + '870ffe74431fb7807453b487011ffd9b6041c739', 'src/third_party/libgifcodec': Var('skia_git') + '/libgifcodec' + '@'+ Var('libgifcodec_revision'), @@ -1805,7 +1794,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@fec9f117f22bd3a18af5c57187396839baee30dd', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@1e2d6d2ec338ad0c2fc2e4ad0ca40bd81e7d7d14', 'condition': 'checkout_src_internal', }, @@ -1835,7 +1824,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/help_app/app', - 'version': 'uDiwkMVyC10EnEMl-8utZEAytrhGGEFQfbLQUxZAHf8C', + 'version': 'UzIHRVp1xEmVQ_5D-Cc6C5j9UinQU7sURRSiZ8SjbEIC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -1846,7 +1835,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/media_app/app', - 'version': 'CflU0D-lTnJJZHRRU9GMM_-hzlNZnSXInx3sci0HjsQC', + 'version': 'MLOomNW7tNEjnsV1u2jKRURIup5kDXE9Bpjw68zETSUC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/android_webview/browser/aw_contents_io_thread_client.cc b/android_webview/browser/aw_contents_io_thread_client.cc index 4cc4e9dd..c4f9f6c 100644 --- a/android_webview/browser/aw_contents_io_thread_client.cc +++ b/android_webview/browser/aw_contents_io_thread_client.cc
@@ -35,6 +35,7 @@ #include "content/public/browser/web_contents_observer.h" #include "net/base/data_url.h" #include "services/network/public/cpp/resource_request.h" +#include "third_party/abseil-cpp/absl/types/optional.h" using base::LazyInstance; using base::android::AttachCurrentThread; @@ -53,20 +54,11 @@ namespace { -struct IoThreadClientData { - bool pending_association; - JavaObjectWeakGlobalRef io_thread_client; +typedef map<content::GlobalRenderFrameHostId, JavaObjectWeakGlobalRef> + RenderFrameHostToWeakGlobalRefType; - IoThreadClientData(); -}; - -IoThreadClientData::IoThreadClientData() : pending_association(false) {} - -typedef map<content::GlobalRenderFrameHostId, IoThreadClientData> - RenderFrameHostToIoThreadClientType; - -typedef pair<base::flat_set<RenderFrameHost*>, IoThreadClientData> - HostsAndClientDataPair; +typedef pair<base::flat_set<RenderFrameHost*>, JavaObjectWeakGlobalRef> + HostsAndWeakGlobalRefPair; // When browser side navigation is enabled, RenderFrameIDs do not have // valid render process host and render frame ids for frame navigations. @@ -74,30 +66,31 @@ // to keep track of which RenderFrameHosts are associated with each // FrameTreeNodeId, so we know when the last RenderFrameHost is deleted (and // therefore the FrameTreeNodeId should be removed). -typedef map<int, HostsAndClientDataPair> FrameTreeNodeToIoThreadClientType; +typedef map<int, HostsAndWeakGlobalRefPair> FrameTreeNodeToWeakGlobalRefType; // RfhToIoThreadClientMap ----------------------------------------------------- class RfhToIoThreadClientMap { public: static RfhToIoThreadClientMap* GetInstance(); void Set(content::GlobalRenderFrameHostId rfh_id, - const IoThreadClientData& client); - bool Get(content::GlobalRenderFrameHostId rfh_id, IoThreadClientData* client); + const JavaObjectWeakGlobalRef& client); + absl::optional<JavaObjectWeakGlobalRef> Get( + content::GlobalRenderFrameHostId rfh_id); - bool Get(int frame_tree_node_id, IoThreadClientData* client); + absl::optional<JavaObjectWeakGlobalRef> Get(int frame_tree_node_id); // Prefer to call these when RenderFrameHost* is available, because they // update both maps at the same time. - void Set(RenderFrameHost* rfh, const IoThreadClientData& client); + void Set(RenderFrameHost* rfh, const JavaObjectWeakGlobalRef& client); void Erase(RenderFrameHost* rfh); private: base::Lock map_lock_; // We maintain two maps simultaneously so that we can always get the correct - // IoThreadClientData, even when only HostIdPair or FrameTreeNodeId is + // JavaObjectWeakGlobalRef, even when only HostIdPair or FrameTreeNodeId is // available. - RenderFrameHostToIoThreadClientType rfh_to_io_thread_client_; - FrameTreeNodeToIoThreadClientType frame_tree_node_to_io_thread_client_; + RenderFrameHostToWeakGlobalRefType rfh_to_weak_global_ref_; + FrameTreeNodeToWeakGlobalRefType frame_tree_node_to_weak_global_ref_; }; // static @@ -114,72 +107,73 @@ } void RfhToIoThreadClientMap::Set(content::GlobalRenderFrameHostId rfh_id, - const IoThreadClientData& client) { + const JavaObjectWeakGlobalRef& client) { base::AutoLock lock(map_lock_); - rfh_to_io_thread_client_[rfh_id] = client; + rfh_to_weak_global_ref_[rfh_id] = client; } -bool RfhToIoThreadClientMap::Get(content::GlobalRenderFrameHostId rfh_id, - IoThreadClientData* client) { +absl::optional<JavaObjectWeakGlobalRef> RfhToIoThreadClientMap::Get( + content::GlobalRenderFrameHostId rfh_id) { base::AutoLock lock(map_lock_); - RenderFrameHostToIoThreadClientType::iterator iterator = - rfh_to_io_thread_client_.find(rfh_id); - if (iterator == rfh_to_io_thread_client_.end()) - return false; - - *client = iterator->second; - return true; + RenderFrameHostToWeakGlobalRefType::iterator iterator = + rfh_to_weak_global_ref_.find(rfh_id); + if (iterator == rfh_to_weak_global_ref_.end()) { + return absl::nullopt; + } else { + return iterator->second; + } } -bool RfhToIoThreadClientMap::Get(int frame_tree_node_id, - IoThreadClientData* client) { +absl::optional<JavaObjectWeakGlobalRef> RfhToIoThreadClientMap::Get( + int frame_tree_node_id) { base::AutoLock lock(map_lock_); - FrameTreeNodeToIoThreadClientType::iterator iterator = - frame_tree_node_to_io_thread_client_.find(frame_tree_node_id); - if (iterator == frame_tree_node_to_io_thread_client_.end()) - return false; - - *client = iterator->second.second; - return true; + FrameTreeNodeToWeakGlobalRefType::iterator iterator = + frame_tree_node_to_weak_global_ref_.find(frame_tree_node_id); + if (iterator == frame_tree_node_to_weak_global_ref_.end()) { + return absl::nullopt; + } else { + return iterator->second.second; + } } void RfhToIoThreadClientMap::Set(RenderFrameHost* rfh, - const IoThreadClientData& client) { + const JavaObjectWeakGlobalRef& client) { int frame_tree_node_id = rfh->GetFrameTreeNodeId(); content::GlobalRenderFrameHostId rfh_id = rfh->GetGlobalId(); base::AutoLock lock(map_lock_); - // If this FrameTreeNodeId already has an associated IoThreadClientData, add - // this RenderFrameHost to the hosts set (it's harmless to overwrite the - // IoThreadClientData). Otherwise, operator[] creates a new map entry and we - // add this RenderFrameHost to the hosts set and insert |client| in the pair. - HostsAndClientDataPair& current_entry = - frame_tree_node_to_io_thread_client_[frame_tree_node_id]; + // If this FrameTreeNodeId already has an associated JavaObjectWeakGlobalRef, + // add this RenderFrameHost to the hosts set (it's harmless to overwrite the + // JavaObjectWeakGlobalRef). Otherwise, operator[] creates a new map entry and + // we add this RenderFrameHost to the hosts set and insert |client| in the + // pair. + HostsAndWeakGlobalRefPair& current_entry = + frame_tree_node_to_weak_global_ref_[frame_tree_node_id]; current_entry.second = client; current_entry.first.insert(rfh); // Always add the entry to the HostIdPair map, since entries are 1:1 with // RenderFrameHosts. - rfh_to_io_thread_client_[rfh_id] = client; + rfh_to_weak_global_ref_[rfh_id] = client; } void RfhToIoThreadClientMap::Erase(RenderFrameHost* rfh) { int frame_tree_node_id = rfh->GetFrameTreeNodeId(); content::GlobalRenderFrameHostId rfh_id = rfh->GetGlobalId(); base::AutoLock lock(map_lock_); - HostsAndClientDataPair& current_entry = - frame_tree_node_to_io_thread_client_[frame_tree_node_id]; + HostsAndWeakGlobalRefPair& current_entry = + frame_tree_node_to_weak_global_ref_[frame_tree_node_id]; size_t num_erased = current_entry.first.erase(rfh); DCHECK(num_erased == 1); // Only remove this entry from the FrameTreeNodeId map if there are no more // live RenderFrameHosts. if (current_entry.first.empty()) { - frame_tree_node_to_io_thread_client_.erase(frame_tree_node_id); + frame_tree_node_to_weak_global_ref_.erase(frame_tree_node_id); } // Always safe to remove the entry from the HostIdPair map, since entries are // 1:1 with RenderFrameHosts. - rfh_to_io_thread_client_.erase(rfh_id); + rfh_to_weak_global_ref_.erase(rfh_id); } // ClientMapEntryUpdater ------------------------------------------------------ @@ -210,10 +204,7 @@ } void ClientMapEntryUpdater::RenderFrameCreated(RenderFrameHost* rfh) { - IoThreadClientData client_data; - client_data.io_thread_client = jdelegate_; - client_data.pending_association = false; - RfhToIoThreadClientMap::GetInstance()->Set(rfh, client_data); + RfhToIoThreadClientMap::GetInstance()->Set(rfh, jdelegate_); } void ClientMapEntryUpdater::RenderFrameDeleted(RenderFrameHost* rfh) { @@ -229,15 +220,15 @@ // AwContentsIoThreadClient ----------------------------------------------- // static -std::unique_ptr<AwContentsIoThreadClient> AwContentsIoThreadClient::FromID( - content::GlobalRenderFrameHostId render_frame_host_id) { - IoThreadClientData client_data; - bool found = RfhToIoThreadClientMap::GetInstance()->Get(render_frame_host_id, - &client_data); - if (found) { +// Wrap an optional |JavaObjectWeakGlobalRef| to a Java +// |AwContentsIoThreadClient| in a native |AwContentsIoThreadClient| by getting +// a scoped local reference. This will return |nullptr| if either the optional +// is empty or the weak reference has already expired. +std::unique_ptr<AwContentsIoThreadClient> WrapOptionalWeakRef( + absl::optional<JavaObjectWeakGlobalRef> opt_delegate_weak_ref) { + if (opt_delegate_weak_ref) { JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef<jobject> java_delegate = - client_data.io_thread_client.get(env); + ScopedJavaLocalRef<jobject> java_delegate = opt_delegate_weak_ref->get(env); if (java_delegate) { return std::make_unique<AwContentsIoThreadClient>(java_delegate); } @@ -245,20 +236,17 @@ return nullptr; } +// static +std::unique_ptr<AwContentsIoThreadClient> AwContentsIoThreadClient::FromID( + content::GlobalRenderFrameHostId render_frame_host_id) { + return WrapOptionalWeakRef( + RfhToIoThreadClientMap::GetInstance()->Get(render_frame_host_id)); +} + std::unique_ptr<AwContentsIoThreadClient> AwContentsIoThreadClient::FromID( int frame_tree_node_id) { - IoThreadClientData client_data; - bool found = RfhToIoThreadClientMap::GetInstance()->Get(frame_tree_node_id, - &client_data); - if (found) { - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef<jobject> java_delegate = - client_data.io_thread_client.get(env); - if (java_delegate) { - return std::make_unique<AwContentsIoThreadClient>(java_delegate); - } - } - return nullptr; + return WrapOptionalWeakRef( + RfhToIoThreadClientMap::GetInstance()->Get(frame_tree_node_id)); } // static @@ -269,26 +257,17 @@ parent_render_frame_id); content::GlobalRenderFrameHostId child_rfh_id(render_process_id, child_render_frame_id); - IoThreadClientData client_data; - if (!RfhToIoThreadClientMap::GetInstance()->Get(parent_rfh_id, - &client_data)) { + RfhToIoThreadClientMap* map = RfhToIoThreadClientMap::GetInstance(); + absl::optional<JavaObjectWeakGlobalRef> opt_delegate_weak_ref = + map->Get(parent_rfh_id); + if (opt_delegate_weak_ref) { + map->Set(child_rfh_id, opt_delegate_weak_ref.value()); + } else { // It is possible to not find a mapping for the parent rfh_id if the WebView // is in the process of being destroyed, and the mapping has already been // erased. LOG(WARNING) << "No IoThreadClient associated with parent RenderFrameHost."; - return; } - - RfhToIoThreadClientMap::GetInstance()->Set(child_rfh_id, client_data); -} - -// static -void AwContentsIoThreadClient::RegisterPendingContents( - WebContents* web_contents) { - IoThreadClientData client_data; - client_data.pending_association = true; - RfhToIoThreadClientMap::GetInstance()->Set( - web_contents->GetMainFrame()->GetGlobalId(), client_data); } // static @@ -313,13 +292,7 @@ // static std::unique_ptr<AwContentsIoThreadClient> AwContentsIoThreadClient::GetServiceWorkerIoThreadClient() { - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef<jobject> java_delegate = g_sw_instance_.Get().get(env); - - if (!java_delegate) - return nullptr; - - return std::make_unique<AwContentsIoThreadClient>(java_delegate); + return WrapOptionalWeakRef(absl::make_optional(g_sw_instance_.Get())); } AwContentsIoThreadClient::AwContentsIoThreadClient(const JavaRef<jobject>& obj)
diff --git a/android_webview/browser/aw_contents_io_thread_client.h b/android_webview/browser/aw_contents_io_thread_client.h index c7fa2acb..8202377d 100644 --- a/android_webview/browser/aw_contents_io_thread_client.h +++ b/android_webview/browser/aw_contents_io_thread_client.h
@@ -53,9 +53,6 @@ LOAD_CACHE_ONLY = 3, }; - // Called when AwContents is created before there is a Java client. - static void RegisterPendingContents(content::WebContents* web_contents); - // Associates the |jclient| instance (which must implement the // AwContentsIoThreadClient Java interface) with the |web_contents|. // This should be called at most once per |web_contents|.
diff --git a/android_webview/browser/aw_web_contents_delegate.cc b/android_webview/browser/aw_web_contents_delegate.cc index 075971e..53a172a 100644 --- a/android_webview/browser/aw_web_contents_delegate.cc +++ b/android_webview/browser/aw_web_contents_delegate.cc
@@ -210,7 +210,7 @@ const std::string& frame_name, const GURL& target_url, content::WebContents* new_contents) { - AwContentsIoThreadClient::RegisterPendingContents(new_contents); + // Intentionally left empty to override implementation in superclasses. } void AwWebContentsDelegate::CloseContents(WebContents* source) {
diff --git a/android_webview/docs/device-setup.md b/android_webview/docs/device-setup.md index 9a9b2c3..638e4b6 100644 --- a/android_webview/docs/device-setup.md +++ b/android_webview/docs/device-setup.md
@@ -115,7 +115,7 @@ `monochrome_{public_}apk`, this is not a valid WebView provider. Unlike on `userdebug`/`eng` images, the WebView update service performs additional signature checks on `user` images, only loading code that has been signed by - one of the expected signatures—as above, these keys are not available + one of the expected signatures—as above, these keys are not available for local builds. Both of the above are important security features: these protect users from
diff --git a/android_webview/docs/java-bridge.md b/android_webview/docs/java-bridge.md index 6d3efef..9929812b 100644 --- a/android_webview/docs/java-bridge.md +++ b/android_webview/docs/java-bridge.md
@@ -58,7 +58,7 @@ The purpose of Java bridge is to establish interaction between two virtual machines (VMs): Java and JavaScript. Both VMs employ a similar approach to -managing objects lifetime -- VMs gather and dispose unreferenced objects during +managing objects lifetime—VMs gather and dispose unreferenced objects during garbage collection (GC) cycles. The twist that Java bridge adds is that objects in one VM can now virtually reference (and prevent from being disposed) objects from another VM. Let us consider the following Java code: @@ -221,8 +221,8 @@ When coercing JavaScript "array-like" objects into Java arrays, only indexed properties are preserved, and named properties are shaved off. Also, passing an -arbitrary JavaScript dictionary object via an interface method is impossible -- -it is simply converted into 0, "", or null (depending on the destination Java +arbitrary JavaScript dictionary object via an interface method is impossible—it +is simply converted into 0, "", or null (depending on the destination Java type). For dealing with method overloading, the spec proposes a cost-based model for @@ -266,7 +266,7 @@ of injected objects. In accordance with the API definition, methods are invoked on a dedicated thread maintained by WebView. -Calls to interface methods are synchronous -- JavaScript VM stops and waits for +Calls to interface methods are synchronous—JavaScript VM stops and waits for a result to be returned from the invoked method. In Chromium, this means that the IPC message sent from a renderer to the browser must be synchronous (such messages are in fact rarely used in Chromium).
diff --git a/android_webview/docs/webview-shell.md b/android_webview/docs/webview-shell.md index 6611f30..db0a218 100644 --- a/android_webview/docs/webview-shell.md +++ b/android_webview/docs/webview-shell.md
@@ -4,8 +4,8 @@  -WebView team maintains a "shell"—a thin interface over the WebView -APIs—to exercise WebView functionality. The System WebView Shell (AKA +WebView team maintains a "shell"—a thin interface over the WebView +APIs—to exercise WebView functionality. The System WebView Shell (AKA "shell browser," "WebView shell") is a standalone app implemented [in chromium](/android_webview/tools/system_webview_shell/). While often used for manual testing, we also use the shell for automated tests (see our [layout and
diff --git a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java index cb4c0e8..6506d4c 100644 --- a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java +++ b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
@@ -106,6 +106,8 @@ "Avoid extra copy for video frames when possible"), Flag.baseFeature(GpuFeatures.WEBVIEW_THREAD_SAFE_MEDIA, "Use thread-safe media path, requires Android P."), + Flag.baseFeature(VizFeatures.WEBVIEW_NEW_INVALIDATE_HEURISTIC, + "More robust heuristic for calling Invalidate"), Flag.baseFeature( VizFeatures.WEBVIEW_VULKAN_INTERMEDIATE_BUFFER, "For debugging vulkan"), Flag.baseFeature(
diff --git a/ash/ambient/ambient_photo_cache.h b/ash/ambient/ambient_photo_cache.h index 289d49f..7be46577 100644 --- a/ash/ambient/ambient_photo_cache.h +++ b/ash/ambient/ambient_photo_cache.h
@@ -58,13 +58,13 @@ // Write photo cache to disk at |cache_index| and call |callback| when // complete. virtual void WritePhotoCache(int cache_index, - const ambient::PhotoCacheEntry& cache_entry, + const ::ambient::PhotoCacheEntry& cache_entry, base::OnceClosure callback) = 0; // Read the photo cache at |cache_index| and call |callback| when complete. // If a particular cache fails to be read, |cache_entry| will be empty. virtual void ReadPhotoCache(int cache_index, - ambient::PhotoCacheEntry* cache_entry, + ::ambient::PhotoCacheEntry* cache_entry, base::OnceCallback<void()> callback) = 0; // Erase all stored files from disk.
diff --git a/ash/ambient/ambient_photo_controller.h b/ash/ambient/ambient_photo_controller.h index e3368ca..48f1599 100644 --- a/ash/ambient/ambient_photo_controller.h +++ b/ash/ambient/ambient_photo_controller.h
@@ -334,7 +334,7 @@ scoped_refptr<base::SequencedTaskRunner> task_runner_; // Temporary data store when fetching images and details. - ambient::PhotoCacheEntry cache_entry_; + ::ambient::PhotoCacheEntry cache_entry_; gfx::ImageSkia image_; gfx::ImageSkia related_image_;
diff --git a/ash/ambient/model/ambient_animation_attribution_provider.cc b/ash/ambient/model/ambient_animation_attribution_provider.cc index c42464c..78e2575 100644 --- a/ash/ambient/model/ambient_animation_attribution_provider.cc +++ b/ash/ambient/model/ambient_animation_attribution_provider.cc
@@ -63,39 +63,50 @@ // 1) The dynamic image assets and attribution text nodes in an animation are // identified by 2 different sets of strings. Ex: // Dynamic image asset ids: -// * "CrOS_AssetId1" -// * "CrOS_AssetId2" +// * "_CrOS_Photo_PositionA_1" +// * "_CrOS_Photo_PositionB_1" // ... -// * "CrOS_AssetIdN" +// * "_CrOS_Photo_Position<P>_N" // Attribution text node names: -// * "CrOS_AttributionNode1" -// * "CrOS_AttributionNode2" +// * "_CrOS_AttributionText1" +// * "_CrOS_AttributionText2" // ... -// * "CrOS_AttributionNodeN" -// Each attribution text node should be assigned the attribution of the -// dynamic image asset who shares the same "index". "CrOS_AttributionNode1" -// is assigned the attribution for "CrOS_AssetId1", "CrOS_AttributionNode2" -// is assigned the attribution for "CrOS_AssetId2", and so on. This is easily -// accomplished by sorting the asset ids and attribution nodes as strings -// first, then iterating through them simultaneously when assigning. That is -// why |new_topics| is a flat_map (whose keys are inherently sorted), and -// GetAttributionNodeIds() returns the attribution node ids sorted by their -// string names. +// * "_CrOS_AttributionTextN" +// +// To assign an image asset to an attribution text node, sort the +// asset ids by index first and position second (this is taken care of +// already by ParsedDynamicAssetId's comparison operator and the use of +// a sorted base::flat_map for |new_topics| below): +// 1) "_CrOS_Photo_PositionA_1" (Index 1 Position A) +// 2) "_CrOS_Photo_PositionB_1" (Index 1 Position B) +// 3) "_CrOS_Photo_PositionA_2" (Index 2 Position A) +// 4) "_CrOS_Photo_PositionB_2" (Index 2 Position B) +// +// And sort the attribution text nodes by their name: +// 1) "_CrOS_AttributionText1" +// 2) "_CrOS_AttributionText2" +// 3) "_CrOS_AttributionText3" +// 4) "_CrOS_AttributionText4" +// +// Afterwards, assign sorted asset <i> to sorted attribution node <i>. Note +// the animation is allowed to have fewer attribution nodes than dynamic +// image assets. In this case, the dynamic image assets left without a +// corresponding attribution text node are just ignored by design. // // 2) If a photo has no attribution (an empty string), just set its // corresponding text node to be blank (an empty string). This is a // corner case though. In practice, either all of the photos in the set // should have an associated attribution, or none do. void AmbientAnimationAttributionProvider::OnDynamicImageAssetsRefreshed( - const base::flat_map</*asset_id*/ std::string, + const base::flat_map<ambient::util::ParsedDynamicAssetId, std::reference_wrapper<const PhotoWithDetails>>& new_topics) { - DCHECK_EQ(new_topics.size(), attribution_node_ids_.size()) - << "All ambient-mode animations should have an equal number of text " - "attribution nodes and dynamic image assets."; + DCHECK_GE(new_topics.size(), attribution_node_ids_.size()) + << "All ambient-mode animations should have at least as many dynamic " + "image assets as text attribution nodes."; auto new_topics_iter = new_topics.begin(); auto attribution_node_ids_iter = attribution_node_ids_.begin(); - for (; new_topics_iter != new_topics.end(); + for (; attribution_node_ids_iter != attribution_node_ids_.end(); ++new_topics_iter, ++attribution_node_ids_iter) { const std::string& attribution_text = new_topics_iter->second.get().details; cc::SkottieResourceIdHash attribution_node_id = *attribution_node_ids_iter;
diff --git a/ash/ambient/model/ambient_animation_attribution_provider.h b/ash/ambient/model/ambient_animation_attribution_provider.h index dfaf4161..e9c92834 100644 --- a/ash/ambient/model/ambient_animation_attribution_provider.h +++ b/ash/ambient/model/ambient_animation_attribution_provider.h
@@ -38,7 +38,7 @@ // AmbientAnimationPhotoProvider::Observer implementation: void OnDynamicImageAssetsRefreshed( - const base::flat_map</*asset_id*/ std::string, + const base::flat_map<ambient::util::ParsedDynamicAssetId, std::reference_wrapper<const PhotoWithDetails>>& new_topics) override;
diff --git a/ash/ambient/model/ambient_animation_attribution_provider_unittest.cc b/ash/ambient/model/ambient_animation_attribution_provider_unittest.cc index eb8b236..fde94cdcf 100644 --- a/ash/ambient/model/ambient_animation_attribution_provider_unittest.cc +++ b/ash/ambient/model/ambient_animation_attribution_provider_unittest.cc
@@ -71,22 +71,27 @@ absl::optional<std::string> asset_1_attribution) { gfx::ImageSkia test_image = gfx::test::CreateImageSkia(/*width=*/10, /*height=*/10); - base::flat_map</*asset_id*/ std::string, + base::flat_map<ambient::util::ParsedDynamicAssetId, std::reference_wrapper<const PhotoWithDetails>> new_topics; + ambient::util::ParsedDynamicAssetId parsed_asset_id; PhotoWithDetails topic_0; if (asset_0_attribution) { + CHECK(ambient::util::ParseDynamicLottieAssetId(asset_id_0_, + parsed_asset_id)); topic_0.photo = test_image; topic_0.details = std::move(*asset_0_attribution); - new_topics.emplace(asset_id_0_, std::cref(topic_0)); + new_topics.emplace(parsed_asset_id, std::cref(topic_0)); } PhotoWithDetails topic_1; if (asset_1_attribution) { + CHECK(ambient::util::ParseDynamicLottieAssetId(asset_id_1_, + parsed_asset_id)); topic_1.photo = test_image; topic_1.details = std::move(*asset_1_attribution); - new_topics.emplace(asset_id_1_, std::cref(topic_1)); + new_topics.emplace(parsed_asset_id, std::cref(topic_1)); } attribution_provider_.OnDynamicImageAssetsRefreshed(new_topics); @@ -127,6 +132,18 @@ /*idx=*/1)) {} }; +class AmbientAnimationAttributionProviderTest2DynamicAssets1Attribution + : public AmbientAnimationAttributionProviderTest { + protected: + AmbientAnimationAttributionProviderTest2DynamicAssets1Attribution() + : AmbientAnimationAttributionProviderTest( + "static-text-node", + GenerateLottieCustomizableIdForTesting(1) + "Attribution", + GenerateLottieDynamicAssetIdForTesting(/*position=*/"A", /*idx=*/1), + GenerateLottieDynamicAssetIdForTesting(/*position=*/"A", + /*idx=*/2)) {} +}; + TEST_F(AmbientAnimationAttributionProviderTest2DynamicAssets, SetsTextInAnimation) { RefreshDynamicImageAssets("attribution_text_0_a", "attribution_text_1_a"); @@ -184,4 +201,23 @@ cc::SkottieTextPropertyValue("attribution_text_1")))); } +TEST_F(AmbientAnimationAttributionProviderTest2DynamicAssets1Attribution, + HandlesFewerAttributionNodesThanAssets) { + RefreshDynamicImageAssets("attribution_text_0", "attribution_text_1"); + // The static text node should the value that's baked into the lottie file + // (|kLottieDataWith2TextNode1Text|). + // + // The one attribution node should be assigned the very first asset's text, + // which is "attribution_text_0" in this case. The second asset's text + // ("attribution_text_1") should be unused because there are fewer text + // nodes than assets here. + EXPECT_THAT(animation_.text_map(), + UnorderedElementsAre( + Pair(cc::HashSkottieResourceId(attribution_node_0_), + cc::SkottieTextPropertyValue( + std::string(cc::kLottieDataWith2TextNode1Text))), + Pair(cc::HashSkottieResourceId(attribution_node_1_), + cc::SkottieTextPropertyValue("attribution_text_0")))); +} + } // namespace ash
diff --git a/ash/ambient/model/ambient_animation_photo_config.cc b/ash/ambient/model/ambient_animation_photo_config.cc index 7cd1991c..4587d891 100644 --- a/ash/ambient/model/ambient_animation_photo_config.cc +++ b/ash/ambient/model/ambient_animation_photo_config.cc
@@ -19,21 +19,21 @@ std::size_t& num_total_positions_out, std::size_t& num_assets_per_position_out) { base::flat_map<std::string, std::size_t> position_to_num_assets; - std::string position_id; - int idx = 0; + ambient::util::ParsedDynamicAssetId parsed_asset_id; for (const auto& [asset_id, _] : skottie_resource_metadata.asset_storage()) { if (!IsCustomizableLottieId(asset_id)) { DVLOG(4) << "Ignoring static image asset id"; continue; } - if (!ambient::util::ParseDynamicLottieAssetId(asset_id, position_id, idx)) { + if (!ambient::util::ParseDynamicLottieAssetId(asset_id, parsed_asset_id)) { NOTREACHED() << "Lottie file contains invalid dynamic asset id " << asset_id; } auto iter = - position_to_num_assets.try_emplace(position_id, /*initial count*/ 0) + position_to_num_assets + .try_emplace(parsed_asset_id.position_id, /*initial count*/ 0) .first; ++iter->second; }
diff --git a/ash/ambient/model/ambient_animation_photo_provider.cc b/ash/ambient/model/ambient_animation_photo_provider.cc index f01d31e..e81cd924 100644 --- a/ash/ambient/model/ambient_animation_photo_provider.cc +++ b/ash/ambient/model/ambient_animation_photo_provider.cc
@@ -239,8 +239,7 @@ const base::WeakPtr<AmbientAnimationPhotoProvider>& provider) : asset_id_(asset_id), size_(std::move(size)), provider_(provider) { DCHECK(provider_); - if (!ambient::util::ParseDynamicLottieAssetId(asset_id, position_id_, - idx_)) { + if (!ambient::util::ParseDynamicLottieAssetId(asset_id, parsed_asset_id_)) { LOG(DFATAL) << "Animation file is invalid. Failed to parse dynamic " "image asset id " << asset_id; @@ -289,8 +288,13 @@ const absl::optional<gfx::Size>& size() const { return size_; } const std::string& asset_id() const { return asset_id_; } - const std::string& position_id() const { return position_id_; } - int idx() const { return idx_; } + const ambient::util::ParsedDynamicAssetId& parsed_asset_id() const { + return parsed_asset_id_; + } + const std::string& position_id() const { + return parsed_asset_id_.position_id; + } + int idx() const { return parsed_asset_id_.idx; } private: static constexpr float kAnimationTimestampInvalid = -1.f; @@ -337,8 +341,7 @@ } const std::string asset_id_; - std::string position_id_; - int idx_; + ambient::util::ParsedDynamicAssetId parsed_asset_id_; const absl::optional<gfx::Size> size_; const base::WeakPtr<AmbientAnimationPhotoProvider> provider_; // Last animation frame timestamp that was observed. @@ -506,11 +509,11 @@ } void AmbientAnimationPhotoProvider::NotifyObserverOfNewTopics() { - base::flat_map</*asset_id*/ std::string, + base::flat_map<ambient::util::ParsedDynamicAssetId, std::reference_wrapper<const PhotoWithDetails>> new_topics; for (const auto& [asset, topic] : pending_dynamic_asset_topics_) { - new_topics.emplace(asset->asset_id(), std::cref(topic)); + new_topics.emplace(asset->parsed_asset_id(), std::cref(topic)); } for (Observer& obs : observers_) { obs.OnDynamicImageAssetsRefreshed(new_topics);
diff --git a/ash/ambient/model/ambient_animation_photo_provider.h b/ash/ambient/model/ambient_animation_photo_provider.h index eb55c9f..342cfe979 100644 --- a/ash/ambient/model/ambient_animation_photo_provider.h +++ b/ash/ambient/model/ambient_animation_photo_provider.h
@@ -10,6 +10,7 @@ #include <vector> #include "ash/ambient/model/ambient_backend_model.h" +#include "ash/ambient/util/ambient_util.h" #include "ash/ash_export.h" #include "base/containers/flat_map.h" #include "base/containers/flat_set.h" @@ -45,7 +46,7 @@ // Note in the event that the same topic is assigned to multiple dynamic // assets, that topic will appear multiple times in |new_topics|. virtual void OnDynamicImageAssetsRefreshed( - const base::flat_map</*asset_id*/ std::string, + const base::flat_map<ambient::util::ParsedDynamicAssetId, std::reference_wrapper<const PhotoWithDetails>>& new_topics) = 0;
diff --git a/ash/ambient/model/ambient_animation_photo_provider_unittest.cc b/ash/ambient/model/ambient_animation_photo_provider_unittest.cc index 614b033..71e20ac0 100644 --- a/ash/ambient/model/ambient_animation_photo_provider_unittest.cc +++ b/ash/ambient/model/ambient_animation_photo_provider_unittest.cc
@@ -36,6 +36,7 @@ using ::testing::AnyOf; using ::testing::Each; using ::testing::ElementsAre; +using ::testing::FieldsAre; using ::testing::Invoke; using ::testing::IsSubsetOf; using ::testing::Key; @@ -80,7 +81,7 @@ MOCK_METHOD( void, OnDynamicImageAssetsRefreshed, - ((const base::flat_map<std::string, + ((const base::flat_map<ambient::util::ParsedDynamicAssetId, std::reference_wrapper<const PhotoWithDetails>>&)), (override)); @@ -435,14 +436,8 @@ EXPECT_CALL( observer, OnDynamicImageAssetsRefreshed(AllOf( - ElementsAre(Key(GenerateLottieDynamicAssetIdForTesting( - /*position=*/"A", /*idx=*/1)), - Key(GenerateLottieDynamicAssetIdForTesting( - /*position=*/"B", /*idx=*/1)), - Key(GenerateLottieDynamicAssetIdForTesting( - /*position=*/"C", /*idx=*/1)), - Key(GenerateLottieDynamicAssetIdForTesting( - /*position=*/"D", /*idx=*/1))), + ElementsAre(Key(FieldsAre("A", 1)), Key(FieldsAre("B", 1)), + Key(FieldsAre("C", 1)), Key(FieldsAre("D", 1))), UnorderedElementsAre(Pair(_, TopicHasDetails("attribution-a")), Pair(_, TopicHasDetails("attribution-b")), Pair(_, TopicHasDetails("attribution-c")), @@ -464,14 +459,8 @@ EXPECT_CALL( observer, OnDynamicImageAssetsRefreshed(AllOf( - ElementsAre(Key(GenerateLottieDynamicAssetIdForTesting( - /*position=*/"A", /*idx=*/1)), - Key(GenerateLottieDynamicAssetIdForTesting( - /*position=*/"B", /*idx=*/1)), - Key(GenerateLottieDynamicAssetIdForTesting( - /*position=*/"C", /*idx=*/1)), - Key(GenerateLottieDynamicAssetIdForTesting( - /*position=*/"D", /*idx=*/1))), + ElementsAre(Key(FieldsAre("A", 1)), Key(FieldsAre("B", 1)), + Key(FieldsAre("C", 1)), Key(FieldsAre("D", 1))), UnorderedElementsAre(Pair(_, TopicHasDetails("attribution-e")), Pair(_, TopicHasDetails("attribution-f")), Pair(_, TopicHasDetails("attribution-g")), @@ -636,22 +625,24 @@ EXPECT_CALL( observer, OnDynamicImageAssetsRefreshed(AllOf( - ElementsAre(Key(dynamic_asset_ids_[kPositionAIdx1]), - Key(dynamic_asset_ids_[kPositionAIdx2]), - Key(dynamic_asset_ids_[kPositionBIdx1]), - Key(dynamic_asset_ids_[kPositionBIdx2])), + ElementsAre(Key(FieldsAre("A", 1)), Key(FieldsAre("B", 1)), + Key(FieldsAre("A", 2)), Key(FieldsAre("B", 2))), UnorderedElementsAre(Pair(_, TopicHasDetails("attribution-a")), Pair(_, TopicHasDetails("attribution-b")), Pair(_, TopicHasDetails("attribution-c")), Pair(_, TopicHasDetails("attribution-d")))))) .WillOnce(Invoke( [&](const base::flat_map< - std::string, std::reference_wrapper<const PhotoWithDetails>>& - new_topics) { + ambient::util::ParsedDynamicAssetId, + std::reference_wrapper<const PhotoWithDetails>>& new_topics) { asset_a_2_prev_attribution = - new_topics.at(dynamic_asset_ids_[kPositionAIdx2]).get().details; + new_topics.at(ambient::util::ParsedDynamicAssetId({"A", 2})) + .get() + .details; asset_b_2_prev_attribution = - new_topics.at(dynamic_asset_ids_[kPositionBIdx2]).get().details; + new_topics.at(ambient::util::ParsedDynamicAssetId({"B", 2})) + .get() + .details; })); GetFrameDataForAssets(all_assets, /*timestamp=*/0); Mock::VerifyAndClearExpectations(&observer); @@ -665,17 +656,15 @@ AddImageToModel(test_image, "attribution-f"); // Cycle 1 Frame 0 - EXPECT_CALL(observer, OnDynamicImageAssetsRefreshed(ElementsAre( - Pair(dynamic_asset_ids_[kPositionAIdx1], - TopicHasDetails(asset_a_2_prev_attribution)), - Pair(dynamic_asset_ids_[kPositionAIdx2], - AnyOf(TopicHasDetails("attribution-e"), - TopicHasDetails("attribution-f"))), - Pair(dynamic_asset_ids_[kPositionBIdx1], - TopicHasDetails(asset_b_2_prev_attribution)), - Pair(dynamic_asset_ids_[kPositionBIdx2], - AnyOf(TopicHasDetails("attribution-e"), - TopicHasDetails("attribution-f")))))); + EXPECT_CALL( + observer, + OnDynamicImageAssetsRefreshed(ElementsAre( + Pair(FieldsAre("A", 1), TopicHasDetails(asset_a_2_prev_attribution)), + Pair(FieldsAre("B", 1), TopicHasDetails(asset_b_2_prev_attribution)), + Pair(FieldsAre("A", 2), AnyOf(TopicHasDetails("attribution-e"), + TopicHasDetails("attribution-f"))), + Pair(FieldsAre("B", 2), AnyOf(TopicHasDetails("attribution-e"), + TopicHasDetails("attribution-f")))))); GetFrameDataForAssets(all_assets, /*timestamp=*/0); Mock::VerifyAndClearExpectations(&observer);
diff --git a/ash/ambient/util/ambient_util.cc b/ash/ambient/util/ambient_util.cc index f19ed0a..99cd323 100644 --- a/ash/ambient/util/ambient_util.cc +++ b/ash/ambient/util/ambient_util.cc
@@ -98,15 +98,19 @@ } } +bool ParsedDynamicAssetId::operator<(const ParsedDynamicAssetId& other) const { + return idx == other.idx ? position_id < other.position_id : idx < other.idx; +} + bool ParseDynamicLottieAssetId(base::StringPiece asset_id, - std::string& position_id, - int& idx) { + ParsedDynamicAssetId& parsed_output) { static const base::NoDestructor<std::string> kAssetIdPatternStr( base::StrCat({kLottieCustomizableIdPrefix, R"(_Photo_Position([[:alnum:]]+)_([[:digit:]]+).*)"})); static const base::NoDestructor<RE2> kAssetIdPattern( kAssetIdPatternStr->data()); - return RE2::FullMatch(asset_id.data(), *kAssetIdPattern, &position_id, &idx); + return RE2::FullMatch(asset_id.data(), *kAssetIdPattern, + &parsed_output.position_id, &parsed_output.idx); } } // namespace util
diff --git a/ash/ambient/util/ambient_util.h b/ash/ambient/util/ambient_util.h index 297ff5ac6..5a72133 100644 --- a/ash/ambient/util/ambient_util.h +++ b/ash/ambient/util/ambient_util.h
@@ -76,11 +76,21 @@ // Note this naming convention is agreed upon with the animation designer, so // any changes to the logic must be confirmed with them. // -// Returns false and leaves the output arguments untouched if the |asset_id| +// Returns false and leaves the output argument untouched if the |asset_id| // does not match the naming convention above. +struct ASH_EXPORT ParsedDynamicAssetId { + // Orders by index first, then by position if indices match: + // "_CrOS_Photo_PositionA_1" + // "_CrOS_Photo_PositionB_1" + // "_CrOS_Photo_PositionA_2" + // "_CrOS_Photo_PositionB_2" + bool operator<(const ParsedDynamicAssetId& other) const; + + std::string position_id; + int idx; +}; ASH_EXPORT bool ParseDynamicLottieAssetId(base::StringPiece asset_id, - std::string& position_id, - int& idx); + ParsedDynamicAssetId& parsed_output); } // namespace util } // namespace ambient
diff --git a/ash/ambient/util/ambient_util_unittest.cc b/ash/ambient/util/ambient_util_unittest.cc index 2d1e85d..4cc63ff 100644 --- a/ash/ambient/util/ambient_util_unittest.cc +++ b/ash/ambient/util/ambient_util_unittest.cc
@@ -14,33 +14,44 @@ namespace util { namespace { using ::testing::Eq; +using ::testing::Lt; +using ::testing::Not; } // namespace TEST(AmbientUtilTest, ParseDynamicLottieAssetId) { - std::string position; - int idx = 0; - EXPECT_FALSE(ParseDynamicLottieAssetId("StaticAsset", position, idx)); - EXPECT_FALSE(ParseDynamicLottieAssetId("_CrOS_UnknownAsset", position, idx)); + ParsedDynamicAssetId output; + EXPECT_FALSE(ParseDynamicLottieAssetId("StaticAsset", output)); + EXPECT_FALSE(ParseDynamicLottieAssetId("_CrOS_UnknownAsset", output)); + ASSERT_TRUE(ParseDynamicLottieAssetId("_CrOS_Photo_PositionA_1", output)); + EXPECT_THAT(output.position_id, Eq("A")); + EXPECT_THAT(output.idx, Eq(1)); + ASSERT_TRUE(ParseDynamicLottieAssetId("_CrOS_Photo_PositionB_1", output)); + EXPECT_THAT(output.position_id, Eq("B")); + EXPECT_THAT(output.idx, Eq(1)); ASSERT_TRUE( - ParseDynamicLottieAssetId("_CrOS_Photo_PositionA_1", position, idx)); - EXPECT_THAT(position, Eq("A")); - EXPECT_THAT(idx, Eq(1)); + ParseDynamicLottieAssetId("_CrOS_Photo_PositionTopLeft_1", output)); + EXPECT_THAT(output.position_id, Eq("TopLeft")); + EXPECT_THAT(output.idx, Eq(1)); ASSERT_TRUE( - ParseDynamicLottieAssetId("_CrOS_Photo_PositionB_1", position, idx)); - EXPECT_THAT(position, Eq("B")); - EXPECT_THAT(idx, Eq(1)); - ASSERT_TRUE(ParseDynamicLottieAssetId("_CrOS_Photo_PositionTopLeft_1", - position, idx)); - EXPECT_THAT(position, Eq("TopLeft")); - EXPECT_THAT(idx, Eq(1)); - ASSERT_TRUE(ParseDynamicLottieAssetId("_CrOS_Photo_PositionTopRight_2", - position, idx)); - EXPECT_THAT(position, Eq("TopRight")); - EXPECT_THAT(idx, Eq(2)); - ASSERT_TRUE( - ParseDynamicLottieAssetId("_CrOS_Photo_PositionA_1.png", position, idx)); - EXPECT_THAT(position, Eq("A")); - EXPECT_THAT(idx, Eq(1)); + ParseDynamicLottieAssetId("_CrOS_Photo_PositionTopRight_2", output)); + EXPECT_THAT(output.position_id, Eq("TopRight")); + EXPECT_THAT(output.idx, Eq(2)); + ASSERT_TRUE(ParseDynamicLottieAssetId("_CrOS_Photo_PositionA_1.png", output)); + EXPECT_THAT(output.position_id, Eq("A")); + EXPECT_THAT(output.idx, Eq(1)); +} + +TEST(AmbientUtilTest, CompareDynamicLottieAssetId) { + EXPECT_THAT(ParsedDynamicAssetId({"A", 1}), + Lt(ParsedDynamicAssetId({"A", 2}))); + EXPECT_THAT(ParsedDynamicAssetId({"A", 2}), + Not(Lt(ParsedDynamicAssetId({"A", 1})))); + EXPECT_THAT(ParsedDynamicAssetId({"A", 1}), + Lt(ParsedDynamicAssetId({"B", 1}))); + EXPECT_THAT(ParsedDynamicAssetId({"B", 1}), + Not(Lt(ParsedDynamicAssetId({"A", 1})))); + EXPECT_THAT(ParsedDynamicAssetId({"A", 1}), + Not(Lt(ParsedDynamicAssetId({"A", 1})))); } } // namespace util
diff --git a/ash/capture_mode/capture_mode_camera_controller.cc b/ash/capture_mode/capture_mode_camera_controller.cc index fefaa2f..7e3deef 100644 --- a/ash/capture_mode/capture_mode_camera_controller.cc +++ b/ash/capture_mode/capture_mode_camera_controller.cc
@@ -252,8 +252,6 @@ views::Widget::ReparentNativeView(native_window, parent); StackingPreviewAtTop(camera_preview_widget_.get()); } - // TODO(minch): Revisit to see whether it is better to separate this from - // MaybeReparentPreviewWidget and do the widget bounds updates when needed. MaybeUpdatePreviewWidgetBounds(); }
diff --git a/ash/controls/rounded_scroll_bar.cc b/ash/controls/rounded_scroll_bar.cc index 7351ce29..3a57886 100644 --- a/ash/controls/rounded_scroll_bar.cc +++ b/ash/controls/rounded_scroll_bar.cc
@@ -15,6 +15,7 @@ #include "ui/compositor/layer.h" #include "ui/compositor/scoped_layer_animation_settings.h" #include "ui/gfx/canvas.h" +#include "ui/views/controls/button/button.h" #include "ui/views/controls/scrollbar/base_scroll_bar_thumb.h" namespace ash { @@ -43,6 +44,13 @@ Thumb& operator=(const Thumb&) = delete; ~Thumb() override = default; + bool ShouldPaintAsActive() const { + // The thumb is active during hover and also when the user is dragging the + // thumb with the mouse. In the latter case, the mouse might be outside the + // scroll bar, due to mouse capture. + return IsMouseHovered() || GetState() == views::Button::STATE_PRESSED; + } + // views::BaseScrollBarThumb: gfx::Size CalculatePreferredSize() const override { return gfx::Size(kScrollThumbThicknessDp, kScrollThumbThicknessDp); @@ -53,7 +61,7 @@ fill_flags.setStyle(cc::PaintFlags::kFill_Style); fill_flags.setAntiAlias(true); // May be null in tests. - if (auto* color_provider = ColorProvider::Get()) { + if (auto* color_provider = ColorProvider::Get(); color_provider) { fill_flags.setColor(color_provider->GetContentLayerColor( ColorProvider::ContentLayerType::kScrollBarColor)); } @@ -68,6 +76,7 @@ RoundedScrollBar::RoundedScrollBar(bool horizontal) : ScrollBar(horizontal), + thumb_(new Thumb(this)), // Owned by views hierarchy. hide_scrollbar_timer_( FROM_HERE, kScrollThumbHideTimeout, @@ -76,12 +85,11 @@ // Moving the mouse directly into the thumb will also notify this view. SetNotifyEnterExitOnChild(true); - auto* thumb = new Thumb(this); // Owned by views hierarchy. - SetThumb(thumb); - thumb->SetPaintToLayer(); - thumb->layer()->SetFillsBoundsOpaquely(false); + SetThumb(thumb_); + thumb_->SetPaintToLayer(); + thumb_->layer()->SetFillsBoundsOpaquely(false); // The thumb is hidden by default. - thumb->layer()->SetOpacity(0.f); + thumb_->layer()->SetOpacity(0.f); } RoundedScrollBar::~RoundedScrollBar() = default; @@ -130,24 +138,23 @@ } views::BaseScrollBarThumb* RoundedScrollBar::GetThumbForTest() const { - return GetThumb(); + return thumb_; } void RoundedScrollBar::ShowScrollbar() { if (!IsMouseHovered()) hide_scrollbar_timer_.Reset(); - auto* thumb = GetThumb(); const float target_opacity = - thumb->IsMouseHovered() ? kActiveOpacity : kDefaultOpacity; - if (base::IsApproximatelyEqual(thumb->layer()->GetTargetOpacity(), + thumb_->ShouldPaintAsActive() ? kActiveOpacity : kDefaultOpacity; + if (base::IsApproximatelyEqual(thumb_->layer()->GetTargetOpacity(), target_opacity, std::numeric_limits<float>::epsilon())) { return; } - ui::ScopedLayerAnimationSettings animation(thumb->layer()->GetAnimator()); + ui::ScopedLayerAnimationSettings animation(thumb_->layer()->GetAnimator()); animation.SetTransitionDuration(kScrollThumbFadeDuration); - thumb->layer()->SetOpacity(target_opacity); + thumb_->layer()->SetOpacity(target_opacity); } void RoundedScrollBar::HideScrollBar() { @@ -157,10 +164,9 @@ return; hide_scrollbar_timer_.Stop(); - ui::ScopedLayerAnimationSettings animation( - GetThumb()->layer()->GetAnimator()); + ui::ScopedLayerAnimationSettings animation(thumb_->layer()->GetAnimator()); animation.SetTransitionDuration(kScrollThumbFadeDuration); - GetThumb()->layer()->SetOpacity(0.f); + thumb_->layer()->SetOpacity(0.f); } void RoundedScrollBar::OnThumbStateChanged() {
diff --git a/ash/controls/rounded_scroll_bar.h b/ash/controls/rounded_scroll_bar.h index 16ad6ac..03a7975d 100644 --- a/ash/controls/rounded_scroll_bar.h +++ b/ash/controls/rounded_scroll_bar.h
@@ -58,6 +58,9 @@ // Called when the thumb hover/pressed state changed. void OnThumbStateChanged(); + // Equivalent to GetThumb() but typed as the inner class `Thumb`. + Thumb* const thumb_; + // Insets for the scroll track. gfx::Insets insets_;
diff --git a/ash/controls/rounded_scroll_bar_unittest.cc b/ash/controls/rounded_scroll_bar_unittest.cc index 038465e..cd919439 100644 --- a/ash/controls/rounded_scroll_bar_unittest.cc +++ b/ash/controls/rounded_scroll_bar_unittest.cc
@@ -18,6 +18,9 @@ namespace ash { namespace { +constexpr int kScrollBarWidth = 10; + +// Thumb opacity values. constexpr float kDefaultOpacity = 0.38f; constexpr float kActiveOpacity = 1.0f; @@ -58,7 +61,7 @@ scroll_bar_ = contents->AddChildView( std::make_unique<RoundedScrollBar>(/*horizontal=*/false)); scroll_bar_->set_controller(&controller_); - scroll_bar_->SetBounds(90, 0, 10, 200); + scroll_bar_->SetBounds(90, 0, kScrollBarWidth, 200); scroll_bar_->Update(/*viewport_size=*/200, /*content_size=*/1000, /*contents_scroll_offset=*/0); thumb_ = scroll_bar_->GetThumbForTest(); @@ -119,5 +122,15 @@ EXPECT_EQ(thumb_->layer()->GetTargetOpacity(), kActiveOpacity); } +TEST_F(RoundedScrollBarTest, DragOutsideTrackShowsActiveOpacity) { + gfx::Point thumb_center = thumb_->GetBoundsInScreen().CenterPoint(); + generator_->MoveMouseTo(thumb_center); + generator_->PressLeftButton(); + gfx::Point outside_scroll_bar(thumb_center.x() + kScrollBarWidth, + thumb_center.y()); + generator_->MoveMouseTo(outside_scroll_bar); + EXPECT_EQ(thumb_->layer()->GetTargetOpacity(), kActiveOpacity); +} + } // namespace } // namespace ash
diff --git a/ash/projector/projector_annotation_tray.cc b/ash/projector/projector_annotation_tray.cc index ded3c23..365eb96 100644 --- a/ash/projector/projector_annotation_tray.cc +++ b/ash/projector/projector_annotation_tray.cc
@@ -34,13 +34,13 @@ constexpr int kPaddingBetweenBottomAndLastTrayItem = 4; // Width of the bubble itself (dp). -constexpr int kBubbleWidth = 288; +constexpr int kBubbleWidth = 242; // Insets for the views (dp). -constexpr gfx::Insets kPenViewPadding(4, 24, 0, 24); +constexpr gfx::Insets kPenViewPadding(4, 16, 0, 16); // Spacing between buttons (dp). -constexpr int kButtonsPadding = 20; +constexpr int kButtonsPadding = 12; // Size of menu rows. constexpr int kMenuRowHeight = 48; @@ -95,6 +95,8 @@ image_view_->SetHorizontalAlignment(views::ImageView::Alignment::kCenter); image_view_->SetVerticalAlignment(views::ImageView::Alignment::kCenter); image_view_->SetPreferredSize(gfx::Size(kTrayItemSize, kTrayItemSize)); + // The default pen color upon creation is red. + current_pen_color_ = kRedPenColor; } ProjectorAnnotationTray::~ProjectorAnnotationTray() = default; @@ -192,14 +194,14 @@ box_layout->set_minimum_cross_axis_size(kMenuRowHeight); marker_view_container->SetLayoutManager(std::move(box_layout)); - // TODO(b/201664243): Only draw outer circle on hover or selection. for (SkColor color : kPenColors) { - marker_view_container->AddChildView( + auto* colorButton = marker_view_container->AddChildView( std::make_unique<ProjectorColorButton>( base::BindRepeating(&ProjectorAnnotationTray::OnPenColorPressed, base::Unretained(this), color), color, kColorButtonColorViewSize, kColorButtonViewRadius, l10n_util::GetStringUTF16(GetAccessibleNameForColor(color)))); + colorButton->SetToggled(current_pen_color_ == color); } setup_layered_view(marker_view_container); } @@ -266,6 +268,7 @@ AnnotatorTool tool; tool.color = color; projector_controller->SetAnnotatorTool(tool); + current_pen_color_ = color; CloseBubble(); UpdateIcon(); }
diff --git a/ash/projector/projector_annotation_tray.h b/ash/projector/projector_annotation_tray.h index b37abcf..28a48154 100644 --- a/ash/projector/projector_annotation_tray.h +++ b/ash/projector/projector_annotation_tray.h
@@ -60,6 +60,9 @@ // The bubble that appears after clicking the annotation tools tray button. std::unique_ptr<TrayBubbleWrapper> bubble_; + + // The last selected pen color. + SkColor current_pen_color_; }; } // namespace ash
diff --git a/ash/projector/ui/projector_button.cc b/ash/projector/ui/projector_button.cc index 6b6976fc..cef5dc6 100644 --- a/ash/projector/ui/projector_button.cc +++ b/ash/projector/ui/projector_button.cc
@@ -41,17 +41,29 @@ } void ProjectorButton::OnPaintBackground(gfx::Canvas* canvas) { + if (!GetToggled()) { + return; + } auto* color_provider = AshColorProvider::Get(); + // Draw a filled background for the button. cc::PaintFlags flags; flags.setAntiAlias(true); flags.setStyle(cc::PaintFlags::kFill_Style); flags.setColor(color_provider->GetControlsLayerColor( - GetToggled() - ? AshColorProvider::ControlsLayerType::kControlBackgroundColorActive - : AshColorProvider::ControlsLayerType:: - kControlBackgroundColorInactive)); + AshColorProvider::ControlsLayerType::kControlBackgroundColorInactive)); const gfx::RectF bounds(GetContentsBounds()); canvas->DrawCircle(bounds.CenterPoint(), bounds.width() / 2, flags); + + // Draw a border on the background circle. + cc::PaintFlags border_flags; + flags.setAntiAlias(true); + flags.setStyle(cc::PaintFlags::kStroke_Style); + flags.setColor(color_provider->GetControlsLayerColor( + AshColorProvider::ControlsLayerType::kHairlineBorderColor)); + flags.setStrokeWidth(kProjectorButtonBorderSize); + canvas->DrawCircle(bounds.CenterPoint(), + (bounds.width() - kProjectorButtonBorderSize * 2) / 2, + flags); } void ProjectorButton::OnThemeChanged() {
diff --git a/ash/projector/ui/projector_button.h b/ash/projector/ui/projector_button.h index 71256554..262bcc1 100644 --- a/ash/projector/ui/projector_button.h +++ b/ash/projector/ui/projector_button.h
@@ -18,6 +18,7 @@ class ASH_EXPORT ProjectorButton : public views::ToggleImageButton { public: const int kProjectorButtonSize = 32; + const int kProjectorButtonBorderSize = 1; ProjectorButton(views::Button::PressedCallback callback, const std::u16string& name);
diff --git a/ash/public/cpp/desks_templates_delegate.h b/ash/public/cpp/desks_templates_delegate.h index 3d5d4db..3783516 100644 --- a/ash/public/cpp/desks_templates_delegate.h +++ b/ash/public/cpp/desks_templates_delegate.h
@@ -100,6 +100,10 @@ // Return the readable app name for this app id (i.e. "madfksjfasdfkjasdkf" -> // "Chrome"). virtual std::string GetAppShortName(const std::string& app_id) = 0; + + // Return true if the app with the given `app_id` is available to launch from + // template. + virtual bool IsAppAvailable(const std::string& app_id) const = 0; }; } // namespace ash
diff --git a/ash/public/cpp/test/test_desks_templates_delegate.cc b/ash/public/cpp/test/test_desks_templates_delegate.cc index 34ff8e3b..32f65eb 100644 --- a/ash/public/cpp/test/test_desks_templates_delegate.cc +++ b/ash/public/cpp/test/test_desks_templates_delegate.cc
@@ -5,6 +5,7 @@ #include "ash/public/cpp/test/test_desks_templates_delegate.h" #include "ash/public/cpp/desk_template.h" +#include "base/containers/contains.h" #include "components/app_restore/app_launch_info.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/window.h" @@ -66,4 +67,9 @@ return std::string(); } +bool TestDesksTemplatesDelegate::IsAppAvailable( + const std::string& app_id) const { + return !base::Contains(unavailable_app_ids_, app_id); +} + } // namespace ash
diff --git a/ash/public/cpp/test/test_desks_templates_delegate.h b/ash/public/cpp/test/test_desks_templates_delegate.h index d7b490e9..cfea00d 100644 --- a/ash/public/cpp/test/test_desks_templates_delegate.h +++ b/ash/public/cpp/test/test_desks_templates_delegate.h
@@ -5,6 +5,8 @@ #ifndef ASH_PUBLIC_CPP_TEST_TEST_DESKS_TEMPLATES_DELEGATE_H_ #define ASH_PUBLIC_CPP_TEST_TEST_DESKS_TEMPLATES_DELEGATE_H_ +#include <vector> + #include "ash/public/cpp/ash_public_export.h" #include "ash/public/cpp/desks_templates_delegate.h" @@ -40,6 +42,11 @@ desk_model_ = desk_model; } + void set_unavailable_apps( + const std::vector<std::string>& unavailable_app_ids) { + unavailable_app_ids_ = unavailable_app_ids; + } + // DesksTemplatesDelegate: std::unique_ptr<app_restore::AppLaunchInfo> GetAppLaunchDataForDeskTemplate( aura::Window* window) const override; @@ -62,9 +69,11 @@ bool IsWindowSupportedForDeskTemplate(aura::Window* window) const override; void OpenFeedbackDialog(const std::string& extra_diagnostics) override; std::string GetAppShortName(const std::string& app_id) override; + bool IsAppAvailable(const std::string& app_id) const override; private: desks_storage::DeskModel* desk_model_ = nullptr; + std::vector<std::string> unavailable_app_ids_; }; } // namespace ash
diff --git a/ash/style/ash_color_provider.cc b/ash/style/ash_color_provider.cc index 3432469..93332df3 100644 --- a/ash/style/ash_color_provider.cc +++ b/ash/style/ash_color_provider.cc
@@ -16,6 +16,7 @@ #include "base/bind.h" #include "base/check_op.h" #include "base/feature_list.h" +#include "base/metrics/histogram_functions.h" #include "base/strings/string_number_conversions.h" #include "components/prefs/pref_change_registrar.h" #include "components/prefs/pref_registry_simple.h" @@ -303,10 +304,12 @@ void AshColorProvider::ToggleColorMode() { DCHECK(active_user_pref_service_); - active_user_pref_service_->SetBoolean(prefs::kDarkModeEnabled, - !IsDarkModeEnabled()); + const bool value = !IsDarkModeEnabled(); + active_user_pref_service_->SetBoolean(prefs::kDarkModeEnabled, value); active_user_pref_service_->CommitPendingWrite(); NotifyDarkModeEnabledPrefChange(); + base::UmaHistogramBoolean("Ash.DarkTheme.SystemTray.IsDarkModeEnabled", + value); } void AshColorProvider::UpdateColorModeThemed(bool is_themed) {
diff --git a/ash/style/highlight_border.cc b/ash/style/highlight_border.cc index 38960e5..d3931c0 100644 --- a/ash/style/highlight_border.cc +++ b/ash/style/highlight_border.cc
@@ -9,6 +9,7 @@ #include "ash/style/ash_color_provider.h" #include "ui/gfx/canvas.h" #include "ui/gfx/geometry/dip_util.h" +#include "ui/gfx/scoped_canvas.h" #include "ui/views/view.h" namespace ash { @@ -51,6 +52,7 @@ // Scale bounds and corner radius with device scale factor to make sure // border bounds match content bounds but keep border stroke width the same. + gfx::ScopedCanvas scoped_canvas(canvas); const float dsf = canvas->UndoDeviceScaleFactor(); const gfx::RectF pixel_bounds = gfx::ConvertRectToPixels(bounds, dsf); const float scaled_corner_radius = dsf * corner_radius;
diff --git a/ash/style/system_toast_style.cc b/ash/style/system_toast_style.cc index 666dd4d..95650a9 100644 --- a/ash/style/system_toast_style.cc +++ b/ash/style/system_toast_style.cc
@@ -10,6 +10,7 @@ #include "ash/shell.h" #include "ash/strings/grit/ash_strings.h" #include "ash/style/ash_color_provider.h" +#include "ash/style/highlight_border.h" #include "ash/style/pill_button.h" #include "ash/system/toast/toast_overlay.h" #include "ash/wm/work_area_insets.h" @@ -160,9 +161,15 @@ views::BoxLayout::CrossAxisAlignment::kCenter); layout->SetFlexForView(label_, 1); - layer()->SetRoundedCornerRadius(gfx::RoundedCornersF(toast_height / 2.f)); + const int toast_corner_radius = toast_height / 2.f; + layer()->SetRoundedCornerRadius(gfx::RoundedCornersF(toast_corner_radius)); SetBackground(views::CreateRoundedRectBackground(GetBackgroundColor(), - toast_height / 2.f)); + toast_corner_radius)); + if (features::IsDarkLightModeEnabled()) { + SetBorder(std::make_unique<HighlightBorder>( + toast_corner_radius, HighlightBorder::Type::kHighlightBorder1, + /*use_light_colors=*/false)); + } } SystemToastStyle::~SystemToastStyle() = default;
diff --git a/ash/webui/personalization_app/mojom/personalization_app.mojom b/ash/webui/personalization_app/mojom/personalization_app.mojom index fd7b991..414d6478 100644 --- a/ash/webui/personalization_app/mojom/personalization_app.mojom +++ b/ash/webui/personalization_app/mojom/personalization_app.mojom
@@ -284,20 +284,6 @@ string name; }; -// Receives necessary information to display and change user image for the -// current user. -interface UserImageObserver { - // Triggered by |UserManager::Observer::OnUserImageChanged|. - OnUserImageChanged(url.mojom.Url image); - - // Triggered by |UserManager::Observer::OnUserProfileImageUpdated|. - OnUserProfileImageUpdated(url.mojom.Url profile_image); - - // Triggered by - // |ash::CameraPresenceNotifier::Observer::OnCameraPresenceCheckDone|. - OnCameraPresenceCheckDone(bool is_camera_present); -}; - // A default user image stored on the device that can be set as the user's // device avatar image. struct DefaultUserImage { @@ -311,6 +297,43 @@ url.mojom.Url url; }; +// An empty struct that is just used to indicate the presence of a profile +// image. +struct ProfileImage {}; + +// An empty struct that is used to signify the user does not have a valid image. +struct InvalidImage {}; + +// The current image that the user has selected as device avatar. +union UserImage { + // Set if the user has selected a default (built-in) avatar image. + DefaultUserImage default_image; + + // Set if the user has selected an external image, usually from file or from + // webcam capture. + mojo_base.mojom.BigBuffer external_image; + + // Set if the user has selected their gaia account profile image. + ProfileImage profile_image; + + // Set if the user does not have a valid image selected or there was an error. + InvalidImage invalid_image; +}; + +// Receives necessary information to display and change user image for the +// current user. +interface UserImageObserver { + // Triggered by |UserManager::Observer::OnUserImageChanged|. + OnUserImageChanged(UserImage user_image); + + // Triggered by |UserManager::Observer::OnUserProfileImageUpdated|. + OnUserProfileImageUpdated(url.mojom.Url profile_image); + + // Triggered by + // |ash::CameraPresenceNotifier::Observer::OnCameraPresenceCheckDone|. + OnCameraPresenceCheckDone(bool is_camera_present); +}; + // Provides APIs to view information about the current user. This API is exposed // only to the Personalization App (chrome://personalization), and is // implemented by |PersonalizationAppUserProviderImpl| in chrome.
diff --git a/ash/webui/personalization_app/resources/BUILD.gn b/ash/webui/personalization_app/resources/BUILD.gn index 218c060..0e31474 100644 --- a/ash/webui/personalization_app/resources/BUILD.gn +++ b/ash/webui/personalization_app/resources/BUILD.gn
@@ -45,6 +45,7 @@ "trusted/user/user_image_observer.ts", "trusted/user/user_interface_provider.ts", "trusted/user/user_reducers.ts", + "trusted/user/user_selectors.ts", "trusted/user/user_state.ts", "trusted/user/webcam_utils_proxy.ts", "trusted/utils.ts",
diff --git a/ash/webui/personalization_app/resources/trusted/ambient/ambient_preview_element.ts b/ash/webui/personalization_app/resources/trusted/ambient/ambient_preview_element.ts index c697769..32bd6b1a 100644 --- a/ash/webui/personalization_app/resources/trusted/ambient/ambient_preview_element.ts +++ b/ash/webui/personalization_app/resources/trusted/ambient/ambient_preview_element.ts
@@ -87,10 +87,16 @@ } private getAlbumDescription_(): string { - return this.previewAlbum_ && this.topicSource_ !== null ? - `${getTopicSourceName(this.topicSource_)} • ${ - getPhotoCount(this.previewAlbum_)}` : - ''; + if (!this.previewAlbum_ || this.topicSource_ === null) { + return ''; + } + const topicSourceDesc = getTopicSourceName(this.topicSource_); + // TODO(b/223834394): replace dot separator symbol • with an icon/image. + // As we don't know the number of photos in Art Gallery albums, + // this info won't be shown in this case. + return this.topicSource_ === TopicSource.kArtGallery ? + topicSourceDesc : + `${topicSourceDesc} • ${getPhotoCount(this.previewAlbum_)}`; } }
diff --git a/ash/webui/personalization_app/resources/trusted/user/avatar_list_element.ts b/ash/webui/personalization_app/resources/trusted/user/avatar_list_element.ts index 1914762..d4414de 100644 --- a/ash/webui/personalization_app/resources/trusted/user/avatar_list_element.ts +++ b/ash/webui/personalization_app/resources/trusted/user/avatar_list_element.ts
@@ -12,7 +12,7 @@ import {html} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {isSelectionEvent} from '../../common/utils.js'; -import {DefaultUserImage} from '../personalization_app.mojom-webui.js'; +import {DefaultUserImage, UserImage} from '../personalization_app.mojom-webui.js'; import {WithPersonalizationStore} from '../personalization_store.js'; import {AvatarCamera, AvatarCameraMode} from './avatar_camera_element.js'; @@ -59,7 +59,7 @@ private profileImage_: Url|null; private isCameraPresent_: boolean; private cameraMode_: AvatarCameraMode|null; - private image_: Url|null; + private image_: UserImage|null; connectedCallback() { super.connectedCallback(); @@ -89,15 +89,13 @@ } private getProfileImageAriaSelected_( - profileImage: Url|null, selectedImage: Url|null): string { - return (!!profileImage && !!selectedImage && - selectedImage.url === profileImage.url) - .toString(); + profileImage: Url|null, selectedImage: UserImage|null): string { + return (!!profileImage && !!selectedImage?.profileImage).toString(); } private getDefaultUserImageAriaSelected_( - image: DefaultUserImage, selectedImage: Url|null): string { - return (!!selectedImage && selectedImage.url === image.url.url).toString(); + image: DefaultUserImage, selectedImage: UserImage|null): string { + return (image.index === selectedImage?.defaultImage?.index).toString(); } private onSelectProfileImage_(event: Event) {
diff --git a/ash/webui/personalization_app/resources/trusted/user/user_actions.ts b/ash/webui/personalization_app/resources/trusted/user/user_actions.ts index 6f0c560..4ceadb0 100644 --- a/ash/webui/personalization_app/resources/trusted/user/user_actions.ts +++ b/ash/webui/personalization_app/resources/trusted/user/user_actions.ts
@@ -5,7 +5,7 @@ import {Action} from 'chrome://resources/js/cr/ui/store.js'; import {Url} from 'chrome://resources/mojo/url/mojom/url.mojom-webui.js'; -import {DefaultUserImage, UserInfo} from '../personalization_app.mojom-webui.js'; +import {DefaultUserImage, UserImage, UserInfo} from '../personalization_app.mojom-webui.js'; /** * @fileoverview Defines the actions to change user state. @@ -37,10 +37,10 @@ export type SetUserImageAction = Action&{ name: UserActionName.SET_USER_IMAGE, - image: Url, + image: UserImage, }; -export function setUserImageAction(image: Url): SetUserImageAction { +export function setUserImageAction(image: UserImage): SetUserImageAction { return {name: UserActionName.SET_USER_IMAGE, image}; }
diff --git a/ash/webui/personalization_app/resources/trusted/user/user_controller.ts b/ash/webui/personalization_app/resources/trusted/user/user_controller.ts index bdc49c47..bbc5d4f 100644 --- a/ash/webui/personalization_app/resources/trusted/user/user_controller.ts +++ b/ash/webui/personalization_app/resources/trusted/user/user_controller.ts
@@ -5,7 +5,7 @@ import {assert} from 'chrome://resources/js/assert.m.js'; import {BigBuffer, BigBufferSharedMemoryRegion} from 'chrome://resources/mojo/mojo/public/mojom/base/big_buffer.mojom-webui.js'; -import {UserProviderInterface} from '../personalization_app.mojom-webui'; +import {UserProviderInterface} from '../personalization_app.mojom-webui.js'; import {PersonalizationStore} from '../personalization_store.js'; import {setDefaultUserImagesAction, setUserInfoAction} from './user_actions.js';
diff --git a/ash/webui/personalization_app/resources/trusted/user/user_image_observer.ts b/ash/webui/personalization_app/resources/trusted/user/user_image_observer.ts index 2cc57780..15c5498 100644 --- a/ash/webui/personalization_app/resources/trusted/user/user_image_observer.ts +++ b/ash/webui/personalization_app/resources/trusted/user/user_image_observer.ts
@@ -4,10 +4,10 @@ import {Url} from 'chrome://resources/mojo/url/mojom/url.mojom-webui.js'; -import {UserImageObserverInterface, UserImageObserverReceiver, UserProviderInterface} from '../personalization_app.mojom-webui.js'; +import {UserImage, UserImageObserverInterface, UserImageObserverReceiver, UserProviderInterface} from '../personalization_app.mojom-webui.js'; import {PersonalizationStore} from '../personalization_store.js'; -import {setIsCameraPresentAction, setProfileImageAction, setUserImageAction} from './user_actions.js'; +import {setIsCameraPresentAction, setProfileImageAction, setUserImageAction} from './user_actions.js'; import {getUserProvider} from './user_interface_provider.js'; /** @fileoverview listens for updates on user's avatar image. */ @@ -40,7 +40,7 @@ return receiver; } - onUserImageChanged(image: Url) { + onUserImageChanged(image: UserImage) { const store = PersonalizationStore.getInstance(); store.dispatch(setUserImageAction(image)); }
diff --git a/ash/webui/personalization_app/resources/trusted/user/user_preview_element.html b/ash/webui/personalization_app/resources/trusted/user/user_preview_element.html index ee49d963..f1c45ef 100644 --- a/ash/webui/personalization_app/resources/trusted/user/user_preview_element.html +++ b/ash/webui/personalization_app/resources/trusted/user/user_preview_element.html
@@ -72,15 +72,15 @@ </style> <div id="container"> <div id="imageContainer"> - <template is="dom-if" if="[[image_]]"> + <template is="dom-if" if="[[imageUrl_]]"> <template is="dom-if" if="[[clickable]]"> <paper-ripple class="circle"></paper-ripple> - <img tabindex="0" id="avatar" src$="[[image_.url]]" + <img tabindex="0" id="avatar" src$="[[imageUrl_.url]]" on-click="onClickUserSubpageLink_" on-keypress="onClickUserSubpageLink_"> </template> <template is="dom-if" if="[[!clickable]]"> - <img id="avatar2" src$="[[image_.url]]"> + <img id="avatar2" src$="[[imageUrl_.url]]"> </template> </template> <slot></slot>
diff --git a/ash/webui/personalization_app/resources/trusted/user/user_preview_element.ts b/ash/webui/personalization_app/resources/trusted/user/user_preview_element.ts index b3c27e0..9317c66 100644 --- a/ash/webui/personalization_app/resources/trusted/user/user_preview_element.ts +++ b/ash/webui/personalization_app/resources/trusted/user/user_preview_element.ts
@@ -16,9 +16,11 @@ import {UserInfo} from '../personalization_app.mojom-webui.js'; import {Paths, PersonalizationRouter} from '../personalization_router_element.js'; import {WithPersonalizationStore} from '../personalization_store.js'; -import {initializeUserData} from '../user/user_controller.js'; -import {UserImageObserver} from '../user/user_image_observer.js'; -import {getUserProvider} from '../user/user_interface_provider.js'; + +import {initializeUserData} from './user_controller.js'; +import {UserImageObserver} from './user_image_observer.js'; +import {getUserProvider} from './user_interface_provider.js'; +import {selectUserImageUrl} from './user_selectors.js'; export class UserPreview extends WithPersonalizationStore { static get is() { @@ -35,20 +37,24 @@ type: Boolean, value: false, }, - image_: Object, info_: Object, + imageUrl_: { + type: String, + observer: 'onImageUrlChanged_', + value: null, + }, }; } - clickable: boolean; - private image_: Url|null; + public clickable: boolean; private info_: UserInfo|null; + private imageUrl_: Url|null; connectedCallback() { super.connectedCallback(); UserImageObserver.initUserImageObserverIfNeeded(); - this.watch<UserPreview['image_']>('image_', state => state.user.image); this.watch<UserPreview['info_']>('info_', state => state.user.info); + this.watch<UserPreview['imageUrl_']>('imageUrl_', selectUserImageUrl); this.updateFromStore(); initializeUserData(getUserProvider(), this.getStore()); } @@ -60,6 +66,14 @@ private onClickUserSubpageLink_() { PersonalizationRouter.instance().goToRoute(Paths.User); } + + private onImageUrlChanged_(_: Url|null, old: Url|null): void { + if (old && old.url.startsWith('blob:')) { + // Revoke old object urls to clear memory. This is safe to call multiple + // times. + URL.revokeObjectURL(old.url); + } + } } customElements.define(UserPreview.is, UserPreview);
diff --git a/ash/webui/personalization_app/resources/trusted/user/user_selectors.ts b/ash/webui/personalization_app/resources/trusted/user/user_selectors.ts new file mode 100644 index 0000000..7f1214621 --- /dev/null +++ b/ash/webui/personalization_app/resources/trusted/user/user_selectors.ts
@@ -0,0 +1,89 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import {assert} from 'chrome://resources/js/assert.m.js'; +import {BigBuffer} from 'chrome://resources/mojo/mojo/public/mojom/base/big_buffer.mojom-webui.js'; +import {Url} from 'chrome://resources/mojo/url/mojom/url.mojom-webui.js'; +import {UserImage} from '../personalization_app.mojom-webui.js'; + +import {PersonalizationState} from '../personalization_state.js'; + +/** + * @fileoverview Utility functions to derive a user image URL to display from + * |PersonalizationState|. Results are cached when necessary to avoid expensive + * re-computation. + */ + +/** + * Transforming a |BigBuffer| to a blob url is expensive. Cache results by + * reference to a |BigBuffer|. Use |WeakMap| so that old |BigBuffer| objects + * that are no longer stored in |PersonalizationState| can be garbage collected. + */ +const objectUrlCache = new WeakMap<BigBuffer, Url>(); + +function bufferToPngObjectUrl(value: BigBuffer): Url|null { + if (value.invalidBuffer) { + console.error('Invalid buffer received'); + return null; + } + + if (objectUrlCache.has(value)) { + return objectUrlCache.get(value)!; + } + + try { + let bytes: Uint8Array; + if (Array.isArray(value.bytes)) { + bytes = new Uint8Array(value.bytes); + } else { + assert(!!value.sharedMemory, 'sharedMemory must be defined here'); + const sharedMemory = value.sharedMemory!; + const {buffer, result} = + sharedMemory.bufferHandle.mapBuffer(0, sharedMemory.size); + assert(result === Mojo.RESULT_OK, 'Could not map buffer'); + bytes = new Uint8Array(buffer); + } + + const result = { + url: URL.createObjectURL(new Blob([bytes], {type: 'image/png'})) + }; + objectUrlCache.set(value, result); + return result; + + } catch (e) { + console.error('Unable to create blob from image data', e); + return null; + } +} + +/** + * Derive a user image |Url| from |PersonalizationState|. Return a |Url| rather + * than |string| to avoid copies on potentially large data URLs. + */ +export function selectUserImageUrl(state: PersonalizationState): Url|null { + const userImage = state.user.image; + + if (!userImage) { + return null; + } + + // Generated types for |userImage| are incorrect for mojom unions. Only one + // key should be present at runtime. This weird construction allows typescript + // to do exhaustiveness checking in the switch/case. + assert(Object.keys(userImage).length === 1, 'only one key is set'); + const key = Object.keys(userImage)[0] as keyof UserImage; + + switch (key) { + case 'invalidImage': + return null; + case 'defaultImage': + return userImage.defaultImage!.url; + case 'profileImage': + return state.user.profileImage; + case 'externalImage': + return bufferToPngObjectUrl(userImage.externalImage!); + } + + console.warn('Unknown image type received', key); +}
diff --git a/ash/webui/personalization_app/resources/trusted/user/user_state.ts b/ash/webui/personalization_app/resources/trusted/user/user_state.ts index e772d1f..968a298 100644 --- a/ash/webui/personalization_app/resources/trusted/user/user_state.ts +++ b/ash/webui/personalization_app/resources/trusted/user/user_state.ts
@@ -4,11 +4,11 @@ import {Url} from 'chrome://resources/mojo/url/mojom/url.mojom-webui.js'; -import {DefaultUserImage, UserInfo} from '../personalization_app.mojom-webui.js'; +import {DefaultUserImage, UserImage, UserInfo} from '../personalization_app.mojom-webui.js'; export interface UserState { defaultUserImages: Array<DefaultUserImage>|null; - image: Url|null; + image: UserImage|null; info: UserInfo|null; profileImage: Url|null; isCameraPresent: boolean;
diff --git a/ash/wm/desks/templates/desks_templates_icon_container.cc b/ash/wm/desks/templates/desks_templates_icon_container.cc index 93e4075..3cca062 100644 --- a/ash/wm/desks/templates/desks_templates_icon_container.cc +++ b/ash/wm/desks/templates/desks_templates_icon_container.cc
@@ -154,8 +154,8 @@ // Iterate through the template's WindowInfo, counting the occurrences of each // unique icon identifier and storing their lowest activation index. std::map<std::string, IconInfo> icon_identifier_to_icon_info; - for (auto& app_id_to_launch_list_entry : - restore_data->app_id_to_launch_list()) { + const auto& launch_list = restore_data->app_id_to_launch_list(); + for (auto& app_id_to_launch_list_entry : launch_list) { InsertIconIdentifierToIconInfoFromLaunchList( app_id_to_launch_list_entry.first, app_id_to_launch_list_entry.second, &icon_identifier_to_icon_info); @@ -228,6 +228,9 @@ if (used_horizontal_space <= available_horizontal_space) break; } + // Overflow icon count = the number of hidden icons + the number of + // unavailable windows + 1 to account for the overflow itself taking an + // icon. overflow_icon_view->UpdateCount(overflow_icon_view->count() + num_hidden_icons + 1); } else if (overflow_icon_view->count() == 0) { @@ -244,27 +247,39 @@ if (icon_identifier_to_icon_info.empty()) return; - for (size_t i = 0; i < kMaxIcons && i < icon_identifier_to_icon_info.size(); - ++i) { + auto* delegate = Shell::Get()->desks_templates_delegate(); + int num_hidden_icons = 0; + for (size_t i = 0; i < icon_identifier_to_icon_info.size(); ++i) { auto icon_identifier = icon_identifier_to_icon_info[i].first; auto icon_info = icon_identifier_to_icon_info[i].second; - DesksTemplatesIconView* icon_view = AddChildView( - views::Builder<DesksTemplatesIconView>() - .SetBackground(views::CreateRoundedRectBackground( - icon_info.count == 1 - ? SK_ColorTRANSPARENT - : AshColorProvider::Get()->GetControlsLayerColor( - AshColorProvider::ControlsLayerType:: - kControlBackgroundColorInactive), - DesksTemplatesIconView::kIconSize / 2)) - .Build()); - icon_view->SetIconIdentifierAndCount(icon_identifier, icon_info.app_id, - icon_info.count); + // Don't create new icons once we have reached the max, or if the app is + // unavailable (uninstalled or unsupported). Count the amount of skipped + // apps so we know what to display on the overflow. + if (children().size() < kMaxIcons && + delegate->IsAppAvailable(icon_info.app_id)) { + DesksTemplatesIconView* icon_view = AddChildView( + views::Builder<DesksTemplatesIconView>() + .SetBackground(views::CreateRoundedRectBackground( + icon_info.count == 1 + ? SK_ColorTRANSPARENT + : AshColorProvider::Get()->GetControlsLayerColor( + AshColorProvider::ControlsLayerType:: + kControlBackgroundColorInactive), + DesksTemplatesIconView::kIconSize / 2)) + .Build()); + icon_view->SetIconIdentifierAndCount(icon_identifier, icon_info.app_id, + icon_info.count, /*show_plus=*/true); + } else { + num_hidden_icons++; + } } + // If no child views were added, the icon container contains only unavailable + // apps so we should *not* show plus. + const bool show_plus = !children().empty(); + // Always add a `DesksTemplatesIconView` overflow counter in case the width // of the view changes. It will be hidden if not needed. - const int num_added_icons = children().size(); DesksTemplatesIconView* overflow_icon_view = AddChildView(views::Builder<DesksTemplatesIconView>() .SetBackground(views::CreateRoundedRectBackground( @@ -273,11 +288,12 @@ kControlBackgroundColorInactive), DesksTemplatesIconView::kIconSize / 2)) .Build()); + // Set both `icon_identifier` and `app_id` to be empty strings for overflow // icon views, since only the count should matter. overflow_icon_view->SetIconIdentifierAndCount( /*icon_identifier=*/std::string(), /*app_id=*/std::string(), - icon_identifier_to_icon_info.size() - num_added_icons); + /*count=*/num_hidden_icons, show_plus); } BEGIN_METADATA(DesksTemplatesIconContainer, views::BoxLayoutView)
diff --git a/ash/wm/desks/templates/desks_templates_icon_view.cc b/ash/wm/desks/templates/desks_templates_icon_view.cc index 15b0c3d..541f424 100644 --- a/ash/wm/desks/templates/desks_templates_icon_view.cc +++ b/ash/wm/desks/templates/desks_templates_icon_view.cc
@@ -39,9 +39,14 @@ constexpr int kAppIdImageSize = 64; // Return the formatted string for `count`. If `count` is <=9, the string will -// be "+<count>". If `count` is >9, the string will be "9+". -std::u16string GetCountString(int count) { - return base::UTF8ToUTF16(count > 9 ? "9+" : base::StringPrintf("+%i", count)); +// be "+<count>". If `count` is >9, the string will be "9+". If `show_plus` is +// true, the string will be just the count. +std::u16string GetCountString(int count, bool show_plus) { + if (show_plus) { + return base::UTF8ToUTF16(count > 9 ? "9+" + : base::StringPrintf("+%i", count)); + } + return base::NumberToString16(count); } gfx::ImageSkia CreateResizedImageToIconSize(const gfx::ImageSkia& icon) { @@ -60,7 +65,8 @@ void DesksTemplatesIconView::SetIconIdentifierAndCount( const std::string& icon_identifier, const std::string& app_id, - int count) { + int count, + bool show_plus) { icon_identifier_ = icon_identifier; count_ = count; @@ -75,7 +81,7 @@ DCHECK(!count_label_); count_label_ = AddChildView( views::Builder<views::Label>() - .SetText(GetCountString(visible_count)) + .SetText(GetCountString(visible_count, show_plus)) .SetBorder(views::CreateEmptyBorder(gfx::Insets( kCountLabelInsetSize, kCountLabelInsetSize, kCountLabelInsetSize, @@ -143,7 +149,7 @@ void DesksTemplatesIconView::UpdateCount(int count) { count_ = count; DCHECK(count_label_); - count_label_->SetText(GetCountString(count_)); + count_label_->SetText(GetCountString(count_, /*show_plus=*/true)); } gfx::Size DesksTemplatesIconView::CalculatePreferredSize() const {
diff --git a/ash/wm/desks/templates/desks_templates_icon_view.h b/ash/wm/desks/templates/desks_templates_icon_view.h index fff1a0b9..a4614f6 100644 --- a/ash/wm/desks/templates/desks_templates_icon_view.h +++ b/ash/wm/desks/templates/desks_templates_icon_view.h
@@ -45,10 +45,13 @@ // Sets `icon_identifier_` to `icon_identifier` and `count_` to `count` then // based on their values determines what views need to be created and starts - // loading the icon specified by `icon_identifier`. + // loading the icon specified by `icon_identifier`. `show_plus` indicates + // whether to show "+" before the count for normal overflow icons, or none for + // all unavailable icons. void SetIconIdentifierAndCount(const std::string& icon_identifier, const std::string& app_id, - int count); + int count, + bool show_plus); // Sets `count_` to `count` and updates the `count_label_`. void UpdateCount(int count);
diff --git a/ash/wm/desks/templates/desks_templates_unittest.cc b/ash/wm/desks/templates/desks_templates_unittest.cc index fc882d6..50574d1 100644 --- a/ash/wm/desks/templates/desks_templates_unittest.cc +++ b/ash/wm/desks/templates/desks_templates_unittest.cc
@@ -11,6 +11,7 @@ #include "ash/public/cpp/desk_template.h" #include "ash/public/cpp/desks_templates_delegate.h" #include "ash/public/cpp/rounded_image_view.h" +#include "ash/public/cpp/test/test_desks_templates_delegate.h" #include "ash/session/session_controller_impl.h" #include "ash/shelf/shelf.h" #include "ash/shelf/shelf_widget.h" @@ -1233,6 +1234,104 @@ EXPECT_FALSE(icon_views.back()->GetVisible()); } +// Test that the overflow icon counts unavailable icons when there are less than +// kMaxIcons visible in the container. +TEST_F(DesksTemplatesTest, OverflowUnavailableLessThan5Icons) { + // Create a `DeskTemplate` which has 4 apps and each app has 1 window. Set 2 + // of those app ids to be unavailable. + std::vector<int> window_info(4, 1); + AddEntry(base::GUID::GenerateRandomV4(), "template", base::Time::Now(), + CreateRestoreData(window_info)); + + // `CreateRestoreData` creates the windows with app ids of "0", "1", "2", etc. + // Set 2 of those app ids to be unavailable. + auto* delegate = static_cast<TestDesksTemplatesDelegate*>( + Shell::Get()->desks_templates_delegate()); + delegate->set_unavailable_apps({"0", "1"}); + + OpenOverviewAndShowTemplatesGrid(); + + // Get the icon views. + DesksTemplatesItemView* item_view = GetItemViewFromTemplatesGrid( + /*grid_item_index=*/0); + const std::vector<DesksTemplatesIconView*>& icon_views = + DesksTemplatesItemViewTestApi(item_view).GetIconViews(); + + // The 2 available app icons should be visible, and the overflow icon should + // contain the hidden (0) + unavailable (2) app counts. + EXPECT_EQ(3u, icon_views.size()); + + DesksTemplatesIconViewTestApi overflow_icon_view{icon_views.back()}; + EXPECT_FALSE(overflow_icon_view.icon_view()); + EXPECT_TRUE(overflow_icon_view.count_label()); + EXPECT_EQ(u"+2", overflow_icon_view.count_label()->GetText()); +} + +// Test that the overflow icon counts unavailable icons when there are more than +// kMaxIcons visible in the container, and hidden icons are also added. +TEST_F(DesksTemplatesTest, OverflowUnavailableMoreThan5Icons) { + // Create a `DeskTemplate` which has 8 apps and each app has 1 window. Set 2 + // of those app ids to be unavailable. + std::vector<int> window_info(8, 1); + AddEntry(base::GUID::GenerateRandomV4(), "template", base::Time::Now(), + CreateRestoreData(window_info)); + + // `CreateRestoreData` creates the windows with app ids of "0", "1", "2", etc. + // Set 2 of those app ids to be unavailable. + auto* delegate = static_cast<TestDesksTemplatesDelegate*>( + Shell::Get()->desks_templates_delegate()); + delegate->set_unavailable_apps({"0", "1"}); + + OpenOverviewAndShowTemplatesGrid(); + + // Get the icon views. + DesksTemplatesItemView* item_view = GetItemViewFromTemplatesGrid( + /*grid_item_index=*/0); + const std::vector<DesksTemplatesIconView*>& icon_views = + DesksTemplatesItemViewTestApi(item_view).GetIconViews(); + + // The 4 available app icons should be visible, and the overflow icon should + // contain the hidden (2) + unavailable (2) app counts. + EXPECT_EQ(5u, icon_views.size()); + + DesksTemplatesIconViewTestApi overflow_icon_view{icon_views.back()}; + EXPECT_FALSE(overflow_icon_view.icon_view()); + EXPECT_TRUE(overflow_icon_view.count_label()); + EXPECT_EQ(u"+4", overflow_icon_view.count_label()->GetText()); +} + +// Test that the overflow icon displays the count without a plus when all icons +// are unavailable. +TEST_F(DesksTemplatesTest, OverflowUnavailableAllUnavailableIcons) { + // Create a `DeskTemplate` which has 10 apps and each app has 1 window. + std::vector<int> window_info(10, 1); + AddEntry(base::GUID::GenerateRandomV4(), "template", base::Time::Now(), + CreateRestoreData(window_info)); + + // Set all 10 app ids to be unavailable. + auto* delegate = static_cast<TestDesksTemplatesDelegate*>( + Shell::Get()->desks_templates_delegate()); + delegate->set_unavailable_apps( + {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}); + + OpenOverviewAndShowTemplatesGrid(); + + // Get the icon views. + DesksTemplatesItemView* item_view = GetItemViewFromTemplatesGrid( + /*grid_item_index=*/0); + const std::vector<DesksTemplatesIconView*>& icon_views = + DesksTemplatesItemViewTestApi(item_view).GetIconViews(); + + // The only added icon view is the overflow icon, and it should have a "10" + // label without the plus sign. + EXPECT_EQ(1u, icon_views.size()); + + DesksTemplatesIconViewTestApi overflow_icon_view{icon_views.back()}; + EXPECT_FALSE(overflow_icon_view.icon_view()); + EXPECT_TRUE(overflow_icon_view.count_label()); + EXPECT_EQ(u"10", overflow_icon_view.count_label()->GetText()); +} + // Tests that the desks templates and save desk template buttons are hidden when // entering overview in tablet mode. TEST_F(DesksTemplatesTest, EnteringInTabletMode) {
diff --git a/base/BUILD.gn b/base/BUILD.gn index 4fdd470d..3a64f694 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -1683,7 +1683,6 @@ "android/task_scheduler/post_task_android.h", "android/task_scheduler/task_runner_android.cc", "android/task_scheduler/task_runner_android.h", - "android/time_utils.cc", "android/timezone_utils.cc", "android/timezone_utils.h", "android/trace_event_binding.cc", @@ -3409,8 +3408,7 @@ # TODO(crbug.com/1304253): iOS test() targets don't support mixing Rust code # yet. if (!is_ios) { - rs_crate_root = "base_unittests.rs" - rs_sources = [ "base_unittests.rs" ] + rs_sources = [] if (build_rust_json_parser) { # TODO(crbug.com/1298039): The BUILDFLAG should be used instead. @@ -4028,7 +4026,6 @@ "android/java/src/org/chromium/base/RadioUtils.java", "android/java/src/org/chromium/base/SysUtils.java", "android/java/src/org/chromium/base/ThreadUtils.java", - "android/java/src/org/chromium/base/TimeUtils.java", "android/java/src/org/chromium/base/TimezoneUtils.java", "android/java/src/org/chromium/base/TraceEvent.java", "android/java/src/org/chromium/base/UnguessableToken.java",
diff --git a/base/allocator/partition_allocator/partition_alloc_config.h b/base/allocator/partition_allocator/partition_alloc_config.h index 1fac13e..8ced44e 100644 --- a/base/allocator/partition_allocator/partition_alloc_config.h +++ b/base/allocator/partition_allocator/partition_alloc_config.h
@@ -210,10 +210,9 @@ // Smaller slot spans may improve dirty memory fragmentation, but may also // increase address space usage. // -// This is intended to roll out more broadly, but only enabled on Linux and -// ARM64 macOS for now to get performance bot and real-world data pre-A/B -// experiment. ARM64 macOS because it has a larger OS page size. -#if BUILDFLAG(IS_LINUX) || (BUILDFLAG(IS_MAC) && defined(ARCH_CPU_ARM64)) +// This is intended to roll out more broadly, but only enabled on Linux for now +// to get performance bot and real-world data pre-A/B experiment. +#if BUILDFLAG(IS_LINUX) #define PA_PREFER_SMALLER_SLOT_SPANS #endif // BUILDFLAG(IS_LINUX)
diff --git a/base/allocator/partition_allocator/spinning_mutex.h b/base/allocator/partition_allocator/spinning_mutex.h index 325f379..2ac1ca1 100644 --- a/base/allocator/partition_allocator/spinning_mutex.h +++ b/base/allocator/partition_allocator/spinning_mutex.h
@@ -134,14 +134,14 @@ #else // defined(PA_HAS_FAST_MUTEX) std::atomic<bool> lock_{false}; -#if BUILDFLAG(IS_APPLE) && !defined(PA_NO_OS_UNFAIR_LOCK_CRBUG_1267256) +#if BUILDFLAG(IS_APPLE) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunguarded-availability" os_unfair_lock unfair_lock_ = OS_UNFAIR_LOCK_INIT; #pragma clang diagnostic pop -#endif // BUILDFLAG(IS_APPLE) && !defined(PA_NO_OS_UNFAIR_LOCK_CRBUG_1267256) +#endif // BUILDFLAG(IS_APPLE) // Spinlock-like, fallback. ALWAYS_INLINE bool TrySpinLock();
diff --git a/base/android/early_trace_event_binding.cc b/base/android/early_trace_event_binding.cc index b51bb467..f9e79ef 100644 --- a/base/android/early_trace_event_binding.cc +++ b/base/android/early_trace_event_binding.cc
@@ -30,7 +30,7 @@ trace_event_internal::AddTraceEventWithThreadIdAndTimestamps( TRACE_EVENT_PHASE_BEGIN, category_group_enabled, name.c_str(), /*scope=*/nullptr, trace_event_internal::kNoId, thread_id, - TimeTicks() + Nanoseconds(time_ns), + TimeTicks::FromJavaNanoTime(time_ns), ThreadTicks() + Milliseconds(thread_time_ms), TRACE_EVENT_FLAG_JAVA_STRING_LITERALS | TRACE_EVENT_FLAG_COPY); #endif // BUILDFLAG(ENABLE_BASE_TRACING) @@ -50,7 +50,7 @@ trace_event_internal::AddTraceEventWithThreadIdAndTimestamps( TRACE_EVENT_PHASE_END, category_group_enabled, name.c_str(), /*scope=*/nullptr, trace_event_internal::kNoId, thread_id, - TimeTicks() + Nanoseconds(time_ns), + TimeTicks::FromJavaNanoTime(time_ns), ThreadTicks() + Milliseconds(thread_time_ms), TRACE_EVENT_FLAG_JAVA_STRING_LITERALS | TRACE_EVENT_FLAG_COPY); #endif // BUILDFLAG(ENABLE_BASE_TRACING) @@ -71,7 +71,7 @@ trace_event_internal::AddTraceEventWithThreadIdAndTimestamps( TRACE_EVENT_PHASE_BEGIN, category_group_enabled, name.c_str(), /*scope=*/nullptr, trace_event_internal::kNoId, thread_id, - TimeTicks() + Nanoseconds(time_ns), + TimeTicks::FromJavaNanoTime(time_ns), ThreadTicks() + Milliseconds(thread_time_ms), TRACE_EVENT_FLAG_JAVA_STRING_LITERALS | TRACE_EVENT_FLAG_COPY); #endif // BUILDFLAG(ENABLE_BASE_TRACING) @@ -92,7 +92,7 @@ trace_event_internal::AddTraceEventWithThreadIdAndTimestamps( TRACE_EVENT_PHASE_END, category_group_enabled, name.c_str(), /*scope=*/nullptr, trace_event_internal::kNoId, thread_id, - TimeTicks() + Nanoseconds(time_ns), + TimeTicks::FromJavaNanoTime(time_ns), ThreadTicks() + Milliseconds(thread_time_ms), TRACE_EVENT_FLAG_JAVA_STRING_LITERALS | TRACE_EVENT_FLAG_COPY); #endif // BUILDFLAG(ENABLE_BASE_TRACING) @@ -102,12 +102,12 @@ JNIEnv* env, const JavaParamRef<jstring>& jname, jlong id, - jlong timestamp_ns) { + jlong time_ns) { std::string name = ConvertJavaStringToUTF8(env, jname); TRACE_EVENT_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP_AND_FLAGS0( internal::kJavaTraceCategory, name.c_str(), TRACE_ID_LOCAL(id), - base::TimeTicks() + base::Nanoseconds(timestamp_ns), + TimeTicks::FromJavaNanoTime(time_ns), TRACE_EVENT_FLAG_JAVA_STRING_LITERALS | TRACE_EVENT_FLAG_COPY); } @@ -115,12 +115,12 @@ JNIEnv* env, const JavaParamRef<jstring>& jname, jlong id, - jlong timestamp_ns) { + jlong time_ns) { std::string name = ConvertJavaStringToUTF8(env, jname); TRACE_EVENT_NESTABLE_ASYNC_END_WITH_TIMESTAMP_AND_FLAGS0( internal::kJavaTraceCategory, name.c_str(), TRACE_ID_LOCAL(id), - base::TimeTicks() + base::Nanoseconds(timestamp_ns), + TimeTicks::FromJavaNanoTime(time_ns), TRACE_EVENT_FLAG_JAVA_STRING_LITERALS | TRACE_EVENT_FLAG_COPY); }
diff --git a/base/android/java/src/org/chromium/base/EarlyTraceEvent.java b/base/android/java/src/org/chromium/base/EarlyTraceEvent.java index a5bf993..32e972e7 100644 --- a/base/android/java/src/org/chromium/base/EarlyTraceEvent.java +++ b/base/android/java/src/org/chromium/base/EarlyTraceEvent.java
@@ -55,7 +55,7 @@ mIsToplevel = isToplevel; mName = name; mThreadId = Process.myTid(); - mTimeNanos = SystemClock.elapsedRealtimeNanos(); + mTimeNanos = System.nanoTime(); // Same timebase as TimeTicks::Now(). mThreadTimeMillis = SystemClock.currentThreadTimeMillis(); } } @@ -65,13 +65,13 @@ final boolean mIsStart; final String mName; final long mId; - final long mTimestampNanos; + final long mTimeNanos; AsyncEvent(String name, long id, boolean isStart) { mName = name; mId = id; mIsStart = isStart; - mTimestampNanos = SystemClock.elapsedRealtimeNanos(); + mTimeNanos = System.nanoTime(); // Same timebase as TimeTicks::Now(). } } @@ -315,46 +315,37 @@ } private static void dumpEvents(List<Event> events) { - long offsetNanos = getOffsetNanos(); for (Event e : events) { if (e.mIsStart) { if (e.mIsToplevel) { EarlyTraceEventJni.get().recordEarlyToplevelBeginEvent( - e.mName, e.mTimeNanos + offsetNanos, e.mThreadId, e.mThreadTimeMillis); + e.mName, e.mTimeNanos, e.mThreadId, e.mThreadTimeMillis); } else { EarlyTraceEventJni.get().recordEarlyBeginEvent( - e.mName, e.mTimeNanos + offsetNanos, e.mThreadId, e.mThreadTimeMillis); + e.mName, e.mTimeNanos, e.mThreadId, e.mThreadTimeMillis); } } else { if (e.mIsToplevel) { EarlyTraceEventJni.get().recordEarlyToplevelEndEvent( - e.mName, e.mTimeNanos + offsetNanos, e.mThreadId, e.mThreadTimeMillis); + e.mName, e.mTimeNanos, e.mThreadId, e.mThreadTimeMillis); } else { EarlyTraceEventJni.get().recordEarlyEndEvent( - e.mName, e.mTimeNanos + offsetNanos, e.mThreadId, e.mThreadTimeMillis); + e.mName, e.mTimeNanos, e.mThreadId, e.mThreadTimeMillis); } } } } + private static void dumpAsyncEvents(List<AsyncEvent> events) { - long offsetNanos = getOffsetNanos(); for (AsyncEvent e : events) { if (e.mIsStart) { - EarlyTraceEventJni.get().recordEarlyAsyncBeginEvent( - e.mName, e.mId, e.mTimestampNanos + offsetNanos); + EarlyTraceEventJni.get().recordEarlyAsyncBeginEvent(e.mName, e.mId, e.mTimeNanos); } else { - EarlyTraceEventJni.get().recordEarlyAsyncEndEvent( - e.mName, e.mId, e.mTimestampNanos + offsetNanos); + EarlyTraceEventJni.get().recordEarlyAsyncEndEvent(e.mName, e.mId, e.mTimeNanos); } } } - private static long getOffsetNanos() { - long nativeNowNanos = TimeUtilsJni.get().getTimeTicksNowUs() * 1000; - long javaNowNanos = SystemClock.elapsedRealtimeNanos(); - return nativeNowNanos - javaNowNanos; - } - @NativeMethods interface Natives { void recordEarlyBeginEvent(String name, long timeNanos, int threadId, long threadMillis); @@ -363,7 +354,7 @@ String name, long timeNanos, int threadId, long threadMillis); void recordEarlyToplevelEndEvent( String name, long timeNanos, int threadId, long threadMillis); - void recordEarlyAsyncBeginEvent(String name, long id, long timestamp); - void recordEarlyAsyncEndEvent(String name, long id, long timestamp); + void recordEarlyAsyncBeginEvent(String name, long id, long timeNanos); + void recordEarlyAsyncEndEvent(String name, long id, long timeNanos); } }
diff --git a/base/android/java/src/org/chromium/base/TimeUtils.java b/base/android/java/src/org/chromium/base/TimeUtils.java index 32f9b27c..b14094d 100644 --- a/base/android/java/src/org/chromium/base/TimeUtils.java +++ b/base/android/java/src/org/chromium/base/TimeUtils.java
@@ -4,12 +4,9 @@ package org.chromium.base; -import org.chromium.base.annotations.JNINamespace; import org.chromium.base.annotations.MainDex; -import org.chromium.base.annotations.NativeMethods; /** Time-related utilities. */ -@JNINamespace("base::android") @MainDex public class TimeUtils { private TimeUtils() {} @@ -19,12 +16,4 @@ public static final int SECONDS_PER_MINUTE = 60; public static final int SECONDS_PER_HOUR = 3600; // 60 sec * 60 min public static final int SECONDS_PER_DAY = 86400; - - @NativeMethods - public interface Natives { - // 60 sec * 60 min * 24 h - - /** Returns TimeTicks::Now() in microseconds. */ - long getTimeTicksNowUs(); - } }
diff --git a/base/android/javatests/src/org/chromium/base/EarlyTraceEventTest.java b/base/android/javatests/src/org/chromium/base/EarlyTraceEventTest.java index 8e417612..f9513051 100644 --- a/base/android/javatests/src/org/chromium/base/EarlyTraceEventTest.java +++ b/base/android/javatests/src/org/chromium/base/EarlyTraceEventTest.java
@@ -96,9 +96,9 @@ Assert.assertEquals(EVENT_ID, eventStart.mId); Assert.assertEquals(EVENT_NAME, eventEnd.mName); Assert.assertEquals(EVENT_ID, eventEnd.mId); - Assert.assertTrue(beforeNanos <= eventStart.mTimestampNanos - && eventEnd.mTimestampNanos <= afterNanos); - Assert.assertTrue(eventStart.mTimestampNanos <= eventEnd.mTimestampNanos); + Assert.assertTrue( + beforeNanos <= eventStart.mTimeNanos && eventEnd.mTimeNanos <= afterNanos); + Assert.assertTrue(eventStart.mTimeNanos <= eventEnd.mTimeNanos); } @Test
diff --git a/base/android/time_utils.cc b/base/android/time_utils.cc deleted file mode 100644 index 08199c1..0000000 --- a/base/android/time_utils.cc +++ /dev/null
@@ -1,18 +0,0 @@ -// Copyright 2016 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 <stdint.h> - -#include "base/base_jni_headers/TimeUtils_jni.h" -#include "base/time/time.h" - -namespace base { -namespace android { - -static jlong JNI_TimeUtils_GetTimeTicksNowUs(JNIEnv* env) { - return (TimeTicks::Now() - TimeTicks()).InMicroseconds(); -} - -} // namespace android -} // namespace base
diff --git a/base/cxx17_backports.h b/base/cxx17_backports.h index c5e77f7..da406aa 100644 --- a/base/cxx17_backports.h +++ b/base/cxx17_backports.h
@@ -5,11 +5,7 @@ #ifndef BASE_CXX17_BACKPORTS_H_ #define BASE_CXX17_BACKPORTS_H_ -#include <array> #include <functional> -#include <initializer_list> -#include <memory> -#include <string> #include <tuple> #include <type_traits> #include <utility>
diff --git a/base/test/trace_event_analyzer.cc b/base/test/trace_event_analyzer.cc index b8034dc..9da67a3 100644 --- a/base/test/trace_event_analyzer.cc +++ b/base/test/trace_event_analyzer.cc
@@ -229,6 +229,16 @@ return false; } +bool TraceEvent::GetArgAsDict(const std::string& arg_name, + base::Value::Dict* arg) const { + const auto it = arg_values.find(arg_name); + if (it != arg_values.end() && it->second.is_dict()) { + *arg = it->second.GetDict().Clone(); + return true; + } + return false; +} + bool TraceEvent::GetArgAsValue(const std::string& arg_name, base::Value* arg) const { const auto it = arg_values.find(arg_name); @@ -247,6 +257,11 @@ return (arg_numbers.find(arg_name) != arg_numbers.end()); } +bool TraceEvent::HasDictArg(const std::string& arg_name) const { + const auto it = arg_values.find(arg_name); + return (it != arg_values.end() && it->second.is_dict()); +} + bool TraceEvent::HasArg(const std::string& arg_name) const { return (arg_values.find(arg_name) != arg_values.end()); } @@ -279,6 +294,14 @@ return (arg_double != 0.0); } +base::Value::Dict TraceEvent::GetKnownArgAsDict( + const std::string& arg_name) const { + base::Value::Dict arg_dict; + bool result = GetArgAsDict(arg_name, &arg_dict); + DCHECK(result); + return arg_dict; +} + base::Value TraceEvent::GetKnownArgAsValue(const std::string& arg_name) const { base::Value arg_value; bool result = GetArgAsValue(arg_name, &arg_value);
diff --git a/base/test/trace_event_analyzer.h b/base/test/trace_event_analyzer.h index d4c36b76..cb68df06 100644 --- a/base/test/trace_event_analyzer.h +++ b/base/test/trace_event_analyzer.h
@@ -150,6 +150,8 @@ bool GetArgAsString(const std::string& arg_name, std::string* arg) const; // Return the argument value if it exists and it is a number. bool GetArgAsNumber(const std::string& arg_name, double* arg) const; + // Return the argument value if it exists and is a dictionary. + bool GetArgAsDict(const std::string& arg_name, base::Value::Dict* arg) const; // Return the argument value if it exists. bool GetArgAsValue(const std::string& arg_name, base::Value* arg) const; @@ -157,6 +159,8 @@ bool HasStringArg(const std::string& arg_name) const; // Check if argument exists and is number (double, int or bool). bool HasNumberArg(const std::string& arg_name) const; + // Check if argument exists and is a dictionary. + bool HasDictArg(const std::string& arg_name) const; // Check if argument exists. bool HasArg(const std::string& arg_name) const; @@ -167,6 +171,7 @@ double GetKnownArgAsDouble(const std::string& arg_name) const; int GetKnownArgAsInt(const std::string& arg_name) const; bool GetKnownArgAsBool(const std::string& arg_name) const; + base::Value::Dict GetKnownArgAsDict(const std::string& arg_name) const; base::Value GetKnownArgAsValue(const std::string& arg_name) const; // Process ID and Thread ID.
diff --git a/base/test/trace_event_analyzer_unittest.cc b/base/test/trace_event_analyzer_unittest.cc index ad3ef32b..68cb1f2 100644 --- a/base/test/trace_event_analyzer_unittest.cc +++ b/base/test/trace_event_analyzer_unittest.cc
@@ -96,13 +96,16 @@ double double_num = 3.5; const char str[] = "the string"; + base::Value::Dict dict; + dict.Set("the key", "the value"); + TraceEvent event; event.arg_numbers["false"] = 0.0; event.arg_numbers["true"] = 1.0; event.arg_numbers["int"] = static_cast<double>(int_num); event.arg_numbers["double"] = double_num; event.arg_strings["string"] = str; - event.arg_values["dict"] = base::Value(base::Value::Type::DICTIONARY); + event.arg_values["dict"] = base::Value(dict.Clone()); ASSERT_TRUE(event.HasNumberArg("false")); ASSERT_TRUE(event.HasNumberArg("true")); @@ -111,7 +114,7 @@ ASSERT_TRUE(event.HasStringArg("string")); ASSERT_FALSE(event.HasNumberArg("notfound")); ASSERT_FALSE(event.HasStringArg("notfound")); - ASSERT_TRUE(event.HasArg("dict")); + ASSERT_TRUE(event.HasDictArg("dict")); ASSERT_FALSE(event.HasArg("notfound")); EXPECT_FALSE(event.GetKnownArgAsBool("false")); @@ -119,10 +122,60 @@ EXPECT_EQ(int_num, event.GetKnownArgAsInt("int")); EXPECT_EQ(double_num, event.GetKnownArgAsDouble("double")); EXPECT_STREQ(str, event.GetKnownArgAsString("string").c_str()); + EXPECT_EQ(dict, event.GetKnownArgAsDict("dict")); +} - base::Value arg; - EXPECT_TRUE(event.GetArgAsValue("dict", &arg)); - EXPECT_EQ(base::Value::Type::DICTIONARY, arg.type()); +TEST_F(TraceEventAnalyzerTest, TraceEventArgsAsValues) { + ManualSetUp(); + + int int_num = 2; + double double_num = 3.5; + const char str[] = "the string"; + + base::Value::Dict dict; + dict.Set("the key", "the value"); + + BeginTracing(); + { + TRACE_EVENT_INSTANT1("cat", "name", TRACE_EVENT_SCOPE_THREAD, "int", + int_num); + TRACE_EVENT_INSTANT1("cat", "name", TRACE_EVENT_SCOPE_THREAD, "double", + double_num); + TRACE_EVENT_INSTANT1("cat", "name", TRACE_EVENT_SCOPE_THREAD, "true", true); + TRACE_EVENT_INSTANT1("cat", "name", TRACE_EVENT_SCOPE_THREAD, "string", + str); + + std::unique_ptr<base::trace_event::TracedValue> value( + new base::trace_event::TracedValue); + value->SetString("the key", "the value"); + TRACE_EVENT_INSTANT1("cat", "name", TRACE_EVENT_SCOPE_THREAD, "dict", + std::move(value)); + } + EndTracing(); + + std::unique_ptr<TraceAnalyzer> analyzer( + TraceAnalyzer::Create(output_.json_output)); + ASSERT_TRUE(analyzer.get()); + + TraceEventVector events; + analyzer->FindEvents(Query::EventName() == Query::String("name"), &events); + + ASSERT_EQ(5u, events.size()); + ASSERT_TRUE(events[0]->HasArg("int")); + EXPECT_EQ(base::Value(int_num), events[0]->GetKnownArgAsValue("int")); + + ASSERT_TRUE(events[1]->HasArg("double")); + EXPECT_EQ(base::Value(double_num), events[1]->GetKnownArgAsValue("double")); + + ASSERT_TRUE(events[2]->HasArg("true")); + EXPECT_EQ(base::Value(true), events[2]->GetKnownArgAsValue("true")); + + ASSERT_TRUE(events[3]->HasArg("string")); + EXPECT_EQ(base::Value(str), events[3]->GetKnownArgAsValue("string")); + + ASSERT_TRUE(events[4]->HasArg("dict")); + EXPECT_EQ(base::Value(std::move(dict)), + events[4]->GetKnownArgAsValue("dict")); } TEST_F(TraceEventAnalyzerTest, QueryEventMember) { @@ -953,13 +1006,11 @@ EXPECT_EQ(1u, events.size()); EXPECT_EQ("cat", events[0]->category); EXPECT_EQ("name", events[0]->name); - EXPECT_TRUE(events[0]->HasArg("arg")); - base::Value arg; - events[0]->GetArgAsValue("arg", &arg); - ASSERT_TRUE(arg.is_dict()); + ASSERT_TRUE(events[0]->HasDictArg("arg")); + base::Value::Dict arg = events[0]->GetKnownArgAsDict("arg"); EXPECT_EQ(absl::optional<std::string>("value"), - base::OptionalFromPtr(arg.FindStringKey("property"))); + base::OptionalFromPtr(arg.FindString("property"))); } } // namespace trace_analyzer
diff --git a/base/time/time.h b/base/time/time.h index c027aab..a2fc56f8 100644 --- a/base/time/time.h +++ b/base/time/time.h
@@ -1012,11 +1012,34 @@ #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH) // Converts to TimeTicks the value obtained from SystemClock.uptimeMillis(). - // Note: this convertion may be non-monotonic in relation to previously + // Note: this conversion may be non-monotonic in relation to previously // obtained TimeTicks::Now() values because of the truncation (to // milliseconds) performed by uptimeMillis(). static TimeTicks FromUptimeMillis(int64_t uptime_millis_value); -#endif + +#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH) + +#if BUILDFLAG(IS_ANDROID) + // Converts to TimeTicks the value obtained from System.nanoTime(). This + // conversion will be monotonic in relation to previously obtained + // TimeTicks::Now() values as the clocks are based on the same posix monotonic + // clock, with nanoTime() potentially providing higher resolution. + static TimeTicks FromJavaNanoTime(int64_t nano_time_value); + + // Truncates the TimeTicks value to the precision of SystemClock#uptimeMillis. + // Note that the clocks already share the same monotonic clock source. + jlong ToUptimeMillis() const; + + // Returns the TimeTicks value as microseconds in the timebase of + // SystemClock#uptimeMillis. + // Note that the clocks already share the same monotonic clock source. + // + // System.nanoTime() may be used to get sub-millisecond precision in Java code + // and may be compared against this value as the two share the same clock + // source (though be sure to convert nanos to micros). + jlong ToUptimeMicros() const; + +#endif // BUILDFLAG(IS_ANDROID) // Get an estimate of the TimeTick value at the time of the UnixEpoch. Because // Time and TimeTicks respond differently to user-set time and NTP
diff --git a/base/time/time_android.cc b/base/time/time_android.cc index 72911d8..2215f096 100644 --- a/base/time/time_android.cc +++ b/base/time/time_android.cc
@@ -23,4 +23,43 @@ return TimeTicks(uptime_millis_value * Time::kMicrosecondsPerMillisecond); } +// This file is included on chromeos_ash because it needs to interpret +// UptimeMillis values from the Android container. +#if BUILDFLAG(IS_ANDROID) + +// static +TimeTicks TimeTicks::FromJavaNanoTime(int64_t nano_time_value) { + // The implementation of the System.nanoTime() in AOSP uses the same + // clock as UptimeMillis() and base::TimeTicks::Now(): + // clock_gettime(CLOCK_MONOTONIC), see ojluni/src/main/native/System.c in + // AOSP. + // + // From Android documentation on android.os.SystemClock: + // [uptimeMillis()] is the basis for most interval timing such as + // Thread.sleep(millls), Object.wait(millis), and System.nanoTime(). + // + // We are not aware of any motivations for Android OEMs to modify the AOSP + // implementation of either uptimeMillis(), nanoTime, or + // clock_gettime(CLOCK_MONOTONIC), so we assume that there are no such + // customizations. + // + // Under these assumptions the conversion is as safe as copying the value of + // base::TimeTicks::Now() without the (theoretical) sub-microsecond + // resolution. + return TimeTicks(nano_time_value / Time::kNanosecondsPerMicrosecond); +} + +jlong TimeTicks::ToUptimeMillis() const { + // See FromUptimeMillis. UptimeMillis and TimeTicks use the same clock source, + // and only differ in resolution. + return us_ / Time::kMicrosecondsPerMillisecond; +} + +jlong TimeTicks::ToUptimeMicros() const { + // Same as ToUptimeMillis but maintains sub-millisecond precision. + return us_; +} + +#endif // BUILDFLAG(IS_ANDROID) + } // namespace base
diff --git a/base/time/time_unittest.cc b/base/time/time_unittest.cc index 92971a9..d22b50a 100644 --- a/base/time/time_unittest.cc +++ b/base/time/time_unittest.cc
@@ -1485,7 +1485,7 @@ android::MethodID::Get<android::MethodID::TYPE_STATIC>( env, clazz.obj(), "uptimeMillis", "()J"); ASSERT_FALSE(!method_id); - // Subtract 1ms from the expected lower bound to allow millisecon-level + // Subtract 1ms from the expected lower bound to allow millisecond-level // truncation performed in uptimeMillis(). const TimeTicks lower_bound_ticks = TimeTicks::Now() - Milliseconds(1); const TimeTicks converted_ticks = TimeTicks::FromUptimeMillis( @@ -1494,6 +1494,25 @@ EXPECT_LE(lower_bound_ticks, converted_ticks); EXPECT_GE(upper_bound_ticks, converted_ticks); } + +TEST(TimeTicks, Android_FromJavaNanoTime_ClocksMatch) { + JNIEnv* const env = android::AttachCurrentThread(); + android::ScopedJavaLocalRef<jclass> clazz( + android::GetClass(env, "java/lang/System")); + ASSERT_TRUE(clazz.obj()); + const jmethodID method_id = + android::MethodID::Get<android::MethodID::TYPE_STATIC>(env, clazz.obj(), + "nanoTime", "()J"); + ASSERT_FALSE(!method_id); + const TimeTicks lower_bound_ticks = TimeTicks::Now(); + const TimeTicks converted_ticks = TimeTicks::FromJavaNanoTime( + env->CallStaticLongMethod(clazz.obj(), method_id)); + // Add 1us to the expected upper bound to allow microsecond-level + // truncation performed in TimeTicks::Now(). + const TimeTicks upper_bound_ticks = TimeTicks::Now() + Microseconds(1); + EXPECT_LE(lower_bound_ticks, converted_ticks); + EXPECT_GE(upper_bound_ticks, converted_ticks); +} #endif // BUILDFLAG(IS_ANDROID) TEST(TimeDelta, FromAndIn) {
diff --git a/build/android/PRESUBMIT.py b/build/android/PRESUBMIT.py index 89812fb..0dd9024 100644 --- a/build/android/PRESUBMIT.py +++ b/build/android/PRESUBMIT.py
@@ -93,7 +93,6 @@ input_api, output_api, unit_tests=[ - J('.', 'convert_dex_profile_tests.py'), J('.', 'emma_coverage_stats_test.py'), J('.', 'list_class_verification_failures_test.py'), J('pylib', 'constants', 'host_paths_unittest.py'),
diff --git a/build/android/apk_operations.pydeps b/build/android/apk_operations.pydeps index 86604a47..1db6059 100644 --- a/build/android/apk_operations.pydeps +++ b/build/android/apk_operations.pydeps
@@ -89,7 +89,6 @@ ../print_python_deps.py adb_command_line.py apk_operations.py -convert_dex_profile.py devil_chromium.py gyp/bundletool.py gyp/dex.py
diff --git a/build/android/gyp/dex.py b/build/android/gyp/dex.py index ba90872..9252a0a 100755 --- a/build/android/gyp/dex.py +++ b/build/android/gyp/dex.py
@@ -18,10 +18,6 @@ from util import md5_check from util import zipalign -sys.path.insert(1, os.path.join(os.path.dirname(__file__), os.path.pardir)) - -import convert_dex_profile - _DEX_XMX = '2G' # Increase this when __final_dex OOMs. @@ -136,37 +132,8 @@ action='store_true', help='Use when filing D8 bugs to capture inputs.' ' Stores inputs to d8inputs.zip') - - group = parser.add_argument_group('Dexlayout') - group.add_argument( - '--dexlayout-profile', - help=('Text profile for dexlayout. If present, a dexlayout ' - 'pass will happen')) - group.add_argument( - '--profman-path', - help=('Path to ART profman binary. There should be a lib/ directory at ' - 'the same path with shared libraries (shared with dexlayout).')) - group.add_argument( - '--dexlayout-path', - help=('Path to ART dexlayout binary. There should be a lib/ directory at ' - 'the same path with shared libraries (shared with dexlayout).')) - group.add_argument('--dexdump-path', help='Path to dexdump binary.') - group.add_argument( - '--proguard-mapping-path', - help=('Path to proguard map from obfuscated symbols in the jar to ' - 'unobfuscated symbols present in the code. If not present, the jar ' - 'is assumed not to be obfuscated.')) - options = parser.parse_args(args) - if options.dexlayout_profile: - build_utils.CheckOptions( - options, - parser, - required=('profman_path', 'dexlayout_path', 'dexdump_path')) - elif options.proguard_mapping_path is not None: - parser.error('Unexpected proguard mapping without dexlayout') - if options.main_dex_rules_path and not options.multi_dex: parser.error('--main-dex-rules-path is unused if multidex is not enabled') @@ -244,128 +211,6 @@ fail_on_output=warnings_as_errors) -def _EnvWithArtLibPath(binary_path): - """Return an environment dictionary for ART host shared libraries. - - Args: - binary_path: the path to an ART host binary. - - Returns: - An environment dictionary where LD_LIBRARY_PATH has been augmented with the - shared library path for the binary. This assumes that there is a lib/ - directory in the same location as the binary. - """ - lib_path = os.path.join(os.path.dirname(binary_path), 'lib') - env = os.environ.copy() - libraries = [l for l in env.get('LD_LIBRARY_PATH', '').split(':') if l] - libraries.append(lib_path) - env['LD_LIBRARY_PATH'] = ':'.join(libraries) - return env - - -def _CreateBinaryProfile(text_profile, input_dex, profman_path, temp_dir): - """Create a binary profile for dexlayout. - - Args: - text_profile: The ART text profile that will be converted to a binary - profile. - input_dex: The input dex file to layout. - profman_path: Path to the profman binary. - temp_dir: Directory to work in. - - Returns: - The name of the binary profile, which will live in temp_dir. - """ - binary_profile = os.path.join( - temp_dir, 'binary_profile-for-' + os.path.basename(text_profile)) - open(binary_profile, 'w').close() # Touch binary_profile. - profman_cmd = [profman_path, - '--apk=' + input_dex, - '--dex-location=' + input_dex, - '--create-profile-from=' + text_profile, - '--reference-profile-file=' + binary_profile] - build_utils.CheckOutput( - profman_cmd, - env=_EnvWithArtLibPath(profman_path), - stderr_filter=lambda output: - build_utils.FilterLines(output, '|'.join( - [r'Could not find (method_id|proto_id|name):', - r'Could not create type list']))) - return binary_profile - - -def _LayoutDex(binary_profile, input_dex, dexlayout_path, temp_dir): - """Layout a dexfile using a profile. - - Args: - binary_profile: An ART binary profile, eg output from _CreateBinaryProfile. - input_dex: The dex file used to create the binary profile. - dexlayout_path: Path to the dexlayout binary. - temp_dir: Directory to work in. - - Returns: - List of output files produced by dexlayout. This will be one if the input - was a single dexfile, or multiple files if the input was a multidex - zip. These output files are located in temp_dir. - """ - dexlayout_output_dir = os.path.join(temp_dir, 'dexlayout_output') - os.mkdir(dexlayout_output_dir) - dexlayout_cmd = [ dexlayout_path, - '-u', # Update checksum - '-p', binary_profile, - '-w', dexlayout_output_dir, - input_dex ] - build_utils.CheckOutput( - dexlayout_cmd, - env=_EnvWithArtLibPath(dexlayout_path), - stderr_filter=lambda output: - build_utils.FilterLines(output, - r'Can.t mmap dex file.*please zipalign')) - output_files = os.listdir(dexlayout_output_dir) - if not output_files: - raise Exception('dexlayout unexpectedly produced no output') - return sorted([os.path.join(dexlayout_output_dir, f) for f in output_files]) - - -def _ZipMultidex(file_dir, dex_files): - """Zip dex files into a multidex. - - Args: - file_dir: The directory into which to write the output. - dex_files: The dexfiles forming the multizip. Their names must end with - classes.dex, classes2.dex, ... - - Returns: - The name of the multidex file, which will live in file_dir. - """ - ordered_files = [] # List of (archive name, file name) - for f in dex_files: - if f.endswith('dex.jar'): - ordered_files.append(('classes.dex', f)) - break - if not ordered_files: - raise Exception('Could not find classes.dex multidex file in %s' % - dex_files) - for dex_idx in range(2, len(dex_files) + 1): - archive_name = 'classes%d.dex' % dex_idx - for f in dex_files: - if f.endswith(archive_name): - ordered_files.append((archive_name, f)) - break - else: - raise Exception('Could not find classes%d.dex multidex file in %s' % - dex_files) - if len(set(f[1] for f in ordered_files)) != len(ordered_files): - raise Exception('Unexpected clashing filenames for multidex in %s' % - dex_files) - - zip_name = os.path.join(file_dir, 'multidex_classes.zip') - build_utils.DoZip(((archive_name, os.path.join(file_dir, file_name)) - for archive_name, file_name in ordered_files), - zip_name) - return zip_name - - def _ZipAligned(dex_files, output_path): """Creates a .dex.jar with 4-byte aligned files. @@ -379,30 +224,6 @@ zipalign.AddToZipHermetic(z, name, src_path=dex_file, alignment=4) -def _PerformDexlayout(tmp_dir, tmp_dex_output, options): - if options.proguard_mapping_path is not None: - matching_profile = os.path.join(tmp_dir, 'obfuscated_profile') - convert_dex_profile.ObfuscateProfile( - options.dexlayout_profile, tmp_dex_output, - options.proguard_mapping_path, options.dexdump_path, matching_profile) - else: - logging.warning('No obfuscation for %s', options.dexlayout_profile) - matching_profile = options.dexlayout_profile - binary_profile = _CreateBinaryProfile(matching_profile, tmp_dex_output, - options.profman_path, tmp_dir) - output_files = _LayoutDex(binary_profile, tmp_dex_output, - options.dexlayout_path, tmp_dir) - if len(output_files) > 1: - return _ZipMultidex(tmp_dir, output_files) - - if zipfile.is_zipfile(output_files[0]): - return output_files[0] - - final_output = os.path.join(tmp_dir, 'dex_classes.zip') - _ZipAligned(output_files, final_output) - return final_output - - def _CreateFinalDex(d8_inputs, output, tmp_dir, dex_cmd, options=None): tmp_dex_output = os.path.join(tmp_dir, 'tmp_dex_output.zip') needs_dexing = not all(f.endswith('.dex') for f in d8_inputs) @@ -433,9 +254,6 @@ _ZipAligned(sorted(d8_inputs), tmp_dex_output) logging.debug('Quick-zipped %d files', len(d8_inputs)) - if options and options.dexlayout_profile: - tmp_dex_output = _PerformDexlayout(tmp_dir, tmp_dex_output, options) - # The dex file is complete and can be moved out of tmp_dir. shutil.move(tmp_dex_output, output)
diff --git a/build/android/gyp/dex.pydeps b/build/android/gyp/dex.pydeps index 23856f3c..f4162643 100644 --- a/build/android/gyp/dex.pydeps +++ b/build/android/gyp/dex.pydeps
@@ -2,7 +2,6 @@ # build/print_python_deps.py --root build/android/gyp --output build/android/gyp/dex.pydeps build/android/gyp/dex.py ../../gn_helpers.py ../../print_python_deps.py -../convert_dex_profile.py dex.py util/__init__.py util/build_utils.py
diff --git a/build/android/gyp/proguard.py b/build/android/gyp/proguard.py index 7260d8f..68fe6b0 100755 --- a/build/android/gyp/proguard.py +++ b/build/android/gyp/proguard.py
@@ -16,10 +16,12 @@ import dex import dex_jdk_libs -from pylib.dex import dex_parser from util import build_utils from util import diff_utils +sys.path.insert(1, os.path.dirname(os.path.dirname(__file__))) +from pylib.dex import dex_parser + _API_LEVEL_VERSION_CODE = [ (21, 'L'), (22, 'LollipopMR1'),
diff --git a/build/android/gyp/proguard.pydeps b/build/android/gyp/proguard.pydeps index c1de73b5..ebb536b 100644 --- a/build/android/gyp/proguard.pydeps +++ b/build/android/gyp/proguard.pydeps
@@ -2,7 +2,6 @@ # build/print_python_deps.py --root build/android/gyp --output build/android/gyp/proguard.pydeps build/android/gyp/proguard.py ../../gn_helpers.py ../../print_python_deps.py -../convert_dex_profile.py ../pylib/__init__.py ../pylib/dex/__init__.py ../pylib/dex/dex_parser.py
diff --git a/build/android/test_runner.pydeps b/build/android/test_runner.pydeps index 9e3a5d7..889465e 100644 --- a/build/android/test_runner.pydeps +++ b/build/android/test_runner.pydeps
@@ -141,7 +141,6 @@ ../util/lib/results/__init__.py ../util/lib/results/result_sink.py ../util/lib/results/result_types.py -convert_dex_profile.py devil_chromium.py gyp/dex.py gyp/util/__init__.py
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni index 0651e6b..aafaab2 100644 --- a/build/config/android/internal_rules.gni +++ b/build/config/android/internal_rules.gni
@@ -87,53 +87,6 @@ _desugar_jdk_libs_configuration_jar = "//third_party/android_deps/libs/com_android_tools_desugar_jdk_libs_configuration/desugar_jdk_libs_configuration-1.1.5.jar" _desugar_runtime_jar = "$root_build_dir/obj/third_party/bazel/desugar/Desugar_runtime.processed.jar" -_dexdump_path = "$android_sdk_build_tools/dexdump" -_dexlayout_path = "//third_party/android_build_tools/art/dexlayout" -_profman_path = "//third_party/android_build_tools/art/profman" -_art_lib_file_names = [ - "libartbase.so", - "libart-compiler.so", - "libart-dexlayout.so", - "libart-disassembler.so", - "libart-gtest.so", - "libart.so", - "libbacktrace.so", - "libbase.so", - "libcrypto-host.so", - "libc++.so", - "libcutils.so", - "libdexfile.so", - "libexpat-host.so", - "libicui18n-host.so", - "libicuuc-host.so", - "libjavacore.so", - "libjavacrypto.so", - "liblog.so", - "liblz4.so", - "liblzma.so", - "libnativebridge.so", - "libnativehelper.so", - "libnativeloader.so", - "libopenjdkjvm.so", - "libopenjdkjvmti.so", - "libopenjdk.so", - "libprofile.so", - "libsigchain.so", - "libssl-host.so", - "libunwindstack.so", - "libvixl-arm64.so", - "libvixl-arm.so", - "libvixld-arm64.so", - "libvixld-arm.so", - "libz-host.so", - "libziparchive.so", - "slicer.so", -] -_default_art_libs = [] -foreach(lib, _art_lib_file_names) { - _default_art_libs += [ "//third_party/android_build_tools/art/lib/$lib" ] -} - # Put the bug number in the target name so that false-positives have a hint in # the error message about why non-existent dependencies are there. build_config_target_suffix = "__build_config_crbug_908819" @@ -1689,26 +1642,6 @@ args += [ "--class-inputs=${_rebased_input_class_jars}" ] } - if (defined(invoker.dexlayout_profile)) { - args += [ - "--dexlayout-profile", - rebase_path(invoker.dexlayout_profile, root_build_dir), - "--dexlayout-path", - rebase_path(_dexlayout_path, root_build_dir), - "--profman-path", - rebase_path(_profman_path, root_build_dir), - "--dexdump-path", - rebase_path(_dexdump_path, root_build_dir), - ] - inputs += [ - _dexlayout_path, - _profman_path, - _dexdump_path, - invoker.dexlayout_profile, - ] - inputs += _default_art_libs - } - # Never compile intemediates with --release in order to: # 1) not require recompiles when toggling is_java_debug, # 2) allow incremental_install=1 to still have local variable
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni index 64c6aaf8..2681639 100644 --- a/build/config/android/rules.gni +++ b/build/config/android/rules.gni
@@ -2891,9 +2891,6 @@ if (defined(invoker.disable_r8_outlining)) { not_needed(invoker, [ "disable_r8_outlining" ]) } - if (defined(invoker.dexlayout_profile)) { - not_needed(invoker, [ "dexlayout_profile" ]) - } } else { # Dex generation for app bundle modules with proguarding enabled takes # place later due to synchronized proguarding. @@ -2902,7 +2899,6 @@ forward_variables_from(invoker, [ "disable_r8_outlining", - "dexlayout_profile", "enable_proguard_checks", "proguard_enable_obfuscation", ]) @@ -3444,7 +3440,6 @@ "data", "data_deps", "deps", - "dexlayout_profile", "disable_r8_outlining", "dist_ijar_path", "enable_lint",
diff --git a/build/fuchsia/linux_internal.sdk.sha1 b/build/fuchsia/linux_internal.sdk.sha1 index 24c1f51..4944c995 100644 --- a/build/fuchsia/linux_internal.sdk.sha1 +++ b/build/fuchsia/linux_internal.sdk.sha1
@@ -1 +1 @@ -7.20220310.0.1 +7.20220310.2.1
diff --git a/build/rust/mixed_target.gni b/build/rust/mixed_target.gni index 5b44778..160d648 100644 --- a/build/rust/mixed_target.gni +++ b/build/rust/mixed_target.gni
@@ -35,6 +35,7 @@ # rs_public_deps # rs_crate_name # rs_crate_root +# rs_generate_crate_root # rs_features # rs_cxx_bindings # Rust parameters. Same meaning as in 'rust_static_library' without the @@ -79,6 +80,7 @@ "rs_crate_name", "rs_crate_root", "rs_build_native_rust_unit_tests", + "rs_generate_crate_root", ] # TODO(crbug.com/1280708, crbug.com/1304707): Drop toolchain_has_rust after we have support for @@ -125,6 +127,9 @@ if (defined(invoker.rs_crate_root)) { crate_root = invoker.rs_crate_root } + if (defined(invoker.rs_generate_crate_root)) { + generate_crate_root = invoker.rs_generate_crate_root + } if (defined(invoker.rs_crate_name)) { crate_name = invoker.rs_crate_name }
diff --git a/build/rust/rust_target.gni b/build/rust/rust_target.gni index fa335ee..fb0e8d7e 100644 --- a/build/rust/rust_target.gni +++ b/build/rust/rust_target.gni
@@ -35,18 +35,16 @@ # different defaults can be provided. template("rust_target") { + # Only one of `crate_root` or `generate_crate_root` can be specified, or + # neither. + assert(!defined(invoker.crate_root) || + !(defined(invoker.generate_crate_root) && invoker.generate_crate_root)) + _target_name = target_name _crate_name = target_name if (defined(invoker.crate_name)) { _crate_name = invoker.crate_name } - if (defined(invoker.crate_root)) { - _crate_root = invoker.crate_root - } else if (invoker.target_type == "executable") { - _crate_root = "src/main.rs" - } else { - _crate_root = "src/lib.rs" - } if (defined(invoker.output_dir) && invoker.output_dir != "") { _out_dir = invoker.output_dir @@ -54,6 +52,34 @@ _out_dir = target_out_dir } + if (defined(invoker.generate_crate_root) && invoker.generate_crate_root) { + generated_file("${_target_name}_crate_root") { + outputs = [ "${target_gen_dir}/${target_name}.rs" ] + contents = [ + "// Generated crate root for ${_target_name}.", + "// @generated", + "", + ] + foreach(rs, invoker.sources) { + rs_path_from_root = rebase_path(rs, target_gen_dir) + contents += [ "#[path = \"${rs_path_from_root}\"]" ] + rs_modname = string_replace(string_replace(rs, "/", "_"), ".rs", "") + contents += [ + "mod ${rs_modname};", + "", + ] + } + } + _crate_root = + string_join("", get_target_outputs(":${_target_name}_crate_root")) + } else if (defined(invoker.crate_root)) { + _crate_root = invoker.crate_root + } else if (invoker.target_type == "executable") { + _crate_root = "src/main.rs" + } else { + _crate_root = "src/lib.rs" + } + _testonly = false if (defined(invoker.testonly)) { _testonly = invoker.testonly
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index 6b92a2d..7a234d8 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc
@@ -2354,10 +2354,11 @@ if (std::unique_ptr<gfx::DelegatedInkMetadata> delegated_ink_metadata = active_tree_->take_delegated_ink_metadata()) { delegated_ink_metadata->set_frame_time(CurrentBeginFrameArgs().frame_time); - TRACE_EVENT_INSTANT1( + TRACE_EVENT_WITH_FLOW1( "delegated_ink_trails", "Delegated Ink Metadata set on compositor frame metadata", - TRACE_EVENT_SCOPE_THREAD, "ink metadata", + TRACE_ID_GLOBAL(delegated_ink_metadata->trace_id()), + TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "metadata", delegated_ink_metadata->ToString()); metadata.delegated_ink_metadata = std::move(delegated_ink_metadata); }
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc index c5bf5d5..ebb18cbb 100644 --- a/cc/trees/layer_tree_impl.cc +++ b/cc/trees/layer_tree_impl.cc
@@ -874,10 +874,11 @@ presentation_callbacks_.clear(); if (delegated_ink_metadata_) { - TRACE_EVENT_INSTANT1("delegated_ink_trails", - "Delegated ink metadata pushed to tree", - TRACE_EVENT_SCOPE_THREAD, "point", - delegated_ink_metadata_->point().ToString()); + TRACE_EVENT_WITH_FLOW1("delegated_ink_trails", + "Delegated ink metadata pushed to tree", + TRACE_ID_GLOBAL(delegated_ink_metadata_->trace_id()), + TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, + "metadata", delegated_ink_metadata_->ToString()); target_tree->set_delegated_ink_metadata(std::move(delegated_ink_metadata_)); }
diff --git a/chrome/VERSION b/chrome/VERSION index be1b1cc9..2be9c6f 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=101 MINOR=0 -BUILD=4936 +BUILD=4937 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index 3782a47..31a5af6b 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -397,6 +397,7 @@ "//chrome/browser/page_annotations/android:java", "//chrome/browser/paint_preview/android:java", "//chrome/browser/partnercustomizations:delegate_java", + "//chrome/browser/partnercustomizations:java", "//chrome/browser/password_check:public_java", "//chrome/browser/password_entry_edit:public_java", "//chrome/browser/password_manager/android:java", @@ -538,6 +539,7 @@ "//components/paint_preview/browser/android:java", "//components/paint_preview/player/android:java", "//components/password_manager/core/browser:password_manager_java_enums", + "//components/password_manager/core/common:password_manager_common_java_enums", "//components/payments/content/android:java", "//components/payments/content/android:service_java", "//components/payments/mojom:mojom_java", @@ -1010,6 +1012,7 @@ "//chrome/browser/omaha/android:java", "//chrome/browser/optimization_guide/android:java", "//chrome/browser/page_annotations/test/android:junit", + "//chrome/browser/partnercustomizations:java", "//chrome/browser/password_edit_dialog/android:junit", "//chrome/browser/password_entry_edit/android/internal:junit", "//chrome/browser/payments/android:junit", @@ -1394,6 +1397,9 @@ "//chrome/browser/page_annotations/test/android:javatests", "//chrome/browser/paint_preview/android:java", "//chrome/browser/paint_preview/android:javatests", + "//chrome/browser/partnercustomizations:delegate_java", + "//chrome/browser/partnercustomizations:java", + "//chrome/browser/partnercustomizations:test_support_java", "//chrome/browser/password_check:public_java", "//chrome/browser/password_edit_dialog/android:javatests", "//chrome/browser/password_entry_edit/android/internal:javatests", @@ -2404,6 +2410,7 @@ "//base:base_java", "//base:base_java_test_support", "//base:jni_java", + "//chrome/browser/download/android:java", "//chrome/browser/prefetch/android:java", "//chrome/browser/profiles/android:java", "//chrome/browser/sync/android:java", @@ -3068,6 +3075,7 @@ shared_libraries = [ ":libchromefortest" ] deps = [ ":chrome_unit_test_java", + "//chrome/browser/partnercustomizations:javatests", "//chrome/browser/user_education:javatests", "//chrome/browser/video_tutorials/internal:javatests", ] @@ -3853,7 +3861,6 @@ "java/src/org/chromium/chrome/browser/download/DownloadManagerService.java", "java/src/org/chromium/chrome/browser/download/DownloadUtils.java", "java/src/org/chromium/chrome/browser/download/DuplicateDownloadDialogBridge.java", - "java/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorFactory.java", "java/src/org/chromium/chrome/browser/download/service/DownloadBackgroundTask.java", "java/src/org/chromium/chrome/browser/download/service/DownloadTaskScheduler.java", "java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBridge.java", @@ -3932,7 +3939,6 @@ "java/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchBackgroundTaskScheduler.java", "java/src/org/chromium/chrome/browser/page_info/PageInfoAboutThisSiteController.java", "java/src/org/chromium/chrome/browser/partnerbookmarks/PartnerBookmarksReader.java", - "java/src/org/chromium/chrome/browser/partnercustomizations/PartnerBrowserCustomizations.java", "java/src/org/chromium/chrome/browser/password_manager/AccountChooserDialog.java", "java/src/org/chromium/chrome/browser/password_manager/AutoSigninFirstRunDialog.java", "java/src/org/chromium/chrome/browser/password_manager/AutoSigninSnackbarController.java",
diff --git a/chrome/android/chrome_java_resources.gni b/chrome/android/chrome_java_resources.gni index 665bc1b..bb294cf 100644 --- a/chrome/android/chrome_java_resources.gni +++ b/chrome/android/chrome_java_resources.gni
@@ -420,7 +420,6 @@ "java/res/drawable/ic_google_services_48dp.xml", "java/res/drawable/ic_image_descriptions.xml", "java/res/drawable/ic_incognito_cct_24dp.xml", - "java/res/drawable/ic_logo_assistant_24dp.xml", "java/res/drawable/ic_new_window.xml", "java/res/drawable/ic_offer_tag.xml", "java/res/drawable/ic_offline_pin_white.xml", @@ -440,6 +439,7 @@ "java/res/drawable/ic_toolbar_share_offset_24dp.xml", "java/res/drawable/ic_translate.xml", "java/res/drawable/ic_trending_down_black.xml", + "java/res/drawable/ic_turn_off_sync_48dp.xml", "java/res/drawable/ic_tv_options_input_settings_rotated_grey.xml", "java/res/drawable/ic_vpn_key_blue.xml", "java/res/drawable/ic_widgets.xml",
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni index c3f2851c..a72634e 100644 --- a/chrome/android/chrome_java_sources.gni +++ b/chrome/android/chrome_java_sources.gni
@@ -556,7 +556,6 @@ "java/src/org/chromium/chrome/browser/download/OMADownloadHandler.java", "java/src/org/chromium/chrome/browser/download/OfflineContentAvailabilityStatusProvider.java", "java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier.java", - "java/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorFactory.java", "java/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorNotificationBridgeUi.java", "java/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorNotificationBridgeUiFactory.java", "java/src/org/chromium/chrome/browser/download/service/DownloadBackgroundTask.java", @@ -881,7 +880,6 @@ "java/src/org/chromium/chrome/browser/partnerbookmarks/PartnerBookmarksProviderIterator.java", "java/src/org/chromium/chrome/browser/partnerbookmarks/PartnerBookmarksReader.java", "java/src/org/chromium/chrome/browser/partnerbookmarks/PartnerBookmarksShim.java", - "java/src/org/chromium/chrome/browser/partnercustomizations/PartnerBrowserCustomizations.java", "java/src/org/chromium/chrome/browser/password_manager/AccountChooserDialog.java", "java/src/org/chromium/chrome/browser/password_manager/AutoSigninFirstRunDialog.java", "java/src/org/chromium/chrome/browser/password_manager/AutoSigninSnackbarController.java",
diff --git a/chrome/android/chrome_test_java_sources.gni b/chrome/android/chrome_test_java_sources.gni index f8f5e5b..30c6090 100644 --- a/chrome/android/chrome_test_java_sources.gni +++ b/chrome/android/chrome_test_java_sources.gni
@@ -373,11 +373,7 @@ "javatests/src/org/chromium/chrome/browser/paint_preview/StartupPaintPreviewHelperTest.java", "javatests/src/org/chromium/chrome/browser/paint_preview/StartupPaintPreviewHelperTestRunner.java", "javatests/src/org/chromium/chrome/browser/partnercustomizations/BasePartnerBrowserCustomizationIntegrationTestRule.java", - "javatests/src/org/chromium/chrome/browser/partnercustomizations/BasePartnerBrowserCustomizationUnitTestRule.java", - "javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerBrowserCustomizationsUnitTest.java", - "javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerDisableBookmarksEditingUnitTest.java", "javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerDisableIncognitoModeIntegrationTest.java", - "javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerDisableIncognitoModeUnitTest.java", "javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerHomepageIntegrationTest.java", "javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerHomepageUnitTest.java", "javatests/src/org/chromium/chrome/browser/password_manager/PasswordGenerationDialogTest.java",
diff --git a/chrome/android/java/res/drawable/ic_sync_off_48dp.xml b/chrome/android/java/res/drawable/ic_sync_off_48dp.xml index da6e4277..fb1ec2c 100644 --- a/chrome/android/java/res/drawable/ic_sync_off_48dp.xml +++ b/chrome/android/java/res/drawable/ic_sync_off_48dp.xml
@@ -2,6 +2,9 @@ <!-- Copyright 2020 The Chromium Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> + +<!-- This drawable and ic_turn_off_sync.xml should be kept identical except for the + colour, size and presence of a background disc. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"
diff --git a/chrome/android/java/res/drawable/ic_turn_off_sync_48dp.xml b/chrome/android/java/res/drawable/ic_turn_off_sync_48dp.xml new file mode 100644 index 0000000..c7e1301 --- /dev/null +++ b/chrome/android/java/res/drawable/ic_turn_off_sync_48dp.xml
@@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2022 The Chromium Authors. All rights reserved. + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. --> + +<!-- This drawable and ic_sync_off_48dp.xml should be kept identical except for the + colour, size and presence of a background disc. --> +<vector + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:width="48dp" + android:height="48dp" + android:viewportWidth="40" + android:viewportHeight="40"> + + <path + android:pathData="M18.7501,16.4687V15.1625C18.2501,15.2938 17.7813,15.5 17.3563,15.7625L18.2688,16.675C18.4251,16.6 18.5813,16.525 18.7501,16.4687ZM14.2876,15.8812L15.7626,17.3562C15.2813,18.1188 15.0001,19.025 15.0001,20C15.0001,21.3813 15.5688,22.625 16.4751,23.525L15.0001,25H18.7501V21.25L17.3501,22.65C16.6751,21.9687 16.2501,21.0375 16.2501,20C16.2501,19.375 16.4063,18.7875 16.6751,18.2687L21.7251,23.3187C21.5688,23.4 21.4126,23.475 21.2438,23.5312V24.8375C21.7438,24.7062 22.2126,24.5 22.6376,24.2375L24.1126,25.7125L24.9063,24.9188L15.0876,15.0875L14.2876,15.8812ZM25.0001,15H21.2501V18.75L22.6501,17.35C23.3251,18.0313 23.7501,18.9625 23.7501,20C23.7501,20.625 23.5938,21.2125 23.3251,21.7313L24.2376,22.6437C24.7188,21.8812 25.0001,20.975 25.0001,20C25.0001,18.6187 24.4313,17.375 23.5251,16.475L25.0001,15Z" + android:fillColor="@macro/default_icon_color"/> +</vector>
diff --git a/chrome/android/java/res/layout/autofill_save_card_base_layout.xml b/chrome/android/java/res/layout/autofill_save_card_base_layout.xml index 310e80a..f8f6bc85bf 100644 --- a/chrome/android/java/res/layout/autofill_save_card_base_layout.xml +++ b/chrome/android/java/res/layout/autofill_save_card_base_layout.xml
@@ -16,6 +16,16 @@ android:layout_marginTop="6dp" android:orientation="vertical"> + <TextView + android:id="@+id/description" + android:textAppearance="@style/TextAppearance.TextMedium.Primary" + android:inputType="textMultiLine" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="20dp" + android:visibility="gone" + tools:ignore="TextViewEdits" /> + <include layout="@layout/autofill_cc_details" android:layout_width="match_parent"
diff --git a/chrome/android/java/res_chromium/drawable-hdpi/fre_product_logo.png b/chrome/android/java/res_chromium/drawable-hdpi/fre_product_logo.png index 64f3f83..2353496 100644 --- a/chrome/android/java/res_chromium/drawable-hdpi/fre_product_logo.png +++ b/chrome/android/java/res_chromium/drawable-hdpi/fre_product_logo.png Binary files differ
diff --git a/chrome/android/java/res_chromium/drawable-mdpi/fre_product_logo.png b/chrome/android/java/res_chromium/drawable-mdpi/fre_product_logo.png index c8ee231..6e79da0 100644 --- a/chrome/android/java/res_chromium/drawable-mdpi/fre_product_logo.png +++ b/chrome/android/java/res_chromium/drawable-mdpi/fre_product_logo.png Binary files differ
diff --git a/chrome/android/java/res_chromium/drawable-xhdpi/fre_product_logo.png b/chrome/android/java/res_chromium/drawable-xhdpi/fre_product_logo.png index 1a23d18..d8a5337 100644 --- a/chrome/android/java/res_chromium/drawable-xhdpi/fre_product_logo.png +++ b/chrome/android/java/res_chromium/drawable-xhdpi/fre_product_logo.png Binary files differ
diff --git a/chrome/android/java/res_chromium/drawable-xxhdpi/fre_product_logo.png b/chrome/android/java/res_chromium/drawable-xxhdpi/fre_product_logo.png index dd654a7..38c50104 100644 --- a/chrome/android/java/res_chromium/drawable-xxhdpi/fre_product_logo.png +++ b/chrome/android/java/res_chromium/drawable-xxhdpi/fre_product_logo.png Binary files differ
diff --git a/chrome/android/java/res_chromium/drawable-xxxhdpi/fre_product_logo.png b/chrome/android/java/res_chromium/drawable-xxxhdpi/fre_product_logo.png index 6594440..056110f 100644 --- a/chrome/android/java/res_chromium/drawable-xxxhdpi/fre_product_logo.png +++ b/chrome/android/java/res_chromium/drawable-xxxhdpi/fre_product_logo.png Binary files differ
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillSaveCardPromptBase.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillSaveCardPromptBase.java index ae4361a..87c29d5d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillSaveCardPromptBase.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillSaveCardPromptBase.java
@@ -20,6 +20,7 @@ import androidx.annotation.Nullable; import org.chromium.chrome.R; +import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.ui.modaldialog.DialogDismissalCause; import org.chromium.ui.modaldialog.ModalDialogManager; import org.chromium.ui.modaldialog.ModalDialogProperties; @@ -77,6 +78,15 @@ stub.inflate(); } + if (ChromeFeatureList.isEnabled(ChromeFeatureList.MESSAGES_FOR_ANDROID_SAVE_CARD) + && ChromeFeatureList.getFieldTrialParamByFeatureAsBoolean( + ChromeFeatureList.MESSAGES_FOR_ANDROID_SAVE_CARD, + "save_card_dialog_explanation", false)) { + TextView description = mDialogView.findViewById(R.id.description); + description.setVisibility(View.VISIBLE); + description.setText(R.string.autofill_save_card_prompt_upload_explanation_v3); + } + PropertyModel.Builder builder = new PropertyModel.Builder(ModalDialogProperties.ALL_KEYS) .with(ModalDialogProperties.CONTROLLER, this)
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHelper.java index 311ce41..99bac12 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHelper.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHelper.java
@@ -4,13 +4,13 @@ package org.chromium.chrome.browser.contextmenu; +import android.os.SystemClock; import android.util.Pair; import android.view.View; import androidx.annotation.VisibleForTesting; import org.chromium.base.Callback; -import org.chromium.base.TimeUtilsJni; import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.NativeMethods; import org.chromium.base.metrics.RecordHistogram; @@ -24,7 +24,6 @@ import org.chromium.ui.modelutil.MVCListAdapter.ModelList; import java.util.List; -import java.util.concurrent.TimeUnit; /** * A helper class that handles generating and dismissing context menus for {@link WebContents}. @@ -113,8 +112,7 @@ }; mOnMenuShown = () -> { mSelectedItemBeforeDismiss = false; - mMenuShownTimeMs = - TimeUnit.MICROSECONDS.toMillis(TimeUtilsJni.get().getTimeTicksNowUs()); + mMenuShownTimeMs = SystemClock.uptimeMillis(); RecordHistogram.recordBooleanHistogram("ContextMenu.Shown", mWebContents != null); recordContextMenuShownType(params); if (sMenuShownCallbackForTests != null) { @@ -191,9 +189,7 @@ private void recordTimeToTakeActionHistogram(boolean selectedItem) { final String histogramName = "ContextMenu.TimeToTakeAction." + (selectedItem ? "SelectedItem" : "Abandoned"); - final long timeToTakeActionMs = - TimeUnit.MICROSECONDS.toMillis(TimeUtilsJni.get().getTimeTicksNowUs()) - - mMenuShownTimeMs; + final long timeToTakeActionMs = SystemClock.uptimeMillis() - mMenuShownTimeMs; RecordHistogram.recordTimesHistogram(histogramName, timeToTakeActionMs); if (mCurrentContextMenuParams.isAnchor() && PerformanceHintsObserver.getPerformanceClassForURL(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java index 747e63f..ee95dad4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
@@ -41,7 +41,6 @@ import org.chromium.base.StrictModeContext; import org.chromium.base.SysUtils; import org.chromium.base.ThreadUtils; -import org.chromium.base.TimeUtilsJni; import org.chromium.base.TraceEvent; import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; @@ -210,10 +209,6 @@ @Nullable private Callback<CustomTabsSessionToken> mDisconnectCallback; - // Conversion between native TimeTicks and SystemClock.uptimeMillis(). - private long mNativeTickOffsetUs; - private boolean mNativeTickOffsetUsComputed; - private volatile ChainedTasks mWarmupTasks; /** @@ -1191,28 +1186,17 @@ * Creates a Bundle with a value for navigation start and the specified page load metric. * * @param metricName Name of the page load metric. - * @param navigationStartTick Absolute navigation start time, as TimeTicks taken from native. + * @param navigationStartMicros Absolute navigation start time, in microseconds, in + * {@link SystemClock#uptimeMillis()} timebase. * @param offsetMs Offset in ms from navigationStart for the page load metric. * * @return A Bundle containing navigation start and the page load metric. */ Bundle createBundleWithNavigationStartAndPageLoadMetric( - String metricName, long navigationStartTick, long offsetMs) { - if (!mNativeTickOffsetUsComputed) { - // Compute offset from time ticks to uptimeMillis. - mNativeTickOffsetUsComputed = true; - long nativeNowUs = TimeUtilsJni.get().getTimeTicksNowUs(); - long javaNowUs = SystemClock.uptimeMillis() * 1000; - mNativeTickOffsetUs = nativeNowUs - javaNowUs; - } + String metricName, long navigationStartMicros, long offsetMs) { Bundle args = new Bundle(); args.putLong(metricName, offsetMs); - // SystemClock.uptimeMillis() is used here as it (as of June 2017) uses the same system call - // as all the native side of Chrome, that is clock_gettime(CLOCK_MONOTONIC). Meaning that - // the offset relative to navigationStart is to be compared with a - // SystemClock.uptimeMillis() value. - args.putLong(PageLoadMetrics.NAVIGATION_START, - (navigationStartTick - mNativeTickOffsetUs) / 1000); + args.putLong(PageLoadMetrics.NAVIGATION_START, navigationStartMicros / 1000); return args; } @@ -1221,16 +1205,17 @@ * * @param session Session identifier. * @param metricName Name of the page load metric. - * @param navigationStartTick Absolute navigation start time, as TimeTicks taken from native. + * @param navigationStartMicros Absolute navigation start time, in microseconds, in + * {@link SystemClock#uptimeMillis()} timebase. * @param offsetMs Offset in ms from navigationStart for the page load metric. * * @return Whether the metric has been dispatched to the client. */ boolean notifySinglePageLoadMetric(CustomTabsSessionToken session, String metricName, - long navigationStartTick, long offsetMs) { + long navigationStartMicros, long offsetMs) { return notifyPageLoadMetrics(session, createBundleWithNavigationStartAndPageLoadMetric( - metricName, navigationStartTick, offsetMs)); + metricName, navigationStartMicros, offsetMs)); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/FirstMeaningfulPaintObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/FirstMeaningfulPaintObserver.java index 7731ba1..8056488 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/FirstMeaningfulPaintObserver.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/FirstMeaningfulPaintObserver.java
@@ -22,7 +22,7 @@ @Override public void onFirstMeaningfulPaint(WebContents webContents, long navigationId, - long navigationStartTick, long firstContentfulPaintMs) { + long navigationStartMicros, long firstContentfulPaintMs) { if (webContents != mTab.getWebContents()) return; mCustomTabObserver.onFirstMeaningfulPaint(mTab);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/PageLoadMetricsObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/PageLoadMetricsObserver.java index 6cf9dad2..9c33b19 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/PageLoadMetricsObserver.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/PageLoadMetricsObserver.java
@@ -52,21 +52,21 @@ @Override public void onFirstContentfulPaint(WebContents webContents, long navigationId, - long navigationStartTick, long firstContentfulPaintMs) { + long navigationStartMicros, long firstContentfulPaintMs) { if (!shouldNotifyPageLoadMetrics(webContents, navigationId)) return; mConnection.notifySinglePageLoadMetric(mSession, PageLoadMetrics.FIRST_CONTENTFUL_PAINT, - navigationStartTick, firstContentfulPaintMs); + navigationStartMicros, firstContentfulPaintMs); } @Override public void onLargestContentfulPaint(WebContents webContents, long navigationId, - long navigationStartTick, long largestContentfulPaintMs, + long navigationStartMicros, long largestContentfulPaintMs, long largestContentfulPaintSize) { if (!shouldNotifyPageLoadMetrics(webContents, navigationId)) return; Bundle args = mConnection.createBundleWithNavigationStartAndPageLoadMetric( - PageLoadMetrics.LARGEST_CONTENTFUL_PAINT, navigationStartTick, + PageLoadMetrics.LARGEST_CONTENTFUL_PAINT, navigationStartMicros, largestContentfulPaintMs); args.putLong(PageLoadMetrics.LARGEST_CONTENTFUL_PAINT_SIZE, largestContentfulPaintSize); mConnection.notifyPageLoadMetrics(mSession, args); @@ -74,11 +74,11 @@ @Override public void onLoadEventStart(WebContents webContents, long navigationId, - long navigationStartTick, long loadEventStartMs) { + long navigationStartMicros, long loadEventStartMs) { if (!shouldNotifyPageLoadMetrics(webContents, navigationId)) return; - mConnection.notifySinglePageLoadMetric( - mSession, PageLoadMetrics.LOAD_EVENT_START, navigationStartTick, loadEventStartMs); + mConnection.notifySinglePageLoadMetric(mSession, PageLoadMetrics.LOAD_EVENT_START, + navigationStartMicros, loadEventStartMs); } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/metrics/ActivityTabStartupMetricsTracker.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/ActivityTabStartupMetricsTracker.java index 6406e69..e4a7b08 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/metrics/ActivityTabStartupMetricsTracker.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/ActivityTabStartupMetricsTracker.java
@@ -103,10 +103,10 @@ @Override public void onFirstContentfulPaint(WebContents webContents, long navigationId, - long navigationStartTick, long firstContentfulPaintMs) { + long navigationStartMicros, long firstContentfulPaintMs) { if (navigationId != mNavigationId || !mShouldRecordHistograms) return; - recordFirstContentfulPaint(navigationStartTick / 1000 + firstContentfulPaintMs); + recordFirstContentfulPaint(navigationStartMicros / 1000 + firstContentfulPaintMs); } void resetMetricsRecordingStateForInitialNavigation() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/metrics/PageLoadMetrics.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/PageLoadMetrics.java index ba229d7f..d4cedc2ee 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/metrics/PageLoadMetrics.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/PageLoadMetrics.java
@@ -72,23 +72,27 @@ * * @param webContents the WebContents this metrics is related to. * @param navigationId the unique id of a navigation this metrics is related to. - * @param navigationStartTick Absolute navigation start time, as TimeTicks. + * @param navigationStartMicros Absolute navigation start time, in microseconds, in + * the same timebase as {@link SystemClock#uptimeMillis()} and + * {@link System#nanoTime()}. * @param firstContentfulPaintMs Time to first contentful paint from navigation start. */ default void onFirstContentfulPaint(WebContents webContents, long navigationId, - long navigationStartTick, long firstContentfulPaintMs) {} + long navigationStartMicros, long firstContentfulPaintMs) {} /** * Called when the largest contentful paint page load metric is available. * * @param webContents the WebContents this metrics is related to. * @param navigationId the unique id of a navigation this metrics is related to. - * @param navigationStartTick Absolute navigation start time, as TimeTicks. + * @param navigationStartMicros Absolute navigation start time, in microseconds, in + * the same timebase as {@link SystemClock#uptimeMillis()} and + * {@link System#nanoTime()}. * @param largestContentfulPaintMs Time to largest contentful paint from navigation start. * @param largestContentfulPaintSize Size of largest contentful paint, in CSS pixels. */ default void onLargestContentfulPaint(WebContents webContents, long navigationId, - long navigationStartTick, long largestContentfulPaintMs, + long navigationStartMicros, long largestContentfulPaintMs, long largestContentfulPaintSize) {} /** @@ -97,11 +101,13 @@ * * @param webContents the WebContents this metrics is related to. * @param navigationId the unique id of a navigation this metrics is related to. - * @param navigationStartTick Absolute navigation start time, as TimeTicks. + * @param navigationStartMicros Absolute navigation start time, in microseconds, in + * the same timebase as {@link SystemClock#uptimeMillis()} and + * {@link System#nanoTime()}. * @param firstMeaningfulPaintMs Time to first meaningful paint from navigation start. */ default void onFirstMeaningfulPaint(WebContents webContents, long navigationId, - long navigationStartTick, long firstMeaningfulPaintMs) {} + long navigationStartMicros, long firstMeaningfulPaintMs) {} /** * Called when the first input delay page load metric is available. @@ -118,11 +124,13 @@ * * @param webContents the WebContents this metrics is related to. * @param navigationId the unique id of a navigation this metrics is related to. - * @param navigationStartTick Absolute navigation start time, as TimeTicks. + * @param navigationStartMicros Absolute navigation start time, in microseconds, in + * the same timebase as {@link SystemClock#uptimeMillis()} and + * {@link System#nanoTime()}. * @param loadEventStartMs Time to load event start from navigation start. */ default void onLoadEventStart(WebContents webContents, long navigationId, - long navigationStartTick, long loadEventStartMs) {} + long navigationStartMicros, long loadEventStartMs) {} /** * Called when the main resource is loaded. @@ -190,35 +198,35 @@ @CalledByNative static void onFirstContentfulPaint(WebContents webContents, long navigationId, - long navigationStartTick, long firstContentfulPaintMs) { + long navigationStartMicros, long firstContentfulPaintMs) { ThreadUtils.assertOnUiThread(); if (sObservers == null) return; for (Observer observer : sObservers) { observer.onFirstContentfulPaint( - webContents, navigationId, navigationStartTick, firstContentfulPaintMs); + webContents, navigationId, navigationStartMicros, firstContentfulPaintMs); } } @CalledByNative static void onLargestContentfulPaint(WebContents webContents, long navigationId, - long navigationStartTick, long largestContentfulPaintMs, + long navigationStartMicros, long largestContentfulPaintMs, long largestContentfulPaintSize) { ThreadUtils.assertOnUiThread(); if (sObservers == null) return; for (Observer observer : sObservers) { - observer.onLargestContentfulPaint(webContents, navigationId, navigationStartTick, + observer.onLargestContentfulPaint(webContents, navigationId, navigationStartMicros, largestContentfulPaintMs, largestContentfulPaintSize); } } @CalledByNative static void onFirstMeaningfulPaint(WebContents webContents, long navigationId, - long navigationStartTick, long firstMeaningfulPaintMs) { + long navigationStartMicros, long firstMeaningfulPaintMs) { ThreadUtils.assertOnUiThread(); if (sObservers == null) return; for (Observer observer : sObservers) { observer.onFirstMeaningfulPaint( - webContents, navigationId, navigationStartTick, firstMeaningfulPaintMs); + webContents, navigationId, navigationStartMicros, firstMeaningfulPaintMs); } } @@ -234,12 +242,12 @@ @CalledByNative static void onLoadEventStart(WebContents webContents, long navigationId, - long navigationStartTick, long loadEventStartMs) { + long navigationStartMicros, long loadEventStartMs) { ThreadUtils.assertOnUiThread(); if (sObservers == null) return; for (Observer observer : sObservers) { observer.onLoadEventStart( - webContents, navigationId, navigationStartTick, loadEventStartMs); + webContents, navigationId, navigationStartMicros, loadEventStartMs); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/paint_preview/StartupPaintPreviewHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/paint_preview/StartupPaintPreviewHelper.java index aab1a27c..a37c96490 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/paint_preview/StartupPaintPreviewHelper.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/paint_preview/StartupPaintPreviewHelper.java
@@ -172,7 +172,7 @@ PageLoadMetrics.Observer observer = new PageLoadMetrics.Observer() { @Override public void onFirstMeaningfulPaint(WebContents webContents, long navigationId, - long navigationStartTick, long firstMeaningfulPaintMs) { + long navigationStartMicros, long firstMeaningfulPaintMs) { startupPaintPreview.onWebContentsFirstMeaningfulPaint(webContents); } };
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/partnercustomizations/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/partnercustomizations/OWNERS deleted file mode 100644 index 39230171..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/partnercustomizations/OWNERS +++ /dev/null
@@ -1 +0,0 @@ -wychen@chromium.org
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordChangeLauncher.java b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordChangeLauncher.java index 2facdd4..433ba1ac 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordChangeLauncher.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordChangeLauncher.java
@@ -24,10 +24,14 @@ private static final String PASSWORD_CHANGE_USERNAME_PARAMETER = "PASSWORD_CHANGE_USERNAME"; private static final String PASSWORD_CHANGE_SKIP_LOGIN_PARAMETER = "PASSWORD_CHANGE_SKIP_LOGIN"; private static final String INTENT_PARAMETER = "INTENT"; + private static final String SOURCE_PARAMETER = "SOURCE"; private static final String INTENT = "PASSWORD_CHANGE"; private static final String DEBUG_BUNDLE_ID = "DEBUG_BUNDLE_ID"; private static final String DEBUG_SOCKET_ID = "DEBUG_SOCKET_ID"; + private static final int IN_CHROME_CALLER = 7; + private static final int SOURCE_PASSWORD_CHANGE_LEAK_WARNING = 10; + private static final int SOURCE_PASSWORD_CHANGE_SETTINGS = 11; private static final String ENCODING = "UTF-8"; @@ -56,6 +60,9 @@ .addParameter(TriggerContext.PARAMETER_ORIGINAL_DEEPLINK, URLEncoder.encode(origin.getSpec(), ENCODING)) .addParameter(TriggerContext.PARAMETER_CALLER, IN_CHROME_CALLER) + .addParameter(SOURCE_PARAMETER, + skipLogin ? SOURCE_PASSWORD_CHANGE_LEAK_WARNING + : SOURCE_PASSWORD_CHANGE_SETTINGS) .build()); } catch (UnsupportedEncodingException e) { throw new IllegalStateException("Encoding not available.", e);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/settings/MainSettings.java b/chrome/android/java/src/org/chromium/chrome/browser/settings/MainSettings.java index 92be037..bc1319ce 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/settings/MainSettings.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/settings/MainSettings.java
@@ -4,7 +4,7 @@ package org.chromium.chrome.browser.settings; -import static org.chromium.chrome.browser.flags.ChromeFeatureList.UNIFIED_PASSWORD_MANAGER_ANDROID; +import static org.chromium.chrome.browser.password_manager.PasswordManagerHelper.usesUnifiedPasswordManagerUI; import android.content.Context; import android.content.Intent; @@ -21,7 +21,6 @@ import org.chromium.base.ContextUtils; import org.chromium.chrome.R; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.homepage.HomepageManager; import org.chromium.chrome.browser.night_mode.NightModeMetrics.ThemeSettingsEntry; import org.chromium.chrome.browser.night_mode.NightModeUtils; @@ -171,7 +170,7 @@ updatePasswordsPreference(); - if (ChromeFeatureList.isEnabled(UNIFIED_PASSWORD_MANAGER_ANDROID)) { + if (usesUnifiedPasswordManagerUI()) { setManagedPreferenceDelegateForPreference(PREF_PASSWORDS); } @@ -380,8 +379,7 @@ if (PREF_SEARCH_ENGINE.equals(preference.getKey())) { return TemplateUrlServiceFactory.get().isDefaultSearchManaged(); } - if (ChromeFeatureList.isEnabled(UNIFIED_PASSWORD_MANAGER_ANDROID) - && PREF_PASSWORDS.equals(preference.getKey())) { + if (usesUnifiedPasswordManagerUI() && PREF_PASSWORDS.equals(preference.getKey())) { return UserPrefs.get(Profile.getLastUsedRegularProfile()) .isManagedPreference(Pref.CREDENTIALS_ENABLE_SERVICE); } @@ -393,8 +391,7 @@ if (PREF_SEARCH_ENGINE.equals(preference.getKey())) { return TemplateUrlServiceFactory.get().isDefaultSearchManaged(); } - if (ChromeFeatureList.isEnabled(UNIFIED_PASSWORD_MANAGER_ANDROID) - && PREF_PASSWORDS.equals(preference.getKey())) { + if (usesUnifiedPasswordManagerUI() && PREF_PASSWORDS.equals(preference.getKey())) { return UserPrefs.get(Profile.getLastUsedRegularProfile()) .isManagedPreference(Pref.CREDENTIALS_ENABLE_SERVICE); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/ManageSyncSettings.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/ManageSyncSettings.java index 100571c..d322d684 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/ManageSyncSettings.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/ManageSyncSettings.java
@@ -39,6 +39,7 @@ import org.chromium.chrome.browser.SyncFirstSetupCompleteSource; import org.chromium.chrome.browser.autofill.PersonalDataManager; import org.chromium.chrome.browser.feedback.HelpAndFeedbackLauncherImpl; +import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.settings.ChromeManagedPreferenceDelegate; import org.chromium.chrome.browser.settings.SettingsActivity; @@ -197,8 +198,27 @@ Profile profile = Profile.getLastUsedRegularProfile(); if (!mIsFromSigninScreen) { - // Child profiles should not be able to sign out. - mTurnOffSync.setVisible(!profile.isChild()); + if (!profile.isChild()) { + // Non-child users have an option to sign out and turn off sync. This is to ensure + // that revoking consents for sign in and sync does not require more steps than + // enabling them. + mTurnOffSync.setVisible(true); + mTurnOffSync.setIcon(R.drawable.ic_signout_40dp); + mTurnOffSync.setTitle(R.string.sign_out_and_turn_off_sync); + } else if (ChromeFeatureList.isEnabled( + ChromeFeatureList.ALLOW_SYNC_OFF_FOR_CHILD_ACCOUNTS)) { + // Child users are force signed-in, so have an option which only turns off sync. + // + // TODO(crbug.com/1294761): update implementation to turn off sync without signing + // out. + mTurnOffSync.setVisible(true); + mTurnOffSync.setIcon(R.drawable.ic_turn_off_sync_48dp); + mTurnOffSync.setTitle(R.string.turn_off_sync); + } else { + // Child users who are not allowed to disable sync have this option hidden. + mTurnOffSync.setVisible(false); + } + findPreference(PREF_ADVANCED_CATEGORY).setVisible(true); /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tasks/EngagementTimeUtil.java b/chrome/android/java/src/org/chromium/chrome/browser/tasks/EngagementTimeUtil.java index 6aa5e11..170b638 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tasks/EngagementTimeUtil.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tasks/EngagementTimeUtil.java
@@ -4,9 +4,7 @@ package org.chromium.chrome.browser.tasks; -import org.chromium.base.TimeUtilsJni; - -import java.util.concurrent.TimeUnit; +import android.os.SystemClock; /** * Utility class to provide engagement time helper methods. @@ -51,19 +49,19 @@ /** * Given the last engagement time, typically set by System.currentTimeMillis(), and the current - * event timestamp in base::TimeTicks in milliseconds, this computes the elapsed time between - * the two in milliseconds. + * event timestamp in {@link SystemClock#uptimeMillis()} timebase, this computes the elapsed + * time between the two in milliseconds. * * @param lastEngagementMs Timestamp of the last engagement in milliseconds. - * @param currentEngagementTicksMs Timestamp of the current event in TimeTicks (ms) + * @param currentEngagementMs Timestamp of the current event in milliseconds + * ({@link SystemClock#uptimeMillis()} timebase). * @return */ public long timeSinceLastEngagementFromTimeTicksMs( - final long lastEngagementMs, final long currentEngagementTicksMs) { + final long lastEngagementMs, final long currentEngagementMs) { final long currentTimeMs = currentTime(); - final long currentTimeTicksUs = TimeUtilsJni.get().getTimeTicksNowUs(); - final long currentTimeTicksMs = TimeUnit.MICROSECONDS.toMillis(currentTimeTicksUs); - final long offsetMs = currentTimeTicksMs - currentEngagementTicksMs; + final long currentUptimeMs = SystemClock.uptimeMillis(); + final long offsetMs = currentUptimeMs - currentEngagementMs; final long currentEngagementTimeMs = currentTimeMs - offsetMs; final long elapsedMs = currentEngagementTimeMs - lastEngagementMs;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java index df92975..b60f0c5 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
@@ -18,7 +18,6 @@ import android.content.IntentFilter; import android.graphics.Point; import android.os.Build; -import android.os.Build.VERSION_CODES; import android.os.SystemClock; import android.support.test.InstrumentationRegistry; import android.text.TextUtils; @@ -58,6 +57,7 @@ import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.FlakyTest; +import org.chromium.base.test.util.MaxAndroidSdkLevel; import org.chromium.base.test.util.MinAndroidSdkLevel; import org.chromium.base.test.util.Restriction; import org.chromium.base.test.util.UserActionTester; @@ -2382,7 +2382,7 @@ @Feature({"ContextualSearch"}) @CommandLineFlags.Add(ChromeSwitches.DISABLE_TAB_MERGING_FOR_TESTING) @MinAndroidSdkLevel(Build.VERSION_CODES.N) - @DisableIf.Build(sdk_is_greater_than = VERSION_CODES.R, message = "crbug.com/1301017") + @MaxAndroidSdkLevel(value = Build.VERSION_CODES.R, reason = "crbug.com/1301017") @ParameterAnnotations.UseMethodParameter(FeatureParamProvider.class) public void testTabReparenting(@EnabledFeature int enabledFeature) throws Exception { // Move our "tap_test" tab to another activity.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/metrics/PageLoadMetricsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/metrics/PageLoadMetricsTest.java index 3e7d33f2..758a6e02a 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/metrics/PageLoadMetricsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/metrics/PageLoadMetricsTest.java
@@ -87,7 +87,7 @@ @Override public void onFirstContentfulPaint(WebContents webContents, long navigationId, - long navigationStartTick, long firstContentfulPaintMs) { + long navigationStartMicros, long firstContentfulPaintMs) { if (mNavigationId != navigationId) return; if (firstContentfulPaintMs > 0) mFirstContentfulPaintLatch.countDown(); @@ -95,7 +95,7 @@ @Override public void onLoadEventStart(WebContents webContents, long navigationId, - long navigationStartTick, long loadEventStartMs) { + long navigationStartMicros, long loadEventStartMs) { if (mNavigationId != navigationId) return; if (loadEventStartMs > 0) mLoadEventStartLatch.countDown();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/BasePartnerBrowserCustomizationIntegrationTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/BasePartnerBrowserCustomizationIntegrationTestRule.java index 3995ef7..e25a751 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/BasePartnerBrowserCustomizationIntegrationTestRule.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/BasePartnerBrowserCustomizationIntegrationTestRule.java
@@ -22,8 +22,9 @@ return super.apply(new Statement() { @Override public void evaluate() throws Throwable { - PartnerBrowserCustomizations.ignoreBrowserProviderSystemPackageCheckForTests(true); - PartnerBrowserCustomizations.setProviderAuthorityForTests( + CustomizationProviderDelegateUpstreamImpl + .ignoreBrowserProviderSystemPackageCheckForTesting(true); + CustomizationProviderDelegateUpstreamImpl.setProviderAuthorityForTesting( TestPartnerBrowserCustomizationsProvider.class.getName()); base.evaluate(); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerDisableIncognitoModeIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerDisableIncognitoModeIntegrationTest.java index 88f104b3..f314519 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerDisableIncognitoModeIntegrationTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerDisableIncognitoModeIntegrationTest.java
@@ -46,7 +46,7 @@ new BasePartnerBrowserCustomizationIntegrationTestRule(); private void setParentalControlsEnabled(boolean enabled) { - Uri uri = PartnerBrowserCustomizations.buildQueryUri( + Uri uri = CustomizationProviderDelegateUpstreamImpl.buildQueryUri( PartnerBrowserCustomizations.PARTNER_DISABLE_INCOGNITO_MODE_PATH); Bundle bundle = new Bundle(); bundle.putBoolean(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerHomepageUnitTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerHomepageUnitTest.java index 6af7a09..521289a 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerHomepageUnitTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerHomepageUnitTest.java
@@ -63,7 +63,8 @@ Assert.assertNotSame( TestPartnerBrowserCustomizationsProvider.HOMEPAGE_URI, TEST_CUSTOM_HOMEPAGE_URI); - PartnerBrowserCustomizations.ignoreBrowserProviderSystemPackageCheckForTests(true); + CustomizationProviderDelegateUpstreamImpl.ignoreBrowserProviderSystemPackageCheckForTesting( + true); } @After @@ -93,8 +94,9 @@ // Note that unlike other tests in this file, we test if Chrome ignores a customizations // provider that is not from a system package. - PartnerBrowserCustomizations.ignoreBrowserProviderSystemPackageCheckForTests(false); - PartnerBrowserCustomizations.setProviderAuthorityForTests( + CustomizationProviderDelegateUpstreamImpl.ignoreBrowserProviderSystemPackageCheckForTesting( + false); + CustomizationProviderDelegateUpstreamImpl.setProviderAuthorityForTesting( PARTNER_BROWSER_CUSTOMIZATIONS_PROVIDER); TestThreadUtils.runOnUiThreadBlocking(() -> { mPartnerBrowserCustomizations.initializeAsync( @@ -123,7 +125,7 @@ mHomepageManager.setHomepagePreferences(false, true, TEST_CUSTOM_HOMEPAGE_URI); }); - PartnerBrowserCustomizations.setProviderAuthorityForTests( + CustomizationProviderDelegateUpstreamImpl.setProviderAuthorityForTesting( PARTNER_BROWSER_CUSTOMIZATIONS_NO_PROVIDER); TestThreadUtils.runOnUiThreadBlocking(() -> { mPartnerBrowserCustomizations.initializeAsync( @@ -152,7 +154,7 @@ mHomepageManager.setHomepagePreferences(false, true, TEST_CUSTOM_HOMEPAGE_URI); }); - PartnerBrowserCustomizations.setProviderAuthorityForTests( + CustomizationProviderDelegateUpstreamImpl.setProviderAuthorityForTesting( PARTNER_BROWSER_CUSTOMIZATIONS_PROVIDER); TestThreadUtils.runOnUiThreadBlocking(() -> { mPartnerBrowserCustomizations.initializeAsync( @@ -184,7 +186,7 @@ mHomepageManager.setHomepagePreferences(false, false, TEST_CUSTOM_HOMEPAGE_URI); }); - PartnerBrowserCustomizations.setProviderAuthorityForTests( + CustomizationProviderDelegateUpstreamImpl.setProviderAuthorityForTesting( PARTNER_BROWSER_CUSTOMIZATIONS_PROVIDER); TestThreadUtils.runOnUiThreadBlocking(() -> { mPartnerBrowserCustomizations.initializeAsync( @@ -217,7 +219,7 @@ mHomepageManager.setHomepagePreferences(false, true, TEST_CUSTOM_HOMEPAGE_URI); }); - PartnerBrowserCustomizations.setProviderAuthorityForTests( + CustomizationProviderDelegateUpstreamImpl.setProviderAuthorityForTesting( PARTNER_BROWSER_CUSTOMIZATIONS_DELAYED_PROVIDER); TestThreadUtils.runOnUiThreadBlocking(() -> { mPartnerBrowserCustomizations.initializeAsync(mTestRule.getContextWrapper(), 500); @@ -258,7 +260,7 @@ mHomepageManager.setHomepagePreferences(false, true, TEST_CUSTOM_HOMEPAGE_URI); }); - PartnerBrowserCustomizations.setProviderAuthorityForTests( + CustomizationProviderDelegateUpstreamImpl.setProviderAuthorityForTesting( PARTNER_BROWSER_CUSTOMIZATIONS_DELAYED_PROVIDER); mTestRule.setDelayProviderUriPathForDelay( PartnerBrowserCustomizations.PARTNER_HOMEPAGE_PATH); @@ -301,7 +303,7 @@ mHomepageManager.setHomepagePreferences(false, true, TEST_CUSTOM_HOMEPAGE_URI); }); - PartnerBrowserCustomizations.setProviderAuthorityForTests( + CustomizationProviderDelegateUpstreamImpl.setProviderAuthorityForTesting( PARTNER_BROWSER_CUSTOMIZATIONS_PROVIDER); TestThreadUtils.runOnUiThreadBlocking(() -> { mPartnerBrowserCustomizations.initializeAsync(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestRule.java index cebc7bf..1b430c3 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestRule.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestRule.java
@@ -400,6 +400,7 @@ /** Clicks on an HTML node. */ protected void clickNode(String nodeId) throws TimeoutException { + DOMUtils.waitForNonZeroNodeBounds(mWebContentsRef.get(), nodeId); DOMUtils.clickNode(mWebContentsRef.get(), nodeId); }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/indicator/OfflineIndicatorControllerV2UnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/indicator/OfflineIndicatorControllerV2UnitTest.java index 49dc5db..460a645 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/indicator/OfflineIndicatorControllerV2UnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/indicator/OfflineIndicatorControllerV2UnitTest.java
@@ -30,8 +30,6 @@ import org.robolectric.Robolectric; import org.robolectric.annotation.Config; -import org.chromium.base.TimeUtils; -import org.chromium.base.TimeUtilsJni; import org.chromium.base.supplier.ObservableSupplierImpl; import org.chromium.base.supplier.Supplier; import org.chromium.base.test.BaseRobolectricTestRunner; @@ -57,8 +55,6 @@ @Mock private Supplier<Boolean> mCanAnimateNativeBrowserControls; @Mock - private TimeUtils.Natives mTimeUtils; - @Mock private OfflineIndicatorMetricsDelegate mMetricsDelegate; private Context mContext; @@ -79,8 +75,6 @@ mOnlineString = mContext.getString(R.string.offline_indicator_v2_back_online_text); when(mCanAnimateNativeBrowserControls.get()).thenReturn(true); - TimeUtilsJni.TEST_HOOKS.setInstanceForTesting(mTimeUtils); - when(mTimeUtils.getTimeTicksNowUs()).thenReturn(0L); when(mOfflineDetector.isApplicationForeground()).thenReturn(true); when(mMetricsDelegate.isTrackingShownDuration()).thenReturn(false);
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 8a371b378..2688a5f 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -3359,6 +3359,7 @@ "//chrome/browser/notifications/chime/android", "//chrome/browser/notifications/scheduler/public", "//chrome/browser/optimization_guide/android:jni_headers", + "//chrome/browser/partnercustomizations:jni_headers", "//chrome/browser/password_check/android:jni_headers", "//chrome/browser/password_check/android:password_check_enums_srcjar", "//chrome/browser/password_edit_dialog/android", @@ -6226,6 +6227,7 @@ deps += [ "//components/user_notes:features", "//components/user_notes/browser", + "//components/user_notes/interfaces", "//components/user_notes/model", ] }
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 7948d620..2e59b112 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -2900,6 +2900,19 @@ }; #endif // BUILDFLAG(IS_ANDROID) +#if BUILDFLAG(IS_ANDROID) +const FeatureEntry::FeatureParam kUpmAndroidShadowSyncingUsers[] = { + {password_manager::features::kUpmExperimentVariationParam.name, + password_manager::features::kUpmExperimentVariationOption[1].name}}; + +const FeatureEntry::FeatureVariation + kUnifiedPasswordManagerAndroidVariations[] = { + // Skip kEnableForSyncingUsers which is the default Enabled param. + {"Shadow Traffic only", kUpmAndroidShadowSyncingUsers, + std::size(kUpmAndroidShadowSyncingUsers), nullptr}, +}; +#endif // BUILDFLAG(IS_ANDROID) + const FeatureEntry::FeatureParam kUnthrottledNestedTimeout_NestingLevel = { "nesting", "100"}; @@ -7714,8 +7727,10 @@ {"google-mobile-services-passwords", flag_descriptions::kUnifiedPasswordManagerAndroidName, flag_descriptions::kUnifiedPasswordManagerAndroidDescription, kOsAndroid, - FEATURE_VALUE_TYPE( - password_manager::features::kUnifiedPasswordManagerAndroid)}, + FEATURE_WITH_PARAMS_VALUE_TYPE( + password_manager::features::kUnifiedPasswordManagerAndroid, + kUnifiedPasswordManagerAndroidVariations, + "UnifiedPasswordManagerAndroid")}, #endif {"extension-workflow-justification", @@ -8326,6 +8341,10 @@ FEATURE_VALUE_TYPE(ash::features::kProjectorExcludeTranscript)}, #endif // BUILDFLAG(IS_CHROMEOS_ASH) + {"web-sql-access", flag_descriptions::kWebSQLAccessName, + flag_descriptions::kWebSQLAccessDescription, kOsAll, + FEATURE_VALUE_TYPE(blink::features::kWebSQLAccess)}, + // NOTE: Adding a new flag requires adding a corresponding entry to enum // "LoginCustomFlags" in tools/metrics/histograms/enums.xml. See "Flag // Histograms" in tools/metrics/histograms/README.md (run the
diff --git a/chrome/browser/android/partner_browser_customizations.cc b/chrome/browser/android/partner_browser_customizations.cc index 1d581ae..b736f9f 100644 --- a/chrome/browser/android/partner_browser_customizations.cc +++ b/chrome/browser/android/partner_browser_customizations.cc
@@ -5,7 +5,7 @@ #include "chrome/browser/android/partner_browser_customizations.h" #include "base/android/jni_android.h" -#include "chrome/android/chrome_jni_headers/PartnerBrowserCustomizations_jni.h" +#include "chrome/browser/partnercustomizations/jni_headers/PartnerBrowserCustomizations_jni.h" namespace chrome { namespace android {
diff --git a/chrome/browser/apps/app_service/app_service_proxy_ash.cc b/chrome/browser/apps/app_service/app_service_proxy_ash.cc index 69f6b1d..5472b0b 100644 --- a/chrome/browser/apps/app_service/app_service_proxy_ash.cc +++ b/chrome/browser/apps/app_service/app_service_proxy_ash.cc
@@ -181,8 +181,7 @@ LoadIconForDialog( update, base::BindOnce(&AppServiceProxyAsh::OnLoadIconForPauseDialog, - weak_ptr_factory_.GetWeakPtr(), - ConvertMojomAppTypToAppType(update.AppType()), + weak_ptr_factory_.GetWeakPtr(), update.AppType(), update.AppId(), update.Name(), data.second)); }); } @@ -297,7 +296,7 @@ const apps::AppUpdate& update) { auto icon_key = update.IconKey(); DCHECK(icon_key.has_value()); - auto app_type = ConvertMojomAppTypToAppType(update.AppType()); + auto app_type = update.AppType(); auto uninstall_dialog_ptr = std::make_unique<UninstallDialog>( profile_, app_type, update.AppId(), update.Name(), parent_window, base::BindOnce(&AppServiceProxyAsh::OnUninstallDialogClosed, @@ -356,8 +355,8 @@ ash::app_time::AppTimeLimitInterface* app_limit = ash::app_time::AppTimeLimitInterface::Get(profile_); DCHECK(app_limit); - auto time_limit = app_limit->GetTimeLimitForApp( - update.AppId(), ConvertMojomAppTypToAppType(update.AppType())); + auto time_limit = + app_limit->GetTimeLimitForApp(update.AppId(), update.AppType()); if (!time_limit.has_value()) { NOTREACHED(); return true; @@ -367,8 +366,7 @@ pause_data.minutes = time_limit.value().InMinutes() % 60; LoadIconForDialog( update, base::BindOnce(&AppServiceProxyAsh::OnLoadIconForPauseDialog, - weak_ptr_factory_.GetWeakPtr(), - ConvertMojomAppTypToAppType(update.AppType()), + weak_ptr_factory_.GetWeakPtr(), update.AppType(), update.AppId(), update.Name(), pause_data)); return true; } @@ -410,9 +408,9 @@ std::move(callback).Run(std::make_unique<IconValue>()); return; } - LoadIconFromIconKey(ConvertMojomAppTypToAppType(app_type), update.AppId(), - icon_key.value(), icon_type, kIconSize, - kAllowPlaceholderIcon, std::move(callback)); + LoadIconFromIconKey(app_type, update.AppId(), icon_key.value(), icon_type, + kIconSize, kAllowPlaceholderIcon, + std::move(callback)); } else { if (!icon_key.has_value()) { MojomIconValueToIconValueCallback(std::move(callback)) @@ -420,7 +418,7 @@ return; } LoadIconFromIconKey( - app_type, update.AppId(), + ConvertAppTypeToMojomAppType(app_type), update.AppId(), ConvertIconKeyToMojomIconKey(icon_key.value()), apps::mojom::IconType::kStandard, kIconSize, kAllowPlaceholderIcon, MojomIconValueToIconValueCallback(std::move(callback))); @@ -505,8 +503,8 @@ const apps::AppUpdate& update, apps::mojom::LaunchSource launch_source, apps::mojom::LaunchContainer container) { - RecordAppLaunchMetrics(profile, ConvertMojomAppTypToAppType(update.AppType()), - update.AppId(), launch_source, container); + RecordAppLaunchMetrics(profile, update.AppType(), update.AppId(), + launch_source, container); } void AppServiceProxyAsh::InitAppPlatformMetrics() {
diff --git a/chrome/browser/apps/app_service/app_service_proxy_base.cc b/chrome/browser/apps/app_service/app_service_proxy_base.cc index ca36772e..e6eb6d8 100644 --- a/chrome/browser/apps/app_service/app_service_proxy_base.cc +++ b/chrome/browser/apps/app_service/app_service_proxy_base.cc
@@ -271,8 +271,9 @@ profile_, update, launch_source, apps::mojom::LaunchContainer::kLaunchContainerNone); - app_service_->Launch(update.AppType(), update.AppId(), event_flags, - launch_source, std::move(window_info)); + app_service_->Launch(ConvertAppTypeToMojomAppType(update.AppType()), + update.AppId(), event_flags, launch_source, + std::move(window_info)); PerformPostLaunchTasks(launch_source); }); @@ -304,9 +305,9 @@ RecordAppLaunch(update.AppId(), launch_source); } - app_service_->LaunchAppWithFiles(update.AppType(), update.AppId(), - event_flags, launch_source, - std::move(file_paths)); + app_service_->LaunchAppWithFiles( + ConvertAppTypeToMojomAppType(update.AppType()), update.AppId(), + event_flags, launch_source, std::move(file_paths)); PerformPostLaunchTasks(launch_source); }); @@ -344,8 +345,9 @@ apps::mojom::LaunchContainer::kLaunchContainerNone); app_service_->LaunchAppWithIntent( - update.AppType(), update.AppId(), event_flags, std::move(intent), - launch_source, std::move(window_info), std::move(callback)); + ConvertAppTypeToMojomAppType(update.AppType()), update.AppId(), + event_flags, std::move(intent), launch_source, + std::move(window_info), std::move(callback)); PerformPostLaunchTasks(launch_source); }); @@ -407,8 +409,9 @@ if (app_service_.is_connected()) { app_registry_cache_.ForOneApp( app_id, [this, &permission](const apps::AppUpdate& update) { - app_service_->SetPermission(update.AppType(), update.AppId(), - std::move(permission)); + app_service_->SetPermission( + ConvertAppTypeToMojomAppType(update.AppType()), update.AppId(), + std::move(permission)); }); } } @@ -465,7 +468,8 @@ if (app_service_.is_connected()) { app_registry_cache_.ForOneApp( app_id, [this](const apps::AppUpdate& update) { - app_service_->OpenNativeSettings(update.AppType(), update.AppId()); + app_service_->OpenNativeSettings( + ConvertAppTypeToMojomAppType(update.AppType()), update.AppId()); }); } }
diff --git a/chrome/browser/apps/app_service/app_service_test.cc b/chrome/browser/apps/app_service/app_service_test.cc index 2e5d6c2f..284273b1 100644 --- a/chrome/browser/apps/app_service/app_service_test.cc +++ b/chrome/browser/apps/app_service/app_service_test.cc
@@ -38,7 +38,7 @@ app_service_proxy->AppRegistryCache().ForEachApp( [&apps](const apps::AppUpdate& update) { apps::mojom::AppPtr app = apps::mojom::App::New(); - app->app_type = update.AppType(); + app->app_type = ConvertAppTypeToMojomAppType(update.AppType()); app->app_id = update.AppId(); app->readiness = apps::mojom::Readiness::kUninstalledByUser; apps.push_back(app.Clone());
diff --git a/chrome/browser/apps/app_service/metrics/app_platform_metrics.cc b/chrome/browser/apps/app_service/metrics/app_platform_metrics.cc index 3ae4240..651e675 100644 --- a/chrome/browser/apps/app_service/metrics/app_platform_metrics.cc +++ b/chrome/browser/apps/app_service/metrics/app_platform_metrics.cc
@@ -666,10 +666,10 @@ return; } - InstallTime install_time = app_registry_cache_.IsAppTypeInitialized( - ConvertMojomAppTypToAppType(update.AppType())) - ? InstallTime::kRunning - : InstallTime::kInit; + InstallTime install_time = + app_registry_cache_.IsAppTypeInitialized(update.AppType()) + ? InstallTime::kRunning + : InstallTime::kInit; RecordAppsInstallUkm(update, install_time); } @@ -900,19 +900,18 @@ std::map<AppTypeName, std::map<apps::InstallReason, int>> app_count_per_install_reason; - apps::mojom::AppType mojom_app_type = ConvertAppTypeToMojomAppType(app_type); app_registry_cache_.ForEachApp( - [mojom_app_type, this, &app_count, + [app_type, this, &app_count, &app_count_per_install_reason](const apps::AppUpdate& update) { - if (mojom_app_type != apps::mojom::AppType::kUnknown && - (update.AppType() != mojom_app_type || + if (app_type != apps::AppType::kUnknown && + (update.AppType() != app_type || update.AppId() == app_constants::kChromeAppId)) { return; } - AppTypeName app_type_name = GetAppTypeName( - profile_, ConvertMojomAppTypToAppType(update.AppType()), - update.AppId(), apps::mojom::LaunchContainer::kLaunchContainerNone); + AppTypeName app_type_name = + GetAppTypeName(profile_, update.AppType(), update.AppId(), + apps::mojom::LaunchContainer::kLaunchContainerNone); if (app_type_name == AppTypeName::kChromeBrowser || app_type_name == AppTypeName::kUnknown) { @@ -1043,9 +1042,9 @@ void AppPlatformMetrics::RecordAppsInstallUkm(const apps::AppUpdate& update, InstallTime install_time) { - AppTypeName app_type_name = GetAppTypeName( - profile_, ConvertMojomAppTypToAppType(update.AppType()), update.AppId(), - apps::mojom::LaunchContainer::kLaunchContainerNone); + AppTypeName app_type_name = + GetAppTypeName(profile_, update.AppType(), update.AppId(), + apps::mojom::LaunchContainer::kLaunchContainerNone); ukm::SourceId source_id = GetSourceId(profile_, update.AppId()); if (source_id == ukm::kInvalidSourceId) {
diff --git a/chrome/browser/apps/app_service/metrics/app_platform_metrics_utils.cc b/chrome/browser/apps/app_service/metrics/app_platform_metrics_utils.cc index b070be4..aaa0c74 100644 --- a/chrome/browser/apps/app_service/metrics/app_platform_metrics_utils.cc +++ b/chrome/browser/apps/app_service/metrics/app_platform_metrics_utils.cc
@@ -118,8 +118,8 @@ ->AppRegistryCache() .ForOneApp( app_id, [&type_name, &window_mode](const apps::AppUpdate& update) { - DCHECK(update.AppType() == apps::mojom::AppType::kWeb || - update.AppType() == apps::mojom::AppType::kSystemWeb); + DCHECK(update.AppType() == apps::AppType::kWeb || + update.AppType() == apps::AppType::kSystemWeb); // For system web apps, the install source is |kSystem|. // The app type may be kSystemWeb (system web apps in Ash when
diff --git a/chrome/browser/apps/app_service/webapk/webapk_manager.cc b/chrome/browser/apps/app_service/webapk/webapk_manager.cc index 55db5bb..3f326c4 100644 --- a/chrome/browser/apps/app_service/webapk/webapk_manager.cc +++ b/chrome/browser/apps/app_service/webapk/webapk_manager.cc
@@ -254,7 +254,7 @@ return false; } - if (app.AppType() != apps::mojom::AppType::kWeb) { + if (app.AppType() != apps::AppType::kWeb) { return false; }
diff --git a/chrome/browser/apps/intent_helper/intent_picker_internal.cc b/chrome/browser/apps/intent_helper/intent_picker_internal.cc index 90b203b..5fc8bde 100644 --- a/chrome/browser/apps/intent_helper/intent_picker_internal.cc +++ b/chrome/browser/apps/intent_helper/intent_picker_internal.cc
@@ -19,7 +19,6 @@ #include "chrome/browser/web_applications/web_app_utils.h" #include "components/no_state_prefetch/browser/no_state_prefetch_contents.h" #include "components/page_load_metrics/browser/page_load_metrics_util.h" -#include "components/services/app_service/public/mojom/types.mojom.h" #include "content/public/browser/navigation_handle.h" #include "content/public/browser/web_contents.h" #include "extensions/common/constants.h" @@ -200,28 +199,28 @@ web_contents->ClosePage(); } -PickerEntryType GetPickerEntryType(mojom::AppType app_type) { +PickerEntryType GetPickerEntryType(AppType app_type) { PickerEntryType picker_entry_type = PickerEntryType::kUnknown; switch (app_type) { - case mojom::AppType::kUnknown: - case mojom::AppType::kBuiltIn: - case mojom::AppType::kCrostini: - case mojom::AppType::kPluginVm: - case mojom::AppType::kChromeApp: - case mojom::AppType::kExtension: - case mojom::AppType::kStandaloneBrowser: - case mojom::AppType::kStandaloneBrowserChromeApp: - case mojom::AppType::kRemote: - case mojom::AppType::kBorealis: + case AppType::kUnknown: + case AppType::kBuiltIn: + case AppType::kCrostini: + case AppType::kPluginVm: + case AppType::kChromeApp: + case AppType::kExtension: + case AppType::kStandaloneBrowser: + case AppType::kStandaloneBrowserChromeApp: + case AppType::kRemote: + case AppType::kBorealis: break; - case mojom::AppType::kArc: + case AppType::kArc: picker_entry_type = PickerEntryType::kArc; break; - case mojom::AppType::kWeb: - case mojom::AppType::kSystemWeb: + case AppType::kWeb: + case AppType::kSystemWeb: picker_entry_type = PickerEntryType::kWeb; break; - case mojom::AppType::kMacOs: + case AppType::kMacOs: picker_entry_type = PickerEntryType::kMacOs; break; }
diff --git a/chrome/browser/apps/intent_helper/intent_picker_internal.h b/chrome/browser/apps/intent_helper/intent_picker_internal.h index 7dd61b4..4c5aa1b 100644 --- a/chrome/browser/apps/intent_helper/intent_picker_internal.h +++ b/chrome/browser/apps/intent_helper/intent_picker_internal.h
@@ -8,7 +8,7 @@ #include <vector> #include "chrome/browser/apps/intent_helper/apps_navigation_types.h" -#include "components/services/app_service/public/mojom/types.mojom-forward.h" +#include "components/services/app_service/public/cpp/app_types.h" namespace content { class NavigationHandle; @@ -45,7 +45,7 @@ bool IsGoogleRedirectorUrlForTesting(const GURL& url); -PickerEntryType GetPickerEntryType(mojom::AppType app_type); +PickerEntryType GetPickerEntryType(AppType app_type); } // namespace apps
diff --git a/chrome/browser/ash/app_restore/app_launch_handler.cc b/chrome/browser/ash/app_restore/app_launch_handler.cc index db415093..e78c1948 100644 --- a/chrome/browser/ash/app_restore/app_launch_handler.cc +++ b/chrome/browser/ash/app_restore/app_launch_handler.cc
@@ -89,8 +89,7 @@ base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(&AppLaunchHandler::LaunchApp, GetWeakPtrAppLaunchHandler(), - apps::ConvertMojomAppTypToAppType(update.AppType()), - update.AppId())); + update.AppType(), update.AppId())); } void AppLaunchHandler::OnAppTypeInitialized(apps::AppType app_type) {
diff --git a/chrome/browser/ash/app_restore/arc_app_launch_handler.cc b/chrome/browser/ash/app_restore/arc_app_launch_handler.cc index 5f07dbda..ac063260 100644 --- a/chrome/browser/ash/app_restore/arc_app_launch_handler.cc +++ b/chrome/browser/ash/app_restore/arc_app_launch_handler.cc
@@ -260,8 +260,7 @@ } void ArcAppLaunchHandler::OnAppUpdate(const apps::AppUpdate& update) { - if (!update.ReadinessChanged() || - update.AppType() != apps::mojom::AppType::kArc) { + if (!update.ReadinessChanged() || update.AppType() != apps::AppType::kArc) { return; } @@ -389,7 +388,7 @@ std::set<std::string> app_ids; cache.ForEachApp([&app_ids, this](const apps::AppUpdate& update) { if (update.Readiness() == apps::Readiness::kReady && - update.AppType() == apps::mojom::AppType::kArc && + update.AppType() == apps::AppType::kArc && base::Contains(app_ids_, update.AppId())) { app_ids.insert(update.AppId()); }
diff --git a/chrome/browser/ash/apps/apk_web_app_service.cc b/chrome/browser/ash/apps/apk_web_app_service.cc index a5da7751..dbf4c6a 100644 --- a/chrome/browser/ash/apps/apk_web_app_service.cc +++ b/chrome/browser/ash/apps/apk_web_app_service.cc
@@ -463,7 +463,7 @@ } void ApkWebAppService::OnAppUpdate(const apps::AppUpdate& update) { - if (update.AppType() == apps::mojom::AppType::kWeb && + if (update.AppType() == apps::AppType::kWeb && update.Readiness() == apps::Readiness::kUninstalledByUser) { MaybeRemoveArcPackageForWebApp(update.AppId()); }
diff --git a/chrome/browser/ash/child_accounts/family_user_app_metrics.cc b/chrome/browser/ash/child_accounts/family_user_app_metrics.cc index 7e65df7..30e8d75 100644 --- a/chrome/browser/ash/child_accounts/family_user_app_metrics.cc +++ b/chrome/browser/ash/child_accounts/family_user_app_metrics.cc
@@ -216,11 +216,10 @@ void FamilyUserAppMetrics::RecordRecentlyUsedAppsCount(apps::AppType app_type) { int app_count = 0; base::Time now = base::Time::Now(); - apps::mojom::AppType mojom_app_type = ConvertAppTypeToMojomAppType(app_type); // The below will execute synchronously. app_registry_->ForEachApp( - [mojom_app_type, now, this, &app_count](const apps::AppUpdate& update) { - if (update.AppType() != mojom_app_type) + [app_type, now, this, &app_count](const apps::AppUpdate& update) { + if (update.AppType() != app_type) return; // Only count apps that have been used recently. if (now - update.LastLaunchTime() <= kOneDay ||
diff --git a/chrome/browser/ash/child_accounts/time_limits/app_service_wrapper.cc b/chrome/browser/ash/child_accounts/time_limits/app_service_wrapper.cc index 393a7dc..5203ae716 100644 --- a/chrome/browser/ash/child_accounts/time_limits/app_service_wrapper.cc +++ b/chrome/browser/ash/child_accounts/time_limits/app_service_wrapper.cc
@@ -37,8 +37,8 @@ // Gets AppId from |update|. AppId AppIdFromAppUpdate(const apps::AppUpdate& update) { - bool is_arc = update.AppType() == apps::mojom::AppType::kArc; - return AppId(apps::ConvertMojomAppTypToAppType(update.AppType()), + bool is_arc = update.AppType() == apps::AppType::kArc; + return AppId(update.AppType(), is_arc ? update.PublisherId() : update.AppId()); }
diff --git a/chrome/browser/ash/login/session/chrome_session_manager.cc b/chrome/browser/ash/login/session/chrome_session_manager.cc index 8f7cbbbe..72da93af 100644 --- a/chrome/browser/ash/login/session/chrome_session_manager.cc +++ b/chrome/browser/ash/login/session/chrome_session_manager.cc
@@ -190,8 +190,14 @@ case session_manager::SessionState::RMA: // Already in RMA, do nothing. break; - case session_manager::SessionState::OOBE: - case session_manager::SessionState::LOGIN_PRIMARY: { + // Restart Chrome and launch RMA from any session state as the user is + // expecting to be in RMA. + case session_manager::SessionState::ACTIVE: + case session_manager::SessionState::LOCKED: + case session_manager::SessionState::LOGGED_IN_NOT_ACTIVE: + case session_manager::SessionState::LOGIN_PRIMARY: + case session_manager::SessionState::LOGIN_SECONDARY: + case session_manager::SessionState::OOBE: { auto* existing_user_controller = ash::ExistingUserController::current_controller(); if (!existing_user_controller || @@ -207,17 +213,7 @@ ash::RestartChrome(command_line, ash::RestartChromeReason::kUserless); break; } - - // If signin in progress, don't launch RMA and fall through to the - // logged in state cases. - ABSL_FALLTHROUGH_INTENDED; } - case session_manager::SessionState::LOGGED_IN_NOT_ACTIVE: - case session_manager::SessionState::ACTIVE: - case session_manager::SessionState::LOCKED: - case session_manager::SessionState::LOGIN_SECONDARY: - // TODO(gavinwill): Trigger a notification to open RMA app. - break; } }
diff --git a/chrome/browser/ash/login/users/default_user_image/default_user_images.cc b/chrome/browser/ash/login/users/default_user_image/default_user_images.cc index b748f79..4e9de319 100644 --- a/chrome/browser/ash/login/users/default_user_image/default_user_images.cc +++ b/chrome/browser/ash/login/users/default_user_image/default_user_images.cc
@@ -358,16 +358,20 @@ kDefaultImageInfo[index].eligibility == Eligibility::kEligible; } +DefaultUserImage GetDefaultUserImage(int index) { + DCHECK(IsValidIndex(index)); + int string_id = kDefaultImageInfo[index].description_message_id; + std::u16string title = + string_id ? l10n_util::GetStringUTF16(string_id) : std::u16string(); + + return {index, std::move(title), + default_user_image::GetDefaultImageUrl(index)}; +} + std::vector<DefaultUserImage> GetCurrentImageSet() { std::vector<DefaultUserImage> result; - for (int index : kCurrentImageIndexes) { - int string_id = kDefaultImageInfo[index].description_message_id; - std::u16string title = - string_id ? l10n_util::GetStringUTF16(string_id) : std::u16string(); - - result.push_back({index, std::move(title), - default_user_image::GetDefaultImageUrl(index)}); - } + for (int index : kCurrentImageIndexes) + result.push_back(GetDefaultUserImage(index)); return result; }
diff --git a/chrome/browser/ash/login/users/default_user_image/default_user_images.h b/chrome/browser/ash/login/users/default_user_image/default_user_images.h index d9d3ccc..c9f827d 100644 --- a/chrome/browser/ash/login/users/default_user_image/default_user_images.h +++ b/chrome/browser/ash/login/users/default_user_image/default_user_images.h
@@ -85,6 +85,8 @@ // Returns true if `index` is a in the current set of default images. bool IsInCurrentImageSet(int index); +DefaultUserImage GetDefaultUserImage(int index); + // Returns a vector of current |DefaultUserImage|. std::vector<DefaultUserImage> GetCurrentImageSet();
diff --git a/chrome/browser/ash/note_taking_helper.cc b/chrome/browser/ash/note_taking_helper.cc index 96cb7244..eb1857f 100644 --- a/chrome/browser/ash/note_taking_helper.cc +++ b/chrome/browser/ash/note_taking_helper.cc
@@ -41,6 +41,7 @@ #include "components/arc/intent_helper/arc_intent_helper_bridge.h" #include "components/prefs/pref_service.h" #include "components/services/app_service/public/cpp/app_registry_cache.h" +#include "components/services/app_service/public/cpp/app_types.h" #include "components/services/app_service/public/cpp/app_update.h" #include "components/services/app_service/public/cpp/intent_util.h" #include "components/services/app_service/public/cpp/types_util.h" @@ -93,7 +94,7 @@ bool result = false; cache->ForOneApp(app_id, [&result](const apps::AppUpdate& update) { if (apps_util::IsInstalled(update.Readiness()) && - update.AppType() == apps::mojom::AppType::kWeb) { + update.AppType() == apps::AppType::kWeb) { result = true; } }); @@ -618,7 +619,7 @@ maybe_cache->ForOneApp(id, [&app_ids](const apps::AppUpdate& update) { if (!apps_util::IsInstalled(update.Readiness())) return; - if (update.AppType() != apps::mojom::AppType::kWeb) + if (update.AppType() != apps::AppType::kWeb) return; DCHECK(!base::Contains(app_ids, update.AppId())); app_ids.push_back(update.AppId()); @@ -648,7 +649,7 @@ return; if (HasNoteTakingIntentFilter(update.IntentFilters())) { // Currently only web apps are expected to have this intent set. - DCHECK(update.AppType() == apps::mojom::AppType::kWeb); + DCHECK(update.AppType() == apps::AppType::kWeb); app_ids.push_back(update.AppId()); } }); @@ -798,9 +799,9 @@ } void NoteTakingHelper::OnAppUpdate(const apps::AppUpdate& update) { - bool is_web_app = update.AppType() == apps::mojom::AppType::kWeb; + bool is_web_app = update.AppType() == apps::AppType::kWeb; bool is_chrome_app = - update.AppType() == apps::mojom::AppType::kStandaloneBrowserChromeApp; + update.AppType() == apps::AppType::kStandaloneBrowserChromeApp; if (!is_web_app && !is_chrome_app) return; // App was added, removed, enabled, or disabled.
diff --git a/chrome/browser/ash/policy/dlp/dlp_content_manager_ash_browsertest.cc b/chrome/browser/ash/policy/dlp/dlp_content_manager_ash_browsertest.cc index 99cf3b1..9f78db8e 100644 --- a/chrome/browser/ash/policy/dlp/dlp_content_manager_ash_browsertest.cc +++ b/chrome/browser/ash/policy/dlp/dlp_content_manager_ash_browsertest.cc
@@ -1092,13 +1092,13 @@ void StartDesktopScreenShare( content::WebContents* web_contents, blink::mojom::MediaStreamRequestResult expected_result) { + const content::DesktopMediaID media_id(content::DesktopMediaID::TYPE_SCREEN, + content::DesktopMediaID::kFakeId); const std::string requested_video_device_id = content::DesktopStreamsRegistry::GetInstance()->RegisterStream( web_contents->GetMainFrame()->GetProcess()->GetID(), web_contents->GetMainFrame()->GetRoutingID(), - url::Origin::Create(GURL(kExampleUrl)), - content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN, - content::DesktopMediaID::kFakeId), + url::Origin::Create(GURL(kExampleUrl)), media_id, /*extension_name=*/"", content::DesktopStreamRegistryType::kRegistryStreamTypeDesktop); @@ -1109,7 +1109,7 @@ CreateMediaStreamRequest( web_contents, requested_video_device_id, blink::mojom::MediaStreamType::GUM_DESKTOP_VIDEO_CAPTURE), - expected_result); + expected_result, media_id); } void StartTabScreenShare( @@ -1131,15 +1131,17 @@ CreateMediaStreamRequest( web_contents, /*requested_video_device_id=*/std::string(), blink::mojom::MediaStreamType::GUM_TAB_VIDEO_CAPTURE), - expected_result); + expected_result, media_id); } private: - void StartScreenShare( - std::unique_ptr<MediaAccessHandler> handler, - content::WebContents* web_contents, - content::MediaStreamRequest request, - blink::mojom::MediaStreamRequestResult expected_result) { + void StartScreenShare(std::unique_ptr<MediaAccessHandler> handler, + content::WebContents* web_contents, + content::MediaStreamRequest request, + blink::mojom::MediaStreamRequestResult expected_result, + const content::DesktopMediaID& media_id) { + // First check for the permission to start screen sharing. + // It should call DlpContentManager::CheckScreenShareRestriction(). base::test::TestFuture< std::reference_wrapper<const blink::MediaStreamDevices>, blink::mojom::MediaStreamRequestResult, @@ -1153,7 +1155,21 @@ /*extension=*/nullptr); ASSERT_TRUE(test_future.Wait()) << "MediaResponseCallback timed out."; EXPECT_EQ(test_future.Get<1>(), expected_result); + + // Simulate starting screen sharing. + // Calls DlpContentManager::OnScreenShareStarted(). + if (expected_result == blink::mojom::MediaStreamRequestResult::OK) { + DlpContentManagerAsh* manager = + static_cast<DlpContentManagerAsh*>(helper_->GetContentManager()); + EXPECT_CALL(stop_cb_, Run).Times(0); + manager->OnScreenShareStarted(kLabel, {media_id}, kApplicationTitle, + stop_cb_.Get(), + /*state_change_callback*/ base::DoNothing(), + /*source_callback=*/base::DoNothing()); + } } + + base::MockCallback<base::RepeatingClosure> stop_cb_; }; IN_PROC_BROWSER_TEST_F(DlpContentManagerAshScreenShareBrowserTest, @@ -1234,7 +1250,7 @@ helper_->ResetWarnNotifierForTesting(); } -// Starting screen sharing and navigating other tabs should create exactly one +// Starting screen sharing and visiting other tabs should create exactly one // reporting event. IN_PROC_BROWSER_TEST_F(DlpContentManagerAshScreenShareBrowserTest, ScreenShareReporting) { @@ -1246,8 +1262,7 @@ browser()->tab_strip_model()->GetActiveWebContents(); helper_->ChangeConfidentiality(web_contents, kScreenShareReported); - StartDesktopScreenShare(web_contents, - blink::mojom::MediaStreamRequestResult::OK); + StartTabScreenShare(web_contents, blink::mojom::MediaStreamRequestResult::OK); CheckEvents(DlpRulesManager::Restriction::kScreenShare, DlpRulesManager::Level::kReport, 1u); EXPECT_FALSE(display_service_tester.GetNotification( @@ -1262,6 +1277,12 @@ chrome::NewTab(browser()); ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GURL(kGoogleUrl))); ASSERT_NE(browser()->tab_strip_model()->GetActiveWebContents(), web_contents); + ASSERT_EQ(web_contents->GetLastCommittedURL(), origin); + ASSERT_EQ(browser() + ->tab_strip_model() + ->GetActiveWebContents() + ->GetLastCommittedURL(), + GURL(kGoogleUrl)); // Just additional check that visiting a tab with restricted content does not // affect the shared tab. helper_->ChangeConfidentiality(
diff --git a/chrome/browser/ash/policy/status_collector/app_info_generator.cc b/chrome/browser/ash/policy/status_collector/app_info_generator.cc index 92f809b7..9e041f7 100644 --- a/chrome/browser/ash/policy/status_collector/app_info_generator.cc +++ b/chrome/browser/ash/policy/status_collector/app_info_generator.cc
@@ -51,29 +51,29 @@ } } -em::AppInfo::AppType ExtractAppType(const apps::mojom::AppType app_type) { +em::AppInfo::AppType ExtractAppType(const apps::AppType app_type) { switch (app_type) { - case apps::mojom::AppType::kArc: + case apps::AppType::kArc: return em::AppInfo::AppType::AppInfo_AppType_TYPE_ARC; - case apps::mojom::AppType::kBuiltIn: + case apps::AppType::kBuiltIn: return em::AppInfo::AppType::AppInfo_AppType_TYPE_BUILTIN; - case apps::mojom::AppType::kCrostini: + case apps::AppType::kCrostini: return em::AppInfo::AppType::AppInfo_AppType_TYPE_CROSTINI; - case apps::mojom::AppType::kPluginVm: + case apps::AppType::kPluginVm: return em::AppInfo::AppType::AppInfo_AppType_TYPE_PLUGINVM; - case apps::mojom::AppType::kChromeApp: - case apps::mojom::AppType::kStandaloneBrowserChromeApp: + case apps::AppType::kChromeApp: + case apps::AppType::kStandaloneBrowserChromeApp: return em::AppInfo::AppType::AppInfo_AppType_TYPE_EXTENSION; - case apps::mojom::AppType::kWeb: - case apps::mojom::AppType::kSystemWeb: + case apps::AppType::kWeb: + case apps::AppType::kSystemWeb: return em::AppInfo::AppType::AppInfo_AppType_TYPE_WEB; - case apps::mojom::AppType::kBorealis: + case apps::AppType::kBorealis: return em::AppInfo::AppType::AppInfo_AppType_TYPE_BOREALIS; - case apps::mojom::AppType::kMacOs: - case apps::mojom::AppType::kStandaloneBrowser: - case apps::mojom::AppType::kExtension: - case apps::mojom::AppType::kRemote: - case apps::mojom::AppType::kUnknown: + case apps::AppType::kMacOs: + case apps::AppType::kStandaloneBrowser: + case apps::AppType::kExtension: + case apps::AppType::kRemote: + case apps::AppType::kUnknown: return em::AppInfo::AppType::AppInfo_AppType_TYPE_UNKNOWN; } } @@ -221,8 +221,8 @@ const apps::AppUpdate& update, const std::vector<em::TimePeriod>& app_activity) const { em::AppInfo info; - bool is_web_app = (update.AppType() == apps::mojom::AppType::kWeb) || - (update.AppType() == apps::mojom::AppType::kSystemWeb); + bool is_web_app = (update.AppType() == apps::AppType::kWeb) || + (update.AppType() == apps::AppType::kSystemWeb); if (!is_web_app) { info.set_app_id(update.AppId()); info.set_app_name(update.Name());
diff --git a/chrome/browser/ash/web_applications/personalization_app/personalization_app_user_provider_impl.cc b/chrome/browser/ash/web_applications/personalization_app/personalization_app_user_provider_impl.cc index 823d9a4..891638106 100644 --- a/chrome/browser/ash/web_applications/personalization_app/personalization_app_user_provider_impl.cc +++ b/chrome/browser/ash/web_applications/personalization_app/personalization_app_user_provider_impl.cc
@@ -4,13 +4,18 @@ #include "chrome/browser/ash/web_applications/personalization_app/personalization_app_user_provider_impl.h" +#include "ash/public/cpp/default_user_image.h" #include "ash/public/cpp/personalization_app/user_display_info.h" +#include "ash/webui/personalization_app/mojom/personalization_app.mojom-forward.h" #include "ash/webui/personalization_app/mojom/personalization_app.mojom.h" #include "ash/webui/personalization_app/mojom/personalization_app_mojom_traits.h" #include "base/bind.h" #include "base/containers/span.h" #include "base/memory/scoped_refptr.h" #include "base/strings/utf_string_conversions.h" +#include "base/task/sequenced_task_runner.h" +#include "base/task/task_traits.h" +#include "base/task/thread_pool.h" #include "chrome/browser/ash/camera_presence_notifier.h" #include "chrome/browser/ash/login/users/avatar/user_image_file_selector.h" #include "chrome/browser/ash/login/users/avatar/user_image_manager.h" @@ -19,6 +24,7 @@ #include "chrome/browser/ash/profiles/profile_helper.h" #include "chrome/browser/ash/web_applications/personalization_app/personalization_app_utils.h" #include "chrome/browser/profiles/profile.h" +#include "components/user_manager/user_image/user_image.h" #include "components/user_manager/user_info.h" #include "components/user_manager/user_manager.h" #include "content/public/browser/web_ui.h" @@ -27,6 +33,7 @@ #include "services/data_decoder/public/cpp/decode_image.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/base/webui/web_ui_util.h" +#include "ui/gfx/codec/png_codec.h" #include "ui/gfx/geometry/size.h" #include "url/gurl.h" @@ -35,17 +42,32 @@ using ash::personalization_app::GetAccountId; using ash::personalization_app::GetUser; -GURL GetUserImageDataUrl(const user_manager::User& user) { - if (user.GetImage().isNull()) - return GURL(); - return GURL(webui::GetBitmapDataUrl(*user.GetImage().bitmap())); +// Called on |image_encoding_task_runner_| sequence. +std::vector<unsigned char> ImageSkiaToPngBytes(const gfx::ImageSkia& image) { + if (image.isNull()) { + return {}; + } + + // Encode the image as png. + std::vector<unsigned char> output; + if (gfx::PNGCodec::EncodeBGRASkBitmap(*image.bitmap(), + /*discard_transparency=*/false, + &output)) { + return output; + } + + // Return empty vector if case encoding failed. + return {}; } } // namespace PersonalizationAppUserProviderImpl::PersonalizationAppUserProviderImpl( content::WebUI* web_ui) - : profile_(Profile::FromWebUI(web_ui)) { + : profile_(Profile::FromWebUI(web_ui)), + image_encoding_task_runner_(base::ThreadPool::CreateSequencedTaskRunner( + {base::TaskPriority::USER_VISIBLE, + base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN})) { ash::UserImageManager* user_image_manager = ash::ChromeUserManager::Get()->GetUserImageManager( GetAccountId(profile_)); @@ -166,15 +188,57 @@ if (user.GetAccountId() != desired_user->GetAccountId()) return; - int image_index = user.image_index(); - // Image is a valid default image and has an internal chrome://theme url. - if (ash::default_user_image::IsInCurrentImageSet(image_index)) { - user_image_observer_remote_->OnUserImageChanged( - ash::default_user_image::GetDefaultImageUrl(image_index)); - return; + // Cancel requests to encode and send external user image data because it is + // now out of date. + image_encoding_weak_ptr_factory_.InvalidateWeakPtrs(); + + int image_index = desired_user->image_index(); + switch (image_index) { + case user_manager::User::USER_IMAGE_INVALID: { + UpdateUserImageObserver( + ash::personalization_app::mojom::UserImage::NewInvalidImage( + ash::personalization_app::mojom::InvalidImage::New())); + break; + } + case user_manager::User::USER_IMAGE_EXTERNAL: { + if (desired_user->image_format() == user_manager::UserImage::FORMAT_PNG && + desired_user->has_image_bytes()) { + // No need to re-encode a png because already have encoded bytes. + auto image_bytes = desired_user->image_bytes(); + UpdateUserImageObserver( + ash::personalization_app::mojom::UserImage::NewExternalImage( + mojo_base::BigBuffer(base::make_span(image_bytes->front(), + image_bytes->size())))); + } else { + DCHECK(desired_user->GetImage().IsThreadSafe()) + << "User image loader marks user images as thread safe"; + image_encoding_task_runner_->PostTaskAndReplyWithResult( + FROM_HERE, + base::BindOnce(&ImageSkiaToPngBytes, desired_user->GetImage()), + base::BindOnce( + &PersonalizationAppUserProviderImpl::OnExternalUserImageEncoded, + image_encoding_weak_ptr_factory_.GetWeakPtr())); + } + break; + } + case user_manager::User::USER_IMAGE_PROFILE: { + UpdateUserImageObserver( + ash::personalization_app::mojom::UserImage::NewProfileImage( + ash::personalization_app::mojom::ProfileImage::New())); + break; + } + default: { + if (!ash::default_user_image::IsValidIndex(image_index)) { + LOG(ERROR) << "Invalid image index received"; + break; + } + // TODO(b/218602268) support deprecated user image text fields. + UpdateUserImageObserver( + ash::personalization_app::mojom::UserImage::NewDefaultImage( + ash::default_user_image::GetDefaultUserImage(image_index))); + break; + } } - // All other cases. - user_image_observer_remote_->OnUserImageChanged(GetUserImageDataUrl(user)); } void PersonalizationAppUserProviderImpl::OnUserProfileImageUpdated( @@ -215,6 +279,18 @@ user_image_manager->SaveUserImage(std::move(user_image)); } +void PersonalizationAppUserProviderImpl::OnExternalUserImageEncoded( + std::vector<unsigned char> encoded_png) { + UpdateUserImageObserver( + ash::personalization_app::mojom::UserImage::NewExternalImage( + mojo_base::BigBuffer(std::move(encoded_png)))); +} + +void PersonalizationAppUserProviderImpl::UpdateUserImageObserver( + ash::personalization_app::mojom::UserImagePtr user_image) { + user_image_observer_remote_->OnUserImageChanged(std::move(user_image)); +} + void PersonalizationAppUserProviderImpl::SetUserImageFileSelectorForTesting( std::unique_ptr<ash::UserImageFileSelector> file_selector) { user_image_file_selector_ = std::move(file_selector);
diff --git a/chrome/browser/ash/web_applications/personalization_app/personalization_app_user_provider_impl.h b/chrome/browser/ash/web_applications/personalization_app/personalization_app_user_provider_impl.h index 8fac0dc..1bacc738 100644 --- a/chrome/browser/ash/web_applications/personalization_app/personalization_app_user_provider_impl.h +++ b/chrome/browser/ash/web_applications/personalization_app/personalization_app_user_provider_impl.h
@@ -9,6 +9,7 @@ #include "ash/webui/personalization_app/personalization_app_user_provider.h" #include "base/memory/raw_ptr.h" #include "base/memory/ref_counted_memory.h" +#include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" #include "base/scoped_observation.h" #include "chrome/browser/ash/camera_presence_notifier.h" @@ -22,6 +23,10 @@ class Profile; +namespace base { +class SequencedTaskRunner; +} // namespace base + namespace content { class WebUI; } // namespace content @@ -80,6 +85,11 @@ void OnCameraImageDecoded(scoped_refptr<base::RefCountedBytes> photo_bytes, const SkBitmap& decoded_bitmap); + void OnExternalUserImageEncoded(std::vector<unsigned char> encoded_png); + + void UpdateUserImageObserver( + ash::personalization_app::mojom::UserImagePtr user_image); + // Pointer to profile of user that opened personalization SWA. Not owned. raw_ptr<Profile> profile_ = nullptr; @@ -99,10 +109,15 @@ std::unique_ptr<ash::UserImageFileSelector> user_image_file_selector_; + scoped_refptr<base::SequencedTaskRunner> image_encoding_task_runner_; + base::WeakPtrFactory<PersonalizationAppUserProviderImpl> weak_ptr_factory_{ this}; base::WeakPtrFactory<PersonalizationAppUserProviderImpl> + image_encoding_weak_ptr_factory_{this}; + + base::WeakPtrFactory<PersonalizationAppUserProviderImpl> image_decode_weak_ptr_factory_{this}; };
diff --git a/chrome/browser/ash/web_applications/personalization_app/personalization_app_user_provider_impl_unittest.cc b/chrome/browser/ash/web_applications/personalization_app/personalization_app_user_provider_impl_unittest.cc index f3bb090..a27928a 100644 --- a/chrome/browser/ash/web_applications/personalization_app/personalization_app_user_provider_impl_unittest.cc +++ b/chrome/browser/ash/web_applications/personalization_app/personalization_app_user_provider_impl_unittest.cc
@@ -9,6 +9,7 @@ #include "ash/constants/ash_features.h" #include "ash/webui/personalization_app/mojom/personalization_app.mojom.h" #include "base/callback_helpers.h" +#include "base/memory/ref_counted_memory.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/test/bind.h" @@ -26,6 +27,7 @@ #include "components/prefs/pref_registry_simple.h" #include "components/prefs/testing_pref_service.h" #include "components/user_manager/scoped_user_manager.h" +#include "components/user_manager/user_image/user_image.h" #include "components/user_manager/user_manager.h" #include "content/public/browser/web_contents.h" #include "content/public/test/browser_task_environment.h" @@ -33,7 +35,9 @@ #include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/bindings/remote.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/skia/include/core/SkColor.h" #include "ui/base/webui/web_ui_util.h" +#include "ui/gfx/codec/png_codec.h" #include "ui/gfx/image/image_skia.h" #include "url/gurl.h" @@ -61,6 +65,7 @@ gfx::ImageSkia CreateImage(int width, int height) { SkBitmap bitmap; bitmap.allocN32Pixels(width, height); + bitmap.eraseColor(SK_ColorGREEN); gfx::ImageSkia image = gfx::ImageSkia::CreateFrom1xBitmap(bitmap); return image; } @@ -68,8 +73,9 @@ class TestUserImageObserver : public ash::personalization_app::mojom::UserImageObserver { public: - void OnUserImageChanged(const GURL& image) override { - current_user_image_ = image; + void OnUserImageChanged( + ash::personalization_app::mojom::UserImagePtr image) override { + current_user_image_ = std::move(image); } void OnUserProfileImageUpdated(const GURL& profile_image) override { @@ -84,10 +90,10 @@ return user_image_observer_receiver_.BindNewPipeAndPassRemote(); } - const GURL& current_user_image() { + const ash::personalization_app::mojom::UserImage* current_user_image() { if (user_image_observer_receiver_.is_bound()) user_image_observer_receiver_.FlushForTesting(); - return current_user_image_; + return current_user_image_.get(); } const GURL& current_profile_image() { @@ -100,7 +106,7 @@ mojo::Receiver<ash::personalization_app::mojom::UserImageObserver> user_image_observer_receiver_{this}; - GURL current_user_image_; + ash::personalization_app::mojom::UserImagePtr current_user_image_; GURL current_profile_image_; }; @@ -172,7 +178,7 @@ test_user_image_observer_.pending_remote()); } - const GURL& current_user_image() { + const ash::personalization_app::mojom::UserImage* current_user_image() { if (user_provider_remote_.is_bound()) user_provider_remote_.FlushForTesting(); return test_user_image_observer_.current_user_image(); @@ -209,23 +215,26 @@ TEST_F(PersonalizationAppUserProviderImplTest, ObservesUserAvatarImage) { // Observer has not received any images yet because it is not bound. - EXPECT_EQ(GURL(), current_user_image()); + EXPECT_EQ(nullptr, current_user_image()); + // Mock out profile image so the test does not try to download a real one. + const gfx::ImageSkia& profile_image = CreateImage(50, 50); + user_image_manager()->SetDownloadedProfileImageForTesting(profile_image); + + user_image_manager()->SaveUserImageFromProfileImage(); SetUserImageObserver(); - // Observer received current user's avatar image as data url. - EXPECT_EQ(webui::GetBitmapDataUrl(*user_image().bitmap()), - current_user_image()); + // Observer received current user's avatar image. + EXPECT_TRUE(current_user_image()->is_profile_image()); // Select a default image. int image_index = ash::default_user_image::GetRandomDefaultImageIndex(); user_image_manager()->SaveUserDefaultImageIndex(image_index); - // Observer received the updated image url. Because it is a default image, - // receives the chrome://theme url. - EXPECT_EQ(base::StringPrintf("chrome://theme/IDR_LOGIN_DEFAULT_USER_%d", - image_index), - current_user_image()); + // Observer received the updated image information. Because it is a default + // image, receives a default image with the right index. + EXPECT_TRUE(current_user_image()->is_default_image()); + EXPECT_EQ(image_index, current_user_image()->get_default_image().index); } TEST_F(PersonalizationAppUserProviderImplTest, SelectDefaultImage) { @@ -236,11 +245,10 @@ user_provider_remote()->get()->SelectDefaultImage(image_index); user_provider_remote()->FlushForTesting(); - // Observer received the updated image url. Because it is a default image, - // receives the chrome://theme url. - EXPECT_EQ(base::StringPrintf("chrome://theme/IDR_LOGIN_DEFAULT_USER_%d", - image_index), - current_user_image()); + // Observer received the updated user image of type default with the right + // index. + EXPECT_TRUE(current_user_image()->is_default_image()); + EXPECT_EQ(image_index, current_user_image()->get_default_image().index); } TEST_F(PersonalizationAppUserProviderImplTest, ObservesUserProfileImage) { @@ -271,6 +279,36 @@ current_profile_image()); } +TEST_F(PersonalizationAppUserProviderImplTest, EncodesUserImageToPngBuffer) { + SetUserImageObserver(); + + gfx::ImageSkia test_image = CreateImage(4, 4); + test_image.MakeThreadSafe(); + + // Save a jpg user image. This will trigger the image encoding to png path. + user_image_manager()->SaveUserImage(std::make_unique<user_manager::UserImage>( + test_image, base::MakeRefCounted<base::RefCountedBytes>(), + user_manager::UserImage::ImageFormat::FORMAT_JPEG)); + + EXPECT_TRUE(current_user_image()->is_external_image()); + + auto encoded_png = base::MakeRefCounted<base::RefCountedBytes>( + current_user_image()->get_external_image().data(), + current_user_image()->get_external_image().size()); + + std::vector<unsigned char> expected_data; + ASSERT_TRUE(gfx::PNGCodec::EncodeBGRASkBitmap( + *test_image.bitmap(), /*discard_transparency=*/false, &expected_data)); + + // The BigBuffer data received from the observer should be equal to the test + // image encoded to png. + ASSERT_EQ(expected_data.size(), encoded_png->size()); + ASSERT_GT(expected_data.size(), 0); + for (auto i = 0; i < expected_data.size(); i++) { + EXPECT_EQ(expected_data.at(i), encoded_png->data().at(i)); + } +} + class PersonalizationAppUserProviderImplWithMockTest : public PersonalizationAppUserProviderImplTest { protected:
diff --git a/chrome/browser/ash/web_applications/personalization_app/personalization_app_wallpaper_provider_impl_unittest.cc b/chrome/browser/ash/web_applications/personalization_app/personalization_app_wallpaper_provider_impl_unittest.cc index 7c4a6400..fa9d85e 100644 --- a/chrome/browser/ash/web_applications/personalization_app/personalization_app_wallpaper_provider_impl_unittest.cc +++ b/chrome/browser/ash/web_applications/personalization_app/personalization_app_wallpaper_provider_impl_unittest.cc
@@ -322,8 +322,8 @@ const GURL image_url("http://test_url"); const uint64_t unit_id = 1; std::vector<ash::OnlineWallpaperVariant> variants; - variants.emplace_back(ash::OnlineWallpaperVariant( - asset_id, image_url, backdrop::Image::IMAGE_TYPE_UNKNOWN)); + variants.emplace_back(asset_id, image_url, + backdrop::Image::IMAGE_TYPE_UNKNOWN); AddWallpaperImage(asset_id, /*image_info=*/{ image_url, @@ -355,8 +355,8 @@ const GURL image_url("http://test_url"); const uint64_t unit_id = 1; std::vector<ash::OnlineWallpaperVariant> variants; - variants.emplace_back(ash::OnlineWallpaperVariant( - asset_id, image_url, backdrop::Image::IMAGE_TYPE_UNKNOWN)); + variants.emplace_back(asset_id, image_url, + backdrop::Image::IMAGE_TYPE_UNKNOWN); AddWallpaperImage(asset_id, /*image_info=*/{ image_url, @@ -391,8 +391,8 @@ const GURL image_url("http://test_url"); const uint64_t unit_id = 1; std::vector<ash::OnlineWallpaperVariant> variants; - variants.emplace_back(ash::OnlineWallpaperVariant( - asset_id, image_url, backdrop::Image::IMAGE_TYPE_UNKNOWN)); + variants.emplace_back(asset_id, image_url, + backdrop::Image::IMAGE_TYPE_UNKNOWN); AddWallpaperImage(asset_id, /*image_info=*/{ image_url,
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 6dbf816e..dd603ad 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -2280,6 +2280,13 @@ process, profile); } + // This passes the preference set by an enterprise policy on to a blink + // switch so that we know whether to force WebSQL to be enabled. + if (g_browser_process->local_state()->GetBoolean( + policy::policy_prefs::kWebSQLAccess)) { + command_line->AppendSwitch(blink::switches::kWebSQLAccess); + } + #if BUILDFLAG(IS_CHROMEOS_ASH) const std::string& login_profile = browser_command_line.GetSwitchValueASCII(ash::switches::kLoginProfile);
diff --git a/chrome/browser/chrome_content_browser_client_unittest.cc b/chrome/browser/chrome_content_browser_client_unittest.cc index 7bf9c33..3067f33 100644 --- a/chrome/browser/chrome_content_browser_client_unittest.cc +++ b/chrome/browser/chrome_content_browser_client_unittest.cc
@@ -845,3 +845,41 @@ &profile_, GURL(kScope))); } #endif // BUILDFLAG(ENABLE_EXTENSIONS) + +class ChromeContentBrowserClientSwitchTest : public testing::Test { + public: + ChromeContentBrowserClientSwitchTest() + : command_line_(base::CommandLine::NO_PROGRAM), + testing_local_state_(TestingBrowserProcess::GetGlobal()) {} + + void SetUp() override { + command_line_.AppendSwitchASCII(switches::kProcessType, + switches::kRendererProcess); + } + + protected: + base::CommandLine command_line_; + ScopedTestingLocalState testing_local_state_; + ChromeContentBrowserClient client_; + content::BrowserTaskEnvironment task_environment_; + static const int kFakeChildProcessId = 1; +}; + +TEST_F(ChromeContentBrowserClientSwitchTest, WebSQLAccessDefault) { + client_.AppendExtraCommandLineSwitches(&command_line_, kFakeChildProcessId); + EXPECT_FALSE(command_line_.HasSwitch(blink::switches::kWebSQLAccess)); +} + +TEST_F(ChromeContentBrowserClientSwitchTest, WebSQLAccessDisabled) { + testing_local_state_.Get()->SetBoolean(policy::policy_prefs::kWebSQLAccess, + false); + client_.AppendExtraCommandLineSwitches(&command_line_, kFakeChildProcessId); + EXPECT_FALSE(command_line_.HasSwitch(blink::switches::kWebSQLAccess)); +} + +TEST_F(ChromeContentBrowserClientSwitchTest, WebSQLAccessEnabled) { + testing_local_state_.Get()->SetBoolean(policy::policy_prefs::kWebSQLAccess, + true); + client_.AppendExtraCommandLineSwitches(&command_line_, kFakeChildProcessId); + EXPECT_TRUE(command_line_.HasSwitch(blink::switches::kWebSQLAccess)); +}
diff --git a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc index 52d8984f..8a9c193 100644 --- a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc +++ b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
@@ -337,33 +337,33 @@ return api::autotest_private::ShelfItemStatus::SHELF_ITEM_STATUS_NONE; } -api::autotest_private::AppType GetAppType(apps::mojom::AppType type) { +api::autotest_private::AppType GetAppType(apps::AppType type) { switch (type) { - case apps::mojom::AppType::kArc: + case apps::AppType::kArc: return api::autotest_private::AppType::APP_TYPE_ARC; - case apps::mojom::AppType::kBuiltIn: + case apps::AppType::kBuiltIn: return api::autotest_private::AppType::APP_TYPE_BUILTIN; - case apps::mojom::AppType::kCrostini: + case apps::AppType::kCrostini: return api::autotest_private::AppType::APP_TYPE_CROSTINI; - case apps::mojom::AppType::kChromeApp: - case apps::mojom::AppType::kExtension: + case apps::AppType::kChromeApp: + case apps::AppType::kExtension: return api::autotest_private::AppType::APP_TYPE_EXTENSION; - case apps::mojom::AppType::kPluginVm: + case apps::AppType::kPluginVm: return api::autotest_private::AppType::APP_TYPE_PLUGINVM; - case apps::mojom::AppType::kWeb: - case apps::mojom::AppType::kSystemWeb: + case apps::AppType::kWeb: + case apps::AppType::kSystemWeb: return api::autotest_private::AppType::APP_TYPE_WEB; - case apps::mojom::AppType::kUnknown: + case apps::AppType::kUnknown: return api::autotest_private::AppType::APP_TYPE_NONE; - case apps::mojom::AppType::kMacOs: + case apps::AppType::kMacOs: return api::autotest_private::AppType::APP_TYPE_MACOS; - case apps::mojom::AppType::kStandaloneBrowser: + case apps::AppType::kStandaloneBrowser: return api::autotest_private::AppType::APP_TYPE_STANDALONEBROWSER; - case apps::mojom::AppType::kRemote: + case apps::AppType::kRemote: return api::autotest_private::AppType::APP_TYPE_REMOTE; - case apps::mojom::AppType::kBorealis: + case apps::AppType::kBorealis: return api::autotest_private::AppType::APP_TYPE_BOREALIS; - case apps::mojom::AppType::kStandaloneBrowserChromeApp: + case apps::AppType::kStandaloneBrowserChromeApp: // Intentionally fall-through for now. // TODO(https://crbug.com/1225848): Figure out appropriate behavior for // Lacros-hosted chrome-apps.
diff --git a/chrome/browser/content_creation/reactions/internal/android/java/src/org/chromium/chrome/browser/content_creation/reactions/scene/SceneCoordinator.java b/chrome/browser/content_creation/reactions/internal/android/java/src/org/chromium/chrome/browser/content_creation/reactions/scene/SceneCoordinator.java index ccaf188..222bb23 100644 --- a/chrome/browser/content_creation/reactions/internal/android/java/src/org/chromium/chrome/browser/content_creation/reactions/scene/SceneCoordinator.java +++ b/chrome/browser/content_creation/reactions/internal/android/java/src/org/chromium/chrome/browser/content_creation/reactions/scene/SceneCoordinator.java
@@ -135,6 +135,8 @@ mNumReactionsInPosition.add(1); } addReactionLayoutToScene(reactionLayout, lp); + reactionLayout.announceForAccessibility(mActivity.getString( + R.string.lightweight_reactions_reaction_added_announcement)); }); } @@ -362,6 +364,8 @@ newLayoutParams.bottomMargin = oldLayoutParams.bottomMargin - offsetPx; } addReactionLayoutToScene(newReactionLayout, newLayoutParams); + mActiveReaction.announceForAccessibility(mActivity.getString( + R.string.lightweight_reactions_reaction_duplicated_announcement)); }); }
diff --git a/chrome/browser/devtools/protocol/emulation_handler.cc b/chrome/browser/devtools/protocol/emulation_handler.cc index afdef64..eff8165 100644 --- a/chrome/browser/devtools/protocol/emulation_handler.cc +++ b/chrome/browser/devtools/protocol/emulation_handler.cc
@@ -42,9 +42,12 @@ } // Note since the observer removes itself when the info bar is removed, the - // observer is added at most once because of the info bar nullity check above. - info_bar_manager->AddObserver(this); + // observer is added at most once because of the info bar nullity check + // above. automation_info_bar_ = AutomationInfoBarDelegate::Create(info_bar_manager); + if (automation_info_bar_) { + info_bar_manager->AddObserver(this); + } return protocol::Response::FallThrough(); }
diff --git a/chrome/browser/download/android/BUILD.gn b/chrome/browser/download/android/BUILD.gn index e22e884..8f8c134d 100644 --- a/chrome/browser/download/android/BUILD.gn +++ b/chrome/browser/download/android/BUILD.gn
@@ -62,6 +62,7 @@ "java/src/org/chromium/chrome/browser/download/home/DownloadManagerUiConfigHelper.java", "java/src/org/chromium/chrome/browser/download/home/FaviconProvider.java", "java/src/org/chromium/chrome/browser/download/home/JustNowProvider.java", + "java/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorFactory.java", "java/src/org/chromium/chrome/browser/download/settings/DownloadDirectoryAdapter.java", "java/src/org/chromium/chrome/browser/download/settings/DownloadLocationPreference.java", "java/src/org/chromium/chrome/browser/download/settings/DownloadLocationPreferenceAdapter.java", @@ -137,6 +138,7 @@ "java/src/org/chromium/chrome/browser/download/MimeUtils.java", "java/src/org/chromium/chrome/browser/download/MixedContentDownloadDialogBridge.java", "java/src/org/chromium/chrome/browser/download/StringUtils.java", + "java/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorFactory.java", ] }
diff --git a/chrome/browser/download/android/items/offline_content_aggregator_factory_android.cc b/chrome/browser/download/android/items/offline_content_aggregator_factory_android.cc index 02967070..6ec908a 100644 --- a/chrome/browser/download/android/items/offline_content_aggregator_factory_android.cc +++ b/chrome/browser/download/android/items/offline_content_aggregator_factory_android.cc
@@ -4,8 +4,8 @@ #include "base/android/jni_android.h" #include "base/android/scoped_java_ref.h" -#include "chrome/android/chrome_jni_headers/OfflineContentAggregatorFactory_jni.h" #include "chrome/browser/android/profile_key_util.h" +#include "chrome/browser/download/android/jni_headers/OfflineContentAggregatorFactory_jni.h" #include "chrome/browser/offline_items_collection/offline_content_aggregator_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_android.h"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorFactory.java b/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorFactory.java similarity index 100% rename from chrome/android/java/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorFactory.java rename to chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorFactory.java
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc index 7ce76455..62fe8998 100644 --- a/chrome/browser/extensions/api/settings_private/prefs_util.cc +++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -63,6 +63,7 @@ #include "ash/constants/ash_pref_names.h" #include "ash/constants/ash_pref_names.h" // nogncheck #include "ash/public/cpp/ambient/ambient_prefs.h" +#include "base/metrics/histogram_functions.h" #include "chrome/browser/ash/app_restore/full_restore_prefs.h" #include "chrome/browser/ash/crostini/crostini_pref_names.h" #include "chrome/browser/ash/guest_os/guest_os_pref_names.h" @@ -1125,6 +1126,18 @@ return settings_private::SetPrefResult::PREF_TYPE_UNSUPPORTED; } +#if BUILDFLAG(IS_CHROMEOS_ASH) + if (pref_name == ash::prefs::kDarkModeEnabled) { + DCHECK(value->is_bool()); + base::UmaHistogramBoolean("Ash.DarkTheme.Settings.IsDarkModeEnabled", + value->GetBool()); + } else if (pref_name == ash::prefs::kColorModeThemed) { + DCHECK(value->is_bool()); + base::UmaHistogramBoolean("Ash.DarkTheme.Settings.IsThemed", + value->GetBool()); + } +#endif + // TODO(orenb): Process setting metrics here and in the CrOS setting method // too (like "ProcessUserMetric" in CoreOptionsHandler). return settings_private::SetPrefResult::SUCCESS;
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index b8d2d4a4..ceb130a 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -6163,6 +6163,11 @@ "expiry_milestone": 114 }, { + "name": "web-sql-access", + "owners": [ "arichiv"], + "expiry_milestone": 113 + }, + { "name": "webnotes-dynamic-templates", "owners": ["chrome-creation@google.com"], "expiry_milestone": 103
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index f9e61d64..26d9c66e 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -2927,6 +2927,10 @@ "The Chrome version in the User-Agent string will be reported as " "Chrome/<major_version>.0.0.0."; +const char kWebSQLAccessName[] = "Allows access to WebSQL APIs"; +const char kWebSQLAccessDescription[] = + "The WebSQL API is enabled by default, but can be disabled here."; + // Android --------------------------------------------------------------------- #if BUILDFLAG(IS_ANDROID)
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 6a7f8e4..138ffb5 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -1668,6 +1668,9 @@ extern const char kReduceUserAgentMinorVersionName[]; extern const char kReduceUserAgentMinorVersionDescription[]; +extern const char kWebSQLAccessName[]; +extern const char kWebSQLAccessDescription[]; + // Android -------------------------------------------------------------------- #if BUILDFLAG(IS_ANDROID)
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc index 12bb25b..8f2bcae3c 100644 --- a/chrome/browser/flags/android/chrome_feature_list.cc +++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -326,6 +326,7 @@ &messages::kMessagesForAndroidInstantApps, &messages::kMessagesForAndroidReaderMode, &messages::kMessagesForAndroidReduceLayoutChanges, + &messages::kMessagesForAndroidSaveCard, &messages::kMessagesForAndroidSyncError, &offline_pages::kOfflineIndicatorFeature, &offline_pages::kOfflinePagesCTFeature, // See crbug.com/620421. @@ -347,6 +348,7 @@ &password_manager::features::kPasswordChange, &password_manager::features::kPasswordScriptsFetching, &password_manager::features::kRecoverFromNeverSaveAndroid, + &password_manager::features::kTouchToFillPasswordSubmission, &password_manager::features::kUnifiedCredentialManagerDryRun, &password_manager::features::kUnifiedPasswordManagerAndroid, &password_manager::features::kUnifiedPasswordManagerMigration,
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 381eb45..5db92b3 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
@@ -517,6 +517,7 @@ public static final String TOOLBAR_IPH_ANDROID = "ToolbarIphAndroid"; public static final String TOOLBAR_MIC_IPH_ANDROID = "ToolbarMicIphAndroid"; public static final String TOOLBAR_USE_HARDWARE_BITMAP_DRAW = "ToolbarUseHardwareBitmapDraw"; + public static final String TOUCH_TO_FILL_PASSWORD_SUBMISSION = "TouchToFillPasswordSubmission"; public static final String TRANSLATE_ASSIST_CONTENT = "TranslateAssistContent"; public static final String TRANSLATE_INTENT = "TranslateIntent"; public static final String TRANSLATE_TFLITE = "TFLiteLanguageDetectionEnabled";
diff --git a/chrome/browser/metrics/power/power_metrics_reporter.cc b/chrome/browser/metrics/power/power_metrics_reporter.cc index 625f288..60d96081 100644 --- a/chrome/browser/metrics/power/power_metrics_reporter.cc +++ b/chrome/browser/metrics/power/power_metrics_reporter.cc
@@ -329,13 +329,17 @@ // .ResourceCoalition.CPUTime2_10sec.AllTabsHidden_NoVideoCaptureOrAudio" constexpr double kHighCPUUsageThreshold_AllTabsHidden = 0.1433; + // This matches the conditions for scenario + // ".AllTabsHidden_NoVideoCaptureOrAudio"; if (short_interval_data.max_visible_window_count == 0 && + short_interval_data.max_tab_count > 0 && short_interval_data.time_playing_audio.is_zero() && short_interval_data.time_capturing_video.is_zero() && coalition_resource_usage_rate->cpu_time_per_second >= kHighCPUUsageThreshold_AllTabsHidden) { const base::TimeTicks now = base::TimeTicks::Now(); - constexpr char kEventTitle[] = "High CPU - All tabs Hidden"; + constexpr char kEventTitle[] = + "High CPU - All Tabs Hidden, No Video Capture or Audio"; TRACE_EVENT_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0( "browser", kEventTitle, TRACE_ID_LOCAL(this),
diff --git a/chrome/browser/notifications/arc_application_notifier_controller.cc b/chrome/browser/notifications/arc_application_notifier_controller.cc index 581afaf..70cdf52 100644 --- a/chrome/browser/notifications/arc_application_notifier_controller.cc +++ b/chrome/browser/notifications/arc_application_notifier_controller.cc
@@ -16,7 +16,7 @@ #include "chrome/common/chrome_features.h" #include "components/services/app_service/public/cpp/app_types.h" #include "components/services/app_service/public/cpp/app_update.h" -#include "components/services/app_service/public/cpp/permission_utils.h" +#include "components/services/app_service/public/cpp/permission.h" #include "components/services/app_service/public/mojom/types.mojom.h" #include "ui/message_center/public/cpp/message_center_constants.h" #include "ui/message_center/public/cpp/notifier_id.h" @@ -48,15 +48,14 @@ service->AppRegistryCache().ForEachApp([¬ifier_dataset]( const apps::AppUpdate& update) { - if (update.AppType() != apps::mojom::AppType::kArc) + if (update.AppType() != apps::AppType::kArc) return; for (const auto& permission : update.Permissions()) { - if (permission->permission_type != - apps::mojom::PermissionType::kNotifications) { + if (permission->permission_type != apps::PermissionType::kNotifications) { continue; } - DCHECK(permission->value->is_bool_value()); + DCHECK(permission->value->bool_value.has_value()); // Do not include notifier metadata for system apps. if (update.InstallReason() == apps::InstallReason::kSystem) { return; @@ -64,7 +63,7 @@ notifier_dataset.push_back(NotifierDataset{ update.AppId() /*app_id*/, update.ShortName() /*app_name*/, update.PublisherId() /*publisher_id*/, - permission->value->get_bool_value() /*enabled*/}); + permission->value->bool_value.value() /*enabled*/}); } }); @@ -166,12 +165,11 @@ if (update.PermissionsChanged()) { for (const auto& permission : update.Permissions()) { - if (permission->permission_type == - apps::mojom::PermissionType::kNotifications) { + if (permission->permission_type == apps::PermissionType::kNotifications) { message_center::NotifierId notifier_id( message_center::NotifierType::ARC_APPLICATION, update.AppId()); - observer_->OnNotifierEnabledChanged( - notifier_id, apps_util::IsPermissionEnabled(permission->value)); + observer_->OnNotifierEnabledChanged(notifier_id, + permission->IsPermissionEnabled()); } } }
diff --git a/chrome/browser/notifications/pwa_notifier_controller.cc b/chrome/browser/notifications/pwa_notifier_controller.cc index b4ed4a96..46b51349 100644 --- a/chrome/browser/notifications/pwa_notifier_controller.cc +++ b/chrome/browser/notifications/pwa_notifier_controller.cc
@@ -14,7 +14,7 @@ #include "chrome/common/chrome_features.h" #include "components/services/app_service/public/cpp/app_types.h" #include "components/services/app_service/public/cpp/app_update.h" -#include "components/services/app_service/public/cpp/permission_utils.h" +#include "components/services/app_service/public/cpp/permission.h" #include "components/services/app_service/public/mojom/types.mojom.h" #include "ui/message_center/public/cpp/message_center_constants.h" #include "ui/message_center/public/cpp/notifier_id.h" @@ -40,15 +40,15 @@ std::vector<NotifierDataset> notifier_dataset; service->AppRegistryCache().ForEachApp( [¬ifier_dataset](const apps::AppUpdate& update) { - if (update.AppType() != apps::mojom::AppType::kWeb) + if (update.AppType() != apps::AppType::kWeb) return; for (const auto& permission : update.Permissions()) { if (permission->permission_type != - apps::mojom::PermissionType::kNotifications) { + apps::PermissionType::kNotifications) { continue; } - DCHECK(permission->value->is_tristate_value()); + DCHECK(permission->value->tristate_value.has_value()); // Do not include notifier metadata for system apps. if (update.InstallReason() == apps::InstallReason::kSystem) { return; @@ -56,7 +56,7 @@ notifier_dataset.push_back(NotifierDataset{ update.AppId() /*app_id*/, update.ShortName() /*app_name*/, update.PublisherId() /*publisher_id*/, - apps_util::IsPermissionEnabled(permission->value)}); + permission->IsPermissionEnabled()}); } }); std::vector<ash::NotifierMetadata> notifiers; @@ -156,12 +156,11 @@ if (update.PermissionsChanged()) { for (const auto& permission : update.Permissions()) { - if (permission->permission_type == - apps::mojom::PermissionType::kNotifications) { + if (permission->permission_type == apps::PermissionType::kNotifications) { message_center::NotifierId notifier_id( message_center::NotifierType::APPLICATION, update.AppId()); - observer_->OnNotifierEnabledChanged( - notifier_id, apps_util::IsPermissionEnabled(permission->value)); + observer_->OnNotifierEnabledChanged(notifier_id, + permission->IsPermissionEnabled()); } } }
diff --git a/chrome/browser/page_load_metrics/observers/android_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/android_page_load_metrics_observer.cc index c7d66dc..e52652e 100644 --- a/chrome/browser/page_load_metrics/observers/android_page_load_metrics_observer.cc +++ b/chrome/browser/page_load_metrics/observers/android_page_load_metrics_observer.cc
@@ -72,39 +72,28 @@ void AndroidPageLoadMetricsObserver::OnFirstContentfulPaintInPage( const page_load_metrics::mojom::PageLoadTiming& timing) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - int64_t first_contentful_paint_ms = - timing.paint_timing->first_contentful_paint->InMilliseconds(); - ReportFirstContentfulPaint( - (GetDelegate().GetNavigationStart() - base::TimeTicks()).InMicroseconds(), - first_contentful_paint_ms); + ReportFirstContentfulPaint(GetDelegate().GetNavigationStart(), + *timing.paint_timing->first_contentful_paint); } void AndroidPageLoadMetricsObserver::OnFirstInputInPage( const page_load_metrics::mojom::PageLoadTiming& timing) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - int64_t first_input_delay_ms = - timing.interactive_timing->first_input_delay->InMilliseconds(); - ReportFirstInputDelay(first_input_delay_ms); + ReportFirstInputDelay(*timing.interactive_timing->first_input_delay); } void AndroidPageLoadMetricsObserver::OnFirstMeaningfulPaintInMainFrameDocument( const page_load_metrics::mojom::PageLoadTiming& timing) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - int64_t first_meaningful_paint_ms = - timing.paint_timing->first_meaningful_paint->InMilliseconds(); - ReportFirstMeaningfulPaint( - (GetDelegate().GetNavigationStart() - base::TimeTicks()).InMicroseconds(), - first_meaningful_paint_ms); + ReportFirstMeaningfulPaint(GetDelegate().GetNavigationStart(), + *timing.paint_timing->first_meaningful_paint); } void AndroidPageLoadMetricsObserver::OnLoadEventStart( const page_load_metrics::mojom::PageLoadTiming& timing) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - int64_t load_event_start_ms = - timing.document_timing->load_event_start->InMilliseconds(); - ReportLoadEventStart( - (GetDelegate().GetNavigationStart() - base::TimeTicks()).InMicroseconds(), - load_event_start_ms); + ReportLoadEventStart(GetDelegate().GetNavigationStart(), + *timing.document_timing->load_event_start); } void AndroidPageLoadMetricsObserver::OnLoadedResource( @@ -166,7 +155,7 @@ GetDelegate().GetWebContents()->GetJavaWebContents(); JNIEnv* env = base::android::AttachCurrentThread(); int64_t navigation_start_tick = - (GetDelegate().GetNavigationStart() - base::TimeTicks()).InMicroseconds(); + GetDelegate().GetNavigationStart().ToUptimeMicros(); const page_load_metrics::ContentfulPaintTimingInfo& largest_contentful_paint = GetDelegate() .GetLargestContentfulPaintHandler() @@ -201,39 +190,39 @@ } void AndroidPageLoadMetricsObserver::ReportFirstContentfulPaint( - int64_t navigation_start_tick, - int64_t first_contentful_paint_ms) { + base::TimeTicks navigation_start_tick, + base::TimeDelta first_contentful_paint) { base::android::ScopedJavaLocalRef<jobject> java_web_contents = GetDelegate().GetWebContents()->GetJavaWebContents(); JNIEnv* env = base::android::AttachCurrentThread(); Java_PageLoadMetrics_onFirstContentfulPaint( env, java_web_contents, static_cast<jlong>(navigation_id_), - static_cast<jlong>(navigation_start_tick), - static_cast<jlong>(first_contentful_paint_ms)); + navigation_start_tick.ToUptimeMicros(), + static_cast<jlong>(first_contentful_paint.InMilliseconds())); } void AndroidPageLoadMetricsObserver::ReportFirstMeaningfulPaint( - int64_t navigation_start_tick, - int64_t first_meaningful_paint_ms) { + base::TimeTicks navigation_start_tick, + base::TimeDelta first_meaningful_paint) { base::android::ScopedJavaLocalRef<jobject> java_web_contents = GetDelegate().GetWebContents()->GetJavaWebContents(); JNIEnv* env = base::android::AttachCurrentThread(); Java_PageLoadMetrics_onFirstMeaningfulPaint( env, java_web_contents, static_cast<jlong>(navigation_id_), - static_cast<jlong>(navigation_start_tick), - static_cast<jlong>(first_meaningful_paint_ms)); + navigation_start_tick.ToUptimeMicros(), + static_cast<jlong>(first_meaningful_paint.InMilliseconds())); } void AndroidPageLoadMetricsObserver::ReportLoadEventStart( - int64_t navigation_start_tick, - int64_t load_event_start_ms) { + base::TimeTicks navigation_start_tick, + base::TimeDelta load_event_start) { base::android::ScopedJavaLocalRef<jobject> java_web_contents = GetDelegate().GetWebContents()->GetJavaWebContents(); JNIEnv* env = base::android::AttachCurrentThread(); Java_PageLoadMetrics_onLoadEventStart( env, java_web_contents, static_cast<jlong>(navigation_id_), - static_cast<jlong>(navigation_start_tick), - static_cast<jlong>(load_event_start_ms)); + navigation_start_tick.ToUptimeMicros(), + static_cast<jlong>(load_event_start.InMilliseconds())); } void AndroidPageLoadMetricsObserver::ReportLoadedMainResource( @@ -256,11 +245,11 @@ } void AndroidPageLoadMetricsObserver::ReportFirstInputDelay( - int64_t first_input_delay_ms) { + base::TimeDelta first_input_delay) { base::android::ScopedJavaLocalRef<jobject> java_web_contents = GetDelegate().GetWebContents()->GetJavaWebContents(); JNIEnv* env = base::android::AttachCurrentThread(); Java_PageLoadMetrics_onFirstInputDelay( env, java_web_contents, static_cast<jlong>(navigation_id_), - static_cast<jlong>(first_input_delay_ms)); + static_cast<jlong>(first_input_delay.InMilliseconds())); }
diff --git a/chrome/browser/page_load_metrics/observers/android_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/android_page_load_metrics_observer.h index 2e5b869..8ded81d 100644 --- a/chrome/browser/page_load_metrics/observers/android_page_load_metrics_observer.h +++ b/chrome/browser/page_load_metrics/observers/android_page_load_metrics_observer.h
@@ -8,6 +8,7 @@ #include <jni.h> #include "base/memory/raw_ptr.h" +#include "base/time/time.h" #include "components/page_load_metrics/browser/page_load_metrics_observer.h" #include "net/nqe/effective_connection_type.h" @@ -67,14 +68,16 @@ int64_t http_rtt_ms, int64_t transport_rtt_ms); - virtual void ReportFirstContentfulPaint(int64_t navigation_start_tick, - int64_t first_contentful_paint_ms); + virtual void ReportFirstContentfulPaint( + base::TimeTicks navigation_start_tick, + base::TimeDelta first_contentful_paint); - virtual void ReportFirstMeaningfulPaint(int64_t navigation_start_tick, - int64_t first_meaningful_paint_ms); + virtual void ReportFirstMeaningfulPaint( + base::TimeTicks navigation_start_tick, + base::TimeDelta first_meaningful_paint); - virtual void ReportLoadEventStart(int64_t navigation_start_tick, - int64_t load_event_start_ms); + virtual void ReportLoadEventStart(base::TimeTicks navigation_start_tick, + base::TimeDelta load_event_start); virtual void ReportLoadedMainResource(int64_t dns_start_ms, int64_t dns_end_ms, @@ -84,7 +87,7 @@ int64_t send_start_ms, int64_t send_end_ms); - virtual void ReportFirstInputDelay(int64_t first_input_delay_ms); + virtual void ReportFirstInputDelay(base::TimeDelta first_input_delay); private: bool did_dispatch_on_main_resource_ = false;
diff --git a/chrome/browser/page_load_metrics/observers/android_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/android_page_load_metrics_observer_unittest.cc index e0e0ed6..5f22cb8 100644 --- a/chrome/browser/page_load_metrics/observers/android_page_load_metrics_observer_unittest.cc +++ b/chrome/browser/page_load_metrics/observers/android_page_load_metrics_observer_unittest.cc
@@ -50,11 +50,11 @@ return reported_first_contentful_paint_ms_; } - int64_t reported_navigation_start_tick_fcp() const { + base::TimeTicks reported_navigation_start_tick_fcp() const { return reported_navigation_start_tick_fcp_; } - int64_t reported_navigation_start_tick_load() const { + base::TimeTicks reported_navigation_start_tick_load() const { return reported_navigation_start_tick_load_; } @@ -74,16 +74,18 @@ reported_transport_rtt_ms_ = transport_rtt_ms; } - void ReportFirstContentfulPaint(int64_t navigation_start_tick, - int64_t first_contentful_paint_ms) override { + void ReportFirstContentfulPaint( + base::TimeTicks navigation_start_tick, + base::TimeDelta first_contentful_paint) override { reported_navigation_start_tick_fcp_ = navigation_start_tick; - reported_first_contentful_paint_ms_ = first_contentful_paint_ms; + reported_first_contentful_paint_ms_ = + first_contentful_paint.InMilliseconds(); } - void ReportLoadEventStart(int64_t navigation_start_tick, - int64_t load_event_start_ms) override { + void ReportLoadEventStart(base::TimeTicks navigation_start_tick, + base::TimeDelta load_event_start) override { reported_navigation_start_tick_load_ = navigation_start_tick; - reported_load_event_start_ms_ = load_event_start_ms; + reported_load_event_start_ms_ = load_event_start.InMilliseconds(); } void ReportLoadedMainResource(int64_t dns_start_ms, @@ -102,8 +104,8 @@ int64_t reported_http_rtt_ms_ = 0; int64_t reported_transport_rtt_ms_ = 0; int64_t reported_first_contentful_paint_ms_ = 0; - int64_t reported_navigation_start_tick_fcp_ = 0; - int64_t reported_navigation_start_tick_load_ = 0; + base::TimeTicks reported_navigation_start_tick_fcp_; + base::TimeTicks reported_navigation_start_tick_load_; int64_t reported_load_event_start_ms_ = 0; int64_t reported_dns_start_ms_ = 0; }; @@ -125,9 +127,7 @@ TestAndroidPageLoadMetricsObserver* observer() const { return observer_ptr_; } - int64_t GetNavigationStartMicroseconds() const { - return (navigation_start_ - base::TimeTicks()).InMicroseconds(); - } + base::TimeTicks GetNavigationStart() const { return navigation_start_; } void SetNetworkQualityMock() { EXPECT_CALL(mock_network_quality_tracker(), GetEffectiveConnectionType()) @@ -222,9 +222,9 @@ NavigateAndCommit(GURL("https://www.example.com")); tester()->SimulateTimingUpdate(timing); EXPECT_EQ(30, observer()->reported_load_event_start_ms()); - EXPECT_EQ(GetNavigationStartMicroseconds(), + EXPECT_EQ(GetNavigationStart(), observer()->reported_navigation_start_tick_load()); EXPECT_EQ(20, observer()->reported_first_contentful_paint_ms()); - EXPECT_EQ(GetNavigationStartMicroseconds(), + EXPECT_EQ(GetNavigationStart(), observer()->reported_navigation_start_tick_fcp()); }
diff --git a/chrome/browser/partnercustomizations/BUILD.gn b/chrome/browser/partnercustomizations/BUILD.gn index 69394ec..26cc6dcd7 100644 --- a/chrome/browser/partnercustomizations/BUILD.gn +++ b/chrome/browser/partnercustomizations/BUILD.gn
@@ -23,6 +23,15 @@ android_library("delegate_public_impl_java") { sources = [ "java/src/org/chromium/chrome/browser/partnercustomizations/CustomizationProviderDelegateImpl.java" ] + deps = [ ":delegate_java" ] +} + +generate_jni("jni_headers") { + sources = [ "java/src/org/chromium/chrome/browser/partnercustomizations/PartnerBrowserCustomizations.java" ] +} + +android_library("java") { + sources = [ "java/src/org/chromium/chrome/browser/partnercustomizations/PartnerBrowserCustomizations.java" ] deps = [ ":delegate_java", "//base:base_java", @@ -30,11 +39,44 @@ "//chrome/browser/preferences:java", "//components/embedder_support/android:util_java", "//components/version_info/android:version_constants_java", + "//content/public/android:content_main_dex_java", "//third_party/androidx:androidx_annotation_annotation_java", - "//ui/android:ui_java", ] } -android_library("java") { - sources = [ "java/src/org/chromium/chrome/browser/partnercustomizations/Placeholder.java" ] +android_library("test_support_java") { + testonly = true + sources = [ "junit/src/org/chromium/chrome/browser/partnercustomizations/BasePartnerBrowserCustomizationUnitTestRule.java" ] + deps = [ + ":delegate_java", + ":java", + "//base:base_java", + "//base:base_java_test_support", + "//chrome/test/android:chrome_java_test_support", + "//content/public/test/android:content_java_test_support", + "//third_party/android_support_test_runner:runner_java", + "//third_party/androidx:androidx_test_runner_java", + "//third_party/junit:junit", + ] +} + +android_library("javatests") { + testonly = true + sources = [ + "junit/src/org/chromium/chrome/browser/partnercustomizations/PartnerBrowserCustomizationsUnitTest.java", + "junit/src/org/chromium/chrome/browser/partnercustomizations/PartnerDisableBookmarksEditingUnitTest.java", + "junit/src/org/chromium/chrome/browser/partnercustomizations/PartnerDisableIncognitoModeUnitTest.java", + ] + deps = [ + ":delegate_java", + ":java", + ":test_support_java", + "//base:base_java", + "//base:base_java_test_support", + "//chrome/test/android:chrome_java_test_support", + "//content/public/test/android:content_java_test_support", + "//third_party/android_support_test_runner:runner_java", + "//third_party/androidx:androidx_test_runner_java", + "//third_party/junit:junit", + ] }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/partnercustomizations/PartnerBrowserCustomizations.java b/chrome/browser/partnercustomizations/java/src/org/chromium/chrome/browser/partnercustomizations/PartnerBrowserCustomizations.java similarity index 61% rename from chrome/android/java/src/org/chromium/chrome/browser/partnercustomizations/PartnerBrowserCustomizations.java rename to chrome/browser/partnercustomizations/java/src/org/chromium/chrome/browser/partnercustomizations/PartnerBrowserCustomizations.java index fa68b364..8d4f1aa 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/partnercustomizations/PartnerBrowserCustomizations.java +++ b/chrome/browser/partnercustomizations/java/src/org/chromium/chrome/browser/partnercustomizations/PartnerBrowserCustomizations.java
@@ -6,24 +6,18 @@ import android.content.Context; import android.content.pm.ApplicationInfo; -import android.content.pm.ProviderInfo; -import android.database.Cursor; -import android.net.Uri; import android.text.TextUtils; import androidx.annotation.VisibleForTesting; import org.chromium.base.CommandLine; -import org.chromium.base.ContextUtils; import org.chromium.base.Log; import org.chromium.base.annotations.CalledByNative; import org.chromium.base.task.AsyncTask; import org.chromium.base.task.PostTask; -import org.chromium.chrome.browser.AppHooks; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.preferences.ChromePreferenceKeys; import org.chromium.chrome.browser.preferences.SharedPreferencesManager; -import org.chromium.components.embedder_support.util.UrlConstants; import org.chromium.components.embedder_support.util.UrlUtilities; import org.chromium.components.version_info.VersionInfo; import org.chromium.content_public.browser.UiThreadTaskTraits; @@ -49,9 +43,9 @@ static final String PARTNER_DISABLE_BOOKMARKS_EDITING_PATH = "disablebookmarksediting"; @VisibleForTesting static final String PARTNER_DISABLE_INCOGNITO_MODE_PATH = "disableincognitomode"; - private static String sProviderAuthority = PROVIDER_AUTHORITY; private static Boolean sIgnoreSystemPackageCheck; + private static Boolean sValid; private static volatile PartnerBrowserCustomizations sInstance; @@ -64,16 +58,6 @@ private PartnerHomepageListener mListener; /** - * Interface that listen to homepage URI updates from provider packages. - */ - public interface PartnerHomepageListener { - /** - * Will be called if homepage have any update after {@link #initializeAsync(Context, long)}. - */ - void onHomepageUpdate(); - } - - /** * Provider of partner customizations. */ public interface Provider extends CustomizationProviderDelegate {} @@ -82,104 +66,38 @@ * Partner customizations provided by ContentProvider package. */ public static class ProviderPackage implements Provider { - private static Boolean sValid; + CustomizationProviderDelegate mDelegate; - private boolean isValidInternal() { - ProviderInfo providerInfo = - ContextUtils.getApplicationContext().getPackageManager().resolveContentProvider( - sProviderAuthority, 0); - if (providerInfo == null) { - return false; - } - if ((providerInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { - return true; - } - - // In prod mode (sIgnoreBrowserProviderSystemPackageCheck == null), non-system package - // is rejected unless Chrome Android is a local build. - // When sIgnoreBrowserProviderSystemPackageCheck is true, accept non-system package. - // When sIgnoreBrowserProviderSystemPackageCheck is false, reject non-system package. - if (sIgnoreSystemPackageCheck != null && sIgnoreSystemPackageCheck) { - return true; - } - - Log.w(TAG, - "Browser Customizations content provider package, " + providerInfo.packageName - + ", is not a system package. " - + "This could be a malicious attempt from a third party " - + "app, so skip reading the browser content provider."); - if (sIgnoreSystemPackageCheck != null && !sIgnoreSystemPackageCheck) { - return false; - } - if (VersionInfo.isLocalBuild()) { - Log.w(TAG, - "This is a local build of Chrome Android, " - + "so keep reading the browser content provider, " - + "to make debugging customization easier."); - return true; - } - return false; - } - - private boolean isValid() { - if (sValid == null) { - sValid = isValidInternal(); - } - return sValid; + public ProviderPackage() { + mDelegate = new CustomizationProviderDelegateImpl(); } @Override public String getHomepage() { - if (!isValid()) { - return null; - } - String homepage = null; - Cursor cursor = ContextUtils.getApplicationContext().getContentResolver().query( - buildQueryUri(PARTNER_HOMEPAGE_PATH), null, null, null, null); - if (cursor != null && cursor.moveToFirst() && cursor.getColumnCount() == 1) { - homepage = cursor.getString(0); - } - if (cursor != null) { - cursor.close(); - } - return homepage; + return mDelegate.getHomepage(); } @Override public boolean isIncognitoModeDisabled() { - if (!isValid()) { - return false; - } - boolean disabled = false; - Cursor cursor = ContextUtils.getApplicationContext().getContentResolver().query( - buildQueryUri(PARTNER_DISABLE_INCOGNITO_MODE_PATH), null, null, null, null); - if (cursor != null && cursor.moveToFirst() && cursor.getColumnCount() == 1) { - disabled = cursor.getInt(0) == 1; - } - if (cursor != null) { - cursor.close(); - } - return disabled; + return mDelegate.isIncognitoModeDisabled(); } @Override public boolean isBookmarksEditingDisabled() { - if (!isValid()) { - return false; - } - boolean disabled = false; - Cursor cursor = ContextUtils.getApplicationContext().getContentResolver().query( - buildQueryUri(PARTNER_DISABLE_BOOKMARKS_EDITING_PATH), null, null, null, null); - if (cursor != null && cursor.moveToFirst() && cursor.getColumnCount() == 1) { - disabled = cursor.getInt(0) == 1; - } - if (cursor != null) { - cursor.close(); - } - return disabled; + return mDelegate.isBookmarksEditingDisabled(); } } + /** + * Interface that listen to homepage URI updates from provider packages. + */ + public interface PartnerHomepageListener { + /** + * Will be called if homepage have any update after {@link #initializeAsync(Context, long)}. + */ + void onHomepageUpdate(); + } + private PartnerBrowserCustomizations() { mInitializeAsyncCallbacks = new ArrayList<>(); } @@ -208,7 +126,7 @@ */ @CalledByNative public static boolean isIncognitoDisabled() { - return getInstance().mIncognitoModeDisabled; + return getInstance().isIncognitoModeDisabled(); } /** @@ -222,6 +140,13 @@ } /** + * @return Whether incognito mode is disabled by the partner. + */ + public boolean isIncognitoModeDisabled() { + return mIncognitoModeDisabled; + } + + /** * @return Whether partner bookmarks editing is disabled by the partner. */ public boolean isBookmarksEditingDisabled() { @@ -237,32 +162,6 @@ return mIsInitialized; } - @VisibleForTesting - static void setProviderAuthorityForTests(String providerAuthority) { - sProviderAuthority = providerAuthority; - } - - /** - * For security, we only allow system package to be a browser customizations provider. However, - * requiring root and installing system apk makes testing harder, so we decided to have this - * hack for testing. This must not be called other than tests. - * - * @param ignore whether we should ignore browser provider system package checking. - */ - @VisibleForTesting - static void ignoreBrowserProviderSystemPackageCheckForTests(boolean ignore) { - sIgnoreSystemPackageCheck = ignore; - } - - @VisibleForTesting - static Uri buildQueryUri(String path) { - return new Uri.Builder() - .scheme(UrlConstants.CONTENT_SCHEME) - .authority(sProviderAuthority) - .appendPath(path) - .build(); - } - /** * Constructs an async task that reads PartnerBrowserCustomization provider. * @@ -285,40 +184,6 @@ final AsyncTask<Void> initializeAsyncTask = new AsyncTask<Void>() { private boolean mHomepageUriChanged; - private void refreshHomepage(Provider provider) { - try { - String homepage = provider.getHomepage(); - if (!isValidHomepage(homepage)) { - homepage = null; - } - if (!TextUtils.equals(mHomepage, homepage)) { - mHomepageUriChanged = true; - } - mHomepage = homepage; - SharedPreferencesManager.getInstance().writeString( - ChromePreferenceKeys.HOMEPAGE_PARTNER_CUSTOMIZED_DEFAULT_URI, - mHomepage); - } catch (Exception e) { - Log.w(TAG, "Partner homepage provider URL read failed : ", e); - } - } - - private void refreshIncognitoModeDisabled(Provider provider) { - try { - mIncognitoModeDisabled = provider.isIncognitoModeDisabled(); - } catch (Exception e) { - Log.w(TAG, "Partner disable incognito mode read failed : ", e); - } - } - - private void refreshBookmarksEditingDisabled(Provider provider) { - try { - mBookmarksEditingDisabled = provider.isBookmarksEditingDisabled(); - } catch (Exception e) { - Log.w(TAG, "Partner disable bookmarks editing read failed : ", e); - } - } - @Override protected Void doInBackground() { try { @@ -332,16 +197,17 @@ } if (isCancelled()) return null; - Provider provider = AppHooks.get().getCustomizationProvider(); + CustomizationProviderDelegateImpl delegate = + new CustomizationProviderDelegateImpl(); if (isCancelled()) return null; - refreshIncognitoModeDisabled(provider); + refreshIncognitoModeDisabled(delegate); if (isCancelled()) return null; - refreshBookmarksEditingDisabled(provider); + refreshBookmarksEditingDisabled(delegate); if (isCancelled()) return null; - refreshHomepage(provider); + mHomepageUriChanged = refreshHomepage(delegate); } catch (Exception e) { Log.w(TAG, "Fetching partner customizations failed", e); } @@ -379,6 +245,45 @@ UiThreadTaskTraits.DEFAULT, () -> initializeAsyncTask.cancel(true), timeoutMs); } + @VisibleForTesting + boolean refreshHomepage(CustomizationProviderDelegate delegate) { + boolean retVal = false; + try { + String homepage = delegate.getHomepage(); + if (!isValidHomepage(homepage)) { + homepage = null; + } + if (!TextUtils.equals(mHomepage, homepage)) { + retVal = true; + } + mHomepage = homepage; + SharedPreferencesManager.getInstance().writeString( + ChromePreferenceKeys.HOMEPAGE_PARTNER_CUSTOMIZED_DEFAULT_URI, mHomepage); + } catch (Exception e) { + Log.w(TAG, "Partner homepage delegate URL read failed : ", e); + } + + return retVal; + } + + @VisibleForTesting + void refreshIncognitoModeDisabled(CustomizationProviderDelegate delegate) { + try { + mIncognitoModeDisabled = delegate.isIncognitoModeDisabled(); + } catch (Exception e) { + Log.w(TAG, "Partner disable incognito mode read failed : ", e); + } + } + + @VisibleForTesting + void refreshBookmarksEditingDisabled(CustomizationProviderDelegate delegate) { + try { + mBookmarksEditingDisabled = delegate.isBookmarksEditingDisabled(); + } catch (Exception e) { + Log.w(TAG, "Partner disable bookmarks editing read failed : ", e); + } + } + /** * Sets a callback that will be executed when the initialization is done. * @@ -415,7 +320,6 @@ public static void destroy() { getInstance().destroyInternal(); sInstance = null; - sIgnoreSystemPackageCheck = null; } private void destroyInternal() {
diff --git a/chrome/browser/partnercustomizations/java/src/org/chromium/chrome/browser/partnercustomizations/Placeholder.java b/chrome/browser/partnercustomizations/java/src/org/chromium/chrome/browser/partnercustomizations/Placeholder.java deleted file mode 100644 index 7edd61b..0000000 --- a/chrome/browser/partnercustomizations/java/src/org/chromium/chrome/browser/partnercustomizations/Placeholder.java +++ /dev/null
@@ -1,8 +0,0 @@ -// Copyright 2022 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.partnercustomizations; - -/** Placeholder class used to introduce a new java library. */ -public class Placeholder {} \ No newline at end of file
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/BasePartnerBrowserCustomizationUnitTestRule.java b/chrome/browser/partnercustomizations/junit/src/org/chromium/chrome/browser/partnercustomizations/BasePartnerBrowserCustomizationUnitTestRule.java similarity index 94% rename from chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/BasePartnerBrowserCustomizationUnitTestRule.java rename to chrome/browser/partnercustomizations/junit/src/org/chromium/chrome/browser/partnercustomizations/BasePartnerBrowserCustomizationUnitTestRule.java index 2c4f9fe..a8c5e98 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/BasePartnerBrowserCustomizationUnitTestRule.java +++ b/chrome/browser/partnercustomizations/junit/src/org/chromium/chrome/browser/partnercustomizations/BasePartnerBrowserCustomizationUnitTestRule.java
@@ -47,9 +47,9 @@ * @param uriPath The path to be delayed. */ void setDelayProviderUriPathForDelay(String uriPath) { - PartnerBrowserCustomizations.setProviderAuthorityForTests( + CustomizationProviderDelegateUpstreamImpl.setProviderAuthorityForTesting( PARTNER_BROWSER_CUSTOMIZATIONS_DELAYED_PROVIDER); - Uri uri = PartnerBrowserCustomizations.buildQueryUri(uriPath); + Uri uri = CustomizationProviderDelegateUpstreamImpl.buildQueryUri(uriPath); getContextWrapper().getContentResolver().call(uri, "setUriPathToDelay", uriPath, null); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerBrowserCustomizationsUnitTest.java b/chrome/browser/partnercustomizations/junit/src/org/chromium/chrome/browser/partnercustomizations/PartnerBrowserCustomizationsUnitTest.java similarity index 60% rename from chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerBrowserCustomizationsUnitTest.java rename to chrome/browser/partnercustomizations/junit/src/org/chromium/chrome/browser/partnercustomizations/PartnerBrowserCustomizationsUnitTest.java index 902c354..ad00244 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerBrowserCustomizationsUnitTest.java +++ b/chrome/browser/partnercustomizations/junit/src/org/chromium/chrome/browser/partnercustomizations/PartnerBrowserCustomizationsUnitTest.java
@@ -22,11 +22,66 @@ @RunWith(BaseJUnit4ClassRunner.class) @Batch(Batch.UNIT_TESTS) public class PartnerBrowserCustomizationsUnitTest { + private static final String TEST_HOMEPAGE = "http://example.com"; + + private static class CustomizationProviderDelegateTestImpl + implements CustomizationProviderDelegate { + @Override + public String getHomepage() { + return TEST_HOMEPAGE; + } + + @Override + public boolean isIncognitoModeDisabled() { + return true; + } + + @Override + public boolean isBookmarksEditingDisabled() { + return true; + } + } + @Before public void setUp() { NativeLibraryTestUtils.loadNativeLibraryNoBrowserProcess(); } + @SmallTest + @Test + public void testGetHomepageUrl() { + PartnerBrowserCustomizations partnerBrowserCustomizations = + PartnerBrowserCustomizations.getInstance(); + Assert.assertEquals(null, partnerBrowserCustomizations.getHomePageUrl()); + + partnerBrowserCustomizations.refreshHomepage(new CustomizationProviderDelegateTestImpl()); + Assert.assertEquals(TEST_HOMEPAGE, partnerBrowserCustomizations.getHomePageUrl()); + } + + @SmallTest + @Test + public void testIsIncognitoModeDisabled() { + PartnerBrowserCustomizations partnerBrowserCustomizations = + PartnerBrowserCustomizations.getInstance(); + Assert.assertEquals(false, partnerBrowserCustomizations.isIncognitoModeDisabled()); + + partnerBrowserCustomizations.refreshIncognitoModeDisabled( + new CustomizationProviderDelegateTestImpl()); + Assert.assertEquals(true, partnerBrowserCustomizations.isIncognitoModeDisabled()); + } + + @SmallTest + @Test + public void testIsBookmarksEditingDisabled() { + PartnerBrowserCustomizations partnerBrowserCustomizations = + PartnerBrowserCustomizations.getInstance(); + Assert.assertEquals(false, partnerBrowserCustomizations.isBookmarksEditingDisabled()); + + partnerBrowserCustomizations.refreshBookmarksEditingDisabled( + new CustomizationProviderDelegateTestImpl()); + Assert.assertEquals(true, partnerBrowserCustomizations.isBookmarksEditingDisabled()); + } + @Feature({"Homepage"}) @SmallTest @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerDisableBookmarksEditingUnitTest.java b/chrome/browser/partnercustomizations/junit/src/org/chromium/chrome/browser/partnercustomizations/PartnerDisableBookmarksEditingUnitTest.java similarity index 90% rename from chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerDisableBookmarksEditingUnitTest.java rename to chrome/browser/partnercustomizations/junit/src/org/chromium/chrome/browser/partnercustomizations/PartnerDisableBookmarksEditingUnitTest.java index 478d864..efa177e4 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerDisableBookmarksEditingUnitTest.java +++ b/chrome/browser/partnercustomizations/junit/src/org/chromium/chrome/browser/partnercustomizations/PartnerDisableBookmarksEditingUnitTest.java
@@ -39,7 +39,7 @@ private PartnerBrowserCustomizations mPartnerBrowserCustomizations; private void setBookmarksEditingDisabled(boolean disabled) { - Uri uri = PartnerBrowserCustomizations.buildQueryUri( + Uri uri = CustomizationProviderDelegateUpstreamImpl.buildQueryUri( PartnerBrowserCustomizations.PARTNER_DISABLE_BOOKMARKS_EDITING_PATH); Bundle bundle = new Bundle(); bundle.putBoolean( @@ -50,7 +50,8 @@ @Before public void setUp() { - PartnerBrowserCustomizations.ignoreBrowserProviderSystemPackageCheckForTests(true); + CustomizationProviderDelegateUpstreamImpl.ignoreBrowserProviderSystemPackageCheckForTesting( + true); mPartnerBrowserCustomizations = PartnerBrowserCustomizations.getInstance(); } @@ -65,8 +66,9 @@ public void testProviderNotFromSystemPackage() throws InterruptedException { // Note that unlike other tests in this file, we test if Chrome ignores a customizations // provider that is not from a system package. - PartnerBrowserCustomizations.ignoreBrowserProviderSystemPackageCheckForTests(false); - PartnerBrowserCustomizations.setProviderAuthorityForTests( + CustomizationProviderDelegateUpstreamImpl.ignoreBrowserProviderSystemPackageCheckForTesting( + false); + CustomizationProviderDelegateUpstreamImpl.setProviderAuthorityForTesting( PARTNER_BROWSER_CUSTOMIZATIONS_PROVIDER); TestThreadUtils.runOnUiThreadBlocking(() -> { mPartnerBrowserCustomizations.initializeAsync( @@ -85,7 +87,7 @@ @SmallTest @Feature({"PartnerBookmarksEditing"}) public void testNoProvider() throws InterruptedException { - PartnerBrowserCustomizations.setProviderAuthorityForTests( + CustomizationProviderDelegateUpstreamImpl.setProviderAuthorityForTesting( PARTNER_BROWSER_CUSTOMIZATIONS_NO_PROVIDER); TestThreadUtils.runOnUiThreadBlocking(() -> { mPartnerBrowserCustomizations.initializeAsync( @@ -103,7 +105,7 @@ @SmallTest @Feature({"PartnerBookmarksEditing"}) public void testBookmarksEditingNotDisabled() throws InterruptedException { - PartnerBrowserCustomizations.setProviderAuthorityForTests( + CustomizationProviderDelegateUpstreamImpl.setProviderAuthorityForTesting( PARTNER_BROWSER_CUSTOMIZATIONS_PROVIDER); setBookmarksEditingDisabled(false); TestThreadUtils.runOnUiThreadBlocking(() -> { @@ -123,7 +125,7 @@ @SmallTest @Feature({"PartnerBookmarksEditing"}) public void testBookmarksEditingDisabled() throws InterruptedException { - PartnerBrowserCustomizations.setProviderAuthorityForTests( + CustomizationProviderDelegateUpstreamImpl.setProviderAuthorityForTesting( PARTNER_BROWSER_CUSTOMIZATIONS_PROVIDER); setBookmarksEditingDisabled(true); TestThreadUtils.runOnUiThreadBlocking(() -> { @@ -143,7 +145,7 @@ @SmallTest @Feature({"PartnerBookmarksEditing"}) public void testBookmarksEditingProviderDelayed() throws InterruptedException { - PartnerBrowserCustomizations.setProviderAuthorityForTests( + CustomizationProviderDelegateUpstreamImpl.setProviderAuthorityForTesting( PARTNER_BROWSER_CUSTOMIZATIONS_DELAYED_PROVIDER); mTestRule.setDelayProviderUriPathForDelay( PartnerBrowserCustomizations.PARTNER_DISABLE_BOOKMARKS_EDITING_PATH);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerDisableIncognitoModeUnitTest.java b/chrome/browser/partnercustomizations/junit/src/org/chromium/chrome/browser/partnercustomizations/PartnerDisableIncognitoModeUnitTest.java similarity index 90% rename from chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerDisableIncognitoModeUnitTest.java rename to chrome/browser/partnercustomizations/junit/src/org/chromium/chrome/browser/partnercustomizations/PartnerDisableIncognitoModeUnitTest.java index 76446eb..5874696 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerDisableIncognitoModeUnitTest.java +++ b/chrome/browser/partnercustomizations/junit/src/org/chromium/chrome/browser/partnercustomizations/PartnerDisableIncognitoModeUnitTest.java
@@ -39,7 +39,7 @@ private PartnerBrowserCustomizations mPartnerBrowserCustomizations; private void setParentalControlsEnabled(boolean enabled) { - Uri uri = PartnerBrowserCustomizations.buildQueryUri( + Uri uri = CustomizationProviderDelegateUpstreamImpl.buildQueryUri( PartnerBrowserCustomizations.PARTNER_DISABLE_INCOGNITO_MODE_PATH); Bundle bundle = new Bundle(); bundle.putBoolean( @@ -50,7 +50,8 @@ @Before public void setUp() { - PartnerBrowserCustomizations.ignoreBrowserProviderSystemPackageCheckForTests(true); + CustomizationProviderDelegateUpstreamImpl.ignoreBrowserProviderSystemPackageCheckForTesting( + true); mPartnerBrowserCustomizations = PartnerBrowserCustomizations.getInstance(); } @@ -65,8 +66,9 @@ public void testProviderNotFromSystemPackage() throws InterruptedException { // Note that unlike other tests in this file, we test if Chrome ignores a customizations // provider that is not from a system package. - PartnerBrowserCustomizations.ignoreBrowserProviderSystemPackageCheckForTests(false); - PartnerBrowserCustomizations.setProviderAuthorityForTests( + CustomizationProviderDelegateUpstreamImpl.ignoreBrowserProviderSystemPackageCheckForTesting( + false); + CustomizationProviderDelegateUpstreamImpl.setProviderAuthorityForTesting( PARTNER_BROWSER_CUSTOMIZATIONS_PROVIDER); TestThreadUtils.runOnUiThreadBlocking(() -> { mPartnerBrowserCustomizations.initializeAsync( @@ -85,7 +87,7 @@ @SmallTest @Feature({"ParentalControls"}) public void testNoProvider() throws InterruptedException { - PartnerBrowserCustomizations.setProviderAuthorityForTests( + CustomizationProviderDelegateUpstreamImpl.setProviderAuthorityForTesting( PARTNER_BROWSER_CUSTOMIZATIONS_NO_PROVIDER); TestThreadUtils.runOnUiThreadBlocking(() -> { mPartnerBrowserCustomizations.initializeAsync( @@ -103,7 +105,7 @@ @SmallTest @Feature({"ParentalControls"}) public void testParentalControlsNotEnabled() throws InterruptedException { - PartnerBrowserCustomizations.setProviderAuthorityForTests( + CustomizationProviderDelegateUpstreamImpl.setProviderAuthorityForTesting( PARTNER_BROWSER_CUSTOMIZATIONS_PROVIDER); setParentalControlsEnabled(false); TestThreadUtils.runOnUiThreadBlocking(() -> { @@ -123,7 +125,7 @@ @SmallTest @Feature({"ParentalControls"}) public void testParentalControlsEnabled() throws InterruptedException { - PartnerBrowserCustomizations.setProviderAuthorityForTests( + CustomizationProviderDelegateUpstreamImpl.setProviderAuthorityForTesting( PARTNER_BROWSER_CUSTOMIZATIONS_PROVIDER); setParentalControlsEnabled(true); TestThreadUtils.runOnUiThreadBlocking(() -> { @@ -143,7 +145,7 @@ @SmallTest @Feature({"ParentalControls"}) public void testParentalControlsProviderDelayed() throws InterruptedException { - PartnerBrowserCustomizations.setProviderAuthorityForTests( + CustomizationProviderDelegateUpstreamImpl.setProviderAuthorityForTesting( PARTNER_BROWSER_CUSTOMIZATIONS_DELAYED_PROVIDER); mTestRule.setDelayProviderUriPathForDelay( PartnerBrowserCustomizations.PARTNER_DISABLE_INCOGNITO_MODE_PATH);
diff --git a/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/helper/PasswordCheckChangePasswordHelper.java b/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/helper/PasswordCheckChangePasswordHelper.java index 9422b084..ff2c2a6 100644 --- a/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/helper/PasswordCheckChangePasswordHelper.java +++ b/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/helper/PasswordCheckChangePasswordHelper.java
@@ -34,11 +34,14 @@ private static final String PASSWORD_CHANGE_USERNAME_PARAMETER = "PASSWORD_CHANGE_USERNAME"; private static final String PASSWORD_CHANGE_SKIP_LOGIN_PARAMETER = "PASSWORD_CHANGE_SKIP_LOGIN"; private static final String INTENT_PARAMETER = "INTENT"; + private static final String SOURCE_PARAMETER = "SOURCE"; private static final String INTENT = "PASSWORD_CHANGE"; private static final String START_IMMEDIATELY_PARAMETER = "START_IMMEDIATELY"; private static final String ORIGINAL_DEEPLINK_PARAMETER = "ORIGINAL_DEEPLINK"; private static final String CALLER_PARAMETER = "CALLER"; + private static final int IN_CHROME_CALLER = 7; + private static final int SOURCE_PASSWORD_CHANGE_SETTINGS = 11; private static final String ENCODING = "UTF-8"; @@ -134,6 +137,8 @@ intent.putExtra(AUTOFILL_ASSISTANT_PACKAGE + INTENT_PARAMETER, INTENT); intent.putExtra(AUTOFILL_ASSISTANT_PACKAGE + START_IMMEDIATELY_PARAMETER, true); intent.putExtra(AUTOFILL_ASSISTANT_PACKAGE + CALLER_PARAMETER, IN_CHROME_CALLER); + intent.putExtra( + AUTOFILL_ASSISTANT_PACKAGE + SOURCE_PARAMETER, SOURCE_PASSWORD_CHANGE_SETTINGS); intent.putExtra(AUTOFILL_ASSISTANT_PACKAGE + PASSWORD_CHANGE_SKIP_LOGIN_PARAMETER, false); // Note: All string-typed parameters must be URL-encoded, because the // corresponding extraction logic will URL-*de*code them before use, @@ -146,7 +151,5 @@ } catch (UnsupportedEncodingException e) { throw new IllegalStateException("Encoding not available.", e); } - // TODO(crbug.com/1086114): Also add the following parameters when server side changes is - // ready: CALLER, SOURCE. That would be useful for metrics. } }
diff --git a/chrome/browser/password_manager/android/BUILD.gn b/chrome/browser/password_manager/android/BUILD.gn index 363dae1..29fdee0 100644 --- a/chrome/browser/password_manager/android/BUILD.gn +++ b/chrome/browser/password_manager/android/BUILD.gn
@@ -71,6 +71,7 @@ "//components/browser_ui/widget/android:java_resources", "//components/device_reauth:device_reauth_java_enums", "//components/password_manager/core/browser:password_manager_java_enums", + "//components/password_manager/core/common:password_manager_common_java_enums", "//components/signin/public/android:java", "//components/sync/android:sync_java", "//components/sync/protocol:protocol_java",
diff --git a/chrome/browser/password_manager/android/generated_password_saved_message_delegate.cc b/chrome/browser/password_manager/android/generated_password_saved_message_delegate.cc index c767c12..1539b2a 100644 --- a/chrome/browser/password_manager/android/generated_password_saved_message_delegate.cc +++ b/chrome/browser/password_manager/android/generated_password_saved_message_delegate.cc
@@ -35,6 +35,8 @@ void GeneratedPasswordSavedMessageDelegate::ShowPrompt( content::WebContents* web_contents, std::unique_ptr<password_manager::PasswordFormManagerForUI> saved_form) { + using password_manager::features::UsesUnifiedPasswordManagerUi; + message_ = std::make_unique<messages::MessageWrapper>( messages::MessageIdentifier::GENERATED_PASSWORD_SAVED, base::OnceCallback<void()>(), @@ -45,11 +47,8 @@ message_->SetTitle( l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_CONFIRM_SAVED_TITLE)); - const bool kIsUnifiedPasswordManager = base::FeatureList::IsEnabled( - password_manager::features::kUnifiedPasswordManagerAndroid); - std::u16string description; - if (kIsUnifiedPasswordManager) { + if (UsesUnifiedPasswordManagerUi()) { description = l10n_util::GetStringUTF16( IDS_PASSWORD_MANAGER_GENERATED_PASSWORD_SAVED_MESSAGE_DESCRIPTION); } else { @@ -64,7 +63,7 @@ message_->SetDescription(description); message_->SetPrimaryButtonText(l10n_util::GetStringUTF16(IDS_OK)); - if (kIsUnifiedPasswordManager) { + if (UsesUnifiedPasswordManagerUi()) { message_->SetIconResourceId(ResourceMapper::MapToJavaDrawableId( IDR_ANDROID_PASSWORD_MANAGER_LOGO_24DP)); message_->DisableIconTint();
diff --git a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordManagerHelper.java b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordManagerHelper.java index 10da6a0..c9c2184 100644 --- a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordManagerHelper.java +++ b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordManagerHelper.java
@@ -27,6 +27,8 @@ // all points of entry to the passwords settings. public static final String MANAGE_PASSWORDS_REFERRER = "manage-passwords-referrer"; + private static final String UPM_VARIATION_FEATURE_PARAM = "stage"; + // |PasswordSettings| full class name to open the fragment. Will be changed to // |PasswordSettings.class.getName()| once it's modularized. private static final String PASSWORD_SETTINGS_CLASS = @@ -61,12 +63,17 @@ RecordHistogram.recordEnumeratedHistogram("PasswordManager.ManagePasswordsReferrer", referrer, ManagePasswordsReferrer.MAX_VALUE + 1); + // The credential manager is NonNull if the Unified password manager is active or there is + // a dry run measuring the latency/success of fetching the launch intent. if (credentialManagerLauncher != null) { + // This method always request the launch intent but only actually launches it when the + // UnifiedPasswordManager feature allows it. launchTheCredentialManager(referrer, credentialManagerLauncher, syncService); - // If the global feature is not enabled the Credential Manager will not be launched even - // if the intent is fetched so the regular password settings should be launched instead. - if (ChromeFeatureList.isEnabled(UNIFIED_PASSWORD_MANAGER_ANDROID)) return; + if (usesUnifiedPasswordManagerUI()) { + // While waiting for the new UI, exit early to prevent launching the old settings. + return; + } } Bundle fragmentArgs = new Bundle(); @@ -118,6 +125,14 @@ return true; } + public static boolean usesUnifiedPasswordManagerUI() { + return ChromeFeatureList.isEnabled(UNIFIED_PASSWORD_MANAGER_ANDROID) + && ChromeFeatureList.getFieldTrialParamByFeatureAsInt( + UNIFIED_PASSWORD_MANAGER_ANDROID, UPM_VARIATION_FEATURE_PARAM, + UpmExperimentVariation.ENABLE_FOR_SYNCING_USERS) + != UpmExperimentVariation.SHADOW_SYNCING_USERS; + } + private static void launchTheCredentialManager(@ManagePasswordsReferrer int referrer, CredentialManagerLauncher credentialManagerLauncher, SyncService syncService) { if (hasChosenToSyncPasswords(syncService)) { @@ -155,8 +170,8 @@ PendingIntent intent, long startTimeMs, boolean forAccount) { recordSuccessMetrics(SystemClock.elapsedRealtime() - startTimeMs, forAccount); - if (!ChromeFeatureList.isEnabled(UNIFIED_PASSWORD_MANAGER_ANDROID)) { - return; + if (!usesUnifiedPasswordManagerUI()) { + return; // The built-in settings screen has already been started at this point. } boolean launchIntentSuccessfully = true;
diff --git a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordStoreAndroidBackendBridgeImpl.java b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordStoreAndroidBackendBridgeImpl.java index 430f913..f766ea13a 100644 --- a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordStoreAndroidBackendBridgeImpl.java +++ b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordStoreAndroidBackendBridgeImpl.java
@@ -4,7 +4,7 @@ package org.chromium.chrome.browser.password_manager; -import static org.chromium.chrome.browser.flags.ChromeFeatureList.UNIFIED_PASSWORD_MANAGER_ANDROID; +import static org.chromium.chrome.browser.password_manager.PasswordManagerHelper.usesUnifiedPasswordManagerUI; import android.accounts.Account; import android.app.PendingIntent; @@ -16,7 +16,6 @@ import org.chromium.base.Log; import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.NativeMethods; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.components.signin.AccountUtils; import java.lang.annotation.ElementType; @@ -128,8 +127,7 @@ error = AndroidBackendErrorType.EXTERNAL_ERROR; api_error_code = ((ApiException) exception).getStatusCode(); - if (ChromeFeatureList.isEnabled(UNIFIED_PASSWORD_MANAGER_ANDROID) - && exception instanceof ResolvableApiException + if (usesUnifiedPasswordManagerUI() && exception instanceof ResolvableApiException && api_error_code != ChromeSyncStatusCode.AUTH_ERROR_RESOLVABLE) { // Backend error is user-recoverable, launch pending intent to allow the user to // resolve it. Resolution for the authentication errors is not launched as
diff --git a/chrome/browser/password_manager/android/save_update_password_message_delegate.cc b/chrome/browser/password_manager/android/save_update_password_message_delegate.cc index d6603dd1..8deff3b 100644 --- a/chrome/browser/password_manager/android/save_update_password_message_delegate.cc +++ b/chrome/browser/password_manager/android/save_update_password_message_delegate.cc
@@ -137,11 +137,9 @@ } message_->SetTitle(l10n_util::GetStringUTF16(title_message_id)); - const bool kIsUnifiedPasswordManager = base::FeatureList::IsEnabled( - password_manager::features::kUnifiedPasswordManagerAndroid); - std::u16string description = GetMessageDescription( - pending_credentials, update_password, kIsUnifiedPasswordManager); + pending_credentials, update_password, + password_manager::features::UsesUnifiedPasswordManagerUi()); message_->SetDescription(description); update_password_ = update_password; @@ -155,7 +153,7 @@ message_->SetPrimaryButtonText(l10n_util::GetStringUTF16( GetPrimaryButtonTextId(update_password, use_followup_button_text))); - if (kIsUnifiedPasswordManager) { + if (password_manager::features::UsesUnifiedPasswordManagerUi()) { message_->SetIconResourceId(ResourceMapper::MapToJavaDrawableId( IDR_ANDROID_PASSWORD_MANAGER_LOGO_24DP)); message_->DisableIconTint();
diff --git a/chrome/browser/password_manager/password_manager_browsertest.cc b/chrome/browser/password_manager/password_manager_browsertest.cc index 5173376..5ed9255 100644 --- a/chrome/browser/password_manager/password_manager_browsertest.cc +++ b/chrome/browser/password_manager/password_manager_browsertest.cc
@@ -2949,7 +2949,8 @@ } // Check that the internals page contains logs from the renderer. -IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, InternalsPage_Renderer) { +IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, + DISABLED_InternalsPage_Renderer) { // The test is flaky with same-site back/forward cache (which is enabled by // default). // TODO(https://crbug.com/1276313): Investigate and fix this.
diff --git a/chrome/browser/payments/payment_handler_just_in_time_installation_browsertest.cc b/chrome/browser/payments/payment_handler_just_in_time_installation_browsertest.cc index e2314d40..90dd1f5 100644 --- a/chrome/browser/payments/payment_handler_just_in_time_installation_browsertest.cc +++ b/chrome/browser/payments/payment_handler_just_in_time_installation_browsertest.cc
@@ -96,7 +96,7 @@ // that uses invalid payment method. ExpectBodyContains( "\nBob Pay and Cards Test\nInstallable App\nThe payment method " - "\"https://henrypay.com/webpay\" is not supported.\n\n\n\n\n"); + "\"https://henrypay.com/webpay\" is not supported.\n\n\n"); } using PaymentHandlerSkipSheetTest = PaymentHandlerJustInTimeInstallationTest;
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc index 1617575d..48f69ef7 100644 --- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc +++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -1620,6 +1620,9 @@ { key::kWindowPlacementBlockedForUrls, prefs::kManagedWindowPlacementBlockedForUrls, base::Value::Type::LIST }, + { key::kWebSQLAccess, + policy_prefs::kWebSQLAccess, + base::Value::Type::BOOLEAN }, #if !BUILDFLAG(IS_ANDROID) { key::kWebAuthenticationRemoteProxiedRequestsAllowed, webauthn::pref_names::kRemoteProxiedRequestsAllowed,
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc index 0daa4ee5..6acfe6a1 100644 --- a/chrome/browser/prefs/browser_prefs.cc +++ b/chrome/browser/prefs/browser_prefs.cc
@@ -1005,6 +1005,7 @@ policy::policy_prefs::kTargetBlankImpliesNoOpener, true); registry->RegisterBooleanPref( policy::policy_prefs::kUserAgentClientHintsGREASEUpdateEnabled, true); + registry->RegisterBooleanPref(policy::policy_prefs::kWebSQLAccess, false); #if BUILDFLAG(IS_ANDROID) registry->RegisterBooleanPref(policy::policy_prefs::kBackForwardCacheEnabled, true);
diff --git a/chrome/browser/printing/print_browsertest.cc b/chrome/browser/printing/print_browsertest.cc index 9b62e3d..5766f4a 100644 --- a/chrome/browser/printing/print_browsertest.cc +++ b/chrome/browser/printing/print_browsertest.cc
@@ -993,7 +993,15 @@ EXPECT_NE(old_height, new_height); } -IN_PROC_BROWSER_TEST_F(PrintBrowserTest, LazyLoadedIframeFetchedCrossOrigin) { +#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) +#define MAYBE_LazyLoadedIframeFetchedCrossOrigin \ + DISABLED_LazyLoadedIframeFetchedCrossOrigin +#else +#define MAYBE_LazyLoadedIframeFetchedCrossOrigin \ + LazyLoadedIframeFetchedCrossOrigin +#endif +IN_PROC_BROWSER_TEST_F(PrintBrowserTest, + MAYBE_LazyLoadedIframeFetchedCrossOrigin) { ASSERT_TRUE(embedded_test_server()->Started()); GURL url(embedded_test_server()->GetURL( "/printing/lazy-loaded-iframe-offscreen-cross-origin.html"));
diff --git a/chrome/browser/profiles/off_the_record_profile_impl.cc b/chrome/browser/profiles/off_the_record_profile_impl.cc index 5e634ca..cbb905e 100644 --- a/chrome/browser/profiles/off_the_record_profile_impl.cc +++ b/chrome/browser/profiles/off_the_record_profile_impl.cc
@@ -49,6 +49,12 @@ #include "chrome/browser/transition_manager/full_browser_transition_manager.h" #include "chrome/browser/ui/webui/extensions/extension_icon_source.h" #include "chrome/browser/ui/zoom/chrome_zoom_level_otr_delegate.h" +#include "chrome/browser/webid/federated_identity_active_session_permission_context.h" +#include "chrome/browser/webid/federated_identity_active_session_permission_context_factory.h" +#include "chrome/browser/webid/federated_identity_request_permission_context.h" +#include "chrome/browser/webid/federated_identity_request_permission_context_factory.h" +#include "chrome/browser/webid/federated_identity_sharing_permission_context.h" +#include "chrome/browser/webid/federated_identity_sharing_permission_context_factory.h" #include "chrome/common/buildflags.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_paths.h" @@ -668,3 +674,19 @@ void OffTheRecordProfileImpl::RecordPrimaryMainFrameNavigation() { main_frame_navigations_++; } + +content::FederatedIdentityActiveSessionPermissionContextDelegate* +OffTheRecordProfileImpl::GetFederatedIdentityActiveSessionPermissionContext() { + return FederatedIdentityActiveSessionPermissionContextFactory::GetForProfile( + this); +} + +content::FederatedIdentityRequestPermissionContextDelegate* +OffTheRecordProfileImpl::GetFederatedIdentityRequestPermissionContext() { + return FederatedIdentityRequestPermissionContextFactory::GetForProfile(this); +} + +content::FederatedIdentitySharingPermissionContextDelegate* +OffTheRecordProfileImpl::GetFederatedIdentitySharingPermissionContext() { + return FederatedIdentitySharingPermissionContextFactory::GetForProfile(this); +}
diff --git a/chrome/browser/profiles/off_the_record_profile_impl.h b/chrome/browser/profiles/off_the_record_profile_impl.h index b8cd69d9..505b665a 100644 --- a/chrome/browser/profiles/off_the_record_profile_impl.h +++ b/chrome/browser/profiles/off_the_record_profile_impl.h
@@ -122,6 +122,12 @@ content::FileSystemAccessPermissionContext* GetFileSystemAccessPermissionContext() override; void RecordPrimaryMainFrameNavigation() override; + content::FederatedIdentityActiveSessionPermissionContextDelegate* + GetFederatedIdentityActiveSessionPermissionContext() override; + content::FederatedIdentityRequestPermissionContextDelegate* + GetFederatedIdentityRequestPermissionContext() override; + content::FederatedIdentitySharingPermissionContextDelegate* + GetFederatedIdentitySharingPermissionContext() override; protected: // Profile implementation.
diff --git a/chrome/browser/resources/new_tab_page/app.ts b/chrome/browser/resources/new_tab_page/app.ts index e8375cde..1c9eba8a 100644 --- a/chrome/browser/resources/new_tab_page/app.ts +++ b/chrome/browser/resources/new_tab_page/app.ts
@@ -308,7 +308,7 @@ Math.floor(document.documentElement.clientHeight)); } - connectedCallback() { + override connectedCallback() { super.connectedCallback(); this.setThemeListenerId_ = this.callbackRouter_.setTheme.addListener((theme: Theme) => { @@ -350,13 +350,13 @@ FocusOutlineManager.forDocument(document); } - disconnectedCallback() { + override disconnectedCallback() { super.disconnectedCallback(); this.callbackRouter_.removeListener(this.setThemeListenerId_!); this.eventTracker_.removeAll(); } - ready() { + override ready() { super.ready(); this.pageHandler_.onAppRendered(WindowProxy.getInstance().now()); // Let the browser breath and then render remaining elements.
diff --git a/chrome/browser/resources/new_tab_page/customize_dialog.ts b/chrome/browser/resources/new_tab_page/customize_dialog.ts index 6aa6907..c437e40 100644 --- a/chrome/browser/resources/new_tab_page/customize_dialog.ts +++ b/chrome/browser/resources/new_tab_page/customize_dialog.ts
@@ -104,7 +104,7 @@ this.pageHandler_ = NewTabPageProxy.getInstance().handler; } - disconnectedCallback() { + override disconnectedCallback() { super.disconnectedCallback(); this.intersectionObservers_.forEach(observer => { observer.disconnect(); @@ -112,7 +112,7 @@ this.intersectionObservers_ = []; } - ready() { + override ready() { super.ready(); this.intersectionObservers_ = [ createScrollBorders(
diff --git a/chrome/browser/resources/new_tab_page/customize_modules.ts b/chrome/browser/resources/new_tab_page/customize_modules.ts index fb17d24..e06638b2 100644 --- a/chrome/browser/resources/new_tab_page/customize_modules.ts +++ b/chrome/browser/resources/new_tab_page/customize_modules.ts
@@ -96,7 +96,7 @@ private setDisabledModulesListenerId_: number|null = null; - connectedCallback() { + override connectedCallback() { super.connectedCallback(); this.setDisabledModulesListenerId_ = NewTabPageProxy.getInstance() @@ -123,13 +123,13 @@ }); } - disconnectedCallback() { + override disconnectedCallback() { super.disconnectedCallback(); NewTabPageProxy.getInstance().callbackRouter.removeListener( this.setDisabledModulesListenerId_!); } - ready() { + override ready() { // |window.CrPolicyStrings.controlledSettingPolicy| populates the tooltip // text of <cr-policy-indicator indicator-type="devicePolicy" /> elements. // Needs to be called before |super.ready()| so that the string is available
diff --git a/chrome/browser/resources/new_tab_page/customize_shortcuts.ts b/chrome/browser/resources/new_tab_page/customize_shortcuts.ts index ecf29b2..713747b2 100644 --- a/chrome/browser/resources/new_tab_page/customize_shortcuts.ts +++ b/chrome/browser/resources/new_tab_page/customize_shortcuts.ts
@@ -60,7 +60,7 @@ }); } - connectedCallback() { + override connectedCallback() { super.connectedCallback(); FocusOutlineManager.forDocument(document); }
diff --git a/chrome/browser/resources/new_tab_page/doodle_share_dialog.ts b/chrome/browser/resources/new_tab_page/doodle_share_dialog.ts index b9ea9a5..89a5c27 100644 --- a/chrome/browser/resources/new_tab_page/doodle_share_dialog.ts +++ b/chrome/browser/resources/new_tab_page/doodle_share_dialog.ts
@@ -52,7 +52,7 @@ }; } - title: string; + override title: string; url: Url; private onFacebookClick_() {
diff --git a/chrome/browser/resources/new_tab_page/logo.ts b/chrome/browser/resources/new_tab_page/logo.ts index 26b51bf..830d9f26 100644 --- a/chrome/browser/resources/new_tab_page/logo.ts +++ b/chrome/browser/resources/new_tab_page/logo.ts
@@ -174,7 +174,7 @@ }); } - connectedCallback() { + override connectedCallback() { super.connectedCallback(); this.eventTracker_.add(window, 'message', ({data}: MessageEvent) => { if (data['cmd'] === 'resizeDoodle') { @@ -190,12 +190,12 @@ this.sendMode_(); } - disconnectedCallback() { + override disconnectedCallback() { super.disconnectedCallback(); this.eventTracker_.removeAll(); } - ready() { + override ready() { super.ready(); performance.measure('logo-creation', 'logo-creation-start'); }
diff --git a/chrome/browser/resources/new_tab_page/middle_slot_promo.ts b/chrome/browser/resources/new_tab_page/middle_slot_promo.ts index 51469aa0..9ee253a9 100644 --- a/chrome/browser/resources/new_tab_page/middle_slot_promo.ts +++ b/chrome/browser/resources/new_tab_page/middle_slot_promo.ts
@@ -126,7 +126,7 @@ return getTemplate(); } - ready() { + override ready() { super.ready(); renderPromo().then(container => { if (container) {
diff --git a/chrome/browser/resources/new_tab_page/modules/cart/module.ts b/chrome/browser/resources/new_tab_page/modules/cart/module.ts index bb3a063..3e8b1746 100644 --- a/chrome/browser/resources/new_tab_page/modules/cart/module.ts +++ b/chrome/browser/resources/new_tab_page/modules/cart/module.ts
@@ -108,7 +108,7 @@ private firstThreeCartItems_: MerchantCart[]; private eventTracker_: EventTracker = new EventTracker(); - connectedCallback() { + override connectedCallback() { super.connectedCallback(); const leftProbe = this.$.cartCarousel.querySelector('#leftProbe'); const rightProbe = this.$.cartCarousel.querySelector('#rightProbe'); @@ -149,7 +149,7 @@ () => this.onDiscountConsentContinued_()); } - disconnectedCallback() { + override disconnectedCallback() { super.disconnectedCallback(); this.intersectionObserver_!.disconnect();
diff --git a/chrome/browser/resources/new_tab_page/modules/cart_v2/module.ts b/chrome/browser/resources/new_tab_page/modules/cart_v2/module.ts index e6e5dab..d5b72a7 100644 --- a/chrome/browser/resources/new_tab_page/modules/cart_v2/module.ts +++ b/chrome/browser/resources/new_tab_page/modules/cart_v2/module.ts
@@ -97,7 +97,7 @@ private intersectionObserver_: IntersectionObserver|null = null; private currentMenuIndex_: number = 0; - connectedCallback() { + override connectedCallback() { super.connectedCallback(); const leftProbe = this.$.cartCarousel.querySelector('#leftProbe'); const rightProbe = this.$.cartCarousel.querySelector('#rightProbe'); @@ -125,7 +125,7 @@ el => this.intersectionObserver_!.observe(el)); } - disconnectedCallback() { + override disconnectedCallback() { super.disconnectedCallback(); this.intersectionObserver_!.disconnect(); }
diff --git a/chrome/browser/resources/new_tab_page/modules/dummy_v2/module.ts b/chrome/browser/resources/new_tab_page/modules/dummy_v2/module.ts index e089daf..3413231e 100644 --- a/chrome/browser/resources/new_tab_page/modules/dummy_v2/module.ts +++ b/chrome/browser/resources/new_tab_page/modules/dummy_v2/module.ts
@@ -45,7 +45,7 @@ } tiles: FooDataItem[]; - title: string; + override title: string; constructor() { super();
diff --git a/chrome/browser/resources/new_tab_page/modules/module_descriptor.ts b/chrome/browser/resources/new_tab_page/modules/module_descriptor.ts index 760e6d1..9daeb69 100644 --- a/chrome/browser/resources/new_tab_page/modules/module_descriptor.ts +++ b/chrome/browser/resources/new_tab_page/modules/module_descriptor.ts
@@ -85,7 +85,7 @@ this.height_ = height; } - get height() { + override get height() { return this.height_; } @@ -93,7 +93,7 @@ * Like |ModuleDescriptor.initialize()| but returns an empty element on * timeout. */ - async initialize(timeout: number): Promise<HTMLElement> { + override async initialize(timeout: number): Promise<HTMLElement> { return (await super.initialize(timeout)) || document.createElement('div'); } }
diff --git a/chrome/browser/resources/new_tab_page/modules/modules.ts b/chrome/browser/resources/new_tab_page/modules/modules.ts index 7ae21ce..115b132 100644 --- a/chrome/browser/resources/new_tab_page/modules/modules.ts +++ b/chrome/browser/resources/new_tab_page/modules/modules.ts
@@ -112,7 +112,7 @@ private setDisabledModulesListenerId_: number|null = null; private eventTracker_: EventTracker = new EventTracker(); - connectedCallback() { + override connectedCallback() { super.connectedCallback(); this.setDisabledModulesListenerId_ = NewTabPageProxy.getInstance() @@ -125,14 +125,14 @@ this.eventTracker_.add(window, 'keydown', this.onWindowKeydown_.bind(this)); } - disconnectedCallback() { + override disconnectedCallback() { super.disconnectedCallback(); NewTabPageProxy.getInstance().callbackRouter.removeListener( assert(this.setDisabledModulesListenerId_!)); this.eventTracker_.removeAll(); } - ready() { + override ready() { super.ready(); this.renderModules_(); }
diff --git a/chrome/browser/resources/new_tab_page/modules/photos/module.ts b/chrome/browser/resources/new_tab_page/modules/photos/module.ts index 1539767..a6e8e11d 100644 --- a/chrome/browser/resources/new_tab_page/modules/photos/module.ts +++ b/chrome/browser/resources/new_tab_page/modules/photos/module.ts
@@ -100,7 +100,7 @@ private customArtworkUrl_: string; private showCustomArtWork_: boolean; - ready() { + override ready() { super.ready(); this.addEventListener('detect-impression', () => { chrome.metricsPrivate.recordBoolean(
diff --git a/chrome/browser/resources/new_tab_page/realbox/realbox.ts b/chrome/browser/resources/new_tab_page/realbox/realbox.ts index 9d5c836..6e49d07d 100644 --- a/chrome/browser/resources/new_tab_page/realbox/realbox.ts +++ b/chrome/browser/resources/new_tab_page/realbox/realbox.ts
@@ -208,7 +208,7 @@ return this.selectedMatch_ ? 'off' : 'polite'; } - connectedCallback() { + override connectedCallback() { super.connectedCallback(); this.autocompleteResultChangedListenerId_ = this.callbackRouter_.autocompleteResultChanged.addListener( @@ -218,7 +218,7 @@ this.onAutocompleteMatchImageAvailable_.bind(this)); } - disconnectedCallback() { + override disconnectedCallback() { super.disconnectedCallback(); this.callbackRouter_.removeListener( assert(this.autocompleteResultChangedListenerId_!)); @@ -226,7 +226,7 @@ assert(this.autocompleteMatchImageAvailableListenerId_!)); } - ready() { + override ready() { super.ready(); performance.measure('realbox-creation', 'realbox-creation-start'); }
diff --git a/chrome/browser/resources/new_tab_page/realbox/realbox_action.html b/chrome/browser/resources/new_tab_page/realbox/realbox_action.html index 05547486..59c1b0a8f 100644 --- a/chrome/browser/resources/new_tab_page/realbox/realbox_action.html +++ b/chrome/browser/resources/new_tab_page/realbox/realbox_action.html
@@ -1,7 +1,7 @@ <style import="cr-shared-style"> :host { --action-height: 32px; - border: solid 1px var(--google-grey-500); + border: solid 1px var(--google-grey-400); border-radius: calc(var(--action-height) / 2); display: flex; height: var(--action-height);
diff --git a/chrome/browser/resources/new_tab_page/realbox/realbox_action.ts b/chrome/browser/resources/new_tab_page/realbox/realbox_action.ts index a9f04d4..fde5b66 100644 --- a/chrome/browser/resources/new_tab_page/realbox/realbox_action.ts +++ b/chrome/browser/resources/new_tab_page/realbox/realbox_action.ts
@@ -66,7 +66,7 @@ action: Action; matchIndex: number; - ariaLabel: string; + override ariaLabel: string; private hintHtml_: string; private tooltip_: string;
diff --git a/chrome/browser/resources/new_tab_page/realbox/realbox_dropdown.ts b/chrome/browser/resources/new_tab_page/realbox/realbox_dropdown.ts index 107ce96e..4cce30f 100644 --- a/chrome/browser/resources/new_tab_page/realbox/realbox_dropdown.ts +++ b/chrome/browser/resources/new_tab_page/realbox/realbox_dropdown.ts
@@ -109,14 +109,14 @@ this.pageHandler_ = RealboxBrowserProxy.getInstance().handler; } - connectedCallback() { + override connectedCallback() { super.connectedCallback(); this.autocompleteMatchImageAvailableListenerId_ = this.callbackRouter_.autocompleteMatchImageAvailable.addListener( this.onAutocompleteMatchImageAvailable_.bind(this)); } - disconnectedCallback() { + override disconnectedCallback() { super.disconnectedCallback(); this.callbackRouter_.removeListener( this.autocompleteMatchImageAvailableListenerId_!);
diff --git a/chrome/browser/resources/new_tab_page/realbox/realbox_match.ts b/chrome/browser/resources/new_tab_page/realbox/realbox_match.ts index 47fe53e..f6bb182 100644 --- a/chrome/browser/resources/new_tab_page/realbox/realbox_match.ts +++ b/chrome/browser/resources/new_tab_page/realbox/realbox_match.ts
@@ -134,7 +134,7 @@ }; } - ariaLabel: string; + override ariaLabel: string; hasImage: boolean; match: AutocompleteMatch; matchIndex: number; @@ -153,7 +153,7 @@ this.pageHandler_ = RealboxBrowserProxy.getInstance().handler; } - ready() { + override ready() { super.ready(); this.addEventListener('click', (event) => this.onMatchClick_(event));
diff --git a/chrome/browser/resources/new_tab_page/tsconfig_base.json b/chrome/browser/resources/new_tab_page/tsconfig_base.json index c63b6fce..3011255 100644 --- a/chrome/browser/resources/new_tab_page/tsconfig_base.json +++ b/chrome/browser/resources/new_tab_page/tsconfig_base.json
@@ -2,6 +2,7 @@ "extends": "../../../../tools/typescript/tsconfig_base.json", "compilerOptions": { "allowJs": true, + "noImplicitOverride": true, "noUncheckedIndexedAccess": false, "noUnusedLocals": false, "strictPropertyInitialization": false,
diff --git a/chrome/browser/resources/new_tab_page/voice_search_overlay.ts b/chrome/browser/resources/new_tab_page/voice_search_overlay.ts index fe9e96c..0bfb1ed 100644 --- a/chrome/browser/resources/new_tab_page/voice_search_overlay.ts +++ b/chrome/browser/resources/new_tab_page/voice_search_overlay.ts
@@ -253,7 +253,7 @@ }; } - connectedCallback() { + override connectedCallback() { super.connectedCallback(); this.$.dialog.showModal(); this.start();
diff --git a/chrome/browser/resources/new_tab_page_third_party/tsconfig_base.json b/chrome/browser/resources/new_tab_page_third_party/tsconfig_base.json index 99a81eca..91de0aa 100644 --- a/chrome/browser/resources/new_tab_page_third_party/tsconfig_base.json +++ b/chrome/browser/resources/new_tab_page_third_party/tsconfig_base.json
@@ -1,6 +1,7 @@ { "extends": "../../../../tools/typescript/tsconfig_base.json", "compilerOptions": { - "allowJs": true + "allowJs": true, + "noImplicitOverride": true } }
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_main/os_settings_main.html b/chrome/browser/resources/settings/chromeos/os_settings_main/os_settings_main.html index e18655e..a0544be 100644 --- a/chrome/browser/resources/settings/chromeos/os_settings_main/os_settings_main.html +++ b/chrome/browser/resources/settings/chromeos/os_settings_main/os_settings_main.html
@@ -59,6 +59,7 @@ <os-settings-about-page role="main" class="cr-centered-card-container" on-subpage-expand="onShowingSubpage_" + on-showing-section="onShowingSection_" on-showing-main-page="onShowingMainPage_" prefs="{{prefs}}" show-crostini="[[showCrostini]]">
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_menu/os_settings_menu.html b/chrome/browser/resources/settings/chromeos/os_settings_menu/os_settings_menu.html index 3e4bd479..892fff5 100644 --- a/chrome/browser/resources/settings/chromeos/os_settings_menu/os_settings_menu.html +++ b/chrome/browser/resources/settings/chromeos/os_settings_menu/os_settings_menu.html
@@ -231,7 +231,7 @@ </iron-selector> </iron-collapse> <div id="menuSeparator"></div> - <a id="aboutItem" href="/help" class="item"> + <a id="aboutItem" href="/help/about" class="item"> $i18n{aboutOsPageTitle} </a> </iron-selector>
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_cookies_fragment.html b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_cookies_fragment.html index f132b7d9..47dff74 100644 --- a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_cookies_fragment.html +++ b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_cookies_fragment.html
@@ -10,7 +10,8 @@ </div> <settings-radio-group id="cookiesRadioGroup" pref="{{prefs.generated.cookie_primary_setting}}" - selectable-elements="settings-collapse-radio-button"> + selectable-elements="settings-collapse-radio-button" + on-keydown="onRadioGroupKeyDown_"> <settings-collapse-radio-button id="block3PIncognito" pref="[[prefs.generated.cookie_primary_setting]]" name="[[cookiePrimarySettingEnum_.BLOCK_THIRD_PARTY_INCOGNITO]]"
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_cookies_fragment.ts b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_cookies_fragment.ts index 3368694..7acf242 100644 --- a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_cookies_fragment.ts +++ b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_cookies_fragment.ts
@@ -96,6 +96,18 @@ this.metricsBrowserProxy_.recordAction( 'Settings.PrivacyGuide.ChangeCookiesBlock3P'); } + + private onRadioGroupKeyDown_(event: KeyboardEvent) { + switch (event.key) { + case 'ArrowLeft': + case 'ArrowRight': + // This event got consumed by the radio group to change the radio button + // selection. Do not propagate further, to not cause a privacy guide + // navigation. + event.stopPropagation(); + break; + } + } } customElements.define(
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_page.html b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_page.html index a4235bc..01a087f 100644 --- a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_page.html +++ b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_page.html
@@ -43,7 +43,7 @@ visibility: hidden; } - .privacy-guide-card { + #privacyGuideCard { background-color: var(--cr-card-background-color); border-radius: var(--cr-card-border-radius); box-shadow: var(--cr-card-shadow); @@ -55,7 +55,7 @@ position: relative; } </style> -<div class="privacy-guide-card"> +<div id="privacyGuideCard" on-keydown="onKeyDown_"> <cr-view-manager id="viewManager" on-view-enter-start="onViewEnterStart_"> <privacy-guide-welcome-fragment id="[[privacyGuideStepEnum_.WELCOME]]" class="managed-fragment" on-start-button-click="onNextButtonClick_"
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_page.ts b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_page.ts index 060155d4..38d3133 100644 --- a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_page.ts +++ b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_page.ts
@@ -349,7 +349,6 @@ private navigateForward_() { const components = this.privacyGuideStepToComponentsMap_.get(this.privacyGuideStep_)!; - assert(components.onForwardNavigation || components.nextStep); if (components.onForwardNavigation) { components.onForwardNavigation(); } @@ -368,10 +367,9 @@ if (components.onBackwardNavigation) { components.onBackwardNavigation(); } - this.navigateToCard_( - this.privacyGuideStepToComponentsMap_.get(this.privacyGuideStep_)! - .previousStep!, - true, true); + if (components.previousStep) { + this.navigateToCard_(components.previousStep, true, true); + } } private navigateToCard_( @@ -477,6 +475,18 @@ .shadowRoot!.querySelector<HTMLElement>('[focus-element]')); afterNextRender(this, () => elementToFocus!.focus()); } + + private onKeyDown_(event: KeyboardEvent) { + const isLtr = loadTimeData.getString('textdirection') === 'ltr'; + switch (event.key) { + case 'ArrowLeft': + isLtr ? this.navigateBackward_() : this.navigateForward_(); + break; + case 'ArrowRight': + isLtr ? this.navigateForward_() : this.navigateBackward_(); + break; + } + } } declare global {
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_safe_browsing_fragment.html b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_safe_browsing_fragment.html index a804fed8..27933c75 100644 --- a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_safe_browsing_fragment.html +++ b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_safe_browsing_fragment.html
@@ -10,7 +10,8 @@ </div> <settings-radio-group id="safeBrowsingRadioGroup" pref="{{prefs.generated.safe_browsing}}" - selectable-elements="settings-collapse-radio-button"> + selectable-elements="settings-collapse-radio-button" + on-keydown="onRadioGroupKeyDown_"> <settings-collapse-radio-button id="safeBrowsingRadioEnhanced" pref="[[prefs.generated.safe_browsing]]" name="[[safeBrowsingSettingEnum_.ENHANCED]]"
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_safe_browsing_fragment.ts b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_safe_browsing_fragment.ts index c0e70fe..0dcee143 100644 --- a/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_safe_browsing_fragment.ts +++ b/chrome/browser/resources/settings/privacy_page/privacy_guide/privacy_guide_safe_browsing_fragment.ts
@@ -94,6 +94,18 @@ this.metricsBrowserProxy_.recordAction( 'Settings.PrivacyGuide.ChangeSafeBrowsingStandard'); } + + private onRadioGroupKeyDown_(event: KeyboardEvent) { + switch (event.key) { + case 'ArrowLeft': + case 'ArrowRight': + // This event got consumed by the radio group to change the radio button + // selection. Do not propagate further, to not cause a privacy guide + // navigation. + event.stopPropagation(); + break; + } + } } customElements.define(
diff --git a/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabData.java b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabData.java index 0e886c5..2b28f0d 100644 --- a/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabData.java +++ b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabData.java
@@ -472,12 +472,14 @@ PersistedTabData.from(tab, (data, storage, id, factoryCallback) -> { - ShoppingPersistedTabData shoppingPersistedTabData = - new ShoppingPersistedTabData(tab, storage, id); - PostTask.postTask(TaskTraits.USER_BLOCKING_MAY_BLOCK, () -> { - shoppingPersistedTabData.deserializeAndLog(data); - PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, - () -> { factoryCallback.onResult(shoppingPersistedTabData); }); + PostTask.postTask(UiThreadTaskTraits.DEFAULT, () -> { + ShoppingPersistedTabData shoppingPersistedTabData = + ShoppingPersistedTabData.from(tab); + PostTask.postTask(TaskTraits.USER_BLOCKING_MAY_BLOCK, () -> { + shoppingPersistedTabData.deserializeAndLog(data); + PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, + () -> { factoryCallback.onResult(shoppingPersistedTabData); }); + }); }); }, (supplierCallback)
diff --git a/chrome/browser/themes/theme_service.cc b/chrome/browser/themes/theme_service.cc index 885cdc7..4b853ed 100644 --- a/chrome/browser/themes/theme_service.cc +++ b/chrome/browser/themes/theme_service.cc
@@ -73,6 +73,10 @@ #include "extensions/browser/extension_registry_observer.h" #endif +#if BUILDFLAG(IS_LINUX) +#include "ui/views/linux_ui/linux_ui.h" +#endif + using TP = ThemeProperties; // Helpers -------------------------------------------------------------------- @@ -490,12 +494,27 @@ if (base::FeatureList::IsEnabled( features::kColorProviderRedirectionForThemeProvider)) { if (auto provider_color_id = ThemeProviderColorIdToColorId(id)) { - const auto* const native_theme = - incognito_ ? ui::NativeTheme::GetInstanceForDarkUI() - : ui::NativeTheme::GetInstanceForNativeUi(); + const ui::NativeTheme* native_theme = nullptr; + + if (incognito_) { + native_theme = ui::NativeTheme::GetInstanceForDarkUI(); + } else { + native_theme = ui::NativeTheme::GetInstanceForNativeUi(); +#if BUILDFLAG(IS_LINUX) + if (const auto* linux_ui = views::LinuxUI::instance()) { + // TODO(crbug.com/1304441): Naively passing nullptr might be + // problematic. If this is not an issue, remove this parameter from + // GetNativeTheme(). + native_theme = linux_ui->GetNativeTheme(nullptr); + } +#endif + } + + auto color_provider_key = native_theme->GetColorProviderKey( + GetThemeSupplier(), delegate_->ShouldUseCustomFrame()); auto* color_provider = ui::ColorProviderManager::Get().GetColorProviderFor( - native_theme->GetColorProviderKey(GetThemeSupplier())); + color_provider_key); return color_provider->GetColor(provider_color_id.value()); } } @@ -602,6 +621,14 @@ return theme_supplier_.get(); } +bool ThemeService::ShouldUseCustomFrame() const { +#if BUILDFLAG(IS_LINUX) + return profile_->GetPrefs()->GetBoolean(prefs::kUseCustomChromeFrame); +#else + return true; +#endif +} + void ThemeService::SetTheme(const extensions::Extension* extension) { DoSetTheme(extension, true); }
diff --git a/chrome/browser/themes/theme_service.h b/chrome/browser/themes/theme_service.h index 2df1555..71c6823 100644 --- a/chrome/browser/themes/theme_service.h +++ b/chrome/browser/themes/theme_service.h
@@ -41,6 +41,7 @@ class BrowserThemeProviderDelegate { public: virtual CustomThemeSupplier* GetThemeSupplier() const = 0; + virtual bool ShouldUseCustomFrame() const = 0; }; class ThemeService : public KeyedService, @@ -87,6 +88,7 @@ // Overridden from BrowserThemeProviderDelegate: CustomThemeSupplier* GetThemeSupplier() const override; + bool ShouldUseCustomFrame() const override; // Set the current theme to the theme defined in |extension|. // |extension| must already be added to this profile's
diff --git a/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_fill_button.xml b/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_fill_button.xml index c042051..978e502f 100644 --- a/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_fill_button.xml +++ b/chrome/browser/touch_to_fill/android/internal/java/res/layout/touch_to_fill_fill_button.xml
@@ -8,13 +8,13 @@ <org.chromium.ui.widget.ButtonCompat xmlns:android="http://schemas.android.com/apk/res/android" android:descendantFocusability="blocksDescendants" + android:id="@+id/touch_to_fill_button_title" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="2dp" android:layout_marginBottom="2dp" android:minHeight="48dp" android:gravity="center" - android:text="@string/touch_to_fill_continue" android:background="@drawable/touch_to_fill_credential_background" android:ellipsize="end" android:singleLine="true"
diff --git a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillBridge.java b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillBridge.java index e1336d4b..c0731b0 100644 --- a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillBridge.java +++ b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillBridge.java
@@ -61,8 +61,10 @@ } @CalledByNative - private void showCredentials(GURL url, boolean isOriginSecure, Credential[] credentials) { - mTouchToFillComponent.showCredentials(url, isOriginSecure, Arrays.asList(credentials)); + private void showCredentials( + GURL url, boolean isOriginSecure, Credential[] credentials, boolean submitCredential) { + mTouchToFillComponent.showCredentials( + url, isOriginSecure, Arrays.asList(credentials), submitCredential); } @Override
diff --git a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillCoordinator.java b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillCoordinator.java index 731ac30..7d1049c 100644 --- a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillCoordinator.java +++ b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillCoordinator.java
@@ -37,8 +37,9 @@ } @Override - public void showCredentials(GURL url, boolean isOriginSecure, List<Credential> credentials) { - mMediator.showCredentials(url, isOriginSecure, credentials); + public void showCredentials(GURL url, boolean isOriginSecure, List<Credential> credentials, + boolean triggerSubmission) { + mMediator.showCredentials(url, isOriginSecure, credentials, triggerSubmission); } /**
diff --git a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillMediator.java b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillMediator.java index bb9406fb31..c919f84 100644 --- a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillMediator.java +++ b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillMediator.java
@@ -8,6 +8,7 @@ import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.CredentialProperties.FAVICON_OR_FALLBACK; import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.CredentialProperties.FORMATTED_ORIGIN; import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.CredentialProperties.ON_CLICK_LISTENER; +import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.CredentialProperties.SHOW_SUBMIT_BUTTON; import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.HeaderProperties.FORMATTED_URL; import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.HeaderProperties.ORIGIN_SECURE; import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.HeaderProperties.SINGLE_CREDENTIAL; @@ -62,7 +63,8 @@ mDesiredIconSize = desiredIconSize; } - void showCredentials(GURL url, boolean isOriginSecure, List<Credential> credentials) { + void showCredentials(GURL url, boolean isOriginSecure, List<Credential> credentials, + boolean triggerSubmission) { assert credentials != null; mModel.set(ON_CLICK_MANAGE, this::onManagePasswordSelected); @@ -80,7 +82,7 @@ mCredentials = credentials; for (Credential credential : credentials) { - final PropertyModel model = createModel(credential); + final PropertyModel model = createModel(credential, triggerSubmission); sheetItems.add(new ListItem(TouchToFillProperties.ItemType.CREDENTIAL, model)); requestIconOrFallbackImage(model, url); if (shouldCreateConfirmationButton(credentials)) { @@ -156,12 +158,13 @@ return credentials.size() == 1; } - private PropertyModel createModel(Credential credential) { + private PropertyModel createModel(Credential credential, boolean triggerSubmission) { return new PropertyModel.Builder(CredentialProperties.ALL_KEYS) .with(CREDENTIAL, credential) .with(ON_CLICK_LISTENER, this::onSelectedCredential) .with(FORMATTED_ORIGIN, UrlFormatter.formatUrlForDisplayOmitScheme(credential.getOriginUrl())) + .with(SHOW_SUBMIT_BUTTON, triggerSubmission) .build(); } }
diff --git a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillProperties.java b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillProperties.java index d108533..c8078f50 100644 --- a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillProperties.java +++ b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillProperties.java
@@ -69,12 +69,14 @@ new PropertyModel.ReadableObjectPropertyKey<>("credential"); static final PropertyModel.ReadableObjectPropertyKey<String> FORMATTED_ORIGIN = new PropertyModel.ReadableObjectPropertyKey<>("formatted_url"); + static final PropertyModel.ReadableObjectPropertyKey<Boolean> SHOW_SUBMIT_BUTTON = + new PropertyModel.ReadableObjectPropertyKey<>("submit_credential"); static final PropertyModel .ReadableObjectPropertyKey<Callback<Credential>> ON_CLICK_LISTENER = new PropertyModel.ReadableObjectPropertyKey<>("on_click_listener"); - static final PropertyKey[] ALL_KEYS = { - FAVICON_OR_FALLBACK, CREDENTIAL, FORMATTED_ORIGIN, ON_CLICK_LISTENER}; + static final PropertyKey[] ALL_KEYS = {FAVICON_OR_FALLBACK, CREDENTIAL, FORMATTED_ORIGIN, + ON_CLICK_LISTENER, SHOW_SUBMIT_BUTTON}; private CredentialProperties() {} }
diff --git a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewBinder.java b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewBinder.java index ef697ae..4416225 100644 --- a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewBinder.java +++ b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewBinder.java
@@ -8,6 +8,7 @@ import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.CredentialProperties.FAVICON_OR_FALLBACK; import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.CredentialProperties.FORMATTED_ORIGIN; import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.CredentialProperties.ON_CLICK_LISTENER; +import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.CredentialProperties.SHOW_SUBMIT_BUTTON; import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.DISMISS_HANDLER; import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.HeaderProperties.FORMATTED_URL; import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.HeaderProperties.ORIGIN_SECURE; @@ -25,6 +26,7 @@ import androidx.annotation.StringRes; +import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.CredentialProperties; import org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.ItemType; import org.chromium.chrome.browser.touch_to_fill.data.Credential; @@ -141,6 +143,8 @@ TextView passwordText = view.findViewById(R.id.password); passwordText.setText(credential.getPassword()); passwordText.setTransformationMethod(new PasswordTransformationMethod()); + } else if (propertyKey == SHOW_SUBMIT_BUTTON) { + // Whether Touch To Fill should auto-submit a form doesn't affect the credentials list. } else { assert false : "Unhandled update to property:" + propertyKey; } @@ -158,15 +162,45 @@ if (propertyKey == ON_CLICK_LISTENER) { view.setOnClickListener( clickedView -> { model.get(ON_CLICK_LISTENER).onResult(credential); }); + } else if (propertyKey == SHOW_SUBMIT_BUTTON) { + TextView buttonTitleText = view.findViewById(R.id.touch_to_fill_button_title); + if (ChromeFeatureList.isEnabled(ChromeFeatureList.TOUCH_TO_FILL_PASSWORD_SUBMISSION)) { + buttonTitleText.setText(view.getContext().getString(model.get(SHOW_SUBMIT_BUTTON) + ? R.string.touch_to_fill_signin + : R.string.touch_to_fill_continue)); + } else { + buttonTitleText.setText(R.string.touch_to_fill_continue); + } } else if (propertyKey == FAVICON_OR_FALLBACK || propertyKey == FORMATTED_ORIGIN || propertyKey == CREDENTIAL) { - // The button appearance is static. + // Credential properties don't affect the button. } else { assert false : "Unhandled update to property:" + propertyKey; } } /** + * Helper function to infer the title of Touch To Fill sheet. + * @param model The observed {@link PropertyModel}. Its data need to be reflected in the view. + * @param view The {@link View} of the header to update. + * @return The title of Touch To Fill sheet. + */ + private static String getTitle(PropertyModel model, View view) { + if (ChromeFeatureList.isEnabled(ChromeFeatureList.TOUCH_TO_FILL_PASSWORD_SUBMISSION)) { + return view.getContext().getString(R.string.touch_to_fill_sheet_uniform_title); + } + + @StringRes + int titleStringId; + if (model.get(SINGLE_CREDENTIAL)) { + titleStringId = R.string.touch_to_fill_sheet_title_single; + } else { + titleStringId = R.string.touch_to_fill_sheet_title; + } + return view.getContext().getString(titleStringId); + } + + /** * Called whenever a property in the given model changes. It updates the given view accordingly. * @param model The observed {@link PropertyModel}. Its data need to be reflected in the view. * @param view The {@link View} of the header to update. @@ -175,15 +209,11 @@ private static void bindHeaderView(PropertyModel model, View view, PropertyKey key) { if (key == SINGLE_CREDENTIAL || key == FORMATTED_URL || key == ORIGIN_SECURE) { TextView sheetTitleText = view.findViewById(R.id.touch_to_fill_sheet_title); - @StringRes - int titleStringId; - if (model.get(SINGLE_CREDENTIAL)) { - titleStringId = R.string.touch_to_fill_sheet_title_single; - } else { - titleStringId = R.string.touch_to_fill_sheet_title; - } - sheetTitleText.setText(view.getContext().getString(titleStringId)); + sheetTitleText.setText(getTitle(model, view)); + TextView sheetSubtitleText = view.findViewById(R.id.touch_to_fill_sheet_subtitle); + // TODO(crbug.com/1283004): Variate the subtitle if auto-submission is going to be + // triggered. if (model.get(ORIGIN_SECURE)) { sheetSubtitleText.setText(model.get(FORMATTED_URL)); } else {
diff --git a/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings.grd b/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings.grd index d850a8c..daad4065 100644 --- a/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings.grd +++ b/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings.grd
@@ -181,6 +181,9 @@ <message name="IDS_TOUCH_TO_FILL_SHEET_TITLE" desc="Header for Touch To Fill sheet where users can pick a credential to fill into a form to."> Choose an account </message> + <message name="IDS_TOUCH_TO_FILL_SHEET_UNIFORM_TITLE" desc="Header for Touch To Fill sheet where users can pick a credential to fill into a form. Will replace SHEET_TITLE_SINGLE and SHEET_TITLE."> + Use saved password? + </message> <message name="IDS_TOUCH_TO_FILL_SHEET_SUBTITLE_NOT_SECURE" desc="Subtitle for Touch To Fill sheet when the website is not secure. Note that similarly to the omnibox 'not secure' in this case primarily refers to HTTPS connection security. So prefer translations with a connotation of 'not private' (someone can intercept your communication with the site) rather than 'not trustworthy' (which would be a judgment of site reputation)."> <ph name="SITE_NAME">%1$s<ex>airbnb.com</ex> (not secure)</ph> </message> @@ -199,9 +202,12 @@ <message name="IDS_MANAGE_PASSWORDS" desc="Title of the button at the end of a touch to fill sheet that will open the password preferences when tapped."> Manage passwords </message> - <message name="IDS_TOUCH_TO_FILL_CONTINUE" desc="Title of the button that continues filling with the only available set of credentials."> + <message name="IDS_TOUCH_TO_FILL_CONTINUE" desc="Title of the button that continues filling with the only available credential."> Continue </message> + <message name="IDS_TOUCH_TO_FILL_SIGNIN" desc="Title of the button that continues filling and submitting the only available credential."> + Sign in + </message> </messages> </release> </grit>
diff --git a/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings_grd/IDS_TOUCH_TO_FILL_SHEET_UNIFORM_TITLE.png.sha1 b/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings_grd/IDS_TOUCH_TO_FILL_SHEET_UNIFORM_TITLE.png.sha1 new file mode 100644 index 0000000..98a2c21 --- /dev/null +++ b/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings_grd/IDS_TOUCH_TO_FILL_SHEET_UNIFORM_TITLE.png.sha1
@@ -0,0 +1 @@ +91d0b55f4b5b68845d1c497f83578100cf59a161 \ No newline at end of file
diff --git a/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings_grd/IDS_TOUCH_TO_FILL_SIGNIN.png.sha1 b/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings_grd/IDS_TOUCH_TO_FILL_SIGNIN.png.sha1 new file mode 100644 index 0000000..db4f348 --- /dev/null +++ b/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings_grd/IDS_TOUCH_TO_FILL_SIGNIN.png.sha1
@@ -0,0 +1 @@ +603d6f470a9dc4d147bdd220d9dba8aa7e802741 \ No newline at end of file
diff --git a/chrome/browser/touch_to_fill/android/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillComponent.java b/chrome/browser/touch_to_fill/android/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillComponent.java index ad7a833..be4e766e 100644 --- a/chrome/browser/touch_to_fill/android/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillComponent.java +++ b/chrome/browser/touch_to_fill/android/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillComponent.java
@@ -74,6 +74,9 @@ * @param url A {@link String} that contains the URL to display credentials for. * @param isOriginSecure A {@link boolean} that indicates whether the current origin is secure. * @param credentials A list of {@link Credential}s that will be displayed. + * @param triggerSubmission A {@link boolean} that indicates whether a form should be submitted + * after filling. */ - void showCredentials(GURL url, boolean isOriginSecure, List<Credential> credentials); + void showCredentials(GURL url, boolean isOriginSecure, List<Credential> credentials, + boolean triggerSubmission); }
diff --git a/chrome/browser/touch_to_fill/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillIntegrationTest.java b/chrome/browser/touch_to_fill/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillIntegrationTest.java index 27504fa0..5e78274 100644 --- a/chrome/browser/touch_to_fill/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillIntegrationTest.java +++ b/chrome/browser/touch_to_fill/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillIntegrationTest.java
@@ -99,7 +99,7 @@ @MediumTest public void testClickingSuggestionsTriggersCallback() { runOnUiThreadBlocking(() -> { - mTouchToFill.showCredentials(sExampleUrl, true, Collections.singletonList(sAna)); + mTouchToFill.showCredentials(sExampleUrl, true, Collections.singletonList(sAna), false); }); BottomSheetTestSupport.waitForOpen(mBottomSheetController); @@ -114,7 +114,7 @@ @MediumTest public void testBackDismissesAndCallsCallback() { runOnUiThreadBlocking(() -> { - mTouchToFill.showCredentials(sExampleUrl, true, Arrays.asList(sAna, sBob)); + mTouchToFill.showCredentials(sExampleUrl, true, Arrays.asList(sAna, sBob), false); }); BottomSheetTestSupport.waitForOpen(mBottomSheetController); @@ -189,7 +189,7 @@ Espresso.onView(withText("Another bottom sheet content")).check(matches(isDisplayed())); runOnUiThreadBlocking(() -> { - mTouchToFill.showCredentials(sExampleUrl, true, Arrays.asList(sAna, sBob)); + mTouchToFill.showCredentials(sExampleUrl, true, Arrays.asList(sAna, sBob), false); }); waitForEvent(mMockBridge).onDismissed(); verify(mMockBridge, never()).onCredentialSelected(any());
diff --git a/chrome/browser/touch_to_fill/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewTest.java b/chrome/browser/touch_to_fill/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewTest.java index f2cc72c7..2379af2f 100644 --- a/chrome/browser/touch_to_fill/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewTest.java +++ b/chrome/browser/touch_to_fill/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewTest.java
@@ -16,6 +16,7 @@ import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.CredentialProperties.CREDENTIAL; import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.CredentialProperties.FORMATTED_ORIGIN; import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.CredentialProperties.ON_CLICK_LISTENER; +import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.CredentialProperties.SHOW_SUBMIT_BUTTON; import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.HeaderProperties.FORMATTED_URL; import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.HeaderProperties.ORIGIN_SECURE; import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.HeaderProperties.SINGLE_CREDENTIAL; @@ -45,11 +46,13 @@ import org.chromium.base.test.util.CriteriaHelper; import org.chromium.base.test.util.ScalableTimeout; import org.chromium.chrome.browser.app.ChromeActivity; +import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.HeaderProperties; import org.chromium.chrome.browser.touch_to_fill.data.Credential; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.chrome.test.ChromeTabbedActivityTestRule; +import org.chromium.chrome.test.util.browser.Features.EnableFeatures; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.SheetState; import org.chromium.components.browser_ui.bottomsheet.BottomSheetTestSupport; @@ -120,6 +123,9 @@ @Test @MediumTest public void testSingleCredentialTitleDisplayed() { + // TODO(crbug.com/1283004): Replace the test with + // |testSingleCredentialTitleDisplayedWithSubmissionEnabled| when + // TOUCH_TO_FILL_PASSWORD_SUBMISSION is enabled. TestThreadUtils.runOnUiThreadBlocking(() -> { mModel.get(SHEET_ITEMS) .add(new MVCListAdapter.ListItem(TouchToFillProperties.ItemType.HEADER, @@ -141,6 +147,9 @@ @Test @MediumTest public void testMultiCredentialTitleDisplayed() { + // TODO(crbug.com/1283004): Replace the test with + // |testMultiCredentialTitleDisplayedWithSubmissionEnabled| when + // TOUCH_TO_FILL_PASSWORD_SUBMISSION is enabled. TestThreadUtils.runOnUiThreadBlocking(() -> { mModel.get(SHEET_ITEMS) .add(new MVCListAdapter.ListItem(TouchToFillProperties.ItemType.HEADER, @@ -161,6 +170,50 @@ @Test @MediumTest + @EnableFeatures({ChromeFeatureList.TOUCH_TO_FILL_PASSWORD_SUBMISSION}) + public void testSingleCredentialTitleDisplayedWithSubmissionEnabled() { + TestThreadUtils.runOnUiThreadBlocking(() -> { + mModel.get(SHEET_ITEMS) + .add(new MVCListAdapter.ListItem(TouchToFillProperties.ItemType.HEADER, + new PropertyModel.Builder(HeaderProperties.ALL_KEYS) + .with(SINGLE_CREDENTIAL, true) + .with(FORMATTED_URL, "www.example.org") + .with(ORIGIN_SECURE, true) + .build())); + mModel.set(VISIBLE, true); + }); + BottomSheetTestSupport.waitForOpen(mBottomSheetController); + TextView title = + mTouchToFillView.getContentView().findViewById(R.id.touch_to_fill_sheet_title); + + assertThat(title.getText(), + is(getActivity().getString(R.string.touch_to_fill_sheet_uniform_title))); + } + + @Test + @MediumTest + @EnableFeatures({ChromeFeatureList.TOUCH_TO_FILL_PASSWORD_SUBMISSION}) + public void testMultiCredentialTitleDisplayedWithSubmissionEnabled() { + TestThreadUtils.runOnUiThreadBlocking(() -> { + mModel.get(SHEET_ITEMS) + .add(new MVCListAdapter.ListItem(TouchToFillProperties.ItemType.HEADER, + new PropertyModel.Builder(HeaderProperties.ALL_KEYS) + .with(SINGLE_CREDENTIAL, false) + .with(FORMATTED_URL, "www.example.org") + .with(ORIGIN_SECURE, true) + .build())); + mModel.set(VISIBLE, true); + }); + BottomSheetTestSupport.waitForOpen(mBottomSheetController); + TextView title = + mTouchToFillView.getContentView().findViewById(R.id.touch_to_fill_sheet_title); + + assertThat(title.getText(), + is(getActivity().getString(R.string.touch_to_fill_sheet_uniform_title))); + } + + @Test + @MediumTest public void testSecureSubtitleUrlDisplayed() { TestThreadUtils.runOnUiThreadBlocking(() -> { mModel.get(SHEET_ITEMS) @@ -255,9 +308,7 @@ public void testSingleCredentialHasClickableButton() { TestThreadUtils.runOnUiThreadBlocking(() -> { mModel.get(SHEET_ITEMS) - .addAll(asList( - buildSheetItem(TouchToFillProperties.ItemType.CREDENTIAL, ANA, null), - buildConfirmationButton(ANA))); + .addAll(asList(buildCredentialItem(ANA), buildConfirmationButton(ANA, false))); mModel.set(VISIBLE, true); }); BottomSheetTestSupport.waitForOpen(mBottomSheetController); @@ -272,6 +323,39 @@ @Test @MediumTest + public void testButtonTitleWithoutAutoSubmission() { + TestThreadUtils.runOnUiThreadBlocking(() -> { + mModel.get(SHEET_ITEMS) + .addAll(asList(buildCredentialItem(ANA), buildConfirmationButton(ANA, false))); + mModel.set(VISIBLE, true); + }); + BottomSheetTestSupport.waitForOpen(mBottomSheetController); + + TextView title = + mTouchToFillView.getContentView().findViewById(R.id.touch_to_fill_button_title); + + assertThat(title.getText(), is(getActivity().getString(R.string.touch_to_fill_continue))); + } + + @Test + @MediumTest + @EnableFeatures({ChromeFeatureList.TOUCH_TO_FILL_PASSWORD_SUBMISSION}) + public void testButtonTitleWithAutoSubmission() { + TestThreadUtils.runOnUiThreadBlocking(() -> { + mModel.get(SHEET_ITEMS) + .addAll(asList(buildCredentialItem(ANA), buildConfirmationButton(ANA, true))); + mModel.set(VISIBLE, true); + }); + BottomSheetTestSupport.waitForOpen(mBottomSheetController); + + TextView title = + mTouchToFillView.getContentView().findViewById(R.id.touch_to_fill_button_title); + + assertThat(title.getText(), is(getActivity().getString(R.string.touch_to_fill_signin))); + } + + @Test + @MediumTest public void testManagePasswordsIsClickable() { final AtomicBoolean manageButtonClicked = new AtomicBoolean(false); TestThreadUtils.runOnUiThreadBlocking(() -> { @@ -338,22 +422,24 @@ private MVCListAdapter.ListItem buildCredentialItem(Credential credential) { return buildSheetItem( - TouchToFillProperties.ItemType.CREDENTIAL, credential, mCredentialCallback); + TouchToFillProperties.ItemType.CREDENTIAL, credential, mCredentialCallback, false); } - private MVCListAdapter.ListItem buildConfirmationButton(Credential credential) { - return buildSheetItem( - TouchToFillProperties.ItemType.FILL_BUTTON, credential, mCredentialCallback); + private MVCListAdapter.ListItem buildConfirmationButton( + Credential credential, boolean showSubmitButton) { + return buildSheetItem(TouchToFillProperties.ItemType.FILL_BUTTON, credential, + mCredentialCallback, showSubmitButton); } private static MVCListAdapter.ListItem buildSheetItem( @TouchToFillProperties.ItemType int itemType, Credential credential, - Callback<Credential> callback) { + Callback<Credential> callback, boolean showSubmitButton) { return new MVCListAdapter.ListItem(itemType, new PropertyModel.Builder(TouchToFillProperties.CredentialProperties.ALL_KEYS) .with(CREDENTIAL, credential) .with(ON_CLICK_LISTENER, callback) .with(FORMATTED_ORIGIN, credential.getOriginUrl()) + .with(SHOW_SUBMIT_BUTTON, showSubmitButton) .build()); } }
diff --git a/chrome/browser/touch_to_fill/android/junit/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillControllerTest.java b/chrome/browser/touch_to_fill/android/junit/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillControllerTest.java index aecc26f..367f5faa 100644 --- a/chrome/browser/touch_to_fill/android/junit/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillControllerTest.java +++ b/chrome/browser/touch_to_fill/android/junit/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillControllerTest.java
@@ -19,6 +19,7 @@ import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.CredentialProperties.FAVICON_OR_FALLBACK; import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.CredentialProperties.FORMATTED_ORIGIN; import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.CredentialProperties.ON_CLICK_LISTENER; +import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.CredentialProperties.SHOW_SUBMIT_BUTTON; import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.DISMISS_HANDLER; import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.HeaderProperties.FORMATTED_URL; import static org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.HeaderProperties.ORIGIN_SECURE; @@ -132,29 +133,62 @@ } @Test - public void testShowCredentialsCreatesHeader() { - mMediator.showCredentials(TEST_URL, true, Arrays.asList(ANA, CARL, BOB)); + public void testShowCredentialsWithMultipleEntries() { + mMediator.showCredentials(TEST_URL, true, Arrays.asList(ANA, CARL), false); ListModel<MVCListAdapter.ListItem> itemList = mModel.get(SHEET_ITEMS); + assertThat(itemList.size(), is(3)); // Header + 2 credentials + assertThat(itemList.get(0).type, is(ItemType.HEADER)); assertThat(itemList.get(0).model.get(SINGLE_CREDENTIAL), is(false)); assertThat( itemList.get(0).model.get(FORMATTED_URL), is(formatForSecurityDisplay(TEST_URL))); assertThat(itemList.get(0).model.get(ORIGIN_SECURE), is(true)); + + assertThat(itemList.get(1).type, is(ItemType.CREDENTIAL)); + assertThat(itemList.get(1).model.get(CREDENTIAL), is(ANA)); + assertNotNull(itemList.get(1).model.get(ON_CLICK_LISTENER)); + assertThat(itemList.get(1).model.get(FORMATTED_ORIGIN), is(format(ANA.getOriginUrl()))); + + assertThat(itemList.get(2).type, is(ItemType.CREDENTIAL)); + assertThat(itemList.get(2).model.get(CREDENTIAL), is(CARL)); + assertNotNull(itemList.get(2).model.get(ON_CLICK_LISTENER)); + assertThat(itemList.get(2).model.get(FORMATTED_ORIGIN), is(format(CARL.getOriginUrl()))); } + @Test - public void testShowCredentialWithSingleEntryCreatesHeader() { - mMediator.showCredentials(TEST_URL, true, Arrays.asList(ANA)); + public void testShowCredentialsWithSingleEntry() { + mMediator.showCredentials(TEST_URL, true, Arrays.asList(ANA), false); ListModel<MVCListAdapter.ListItem> itemList = mModel.get(SHEET_ITEMS); + assertThat(itemList.size(), is(3)); // Header + 1 credential + Button + assertThat(itemList.get(0).type, is(ItemType.HEADER)); assertThat(itemList.get(0).model.get(SINGLE_CREDENTIAL), is(true)); assertThat( itemList.get(0).model.get(FORMATTED_URL), is(formatForSecurityDisplay(TEST_URL))); assertThat(itemList.get(0).model.get(ORIGIN_SECURE), is(true)); + + assertThat(itemList.get(1).type, is(ItemType.CREDENTIAL)); + assertThat(itemList.get(1).model.get(CREDENTIAL), is(ANA)); + assertNotNull(itemList.get(1).model.get(ON_CLICK_LISTENER)); + assertThat(itemList.get(1).model.get(FORMATTED_ORIGIN), is(format(ANA.getOriginUrl()))); + + assertThat(itemList.get(2).type, is(ItemType.FILL_BUTTON)); + assertThat(itemList.get(2).model.get(SHOW_SUBMIT_BUTTON), is(false)); + } + + @Test + public void testShowCredentialsToSubmit() { + mMediator.showCredentials(TEST_URL, true, Arrays.asList(ANA), true); + ListModel<MVCListAdapter.ListItem> itemList = mModel.get(SHEET_ITEMS); + assertThat(itemList.size(), is(3)); // Header + 1 credential + Button + + assertThat(itemList.get(2).type, is(ItemType.FILL_BUTTON)); + assertThat(itemList.get(2).model.get(SHOW_SUBMIT_BUTTON), is(true)); } @Test public void testShowCredentialsSetsCredentialListAndRequestsFavicons() { - mMediator.showCredentials(TEST_URL, true, Arrays.asList(ANA, CARL, BOB)); + mMediator.showCredentials(TEST_URL, true, Arrays.asList(ANA, CARL, BOB), false); ListModel<MVCListAdapter.ListItem> itemList = mModel.get(SHEET_ITEMS); assertThat(itemList.size(), is(4)); // Header + three Credentials assertThat(itemList.get(1).type, is(ItemType.CREDENTIAL)); @@ -177,7 +211,7 @@ @Test public void testFetchFaviconUpdatesModel() { - mMediator.showCredentials(TEST_URL, true, Collections.singletonList(CARL)); + mMediator.showCredentials(TEST_URL, true, Collections.singletonList(CARL), false); ListModel<MVCListAdapter.ListItem> itemList = mModel.get(SHEET_ITEMS); assertThat(itemList.size(), is(3)); // Header + Credential + Continue Button assertThat(itemList.get(1).type, is(ItemType.CREDENTIAL)); @@ -203,7 +237,7 @@ @Test public void testShowCredentialsFormatPslOrigins() { - mMediator.showCredentials(TEST_URL, true, Arrays.asList(ANA, BOB)); + mMediator.showCredentials(TEST_URL, true, Arrays.asList(ANA, BOB), false); assertThat(mModel.get(SHEET_ITEMS).size(), is(3)); // Header + two Credentials assertThat(mModel.get(SHEET_ITEMS).get(1).type, is(ItemType.CREDENTIAL)); assertThat(mModel.get(SHEET_ITEMS).get(1).model.get(FORMATTED_ORIGIN), @@ -215,7 +249,7 @@ @Test public void testClearsCredentialListWhenShowingAgain() { - mMediator.showCredentials(TEST_URL, true, Collections.singletonList(ANA)); + mMediator.showCredentials(TEST_URL, true, Collections.singletonList(ANA), false); ListModel<MVCListAdapter.ListItem> itemList = mModel.get(SHEET_ITEMS); assertThat(itemList.size(), is(3)); // Header + Credential + Continue Button assertThat(itemList.get(1).type, is(ItemType.CREDENTIAL)); @@ -223,7 +257,7 @@ assertThat(itemList.get(1).model.get(FAVICON_OR_FALLBACK), is(nullValue())); // Showing the sheet a second time should replace all changed credentials. - mMediator.showCredentials(TEST_URL, true, Collections.singletonList(BOB)); + mMediator.showCredentials(TEST_URL, true, Collections.singletonList(BOB), false); itemList = mModel.get(SHEET_ITEMS); assertThat(itemList.size(), is(3)); // Header + Credential + Continue Button assertThat(itemList.get(1).type, is(ItemType.CREDENTIAL)); @@ -233,13 +267,13 @@ @Test public void testShowCredentialsSetsVisibile() { - mMediator.showCredentials(TEST_URL, true, Arrays.asList(ANA, CARL, BOB)); + mMediator.showCredentials(TEST_URL, true, Arrays.asList(ANA, CARL, BOB), false); assertThat(mModel.get(VISIBLE), is(true)); } @Test public void testCallsCallbackAndHidesOnSelectingItemDoesNotRecordIndexForSingleCredential() { - mMediator.showCredentials(TEST_URL, true, Arrays.asList(ANA)); + mMediator.showCredentials(TEST_URL, true, Arrays.asList(ANA), false); assertThat(mModel.get(VISIBLE), is(true)); assertNotNull(mModel.get(SHEET_ITEMS).get(1).model.get(ON_CLICK_LISTENER)); @@ -257,7 +291,7 @@ @Test public void testCallsCallbackAndHidesOnSelectingItem() { - mMediator.showCredentials(TEST_URL, true, Arrays.asList(ANA, CARL)); + mMediator.showCredentials(TEST_URL, true, Arrays.asList(ANA, CARL), false); assertThat(mModel.get(VISIBLE), is(true)); assertNotNull(mModel.get(SHEET_ITEMS).get(1).model.get(ON_CLICK_LISTENER)); @@ -275,7 +309,7 @@ @Test public void testCallsDelegateAndHidesOnDismiss() { - mMediator.showCredentials(TEST_URL, true, Arrays.asList(ANA, CARL)); + mMediator.showCredentials(TEST_URL, true, Arrays.asList(ANA, CARL), false); mMediator.onDismissed(BottomSheetController.StateChangeReason.BACK_PRESS); verify(mMockDelegate).onDismissed(); assertThat(mModel.get(VISIBLE), is(false)); @@ -290,7 +324,7 @@ @Test public void testHidesWhenSelectingManagePasswords() { - mMediator.showCredentials(TEST_URL, true, Arrays.asList(ANA, CARL, BOB)); + mMediator.showCredentials(TEST_URL, true, Arrays.asList(ANA, CARL, BOB), false); assertThat(mModel.get(ON_CLICK_MANAGE), is(notNullValue())); mModel.get(ON_CLICK_MANAGE).run(); verify(mMockDelegate).onManagePasswordsSelected();
diff --git a/chrome/browser/touch_to_fill/android/touch_to_fill_view_impl.cc b/chrome/browser/touch_to_fill/android/touch_to_fill_view_impl.cc index f0f12df..31d5170a 100644 --- a/chrome/browser/touch_to_fill/android/touch_to_fill_view_impl.cc +++ b/chrome/browser/touch_to_fill/android/touch_to_fill_view_impl.cc
@@ -64,7 +64,8 @@ void TouchToFillViewImpl::Show( const GURL& url, IsOriginSecure is_origin_secure, - base::span<const password_manager::UiCredential> credentials) { + base::span<const password_manager::UiCredential> credentials, + bool trigger_submission) { if (!RecreateJavaObject()) { // It's possible that the constructor cannot access the bottom sheet clank // component. That case may be temporary but we can't let users in a waiting @@ -93,8 +94,7 @@ Java_TouchToFillBridge_showCredentials( env, java_object_internal_, url::GURLAndroid::FromNativeGURL(env, url), - - is_origin_secure.value(), credential_array); + is_origin_secure.value(), credential_array, trigger_submission); } void TouchToFillViewImpl::OnCredentialSelected(const UiCredential& credential) {
diff --git a/chrome/browser/touch_to_fill/android/touch_to_fill_view_impl.h b/chrome/browser/touch_to_fill/android/touch_to_fill_view_impl.h index cf2e382..4a01e89 100644 --- a/chrome/browser/touch_to_fill/android/touch_to_fill_view_impl.h +++ b/chrome/browser/touch_to_fill/android/touch_to_fill_view_impl.h
@@ -24,10 +24,10 @@ ~TouchToFillViewImpl() override; // TouchToFillView: - void Show( - const GURL& url, - IsOriginSecure is_origin_secure, - base::span<const password_manager::UiCredential> credentials) override; + void Show(const GURL& url, + IsOriginSecure is_origin_secure, + base::span<const password_manager::UiCredential> credentials, + bool trigger_submission) override; void OnCredentialSelected( const password_manager::UiCredential& credential) override; void OnDismiss() override;
diff --git a/chrome/browser/touch_to_fill/touch_to_fill_controller.cc b/chrome/browser/touch_to_fill/touch_to_fill_controller.cc index 7c65942..33a47cf 100644 --- a/chrome/browser/touch_to_fill/touch_to_fill_controller.cc +++ b/chrome/browser/touch_to_fill/touch_to_fill_controller.cc
@@ -76,11 +76,13 @@ void TouchToFillController::Show(base::span<const UiCredential> credentials, base::WeakPtr<PasswordManagerDriver> driver, - bool trigger_submission) { + bool ready_for_submission) { DCHECK(!driver_ || driver_.get() == driver.get()); driver_ = std::move(driver); - // TODO(crbug.com/1283004): Propagte this to Java to variate UI strings. - trigger_submission_ = trigger_submission; + trigger_submission_ = + ready_for_submission && + base::FeatureList::IsEnabled( + password_manager::features::kTouchToFillPasswordSubmission); base::UmaHistogramCounts100("PasswordManager.TouchToFill.NumCredentialsShown", credentials.size()); @@ -101,7 +103,7 @@ url, TouchToFillView::IsOriginSecure( network::IsOriginPotentiallyTrustworthy(url::Origin::Create(url))), - SortCredentials(credentials)); + SortCredentials(credentials), trigger_submission_); } void TouchToFillController::OnCredentialSelected( @@ -189,10 +191,7 @@ driver_->FillSuggestion(credential.username(), credential.password()); if (trigger_submission_) { - if (base::FeatureList::IsEnabled( - password_manager::features::kTouchToFillPasswordSubmission)) { - driver_->TriggerFormSubmission(); - } + driver_->TriggerFormSubmission(); } driver_ = nullptr;
diff --git a/chrome/browser/touch_to_fill/touch_to_fill_controller.h b/chrome/browser/touch_to_fill/touch_to_fill_controller.h index bb12ab8..da8a566f 100644 --- a/chrome/browser/touch_to_fill/touch_to_fill_controller.h +++ b/chrome/browser/touch_to_fill/touch_to_fill_controller.h
@@ -70,7 +70,7 @@ // Instructs the controller to show the provided |credentials| to the user. void Show(base::span<const password_manager::UiCredential> credentials, base::WeakPtr<password_manager::PasswordManagerDriver> driver, - bool trigger_submission); + bool ready_for_submission); // Informs the controller that the user has made a selection. Invokes both // FillSuggestion() and TouchToFillDismissed() on |driver_|. No-op if invoked
diff --git a/chrome/browser/touch_to_fill/touch_to_fill_controller_unittest.cc b/chrome/browser/touch_to_fill/touch_to_fill_controller_unittest.cc index 4d698dc..8d388d1 100644 --- a/chrome/browser/touch_to_fill/touch_to_fill_controller_unittest.cc +++ b/chrome/browser/touch_to_fill/touch_to_fill_controller_unittest.cc
@@ -59,10 +59,11 @@ }; struct MockTouchToFillView : TouchToFillView { - MOCK_METHOD3(Show, - void(const GURL&, - IsOriginSecure, - base::span<const UiCredential>)); + MOCK_METHOD( + void, + Show, + (const GURL&, IsOriginSecure, base::span<const UiCredential>, bool), + (override)); MOCK_METHOD1(OnCredentialSelected, void(const UiCredential&)); MOCK_METHOD0(OnDismiss, void()); }; @@ -160,9 +161,10 @@ MakeUiCredential({.username = "alice", .password = "p4ssw0rd"})}; EXPECT_CALL(*weak_view, Show(Eq(GURL(kExampleCom)), IsOriginSecure(true), - ElementsAreArray(credentials))); + ElementsAreArray(credentials), + /*trigger_submission=*/false)); controller_no_auth->Show(credentials, driver().AsWeakPtr(), - /*trigger_submission=*/false); + /*ready_for_submission=*/false); // Test that we correctly log the absence of an Android credential. EXPECT_CALL(driver(), FillSuggestion(std::u16string(u"alice"), @@ -201,9 +203,10 @@ MakeUiCredential({.username = "alice", .password = "p4ssw0rd"})}; EXPECT_CALL(*weak_view, Show(Eq(GURL(kExampleCom)), IsOriginSecure(true), - ElementsAreArray(credentials))); + ElementsAreArray(credentials), + /*trigger_submission=*/true)); controller_no_auth->Show(credentials, driver().AsWeakPtr(), - /*trigger_submission=*/true); + /*ready_for_submission=*/true); EXPECT_CALL(driver(), FillSuggestion(std::u16string(u"alice"), std::u16string(u"p4ssw0rd"))); @@ -229,9 +232,10 @@ MakeUiCredential({.username = "alice", .password = "p4ssw0rd"})}; EXPECT_CALL(*weak_view, Show(Eq(GURL(kExampleCom)), IsOriginSecure(true), - ElementsAreArray(credentials))); + ElementsAreArray(credentials), + /*trigger_submission=*/false)); controller_no_auth->Show(credentials, driver().AsWeakPtr(), - /*trigger_submission=*/false); + /*ready_for_submission=*/false); EXPECT_CALL(driver(), FillSuggestion(std::u16string(u"alice"), std::u16string(u"p4ssw0rd"))); @@ -247,9 +251,10 @@ MakeUiCredential({.username = "alice", .password = "p4ssw0rd"})}; EXPECT_CALL(view(), Show(Eq(GURL(kExampleCom)), IsOriginSecure(true), - ElementsAreArray(credentials))); + ElementsAreArray(credentials), + /*trigger_submission=*/false)); touch_to_fill_controller().Show(credentials, driver().AsWeakPtr(), - /*trigger_submission=*/false); + /*ready_for_submission=*/false); // Test that we correctly log the absence of an Android credential. EXPECT_CALL(driver(), FillSuggestion(std::u16string(u"alice"), @@ -278,10 +283,13 @@ UiCredential credentials[] = { MakeUiCredential({.username = "alice", .password = "p4ssw0rd"})}; + // Without |kTouchToFillPasswordSubmission|, |ready_for_submission=true| has + // no effect. EXPECT_CALL(view(), Show(Eq(GURL(kExampleCom)), IsOriginSecure(true), - ElementsAreArray(credentials))); + ElementsAreArray(credentials), + /*trigger_submission=*/false)); touch_to_fill_controller().Show(credentials, driver().AsWeakPtr(), - /*trigger_submission=*/true); + /*ready_for_submission=*/true); EXPECT_CALL(driver(), FillSuggestion(std::u16string(u"alice"), std::u16string(u"p4ssw0rd"))); @@ -293,8 +301,8 @@ EXPECT_CALL(*authenticator(), Authenticate(BiometricAuthRequester::kTouchToFill, _)) .WillOnce(RunOnceCallback<1>(true)); - // Without |kTouchToFillPasswordSubmission|, |trigger_submission=true| has no - // effect. + // Without |kTouchToFillPasswordSubmission|, |ready_for_submission=true| has + // no effect. EXPECT_CALL(driver(), TriggerFormSubmission()).Times(0); touch_to_fill_controller().OnCredentialSelected(credentials[0]); } @@ -304,9 +312,10 @@ MakeUiCredential({.username = "alice", .password = "p4ssw0rd"})}; EXPECT_CALL(view(), Show(Eq(GURL(kExampleCom)), IsOriginSecure(true), - ElementsAreArray(credentials))); + ElementsAreArray(credentials), + /*trigger_submission=*/false)); touch_to_fill_controller().Show(credentials, driver().AsWeakPtr(), - /*trigger_submission=*/false); + /*ready_for_submission=*/false); EXPECT_CALL(driver(), FillSuggestion(_, _)).Times(0); EXPECT_CALL(driver(), TouchToFillClosed(ShowVirtualKeyboard(true))); @@ -339,11 +348,11 @@ UiCredential credentials[] = { MakeUiCredential({.username = "alice", .password = "p4ssw0rd"})}; - EXPECT_CALL(view(), - Show(Eq(GURL("http://example.com")), IsOriginSecure(false), - ElementsAreArray(credentials))); + EXPECT_CALL(view(), Show(Eq(GURL("http://example.com")), + IsOriginSecure(false), ElementsAreArray(credentials), + /*ready_for_submission=*/false)); touch_to_fill_controller().Show(credentials, driver().AsWeakPtr(), - /*trigger_submission=*/false); + /*ready_for_submission=*/false); } TEST_F(TouchToFillControllerTest, Show_And_Fill_Android_Credential) { @@ -364,9 +373,10 @@ }; EXPECT_CALL(view(), Show(Eq(GURL(kExampleCom)), IsOriginSecure(true), - ElementsAreArray(credentials))); + ElementsAreArray(credentials), + /*trigger_submission=*/false)); touch_to_fill_controller().Show(credentials, driver().AsWeakPtr(), - /*trigger_submission=*/false); + /*ready_for_submission=*/false); // Test that we correctly log the presence of an Android credential. EXPECT_CALL(driver(), FillSuggestion(std::u16string(u"bob"), @@ -417,9 +427,10 @@ UiCredential credentials[] = {alice, bob, charlie, david}; EXPECT_CALL(view(), Show(Eq(GURL(kExampleCom)), IsOriginSecure(true), - testing::ElementsAre(charlie, alice, bob, david))); + testing::ElementsAre(charlie, alice, bob, david), + /*trigger_submission=*/false)); touch_to_fill_controller().Show(credentials, driver().AsWeakPtr(), - /*trigger_submission=*/false); + /*ready_for_submission=*/false); } TEST_F(TouchToFillControllerTest, Dismiss) { @@ -427,9 +438,10 @@ MakeUiCredential({.username = "alice", .password = "p4ssw0rd"})}; EXPECT_CALL(view(), Show(Eq(GURL(kExampleCom)), IsOriginSecure(true), - ElementsAreArray(credentials))); + ElementsAreArray(credentials), + /*trigger_submission=*/false)); touch_to_fill_controller().Show(credentials, driver().AsWeakPtr(), - /*trigger_submission=*/false); + /*ready_for_submission=*/false); EXPECT_CALL(driver(), TouchToFillClosed(ShowVirtualKeyboard(true))); touch_to_fill_controller().OnDismiss(); @@ -449,9 +461,10 @@ MakeUiCredential({.username = "alice", .password = "p4ssw0rd"})}; EXPECT_CALL(view(), Show(Eq(GURL(kExampleCom)), IsOriginSecure(true), - ElementsAreArray(credentials))); + ElementsAreArray(credentials), + /*trigger_submission=*/false)); touch_to_fill_controller().Show(credentials, driver().AsWeakPtr(), - /*trigger_submission=*/false); + /*ready_for_submission=*/false); EXPECT_CALL(*authenticator(), CanAuthenticate(BiometricAuthRequester::kTouchToFill))
diff --git a/chrome/browser/touch_to_fill/touch_to_fill_view.h b/chrome/browser/touch_to_fill/touch_to_fill_view.h index a9cb232..fd2256e2 100644 --- a/chrome/browser/touch_to_fill/touch_to_fill_view.h +++ b/chrome/browser/touch_to_fill/touch_to_fill_view.h
@@ -28,12 +28,14 @@ // Instructs Touch To Fill to show the provided |credentials| to the user. // |formatted_url| contains a human friendly version of the current origin. // |is_origin_secure| indicates whether the current frame origin is secure. - // After user interaction either OnCredentialSelected() or OnDismiss() gets - // invoked. + // |trigger_submission| indicates whether Touch To Fill will submit a form + // after filling. After user interaction either OnCredentialSelected() or + // OnDismiss() gets invoked. virtual void Show( const GURL& url, IsOriginSecure is_origin_secure, - base::span<const password_manager::UiCredential> credentials) = 0; + base::span<const password_manager::UiCredential> credentials, + bool trigger_submission) = 0; // Invoked in case the user chooses an entry from the credential list // presented to them.
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index a894ddd74..ae150c4a 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -5452,6 +5452,8 @@ "side_search/side_search_utils.h", "views/side_search/side_search_browser_controller.cc", "views/side_search/side_search_browser_controller.h", + "views/side_search/side_search_icon_view.cc", + "views/side_search/side_search_icon_view.h", ] deps += [
diff --git a/chrome/browser/ui/android/autofill/save_card_controller_metrics_android.cc b/chrome/browser/ui/android/autofill/save_card_controller_metrics_android.cc index 68f44ea..fe0f3494 100644 --- a/chrome/browser/ui/android/autofill/save_card_controller_metrics_android.cc +++ b/chrome/browser/ui/android/autofill/save_card_controller_metrics_android.cc
@@ -49,4 +49,24 @@ } } +void LogAutofillCreditCardMessageDialogPromptMetrics( + MessageDialogPromptMetrics metric, + AutofillClient::SaveCreditCardOptions options, + bool is_link_clicked) { + std::string histogram = base::StrCat({kPrefix, ".DialogPrompt"}); + if (options.should_request_expiration_date_from_user) { + histogram = base::StrCat({histogram, ".RequestingExpirationDate"}); + } else if (options.should_request_name_from_user) { + histogram = base::StrCat({histogram, ".RequestingCardholderName"}); + } else { + histogram = base::StrCat({histogram, ".ConfirmInfo"}); + } + + base::UmaHistogramEnumeration(histogram, metric); + if (is_link_clicked) { + base::UmaHistogramEnumeration(base::StrCat({histogram, ".DidClickLinks"}), + metric); + } +} + } // namespace autofill
diff --git a/chrome/browser/ui/android/autofill/save_card_controller_metrics_android.h b/chrome/browser/ui/android/autofill/save_card_controller_metrics_android.h index 02e4a68e..4c53396d7 100644 --- a/chrome/browser/ui/android/autofill/save_card_controller_metrics_android.h +++ b/chrome/browser/ui/android/autofill/save_card_controller_metrics_android.h
@@ -17,11 +17,23 @@ kMaxValue = kIgnored }; +enum class MessageDialogPromptMetrics { + kAccepted = 0, + kDenied = 1, + kIgnored = 2, + kMaxValue = kIgnored +}; + void LogAutofillCreditCardMessageMetrics( MessageMetrics metric, bool is_uploading, AutofillClient::SaveCreditCardOptions options); +void LogAutofillCreditCardMessageDialogPromptMetrics( + MessageDialogPromptMetrics metric, + AutofillClient::SaveCreditCardOptions options, + bool is_link_clicked); + } // namespace autofill #endif // CHROME_BROWSER_UI_ANDROID_AUTOFILL_SAVE_CARD_CONTROLLER_METRICS_ANDROID_H_
diff --git a/chrome/browser/ui/android/autofill/save_card_message_controller_android.cc b/chrome/browser/ui/android/autofill/save_card_message_controller_android.cc index d4fcdadb..e521f8256 100644 --- a/chrome/browser/ui/android/autofill/save_card_message_controller_android.cc +++ b/chrome/browser/ui/android/autofill/save_card_message_controller_android.cc
@@ -11,6 +11,7 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/android/autofill/save_card_controller_metrics_android.h" #include "components/autofill/core/browser/data_model/credit_card.h" +#include "components/autofill/core/browser/metrics/autofill_metrics.h" #include "components/autofill/core/browser/payments/autofill_save_card_ui_utils_mobile.h" #include "components/autofill/core/common/autofill_prefs.h" #include "components/grit/components_scaled_resources.h" @@ -162,10 +163,13 @@ if (is_upload_ && !request_more_info_) { // If we already know all the info, confirm save card to show other info // such as legal terms, and then run callback after user confirms. + is_dialog_shown_ = true; ConfirmSaveCard(); } else if (options_.should_request_name_from_user) { + is_dialog_shown_ = true; FixName(inferred_name_); } else if (options_.should_request_expiration_date_from_user) { + is_dialog_shown_ = true; FixDate(); } else { OnPromptCompleted(AutofillClient::SaveCardOfferUserDecision::kAccepted, {}); @@ -232,6 +236,7 @@ JNIEnv* env, const base::android::JavaParamRef<jstring>& url) { reprompt_required_ = true; + is_link_clicked_ = true; // Temporarily dismiss the dialog and then re-prompt when user returns to // the page. save_card_message_confirm_controller_->DismissDialog(); @@ -253,19 +258,27 @@ AutofillClient::SaveCardOfferUserDecision user_decision, AutofillClient::UserProvidedCardDetails user_provided_details) { MessageMetrics message_state; + MessageDialogPromptMetrics dialog_state; switch (user_decision) { case AutofillClient::SaveCardOfferUserDecision::kAccepted: message_state = MessageMetrics::kAccepted; + dialog_state = MessageDialogPromptMetrics::kAccepted; break; case AutofillClient::SaveCardOfferUserDecision::kDeclined: message_state = MessageMetrics::kDenied; + dialog_state = MessageDialogPromptMetrics::kDenied; break; case AutofillClient::SaveCardOfferUserDecision::kIgnored: message_state = MessageMetrics::kIgnored; + dialog_state = MessageDialogPromptMetrics::kIgnored; break; } LogAutofillCreditCardMessageMetrics(message_state, is_upload_, options_); if (is_upload_) { + if (is_dialog_shown_) { + LogAutofillCreditCardMessageDialogPromptMetrics(dialog_state, options_, + is_link_clicked_); + } std::move(upload_save_card_prompt_callback_) .Run(user_decision, user_provided_details); } else {
diff --git a/chrome/browser/ui/android/autofill/save_card_message_controller_android.h b/chrome/browser/ui/android/autofill/save_card_message_controller_android.h index 1a9b05ea..c0bfa42 100644 --- a/chrome/browser/ui/android/autofill/save_card_message_controller_android.h +++ b/chrome/browser/ui/android/autofill/save_card_message_controller_android.h
@@ -128,6 +128,13 @@ // Whether we should re-show the dialog to users when users return to the tab. bool reprompt_required_ = false; + // True if user clicked links. + bool is_link_clicked_ = false; + + // True if dialog is shown. The dialog is triggered when primary action button + // of message is clicked and the card should be uploaded. + bool is_dialog_shown_ = false; + bool is_name_confirmed_for_testing_ = false; bool is_date_confirmed_for_testing_ = false; bool is_save_card_confirmed_for_testing_ = false;
diff --git a/chrome/browser/ui/android/autofill/save_card_message_controller_android_unittest.cc b/chrome/browser/ui/android/autofill/save_card_message_controller_android_unittest.cc index 5c24282..bd3717a 100644 --- a/chrome/browser/ui/android/autofill/save_card_message_controller_android_unittest.cc +++ b/chrome/browser/ui/android/autofill/save_card_message_controller_android_unittest.cc
@@ -25,6 +25,7 @@ constexpr char16_t kDefaultUrl[] = u"http://example.com"; static const char kServerPrefix[] = "Autofill.CreditCardMessage.Server"; static const char kLocalPrefix[] = "Autofill.CreditCardMessage.Local"; +static const char kDialogPrefix[] = "Autofill.CreditCardMessage.DialogPrompt"; } // namespace class SaveCardMessageControllerAndroidTest @@ -389,6 +390,7 @@ mock_upload_callback_receiver, Run(AutofillClient::SaveCardOfferUserDecision::kAccepted, testing::_)); // Triggering dialog will dismiss the message. + TriggerPrimaryButtonClick(); DismissMessage(messages::DismissReason::PRIMARY_ACTION); OnNameConfirmed(); EXPECT_EQ(nullptr, GetMessageWrapper()); @@ -401,6 +403,13 @@ MessageMetrics::kAccepted, 1); histogram_tester.ExpectBucketCount(kServerPrefix, MessageMetrics::kAccepted, 1); + histogram_tester.ExpectBucketCount( + base::StrCat({kDialogPrefix, ".RequestingCardholderName"}), + MessageDialogPromptMetrics::kAccepted, 1); + histogram_tester.ExpectBucketCount( + base::StrCat( + {kDialogPrefix, ".RequestingCardholderName", ".DidClickLinks"}), + MessageDialogPromptMetrics::kAccepted, 0); } TEST_F(SaveCardMessageControllerAndroidTest, DismissOnConfirmDateAcceptUpload) { @@ -414,6 +423,7 @@ EXPECT_CALL( mock_upload_callback_receiver, Run(AutofillClient::SaveCardOfferUserDecision::kAccepted, testing::_)); + TriggerPrimaryButtonClick(); // Triggering dialog will dismiss the message. DismissMessage(messages::DismissReason::PRIMARY_ACTION); OnDateConfirmed(); @@ -427,6 +437,13 @@ MessageMetrics::kAccepted, 1); histogram_tester.ExpectBucketCount(kServerPrefix, MessageMetrics::kAccepted, 1); + histogram_tester.ExpectBucketCount( + base::StrCat({kDialogPrefix, ".RequestingExpirationDate"}), + MessageDialogPromptMetrics::kAccepted, 1); + histogram_tester.ExpectBucketCount( + base::StrCat( + {kDialogPrefix, ".RequestingExpirationDate", ".DidClickLinks"}), + MessageDialogPromptMetrics::kAccepted, 0); } TEST_F(SaveCardMessageControllerAndroidTest, @@ -466,12 +483,19 @@ EXPECT_CALL( mock_upload_callback_receiver, Run(AutofillClient::SaveCardOfferUserDecision::kDeclined, testing::_)); + TriggerPrimaryButtonClick(); // Triggering dialog will dismiss the message. DismissMessage(messages::DismissReason::PRIMARY_ACTION); OnConfirmationDialogDismissed(); EXPECT_EQ(nullptr, GetMessageWrapper()); histogram_tester.ExpectBucketCount(kServerPrefix, MessageMetrics::kShown, 1); histogram_tester.ExpectBucketCount(kServerPrefix, MessageMetrics::kDenied, 1); + histogram_tester.ExpectBucketCount( + base::StrCat({kDialogPrefix, ".ConfirmInfo"}), + MessageDialogPromptMetrics::kDenied, 1); + histogram_tester.ExpectBucketCount( + base::StrCat({kDialogPrefix, ".ConfirmInfo", ".DidClickLinks"}), + MessageDialogPromptMetrics::kDenied, 0); } // -- Others -- @@ -505,6 +529,13 @@ MessageMetrics::kAccepted, 1); histogram_tester.ExpectBucketCount(kServerPrefix, MessageMetrics::kAccepted, 1); + histogram_tester.ExpectBucketCount( + base::StrCat({kDialogPrefix, ".RequestingExpirationDate"}), + MessageDialogPromptMetrics::kAccepted, 1); + histogram_tester.ExpectBucketCount( + base::StrCat( + {kDialogPrefix, ".RequestingExpirationDate", ".DidClickLinks"}), + MessageDialogPromptMetrics::kAccepted, 1); } TEST_F(SaveCardMessageControllerAndroidTest, @@ -528,6 +559,9 @@ EnqueueAnotherMessage(mock_upload_callback_receiver2.Get(), {}); histogram_tester.ExpectBucketCount(kServerPrefix, MessageMetrics::kIgnored, 1); + histogram_tester.ExpectBucketCount( + base::StrCat({kDialogPrefix, ".RequestingExpirationDate"}), + MessageDialogPromptMetrics::kIgnored, 0); DismissMessage(); } @@ -541,6 +575,9 @@ DismissMessage(messages::DismissReason::TIMER); histogram_tester.ExpectBucketCount(kServerPrefix, MessageMetrics::kIgnored, 1); + histogram_tester.ExpectBucketCount( + base::StrCat({kDialogPrefix, ".RequestingExpirationDate"}), + MessageDialogPromptMetrics::kIgnored, 0); } } // namespace autofill
diff --git a/chrome/browser/ui/android/omnibox/BUILD.gn b/chrome/browser/ui/android/omnibox/BUILD.gn index bb7d354..fb7c9bf1 100644 --- a/chrome/browser/ui/android/omnibox/BUILD.gn +++ b/chrome/browser/ui/android/omnibox/BUILD.gn
@@ -342,7 +342,7 @@ sources = [ "$proto_path/partner_location_descriptor.proto" ] } -java_library("junit") { +android_library("junit") { # Skip platform checks since Robolectric depends on requires_android targets. bypass_platform_checks = true testonly = true @@ -398,6 +398,7 @@ "//chrome/test/android:chrome_java_test_support", "//components/browser_ui/site_settings/android:java", "//components/browser_ui/styles/android:java", + "//components/browser_ui/styles/android:java_resources", "//components/browser_ui/widget/android:java", "//components/content_settings/android:content_settings_enums_java", "//components/embedder_support/android:util_java", @@ -425,5 +426,5 @@ "//url:gurl_junit_test_support", ] annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ] - resources_package = "org.chromium.chrome.browser.omnibox" + resources_package = "org.chromium.chrome.browser.omnibox.test" }
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediatorTest.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediatorTest.java index 0748d771..223dde1 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediatorTest.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediatorTest.java
@@ -70,6 +70,7 @@ import org.chromium.chrome.browser.omnibox.geo.GeolocationHeader; import org.chromium.chrome.browser.omnibox.status.StatusCoordinator; import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteCoordinator; +import org.chromium.chrome.browser.omnibox.test.R; import org.chromium.chrome.browser.omnibox.voice.AssistantVoiceSearchService; import org.chromium.chrome.browser.omnibox.voice.VoiceRecognitionHandler; import org.chromium.chrome.browser.prefetch.settings.PreloadPagesSettingsBridge;
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd index 81e77f4..29b0b4f 100644 --- a/chrome/browser/ui/android/strings/android_chrome_strings.grd +++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -300,6 +300,9 @@ <message name="IDS_SIGN_OUT_AND_TURN_OFF_SYNC" desc="The text for a preferences row that for signs out the user and turns off sync."> Sign out and turn off sync </message> + <message name="IDS_TURN_OFF_SYNC" desc="The text for a preferences row that turns off sync without signing the user out."> + Turn off sync + </message> <message name="IDS_SIGN_OUT" desc="The text for a preference row that signs out the user."> Sign out </message> @@ -5145,6 +5148,10 @@ Reaction deleted </message> + <message name="IDS_LIGHTWEIGHT_REACTIONS_REACTION_DUPLICATED_ANNOUNCEMENT" is_accessibility_with_no_ui="true" desc="The accessibility text to read when a reaction is duplicated."> + Reaction duplicated + </message> + <message name="IDS_LIGHTWEIGHT_REACTIONS_TOOLBAR_ANNOUNCEMENT" is_accessibility_with_no_ui="true" desc="The accessibility text to read when the lightweight reactions toolbar is selected. The user can then select a reaction from the toolbar to place on the screen."> Choose an emotion </message> @@ -5153,6 +5160,10 @@ Reaction changed </message> + <message name="IDS_LIGHTWEIGHT_REACTIONS_REACTION_ADDED_ANNOUNCEMENT" is_accessibility_with_no_ui="true" desc="The accessibility text to read when a reaction is added to the scene."> + Reaction added + </message> + <message name="IDS_LIGHTWEIGHT_REACTIONS_RESIZE_AND_ROTATE_BUTTON" is_accessibility_with_no_ui="true" desc="The accessibility text to read when the resize and rotate editing tool is selected. The user can then resize and rotate the reaction on the scene."> Resize and rotate </message>
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_TURN_OFF_SYNC.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_TURN_OFF_SYNC.png.sha1 new file mode 100644 index 0000000..ade69ca --- /dev/null +++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_TURN_OFF_SYNC.png.sha1
@@ -0,0 +1 @@ +ec4104c66cdce7a6cb4fb8542b1ca909b2b5ca52 \ No newline at end of file
diff --git a/chrome/browser/ui/android/webid/internal/java/res/layout/account_selection_continue_button.xml b/chrome/browser/ui/android/webid/internal/java/res/layout/account_selection_continue_button.xml index 3c88471..8483a65 100644 --- a/chrome/browser/ui/android/webid/internal/java/res/layout/account_selection_continue_button.xml +++ b/chrome/browser/ui/android/webid/internal/java/res/layout/account_selection_continue_button.xml
@@ -5,7 +5,6 @@ <org.chromium.ui.widget.ButtonCompat xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/account_selection_continue_btn" android:descendantFocusability="blocksDescendants" android:layout_width="match_parent" android:layout_height="wrap_content"
diff --git a/chrome/browser/ui/android/webid/internal/java/res/layout/account_selection_data_sharing_consent_item.xml b/chrome/browser/ui/android/webid/internal/java/res/layout/account_selection_data_sharing_consent_item.xml index 77602293..36852cc1 100644 --- a/chrome/browser/ui/android/webid/internal/java/res/layout/account_selection_data_sharing_consent_item.xml +++ b/chrome/browser/ui/android/webid/internal/java/res/layout/account_selection_data_sharing_consent_item.xml
@@ -6,7 +6,6 @@ <org.chromium.ui.widget.TextViewWithClickableSpans xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" - android:id="@+id/user_data_sharing_consent" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_horizontal"
diff --git a/chrome/browser/ui/android/webid/internal/java/res/layout/account_selection_sheet.xml b/chrome/browser/ui/android/webid/internal/java/res/layout/account_selection_sheet.xml index 30471a2..e4226228 100644 --- a/chrome/browser/ui/android/webid/internal/java/res/layout/account_selection_sheet.xml +++ b/chrome/browser/ui/android/webid/internal/java/res/layout/account_selection_sheet.xml
@@ -9,17 +9,26 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_height="match_parent" android:layout_width="match_parent" + android:paddingBottom="8dp" android:orientation="vertical"> <include layout="@layout/account_selection_header_item" - android:id="@+id/header_view" /> + android:id="@+id/header_view_item" /> <androidx.recyclerview.widget.RecyclerView android:id="@+id/sheet_item_list" android:layout_width="match_parent" - android:layout_height="0dp" - android:layout_weight="1" + android:layout_height="wrap_content" android:clipToPadding="false" - android:paddingBottom="8dp" android:divider="@null" tools:listitem="@layout/account_selection_account_item"/> + + <include layout="@layout/account_selection_continue_button" + android:id="@+id/account_selection_continue_btn" + android:visibility="gone"/> + <include layout="@layout/auto_sign_in_cancel_button" + android:id="@+id/auto_sign_in_cancel_btn" + android:visibility="gone"/> + <include layout="@layout/account_selection_data_sharing_consent_item" + android:id="@+id/user_data_sharing_consent" + android:visibility="gone"/> </LinearLayout>
diff --git a/chrome/browser/ui/android/webid/internal/java/res/layout/auto_sign_in_cancel_button.xml b/chrome/browser/ui/android/webid/internal/java/res/layout/auto_sign_in_cancel_button.xml index e7ff405..3e3d405 100644 --- a/chrome/browser/ui/android/webid/internal/java/res/layout/auto_sign_in_cancel_button.xml +++ b/chrome/browser/ui/android/webid/internal/java/res/layout/auto_sign_in_cancel_button.xml
@@ -5,7 +5,6 @@ <org.chromium.ui.widget.ButtonCompat xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/auto_sign_in_cancel_btn" android:descendantFocusability="blocksDescendants" android:layout_width="match_parent" android:layout_height="wrap_content"
diff --git a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionBottomSheetContent.java b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionBottomSheetContent.java index 54e37b5..db5a4ee8 100644 --- a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionBottomSheetContent.java +++ b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionBottomSheetContent.java
@@ -5,6 +5,7 @@ package org.chromium.chrome.browser.ui.android.webid; import android.view.View; +import android.view.accessibility.AccessibilityEvent; import androidx.annotation.Nullable; @@ -42,6 +43,15 @@ mContentView.announceForAccessibility(headerText); } + public void focusContinueButtonForAccessibility() { + // {@link mContentView} is null for some tests. + if (mContentView == null) return; + + View continueButton = mContentView.findViewById(R.id.account_selection_continue_btn); + continueButton.requestFocus(); + continueButton.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); + } + @Override public void destroy() {}
diff --git a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionControllerTest.java b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionControllerTest.java index 777e8a2a..dd460e9a 100644 --- a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionControllerTest.java +++ b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionControllerTest.java
@@ -52,7 +52,7 @@ import org.chromium.chrome.browser.ui.android.webid.AccountSelectionProperties.ContinueButtonProperties; import org.chromium.chrome.browser.ui.android.webid.AccountSelectionProperties.DataSharingConsentProperties; import org.chromium.chrome.browser.ui.android.webid.AccountSelectionProperties.HeaderProperties.HeaderType; -import org.chromium.chrome.browser.ui.android.webid.AccountSelectionProperties.ItemType; +import org.chromium.chrome.browser.ui.android.webid.AccountSelectionProperties.ItemProperties; import org.chromium.chrome.browser.ui.android.webid.data.Account; import org.chromium.chrome.browser.ui.android.webid.data.ClientIdMetadata; import org.chromium.chrome.browser.ui.android.webid.data.IdentityProviderMetadata; @@ -63,7 +63,9 @@ import org.chromium.components.url_formatter.UrlFormatterJni; import org.chromium.ui.modelutil.MVCListAdapter.ListItem; import org.chromium.ui.modelutil.MVCListAdapter.ModelList; +import org.chromium.ui.modelutil.PropertyKey; import org.chromium.ui.modelutil.PropertyModel; +import org.chromium.ui.modelutil.PropertyModel.WritableObjectPropertyKey; import org.chromium.url.GURL; import org.chromium.url.JUnitTestGURLs; import org.chromium.url.ShadowGURL; @@ -122,9 +124,9 @@ private AccountSelectionBottomSheetContent mBottomSheetContent; private AccountSelectionMediator mMediator; - private final PropertyModel mHeaderModel = - new PropertyModel.Builder(AccountSelectionProperties.HeaderProperties.ALL_KEYS).build(); - private final ModelList mSheetItems = new ModelList(); + private final PropertyModel mModel = + new PropertyModel.Builder(AccountSelectionProperties.ItemProperties.ALL_KEYS).build(); + private final ModelList mSheetAccountItems = new ModelList(); public AccountSelectionControllerTest() { MockitoAnnotations.initMocks(this); @@ -145,7 +147,7 @@ when(mUrlFormatterJniMock.fixupUrl(anyString())).then(inv -> fixupUrl(inv.getArgument(0))); mBottomSheetContent = new AccountSelectionBottomSheetContent(null, null); - mMediator = new AccountSelectionMediator(mMockDelegate, mHeaderModel, mSheetItems, + mMediator = new AccountSelectionMediator(mMockDelegate, mModel, mSheetAccountItems, mMockBottomSheetController, mBottomSheetContent, mMockImageFetcher, DESIRED_AVATAR_SIZE); } @@ -155,12 +157,13 @@ mMediator.showAccounts(TEST_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_1, Arrays.asList(ANA), IDP_METADATA, CLIENT_ID_METADATA, false /* isAutoSignIn */); - assertEquals(HeaderType.SIGN_IN, mHeaderModel.get(TYPE)); + PropertyModel headerModel = mModel.get(ItemProperties.HEADER); + assertEquals(HeaderType.SIGN_IN, headerModel.get(TYPE)); assertEquals(formatForSecurityDisplay(TEST_ETLD_PLUS_ONE), - mHeaderModel.get(FORMATTED_RP_ETLD_PLUS_ONE)); + headerModel.get(FORMATTED_RP_ETLD_PLUS_ONE)); assertEquals(formatForSecurityDisplay(TEST_ETLD_PLUS_ONE_1), - mHeaderModel.get(FORMATTED_IDP_ETLD_PLUS_ONE)); - assertNotNull(mHeaderModel.get(IDP_BRAND_ICON)); + headerModel.get(FORMATTED_IDP_ETLD_PLUS_ONE)); + assertNotNull(headerModel.get(IDP_BRAND_ICON)); } @Test @@ -168,23 +171,25 @@ mMediator.showAccounts(TEST_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_1, Arrays.asList(NEW_USER), IDP_METADATA, CLIENT_ID_METADATA, false /* isAutoSignIn */); - assertEquals(HeaderType.SIGN_IN, mHeaderModel.get(TYPE)); + PropertyModel headerModel = mModel.get(ItemProperties.HEADER); + assertEquals(HeaderType.SIGN_IN, headerModel.get(TYPE)); } @Test public void testShowAccountAutoSignInHeader() { mMediator.showAccounts(TEST_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_1, Arrays.asList(ANA), IDP_METADATA, CLIENT_ID_METADATA, true /* isAutoSignIn */); - assertEquals(HeaderType.AUTO_SIGN_IN, mHeaderModel.get(TYPE)); + PropertyModel headerModel = mModel.get(ItemProperties.HEADER); + assertEquals(HeaderType.AUTO_SIGN_IN, headerModel.get(TYPE)); } @Test public void testShowAccountsSetsAccountListAndRequestsAvatar() { mMediator.showAccounts(TEST_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_1, Arrays.asList(ANA, BOB), IDP_METADATA, CLIENT_ID_METADATA, false); - assertEquals("Incorrect item sheet count", 2, mSheetItems.size()); - assertNull(mSheetItems.get(0).model.get(AVATAR)); - assertNull(mSheetItems.get(1).model.get(AVATAR)); + assertEquals("Incorrect item sheet count", 2, mSheetAccountItems.size()); + assertNull(mSheetAccountItems.get(0).model.get(AVATAR)); + assertNull(mSheetAccountItems.get(1).model.get(AVATAR)); // Both accounts have the same profile pic URL ImageFetcher.Params expected_params = ImageFetcher.Params.create(TEST_PROFILE_PIC.getSpec(), @@ -198,10 +203,9 @@ public void testFetchAvatarUpdatesModel() { mMediator.showAccounts(TEST_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_1, Collections.singletonList(CARL), IDP_METADATA, CLIENT_ID_METADATA, false); - assertEquals("Incorrect item sheet count", 2, mSheetItems.size()); - assertEquals("Incorrect type", ItemType.ACCOUNT, mSheetItems.get(0).type); - assertEquals("Incorrect account", CARL, mSheetItems.get(0).model.get(ACCOUNT)); - assertNull(mSheetItems.get(0).model.get(AVATAR)); + assertEquals("Incorrect item sheet count", 1, mSheetAccountItems.size()); + assertEquals("Incorrect account", CARL, mSheetAccountItems.get(0).model.get(ACCOUNT)); + assertNull(mSheetAccountItems.get(0).model.get(AVATAR)); ImageFetcher.Params expected_params = ImageFetcher.Params.create(TEST_PROFILE_PIC.getSpec(), ImageFetcher.WEB_ID_ACCOUNT_SELECTION_UMA_CLIENT_NAME, DESIRED_AVATAR_SIZE, @@ -214,7 +218,7 @@ DESIRED_AVATAR_SIZE, DESIRED_AVATAR_SIZE, Bitmap.Config.ARGB_8888); callback.getValue().onResult(bitmap); - Avatar avatarData = mSheetItems.get(0).model.get(AVATAR); + Avatar avatarData = mSheetAccountItems.get(0).model.get(AVATAR); assertEquals("incorrect avatar bitmap", bitmap, avatarData.mAvatar); assertEquals("incorrect avatar name", CARL.getName(), avatarData.mName); assertEquals("incorrect avatar size", DESIRED_AVATAR_SIZE, avatarData.mAvatarSize); @@ -224,27 +228,24 @@ public void testShowAccountsFormatPslOrigins() { mMediator.showAccounts(TEST_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_1, Arrays.asList(ANA, BOB), IDP_METADATA, CLIENT_ID_METADATA, false); - assertEquals("Incorrect item sheet count", 2, mSheetItems.size()); // Header + two Accounts - assertEquals("Incorrect item type", ItemType.ACCOUNT, mSheetItems.get(0).type); - assertEquals("Incorrect item type", ItemType.ACCOUNT, mSheetItems.get(1).type); + assertEquals(3, countAllItems()); // Header + two Accounts + assertEquals("Incorrect item sheet count", 2, mSheetAccountItems.size()); } @Test public void testClearsAccountListWhenShowingAgain() { mMediator.showAccounts(TEST_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_1, Collections.singletonList(ANA), IDP_METADATA, CLIENT_ID_METADATA, false); - assertEquals("Incorrect item sheet count", 2, - mSheetItems.size()); // Header + Account + Continue Button - assertEquals("Incorrect item type", ItemType.ACCOUNT, mSheetItems.get(0).type); - assertEquals("Incorrect account", ANA, mSheetItems.get(0).model.get(ACCOUNT)); + assertEquals(3, countAllItems()); // Header + Account + Continue Button + assertEquals(1, mSheetAccountItems.size()); + assertEquals("Incorrect account", ANA, mSheetAccountItems.get(0).model.get(ACCOUNT)); // Showing the sheet a second time should replace all changed accounts. mMediator.showAccounts(TEST_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_1, Collections.singletonList(BOB), IDP_METADATA, CLIENT_ID_METADATA, false); - assertEquals("Incorrect item sheet count", 2, - mSheetItems.size()); // Header + Account + Continue Button - assertEquals("Incorrect item type", ItemType.ACCOUNT, mSheetItems.get(0).type); - assertEquals("Incorrect account", BOB, mSheetItems.get(0).model.get(ACCOUNT)); + assertEquals(3, countAllItems()); // Header + Account + Continue Button + assertEquals(1, mSheetAccountItems.size()); + assertEquals("Incorrect account", BOB, mSheetAccountItems.get(0).model.get(ACCOUNT)); } @Test @@ -263,9 +264,12 @@ mMediator.showAccounts(TEST_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_1, Arrays.asList(ANA), IDP_METADATA, CLIENT_ID_METADATA, false); assertEquals("Incorrectly hidden", true, mMediator.isVisible()); - assertNotNull(mSheetItems.get(1).model.get(ContinueButtonProperties.ON_CLICK_LISTENER)); + assertNotNull(mModel.get(ItemProperties.CONTINUE_BUTTON) + .get(ContinueButtonProperties.ON_CLICK_LISTENER)); - mSheetItems.get(1).model.get(ContinueButtonProperties.ON_CLICK_LISTENER).onResult(ANA); + mModel.get(ItemProperties.CONTINUE_BUTTON) + .get(ContinueButtonProperties.ON_CLICK_LISTENER) + .onResult(ANA); verify(mMockDelegate).onAccountSelected(ANA); assertEquals(true, mMediator.isVisible()); mMediator.hideBottomSheet(); @@ -278,9 +282,9 @@ mMediator.showAccounts(TEST_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_1, Arrays.asList(ANA, CARL), IDP_METADATA, CLIENT_ID_METADATA, false); assertEquals("Incorrectly hidden", true, mMediator.isVisible()); - assertNotNull(mSheetItems.get(0).model.get(AccountProperties.ON_CLICK_LISTENER)); + assertNotNull(mSheetAccountItems.get(0).model.get(AccountProperties.ON_CLICK_LISTENER)); - mSheetItems.get(0).model.get(AccountProperties.ON_CLICK_LISTENER).onResult(CARL); + mSheetAccountItems.get(0).model.get(AccountProperties.ON_CLICK_LISTENER).onResult(CARL); verify(mMockDelegate).onAccountSelected(CARL); assertEquals(true, mMediator.isVisible()); mMediator.hideBottomSheet(); @@ -327,8 +331,8 @@ mMediator.onAccountSelected(NEW_USER); assertEquals(true, mMediator.isVisible()); - assertTrue(containsListItemOfType(mSheetItems, ItemType.DATA_SHARING_CONSENT)); - assertEquals(1, countListItemsOfType(mSheetItems, ItemType.ACCOUNT)); + assertTrue(containsItemOfType(mModel, ItemProperties.DATA_SHARING_CONSENT)); + assertEquals(1, mSheetAccountItems.size()); verify(mMockDelegate, never()).onAccountSelected(NEW_USER); } @@ -342,8 +346,8 @@ pressBack(); assertTrue(mMediator.isVisible()); - assertFalse(containsListItemOfType(mSheetItems, ItemType.DATA_SHARING_CONSENT)); - assertEquals(2, countListItemsOfType(mSheetItems, ItemType.ACCOUNT)); + assertFalse(containsItemOfType(mModel, ItemProperties.DATA_SHARING_CONSENT)); + assertEquals(2, mSheetAccountItems.size()); pressBack(); assertFalse(mMediator.isVisible()); @@ -380,10 +384,12 @@ mMediator.showAccounts(TEST_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_1, Arrays.asList(ANA), IDP_METADATA, CLIENT_ID_METADATA, true); assertEquals("Incorrectly hidden", true, mMediator.isVisible()); - assertNotNull( - mSheetItems.get(1).model.get(AutoSignInCancelButtonProperties.ON_CLICK_LISTENER)); + assertNotNull(mModel.get(ItemProperties.AUTO_SIGN_IN_CANCEL_BUTTON) + .get(AutoSignInCancelButtonProperties.ON_CLICK_LISTENER)); - mSheetItems.get(1).model.get(AutoSignInCancelButtonProperties.ON_CLICK_LISTENER).run(); + mModel.get(ItemProperties.AUTO_SIGN_IN_CANCEL_BUTTON) + .get(AutoSignInCancelButtonProperties.ON_CLICK_LISTENER) + .run(); verify(mMockDelegate).onAutoSignInCancelled(); assertEquals("Incorrectly visible", false, mMediator.isVisible()); } @@ -406,18 +412,18 @@ mMediator.showAccounts(TEST_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_2, Arrays.asList(NEW_USER), IDP_METADATA, CLIENT_ID_METADATA, false); // For new user we expect header + account + consent text + continue btn - assertEquals("Incorrect item sheet count", 3, mSheetItems.size()); - assertEquals("Incorrect item type", ItemType.ACCOUNT, mSheetItems.get(0).type); - assertEquals( - "Incorrect consent type", ItemType.DATA_SHARING_CONSENT, mSheetItems.get(2).type); + assertEquals(4, countAllItems()); + assertEquals("Incorrect item sheet count", 1, mSheetAccountItems.size()); + assertTrue(containsItemOfType(mModel, ItemProperties.DATA_SHARING_CONSENT)); DataSharingConsentProperties.Properties dataSharingProperties = - mSheetItems.get(2).model.get(DataSharingConsentProperties.PROPERTIES); + mModel.get(ItemProperties.DATA_SHARING_CONSENT) + .get(DataSharingConsentProperties.PROPERTIES); assertEquals("Incorrect privacy policy URL", TEST_URL_PRIVACY_POLICY.getSpec(), dataSharingProperties.mPrivacyPolicyUrl); assertEquals("Incorrect terms of service URL", TEST_URL_TERMS_OF_SERVICE.getSpec(), dataSharingProperties.mTermsOfServiceUrl); - assertEquals("Incorrect continue type", ItemType.CONTINUE_BUTTON, mSheetItems.get(1).type); + assertTrue(containsItemOfType(mModel, ItemProperties.CONTINUE_BUTTON)); assertEquals("Incorrect provider ETLD+1", formatForSecurityDisplay(TEST_ETLD_PLUS_ONE_2), dataSharingProperties.mFormattedIdpEtldPlusOne); } @@ -429,9 +435,8 @@ IDP_METADATA, CLIENT_ID_METADATA, false); mMediator.showVerifySheet(ANA); - assertEquals(1, mSheetItems.size()); - assertEquals(HeaderType.VERIFY, mHeaderModel.get(TYPE)); - assertEquals(ItemType.ACCOUNT, mSheetItems.get(0).type); + assertEquals(1, mSheetAccountItems.size()); + assertEquals(HeaderType.VERIFY, mModel.get(ItemProperties.HEADER).get(TYPE)); } private void pressBack() { @@ -440,8 +445,18 @@ mMediator.onDismissed(BottomSheetController.StateChangeReason.BACK_PRESS); } - private static boolean containsListItemOfType(ModelList list, int searchType) { - return countListItemsOfType(list, searchType) >= 1; + private int countAllItems() { + int count = 0; + for (PropertyKey key : mModel.getAllProperties()) { + if (containsItemOfType(mModel, key)) { + count += 1; + } + } + return count + mSheetAccountItems.size(); + } + + private static boolean containsItemOfType(PropertyModel model, PropertyKey key) { + return model.get((WritableObjectPropertyKey<PropertyModel>) key) != null; } private static int countListItemsOfType(ModelList list, int searchType) {
diff --git a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionCoordinator.java b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionCoordinator.java index b06e043b..0a82870 100644 --- a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionCoordinator.java +++ b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionCoordinator.java
@@ -50,12 +50,12 @@ mBottomSheetController = sheetController; mContext = context; - PropertyModel headerModel = - new PropertyModel.Builder(AccountSelectionProperties.HeaderProperties.ALL_KEYS) + PropertyModel model = + new PropertyModel.Builder(AccountSelectionProperties.ItemProperties.ALL_KEYS) .build(); // Construct view and its related adaptor to be displayed in the bottom sheet. ModelList sheetItems = new ModelList(); - View contentView = setupContentView(context, headerModel, sheetItems); + View contentView = setupContentView(context, model, sheetItems); mSheetItemListView = contentView.findViewById(R.id.sheet_item_list); // Setup the bottom sheet content view. @@ -73,16 +73,16 @@ @Px int avatarSize = context.getResources().getDimensionPixelSize( R.dimen.account_selection_account_avatar_size); - mMediator = new AccountSelectionMediator(delegate, headerModel, sheetItems, + mMediator = new AccountSelectionMediator(delegate, model, sheetItems, mBottomSheetController, mBottomSheetContent, imageFetcher, avatarSize); } - static View setupContentView(Context context, PropertyModel headerModel, ModelList sheetItems) { + static View setupContentView(Context context, PropertyModel model, ModelList sheetItems) { View contentView = (LinearLayout) LayoutInflater.from(context).inflate( R.layout.account_selection_sheet, null); - PropertyModelChangeProcessor.create(headerModel, contentView.findViewById(R.id.header_view), - AccountSelectionViewBinder::bindHeaderView); + PropertyModelChangeProcessor.create( + model, contentView, AccountSelectionViewBinder::bindContentView); RecyclerView sheetItemListView = contentView.findViewById(R.id.sheet_item_list); sheetItemListView.setLayoutManager(new LinearLayoutManager( @@ -91,18 +91,9 @@ // Setup the recycler view to be updated as we update the sheet items. SimpleRecyclerViewAdapter adapter = new SimpleRecyclerViewAdapter(sheetItems); - adapter.registerType(AccountSelectionProperties.ItemType.ACCOUNT, + adapter.registerType(AccountSelectionProperties.ITEM_TYPE_ACCOUNT, AccountSelectionCoordinator::buildAccountView, AccountSelectionViewBinder::bindAccountView); - adapter.registerType(AccountSelectionProperties.ItemType.CONTINUE_BUTTON, - AccountSelectionCoordinator::buildContinueButtonView, - AccountSelectionViewBinder::bindContinueButtonView); - adapter.registerType(AccountSelectionProperties.ItemType.AUTO_SIGN_IN_CANCEL_BUTTON, - AccountSelectionCoordinator::buildAutoSignInCancelButtonView, - AccountSelectionViewBinder::bindAutoSignInCancelButtonView); - adapter.registerType(AccountSelectionProperties.ItemType.DATA_SHARING_CONSENT, - AccountSelectionCoordinator::buildDataSharingConsentView, - AccountSelectionViewBinder::bindDataSharingConsentView); sheetItemListView.setAdapter(adapter); return contentView;
diff --git a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionMediator.java b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionMediator.java index e3b585b..88f1462 100644 --- a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionMediator.java +++ b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionMediator.java
@@ -15,7 +15,7 @@ import org.chromium.chrome.browser.ui.android.webid.AccountSelectionProperties.DataSharingConsentProperties; import org.chromium.chrome.browser.ui.android.webid.AccountSelectionProperties.HeaderProperties; import org.chromium.chrome.browser.ui.android.webid.AccountSelectionProperties.HeaderProperties.HeaderType; -import org.chromium.chrome.browser.ui.android.webid.AccountSelectionProperties.ItemType; +import org.chromium.chrome.browser.ui.android.webid.AccountSelectionProperties.ItemProperties; import org.chromium.chrome.browser.ui.android.webid.data.Account; import org.chromium.chrome.browser.ui.android.webid.data.ClientIdMetadata; import org.chromium.chrome.browser.ui.android.webid.data.IdentityProviderMetadata; @@ -40,8 +40,8 @@ class AccountSelectionMediator { private boolean mVisible; private final AccountSelectionComponent.Delegate mDelegate; - private final PropertyModel mHeaderModel; - private final ModelList mSheetItems; + private final PropertyModel mModel; + private final ModelList mSheetAccountItems; private final ImageFetcher mImageFetcher; private final @Px int mDesiredAvatarSize; @@ -64,15 +64,15 @@ // The account that the user has selected. private Account mSelectedAccount; - AccountSelectionMediator(AccountSelectionComponent.Delegate delegate, PropertyModel headerModel, - ModelList sheetItems, BottomSheetController bottomSheetController, + AccountSelectionMediator(AccountSelectionComponent.Delegate delegate, PropertyModel model, + ModelList sheetAccountItems, BottomSheetController bottomSheetController, AccountSelectionBottomSheetContent bottomSheetContent, ImageFetcher imageFetcher, @Px int desiredAvatarSize) { assert delegate != null; mVisible = false; mDelegate = delegate; - mHeaderModel = headerModel; - mSheetItems = sheetItems; + mModel = model; + mSheetAccountItems = sheetAccountItems; mImageFetcher = imageFetcher; mDesiredAvatarSize = desiredAvatarSize; mBottomSheetController = bottomSheetController; @@ -105,8 +105,8 @@ return false; } - private void updateHeader(HeaderType headerType, String rpEtldPlusOne, String idpEtldPlusOne, - IdentityProviderMetadata idpMetadata) { + private PropertyModel createHeaderItem(HeaderType headerType, String rpEtldPlusOne, + String idpEtldPlusOne, IdentityProviderMetadata idpMetadata) { String formattedRpEtldPlusOne = UrlFormatter.formatUrlForSecurityDisplay( UrlFormatter.fixupUrl(rpEtldPlusOne), SchemeDisplay.OMIT_HTTP_AND_HTTPS); String formattedIdpEtldPlusOne = UrlFormatter.formatUrlForSecurityDisplay( @@ -116,48 +116,29 @@ onDismissed(BottomSheetController.StateChangeReason.NONE); }; - // We remove the HTTPS from URL since it is the only protocol that is - // allowed with WebID. - mHeaderModel.set(HeaderProperties.IDP_BRAND_ICON, idpMetadata.getBrandIcon()); - mHeaderModel.set(HeaderProperties.CLOSE_ON_CLICK_LISTENER, closeOnClickRunnable); - mHeaderModel.set(HeaderProperties.FORMATTED_IDP_ETLD_PLUS_ONE, formattedIdpEtldPlusOne); - mHeaderModel.set(HeaderProperties.FORMATTED_RP_ETLD_PLUS_ONE, formattedRpEtldPlusOne); - mHeaderModel.set(HeaderProperties.TYPE, headerType); + return new PropertyModel.Builder(HeaderProperties.ALL_KEYS) + .with(HeaderProperties.IDP_BRAND_ICON, idpMetadata.getBrandIcon()) + .with(HeaderProperties.CLOSE_ON_CLICK_LISTENER, closeOnClickRunnable) + .with(HeaderProperties.FORMATTED_IDP_ETLD_PLUS_ONE, formattedIdpEtldPlusOne) + .with(HeaderProperties.FORMATTED_RP_ETLD_PLUS_ONE, formattedRpEtldPlusOne) + .with(HeaderProperties.TYPE, headerType) + .build(); } - private void addAccounts( + private void updateAccounts( String idpEtldPlusOne, List<Account> accounts, boolean areAccountsClickable) { + mSheetAccountItems.clear(); + for (Account account : accounts) { final PropertyModel model = createAccountItem(account, areAccountsClickable); - mSheetItems.add(new ListItem(ItemType.ACCOUNT, model)); + mSheetAccountItems.add( + new ListItem(AccountSelectionProperties.ITEM_TYPE_ACCOUNT, model)); requestAvatarImage(model); } } - private void addAutoSignInCancelButton(Account account) { - final PropertyModel cancelBtnModel = createAutoSignInCancelBtnItem(); - mSheetItems.add(new ListItem(ItemType.AUTO_SIGN_IN_CANCEL_BUTTON, cancelBtnModel)); - } - - private void addContinueButton(Account account, String idpEtldPlusOne, - IdentityProviderMetadata idpMetadata, ClientIdMetadata clientMetadata) { - // Shows the continue button for both sign-up and non auto-sign-in. - final PropertyModel continueBtnModel = createContinueBtnItem(account, idpMetadata); - mSheetItems.add(new ListItem(ItemType.CONTINUE_BUTTON, continueBtnModel)); - - // Only show the user data sharing consent text for sign up. - if (!account.isSignIn()) { - mSheetItems.add(new ListItem(ItemType.DATA_SHARING_CONSENT, - createDataSharingConsentItem(idpEtldPlusOne, clientMetadata))); - } - } - void showVerifySheet(Account account) { - mSheetItems.clear(); - - updateHeader(HeaderType.VERIFY, mRpEtldPlusOne, mIdpEtldPlusOne, mIdpMetadata); - - addAccounts(mIdpEtldPlusOne, Arrays.asList(account), /*areAccountsClickable=*/false); + updateSheet(HeaderType.VERIFY, Arrays.asList(account), /*areAccountsClickable=*/false); showContent(); // When TalkBack is enabled, updating |mSheetItems| clears the current item's accessibility @@ -183,8 +164,6 @@ private void showAccountsInternal(String rpEtldPlusOne, String idpEtldPlusOne, List<Account> accounts, Account selectedAccount, IdentityProviderMetadata idpMetadata, ClientIdMetadata clientMetadata, boolean isAutoSignIn) { - mSheetItems.clear(); - mRpEtldPlusOne = rpEtldPlusOne; mIdpEtldPlusOne = idpEtldPlusOne; mAccounts = accounts; @@ -196,21 +175,45 @@ accounts = Arrays.asList(selectedAccount); } - updateHeader(isAutoSignIn ? HeaderType.AUTO_SIGN_IN : HeaderType.SIGN_IN, rpEtldPlusOne, - idpEtldPlusOne, idpMetadata); - addAccounts(idpEtldPlusOne, accounts, /*areAccountsClickable=*/mSelectedAccount == null); + HeaderType headerType = isAutoSignIn ? HeaderType.AUTO_SIGN_IN : HeaderType.SIGN_IN; + updateSheet(headerType, accounts, /*areAccountsClickable=*/mSelectedAccount == null); + showContent(); + } - if (isAutoSignIn) { - assert mSelectedAccount != null; - assert mSelectedAccount.isSignIn(); - addAutoSignInCancelButton(mSelectedAccount); - mAutoSignInTaskHandler.postDelayed( - () -> onAccountSelected(mSelectedAccount), AUTO_SIGN_IN_CANCELLATION_TIMER_MS); - } else if (mSelectedAccount != null) { - addContinueButton(mSelectedAccount, idpEtldPlusOne, idpMetadata, clientMetadata); + private void updateSheet( + HeaderType headerType, List<Account> accounts, boolean areAccountsClickable) { + updateAccounts(mIdpEtldPlusOne, accounts, areAccountsClickable); + + PropertyModel headerModel = + createHeaderItem(headerType, mRpEtldPlusOne, mIdpEtldPlusOne, mIdpMetadata); + mModel.set(ItemProperties.HEADER, headerModel); + + boolean isContinueButtonVisible = false; + boolean isDataSharingConsentVisible = false; + if (headerType == HeaderType.SIGN_IN && mSelectedAccount != null) { + isContinueButtonVisible = true; + // Only show the user data sharing consent text for sign up. + isDataSharingConsentVisible = !mSelectedAccount.isSignIn(); } - showContent(); + if (headerType == HeaderType.AUTO_SIGN_IN) { + assert mSelectedAccount != null; + assert mSelectedAccount.isSignIn(); + + mModel.set(ItemProperties.AUTO_SIGN_IN_CANCEL_BUTTON, createAutoSignInCancelBtnItem()); + mAutoSignInTaskHandler.postDelayed( + () -> onAccountSelected(mSelectedAccount), AUTO_SIGN_IN_CANCELLATION_TIMER_MS); + } else { + mModel.set(ItemProperties.AUTO_SIGN_IN_CANCEL_BUTTON, null); + } + + mModel.set(ItemProperties.CONTINUE_BUTTON, + isContinueButtonVisible ? createContinueBtnItem(mSelectedAccount, mIdpMetadata) + : null); + mModel.set(ItemProperties.DATA_SHARING_CONSENT, + isDataSharingConsentVisible + ? createDataSharingConsentItem(mIdpEtldPlusOne, mClientMetadata) + : null); } /** @@ -268,6 +271,7 @@ if (mSelectedAccount == null && !selectedAccount.isSignIn()) { showAccountsInternal(mRpEtldPlusOne, mIdpEtldPlusOne, mAccounts, selectedAccount, mIdpMetadata, mClientMetadata, /*isAutoSignIn=*/false); + mBottomSheetContent.focusContinueButtonForAccessibility(); return; }
diff --git a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionProperties.java b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionProperties.java index 752d3a2..b2c506e 100644 --- a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionProperties.java +++ b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionProperties.java
@@ -6,23 +6,22 @@ import android.graphics.Bitmap; -import androidx.annotation.IntDef; import androidx.annotation.Nullable; import org.chromium.base.Callback; import org.chromium.chrome.browser.ui.android.webid.data.Account; import org.chromium.chrome.browser.ui.android.webid.data.IdentityProviderMetadata; 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; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - /** * Properties defined here reflect the state of the AccountSelection-components. */ class AccountSelectionProperties { + public static final int ITEM_TYPE_ACCOUNT = 1; + /** * Properties for an account entry in AccountSelection sheet. */ @@ -58,16 +57,16 @@ */ static class HeaderProperties { public enum HeaderType { AUTO_SIGN_IN, SIGN_IN, VERIFY } - static final WritableObjectPropertyKey<Runnable> CLOSE_ON_CLICK_LISTENER = - new WritableObjectPropertyKey<>("close_on_click_listener"); - static final WritableObjectPropertyKey<String> FORMATTED_IDP_ETLD_PLUS_ONE = - new WritableObjectPropertyKey<>("formatted_idp_etld_plus_one"); - static final WritableObjectPropertyKey<String> FORMATTED_RP_ETLD_PLUS_ONE = - new WritableObjectPropertyKey<>("formatted_rp_etld_plus_one"); - static final WritableObjectPropertyKey<Bitmap> IDP_BRAND_ICON = - new WritableObjectPropertyKey<>("brand_icon"); - static final WritableObjectPropertyKey<HeaderType> TYPE = - new WritableObjectPropertyKey<>("type"); + static final ReadableObjectPropertyKey<Runnable> CLOSE_ON_CLICK_LISTENER = + new ReadableObjectPropertyKey<>("close_on_click_listener"); + static final ReadableObjectPropertyKey<String> FORMATTED_IDP_ETLD_PLUS_ONE = + new ReadableObjectPropertyKey<>("formatted_idp_etld_plus_one"); + static final ReadableObjectPropertyKey<String> FORMATTED_RP_ETLD_PLUS_ONE = + new ReadableObjectPropertyKey<>("formatted_rp_etld_plus_one"); + static final ReadableObjectPropertyKey<Bitmap> IDP_BRAND_ICON = + new ReadableObjectPropertyKey<>("brand_icon"); + static final ReadableObjectPropertyKey<HeaderType> TYPE = + new ReadableObjectPropertyKey<>("type"); static final PropertyKey[] ALL_KEYS = {CLOSE_ON_CLICK_LISTENER, FORMATTED_IDP_ETLD_PLUS_ONE, FORMATTED_RP_ETLD_PLUS_ONE, IDP_BRAND_ICON, TYPE}; @@ -123,30 +122,23 @@ private AutoSignInCancelButtonProperties() {} } - @IntDef({ItemType.ACCOUNT, ItemType.CONTINUE_BUTTON, ItemType.AUTO_SIGN_IN_CANCEL_BUTTON, - ItemType.DATA_SHARING_CONSENT}) - @Retention(RetentionPolicy.SOURCE) - @interface ItemType { - /** - * A section containing a user's name and email. - */ - int ACCOUNT = 1; + /** + * Properties defined here reflect sections in the FedCM bottom sheet. + */ + static class ItemProperties { + static final WritableObjectPropertyKey<PropertyModel> AUTO_SIGN_IN_CANCEL_BUTTON = + new WritableObjectPropertyKey<>("auto_sign_in_btn"); + static final WritableObjectPropertyKey<PropertyModel> CONTINUE_BUTTON = + new WritableObjectPropertyKey<>("continue_btn"); + static final WritableObjectPropertyKey<PropertyModel> DATA_SHARING_CONSENT = + new WritableObjectPropertyKey<>("data_sharing_consent"); + static final WritableObjectPropertyKey<PropertyModel> HEADER = + new WritableObjectPropertyKey<>("header"); - /** - * The continue button at the end of the sheet when there is only one account. - */ - int CONTINUE_BUTTON = 2; + static final PropertyKey[] ALL_KEYS = { + AUTO_SIGN_IN_CANCEL_BUTTON, CONTINUE_BUTTON, DATA_SHARING_CONSENT, HEADER}; - /** - * The cancel button at the end of the sheet with auto sign in. - */ - int AUTO_SIGN_IN_CANCEL_BUTTON = 3; - - /** - * The user data sharing consent text when there is only one account and it is a sign-up - * moment. - */ - int DATA_SHARING_CONSENT = 4; + private ItemProperties() {} } private AccountSelectionProperties() {}
diff --git a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionViewBinder.java b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionViewBinder.java index 367724c..0cba32ef 100644 --- a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionViewBinder.java +++ b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionViewBinder.java
@@ -39,12 +39,15 @@ import org.chromium.chrome.browser.ui.android.webid.AccountSelectionProperties.ContinueButtonProperties; import org.chromium.chrome.browser.ui.android.webid.AccountSelectionProperties.DataSharingConsentProperties; import org.chromium.chrome.browser.ui.android.webid.AccountSelectionProperties.HeaderProperties; +import org.chromium.chrome.browser.ui.android.webid.AccountSelectionProperties.ItemProperties; import org.chromium.chrome.browser.ui.android.webid.data.Account; import org.chromium.chrome.browser.ui.android.webid.data.IdentityProviderMetadata; import org.chromium.components.browser_ui.util.AvatarGenerator; import org.chromium.components.browser_ui.widget.RoundedIconGenerator; import org.chromium.ui.modelutil.PropertyKey; import org.chromium.ui.modelutil.PropertyModel; +import org.chromium.ui.modelutil.PropertyModel.WritableObjectPropertyKey; +import org.chromium.ui.modelutil.PropertyModelChangeProcessor.ViewBinder; import org.chromium.ui.text.NoUnderlineClickableSpan; import org.chromium.ui.text.SpanApplier; import org.chromium.ui.util.ColorUtils; @@ -195,8 +198,8 @@ int consentTextId = termsOfServiceSpan == null ? R.string.account_selection_data_sharing_consent_no_tos : R.string.account_selection_data_sharing_consent; - String consentText = String.format(view.getContext().getString(consentTextId), - properties.mFormattedIdpEtldPlusOne); + String consentText = String.format( + context.getString(consentTextId), properties.mFormattedIdpEtldPlusOne); // |privacyPolicySpan| cannot be null due to the following: // 1. We check that the privacy URL is valid in @@ -228,11 +231,11 @@ @SuppressWarnings("checkstyle:SetTextColorAndSetTextSizeCheck") static void bindContinueButtonView(PropertyModel model, View view, PropertyKey key) { Context context = view.getContext(); + ButtonCompat button = view.findViewById(R.id.account_selection_continue_btn); if (key == ContinueButtonProperties.IDP_METADATA) { if (!ColorUtils.inNightMode(context)) { IdentityProviderMetadata idpMetadata = model.get(ContinueButtonProperties.IDP_METADATA); - ButtonCompat button = view.findViewById(R.id.account_selection_continue_btn); Integer backgroundColor = idpMetadata.getBrandBackgroundColor(); if (backgroundColor != null) { @@ -257,10 +260,9 @@ givenName != null && !givenName.isEmpty() ? givenName : account.getName(); String btnText = String.format( context.getString(R.string.account_selection_continue), displayedName); - Button button = view.findViewById(R.id.account_selection_continue_btn); button.setText(btnText); } else if (key == ContinueButtonProperties.ON_CLICK_LISTENER) { - view.setOnClickListener(clickedView -> { + button.setOnClickListener(clickedView -> { Account account = model.get(ContinueButtonProperties.ACCOUNT); model.get(ContinueButtonProperties.ON_CLICK_LISTENER).onResult(account); }); @@ -289,6 +291,44 @@ } /** + * Called whenever non-account views are bound to the bottom sheet. + * @param model The model containing the data for the view. + * @param view The view to be bound. + * @param key The key of the property to be bound. + */ + static void bindContentView(PropertyModel model, View view, PropertyKey key) { + PropertyModel itemModel = model.get((WritableObjectPropertyKey<PropertyModel>) key); + View itemView = null; + ViewBinder<PropertyModel, View, PropertyKey> itemBinder = null; + if (key == ItemProperties.HEADER) { + itemView = view.findViewById(R.id.header_view_item); + itemBinder = AccountSelectionViewBinder::bindHeaderView; + } else if (key == ItemProperties.CONTINUE_BUTTON) { + itemView = view.findViewById(R.id.account_selection_continue_btn); + itemBinder = AccountSelectionViewBinder::bindContinueButtonView; + } else if (key == ItemProperties.AUTO_SIGN_IN_CANCEL_BUTTON) { + itemView = view.findViewById(R.id.auto_sign_in_cancel_btn); + itemBinder = AccountSelectionViewBinder::bindAutoSignInCancelButtonView; + } else if (key == ItemProperties.DATA_SHARING_CONSENT) { + itemView = view.findViewById(R.id.user_data_sharing_consent); + itemBinder = AccountSelectionViewBinder::bindDataSharingConsentView; + } else { + assert false : "Unhandled update to property:" + key; + return; + } + + if (itemModel == null) { + itemView.setVisibility(View.GONE); + return; + } + + itemView.setVisibility(View.VISIBLE); + for (PropertyKey itemKey : itemModel.getAllSetProperties()) { + itemBinder.bind(itemModel, itemView, itemKey); + } + } + + /** * Called whenever a header is bound to this view. * @param model The model containing the data for the view. * @param view The view to be bound.
diff --git a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionViewTest.java b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionViewTest.java index b12a21f..c11055a 100644 --- a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionViewTest.java +++ b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionViewTest.java
@@ -6,6 +6,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.verify; @@ -43,6 +44,7 @@ import org.chromium.chrome.browser.ui.android.webid.AccountSelectionProperties.DataSharingConsentProperties; import org.chromium.chrome.browser.ui.android.webid.AccountSelectionProperties.HeaderProperties; import org.chromium.chrome.browser.ui.android.webid.AccountSelectionProperties.HeaderProperties.HeaderType; +import org.chromium.chrome.browser.ui.android.webid.AccountSelectionProperties.ItemProperties; import org.chromium.chrome.browser.ui.android.webid.data.Account; import org.chromium.chrome.browser.ui.android.webid.data.IdentityProviderMetadata; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; @@ -77,8 +79,8 @@ private Runnable mAutoSignInCancelCallback; private BlankUiTestActivity mActivity; - private PropertyModel mHeaderModel; - private ModelList mSheetItems; + private PropertyModel mModel; + private ModelList mSheetAccountItems; private View mContentView; @Rule public BaseActivityTestRule<BlankUiTestActivity> mActivityTestRule = @@ -91,12 +93,11 @@ mActivity = mActivityTestRule.getActivity(); TestThreadUtils.runOnUiThreadBlocking(() -> { - mHeaderModel = - new PropertyModel.Builder(AccountSelectionProperties.HeaderProperties.ALL_KEYS) - .build(); - mSheetItems = new ModelList(); + mModel = new PropertyModel.Builder(AccountSelectionProperties.ItemProperties.ALL_KEYS) + .build(); + mSheetAccountItems = new ModelList(); mContentView = AccountSelectionCoordinator.setupContentView( - mActivity, mHeaderModel, mSheetItems); + mActivity, mModel, mSheetAccountItems); mActivity.setContentView(mContentView); }); } @@ -105,9 +106,12 @@ @MediumTest public void testSignInTitleDisplayed() { TestThreadUtils.runOnUiThreadBlocking(() -> { - mHeaderModel.set(HeaderProperties.TYPE, HeaderType.SIGN_IN); - mHeaderModel.set(HeaderProperties.FORMATTED_RP_ETLD_PLUS_ONE, "example.org"); - mHeaderModel.set(HeaderProperties.FORMATTED_IDP_ETLD_PLUS_ONE, "idp.org"); + mModel.set(ItemProperties.HEADER, + new PropertyModel.Builder(HeaderProperties.ALL_KEYS) + .with(HeaderProperties.TYPE, HeaderType.SIGN_IN) + .with(HeaderProperties.FORMATTED_RP_ETLD_PLUS_ONE, "example.org") + .with(HeaderProperties.FORMATTED_IDP_ETLD_PLUS_ONE, "idp.org") + .build()); }); pollUiThread(() -> mContentView.getVisibility() == View.VISIBLE); TextView title = mContentView.findViewById(R.id.header_title); @@ -122,9 +126,12 @@ @MediumTest public void testVerifyingTitleDisplayed() { TestThreadUtils.runOnUiThreadBlocking(() -> { - mHeaderModel.set(HeaderProperties.TYPE, HeaderType.VERIFY); - mHeaderModel.set(HeaderProperties.FORMATTED_RP_ETLD_PLUS_ONE, "example.org"); - mHeaderModel.set(HeaderProperties.FORMATTED_IDP_ETLD_PLUS_ONE, "idp.org"); + mModel.set(ItemProperties.HEADER, + new PropertyModel.Builder(HeaderProperties.ALL_KEYS) + .with(HeaderProperties.TYPE, HeaderType.VERIFY) + .with(HeaderProperties.FORMATTED_RP_ETLD_PLUS_ONE, "example.org") + .with(HeaderProperties.FORMATTED_IDP_ETLD_PLUS_ONE, "idp.org") + .build()); }); pollUiThread(() -> mContentView.getVisibility() == View.VISIBLE); TextView title = mContentView.findViewById(R.id.header_title); @@ -137,7 +144,7 @@ @MediumTest public void testAccountsChangedByModel() { TestThreadUtils.runOnUiThreadBlocking(() -> { - mSheetItems.addAll( + mSheetAccountItems.addAll( asList(buildAccountItem(ANA), buildAccountItem(NO_ONE), buildAccountItem(BOB))); }); @@ -154,8 +161,9 @@ @Test @MediumTest public void testAccountsAreClickable() { - TestThreadUtils.runOnUiThreadBlocking( - () -> { mSheetItems.addAll(Collections.singletonList(buildAccountItem(ANA))); }); + TestThreadUtils.runOnUiThreadBlocking(() -> { + mSheetAccountItems.addAll(Collections.singletonList(buildAccountItem(ANA))); + }); pollUiThread(() -> mContentView.getVisibility() == View.VISIBLE); assertNotNull(getAccounts().getChildAt(0)); @@ -171,21 +179,22 @@ TestThreadUtils.runOnUiThreadBlocking(() -> { // Create an account with no callback to ensure the button callback // is the one that gets invoked. - final MVCListAdapter.ListItem account_without_callback = - new MVCListAdapter.ListItem(AccountSelectionProperties.ItemType.ACCOUNT, + mSheetAccountItems.add( + new MVCListAdapter.ListItem(AccountSelectionProperties.ITEM_TYPE_ACCOUNT, new PropertyModel.Builder(AccountProperties.ALL_KEYS) .with(AccountProperties.ACCOUNT, ANA) .with(AccountProperties.ON_CLICK_LISTENER, null) - .build()); + .build())); - mSheetItems.addAll(asList(account_without_callback, buildContinueButton(ANA, null))); + mModel.set(ItemProperties.CONTINUE_BUTTON, buildContinueButton(ANA, null)); }); pollUiThread(() -> mContentView.getVisibility() == View.VISIBLE); assertNotNull(getAccounts().getChildAt(0)); - assertNotNull(getAccounts().getChildAt(1)); - TouchCommon.singleClickView(getAccounts().getChildAt(1)); + View continueButton = mContentView.findViewById(R.id.account_selection_continue_btn); + assertTrue(continueButton.isShown()); + TouchCommon.singleClickView(continueButton); waitForEvent(mAccountCallback).onResult(eq(ANA)); } @@ -196,28 +205,31 @@ TestThreadUtils.runOnUiThreadBlocking(() -> { // Create an account with no callback to ensure the button callback // is the one that gets invoked. - final MVCListAdapter.ListItem account_without_callback = - new MVCListAdapter.ListItem(AccountSelectionProperties.ItemType.ACCOUNT, + mSheetAccountItems.add( + new MVCListAdapter.ListItem(AccountSelectionProperties.ITEM_TYPE_ACCOUNT, new PropertyModel.Builder(AccountProperties.ALL_KEYS) .with(AccountProperties.ACCOUNT, ANA) .with(AccountProperties.ON_CLICK_LISTENER, null) - .build()); + .build())); - mSheetItems.addAll(asList(account_without_callback, buildCancelButton())); + mModel.set(ItemProperties.AUTO_SIGN_IN_CANCEL_BUTTON, buildCancelButton()); }); pollUiThread(() -> mContentView.getVisibility() == View.VISIBLE); assertNotNull(getAccounts().getChildAt(0)); - assertNotNull(getAccounts().getChildAt(1)); + assertTrue(mContentView.findViewById(R.id.auto_sign_in_cancel_btn).isShown()); } @Test @MediumTest public void testHeaderDisplayedForAutoSignIn() { TestThreadUtils.runOnUiThreadBlocking(() -> { - mHeaderModel.set(HeaderProperties.TYPE, HeaderType.AUTO_SIGN_IN); - mHeaderModel.set(HeaderProperties.FORMATTED_RP_ETLD_PLUS_ONE, "example.org"); - mHeaderModel.set(HeaderProperties.FORMATTED_IDP_ETLD_PLUS_ONE, "idp.org"); + mModel.set(ItemProperties.HEADER, + new PropertyModel.Builder(HeaderProperties.ALL_KEYS) + .with(HeaderProperties.TYPE, HeaderType.AUTO_SIGN_IN) + .with(HeaderProperties.FORMATTED_RP_ETLD_PLUS_ONE, "example.org") + .with(HeaderProperties.FORMATTED_IDP_ETLD_PLUS_ONE, "idp.org") + .build()); }); pollUiThread(() -> mContentView.getVisibility() == View.VISIBLE); TextView title = mContentView.findViewById(R.id.header_title); @@ -233,12 +245,12 @@ public void testDataSharingConsentDisplayed() { final String idpEtldPlusOne = "idp.org"; TestThreadUtils.runOnUiThreadBlocking(() -> { - mSheetItems.addAll( - Collections.singletonList(buildDataSharingConsentItem(idpEtldPlusOne))); + mModel.set(ItemProperties.DATA_SHARING_CONSENT, + buildDataSharingConsentItem(idpEtldPlusOne)); }); pollUiThread(() -> mContentView.getVisibility() == View.VISIBLE); - assertNotNull(getAccounts().getChildAt(0)); TextView consent = mContentView.findViewById(R.id.user_data_sharing_consent); + assertTrue(consent.isShown()); String expectedSharingConsentText = mActivity.getString(R.string.account_selection_data_sharing_consent, "idp.org"); expectedSharingConsentText = expectedSharingConsentText.replaceAll("<[^>]*>", ""); @@ -266,12 +278,11 @@ IdentityProviderMetadata idpMetadata = new IdentityProviderMetadata( expectedTextColor, /*brandBackgroundColor*/ Color.GREEN, brandIcon); - mSheetItems.addAll(Collections.singletonList(buildContinueButton(ANA, idpMetadata))); + mModel.set(ItemProperties.CONTINUE_BUTTON, buildContinueButton(ANA, idpMetadata)); }); pollUiThread(() -> mContentView.getVisibility() == View.VISIBLE); - assertNotNull(getAccounts().getChildAt(0)); TextView continueButton = mContentView.findViewById(R.id.account_selection_continue_btn); assertEquals(expectedTextColor, continueButton.getTextColors().getDefaultColor()); @@ -295,14 +306,14 @@ } private MVCListAdapter.ListItem buildAccountItem(Account account) { - return new MVCListAdapter.ListItem(AccountSelectionProperties.ItemType.ACCOUNT, + return new MVCListAdapter.ListItem(AccountSelectionProperties.ITEM_TYPE_ACCOUNT, new PropertyModel.Builder(AccountProperties.ALL_KEYS) .with(AccountProperties.ACCOUNT, account) .with(AccountProperties.ON_CLICK_LISTENER, mAccountCallback) .build()); } - private MVCListAdapter.ListItem buildContinueButton( + private PropertyModel buildContinueButton( Account account, IdentityProviderMetadata idpMetadata) { PropertyModel.Builder modelBuilder = new PropertyModel.Builder(ContinueButtonProperties.ALL_KEYS) @@ -312,29 +323,24 @@ modelBuilder.with(ContinueButtonProperties.IDP_METADATA, idpMetadata); } - return new MVCListAdapter.ListItem( - AccountSelectionProperties.ItemType.CONTINUE_BUTTON, modelBuilder.build()); + return modelBuilder.build(); } - private MVCListAdapter.ListItem buildCancelButton() { - return new MVCListAdapter.ListItem( - AccountSelectionProperties.ItemType.AUTO_SIGN_IN_CANCEL_BUTTON, - new PropertyModel.Builder(AutoSignInCancelButtonProperties.ALL_KEYS) - .with(AutoSignInCancelButtonProperties.ON_CLICK_LISTENER, - mAutoSignInCancelCallback) - .build()); + private PropertyModel buildCancelButton() { + return new PropertyModel.Builder(AutoSignInCancelButtonProperties.ALL_KEYS) + .with(AutoSignInCancelButtonProperties.ON_CLICK_LISTENER, mAutoSignInCancelCallback) + .build(); } - private MVCListAdapter.ListItem buildDataSharingConsentItem(String idpEtldPlusOne) { + private PropertyModel buildDataSharingConsentItem(String idpEtldPlusOne) { DataSharingConsentProperties.Properties properties = new DataSharingConsentProperties.Properties(); properties.mFormattedIdpEtldPlusOne = idpEtldPlusOne; properties.mTermsOfServiceUrl = "https://rp.com/tos"; properties.mPrivacyPolicyUrl = "https://rp.com/privacy"; - return new MVCListAdapter.ListItem(AccountSelectionProperties.ItemType.DATA_SHARING_CONSENT, - new PropertyModel.Builder(DataSharingConsentProperties.ALL_KEYS) - .with(DataSharingConsentProperties.PROPERTIES, properties) - .build()); + return new PropertyModel.Builder(DataSharingConsentProperties.ALL_KEYS) + .with(DataSharingConsentProperties.PROPERTIES, properties) + .build(); } }
diff --git a/chrome/browser/ui/app_list/app_service/app_service_app_item.cc b/chrome/browser/ui/app_list/app_service/app_service_app_item.cc index 62ccab8..58c2886 100644 --- a/chrome/browser/ui/app_list/app_service/app_service_app_item.cc +++ b/chrome/browser/ui/app_list/app_service/app_service_app_item.cc
@@ -46,24 +46,24 @@ return false; switch (app_update.AppType()) { - case apps::mojom::AppType::kUnknown: - case apps::mojom::AppType::kBuiltIn: - case apps::mojom::AppType::kStandaloneBrowser: - case apps::mojom::AppType::kSystemWeb: + case apps::AppType::kUnknown: + case apps::AppType::kBuiltIn: + case apps::AppType::kStandaloneBrowser: + case apps::AppType::kSystemWeb: // Chrome, Lacros, Settings, etc. are built-in. return false; - case apps::mojom::AppType::kMacOs: + case apps::AppType::kMacOs: NOTREACHED(); return false; - case apps::mojom::AppType::kArc: - case apps::mojom::AppType::kCrostini: - case apps::mojom::AppType::kChromeApp: - case apps::mojom::AppType::kExtension: - case apps::mojom::AppType::kWeb: - case apps::mojom::AppType::kPluginVm: - case apps::mojom::AppType::kRemote: - case apps::mojom::AppType::kBorealis: - case apps::mojom::AppType::kStandaloneBrowserChromeApp: + case apps::AppType::kArc: + case apps::AppType::kCrostini: + case apps::AppType::kChromeApp: + case apps::AppType::kExtension: + case apps::AppType::kWeb: + case apps::AppType::kPluginVm: + case apps::AppType::kRemote: + case apps::AppType::kBorealis: + case apps::AppType::kStandaloneBrowserChromeApp: // Other app types are user-installed. return true; } @@ -80,7 +80,7 @@ const app_list::AppListSyncableService::SyncItem* sync_item, const apps::AppUpdate& app_update) : ChromeAppListItem(profile, app_update.AppId()), - app_type_(apps::ConvertMojomAppTypToAppType(app_update.AppType())), + app_type_(app_update.AppType()), creation_time_(base::TimeTicks::Now()) { OnAppUpdate(app_update, /*in_constructor=*/true); if (sync_item && sync_item->item_ordinal.IsValid()) { @@ -173,10 +173,10 @@ apps::AppServiceProxyFactory::GetForProfile(profile()) ->AppRegistryCache() .ForOneApp(id(), [&is_active_app](const apps::AppUpdate& update) { - if (update.AppType() == apps::mojom::AppType::kCrostini || - update.AppType() == apps::mojom::AppType::kWeb || - update.AppType() == apps::mojom::AppType::kSystemWeb || - (update.AppType() == apps::mojom::AppType::kChromeApp && + if (update.AppType() == apps::AppType::kCrostini || + update.AppType() == apps::AppType::kWeb || + update.AppType() == apps::AppType::kSystemWeb || + (update.AppType() == apps::AppType::kChromeApp && update.IsPlatformApp().value_or(true))) { is_active_app = true; }
diff --git a/chrome/browser/ui/app_list/app_service/app_service_app_model_builder.cc b/chrome/browser/ui/app_list/app_service/app_service_app_model_builder.cc index cdf3aab..2cc5483 100644 --- a/chrome/browser/ui/app_list/app_service/app_service_app_model_builder.cc +++ b/chrome/browser/ui/app_list/app_service/app_service_app_model_builder.cc
@@ -56,10 +56,10 @@ // TODO(crbug.com/826982): drop the check for kChromeApp or kWeb, and // call UpdateItem unconditionally? - apps::mojom::AppType app_type = update.AppType(); - if ((app_type == apps::mojom::AppType::kChromeApp) || - (app_type == apps::mojom::AppType::kSystemWeb) || - (app_type == apps::mojom::AppType::kWeb)) { + apps::AppType app_type = update.AppType(); + if ((app_type == apps::AppType::kChromeApp) || + (app_type == apps::AppType::kSystemWeb) || + (app_type == apps::AppType::kWeb)) { app_list::AppListSyncableService* serv = service(); if (serv) { serv->UpdateItem(item); @@ -68,7 +68,7 @@ } else { bool unsynced_change = false; - if (update.AppType() == apps::mojom::AppType::kArc) { + if (update.AppType() == apps::AppType::kArc) { // Don't sync app removal in case it was caused by disabling Google // Play Store. unsynced_change = !arc::IsArcPlayStoreEnabledForProfile(profile());
diff --git a/chrome/browser/ui/app_list/app_service/app_service_app_model_builder_unittest.cc b/chrome/browser/ui/app_list/app_service/app_service_app_model_builder_unittest.cc index d3148f8..8a20bf4 100644 --- a/chrome/browser/ui/app_list/app_service/app_service_app_model_builder_unittest.cc +++ b/chrome/browser/ui/app_list/app_service/app_service_app_model_builder_unittest.cc
@@ -144,7 +144,7 @@ // For testing purposes, we want to pretend there are only |app_type| apps on // the system. This method removes the others. -void RemoveApps(apps::mojom::AppType app_type, +void RemoveApps(apps::AppType app_type, Profile* profile, FakeAppListModelUpdater* model_updater) { apps::AppServiceProxy* proxy = @@ -251,7 +251,7 @@ // Creates a new builder, destroying any existing one. void CreateBuilder(bool guest_mode) { AppServiceAppModelBuilderTest::CreateBuilder(guest_mode); - RemoveApps(apps::mojom::AppType::kBuiltIn, testing_profile(), + RemoveApps(apps::AppType::kBuiltIn, testing_profile(), model_updater_.get()); } }; @@ -269,7 +269,7 @@ // Creates a new builder, destroying any existing one. void CreateBuilder() { AppServiceAppModelBuilderTest::CreateBuilder(false /*guest_mode*/); - RemoveApps(apps::mojom::AppType::kChromeApp, testing_profile(), + RemoveApps(apps::AppType::kChromeApp, testing_profile(), model_updater_.get()); } @@ -331,8 +331,7 @@ // Creates a new builder, destroying any existing one. void CreateBuilder() { AppServiceAppModelBuilderTest::CreateBuilder(false /*guest_mode*/); - RemoveApps(apps::mojom::AppType::kWeb, testing_profile(), - model_updater_.get()); + RemoveApps(apps::AppType::kWeb, testing_profile(), model_updater_.get()); } std::string CreateWebApp(const std::string& app_name) { @@ -651,7 +650,7 @@ CreateWebApp(kAppName); app_service_test_.SetUp(profile_.get()); - RemoveApps(apps::mojom::AppType::kWeb, profile(), model_updater_.get()); + RemoveApps(apps::AppType::kWeb, profile(), model_updater_.get()); EXPECT_EQ(1u, model_updater_->ItemCount()); EXPECT_EQ((std::vector<std::string>{kAppName}), GetModelContent(model_updater_.get())); @@ -687,7 +686,7 @@ demo_mode_test_helper_->InitializeSession(); app_service_test_.SetUp(profile_.get()); - RemoveApps(apps::mojom::AppType::kWeb, profile(), model_updater_.get()); + RemoveApps(apps::AppType::kWeb, profile(), model_updater_.get()); } void TearDown() override { @@ -1020,7 +1019,7 @@ builder_.get(), base::BindRepeating(&InitAppPosition)); builder_->Initialize(nullptr, testing_profile_.get(), model_updater_.get()); - RemoveApps(apps::mojom::AppType::kPluginVm, testing_profile_.get(), + RemoveApps(apps::AppType::kPluginVm, testing_profile_.get(), model_updater_.get()); }
diff --git a/chrome/browser/ui/app_list/app_service/app_service_context_menu.cc b/chrome/browser/ui/app_list/app_service/app_service_context_menu.cc index 9e0c40c5..508a2f1 100644 --- a/chrome/browser/ui/app_list/app_service/app_service_context_menu.cc +++ b/chrome/browser/ui/app_list/app_service/app_service_context_menu.cc
@@ -133,7 +133,7 @@ proxy_->AppRegistryCache().ForOneApp( app_id, [this](const apps::AppUpdate& update) { app_type_ = apps_util::IsInstalled(update.Readiness()) - ? apps::ConvertMojomAppTypToAppType(update.AppType()) + ? update.AppType() : apps::AppType::kUnknown; });
diff --git a/chrome/browser/ui/app_list/arc/arc_app_unittest.cc b/chrome/browser/ui/app_list/arc/arc_app_unittest.cc index 34f25fbb..223ba807 100644 --- a/chrome/browser/ui/app_list/arc/arc_app_unittest.cc +++ b/chrome/browser/ui/app_list/arc/arc_app_unittest.cc
@@ -436,7 +436,7 @@ proxy->FlushMojoCallsForTesting(); proxy->AppRegistryCache().ForEachApp( [&model_updater](const apps::AppUpdate& update) { - if (update.AppType() != apps::mojom::AppType::kArc) { + if (update.AppType() != apps::AppType::kArc) { model_updater->RemoveItem(update.AppId(), /*is_uninstall=*/true); } }); @@ -448,7 +448,7 @@ apps::AppServiceProxyFactory::GetForProfile(profile) ->AppRegistryCache() .ForEachApp([&model_updater](const apps::AppUpdate& update) { - if (update.AppType() == apps::mojom::AppType::kArc) { + if (update.AppType() == apps::AppType::kArc) { model_updater->RemoveItem(update.AppId(), /*is_uninstall=*/true); } });
diff --git a/chrome/browser/ui/app_list/search/app_search_provider.cc b/chrome/browser/ui/app_list/search/app_search_provider.cc index df125a36..4cf8d11 100644 --- a/chrome/browser/ui/app_list/search/app_search_provider.cc +++ b/chrome/browser/ui/app_list/search/app_search_provider.cc
@@ -325,7 +325,7 @@ if (!apps_util::IsInstalled(update.Readiness()) || (!update.ShowInSearch().value_or(false) && !(update.Recommendable().value_or(false) && - update.AppType() == apps::mojom::AppType::kBuiltIn))) { + update.AppType() == apps::AppType::kBuiltIn))) { return; }
diff --git a/chrome/browser/ui/app_list/search/app_search_provider_unittest.cc b/chrome/browser/ui/app_list/search/app_search_provider_unittest.cc index 6d1aafd8..7174745 100644 --- a/chrome/browser/ui/app_list/search/app_search_provider_unittest.cc +++ b/chrome/browser/ui/app_list/search/app_search_provider_unittest.cc
@@ -45,6 +45,7 @@ #include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/seneschal/seneschal_client.h" #include "components/crx_file/id_util.h" +#include "components/services/app_service/public/cpp/app_types.h" #include "components/services/app_service/public/cpp/stub_icon_loader.h" #include "components/services/app_service/public/mojom/types.mojom.h" #include "components/sessions/content/content_test_helper.h" @@ -121,7 +122,7 @@ app->app_id = app_id; proxy.AppRegistryCache().ForOneApp( app_id, [&app](const apps::AppUpdate& update) { - app->app_type = update.AppType(); + app->app_type = ConvertAppTypeToMojomAppType(update.AppType()); app->icon_key = apps::mojom::IconKey::New( update.IconKey()->timeline + 1, update.IconKey()->resource_id, update.IconKey()->icon_effects);
diff --git a/chrome/browser/ui/app_list/search/app_service_app_result.cc b/chrome/browser/ui/app_list/search/app_service_app_result.cc index 4f12600..b3924bd0 100644 --- a/chrome/browser/ui/app_list/search/app_service_app_result.cc +++ b/chrome/browser/ui/app_list/search/app_service_app_result.cc
@@ -51,7 +51,7 @@ apps::AppServiceProxyFactory::GetForProfile(profile) ->AppRegistryCache() .ForOneApp(app_id, [this](const apps::AppUpdate& update) { - app_type_ = apps::ConvertMojomAppTypToAppType(update.AppType()); + app_type_ = update.AppType(); is_platform_app_ = update.IsPlatformApp().value_or(false); show_in_launcher_ = update.ShowInLauncher().value_or(false); @@ -182,10 +182,10 @@ bool is_active_app = false; proxy->AppRegistryCache().ForOneApp( app_id(), [&is_active_app](const apps::AppUpdate& update) { - if (update.AppType() == apps::mojom::AppType::kCrostini || - update.AppType() == apps::mojom::AppType::kWeb || - update.AppType() == apps::mojom::AppType::kSystemWeb || - (update.AppType() == apps::mojom::AppType::kChromeApp && + if (update.AppType() == apps::AppType::kCrostini || + update.AppType() == apps::AppType::kWeb || + update.AppType() == apps::AppType::kSystemWeb || + (update.AppType() == apps::AppType::kChromeApp && update.IsPlatformApp().value_or(true))) { is_active_app = true; }
diff --git a/chrome/browser/ui/app_list/search/os_settings_provider.cc b/chrome/browser/ui/app_list/search/os_settings_provider.cc index 5f346e1..f3805b44 100644 --- a/chrome/browser/ui/app_list/search/os_settings_provider.cc +++ b/chrome/browser/ui/app_list/search/os_settings_provider.cc
@@ -328,16 +328,16 @@ if (base::FeatureList::IsEnabled( features::kAppServiceLoadIconWithoutMojom)) { app_service_proxy_->LoadIcon( - apps::ConvertMojomAppTypToAppType(update.AppType()), - web_app::kOsSettingsAppId, apps::IconType::kStandard, - GetAppIconDimension(), + update.AppType(), web_app::kOsSettingsAppId, + apps::IconType::kStandard, GetAppIconDimension(), /*allow_placeholder_icon=*/false, base::BindOnce(&OsSettingsProvider::OnLoadIcon, weak_factory_.GetWeakPtr())); } else { app_service_proxy_->LoadIcon( - update.AppType(), web_app::kOsSettingsAppId, - apps::mojom::IconType::kStandard, GetAppIconDimension(), + apps::ConvertAppTypeToMojomAppType(update.AppType()), + web_app::kOsSettingsAppId, apps::mojom::IconType::kStandard, + GetAppIconDimension(), /*allow_placeholder_icon=*/false, apps::MojomIconValueToIconValueCallback(base::BindOnce( &OsSettingsProvider::OnLoadIcon, weak_factory_.GetWeakPtr())));
diff --git a/chrome/browser/ui/ash/desks_templates/chrome_desks_templates_delegate.cc b/chrome/browser/ui/ash/desks_templates/chrome_desks_templates_delegate.cc index 81f1d19b..22829f6e 100644 --- a/chrome/browser/ui/ash/desks_templates/chrome_desks_templates_delegate.cc +++ b/chrome/browser/ui/ash/desks_templates/chrome_desks_templates_delegate.cc
@@ -331,6 +331,18 @@ } } +bool ChromeDesksTemplatesDelegate::IsAppAvailable( + const std::string& app_id) const { + Profile* app_profile = ProfileManager::GetActiveUserProfile(); + DCHECK(app_profile); + + auto* app_service_proxy = + apps::AppServiceProxyFactory::GetForProfile(app_profile); + DCHECK(app_service_proxy); + + return ::IsAppAvailable(app_id, app_service_proxy); +} + void ChromeDesksTemplatesDelegate::LaunchAppsFromTemplate( std::unique_ptr<ash::DeskTemplate> desk_template, base::Time time_launch_started,
diff --git a/chrome/browser/ui/ash/desks_templates/chrome_desks_templates_delegate.h b/chrome/browser/ui/ash/desks_templates/chrome_desks_templates_delegate.h index 8b658d6..de63bb4c 100644 --- a/chrome/browser/ui/ash/desks_templates/chrome_desks_templates_delegate.h +++ b/chrome/browser/ui/ash/desks_templates/chrome_desks_templates_delegate.h
@@ -50,6 +50,7 @@ bool IsWindowSupportedForDeskTemplate(aura::Window* window) const override; void OpenFeedbackDialog(const std::string& extra_diagnostics) override; std::string GetAppShortName(const std::string& app_id) override; + bool IsAppAvailable(const std::string& app_id) const override; }; #endif // CHROME_BROWSER_UI_ASH_DESKS_TEMPLATES_CHROME_DESKS_TEMPLATES_DELEGATE_H_
diff --git a/chrome/browser/ui/ash/desks_templates/desks_templates_app_launch_handler.cc b/chrome/browser/ui/ash/desks_templates/desks_templates_app_launch_handler.cc index 4463f99..2da9115 100644 --- a/chrome/browser/ui/ash/desks_templates/desks_templates_app_launch_handler.cc +++ b/chrome/browser/ui/ash/desks_templates/desks_templates_app_launch_handler.cc
@@ -94,8 +94,8 @@ apps::AppServiceProxyFactory::GetForProfile(profile()) ->AppRegistryCache() .ForOneApp(app_id, [&is_system_web_app](const apps::AppUpdate& update) { - if (update.AppType() == apps::mojom::AppType::kWeb || - update.AppType() == apps::mojom::AppType::kSystemWeb) { + if (update.AppType() == apps::AppType::kWeb || + update.AppType() == apps::AppType::kSystemWeb) { is_system_web_app = true; } }); @@ -232,7 +232,7 @@ cache.ForEachApp( [&app_ids, &app_id_to_launch_list](const apps::AppUpdate& update) { if (update.Readiness() == apps::Readiness::kReady && - update.AppType() == apps::mojom::AppType::kArc && + update.AppType() == apps::AppType::kArc && base::Contains(app_id_to_launch_list, update.AppId())) { app_ids.insert(update.AppId()); }
diff --git a/chrome/browser/ui/ash/shelf/shelf_controller_helper.cc b/chrome/browser/ui/ash/shelf/shelf_controller_helper.cc index 9017b65..ad1aa47 100644 --- a/chrome/browser/ui/ash/shelf/shelf_controller_helper.cc +++ b/chrome/browser/ui/ash/shelf/shelf_controller_helper.cc
@@ -33,6 +33,7 @@ #include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/browser/ui/extensions/extension_enable_flow.h" #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" +#include "components/services/app_service/public/cpp/app_types.h" #include "components/services/app_service/public/cpp/types_util.h" #include "content/public/browser/navigation_entry.h" #include "net/base/url_util.h" @@ -263,8 +264,8 @@ apps::AppServiceProxyFactory::GetForProfile(profile_) ->AppRegistryCache() .ForOneApp(app_id, [&is_valid](const apps::AppUpdate& update) { - if (update.AppType() != apps::mojom::AppType::kArc && - update.AppType() != apps::mojom::AppType::kUnknown && + if (update.AppType() != apps::AppType::kArc && + update.AppType() != apps::AppType::kUnknown && update.Readiness() != apps::Readiness::kUnknown && apps_util::IsInstalled(update.Readiness())) { is_valid = true;
diff --git a/chrome/browser/ui/cocoa/fullscreen/fullscreen_toolbar_mouse_tracker.mm b/chrome/browser/ui/cocoa/fullscreen/fullscreen_toolbar_mouse_tracker.mm index c2033ab..6804218 100644 --- a/chrome/browser/ui/cocoa/fullscreen/fullscreen_toolbar_mouse_tracker.mm +++ b/chrome/browser/ui/cocoa/fullscreen/fullscreen_toolbar_mouse_tracker.mm
@@ -100,7 +100,11 @@ if (!_trackingArea) return; - DCHECK(_contentView); + // TODO(https://crbug.com/1063417, https://crbug.com/1064911): This DCHECK + // is hit when closing a fullscreen window using the traffic lights. This is + // because `removeTrackingArea` should be removed in response to the window + // closing, but isn't. + // DCHECK(_contentView); [_contentView removeTrackingArea:_trackingArea]; _trackingArea.reset(); _contentView.reset();
diff --git a/chrome/browser/ui/color/chrome_color_id.h b/chrome/browser/ui/color/chrome_color_id.h index 9a955580..d36157f 100644 --- a/chrome/browser/ui/color/chrome_color_id.h +++ b/chrome/browser/ui/color/chrome_color_id.h
@@ -74,10 +74,13 @@ E(kColorNewTabPageHeader, ThemeProperties::COLOR_NTP_HEADER) \ E(kColorNewTabPageLink, ThemeProperties::COLOR_NTP_LINK) \ E(kColorNewTabPageLogo, ThemeProperties::COLOR_NTP_LOGO) \ + E_CPONLY(kColorNewTabPageLogoUnthemed) \ E(kColorNewTabPageMostVisitedTileBackground, \ ThemeProperties::COLOR_NTP_SHORTCUT) \ + E_CPONLY(kColorNewTabPageMostVisitedTileBackgroundUnthemed) \ E(kColorNewTabPageSectionBorder, ThemeProperties::COLOR_NTP_SECTION_BORDER) \ E(kColorNewTabPageText, ThemeProperties::COLOR_NTP_TEXT) \ + E_CPONLY(kColorNewTabPageTextUnthemed) \ E(kColorNewTabPageTextLight, ThemeProperties::COLOR_NTP_TEXT_LIGHT) \ /* Omnibox colors. */ \ E(kColorOmniboxBackground, ThemeProperties::COLOR_OMNIBOX_BACKGROUND) \
diff --git a/chrome/browser/ui/color/chrome_color_mixer.cc b/chrome/browser/ui/color/chrome_color_mixer.cc index 1b6c7fd..4e25be5 100644 --- a/chrome/browser/ui/color/chrome_color_mixer.cc +++ b/chrome/browser/ui/color/chrome_color_mixer.cc
@@ -247,13 +247,21 @@ mixer[kColorNewTabPageHeader] = {SkColorSetRGB(0x96, 0x96, 0x96)}; mixer[kColorNewTabPageLink] = {dark_mode ? gfx::kGoogleBlue300 : SkColorSetRGB(0x06, 0x37, 0x74)}; - mixer[kColorNewTabPageLogo] = {SkColorSetRGB(0xEE, 0xEE, 0xEE)}; - mixer[kColorNewTabPageMostVisitedTileBackground] = { - dark_mode ? gfx::kGoogleGrey900 : gfx::kGoogleGrey100}; + mixer[kColorNewTabPageLogo] = {kColorNewTabPageLogoUnthemed}; + mixer[kColorNewTabPageLogoUnthemed] = {SkColorSetRGB(0xEE, 0xEE, 0xEE)}; + if (dark_mode) { + mixer[kColorNewTabPageMostVisitedTileBackground] = {gfx::kGoogleGrey900}; + } else { + mixer[kColorNewTabPageMostVisitedTileBackground] = { + kColorNewTabPageMostVisitedTileBackgroundUnthemed}; + } + mixer[kColorNewTabPageMostVisitedTileBackgroundUnthemed] = { + gfx::kGoogleGrey100}; mixer[kColorNewTabPageSectionBorder] = ui::SetAlpha(kColorNewTabPageHeader, 0x50); mixer[kColorNewTabPageText] = {dark_mode ? gfx::kGoogleGrey200 : SK_ColorBLACK}; + mixer[kColorNewTabPageTextUnthemed] = {gfx::kGoogleGrey050}; mixer[kColorNewTabPageTextLight] = IncreaseLightness(kColorNewTabPageText, 0.40); mixer[kColorOmniboxBackground] = {dark_mode ? gfx::kGoogleGrey900
diff --git a/chrome/browser/ui/color/tools/dump_colors.cc b/chrome/browser/ui/color/tools/dump_colors.cc index f125f7a9..aa5275b8 100644 --- a/chrome/browser/ui/color/tools/dump_colors.cc +++ b/chrome/browser/ui/color/tools/dump_colors.cc
@@ -51,7 +51,8 @@ auto contrast_mode) { const ui::ColorProviderManager::Key key = { color_mode, contrast_mode, - ui::ColorProviderManager::SystemTheme::kDefault, nullptr}; + ui::ColorProviderManager::SystemTheme::kDefault, + ui::ColorProviderManager::FrameType::kChromium, nullptr}; ui::AddColorMixers(provider, key); AddChromeColorMixers(provider, key); };
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller.h b/chrome/browser/ui/exclusive_access/fullscreen_controller.h index 112cf0b2a..2c7a32b 100644 --- a/chrome/browser/ui/exclusive_access/fullscreen_controller.h +++ b/chrome/browser/ui/exclusive_access/fullscreen_controller.h
@@ -128,9 +128,13 @@ // |web_contents| represents the tab that requests to no longer be fullscreen. void ExitFullscreenModeForTab(content::WebContents* web_contents); + base::WeakPtr<FullscreenController> GetWeakPtr() { + return ptr_factory_.GetWeakPtr(); + } + // Platform Fullscreen /////////////////////////////////////////////////////// - // Overrde from ExclusiveAccessControllerBase. + // Override from ExclusiveAccessControllerBase. void OnTabDeactivated(content::WebContents* web_contents) override; void OnTabDetachedFromView(content::WebContents* web_contents) override; void OnTabClosing(content::WebContents* web_contents) override;
diff --git a/chrome/browser/ui/page_action/page_action_icon_type.h b/chrome/browser/ui/page_action/page_action_icon_type.h index 0635c06a..46741256 100644 --- a/chrome/browser/ui/page_action/page_action_icon_type.h +++ b/chrome/browser/ui/page_action/page_action_icon_type.h
@@ -23,6 +23,7 @@ kSendTabToSelf, kSharedClipboard, kSharingHub, + kSideSearch, kSmsRemoteFetcher, kTranslate, kVirtualCardManualFallback,
diff --git a/chrome/browser/ui/views/autofill/payments/payments_view_util.cc b/chrome/browser/ui/views/autofill/payments/payments_view_util.cc index 053de998..fe0cc0f 100644 --- a/chrome/browser/ui/views/autofill/payments/payments_view_util.cc +++ b/chrome/browser/ui/views/autofill/payments/payments_view_util.cc
@@ -168,9 +168,15 @@ LegalMessageView::LegalMessageView(const LegalMessageLines& legal_message_lines, LinkClickedCallback callback) { SetOrientation(views::BoxLayout::Orientation::kVertical); + SetBetweenChildSpacing(ChromeLayoutProvider::Get()->GetDistanceMetric( + DISTANCE_RELATED_CONTROL_VERTICAL_SMALL)); for (const LegalMessageLine& line : legal_message_lines) { + // To ensure spacing between child paragraphs, all legal message lines are + // enclosed in their own view. + auto* line_view_ptr = + AddChildView(std::make_unique<views::BoxLayoutView>()); views::StyledLabel* label = - AddChildView(std::make_unique<views::StyledLabel>()); + line_view_ptr->AddChildView(std::make_unique<views::StyledLabel>()); label->SetText(line.text()); label->SetTextContext(views::style::CONTEXT_DIALOG_BODY_TEXT); label->SetDefaultTextStyle(views::style::STYLE_SECONDARY);
diff --git a/chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.cc b/chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.cc index 7b2501e..9526530a 100644 --- a/chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.cc +++ b/chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.cc
@@ -86,9 +86,13 @@ if (web_contents) { Browser* browser = chrome::FindBrowserWithWebContents(web_contents); // |browser| can be null in tests. - if (browser) + if (browser) { fullscreen_observation_.Observe( browser->exclusive_access_manager()->fullscreen_controller()); + fullscreen_controller_ = browser->exclusive_access_manager() + ->fullscreen_controller() + ->GetWeakPtr(); + } } // TODO(pbos): Removing this seems to crash on linux-ozone-rel which seems // really wrong. If we need the accessible role before ShowForReason() we @@ -97,7 +101,9 @@ SetAccessibleRole(GetAccessibleRoleForReason(display_reason_)); } -LocationBarBubbleDelegateView::~LocationBarBubbleDelegateView() = default; +LocationBarBubbleDelegateView::~LocationBarBubbleDelegateView() { + CHECK(!fullscreen_controller_.WasInvalidated()); +} void LocationBarBubbleDelegateView::ShowForReason(DisplayReason reason, bool allow_refocus_alert) {
diff --git a/chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.h b/chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.h index 43354de..0091b10 100644 --- a/chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.h +++ b/chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.h
@@ -113,6 +113,10 @@ base::ScopedObservation<FullscreenController, FullscreenObserver> fullscreen_observation_{this}; + // Use to track down potential UaF. See https://crbug.com/1304280. Remove this + // code when issue is fixed. + base::WeakPtr<FullscreenController> fullscreen_controller_; + // A flag controlling bubble closure when the main frame navigates to a // different origin. bool close_on_main_frame_origin_navigation_ = false;
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc index cda21950..b966ff4 100644 --- a/chrome/browser/ui/views/location_bar/location_bar_view.cc +++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -138,6 +138,10 @@ #include "ui/views/view_utils.h" #include "ui/views/widget/widget.h" +#if BUILDFLAG(ENABLE_SIDE_SEARCH) +#include "chrome/browser/ui/side_search/side_search_utils.h" +#endif // BUILDFLAG(ENABLE_SIDE_SEARCH) + namespace { int IncrementalMinimumWidth(const views::View* view) { @@ -312,6 +316,10 @@ if (!base::FeatureList::IsEnabled(features::kLinkCapturingUiUpdate)) params.types_enabled.push_back(PageActionIconType::kIntentPicker); params.types_enabled.push_back(PageActionIconType::kPwaInstall); +#if BUILDFLAG(ENABLE_SIDE_SEARCH) + if (side_search::IsDSESupportEnabled(profile_)) + params.types_enabled.push_back(PageActionIconType::kSideSearch); +#endif // BUILDFLAG(ENABLE_SIDE_SEARCH) params.types_enabled.push_back(PageActionIconType::kFind); params.types_enabled.push_back(PageActionIconType::kTranslate); params.types_enabled.push_back(PageActionIconType::kZoom);
diff --git a/chrome/browser/ui/views/location_bar/zoom_bubble_view_browsertest.cc b/chrome/browser/ui/views/location_bar/zoom_bubble_view_browsertest.cc index 5226ef0..e6d820d 100644 --- a/chrome/browser/ui/views/location_bar/zoom_bubble_view_browsertest.cc +++ b/chrome/browser/ui/views/location_bar/zoom_bubble_view_browsertest.cc
@@ -175,6 +175,11 @@ chrome::ToggleFullscreenMode(browser()); waiter.Wait(); } + +#if BUILDFLAG(IS_MAC) + // Let the message loop run so that `fake_fullscreen` finishes its transition. + base::RunLoop().RunUntilIdle(); +#endif } #if BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/ui/views/page_action/page_action_icon_controller.cc b/chrome/browser/ui/views/page_action/page_action_icon_controller.cc index 0caeec9..a212d0583 100644 --- a/chrome/browser/ui/views/page_action/page_action_icon_controller.cc +++ b/chrome/browser/ui/views/page_action/page_action_icon_controller.cc
@@ -39,10 +39,15 @@ #include "chrome/browser/ui/views/toolbar/toolbar_icon_container_view.h" #include "chrome/browser/ui/views/translate/translate_icon_view.h" #include "chrome/browser/ui/views/webauthn/webauthn_icon_view.h" +#include "chrome/common/chrome_features.h" #include "content/public/common/content_features.h" #include "ui/views/animation/ink_drop.h" #include "ui/views/layout/box_layout.h" +#if BUILDFLAG(ENABLE_SIDE_SEARCH) +#include "chrome/browser/ui/views/side_search/side_search_icon_view.h" +#endif // BUILDFLAG(ENABLE_SIDE_SEARCH) + PageActionIconController::PageActionIconController() = default; PageActionIconController::~PageActionIconController() = default; @@ -206,6 +211,15 @@ }), base::BindRepeating(SharingDialogView::GetAsBubble))); break; + case PageActionIconType::kSideSearch: +#if BUILDFLAG(ENABLE_SIDE_SEARCH) + DCHECK(params.command_updater); + add_page_action_icon( + type, std::make_unique<SideSearchIconView>( + params.command_updater, params.icon_label_bubble_delegate, + params.page_action_icon_delegate, params.browser)); +#endif // BUILDFLAG(ENABLE_SIDE_SEARCH) + break; case PageActionIconType::kTranslate: DCHECK(params.command_updater); add_page_action_icon(
diff --git a/chrome/browser/ui/views/side_search/side_search_browser_controller.cc b/chrome/browser/ui/views/side_search/side_search_browser_controller.cc index c5c74c4..2f8997f 100644 --- a/chrome/browser/ui/views/side_search/side_search_browser_controller.cc +++ b/chrome/browser/ui/views/side_search/side_search_browser_controller.cc
@@ -12,6 +12,7 @@ #include "chrome/browser/ui/browser_element_identifiers.h" #include "chrome/browser/ui/chrome_pages.h" #include "chrome/browser/ui/layout_constants.h" +#include "chrome/browser/ui/page_action/page_action_icon_type.h" #include "chrome/browser/ui/side_search/side_search_utils.h" #include "chrome/browser/ui/ui_features.h" #include "chrome/browser/ui/user_education/feature_promo_controller.h" @@ -330,9 +331,8 @@ toolbar_button->SetVectorIcon(kWebIcon); #endif - toolbar_button->SetCallback( - base::BindRepeating(&SideSearchBrowserController::SidePanelButtonPressed, - base::Unretained(this))); + toolbar_button->SetCallback(base::BindRepeating( + &SideSearchBrowserController::ToggleSidePanel, base::Unretained(this))); toolbar_button->SetVisible(false); toolbar_button->SetEnabled(true); @@ -340,6 +340,13 @@ return toolbar_button; } +void SideSearchBrowserController::ToggleSidePanel() { + if (GetSidePanelToggledOpen()) + CloseSidePanel(SideSearchCloseActionType::kTapOnSideSearchToolbarButton); + else + OpenSidePanel(); +} + bool SideSearchBrowserController::GetSidePanelToggledOpen() const { auto* active_contents = browser_view_->GetActiveWebContents(); return active_contents @@ -348,13 +355,6 @@ : false; } -void SideSearchBrowserController::SidePanelButtonPressed() { - if (GetSidePanelToggledOpen()) - CloseSidePanel(SideSearchCloseActionType::kTapOnSideSearchToolbarButton); - else - OpenSidePanel(); -} - void SideSearchBrowserController::SidePanelCloseButtonPressed() { CloseSidePanel(SideSearchCloseActionType::kTapOnSideSearchCloseButton); } @@ -435,20 +435,28 @@ ? tab_contents_helper->GetSidePanelContents() : nullptr); side_panel_->SetVisible(will_show_side_panel); - toolbar_button_->SetHighlighted(will_show_side_panel); - toolbar_button_->SetAccessibleName(l10n_util::GetStringUTF16( - will_show_side_panel - ? IDS_ACCNAME_SIDE_SEARCH_TOOLBAR_BUTTON_ACTIVATED - : IDS_ACCNAME_SIDE_SEARCH_TOOLBAR_BUTTON_NOT_ACTIVATED)); - // The toolbar button should remain visible in the toolbar as a side panel can - // be shown for the active tab. - if (toolbar_button_->GetVisible() != can_show_side_panel_for_page) { - toolbar_button_->SetVisible(can_show_side_panel_for_page); - RecordSideSearchAvailabilityChanged( - can_show_side_panel_for_page - ? SideSearchAvailabilityChangeType::kBecomeAvailable - : SideSearchAvailabilityChangeType::kBecomeUnavailable); + // Update the side panel entrypoints - either the page action or the toolbar + // button. + // TODO(tluk): Split the entrypoint implementations out into a separate class. + browser_view_->UpdatePageActionIcon(PageActionIconType::kSideSearch); + + if (toolbar_button_) { + toolbar_button_->SetHighlighted(will_show_side_panel); + toolbar_button_->SetAccessibleName(l10n_util::GetStringUTF16( + will_show_side_panel + ? IDS_ACCNAME_SIDE_SEARCH_TOOLBAR_BUTTON_ACTIVATED + : IDS_ACCNAME_SIDE_SEARCH_TOOLBAR_BUTTON_NOT_ACTIVATED)); + + // The toolbar button should remain visible in the toolbar as a side panel + // can be shown for the active tab. + if (toolbar_button_->GetVisible() != can_show_side_panel_for_page) { + toolbar_button_->SetVisible(can_show_side_panel_for_page); + RecordSideSearchAvailabilityChanged( + can_show_side_panel_for_page + ? SideSearchAvailabilityChangeType::kBecomeAvailable + : SideSearchAvailabilityChangeType::kBecomeUnavailable); + } } // Once the anchor element is visible, maybe show promo.
diff --git a/chrome/browser/ui/views/side_search/side_search_browser_controller.h b/chrome/browser/ui/views/side_search/side_search_browser_controller.h index 4439e98..33db256 100644 --- a/chrome/browser/ui/views/side_search/side_search_browser_controller.h +++ b/chrome/browser/ui/views/side_search/side_search_browser_controller.h
@@ -5,6 +5,7 @@ #ifndef CHROME_BROWSER_UI_VIEWS_SIDE_SEARCH_SIDE_SEARCH_BROWSER_CONTROLLER_H_ #define CHROME_BROWSER_UI_VIEWS_SIDE_SEARCH_SIDE_SEARCH_BROWSER_CONTROLLER_H_ +#include "base/memory/raw_ptr.h" #include "base/memory/weak_ptr.h" #include "base/scoped_observation.h" #include "chrome/browser/ui/side_search/side_search_metrics.h" @@ -67,15 +68,15 @@ bool GetSidePanelToggledOpen() const; + // Toggles panel visibility. + void ToggleSidePanel(); + private: // Gets and sets the toggled state of the side panel. If called with // kSideSearchStatePerTab enabled this determines whether the side panel // should be open for the currently active tab. void SetSidePanelToggledOpen(bool toggled_open); - // Toggles panel visibility on side panel toolbar button press. - void SidePanelButtonPressed(); - // Closes side panel on close button press. void SidePanelCloseButtonPressed(); @@ -98,10 +99,10 @@ base::CallbackListSubscription web_view_visibility_subscription_; - ToolbarButton* toolbar_button_; - SidePanel* const side_panel_; - BrowserView* const browser_view_; - views::WebView* const web_view_; + raw_ptr<ToolbarButton> toolbar_button_ = nullptr; + raw_ptr<SidePanel> const side_panel_; + raw_ptr<BrowserView> const browser_view_; + raw_ptr<views::WebView> const web_view_; // Tracks and stores the last focused view which is not the // `side_panel_` or any of its children. Used to restore focus once
diff --git a/chrome/browser/ui/views/side_search/side_search_icon_view.cc b/chrome/browser/ui/views/side_search/side_search_icon_view.cc new file mode 100644 index 0000000..55553c1 --- /dev/null +++ b/chrome/browser/ui/views/side_search/side_search_icon_view.cc
@@ -0,0 +1,73 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/views/side_search/side_search_icon_view.h" + +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/side_search/side_search_tab_contents_helper.h" +#include "chrome/browser/ui/views/frame/browser_view.h" +#include "chrome/browser/ui/views/side_search/side_search_browser_controller.h" +#include "chrome/grit/generated_resources.h" +#include "components/vector_icons/vector_icons.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/metadata/metadata_impl_macros.h" + +SideSearchIconView::SideSearchIconView( + CommandUpdater* command_updater, + IconLabelBubbleView::Delegate* icon_label_bubble_delegate, + PageActionIconView::Delegate* page_action_icon_delegate, + Browser* browser) + : PageActionIconView(nullptr, + 0, + icon_label_bubble_delegate, + page_action_icon_delegate), + browser_(browser) { + SetVisible(false); + SetLabel(l10n_util::GetStringUTF16(IDS_TOOLTIP_SIDE_SEARCH_TOOLBAR_BUTTON)); +} + +SideSearchIconView::~SideSearchIconView() = default; + +void SideSearchIconView::UpdateImpl() { + content::WebContents* active_contents = GetWebContents(); + if (!active_contents) + return; + + if (active_contents->IsCrashed()) { + SetVisible(false); + return; + } + + // Only show the page action button if the side panel is showable for this + // active web contents and is not currently toggled open. + // TODO(tluk): Setup conditions for `AnimateIn()`. + auto* tab_contents_helper = + SideSearchTabContentsHelper::FromWebContents(active_contents); + const bool should_show = + tab_contents_helper->CanShowSidePanelForCommittedNavigation() && + !tab_contents_helper->toggled_open(); + SetVisible(should_show); +} + +void SideSearchIconView::OnExecuting(PageActionIconView::ExecuteSource source) { + auto* side_search_browser_controller = + BrowserView::GetBrowserViewForBrowser(browser_)->side_search_controller(); + side_search_browser_controller->ToggleSidePanel(); +} + +views::BubbleDialogDelegate* SideSearchIconView::GetBubble() const { + return nullptr; +} + +const gfx::VectorIcon& SideSearchIconView::GetVectorIcon() const { + return vector_icons::kSearchIcon; +} + +std::u16string SideSearchIconView::GetTextForTooltipAndAccessibleName() const { + return l10n_util::GetStringUTF16(IDS_TOOLTIP_SIDE_SEARCH_TOOLBAR_BUTTON); +} + +BEGIN_METADATA(SideSearchIconView, PageActionIconView) +END_METADATA
diff --git a/chrome/browser/ui/views/side_search/side_search_icon_view.h b/chrome/browser/ui/views/side_search/side_search_icon_view.h new file mode 100644 index 0000000..eacd10b7 --- /dev/null +++ b/chrome/browser/ui/views/side_search/side_search_icon_view.h
@@ -0,0 +1,40 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_VIEWS_SIDE_SEARCH_SIDE_SEARCH_ICON_VIEW_H_ +#define CHROME_BROWSER_UI_VIEWS_SIDE_SEARCH_SIDE_SEARCH_ICON_VIEW_H_ + +#include "base/memory/raw_ptr.h" +#include "chrome/browser/ui/views/page_action/page_action_icon_view.h" +#include "ui/base/metadata/metadata_header_macros.h" + +class Browser; + +// A search icon that appears when the side search feature is available. Opens +// the side panel to the available SRP. +class SideSearchIconView : public PageActionIconView { + public: + METADATA_HEADER(SideSearchIconView); + explicit SideSearchIconView( + CommandUpdater* command_updater, + IconLabelBubbleView::Delegate* icon_label_bubble_delegate, + PageActionIconView::Delegate* page_action_icon_delegate, + Browser* browser); + SideSearchIconView(const SideSearchIconView&) = delete; + SideSearchIconView& operator=(const SideSearchIconView&) = delete; + ~SideSearchIconView() override; + + protected: + // PageActionIconView: + void UpdateImpl() override; + void OnExecuting(PageActionIconView::ExecuteSource source) override; + views::BubbleDialogDelegate* GetBubble() const override; + const gfx::VectorIcon& GetVectorIcon() const override; + std::u16string GetTextForTooltipAndAccessibleName() const override; + + private: + raw_ptr<Browser> browser_ = nullptr; +}; + +#endif // CHROME_BROWSER_UI_VIEWS_SIDE_SEARCH_SIDE_SEARCH_ICON_VIEW_H_
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.cc b/chrome/browser/ui/views/toolbar/toolbar_view.cc index 04d47a83..b02bd62 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_view.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_view.cc
@@ -129,6 +129,7 @@ #endif #if BUILDFLAG(ENABLE_SIDE_SEARCH) +#include "chrome/browser/ui/side_search/side_search_utils.h" #include "chrome/browser/ui/views/side_search/side_search_browser_controller.h" #endif // BUILDFLAG(ENABLE_SIDE_SEARCH) @@ -314,7 +315,8 @@ #if BUILDFLAG(ENABLE_SIDE_SEARCH) // The side search button (if enabled) should sit between the location bar and // the other navigation buttons. - if (browser_view_->side_search_controller()) { + if (browser_view_->side_search_controller() && + !side_search::IsDSESupportEnabled(browser_->profile())) { left_side_panel_button_ = AddChildView( browser_view_->side_search_controller()->CreateToolbarButton()); }
diff --git a/chrome/browser/ui/web_applications/app_browser_controller.cc b/chrome/browser/ui/web_applications/app_browser_controller.cc index 93a3004..cd59f93 100644 --- a/chrome/browser/ui/web_applications/app_browser_controller.cc +++ b/chrome/browser/ui/web_applications/app_browser_controller.cc
@@ -8,6 +8,7 @@ #include "base/feature_list.h" #include "base/strings/string_piece.h" #include "base/strings/utf_string_conversions.h" +#include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ssl/security_state_tab_helper.h" @@ -21,6 +22,7 @@ #include "chrome/browser/web_applications/system_web_apps/system_web_app_delegate.h" #include "chrome/browser/web_applications/system_web_apps/system_web_app_types.h" #include "chrome/common/chrome_features.h" +#include "chrome/common/pref_names.h" #include "chrome/common/themes/autogenerated_theme_util.h" #include "chrome/grit/generated_resources.h" #include "components/security_state/core/security_state.h" @@ -376,6 +378,15 @@ return theme_pack_.get(); } +bool AppBrowserController::ShouldUseCustomFrame() const { +#if BUILDFLAG(IS_LINUX) + return browser_->profile()->GetPrefs()->GetBoolean( + prefs::kUseCustomChromeFrame); +#else + return true; +#endif +} + void AppBrowserController::OnReceivedInitialURL() { UpdateCustomTabBarVisibility(/*animate=*/false);
diff --git a/chrome/browser/ui/web_applications/app_browser_controller.h b/chrome/browser/ui/web_applications/app_browser_controller.h index 1d372ec..dbc33c9 100644 --- a/chrome/browser/ui/web_applications/app_browser_controller.h +++ b/chrome/browser/ui/web_applications/app_browser_controller.h
@@ -199,6 +199,7 @@ // BrowserThemeProviderDelegate: CustomThemeSupplier* GetThemeSupplier() const override; + bool ShouldUseCustomFrame() const override; void UpdateDraggableRegion(const SkRegion& region); const absl::optional<SkRegion>& draggable_region() const {
diff --git a/chrome/browser/ui/web_applications/share_target_utils.cc b/chrome/browser/ui/web_applications/share_target_utils.cc index 1ebf7c0..d66d20f0 100644 --- a/chrome/browser/ui/web_applications/share_target_utils.cc +++ b/chrome/browser/ui/web_applications/share_target_utils.cc
@@ -171,10 +171,9 @@ names.push_back(shared_field.name); values.push_back(shared_field.value); is_value_file_uris.push_back(false); - filenames.emplace_back(std::string()); + filenames.emplace_back(); types.push_back("text/plain"); - data_pipe_getters.emplace_back( - mojo::PendingRemote<network::mojom::DataPipeGetter>()); + data_pipe_getters.emplace_back(); } if (share_target.enctype == apps::ShareTarget::Enctype::kMultipartFormData) {
diff --git a/chrome/browser/ui/web_applications/web_app_browsertest.cc b/chrome/browser/ui/web_applications/web_app_browsertest.cc index 02f7923..232a5f083 100644 --- a/chrome/browser/ui/web_applications/web_app_browsertest.cc +++ b/chrome/browser/ui/web_applications/web_app_browsertest.cc
@@ -1711,6 +1711,11 @@ EXPECT_TRUE( popup_browser->CanSupportWindowFeature(Browser::FEATURE_LOCATIONBAR)); + +#if BUILDFLAG(IS_MAC) + // Let the message loop run so that `fake_fullscreen` finishes its transition. + base::RunLoop().RunUntilIdle(); +#endif } // Make sure chrome://web-app-internals page loads fine.
diff --git a/chrome/browser/ui/webui/app_management/app_management_page_handler.cc b/chrome/browser/ui/webui/app_management/app_management_page_handler.cc index 4db37b3a..a85cacb 100644 --- a/chrome/browser/ui/webui/app_management/app_management_page_handler.cc +++ b/chrome/browser/ui/webui/app_management/app_management_page_handler.cc
@@ -354,21 +354,15 @@ const apps::AppUpdate& update) { auto app = app_management::mojom::App::New(); app->id = update.AppId(); - app->type = apps::ConvertMojomAppTypToAppType(update.AppType()); + app->type = update.AppType(); app->title = update.Name(); for (const auto& permission : update.Permissions()) { - if (permission->permission_type == apps::mojom::PermissionType::kStorage && + if (permission->permission_type == apps::PermissionType::kStorage && ShouldHideStoragePermission(update.AppId())) { continue; } - app_management::mojom::PermissionType permission_type = - mojo::EnumTraits<app_management::mojom::PermissionType, - apps::PermissionType>:: - ToMojom(apps::ConvertMojomPermissionTypeToPermissionType( - permission->permission_type)); - app->permissions[permission_type] = - apps::ConvertMojomPermissionToPermission(permission); + app->permissions[permission->permission_type] = permission->Clone(); } app->install_reason = update.InstallReason(); @@ -404,7 +398,7 @@ // TODO(crbug/1245293): implement on Chrome OS. #if !BUILDFLAG(IS_CHROMEOS) - if (update.AppType() == apps::mojom::AppType::kWeb) { + if (update.AppType() == apps::AppType::kWeb) { auto* provider = web_app::WebAppProvider::GetForWebApps(profile_); const bool fh_enabled = !provider->registrar().IsAppFileHandlerPermissionBlocked(app->id);
diff --git a/chrome/browser/ui/webui/chromeos/add_supervision/add_supervision_handler_utils.cc b/chrome/browser/ui/webui/chromeos/add_supervision/add_supervision_handler_utils.cc index c9a6bbf3..674fe5f 100644 --- a/chrome/browser/ui/webui/chromeos/add_supervision/add_supervision_handler_utils.cc +++ b/chrome/browser/ui/webui/chromeos/add_supervision/add_supervision_handler_utils.cc
@@ -9,11 +9,11 @@ #include "chrome/browser/supervised_user/supervised_user_service.h" #include "chrome/browser/supervised_user/supervised_user_service_factory.h" #include "chrome/browser/ui/webui/chromeos/add_supervision/add_supervision_metrics_recorder.h" +#include "components/services/app_service/public/cpp/app_types.h" #include "components/services/app_service/public/cpp/app_update.h" -#include "components/services/app_service/public/mojom/types.mojom.h" bool ShouldIncludeAppUpdate(const apps::AppUpdate& app_update) { - return app_update.AppType() == apps::mojom::AppType::kArc && + return app_update.AppType() == apps::AppType::kArc && app_update.InstallReason() != apps::InstallReason::kSystem; }
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_handler.cc b/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_handler.cc index aaf7933..b91b257 100644 --- a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_handler.cc +++ b/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_handler.cc
@@ -4,6 +4,8 @@ #include "chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_handler.h" +#include <memory> + #include "ash/components/login/auth/challenge_response/cert_utils.h" #include "ash/components/login/auth/cryptohome_key_constants.h" #include "ash/constants/ash_features.h" @@ -304,9 +306,9 @@ } void LockScreenReauthHandler::CheckCredentials( - const UserContext& user_context) { + std::unique_ptr<UserContext> user_context) { Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByAccountId( - user_context.GetAccountId()); + user_context->GetAccountId()); if (!profile) { LOG(ERROR) << "Invalid account id"; return; @@ -316,7 +318,7 @@ weak_factory_.GetWeakPtr()); password_sync_manager_ = InSessionPasswordSyncManagerFactory::GetForProfile(profile); - password_sync_manager_->CheckCredentials(user_context, + password_sync_manager_->CheckCredentials(*user_context, password_changed_callback); }
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_handler.h b/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_handler.h index 567c06c..45c64e2 100644 --- a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_handler.h +++ b/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_handler.h
@@ -5,6 +5,7 @@ #ifndef CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_REAUTH_HANDLER_H_ #define CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_REAUTH_HANDLER_H_ +#include <memory> #include "base/memory/weak_ptr.h" #include "base/values.h" // TODO(https://crbug.com/1164001): move to forward declaration. @@ -61,7 +62,7 @@ void OnReauthDialogReadyForTesting(); - void CheckCredentials(const UserContext& user_context); + void CheckCredentials(std::unique_ptr<UserContext> user_context); void UpdateOrientationAndWidth();
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc index 412a2b43..9e2e1a40 100644 --- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -45,6 +45,7 @@ #include "chrome/browser/ash/certificate_provider/certificate_provider_service.h" #include "chrome/browser/ash/certificate_provider/certificate_provider_service_factory.h" #include "chrome/browser/ash/certificate_provider/pin_dialog_manager.h" +#include "chrome/browser/ash/login/helper.h" #include "chrome/browser/ash/login/reauth_stats.h" #include "chrome/browser/ash/login/saml/public_saml_url_fetcher.h" #include "chrome/browser/ash/login/saml/saml_metric_utils.h" @@ -817,10 +818,11 @@ signin_partition_name_, signin_partition_manager, base::BindOnce(&GaiaScreenHandler::OnCookieWaitTimeout, weak_factory_.GetWeakPtr()), - base::BindOnce(&LoginDisplayHost::CompleteLogin, - base::Unretained(LoginDisplayHost::default_host()))); + base::BindOnce([](std::unique_ptr<UserContext> user_context) { + LoginDisplayHost::default_host()->CompleteLogin(*user_context); + })); - pending_user_context_ = std::make_unique<UserContext>(); + auto user_context = std::make_unique<UserContext>(); SigninError error; if (!login::BuildUserContextForGaiaSignIn( login::GetUsertypeFromServicesString(services), @@ -829,15 +831,14 @@ SamlPasswordAttributes::FromJs(*password_attributes), GetSyncTrustedVaultKeysForUserContext(sync_trusted_vault_keys, gaia_id), - *extension_provided_client_cert_usage_observer_, - pending_user_context_.get(), &error)) { + *extension_provided_client_cert_usage_observer_, user_context.get(), + &error)) { LoginDisplayHost::default_host()->GetSigninUI()->ShowSigninError( error, /*details=*/std::string()); - pending_user_context_.reset(); return; } - online_login_helper_->SetUserContext(std::move(pending_user_context_)); + online_login_helper_->SetUserContext(std::move(user_context)); online_login_helper_->RequestCookiesAndCompleteAuthentication(); if (test_expects_complete_login_) {
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h index 35e0670e..f127e59 100644 --- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h
@@ -446,8 +446,6 @@ std::unique_ptr<OnlineLoginHelper> online_login_helper_; - std::unique_ptr<UserContext> pending_user_context_; - base::WeakPtrFactory<GaiaScreenHandler> weak_factory_{this}; };
diff --git a/chrome/browser/ui/webui/chromeos/login/online_login_helper.cc b/chrome/browser/ui/webui/chromeos/login/online_login_helper.cc index 626ea01d..82e95442 100644 --- a/chrome/browser/ui/webui/chromeos/login/online_login_helper.cc +++ b/chrome/browser/ui/webui/chromeos/login/online_login_helper.cc
@@ -172,7 +172,7 @@ on_cookie_timeout_callback_(std::move(on_cookie_timeout_callback)), complete_login_callback_(std::move(complete_login_callback)) {} -OnlineLoginHelper::~OnlineLoginHelper() {} +OnlineLoginHelper::~OnlineLoginHelper() = default; void OnlineLoginHelper::SetUserContext( std::unique_ptr<UserContext> pending_user_context) { @@ -244,18 +244,18 @@ } DCHECK(pending_user_context_); - UserContext user_context = *pending_user_context_; + auto user_context = std::move(pending_user_context_); pending_user_context_.reset(); oauth_code_listener_.reset(); cookie_waiting_timer_.reset(); - user_context.SetAuthCode(auth_code); + user_context->SetAuthCode(auth_code); if (!gaps_cookie.empty()) - user_context.SetGAPSCookie(gaps_cookie); + user_context->SetGAPSCookie(gaps_cookie); if (!rapt.empty()) - user_context.SetReauthProofToken(rapt); + user_context->SetReauthProofToken(rapt); - std::move(complete_login_callback_).Run(user_context); + std::move(complete_login_callback_).Run(std::move(user_context)); } } // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/login/online_login_helper.h b/chrome/browser/ui/webui/chromeos/login/online_login_helper.h index c436d9c..39971173 100644 --- a/chrome/browser/ui/webui/chromeos/login/online_login_helper.h +++ b/chrome/browser/ui/webui/chromeos/login/online_login_helper.h
@@ -5,6 +5,7 @@ #ifndef CHROME_BROWSER_UI_WEBUI_CHROMEOS_LOGIN_ONLINE_LOGIN_HELPER_H_ #define CHROME_BROWSER_UI_WEBUI_CHROMEOS_LOGIN_ONLINE_LOGIN_HELPER_H_ +#include <memory> #include <string> #include "ash/components/login/auth/cryptohome_authenticator.h" @@ -89,7 +90,8 @@ class OnlineLoginHelper : public network::mojom::CookieChangeListener { public: using OnCookieTimeoutCallback = base::OnceCallback<void(void)>; - using CompleteLoginCallback = base::OnceCallback<void(const UserContext&)>; + using CompleteLoginCallback = + base::OnceCallback<void(std::unique_ptr<UserContext>)>; explicit OnlineLoginHelper( std::string signin_partition_name,
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc index 85ff890..e087bcb 100644 --- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
@@ -250,6 +250,8 @@ IDS_ENTERPRISE_ENROLLMENT_AUTH_INSECURE_URL_ERROR); } +void SigninScreenHandler::Initialize() {} + void SigninScreenHandler::RegisterMessages() { AddCallback("launchIncognito", &SigninScreenHandler::HandleLaunchIncognito); AddCallback("offlineLogin", &SigninScreenHandler::HandleOfflineLogin); @@ -268,8 +270,6 @@ void SigninScreenHandler::Show() { CHECK(delegate_); - - ShowImpl(); histogram_helper_->OnScreenShow(); } @@ -292,13 +292,6 @@ // SigninScreenHandler, private: ----------------------------------------------- -void SigninScreenHandler::ShowImpl() { - if (!page_is_ready()) { - show_on_init_ = true; - return; - } -} - // TODO(antrim@): split this method into small parts. // TODO(antrim@): move this logic to GaiaScreenHandler. void SigninScreenHandler::UpdateStateInternal(NetworkError::ErrorReason reason, @@ -454,14 +447,6 @@ gaia_screen_handler_->ReloadGaia(force_reload); } -void SigninScreenHandler::Initialize() { - // `delegate_` is null when we are preloading the lock screen. - if (delegate_ && show_on_init_) { - show_on_init_ = false; - ShowImpl(); - } -} - void SigninScreenHandler::RegisterPrefs(PrefRegistrySimple* registry) { // The pref is deprecated. Remove around 09/2022 (https://crbug.com/1297407) registry->RegisterDictionaryPref(prefs::kUsersLastInputMethod);
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h index 4e07158..76bc050 100644 --- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
@@ -115,8 +115,6 @@ friend class ash::LoginDisplayHostMojo; friend class ReportDnsCacheClearedOnUIThread; - void ShowImpl(); - void UpdateStateInternal(NetworkError::ErrorReason reason, bool force_update); void SetupAndShowOfflineMessage(NetworkStateInformer::State state, NetworkError::ErrorReason reason); @@ -169,9 +167,6 @@ // A delegate that glues this handler with backend LoginDisplay. SigninScreenHandlerDelegate* delegate_ = nullptr; - // Whether screen should be shown right after initialization. - bool show_on_init_ = false; - // Network state informer used to keep signin screen up. scoped_refptr<NetworkStateInformer> network_state_informer_;
diff --git a/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.cc b/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.cc index 2f1761a..e961ce6 100644 --- a/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.cc +++ b/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.cc
@@ -33,6 +33,7 @@ #include "chrome/browser/search_engines/template_url_service_factory.h" #include "chrome/browser/themes/theme_properties.h" #include "chrome/browser/ui/chrome_select_file_policy.h" +#include "chrome/browser/ui/color/chrome_color_id.h" #include "chrome/browser/ui/hats/hats_service.h" #include "chrome/browser/ui/hats/hats_service_factory.h" #include "chrome/browser/ui/omnibox/omnibox_theme.h" @@ -57,6 +58,7 @@ #include "services/network/public/mojom/url_response_head.mojom.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/theme_provider.h" +#include "ui/color/color_provider.h" #include "ui/gfx/color_palette.h" #include "ui/gfx/color_utils.h" #include "ui/native_theme/native_theme.h" @@ -66,6 +68,7 @@ const int64_t kMaxDownloadBytes = 1024 * 1024; new_tab_page::mojom::ThemePtr MakeTheme( + const ui::ColorProvider& color_provider, const ui::ThemeProvider* theme_provider, ThemeService* theme_service, NtpCustomBackgroundService* ntp_custom_background_service) { @@ -79,23 +82,20 @@ ? ntp_custom_background_service->GetCustomBackground() : absl::nullopt; theme->is_default = theme_service->UsingDefaultTheme(); - theme->background_color = - theme_provider->GetColor(ThemeProperties::COLOR_NTP_BACKGROUND); + theme->background_color = color_provider.GetColor(kColorNewTabPageBackground); SkColor text_color; if (custom_background.has_value()) { - text_color = gfx::kGoogleGrey050; - most_visited->background_color = ThemeProperties::GetDefaultColor( - ThemeProperties::COLOR_NTP_SHORTCUT, false); - theme->logo_color = ThemeProperties::GetDefaultColor( - ThemeProperties::COLOR_NTP_LOGO, false); + text_color = color_provider.GetColor(kColorNewTabPageTextUnthemed); + most_visited->background_color = color_provider.GetColor( + kColorNewTabPageMostVisitedTileBackgroundUnthemed); + theme->logo_color = color_provider.GetColor(kColorNewTabPageLogoUnthemed); } else { - text_color = theme_provider->GetColor(ThemeProperties::COLOR_NTP_TEXT); + text_color = color_provider.GetColor(kColorNewTabPageText); most_visited->background_color = - theme_provider->GetColor(ThemeProperties::COLOR_NTP_SHORTCUT); + color_provider.GetColor(kColorNewTabPageMostVisitedTileBackground); if (theme_provider->GetDisplayProperty( ThemeProperties::NTP_LOGO_ALTERNATE) == 1) { - theme->logo_color = - theme_provider->GetColor(ThemeProperties::COLOR_NTP_LOGO); + theme->logo_color = color_provider.GetColor(kColorNewTabPageLogo); } } most_visited->use_white_tile_icon = @@ -173,8 +173,7 @@ theme->most_visited = std::move(most_visited); auto search_box = realbox::mojom::SearchBoxTheme::New(); - search_box->ntp_bg = - theme_provider->GetColor(ThemeProperties::COLOR_NTP_BACKGROUND); + search_box->ntp_bg = color_provider.GetColor(kColorNewTabPageBackground); search_box->bg = GetOmniboxColor(theme_provider, OmniboxPart::LOCATION_BAR_BACKGROUND); search_box->bg_hovered = @@ -384,8 +383,7 @@ ntp_custom_background_service_observation_.Observe( ntp_custom_background_service_.get()); promo_service_observation_.Observe(promo_service_.get()); - page_->SetTheme(MakeTheme(theme_provider_, theme_service_, - ntp_custom_background_service_)); + OnThemeChanged(); } NewTabPageHandler::~NewTabPageHandler() { @@ -848,18 +846,16 @@ } void NewTabPageHandler::OnNativeThemeUpdated(ui::NativeTheme* observed_theme) { - page_->SetTheme(MakeTheme(theme_provider_, theme_service_, - ntp_custom_background_service_)); + OnThemeChanged(); } void NewTabPageHandler::OnThemeChanged() { - page_->SetTheme(MakeTheme(theme_provider_, theme_service_, - ntp_custom_background_service_)); + page_->SetTheme(MakeTheme(web_contents_->GetColorProvider(), theme_provider_, + theme_service_, ntp_custom_background_service_)); } void NewTabPageHandler::OnCustomBackgroundImageUpdated() { - page_->SetTheme(MakeTheme(theme_provider_, theme_service_, - ntp_custom_background_service_)); + OnThemeChanged(); } void NewTabPageHandler::OnNtpCustomBackgroundServiceShuttingDown() {
diff --git a/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler_unittest.cc b/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler_unittest.cc index b846f8a..dfe338d 100644 --- a/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler_unittest.cc +++ b/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler_unittest.cc
@@ -20,6 +20,7 @@ #include "chrome/browser/themes/theme_properties.h" #include "chrome/browser/themes/theme_service.h" #include "chrome/browser/themes/theme_service_observer.h" +#include "chrome/browser/ui/color/chrome_color_id.h" #include "chrome/browser/ui/webui/new_tab_page/new_tab_page.mojom.h" #include "chrome/browser/ui/webui/webui_util.h" #include "chrome/common/pref_names.h" @@ -32,6 +33,7 @@ #include "components/search/ntp_features.h" #include "components/search_provider_logos/logo_common.h" #include "components/search_provider_logos/logo_service.h" +#include "content/public/browser/web_contents.h" #include "content/public/test/browser_task_environment.h" #include "content/public/test/test_web_contents_factory.h" #include "mojo/public/cpp/bindings/pending_receiver.h" @@ -44,6 +46,10 @@ #include "testing/gtest/include/gtest/gtest.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/base/theme_provider.h" +#include "ui/color/color_mixer.h" +#include "ui/color/color_provider_source.h" +#include "ui/color/color_recipe.h" +#include "ui/color/color_transform.h" #include "ui/gfx/color_palette.h" #include "url/gurl.h" @@ -79,6 +85,25 @@ MOCK_METHOD1(GetLogo, void(search_provider_logos::LogoObserver*)); }; +class MockColorProviderSource : public ui::ColorProviderSource { + public: + MockColorProviderSource() { color_provider_.GenerateColorMap(); } + MockColorProviderSource(const MockColorProviderSource&) = delete; + MockColorProviderSource& operator=(const MockColorProviderSource&) = delete; + ~MockColorProviderSource() override = default; + + const ui::ColorProvider* GetColorProvider() const override { + return &color_provider_; + } + + void SetColor(ui::ColorId id, SkColor color) { + color_provider_.SetColorForTesting(id, color); + } + + private: + ui::ColorProvider color_provider_; +}; + class MockThemeProvider : public ui::ThemeProvider { public: MOCK_CONST_METHOD1(GetImageSkiaNamed, gfx::ImageSkia*(int)); @@ -169,6 +194,7 @@ EXPECT_CALL(mock_ntp_custom_background_service_, RefreshBackgroundIfNeeded) .Times(1); webui::SetThemeProviderForTesting(&mock_theme_provider_); + web_contents_->SetColorProviderSource(&mock_color_provider_source_); handler_ = std::make_unique<NewTabPageHandler>( mojo::PendingReceiver<new_tab_page::mojom::PageHandler>(), mock_page_.BindAndGetRemote(), profile_.get(), @@ -221,6 +247,7 @@ mock_ntp_custom_background_service_; testing::NiceMock<MockThemeService> mock_theme_service_; MockLogoService mock_logo_service_; + MockColorProviderSource mock_color_provider_source_; testing::NiceMock<MockThemeProvider> mock_theme_provider_; MockPromoService& mock_promo_service_; content::TestWebContentsFactory factory_; @@ -241,17 +268,17 @@ })); ON_CALL(mock_ntp_custom_background_service_, GetCustomBackground()) .WillByDefault(testing::Return(absl::optional<CustomBackground>())); - ON_CALL(mock_theme_provider_, GetColor(ThemeProperties::COLOR_NTP_BACKGROUND)) - .WillByDefault(testing::Return(SkColorSetRGB(0, 0, 1))); - ON_CALL(mock_theme_provider_, GetColor(ThemeProperties::COLOR_NTP_TEXT)) - .WillByDefault(testing::Return(SkColorSetRGB(0, 0, 2))); + mock_color_provider_source_.SetColor(kColorNewTabPageBackground, + SkColorSetRGB(0, 0, 1)); + mock_color_provider_source_.SetColor(kColorNewTabPageText, + SkColorSetRGB(0, 0, 2)); ON_CALL(mock_theme_service_, UsingDefaultTheme()) .WillByDefault(testing::Return(false)); ON_CALL(mock_theme_provider_, GetDisplayProperty(ThemeProperties::NTP_LOGO_ALTERNATE)) .WillByDefault(testing::Return(1)); - ON_CALL(mock_theme_provider_, GetColor(ThemeProperties::COLOR_NTP_LOGO)) - .WillByDefault(testing::Return(SkColorSetRGB(0, 0, 3))); + mock_color_provider_source_.SetColor(kColorNewTabPageLogo, + SkColorSetRGB(0, 0, 3)); ON_CALL(mock_theme_service_, GetThemeID()) .WillByDefault(testing::Return("bar")); ON_CALL(mock_theme_provider_, @@ -264,8 +291,8 @@ .WillByDefault(testing::Return(true)); ON_CALL(mock_theme_provider_, HasCustomImage(IDR_THEME_NTP_BACKGROUND)) .WillByDefault(testing::Return(true)); - ON_CALL(mock_theme_provider_, GetColor(ThemeProperties::COLOR_NTP_SHORTCUT)) - .WillByDefault(testing::Return(SkColorSetRGB(0, 0, 4))); + mock_color_provider_source_.SetColor( + kColorNewTabPageMostVisitedTileBackground, SkColorSetRGB(0, 0, 4)); ON_CALL(mock_theme_provider_, GetColor(ThemeProperties::COLOR_OMNIBOX_BACKGROUND)) .WillByDefault(testing::Return(SkColorSetRGB(0, 0, 5))); @@ -368,13 +395,25 @@ custom_background.collection_id = "baz collection"; ON_CALL(mock_ntp_custom_background_service_, GetCustomBackground()) .WillByDefault(testing::Return(absl::make_optional(custom_background))); + mock_color_provider_source_.SetColor(kColorNewTabPageBackground, + SkColorSetRGB(0, 0, 1)); + mock_color_provider_source_.SetColor(kColorNewTabPageTextUnthemed, + SkColorSetRGB(0, 0, 2)); + mock_color_provider_source_.SetColor(kColorNewTabPageLogoUnthemed, + SkColorSetRGB(0, 0, 3)); + mock_color_provider_source_.SetColor( + kColorNewTabPageMostVisitedTileBackgroundUnthemed, + SkColorSetRGB(0, 0, 4)); ntp_custom_background_service_observer_->OnCustomBackgroundImageUpdated(); mock_page_.FlushForTesting(); ASSERT_TRUE(theme); EXPECT_TRUE(theme->is_custom_background); - EXPECT_EQ(gfx::kGoogleGrey050, theme->text_color); + EXPECT_EQ(SkColorSetRGB(0, 0, 1), theme->background_color); + EXPECT_EQ(SkColorSetRGB(0, 0, 2), theme->text_color); + EXPECT_EQ(SkColorSetRGB(0, 0, 3), theme->logo_color); + EXPECT_EQ(SkColorSetRGB(0, 0, 4), theme->most_visited->background_color); EXPECT_EQ("https://foo.com/img.png", theme->background_image->url); EXPECT_EQ("foo line", theme->background_image_attribution_1); EXPECT_EQ("bar line", theme->background_image_attribution_2);
diff --git a/chrome/browser/ui/webui/settings/ash/os_apps_page/app_notification_handler.cc b/chrome/browser/ui/webui/settings/ash/os_apps_page/app_notification_handler.cc index 2063da8..debd20b 100644 --- a/chrome/browser/ui/webui/settings/ash/os_apps_page/app_notification_handler.cc +++ b/chrome/browser/ui/webui/settings/ash/os_apps_page/app_notification_handler.cc
@@ -21,21 +21,18 @@ namespace { app_notification::mojom::AppPtr CreateAppPtr(const apps::AppUpdate& update) { - apps::PermissionPtr permission_copy; - for (const auto& permission : update.Permissions()) { - if (permission->permission_type == - apps::mojom::PermissionType::kNotifications) { - permission_copy = apps::ConvertMojomPermissionToPermission(permission); - break; - } - } - auto app = app_notification::mojom::App::New(); app->id = update.AppId(); app->title = update.Name(); - app->notification_permission = std::move(permission_copy); app->readiness = update.Readiness(); + for (const auto& permission : update.Permissions()) { + if (permission->permission_type == apps::PermissionType::kNotifications) { + app->notification_permission = permission->Clone(); + break; + } + } + return app; } @@ -46,11 +43,10 @@ } // Only kArc and kWeb apps are supported. - if (update.AppType() == apps::mojom::AppType::kArc || - update.AppType() == apps::mojom::AppType::kWeb) { + if (update.AppType() == apps::AppType::kArc || + update.AppType() == apps::AppType::kWeb) { for (const auto& permission : update.Permissions()) { - if (permission->permission_type == - apps::mojom::PermissionType::kNotifications) { + if (permission->permission_type == apps::PermissionType::kNotifications) { return true; } }
diff --git a/chrome/browser/ui/webui/settings/site_settings_handler.cc b/chrome/browser/ui/webui/settings/site_settings_handler.cc index 4c60200..8d9c5370 100644 --- a/chrome/browser/ui/webui/settings/site_settings_handler.cc +++ b/chrome/browser/ui/webui/settings/site_settings_handler.cc
@@ -56,6 +56,7 @@ #include "components/prefs/pref_change_registrar.h" #include "components/prefs/pref_service.h" #include "components/services/app_service/public/cpp/app_registry_cache.h" +#include "components/services/app_service/public/cpp/app_types.h" #include "components/services/app_service/public/cpp/app_update.h" #include "components/services/app_service/public/mojom/types.mojom.h" #include "components/site_engagement/content/site_engagement_service.h" @@ -172,8 +173,8 @@ apps::AppServiceProxyFactory::GetForProfile(profile) ->AppRegistryCache() .ForEachApp([&origins](const apps::AppUpdate& update) { - if (update.AppType() == apps::mojom::AppType::kWeb || - update.AppType() == apps::mojom::AppType::kSystemWeb) { + if (update.AppType() == apps::AppType::kWeb || + update.AppType() == apps::AppType::kSystemWeb) { // For web apps, |PublisherId()| is set to the start URL. const GURL start_url(update.PublisherId()); DCHECK(start_url.is_valid());
diff --git a/chrome/browser/web_applications/adjustments/link_capturing_pref_migration.cc b/chrome/browser/web_applications/adjustments/link_capturing_pref_migration.cc index cf2168d..d5dafd8b 100644 --- a/chrome/browser/web_applications/adjustments/link_capturing_pref_migration.cc +++ b/chrome/browser/web_applications/adjustments/link_capturing_pref_migration.cc
@@ -10,6 +10,7 @@ #include "chrome/browser/web_applications/web_app.h" #include "chrome/browser/web_applications/web_app_provider.h" #include "chrome/browser/web_applications/web_app_registrar.h" +#include "components/services/app_service/public/cpp/app_types.h" #include "components/services/app_service/public/cpp/types_util.h" namespace web_app { @@ -24,7 +25,7 @@ LinkCapturingPrefMigration::~LinkCapturingPrefMigration() = default; void LinkCapturingPrefMigration::OnAppUpdate(const apps::AppUpdate& update) { - if (update.AppType() != apps::mojom::AppType::kWeb) + if (update.AppType() != apps::AppType::kWeb) return; if (apps_util::IsInstalled(update.PriorReadiness()))
diff --git a/chrome/browser/web_applications/adjustments/preinstalled_web_app_duplication_fixer.cc b/chrome/browser/web_applications/adjustments/preinstalled_web_app_duplication_fixer.cc index 1875bdca..aa73fb13 100644 --- a/chrome/browser/web_applications/adjustments/preinstalled_web_app_duplication_fixer.cc +++ b/chrome/browser/web_applications/adjustments/preinstalled_web_app_duplication_fixer.cc
@@ -103,9 +103,9 @@ if (update.Readiness() != apps::Readiness::kReady) return; - if (update.GetAppType() == apps::AppType::kWeb) + if (update.AppType() == apps::AppType::kWeb) installed_web_apps.push_back(update.AppId()); - else if (update.GetAppType() == apps::AppType::kChromeApp) + else if (update.AppType() == apps::AppType::kChromeApp) installed_chrome_apps.push_back(update.AppId()); });
diff --git a/chrome/browser/web_applications/extensions/web_app_extension_shortcut.cc b/chrome/browser/web_applications/extensions/web_app_extension_shortcut.cc index 16905c23..1aaed0e 100644 --- a/chrome/browser/web_applications/extensions/web_app_extension_shortcut.cc +++ b/chrome/browser/web_applications/extensions/web_app_extension_shortcut.cc
@@ -163,10 +163,10 @@ extensions::IconsInfo::GetIconResource(extension, size, ExtensionIconSet::MATCH_EXACTLY); if (!resource.empty()) { - info_list.emplace_back(extensions::ImageLoader::ImageRepresentation( + info_list.emplace_back( resource, extensions::ImageLoader::ImageRepresentation::ALWAYS_RESIZE, gfx::Size(size, size), - GetScaleForResourceScaleFactor(ui::k100Percent))); + GetScaleForResourceScaleFactor(ui::k100Percent)); } } @@ -183,10 +183,9 @@ resource = extensions::IconsInfo::GetIconResource( extension, size, ExtensionIconSet::MATCH_SMALLER); } - info_list.emplace_back(extensions::ImageLoader::ImageRepresentation( + info_list.emplace_back( resource, extensions::ImageLoader::ImageRepresentation::ALWAYS_RESIZE, - gfx::Size(size, size), - GetScaleForResourceScaleFactor(ui::k100Percent))); + gfx::Size(size, size), GetScaleForResourceScaleFactor(ui::k100Percent)); } // |info_list| may still be empty at this point, in which case
diff --git a/chrome/browser/web_applications/system_web_apps/system_web_app_manager.cc b/chrome/browser/web_applications/system_web_apps/system_web_app_manager.cc index 2b83244..ee55562 100644 --- a/chrome/browser/web_applications/system_web_apps/system_web_app_manager.cc +++ b/chrome/browser/web_applications/system_web_apps/system_web_app_manager.cc
@@ -110,41 +110,36 @@ // TODO(crbug.com/1051229): Currently unused, will be hooked up // post-migration. We're making delegates for everything, and will then use // them in place of SystemAppInfos. - info_vec.emplace_back(std::make_unique<CameraSystemAppDelegate>(profile)); - info_vec.emplace_back( - std::make_unique<DiagnosticsSystemAppDelegate>(profile)); - info_vec.emplace_back(std::make_unique<OSSettingsSystemAppDelegate>(profile)); - info_vec.emplace_back(std::make_unique<CroshSystemAppDelegate>(profile)); - info_vec.emplace_back(std::make_unique<TerminalSystemAppDelegate>(profile)); - info_vec.emplace_back( - std::make_unique<ash::HelpAppSystemAppDelegate>(profile)); - info_vec.emplace_back(std::make_unique<MediaSystemAppDelegate>(profile)); - info_vec.emplace_back( + info_vec.push_back(std::make_unique<CameraSystemAppDelegate>(profile)); + info_vec.push_back(std::make_unique<DiagnosticsSystemAppDelegate>(profile)); + info_vec.push_back(std::make_unique<OSSettingsSystemAppDelegate>(profile)); + info_vec.push_back(std::make_unique<CroshSystemAppDelegate>(profile)); + info_vec.push_back(std::make_unique<TerminalSystemAppDelegate>(profile)); + info_vec.push_back(std::make_unique<ash::HelpAppSystemAppDelegate>(profile)); + info_vec.push_back(std::make_unique<MediaSystemAppDelegate>(profile)); + info_vec.push_back( std::make_unique<PrintManagementSystemAppDelegate>(profile)); - info_vec.emplace_back(std::make_unique<ScanningSystemAppDelegate>(profile)); - info_vec.emplace_back( - std::make_unique<ShimlessRMASystemAppDelegate>(profile)); - info_vec.emplace_back( + info_vec.push_back(std::make_unique<ScanningSystemAppDelegate>(profile)); + info_vec.push_back(std::make_unique<ShimlessRMASystemAppDelegate>(profile)); + info_vec.push_back( std::make_unique<ConnectivityDiagnosticsSystemAppDelegate>(profile)); - info_vec.emplace_back(std::make_unique<EcheSystemAppDelegate>(profile)); - info_vec.emplace_back( + info_vec.push_back(std::make_unique<EcheSystemAppDelegate>(profile)); + info_vec.push_back( std::make_unique<PersonalizationSystemAppDelegate>(profile)); - info_vec.emplace_back( + info_vec.push_back( std::make_unique<ShortcutCustomizationSystemAppDelegate>(profile)); - info_vec.emplace_back(std::make_unique<OSFeedbackAppDelegate>(profile)); - info_vec.emplace_back( - std::make_unique<FileManagerSystemAppDelegate>(profile)); - info_vec.emplace_back( - std::make_unique<ProjectorSystemWebAppDelegate>(profile)); - info_vec.emplace_back( + info_vec.push_back(std::make_unique<OSFeedbackAppDelegate>(profile)); + info_vec.push_back(std::make_unique<FileManagerSystemAppDelegate>(profile)); + info_vec.push_back(std::make_unique<ProjectorSystemWebAppDelegate>(profile)); + info_vec.push_back( std::make_unique<OsUrlHandlerSystemWebAppDelegate>(profile)); - info_vec.emplace_back( + info_vec.push_back( std::make_unique<FirmwareUpdateSystemAppDelegate>(profile)); - info_vec.emplace_back(std::make_unique<OsFlagsSystemWebAppDelegate>(profile)); + info_vec.push_back(std::make_unique<OsFlagsSystemWebAppDelegate>(profile)); #if !defined(OFFICIAL_BUILD) - info_vec.emplace_back(std::make_unique<DemoModeSystemAppDelegate>(profile)); - info_vec.emplace_back(std::make_unique<SampleSystemAppDelegate>(profile)); + info_vec.push_back(std::make_unique<DemoModeSystemAppDelegate>(profile)); + info_vec.push_back(std::make_unique<SampleSystemAppDelegate>(profile)); #endif // !defined(OFFICIAL_BUILD) SystemAppDelegateMap delegate_map;
diff --git a/chrome/browser/web_applications/system_web_apps/test/system_web_app_manager_browsertest.cc b/chrome/browser/web_applications/system_web_apps/test/system_web_app_manager_browsertest.cc index 1fd046c..e7effe6 100644 --- a/chrome/browser/web_applications/system_web_apps/test/system_web_app_manager_browsertest.cc +++ b/chrome/browser/web_applications/system_web_apps/test/system_web_app_manager_browsertest.cc
@@ -1102,8 +1102,8 @@ bool swa_found = false; app_service_proxy->AppRegistryCache().ForEachApp( [&](const apps::AppUpdate& app) { - if (app.AppType() == apps::mojom::AppType::kSystemWeb || - app.AppType() == apps::mojom::AppType::kWeb) { + if (app.AppType() == apps::AppType::kSystemWeb || + app.AppType() == apps::AppType::kWeb) { swa_found = true; } });
diff --git a/chrome/browser/web_applications/system_web_apps/test/test_system_web_app_installation.cc b/chrome/browser/web_applications/system_web_apps/test/test_system_web_app_installation.cc index f836018e..a38ab9e 100644 --- a/chrome/browser/web_applications/system_web_apps/test/test_system_web_app_installation.cc +++ b/chrome/browser/web_applications/system_web_apps/test/test_system_web_app_installation.cc
@@ -676,19 +676,19 @@ std::unique_ptr<TestSystemWebAppInstallation> TestSystemWebAppInstallation::SetUpAppsForContestMenuTest() { std::vector<std::unique_ptr<UnittestingSystemAppDelegate>> delegates; - delegates.emplace_back(CreateSystemAppDelegateWithWindowConfig( + delegates.push_back(CreateSystemAppDelegateWithWindowConfig( SystemAppType::SETTINGS, GURL("chrome://single-window/pwa.html"), SystemWebAppWindowConfig::SINGLE_WINDOW)); - delegates.emplace_back(CreateSystemAppDelegateWithWindowConfig( + delegates.push_back(CreateSystemAppDelegateWithWindowConfig( SystemAppType::FILE_MANAGER, GURL("chrome://multi-window/pwa.html"), SystemWebAppWindowConfig::MULTI_WINDOW)); - delegates.emplace_back(CreateSystemAppDelegateWithWindowConfig( + delegates.push_back(CreateSystemAppDelegateWithWindowConfig( SystemAppType::MEDIA, GURL("chrome://single-window-tab-strip/pwa.html"), SystemWebAppWindowConfig::SINGLE_WINDOW_TAB_STRIP)); - delegates.emplace_back(CreateSystemAppDelegateWithWindowConfig( + delegates.push_back(CreateSystemAppDelegateWithWindowConfig( SystemAppType::HELP, GURL("chrome://multi-window-tab-strip/pwa.html"), SystemWebAppWindowConfig::MULTI_WINDOW_TAB_STRIP)); auto* installation =
diff --git a/chrome/browser/web_applications/test/web_app_icon_test_utils.cc b/chrome/browser/web_applications/test/web_app_icon_test_utils.cc index ca3ec05..249a4a0 100644 --- a/chrome/browser/web_applications/test/web_app_icon_test_utils.cc +++ b/chrome/browser/web_applications/test/web_app_icon_test_utils.cc
@@ -62,7 +62,7 @@ void AddEmptyIconToIconsMap(const GURL& icon_url, IconsMap* icons_map) { std::vector<SkBitmap> bitmaps; - bitmaps.emplace_back(SkBitmap{}); + bitmaps.emplace_back(); icons_map->emplace(icon_url, std::move(bitmaps)); }
diff --git a/chrome/browser/web_applications/test/web_app_test_utils.cc b/chrome/browser/web_applications/test/web_app_test_utils.cc index 4d6fc24..a7503b0a 100644 --- a/chrome/browser/web_applications/test/web_app_test_utils.cc +++ b/chrome/browser/web_applications/test/web_app_test_utils.cc
@@ -234,7 +234,7 @@ shortcut_info.SetShortcutIconInfosForPurpose( IconPurpose::MONOCHROME, std::move(shortcut_icons_monochrome)); - shortcuts_menu_item_infos.emplace_back(std::move(shortcut_info)); + shortcuts_menu_item_infos.push_back(std::move(shortcut_info)); } return shortcuts_menu_item_infos; } @@ -248,11 +248,9 @@ std::vector<SquareSizePx> shortcuts_menu_icon_sizes_maskable; std::vector<SquareSizePx> shortcuts_menu_icon_sizes_monochrome; for (unsigned int j = 0; j < i; ++j) { - shortcuts_menu_icon_sizes_any.emplace_back(random.next_uint(256) + 1); - shortcuts_menu_icon_sizes_maskable.emplace_back(random.next_uint(256) + - 1); - shortcuts_menu_icon_sizes_monochrome.emplace_back(random.next_uint(256) + - 1); + shortcuts_menu_icon_sizes_any.push_back(random.next_uint(256) + 1); + shortcuts_menu_icon_sizes_maskable.push_back(random.next_uint(256) + 1); + shortcuts_menu_icon_sizes_monochrome.push_back(random.next_uint(256) + 1); } result.SetSizesForPurpose(IconPurpose::ANY, std::move(shortcuts_menu_icon_sizes_any)); @@ -260,7 +258,7 @@ std::move(shortcuts_menu_icon_sizes_maskable)); result.SetSizesForPurpose(IconPurpose::MONOCHROME, std::move(shortcuts_menu_icon_sizes_monochrome)); - results.emplace_back(std::move(result)); + results.push_back(std::move(result)); } return results; }
diff --git a/chrome/browser/web_applications/web_app_install_task_unittest.cc b/chrome/browser/web_applications/web_app_install_task_unittest.cc index 62f41f8..417047ba 100644 --- a/chrome/browser/web_applications/web_app_install_task_unittest.cc +++ b/chrome/browser/web_applications/web_app_install_task_unittest.cc
@@ -1503,31 +1503,34 @@ const GURL& shortcut_url, SquareSizePx icon_size, const GURL& icon_src) { - InstallResult result; - auto manifest = blink::mojom::Manifest::New(); - manifest->start_url = start_url; - manifest->has_theme_color = true; - manifest->theme_color = theme_color; - manifest->name = u"Manifest Name"; + { + auto manifest = blink::mojom::Manifest::New(); + manifest->start_url = start_url; + manifest->has_theme_color = true; + manifest->theme_color = theme_color; + manifest->name = u"Manifest Name"; - // Add shortcuts to manifest. - blink::Manifest::ShortcutItem shortcut_item; - shortcut_item.name = base::UTF8ToUTF16(shortcut_name); - shortcut_item.url = shortcut_url; - blink::Manifest::ImageResource icon; - icon.src = icon_src; - icon.sizes.emplace_back(gfx::Size(icon_size, icon_size)); - icon.purpose.emplace_back(IconPurpose::ANY); - shortcut_item.icons.emplace_back(icon); - manifest->shortcuts.emplace_back(shortcut_item); + // Add shortcuts to manifest. + blink::Manifest::ShortcutItem shortcut_item; + shortcut_item.name = base::UTF8ToUTF16(shortcut_name); + shortcut_item.url = shortcut_url; + blink::Manifest::ImageResource icon; + icon.src = icon_src; + icon.sizes.emplace_back(icon_size, icon_size); + icon.purpose.push_back(IconPurpose::ANY); + shortcut_item.icons.push_back(std::move(icon)); + manifest->shortcuts.push_back(std::move(shortcut_item)); - data_retriever_->SetManifest(std::move(manifest), /*is_installable=*/true); + data_retriever_->SetManifest(std::move(manifest), + /*is_installable=*/true); + } base::RunLoop run_loop; bool callback_called = false; SetInstallFinalizerForTesting(); + InstallResult result; install_task_->InstallWebAppFromManifest( web_contents(), /*bypass_service_worker_check=*/false, webapps::WebappInstallSource::MENU_BROWSER_TAB, @@ -1598,8 +1601,7 @@ icon.square_size_px = icon_size; shortcut_item.SetShortcutIconInfosForPurpose(IconPurpose::MASKABLE, {std::move(icon)}); - web_app_info->shortcuts_menu_item_infos.emplace_back( - std::move(shortcut_item)); + web_app_info->shortcuts_menu_item_infos.push_back(std::move(shortcut_item)); base::RunLoop run_loop; bool callback_called = false;
diff --git a/chrome/browser/webid/federated_identity_api_permission_context.cc b/chrome/browser/webid/federated_identity_api_permission_context.cc index 44fdcd46..4f83561 100644 --- a/chrome/browser/webid/federated_identity_api_permission_context.cc +++ b/chrome/browser/webid/federated_identity_api_permission_context.cc
@@ -4,13 +4,17 @@ #include "chrome/browser/webid/federated_identity_api_permission_context.h" +#include "chrome/browser/content_settings/cookie_settings_factory.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" +#include "chrome/browser/profiles/profile.h" #include "components/content_settings/core/common/content_settings_types.h" FederatedIdentityApiPermissionContext::FederatedIdentityApiPermissionContext( content::BrowserContext* browser_context) : host_content_settings_map_( - HostContentSettingsMapFactory::GetForProfile(browser_context)) {} + HostContentSettingsMapFactory::GetForProfile(browser_context)), + cookie_settings_(CookieSettingsFactory::GetForProfile( + Profile::FromBrowserContext(browser_context))) {} FederatedIdentityApiPermissionContext:: ~FederatedIdentityApiPermissionContext() = default; @@ -20,3 +24,7 @@ ContentSettingsType::FEDERATED_IDENTITY_API, nullptr) != ContentSetting::CONTENT_SETTING_BLOCK; } + +bool FederatedIdentityApiPermissionContext::AreThirdPartyCookiesBlocked() { + return cookie_settings_->ShouldBlockThirdPartyCookies(); +}
diff --git a/chrome/browser/webid/federated_identity_api_permission_context.h b/chrome/browser/webid/federated_identity_api_permission_context.h index a86584d6..99f0d8c 100644 --- a/chrome/browser/webid/federated_identity_api_permission_context.h +++ b/chrome/browser/webid/federated_identity_api_permission_context.h
@@ -5,6 +5,7 @@ #ifndef CHROME_BROWSER_WEBID_FEDERATED_IDENTITY_API_PERMISSION_CONTEXT_H_ #define CHROME_BROWSER_WEBID_FEDERATED_IDENTITY_API_PERMISSION_CONTEXT_H_ +#include "components/content_settings/core/browser/cookie_settings.h" #include "components/content_settings/core/browser/host_content_settings_map.h" #include "components/keyed_service/core/keyed_service.h" #include "content/public/browser/federated_identity_api_permission_context_delegate.h" @@ -30,9 +31,11 @@ // content::FederatedIdentityApiPermissionContextDelegate: bool HasApiPermission() override; + bool AreThirdPartyCookiesBlocked() override; private: const raw_ptr<HostContentSettingsMap> host_content_settings_map_; + scoped_refptr<content_settings::CookieSettings> cookie_settings_; }; #endif // CHROME_BROWSER_WEBID_FEDERATED_IDENTITY_API_PERMISSION_CONTEXT_H_
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt index f892fcb..b07042ae 100644 --- a/chrome/build/mac-arm.pgo.txt +++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@ -chrome-mac-arm-main-1646870321-a4ff75768993ceb035538c154fe6cb1ed18e31c5.profdata +chrome-mac-arm-main-1646911591-55f78d540ff78a5e719ab369cc2aa9bad8262b42.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt index 085f08b..67ce111 100644 --- a/chrome/build/mac.pgo.txt +++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@ -chrome-mac-main-1646891929-6e8950a9aea4ffd7853a4ffdde068b178092fb98.profdata +chrome-mac-main-1646911591-d61660c669edb08ff83d4e495602da55fd43110f.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index 61947d0..27b3872 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1646891929-82d9d530e22aac0fbb4a173d962ff90df21e416c.profdata +chrome-win32-main-1646924360-f677b642422b24db0082fd8ba9fb8367a361a1e4.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index d6b57c83..745d3049 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1646902708-df6bcb3ca92716bed756ccfd0e41a26162bc0de9.profdata +chrome-win64-main-1646924360-e025b34ca73b47cf946ed86693ff70ab02496910.profdata
diff --git a/chrome/common/features.gni b/chrome/common/features.gni index 39806f3..029b610b 100644 --- a/chrome/common/features.gni +++ b/chrome/common/features.gni
@@ -60,8 +60,7 @@ enable_session_service = !is_android && !is_chromecast # Enables usage of the side search feature, which is disabled by default. - # This feature is only approved for release on ChromeOS at this time. - enable_side_search = is_chromeos + enable_side_search = toolkit_views # Enables supervision for Family Link users. # Supervision is only supported on Chrome OS and Android.
diff --git a/chrome/test/base/test_browser_window.cc b/chrome/test/base/test_browser_window.cc index 407334e..1ad88f8 100644 --- a/chrome/test/base/test_browser_window.cc +++ b/chrome/test/base/test_browser_window.cc
@@ -123,7 +123,8 @@ return ui::ColorProviderManager::Get().GetColorProviderFor( {ui::ColorProviderManager::ColorMode::kLight, ui::ColorProviderManager::ContrastMode::kNormal, - ui::ColorProviderManager::SystemTheme::kDefault, nullptr}); + ui::ColorProviderManager::SystemTheme::kDefault, + ui::ColorProviderManager::FrameType::kChromium, nullptr}); } ui::ElementContext TestBrowserWindow::GetElementContext() {
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json index 54dbc14..47795e7 100644 --- a/chrome/test/data/policy/policy_test_cases.json +++ b/chrome/test/data/policy/policy_test_cases.json
@@ -18231,5 +18231,44 @@ } } ] + }, + "WebSQLAccess": { + "os": [ + "win", + "linux", + "mac", + "chromeos_ash", + "chromeos_lacros", + "android" + ], + "policy_pref_mapping_tests": [ + { + "policies": {}, + "prefs": { + "policy.web_sql_access": { + "location": "local_state", + "default_value": false + } + } + }, + { + "policies": { "WebSQLAccess": false }, + "prefs": { + "policy.web_sql_access": { + "location": "local_state", + "value": false + } + } + }, + { + "policies": { "WebSQLAccess": true }, + "prefs": { + "policy.web_sql_access": { + "location": "local_state", + "value": true + } + } + } + ] } }
diff --git a/chrome/test/data/webui/chromeos/personalization_app/test_user_interface_provider.ts b/chrome/test/data/webui/chromeos/personalization_app/test_user_interface_provider.ts index 8d225217..3189fc6 100644 --- a/chrome/test/data/webui/chromeos/personalization_app/test_user_interface_provider.ts +++ b/chrome/test/data/webui/chromeos/personalization_app/test_user_interface_provider.ts
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import {DefaultUserImage, UserImageObserverRemote, UserInfo, UserProviderInterface} from 'chrome://personalization/trusted/personalization_app.mojom-webui.js'; +import {DefaultUserImage, UserImage, UserImageObserverRemote, UserInfo, UserProviderInterface} from 'chrome://personalization/trusted/personalization_app.mojom-webui.js'; import {BigBuffer} from 'chrome://resources/mojo/mojo/public/mojom/base/big_buffer.mojom-webui.js'; import {Url} from 'chrome://resources/mojo/url/mojom/url.mojom-webui.js'; import {TestBrowserProxy} from 'chrome://webui-test/test_browser_proxy.js'; @@ -17,7 +17,7 @@ }, ]; - public image: Url = {url: 'data://avatar-url'}; + public image: UserImage = {defaultImage: this.defaultUserImages[0]} as any; public info: UserInfo = { name: 'test name',
diff --git a/chrome/test/data/webui/chromeos/personalization_app/user_preview_element_test.ts b/chrome/test/data/webui/chromeos/personalization_app/user_preview_element_test.ts index f112c5602..b5212aaa 100644 --- a/chrome/test/data/webui/chromeos/personalization_app/user_preview_element_test.ts +++ b/chrome/test/data/webui/chromeos/personalization_app/user_preview_element_test.ts
@@ -2,8 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import {UserImage} from 'chrome://personalization/trusted/personalization_app.mojom-webui.js'; import {UserPreview} from 'chrome://personalization/trusted/user/user_preview_element.js'; -import {assertEquals} from 'chrome://webui-test/chai_assert.js'; +import {assertEquals, assertTrue} from 'chrome://webui-test/chai_assert.js'; import {waitAfterNextRender} from 'chrome://webui-test/test_util.js'; import {baseSetup, initElement, teardownElement} from './personalization_app_test_utils.js'; @@ -46,23 +47,63 @@ userPreviewElement!.shadowRoot!.getElementById('name')!.innerText); }); - test('displays clickable user image on main page', async () => { + test('displays user image from default image', async () => { personalizationStore.data.user.image = userProvider.image; - userPreviewElement = initElement(UserPreview, {'clickable': true}); + userPreviewElement = initElement(UserPreview, {clickable: true}); await waitAfterNextRender(userPreviewElement!); const avatarImage = userPreviewElement!.shadowRoot!.getElementById( 'avatar') as HTMLImageElement; - assertEquals(userProvider.image.url, avatarImage.src); + assertEquals( + userProvider.image.defaultImage?.url.url, avatarImage.src, + 'correct image url is shown for default image'); + }); + + test('displays user image from profile image', async () => { + personalizationStore.data.user.image = {profileImage: {}}; + personalizationStore.data.user.profileImage = userProvider.profileImage; + userPreviewElement = initElement(UserPreview, {clickable: true}); + await waitAfterNextRender(userPreviewElement!); + + const avatarImage = userPreviewElement!.shadowRoot!.getElementById( + 'avatar') as HTMLImageElement; + assertEquals( + userProvider.profileImage.url, avatarImage.src, + 'correct image url is shown for profile image'); + }); + + test('displays user image from external image', async () => { + // Use a cast here because generated types for |UserImage| are incorrect: + // only one field should be specified at a time. + const externalImage = { + externalImage: { + bytes: [0, 0, 0, 0], + sharedMemory: undefined, + invalidBuffer: false, + }, + } as UserImage; + personalizationStore.data.user.image = externalImage; + + userPreviewElement = initElement(UserPreview, {clickable: true}); + await waitAfterNextRender(userPreviewElement); + + const avatarImage = userPreviewElement!.shadowRoot!.getElementById( + 'avatar') as HTMLImageElement; + + assertTrue( + avatarImage.src.startsWith('blob:'), + 'blob url is shown for external image'); }); test('displays non-clickable user image on user subpage', async () => { personalizationStore.data.user.image = userProvider.image; userPreviewElement = initElement(UserPreview); - await waitAfterNextRender(userPreviewElement!); + await waitAfterNextRender(userPreviewElement); const avatarImage = userPreviewElement!.shadowRoot!.getElementById( 'avatar2') as HTMLImageElement; - assertEquals(userProvider.image.url, avatarImage.src); + assertEquals( + userProvider.image.defaultImage?.url.url, avatarImage.src, + 'default image url is shown on non-clickable image'); }); }
diff --git a/chrome/test/data/webui/settings/chromeos/os_settings_ui_test_2.js b/chrome/test/data/webui/settings/chromeos/os_settings_ui_test_2.js index f1932a0..bf2724b 100644 --- a/chrome/test/data/webui/settings/chromeos/os_settings_ui_test_2.js +++ b/chrome/test/data/webui/settings/chromeos/os_settings_ui_test_2.js
@@ -7,7 +7,7 @@ // #import {CrSettingsPrefs, Router, routes, setUserActionRecorderForTesting, setNearbyShareSettingsForTesting, setContactManagerForTesting} from 'chrome://os-settings/chromeos/os_settings.js'; // #import {FakeUserActionRecorder} from './fake_user_action_recorder.m.js'; -// #import {eventToPromise} from '../../../test_util.js'; +// #import {eventToPromise, waitBeforeNextRender} from '../../../test_util.js'; // #import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; // #import {assertEquals, assertFalse, assertTrue} from '../../chai_assert.js'; // #import {assert} from 'chrome://resources/js/assert.m.js'; @@ -190,6 +190,29 @@ '', settings.Router.getInstance().getQueryParameters().toString()); }); + test('Clicking About menu item should focus About section', async () => { + const router = settings.Router.getInstance(); + const settingsMenu = ui.$$('os-settings-menu'); + + // As of iron-selector 2.x, need to force iron-selector to update before + // clicking items on it, or wait for 'iron-items-changed' + const ironSelector = settingsMenu.$$('iron-selector'); + ironSelector.forceSynchronousItemUpdate(); + + const {aboutItem} = settingsMenu.$; + aboutItem.click(); + + Polymer.dom.flush(); + assertEquals(settings.routes.ABOUT_ABOUT, router.getCurrentRoute()); + assertNotEquals(aboutItem, settingsMenu.shadowRoot.activeElement); + + const settingsMain = ui.$$('os-settings-main'); + const aboutPage = settingsMain.$$('os-settings-about-page'); + await waitBeforeNextRender(aboutPage); + const aboutSection = aboutPage.$$('settings-section[section="about"]'); + assertEquals(aboutSection, aboutPage.shadowRoot.activeElement); + }); + test('userActionRouteChange', function() { assertEquals(userActionRecorder.navigationCount, 0); settings.Router.getInstance().navigateTo(settings.routes.BASIC);
diff --git a/chrome/test/data/webui/settings/privacy_guide_page_test.ts b/chrome/test/data/webui/settings/privacy_guide_page_test.ts index fed1834..9bed26d4 100644 --- a/chrome/test/data/webui/settings/privacy_guide_page_test.ts +++ b/chrome/test/data/webui/settings/privacy_guide_page_test.ts
@@ -4,6 +4,7 @@ // clang-format off import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js'; +import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js'; import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {CookiePrimarySetting, PrivacyGuideCompletionFragmentElement, PrivacyGuideHistorySyncFragmentElement, PrivacyGuideStep, PrivacyGuideWelcomeFragmentElement, SafeBrowsingSetting, SettingsPrivacyGuidePageElement, SettingsRadioGroupElement} from 'chrome://settings/lazy_load.js'; import {MetricsBrowserProxyImpl, PrivacyGuideInteractions, PrivacyGuideSettingsStates, Router, routes, StatusAction, SyncBrowserProxyImpl, SyncPrefs, syncPrefsIndividualDataTypes, SyncStatus} from 'chrome://settings/settings.js'; @@ -774,6 +775,89 @@ flush(); assertEquals(routes.PRIVACY, Router.getInstance().getCurrentRoute()); }); + + test('arrowKeyNavigation', function() { + const pgCard = + page.shadowRoot!.querySelector<HTMLElement>('#privacyGuideCard')!; + const arrowLeftEvent = new KeyboardEvent( + 'keydown', {cancelable: true, key: 'ArrowLeft', keyCode: 37}); + const arrowRightEvent = new KeyboardEvent( + 'keydown', {cancelable: true, key: 'ArrowRight', keyCode: 39}); + function dispatchArrowLeftEvent() { + pgCard.dispatchEvent(arrowLeftEvent); + flush(); + } + function dispatchArrowRightEvent() { + pgCard.dispatchEvent(arrowRightEvent); + flush(); + } + + // Ensure a defined text direction. + loadTimeData.overrideValues({textdirection: 'ltr'}); + + // Ensure that all fragments are part of the flow. + setupSync({ + syncBrowserProxy: syncBrowserProxy, + syncOn: true, + syncAllDataTypes: true, + typedUrlsSynced: true, + }); + setCookieSetting(CookiePrimarySetting.BLOCK_THIRD_PARTY); + setSafeBrowsingSetting(SafeBrowsingSetting.STANDARD); + + // Forward flow. + navigateToStep(PrivacyGuideStep.WELCOME); + dispatchArrowRightEvent(); + assertMsbbCardVisible(); + dispatchArrowRightEvent(); + assertHistorySyncCardVisible(); + dispatchArrowRightEvent(); + assertSafeBrowsingCardVisible(); + // Arrow keys don't trigger a navigation when the focus is inside the radio + // group. + const sbRadioGroup = + page.shadowRoot! + .querySelector<HTMLElement>('#' + PrivacyGuideStep.SAFE_BROWSING)! + .shadowRoot!.querySelector<HTMLElement>('#safeBrowsingRadioGroup')!; + sbRadioGroup.dispatchEvent(arrowLeftEvent); + assertSafeBrowsingCardVisible(); + sbRadioGroup.dispatchEvent(arrowRightEvent); + assertSafeBrowsingCardVisible(); + + dispatchArrowRightEvent(); + assertCookiesCardVisible(); + // Arrow keys don't trigger a navigation when the focus is inside the radio + // group. + const cookiesRadioGroup = + page.shadowRoot! + .querySelector<HTMLElement>('#' + PrivacyGuideStep.COOKIES)! + .shadowRoot!.querySelector<HTMLElement>('#cookiesRadioGroup')!; + cookiesRadioGroup.dispatchEvent(arrowLeftEvent); + assertCookiesCardVisible(); + cookiesRadioGroup.dispatchEvent(arrowRightEvent); + assertCookiesCardVisible(); + + dispatchArrowRightEvent(); + assertCompletionCardVisible(); + // Forward navigation on the completion card does not trigger a navigation. + dispatchArrowRightEvent(); + assertCompletionCardVisible(); + + // Backward flow. + dispatchArrowLeftEvent(); + assertCookiesCardVisible(); + dispatchArrowLeftEvent(); + assertSafeBrowsingCardVisible(); + dispatchArrowLeftEvent(); + assertHistorySyncCardVisible(); + dispatchArrowLeftEvent(); + assertMsbbCardVisible(); + dispatchArrowLeftEvent(); + assertWelcomeCardVisible(); + // Backward navigation on the welcome card does not trigger a navigation. + dispatchArrowLeftEvent(); + assertWelcomeCardVisible(); + }); }); suite('PrivacyGuideFragmentMetrics', function() {
diff --git a/chrome/updater/win/protocol_parser_xml.cc b/chrome/updater/win/protocol_parser_xml.cc index cdf86215..b3a1a878 100644 --- a/chrome/updater/win/protocol_parser_xml.cc +++ b/chrome/updater/win/protocol_parser_xml.cc
@@ -129,8 +129,29 @@ } bool ProtocolParserXML::ParseData(IXMLDOMNode* node, Results* results) { - // TODO(crbug.com/1292640): Parse <data> once Results structure adds the - // peer members. + ProtocolParser::Result::Data data; + if (!ReadStringAttribute(node, L"status", &data.status)) { + ParseError("Missing `status` attribute in <data>"); + return false; + } + if (!ReadStringAttribute(node, L"index", &data.install_data_index)) { + ParseError("Missing `index` attribute in <data>"); + return false; + } + if (!ReadStringAttribute(node, L"name", &data.name)) { + ParseError("Missing `name` attribute in <data>"); + return false; + } + + base::win::ScopedBstr text; + HRESULT hr = node->get_text(text.Receive()); + if (FAILED(hr)) { + ParseError("Failed to get text from <data>: 0x%x", hr); + return false; + } + data.text = base::SysWideToUTF8(text.Get()); + + results->list.back().data.push_back(data); return true; }
diff --git a/chrome/updater/win/protocol_parser_xml_unittest.cc b/chrome/updater/win/protocol_parser_xml_unittest.cc index 354eea1..fcae276 100644 --- a/chrome/updater/win/protocol_parser_xml_unittest.cc +++ b/chrome/updater/win/protocol_parser_xml_unittest.cc
@@ -4,8 +4,6 @@ #include "chrome/updater/win/protocol_parser_xml.h" -#include "base/logging.h" - #include "testing/gtest/include/gtest/gtest.h" namespace updater { @@ -89,6 +87,26 @@ EXPECT_TRUE(result.manifest.packages[0].namediff.empty()); EXPECT_TRUE(result.manifest.packages[0].hashdiff_sha256.empty()); EXPECT_EQ(result.manifest.packages[0].sizediff, 0); + + EXPECT_EQ(result.data.size(), size_t{2}); + EXPECT_EQ(result.data[0].status, "ok"); + EXPECT_EQ(result.data[0].name, "install"); + EXPECT_EQ(result.data[0].install_data_index, "verboselogging"); + EXPECT_EQ(result.data[0].text, + "{" + " \"distribution\": {" + " \"verbose_logging\": true" + " }" + " }"); + EXPECT_EQ(result.data[1].status, "ok"); + EXPECT_EQ(result.data[1].name, "install"); + EXPECT_EQ(result.data[1].install_data_index, "defaultbrowser"); + EXPECT_EQ(result.data[1].text, + "{" + " \"distribution\": {" + " \"make_chrome_default_for_user\": true" + " }" + " }"); } } // namespace updater
diff --git a/chromeos/services/bluetooth_config/device_pairing_handler.cc b/chromeos/services/bluetooth_config/device_pairing_handler.cc index 8c25cb9..36bbaa76 100644 --- a/chromeos/services/bluetooth_config/device_pairing_handler.cc +++ b/chromeos/services/bluetooth_config/device_pairing_handler.cc
@@ -291,7 +291,9 @@ return; } - BLUETOOTH_LOG(ERROR) << device->GetAddress() + // We use |current_pairing_device_id_| since it conveys the same information + // as the address and |device| could be |nullptr|. + BLUETOOTH_LOG(ERROR) << current_pairing_device_id_ << ": Pairing failed with error code: " << error_code; using ErrorCode = device::BluetoothDevice::ConnectErrorCode;
diff --git a/components/account_manager_core/account_manager_facade_impl.cc b/components/account_manager_core/account_manager_facade_impl.cc index dc3a2d9..730b90d 100644 --- a/components/account_manager_core/account_manager_facade_impl.cc +++ b/components/account_manager_core/account_manager_facade_impl.cc
@@ -222,7 +222,7 @@ CancelRequest(); FireOnGetTokenFailure( - GoogleServiceAuthError(GoogleServiceAuthError::State::SERVICE_ERROR)); + GoogleServiceAuthError::FromServiceError("Mojo pipe disconnected")); } AccountManagerFacadeImpl* const account_manager_facade_impl_; @@ -391,7 +391,7 @@ << " for CreateAccessTokenFetcher"; return std::make_unique<OAuth2AccessTokenFetcherImmediateError>( consumer, - GoogleServiceAuthError(GoogleServiceAuthError::State::SERVICE_ERROR)); + GoogleServiceAuthError::FromServiceError("Mojo pipe disconnected")); } auto access_token_fetcher = std::make_unique<AccessTokenFetcher>(
diff --git a/components/account_manager_core/account_manager_facade_impl_unittest.cc b/components/account_manager_core/account_manager_facade_impl_unittest.cc index c8735273..9683f5d3 100644 --- a/components/account_manager_core/account_manager_facade_impl_unittest.cc +++ b/components/account_manager_core/account_manager_facade_impl_unittest.cc
@@ -397,7 +397,7 @@ // scoped_closure that sets `callback_was_dropped` when it is destroyed. base::ScopedClosureRunner scoped_closure(base::BindLambdaForTesting( [&callback_was_dropped]() { callback_was_dropped = true; })); - // Pass ownership of the scopped closure to the main callback, so that the + // Pass ownership of the scoped closure to the main callback, so that the // scoped closure is run when the callback is destroyed. // This callback should not be run. base::OnceCallback<void(const std::vector<Account>&)> dropped_callback = @@ -592,7 +592,8 @@ const Account account = CreateTestGaiaAccount(kTestAccountEmail); MockOAuthConsumer consumer; - GoogleServiceAuthError error(GoogleServiceAuthError::SERVICE_ERROR); + GoogleServiceAuthError error = + GoogleServiceAuthError::FromServiceError("Mojo pipe disconnected"); EXPECT_CALL(consumer, OnGetTokenFailure(Eq(error))); std::unique_ptr<OAuth2AccessTokenFetcher> access_token_fetcher = @@ -639,7 +640,8 @@ const Account account = CreateTestGaiaAccount(kTestAccountEmail); MockOAuthConsumer consumer; - GoogleServiceAuthError error(GoogleServiceAuthError::SERVICE_ERROR); + GoogleServiceAuthError error = + GoogleServiceAuthError::FromServiceError("Mojo pipe disconnected"); EXPECT_CALL(consumer, OnGetTokenFailure(Eq(error))); std::unique_ptr<OAuth2AccessTokenFetcher> access_token_fetcher =
diff --git a/components/autofill/content/renderer/password_autofill_agent.cc b/components/autofill/content/renderer/password_autofill_agent.cc index b3c2113..4d53e1ed 100644 --- a/components/autofill/content/renderer/password_autofill_agent.cc +++ b/components/autofill/content/renderer/password_autofill_agent.cc
@@ -534,9 +534,9 @@ DeferMsg(&mojom::PasswordManagerDriver::ShowPasswordSuggestions, text_direction, typed_username, options, bounds); } - void ShowTouchToFill(bool trigger_submission) override { + void ShowTouchToFill(bool ready_for_submission) override { DeferMsg(&mojom::PasswordManagerDriver::ShowTouchToFill, - trigger_submission); + ready_for_submission); } void CheckSafeBrowsingReputation(const GURL& form_action, const GURL& frame_url) override { @@ -1006,7 +1006,7 @@ IsReadyForSubmissionAfterCredentialFilling(username_element, password_element)); #else - GetPasswordManagerDriver().ShowTouchToFill(/*trigger_submission*/ false); + GetPasswordManagerDriver().ShowTouchToFill(/*ready_for_submission*/ false); #endif touch_to_fill_state_ = TouchToFillState::kIsShowing;
diff --git a/components/autofill_assistant/content/renderer/autofill_assistant_model_executor.cc b/components/autofill_assistant/content/renderer/autofill_assistant_model_executor.cc index 12fd6138..4e499ae 100644 --- a/components/autofill_assistant/content/renderer/autofill_assistant_model_executor.cc +++ b/components/autofill_assistant/content/renderer/autofill_assistant_model_executor.cc
@@ -148,6 +148,8 @@ for (const auto& text : node_signals.context_features.header_text) { Tokenize(text.Utf16(), text_tokenizer_.get(), &inputs[4]); } + Tokenize(node_signals.context_features.form_type.Utf16(), + text_tokenizer_.get(), &inputs[4]); for (size_t i = 0; i < inputs.size(); ++i) { absl::Status tensor_status =
diff --git a/components/autofill_payments_strings.grdp b/components/autofill_payments_strings.grdp index d7a1c60..2f1c7378 100644 --- a/components/autofill_payments_strings.grdp +++ b/components/autofill_payments_strings.grdp
@@ -154,7 +154,7 @@ <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION" desc="Explanation of the effect of the Autofill save card prompt when the card is to be saved by uploading it to Google Payments and also saved locally. The prompt can be either a bubble or an infobar."> Pay quickly on sites and apps across devices using cards you have saved with Google. </message> - <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION_V3" desc="Explanation of the effect of the Autofill save card prompt when the card is to be saved by uploading it to Google Payments, according to April 2018 UI guidelines. The prompt will be shown in a bubble below the omnibox."> + <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION_V3" desc="Explanation of the effect of the Autofill save card prompt when the card is to be saved by uploading it to Google Payments, according to April 2018 UI guidelines. The prompt will be shown in a bubble below the omnibox." formatter_data="android_java"> To pay faster next time, save your card and billing address to your Google Account. </message> <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION_V3_WITH_NAME" desc="Explanation of the effect of the Autofill save card prompt when the card is to be saved by uploading it to Google Payments, according to April 2018 UI guidelines. The prompt will be shown in a bubble below the omnibox.">
diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java index 5f6f342a..9af97562 100644 --- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java +++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java
@@ -298,7 +298,7 @@ private void init() { // Remove this Preference if it gets restored without a valid SiteSettingsDelegate. This // can happen e.g. when it is included in PageInfo. - if (getSiteSettingsDelegate() == null) { + if (!hasSiteSettingsDelegate()) { getParentFragmentManager().beginTransaction().remove(this).commit(); return; }
diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteSettingsPreferenceFragment.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteSettingsPreferenceFragment.java index 0d816be..9c42ae3 100644 --- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteSettingsPreferenceFragment.java +++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteSettingsPreferenceFragment.java
@@ -29,4 +29,11 @@ assert mSiteSettingsDelegate != null : "SiteSettingsDelegate not set"; return mSiteSettingsDelegate; } + + /** + * @return Whether a SiteSettingsDelegate instance has been assigned to this Fragment. + */ + public boolean hasSiteSettingsDelegate() { + return mSiteSettingsDelegate != null; + } }
diff --git a/components/browser_ui/styles/android/BUILD.gn b/components/browser_ui/styles/android/BUILD.gn index af80ce5..c780d9c 100644 --- a/components/browser_ui/styles/android/BUILD.gn +++ b/components/browser_ui/styles/android/BUILD.gn
@@ -191,6 +191,7 @@ "java/res/drawable/ic_info_outline_grey_24dp.xml", "java/res/drawable/ic_lightbulb_24dp.xml", "java/res/drawable/ic_link_24dp.xml", + "java/res/drawable/ic_logo_assistant_24dp.xml", "java/res/drawable/ic_music_note_24dp.xml", "java/res/drawable/ic_offline_pin_24dp_on_dark_bg.xml", "java/res/drawable/ic_offline_pin_24dp_on_light_bg.xml",
diff --git a/chrome/android/java/res/drawable/ic_logo_assistant_24dp.xml b/components/browser_ui/styles/android/java/res/drawable/ic_logo_assistant_24dp.xml similarity index 100% rename from chrome/android/java/res/drawable/ic_logo_assistant_24dp.xml rename to components/browser_ui/styles/android/java/res/drawable/ic_logo_assistant_24dp.xml
diff --git a/components/certificate_transparency/data/log_list.json b/components/certificate_transparency/data/log_list.json index 8a68998..3ac26a6 100644 --- a/components/certificate_transparency/data/log_list.json +++ b/components/certificate_transparency/data/log_list.json
@@ -1,6 +1,6 @@ { - "version": "6.4", - "log_list_timestamp": "2022-03-08T01:36:27Z", + "version": "6.6", + "log_list_timestamp": "2022-03-10T01:34:39Z", "operators": [ { "name": "Google",
diff --git a/components/cronet/BUILD.gn b/components/cronet/BUILD.gn index 61708d8..5be0ce2 100644 --- a/components/cronet/BUILD.gn +++ b/components/cronet/BUILD.gn
@@ -87,6 +87,7 @@ sources = [ "host_cache_persistence_manager_unittest.cc", + "network_tasks_unittest.cc", "stale_host_resolver_unittest.cc", "url_request_context_config_unittest.cc", ]
diff --git a/components/cronet/cronet_context.cc b/components/cronet/cronet_context.cc index 8e213bb..3f2e7e57 100644 --- a/components/cronet/cronet_context.cc +++ b/components/cronet/cronet_context.cc
@@ -209,11 +209,13 @@ CronetContext::NetworkTasks::NetworkTasks( std::unique_ptr<URLRequestContextConfig> context_config, - std::unique_ptr<CronetContext::Callback> callback) + std::unique_ptr<CronetContext::Callback> callback, + bool listen_to_network_changes) : default_context_(nullptr), is_default_context_initialized_(false), context_config_(std::move(context_config)), - callback_(std::move(callback)) { + callback_(std::move(callback)), + listen_to_network_changes_(listen_to_network_changes) { DETACH_FROM_THREAD(network_thread_checker_); } @@ -230,6 +232,9 @@ network_quality_estimator_->RemoveEffectiveConnectionTypeObserver(this); network_quality_estimator_->RemoveRTTAndThroughputEstimatesObserver(this); } + + if (listen_to_network_changes_) + net::NetworkChangeNotifier::RemoveNetworkObserver(this); } void CronetContext::InitRequestContextOnInitThread() { @@ -309,6 +314,19 @@ base::Unretained(network_tasks_), should)); } +void CronetContext::NetworkTasks::SpawnNetworkBoundURLRequestContextForTesting( + net::NetworkChangeNotifier::NetworkHandle network) { + DCHECK_CALLED_ON_VALID_THREAD(network_thread_checker_); + DCHECK(!contexts_.contains(network)); + contexts_[network] = BuildNetworkBoundURLRequestContext(network); +} + +bool CronetContext::NetworkTasks::DoesURLRequestContextExistForTesting( + net::NetworkChangeNotifier::NetworkHandle network) { + DCHECK_CALLED_ON_VALID_THREAD(network_thread_checker_); + return contexts_.contains(network); +} + void CronetContext::NetworkTasks::InitializeNQEPrefs() const { DCHECK_CALLED_ON_VALID_THREAD(network_thread_checker_); // Initializing |network_qualities_prefs_manager_| may post a callback to @@ -493,6 +511,9 @@ BuildDefaultURLRequestContext(std::move(proxy_config_service)); default_context_ = contexts_[default_network].get(); + if (listen_to_network_changes_) + net::NetworkChangeNotifier::AddNetworkObserver(this); + callback_->OnInitNetworkThread(); is_default_context_initialized_ = true; @@ -689,6 +710,29 @@ (timestamp - base::TimeTicks::UnixEpoch()).InMilliseconds(), source); } +void CronetContext::NetworkTasks::OnNetworkDisconnected( + net::NetworkChangeNotifier::NetworkHandle network) { + DCHECK_CALLED_ON_VALID_THREAD(network_thread_checker_); + DCHECK(listen_to_network_changes_); + + // TODO(stefanoduo): Properly cancel pending requests before destroying the + // context. + contexts_.erase(network); +} + +void CronetContext::NetworkTasks::OnNetworkConnected( + net::NetworkChangeNotifier::NetworkHandle network) { + DCHECK_CALLED_ON_VALID_THREAD(network_thread_checker_); +} +void CronetContext::NetworkTasks::OnNetworkSoonToDisconnect( + net::NetworkChangeNotifier::NetworkHandle network) { + DCHECK_CALLED_ON_VALID_THREAD(network_thread_checker_); +} +void CronetContext::NetworkTasks::OnNetworkMadeDefault( + net::NetworkChangeNotifier::NetworkHandle network) { + DCHECK_CALLED_ON_VALID_THREAD(network_thread_checker_); +} + void CronetContext::NetworkTasks::StartNetLog(const base::FilePath& file_path, bool include_socket_bytes) { DCHECK_CALLED_ON_VALID_THREAD(network_thread_checker_);
diff --git a/components/cronet/cronet_context.h b/components/cronet/cronet_context.h index 8fc71a3..bfd3d06 100644 --- a/components/cronet/cronet_context.h +++ b/components/cronet/cronet_context.h
@@ -172,20 +172,21 @@ } base::TimeDelta heartbeat_interval() const { return heartbeat_interval_; } - private: - friend class TestUtil; - class ContextGetter; - // NetworkTasks performs tasks on the network thread and owns objects that // live on the network thread. class NetworkTasks : public net::EffectiveConnectionTypeObserver, public net::RTTAndThroughputEstimatesObserver, public net::NetworkQualityEstimator::RTTObserver, - public net::NetworkQualityEstimator::ThroughputObserver { + public net::NetworkQualityEstimator::ThroughputObserver, + public net::NetworkChangeNotifier::NetworkObserver { public: // Invoked off the network thread. + // `listen_to_network_changes` is a temporary parameter to allow + // multi-network testing for the time being. + // TODO(1284972): Remove listen_to_network_changes once that has been fixed. NetworkTasks(std::unique_ptr<URLRequestContextConfig> config, - std::unique_ptr<CronetContext::Callback> callback); + std::unique_ptr<CronetContext::Callback> callback, + bool listen_to_network_changes = false); NetworkTasks(const NetworkTasks&) = delete; NetworkTasks& operator=(const NetworkTasks&) = delete; @@ -238,6 +239,16 @@ const base::TimeTicks& timestamp, net::NetworkQualityObservationSource source) override; + // net::NetworkChangeNotifier::NetworkObserver implementation. + void OnNetworkDisconnected( + net::NetworkChangeNotifier::NetworkHandle network) override; + void OnNetworkConnected( + net::NetworkChangeNotifier::NetworkHandle network) override; + void OnNetworkSoonToDisconnect( + net::NetworkChangeNotifier::NetworkHandle network) override; + void OnNetworkMadeDefault( + net::NetworkChangeNotifier::NetworkHandle network) override; + net::URLRequestContext* GetURLRequestContext( net::NetworkChangeNotifier::NetworkHandle network); @@ -261,6 +272,11 @@ // thread. void InitializeNQEPrefs() const; + void SpawnNetworkBoundURLRequestContextForTesting( + net::NetworkChangeNotifier::NetworkHandle network); + bool DoesURLRequestContextExistForTesting( + net::NetworkChangeNotifier::NetworkHandle network); + private: friend class TestUtil; base::Value GetNetLogInfo() const; @@ -330,9 +346,17 @@ // Callback implemented by the client. std::unique_ptr<CronetContext::Callback> callback_; + // Whether `this` should listen to network changes and destroy network-bound + // contexts when their network goes away. + bool listen_to_network_changes_; + THREAD_CHECKER(network_thread_checker_); }; + private: + friend class TestUtil; + class ContextGetter; + scoped_refptr<base::SingleThreadTaskRunner> GetNetworkTaskRunner() const; // Gets the file thread. Create one if there is none.
diff --git a/components/cronet/network_tasks_unittest.cc b/components/cronet/network_tasks_unittest.cc new file mode 100644 index 0000000..ff6bd6b --- /dev/null +++ b/components/cronet/network_tasks_unittest.cc
@@ -0,0 +1,176 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/cronet/cronet_context.h" + +#include <latch> + +#include "base/test/bind.h" +#include "base/test/task_environment.h" +#include "components/cronet/cronet_global_state.h" +#include "components/cronet/url_request_context_config.h" +#include "net/base/mock_network_change_notifier.h" +#include "net/base/request_priority.h" +#include "net/cert/cert_verifier.h" +#include "net/proxy_resolution/proxy_config_service_fixed.h" +#include "net/url_request/url_request.h" +#include "net/url_request/url_request_context.h" +#include "testing/gtest/include/gtest/gtest.h" + +#if BUILDFLAG(IS_ANDROID) +#include "base/android/build_info.h" +#endif // BUILDFLAG(IS_ANDROID) + +namespace cronet { + +namespace { + +class NoOpCronetContextCallback : public CronetContext::Callback { + public: + NoOpCronetContextCallback() = default; + + NoOpCronetContextCallback(const NoOpCronetContextCallback&) = delete; + NoOpCronetContextCallback& operator=(const NoOpCronetContextCallback&) = + delete; + + void OnInitNetworkThread() override {} + + void OnDestroyNetworkThread() override {} + + void OnEffectiveConnectionTypeChanged( + net::EffectiveConnectionType effective_connection_type) override {} + + void OnRTTOrThroughputEstimatesComputed( + int32_t http_rtt_ms, + int32_t transport_rtt_ms, + int32_t downstream_throughput_kbps) override {} + + void OnRTTObservation(int32_t rtt_ms, + int32_t timestamp_ms, + net::NetworkQualityObservationSource source) override {} + + void OnThroughputObservation( + int32_t throughput_kbps, + int32_t timestamp_ms, + net::NetworkQualityObservationSource source) override {} + + void OnStopNetLogCompleted() override {} + + ~NoOpCronetContextCallback() override = default; +}; + +std::unique_ptr<URLRequestContextConfig> CreateSimpleURLRequestContextConfig() { + return URLRequestContextConfig::CreateURLRequestContextConfig( + // Enable QUIC. + true, + // QUIC User Agent ID. + "Default QUIC User Agent ID", + // Enable SPDY. + true, + // Enable Brotli. + false, + // Type of http cache. + URLRequestContextConfig::HttpCacheType::DISK, + // Max size of http cache in bytes. + 1024000, + // Disable caching for HTTP responses. Other information may be stored + // in the cache. + false, + // Storage path for http cache and cookie storage. + "/data/data/org.chromium.net/app_cronet_test/test_storage", + // Accept-Language request header field. + "foreign-language", + // User-Agent request header field. + "fake agent", + // JSON encoded experimental options. + "", + // MockCertVerifier to use for testing purposes. + std::unique_ptr<net::CertVerifier>(), + // Enable network quality estimator. + false, + // Enable Public Key Pinning bypass for local trust anchors. + true, + // Optional network thread priority. + absl::nullopt); +} + +class NetworkTasksTest : public testing::Test { + protected: + NetworkTasksTest() + : ncn_(net::NetworkChangeNotifier::CreateIfNeeded()), + network_task_runner_( + base::ThreadPool::CreateSingleThreadTaskRunner({})), + file_task_runner_(base::ThreadPool::CreateSingleThreadTaskRunner({})), + network_tasks_(new CronetContext::NetworkTasks( + CreateSimpleURLRequestContextConfig(), + std::make_unique<NoOpCronetContextCallback>(), + true /* listen_to_network_changes */)) { + scoped_ncn_.mock_network_change_notifier()->ForceNetworkHandlesSupported(); + Initialize(); + } + + void Initialize() { + PostToNetworkThreadSync( + base::BindOnce(&CronetContext::NetworkTasks::Initialize, + base::Unretained(network_tasks_), network_task_runner_, + file_task_runner_, + std::make_unique<net::ProxyConfigServiceFixed>( + net::ProxyConfigWithAnnotation::CreateDirect()))); + } + + void SpawnNetworkBoundURLRequestContext( + net::NetworkChangeNotifier::NetworkHandle network) { + PostToNetworkThreadSync(base::BindLambdaForTesting([=]() { + network_tasks_->SpawnNetworkBoundURLRequestContextForTesting(network); + })); + } + + void CheckURLRequestContextExistence( + net::NetworkChangeNotifier::NetworkHandle network, + bool expected) { + PostToNetworkThreadSync(base::BindLambdaForTesting([=]() { + EXPECT_EQ(expected, + network_tasks_->DoesURLRequestContextExistForTesting(network)); + })); + } + + void PostToNetworkThreadSync(base::OnceCallback<void()> callback) { + std::latch callback_executed{1}; + auto wait_for_callback = base::BindLambdaForTesting( + [&callback_executed]() { callback_executed.count_down(); }); + network_task_runner_->PostTask( + FROM_HERE, std::move(callback).Then(std::move(wait_for_callback))); + callback_executed.wait(); + } + + base::test::TaskEnvironment task_environment_; + std::unique_ptr<net::NetworkChangeNotifier> ncn_; + net::test::ScopedMockNetworkChangeNotifier scoped_ncn_; + scoped_refptr<base::SingleThreadTaskRunner> network_task_runner_; + scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_; + raw_ptr<CronetContext::NetworkTasks> network_tasks_; +}; + +TEST_F(NetworkTasksTest, NetworkBoundContextLifetime) { +#if BUILDFLAG(IS_ANDROID) + if (base::android::BuildInfo::GetInstance()->sdk_int() < + base::android::SDK_VERSION_MARSHMALLOW) { + GTEST_SKIP() << "Network binding on Android requires an API level >= 23"; + } +#endif // BUILDFLAG(IS_ANDROID) + constexpr net::NetworkChangeNotifier::NetworkHandle kNetwork = 1; + + CheckURLRequestContextExistence(kNetwork, false); + SpawnNetworkBoundURLRequestContext(kNetwork); + CheckURLRequestContextExistence(kNetwork, true); + + // Once the network disconnects the context should be destroyed. + scoped_ncn_.mock_network_change_notifier()->NotifyNetworkDisconnected( + kNetwork); + CheckURLRequestContextExistence(kNetwork, false); +} + +} // namespace + +} // namespace cronet
diff --git a/components/exo/data_source_delegate.h b/components/exo/data_source_delegate.h index 6105e90..c50c9ae 100644 --- a/components/exo/data_source_delegate.h +++ b/components/exo/data_source_delegate.h
@@ -8,6 +8,7 @@ #include <string> #include "base/files/scoped_file.h" +#include "components/exo/data_device.h" #include "third_party/abseil-cpp/absl/types/optional.h" namespace exo {
diff --git a/components/exo/drag_drop_operation.cc b/components/exo/drag_drop_operation.cc index 177ff350..824114e 100644 --- a/components/exo/drag_drop_operation.cc +++ b/components/exo/drag_drop_operation.cc
@@ -14,11 +14,14 @@ #include "components/exo/data_offer.h" #include "components/exo/data_source.h" #include "components/exo/seat.h" +#include "components/exo/shell_surface_base.h" +#include "components/exo/shell_surface_util.h" #include "components/exo/surface.h" #include "components/exo/surface_tree_host.h" #include "components/viz/common/frame_sinks/copy_output_request.h" #include "components/viz/common/frame_sinks/copy_output_result.h" #include "ui/aura/client/drag_drop_client.h" +#include "ui/aura/window_tracker.h" #include "ui/base/clipboard/file_info.h" #include "ui/base/data_transfer_policy/data_transfer_endpoint.h" #include "ui/base/dragdrop/drag_drop_types.h" @@ -88,6 +91,9 @@ return DndAction::kCopy; case DragOperation::kLink: return DndAction::kAsk; + default: + NOTREACHED() << op; + return DndAction::kNone; } NOTREACHED(); } @@ -374,6 +380,14 @@ // to let any nested run loops that are currently running to have a chance to // exit to avoid arbitrarily deep nesting. We can accomplish both of those // things by posting a new task to actually start the drag and drop operation. +#if BUILDFLAG(IS_CHROMEOS_ASH) + if (extended_drag_source_) { + ShellSurfaceBase* shell_surface = GetShellSurfaceBaseForWindow( + origin_->get()->window()->GetToplevelWindow()); + if (shell_surface) + shell_surface->set_in_extended_drag(true); + } +#endif base::SequencedTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(&DragDropOperation::StartDragDropOperation, weak_ptr_factory_.GetWeakPtr())); @@ -399,6 +413,17 @@ if (!weak_ptr) return; +#if BUILDFLAG(IS_CHROMEOS_ASH) + // Always reset the in_extended_drag becacuse ExtendedDragSource may be + // destroyed during nested loop. + if (origin_->get()) { + ShellSurfaceBase* shell_surface = GetShellSurfaceBaseForWindow( + origin_->get()->window()->GetToplevelWindow()); + if (shell_surface) + shell_surface->set_in_extended_drag(false); + } +#endif + // In tests, drag_drop_controller_ does not create a nested message loop and // so StartDragAndDrop exits before the drag&drop session finishes. In that // case the cleanup process shouldn't be made.
diff --git a/components/exo/drag_drop_operation_unittest.cc b/components/exo/drag_drop_operation_unittest.cc index 14b8458..6a2656dd 100644 --- a/components/exo/drag_drop_operation_unittest.cc +++ b/components/exo/drag_drop_operation_unittest.cc
@@ -41,46 +41,10 @@ using ::testing::_; using ::testing::Property; -constexpr char kText[] = "test"; constexpr char kTextMimeType[] = "text/plain"; } // namespace -class TestDataSourceDelegate : public DataSourceDelegate { - public: - // DataSourceDelegate: - void OnDataSourceDestroying(DataSource* source) override {} - - void OnTarget(const absl::optional<std::string>& mime_type) override {} - - void OnSend(const std::string& mime_type, base::ScopedFD fd) override { - if (data_map_.empty()) { - base::WriteFileDescriptor(fd.get(), kText); - } else { - base::WriteFileDescriptor(fd.get(), data_map_[mime_type]); - } - } - - void OnCancelled() override {} - - void OnDndDropPerformed() override {} - - void OnDndFinished() override {} - - void OnAction(DndAction dnd_action) override {} - - bool CanAcceptDataEventsForSurface(Surface* surface) const override { - return true; - } - - void SetData(const std::string& mime_type, std::vector<uint8_t> data) { - data_map_[mime_type] = std::move(data); - } - - private: - base::flat_map<std::string, std::vector<uint8_t>> data_map_; -}; - class DragDropOperationTest : public test::ExoTestBase, public aura::client::DragDropClientObserver { public: @@ -104,8 +68,10 @@ // aura::client::DragDropClientObserver: void OnDragStarted() override { drag_start_count_++; - base::SequencedTaskRunnerHandle::Get()->PostTask( - FROM_HERE, std::move(drag_blocked_callback_)); + if (!drag_blocked_callback_.is_null()) { + base::SequencedTaskRunnerHandle::Get()->PostTask( + FROM_HERE, std::move(drag_blocked_callback_)); + } } void OnDragCompleted(const ui::DropTargetEvent& event) override { @@ -466,6 +432,7 @@ ::testing::Mock::VerifyAndClearExpectations(dlp_controller.get()); } + #endif } // namespace exo
diff --git a/components/exo/extended_drag_source.cc b/components/exo/extended_drag_source.cc index 9e4f801..9681600 100644 --- a/components/exo/extended_drag_source.cc +++ b/components/exo/extended_drag_source.cc
@@ -81,6 +81,9 @@ private: // aura::WindowObserver: void OnWindowAddedToRootWindow(aura::Window* window) override { + if (toplevel_window_) + return; + DCHECK_EQ(window, surface_->window()); FindToplevelWindow(); DCHECK(toplevel_window_);
diff --git a/components/exo/extended_drag_source_unittest.cc b/components/exo/extended_drag_source_unittest.cc index 61707eb..459fb5c 100644 --- a/components/exo/extended_drag_source_unittest.cc +++ b/components/exo/extended_drag_source_unittest.cc
@@ -21,6 +21,7 @@ #include "components/exo/buffer.h" #include "components/exo/data_source.h" #include "components/exo/data_source_delegate.h" +#include "components/exo/drag_drop_operation.h" #include "components/exo/seat.h" #include "components/exo/shell_surface.h" #include "components/exo/surface.h" @@ -65,32 +66,6 @@ CHECK(!details.dispatcher_destroyed); } -class TestDataSourceDelegate : public DataSourceDelegate { - public: - TestDataSourceDelegate() {} - TestDataSourceDelegate(const TestDataSourceDelegate&) = delete; - TestDataSourceDelegate& operator=(const TestDataSourceDelegate&) = delete; - ~TestDataSourceDelegate() override = default; - - bool cancelled() const { return cancelled_; } - - // Overridden from DataSourceDelegate: - void OnDataSourceDestroying(DataSource* device) override { delete this; } - void OnTarget(const absl::optional<std::string>& mime_type) override {} - void OnSend(const std::string& mime_type, base::ScopedFD fd) override {} - void OnCancelled() override { cancelled_ = true; } - void OnDndDropPerformed() override {} - void OnDndFinished() override { finished_ = true; } - void OnAction(DndAction dnd_action) override {} - bool CanAcceptDataEventsForSurface(Surface* surface) const override { - return true; - } - - private: - bool cancelled_ = false; - bool finished_ = false; -}; - class TestExtendedDragSourceDelegate : public ExtendedDragSource::Delegate { public: TestExtendedDragSourceDelegate(bool allow_drop_no_target, bool lock_cursor) @@ -146,8 +121,8 @@ seat_ = std::make_unique<Seat>(std::make_unique<TestDataExchangeDelegate>()); - data_source_delegate_ = new TestDataSourceDelegate; - data_source_ = std::make_unique<DataSource>(data_source_delegate_); + data_source_delegate_ = std::make_unique<TestDataSourceDelegate>(); + data_source_ = std::make_unique<DataSource>(data_source_delegate_.get()); extended_drag_source_ = std::make_unique<ExtendedDragSource>( data_source_.get(), new TestExtendedDragSourceDelegate( /*allow_drop_no_target=*/true, @@ -157,6 +132,7 @@ void TearDown() override { extended_drag_source_.reset(); data_source_.reset(); + data_source_delegate_.reset(); seat_.reset(); test::ExoTestBase::TearDown(); } @@ -184,9 +160,7 @@ std::unique_ptr<Seat> seat_; std::unique_ptr<DataSource> data_source_; std::unique_ptr<ExtendedDragSource> extended_drag_source_; - - // DataSource deletes it upon destruction. - TestDataSourceDelegate* data_source_delegate_ = nullptr; + std::unique_ptr<TestDataSourceDelegate> data_source_delegate_; }; // Enables or disables tablet mode and waits for the transition to finish. @@ -591,4 +565,37 @@ EXPECT_TRUE(data_source_delegate_->cancelled()); } +// Make sure that the extended drag is recognized as shell surface drag. +TEST_F(ExtendedDragSourceTest, DragWithScreenCoordinates) { + auto shell_surface = test::ShellSurfaceBuilder({20, 20}).BuildShellSurface(); + TestDataExchangeDelegate data_exchange_delegate; + + auto delegate = std::make_unique<TestDataSourceDelegate>(); + auto data_source = std::make_unique<DataSource>(delegate.get()); + constexpr char kTextMimeType[] = "text/plain"; + data_source->Offer(kTextMimeType); + + gfx::PointF location(10, 10); + auto operation = DragDropOperation::Create( + &data_exchange_delegate, data_source.get(), shell_surface->root_surface(), + nullptr, location, ui::mojom::DragEventSource::kMouse); + + auto* drag_drop_controller = static_cast<ash::DragDropController*>( + aura::client::GetDragDropClient(ash::Shell::GetPrimaryRootWindow())); + EXPECT_FALSE(shell_surface->IsDragged()); + base::RunLoop loop; + drag_drop_controller->SetLoopClosureForTesting( + base::BindLambdaForTesting([&]() { + // The drag session must have been started by the time + // drag loop starts. + EXPECT_TRUE(shell_surface->IsDragged()); + drag_drop_controller->DragCancel(); + loop.Quit(); + }), + base::DoNothing()); + loop.Run(); + operation.reset(); + EXPECT_FALSE(shell_surface->IsDragged()); +} + } // namespace exo
diff --git a/components/exo/shell_surface.cc b/components/exo/shell_surface.cc index 5a409c27..600ff243 100644 --- a/components/exo/shell_surface.cc +++ b/components/exo/shell_surface.cc
@@ -4,6 +4,7 @@ #include "components/exo/shell_surface.h" +#include "ash/frame/non_client_frame_view_ash.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/scoped_animation_disabler.h" #include "ash/shell.h" @@ -39,6 +40,14 @@ // fullscreen or pinned state. constexpr int kMaximizedOrFullscreenOrPinnedLockTimeoutMs = 100; +gfx::Rect GetClientBoundsInScreen(views::Widget* widget) { + ash::NonClientFrameViewAsh* frame_view = + static_cast<ash::NonClientFrameViewAsh*>( + widget->non_client_view()->frame_view()); + gfx::Rect window_bounds = widget->GetWindowBoundsInScreen(); + return frame_view->GetClientBoundsForWindowBounds(window_bounds); +} + } // namespace //////////////////////////////////////////////////////////////////////////////// @@ -110,6 +119,7 @@ DCHECK(!scoped_configure_); // Client is gone by now, so don't call callback. configure_callback_.Reset(); + origin_change_callback_.Reset(); if (widget_) ash::WindowState::Get(widget_->GetNativeWindow())->RemoveObserver(this); } @@ -373,8 +383,11 @@ return; if (window == widget_->GetNativeWindow()) { - if (new_bounds.size() == old_bounds.size()) + if (new_bounds.size() == old_bounds.size()) { + if (!origin_change_callback_.is_null()) + origin_change_callback_.Run(GetClientBoundsInScreen(widget_).origin()); return; + } // If size changed then give the client a chance to produce new contents // before origin on screen is changed. Retain the old origin by reverting @@ -565,10 +578,10 @@ if (!configure_callback_.is_null()) { if (window_state) { serial = configure_callback_.Run( - GetClientViewBounds().size(), window_state->GetStateType(), + GetClientBoundsInScreen(widget_), window_state->GetStateType(), IsResizing(), widget_->IsActive(), origin_offset); } else { - serial = configure_callback_.Run(gfx::Size(), + serial = configure_callback_.Run(gfx::Rect(), chromeos::WindowStateType::kNormal, false, false, origin_offset); }
diff --git a/components/exo/shell_surface.h b/components/exo/shell_surface.h index 9822c62..73d8eab 100644 --- a/components/exo/shell_surface.h +++ b/components/exo/shell_surface.h
@@ -44,15 +44,23 @@ // it doesn't resize, pick a smaller size (to satisfy aspect ratio or resize // in steps of NxM pixels). using ConfigureCallback = - base::RepeatingCallback<uint32_t(const gfx::Size& size, + base::RepeatingCallback<uint32_t(const gfx::Rect& bounds, chromeos::WindowStateType state_type, bool resizing, bool activated, const gfx::Vector2d& origin_offset)>; + using OriginChangeCallback = + base::RepeatingCallback<void(const gfx::Point& origin)>; + void set_configure_callback(const ConfigureCallback& configure_callback) { configure_callback_ = configure_callback; } + void set_origin_change_callback( + const OriginChangeCallback& origin_change_callback) { + origin_change_callback_ = origin_change_callback; + } + // When the client is asked to configure the surface, it should acknowledge // the configure request sometime before the commit. |serial| is the serial // from the configure callback. @@ -167,6 +175,7 @@ std::unique_ptr<ui::CompositorLock> configure_compositor_lock_; ConfigureCallback configure_callback_; + OriginChangeCallback origin_change_callback_; ScopedConfigure* scoped_configure_ = nullptr; base::circular_deque<std::unique_ptr<Config>> pending_configs_;
diff --git a/components/exo/shell_surface_base.cc b/components/exo/shell_surface_base.cc index ac94598..b8700a2 100644 --- a/components/exo/shell_surface_base.cc +++ b/components/exo/shell_surface_base.cc
@@ -662,6 +662,19 @@ pending_geometry_ = geometry; } +void ShellSurfaceBase::SetWindowBounds(const gfx::Rect& bounds) { + TRACE_EVENT1("exo", "ShellSurfaceBase::SetWindowBounds", "bounds", + bounds.ToString()); + if (!widget_) { + // TODO(crbug.com/1261321): Handle initial bounds. + return; + } + // TODO(crbug.com/1261321): This will not work if the full server side + // decoration is used. + DCHECK(!frame_enabled()); + widget_->SetBounds(bounds); +} + void ShellSurfaceBase::SetDisplay(int64_t display_id) { TRACE_EVENT1("exo", "ShellSurfaceBase::SetDisplay", "display_id", display_id); @@ -1185,6 +1198,15 @@ } } +// Returns true if surface is currently being resized. +bool ShellSurfaceBase::IsDragged() const { + if (in_extended_drag_) + return true; + ash::WindowState* window_state = + ash::WindowState::Get(widget_->GetNativeWindow()); + return window_state->is_dragged(); +} + //////////////////////////////////////////////////////////////////////////////// // ui::AcceleratorTarget overrides: @@ -1407,9 +1429,10 @@ origin += GetSurfaceOrigin().OffsetFromOrigin(); origin -= ToFlooredVector2d(ScaleVector2d( root_surface_origin().OffsetFromOrigin(), 1.f / GetScale())); - - if (host_window()->bounds().origin() != origin) - host_window()->SetBounds(gfx::Rect(origin, host_window()->bounds().size())); + gfx::Rect surface_bounds(origin, host_window()->bounds().size()); + if (host_window()->bounds() == surface_bounds) + return; + host_window()->SetBounds(surface_bounds); } void ShellSurfaceBase::UpdateShadow() {
diff --git a/components/exo/shell_surface_base.h b/components/exo/shell_surface_base.h index 6be021f5..a8c2bdde 100644 --- a/components/exo/shell_surface_base.h +++ b/components/exo/shell_surface_base.h
@@ -85,6 +85,16 @@ surface_destroyed_callback_ = std::move(surface_destroyed_callback); } + // Whether the connected client supports setting window bounds and is + // expecting to receive window origin in configure updates. + bool client_supports_window_bounds() const { + return client_supports_window_bounds_; + } + + void set_client_supports_window_bounds(bool enable) { + client_supports_window_bounds_ = enable; + } + // Activates the shell surface. void Activate(); @@ -147,6 +157,10 @@ bool can_minimize, int container); + // Set the window bounds. The bounds specify 'visible bounds' of the + // shell surface. + void SetWindowBounds(const gfx::Rect& bounds_in_screen); + // Returns a trace value representing the state of the surface. std::unique_ptr<base::trace_event::TracedValue> AsTracedValue() const; @@ -272,6 +286,13 @@ return overlay_widget_.get(); } + // Returns true if surface is currently being dragged. + bool IsDragged() const; + + void set_in_extended_drag(bool in_extended_drag) { + in_extended_drag_ = in_extended_drag; + } + protected: // Creates the |widget_| for |surface_|. |show_state| is the initial state // of the widget (e.g. maximized). @@ -350,6 +371,7 @@ gfx::Rect geometry_; gfx::Rect pending_geometry_; gfx::Size initial_size_; + int64_t display_id_ = display::kInvalidDisplayId; int64_t pending_display_id_ = display::kInvalidDisplayId; absl::optional<gfx::Rect> shadow_bounds_; @@ -359,6 +381,7 @@ bool has_grab_ = false; bool server_side_resize_ = false; bool needs_layout_on_show_ = false; + bool client_supports_window_bounds_ = false; // The orientation to be applied when widget is being created. Only set when // widget is not created yet orientation lock is being set. This is currently @@ -412,6 +435,7 @@ gfx::Size pending_maximum_size_; gfx::SizeF pending_aspect_ratio_; bool pending_pip_ = false; + bool in_extended_drag_ = false; absl::optional<std::string> initial_workspace_; // Overlay members.
diff --git a/components/exo/shell_surface_unittest.cc b/components/exo/shell_surface_unittest.cc index 2b41d522..f3a0b20 100644 --- a/components/exo/shell_surface_unittest.cc +++ b/components/exo/shell_surface_unittest.cc
@@ -65,7 +65,7 @@ } uint32_t ConfigureFullscreen(uint32_t serial, - const gfx::Size& size, + const gfx::Rect& bounds, chromeos::WindowStateType state_type, bool resizing, bool activated, @@ -674,7 +674,7 @@ uint32_t serial = 0; auto configure_callback = base::BindRepeating( - [](uint32_t* const serial_ptr, const gfx::Size& size, + [](uint32_t* const serial_ptr, const gfx::Rect& bounds, chromeos::WindowStateType state_type, bool resizing, bool activated, const gfx::Vector2d& origin_offset) { return ++(*serial_ptr); }, &serial); @@ -694,7 +694,7 @@ surface->Commit(); shell_surface->set_configure_callback(base::BindRepeating( - [](const gfx::Size& size, chromeos::WindowStateType state_type, + [](const gfx::Rect& bounds, chromeos::WindowStateType state_type, bool resizing, bool activated, const gfx::Vector2d& origin_offset) { ADD_FAILURE() << "Configure Should not be called"; return uint32_t{0}; @@ -849,16 +849,16 @@ EXPECT_EQ(surface_destroyed_ctr, 1); } -uint32_t Configure(gfx::Size* suggested_size, +uint32_t Configure(gfx::Rect* suggested_bounds, chromeos::WindowStateType* has_state_type, bool* is_resizing, bool* is_active, - const gfx::Size& size, + const gfx::Rect& bounds, chromeos::WindowStateType state_type, bool resizing, bool activated, const gfx::Vector2d& origin_offset) { - *suggested_size = size; + *suggested_bounds = bounds; *has_state_type = state_type; *is_resizing = resizing; *is_active = activated; @@ -868,7 +868,7 @@ TEST_F(ShellSurfaceTest, ConfigureCallback) { // Must be before shell_surface so it outlives it, for shell_surface's // destructor calls Configure() referencing these 4 variables. - gfx::Size suggested_size; + gfx::Rect suggested_bounds; chromeos::WindowStateType has_state_type = chromeos::WindowStateType::kNormal; bool is_resizing = false; bool is_active = false; @@ -877,7 +877,7 @@ std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get())); shell_surface->set_configure_callback(base::BindRepeating( - &Configure, base::Unretained(&suggested_size), + &Configure, base::Unretained(&suggested_bounds), base::Unretained(&has_state_type), base::Unretained(&is_resizing), base::Unretained(&is_active))); @@ -887,7 +887,7 @@ // Commit without contents should result in a configure callback with empty // suggested size as a mechanisms to ask the client size itself. surface->Commit(); - EXPECT_TRUE(suggested_size.IsEmpty()); + EXPECT_TRUE(suggested_bounds.IsEmpty()); EXPECT_TRUE(shell_surface->GetWidget()); EXPECT_FALSE(shell_surface->GetWidget()->IsVisible()); EXPECT_EQ(geometry.size(), shell_surface->CalculatePreferredSize()); @@ -900,8 +900,8 @@ shell_surface->Maximize(); shell_surface->AcknowledgeConfigure(0); - EXPECT_FALSE(suggested_size.IsEmpty()); - EXPECT_EQ(maximized_bounds.size(), suggested_size); + EXPECT_FALSE(suggested_bounds.IsEmpty()); + EXPECT_EQ(maximized_bounds.size(), suggested_bounds.size()); EXPECT_EQ(chromeos::WindowStateType::kMaximized, has_state_type); gfx::Size buffer_size(64, 64); @@ -911,7 +911,7 @@ surface->Commit(); EXPECT_TRUE(shell_surface->GetWidget()); - EXPECT_EQ(maximized_bounds.size(), suggested_size); + EXPECT_EQ(maximized_bounds.size(), suggested_bounds.size()); EXPECT_EQ(chromeos::WindowStateType::kMaximized, has_state_type); shell_surface->Restore(); shell_surface->AcknowledgeConfigure(0); @@ -920,8 +920,7 @@ shell_surface->SetFullscreen(true); shell_surface->AcknowledgeConfigure(0); - EXPECT_EQ(GetContext()->bounds().size().ToString(), - suggested_size.ToString()); + EXPECT_EQ(GetContext()->bounds().size(), suggested_bounds.size()); EXPECT_EQ(chromeos::WindowStateType::kFullscreen, has_state_type); shell_surface->SetFullscreen(false); shell_surface->AcknowledgeConfigure(0); @@ -943,7 +942,7 @@ TEST_F(ShellSurfaceTest, CreateMinimizedWindow) { // Must be before shell_surface so it outlives it, for shell_surface's // destructor calls Configure() referencing these 4 variables. - gfx::Size suggested_size; + gfx::Rect suggested_bounds; chromeos::WindowStateType has_state_type = chromeos::WindowStateType::kNormal; bool is_resizing = false; bool is_active = false; @@ -952,7 +951,7 @@ std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get())); shell_surface->set_configure_callback(base::BindRepeating( - &Configure, base::Unretained(&suggested_size), + &Configure, base::Unretained(&suggested_bounds), base::Unretained(&has_state_type), base::Unretained(&is_resizing), base::Unretained(&is_active))); @@ -966,14 +965,14 @@ EXPECT_TRUE(shell_surface->GetWidget()); EXPECT_TRUE(shell_surface->GetWidget()->IsMinimized()); - EXPECT_TRUE(suggested_size.IsEmpty()); + EXPECT_TRUE(suggested_bounds.IsEmpty()); EXPECT_EQ(geometry.size(), shell_surface->CalculatePreferredSize()); } TEST_F(ShellSurfaceTest, CreateMinimizedWindow2) { // Must be before shell_surface so it outlives it, for shell_surface's // destructor calls Configure() referencing these 4 variables. - gfx::Size suggested_size; + gfx::Rect suggested_bounds; auto has_state_type = chromeos::WindowStateType::kNormal; bool is_resizing = false; bool is_active = false; @@ -982,7 +981,7 @@ std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get())); shell_surface->set_configure_callback(base::BindRepeating( - &Configure, base::Unretained(&suggested_size), + &Configure, base::Unretained(&suggested_bounds), base::Unretained(&has_state_type), base::Unretained(&is_resizing), base::Unretained(&is_active))); @@ -992,7 +991,7 @@ // Commit without contents should result in a configure callback with empty // suggested size as a mechanisms to ask the client size itself. surface->Commit(); - EXPECT_TRUE(suggested_size.IsEmpty()); + EXPECT_TRUE(suggested_bounds.IsEmpty()); EXPECT_TRUE(shell_surface->GetWidget()); EXPECT_FALSE(shell_surface->GetWidget()->IsVisible()); EXPECT_EQ(geometry.size(), shell_surface->CalculatePreferredSize()); @@ -1010,14 +1009,14 @@ // Once the initial empty size is sent in configure, // new configure should send the size requested. - EXPECT_EQ(geometry.size(), suggested_size); + EXPECT_EQ(geometry.size(), suggested_bounds.size()); } TEST_F(ShellSurfaceTest, CreateMaximizedWindowWithRestoreBoundsWithoutInitialBuffer) { // Must be before shell_surface so it outlives it, for shell_surface's // destructor calls Configure() referencing these 4 variables. - gfx::Size suggested_size; + gfx::Rect suggested_bounds; chromeos::WindowStateType has_state_type = chromeos::WindowStateType::kNormal; bool is_resizing = false; bool is_active = false; @@ -1029,7 +1028,7 @@ .BuildShellSurface(); shell_surface->set_configure_callback(base::BindRepeating( - &Configure, base::Unretained(&suggested_size), + &Configure, base::Unretained(&suggested_bounds), base::Unretained(&has_state_type), base::Unretained(&is_resizing), base::Unretained(&is_active))); @@ -1075,7 +1074,7 @@ TEST_F(ShellSurfaceTest, CreateMaximizedWindowWithRestoreBounds) { // Must be before shell_surface so it outlives it, for shell_surface's // destructor calls Configure() referencing these 4 variables. - gfx::Size suggested_size; + gfx::Rect suggested_bounds; chromeos::WindowStateType has_state_type = chromeos::WindowStateType::kNormal; bool is_resizing = false; bool is_active = false; @@ -1087,7 +1086,7 @@ std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get())); shell_surface->set_configure_callback(base::BindRepeating( - &Configure, base::Unretained(&suggested_size), + &Configure, base::Unretained(&suggested_bounds), base::Unretained(&has_state_type), base::Unretained(&is_resizing), base::Unretained(&is_active))); @@ -1131,9 +1130,8 @@ surface->Attach(buffer.get()); surface->Commit(); EXPECT_FALSE(HasBackdrop()); - EXPECT_EQ( - buffer_size.ToString(), - shell_surface->GetWidget()->GetWindowBoundsInScreen().size().ToString()); + EXPECT_EQ(buffer_size, + shell_surface->GetWidget()->GetWindowBoundsInScreen().size()); shell_surface->Maximize(); EXPECT_FALSE(HasBackdrop()); EXPECT_EQ(GetContext()->bounds().width(), @@ -1544,8 +1542,8 @@ chromeos::WindowStateType configured_state = chromeos::WindowStateType::kDefault; shell_surface->set_configure_callback(base::BindLambdaForTesting( - [&](const gfx::Size& size, chromeos::WindowStateType state, bool resizing, - bool activated, const gfx::Vector2d& origin_offset) { + [&](const gfx::Rect& bounds, chromeos::WindowStateType state, + bool resizing, bool activated, const gfx::Vector2d& origin_offset) { configured_state = state; return uint32_t{0}; })); @@ -1759,7 +1757,7 @@ gfx::Rect new_bounds(new_size); uint32_t serial = 0; auto configure_callback = base::BindRepeating( - [](uint32_t* const serial_ptr, const gfx::Size& size, + [](uint32_t* const serial_ptr, const gfx::Rect& bounds, chromeos::WindowStateType state_type, bool resizing, bool activated, const gfx::Vector2d& origin_offset) { return ++(*serial_ptr); }, &serial); @@ -2134,4 +2132,62 @@ shell_surface->root_surface()->RemoveSurfaceObserver(&observer); } +namespace { + +struct ShellSurfaceCallbacks { + struct ConfigureState { + gfx::Rect bounds; + chromeos::WindowStateType state_type; + bool resizing; + bool activated; + }; + + uint32_t OnConfigure(const gfx::Rect& bounds, + chromeos::WindowStateType state_type, + bool resizing, + bool activated, + const gfx::Vector2d& origin_offset) { + configure_state.emplace(); + *configure_state = {bounds, state_type, resizing, activated}; + // The serial number is not used, not important in this test. + return 0; + } + void OnOriginChange(const gfx::Point& origin_) { origin = origin_; } + void Reset() { + configure_state.reset(); + origin.reset(); + } + absl::optional<ConfigureState> configure_state; + absl::optional<gfx::Point> origin; +}; + +} // namespace + +TEST_F(ShellSurfaceTest, ScreenCoordinates) { + auto shell_surface = test::ShellSurfaceBuilder({20, 20}).BuildShellSurface(); + ShellSurfaceCallbacks callbacks; + + shell_surface->set_configure_callback(base::BindRepeating( + &ShellSurfaceCallbacks::OnConfigure, base::Unretained(&callbacks))); + shell_surface->set_origin_change_callback(base::BindRepeating( + &ShellSurfaceCallbacks::OnOriginChange, base::Unretained(&callbacks))); + + shell_surface->SetWindowBounds(gfx::Rect(10, 10, 300, 300)); + ASSERT_TRUE(!!callbacks.configure_state); + ASSERT_TRUE(!callbacks.origin); + EXPECT_EQ(callbacks.configure_state->bounds, gfx::Rect(10, 10, 300, 300)); + + callbacks.Reset(); + shell_surface->SetWindowBounds(gfx::Rect(100, 100, 300, 300)); + ASSERT_TRUE(!callbacks.configure_state); + ASSERT_TRUE(!!callbacks.origin); + EXPECT_EQ(*callbacks.origin, gfx::Point(100, 100)); + + callbacks.Reset(); + shell_surface->SetWindowBounds(gfx::Rect(0, 0, 300000, 300000)); + ASSERT_TRUE(!!callbacks.configure_state); + EXPECT_EQ(callbacks.configure_state->bounds, + display::Screen::GetScreen()->GetPrimaryDisplay().work_area()); +} + } // namespace exo
diff --git a/components/exo/test/exo_test_data_exchange_delegate.cc b/components/exo/test/exo_test_data_exchange_delegate.cc index 56cd011..9c02a620 100644 --- a/components/exo/test/exo_test_data_exchange_delegate.cc +++ b/components/exo/test/exo_test_data_exchange_delegate.cc
@@ -9,6 +9,7 @@ #include <vector> #include "base/callback.h" +#include "base/files/file_util.h" #include "base/memory/ref_counted_memory.h" #include "base/pickle.h" #include "base/strings/string_split.h" @@ -97,4 +98,35 @@ return file_info; } +TestDataSourceDelegate::TestDataSourceDelegate() = default; +TestDataSourceDelegate::~TestDataSourceDelegate() = default; + +void TestDataSourceDelegate::OnSend(const std::string& mime_type, + base::ScopedFD fd) { + constexpr char kText[] = "test"; + if (data_map_.empty()) { + base::WriteFileDescriptor(fd.get(), kText); + } else { + base::WriteFileDescriptor(fd.get(), data_map_[mime_type]); + } +} + +void TestDataSourceDelegate::OnCancelled() { + cancelled_ = true; +} + +void TestDataSourceDelegate::OnDndFinished() { + finished_ = true; +} + +bool TestDataSourceDelegate::CanAcceptDataEventsForSurface( + Surface* surface) const { + return true; +} + +void TestDataSourceDelegate::SetData(const std::string& mime_type, + std::vector<uint8_t> data) { + data_map_[mime_type] = std::move(data); +} + } // namespace exo
diff --git a/components/exo/test/exo_test_data_exchange_delegate.h b/components/exo/test/exo_test_data_exchange_delegate.h index a428f2f3..0288823 100644 --- a/components/exo/test/exo_test_data_exchange_delegate.h +++ b/components/exo/test/exo_test_data_exchange_delegate.h
@@ -6,6 +6,7 @@ #define COMPONENTS_EXO_TEST_EXO_TEST_DATA_EXCHANGE_DELEGATE_H_ #include "components/exo/data_exchange_delegate.h" +#include "components/exo/data_source_delegate.h" #include "ui/base/data_transfer_policy/data_transfer_endpoint.h" @@ -49,6 +50,38 @@ SendDataCallback send_pickle_callback_; }; +class TestDataSourceDelegate : public DataSourceDelegate { + public: + TestDataSourceDelegate(); + ~TestDataSourceDelegate() override; + + bool cancelled() const { return cancelled_; } + + // DataSourceDelegate: + void OnDataSourceDestroying(DataSource* source) override {} + + void OnTarget(const absl::optional<std::string>& mime_type) override {} + + void OnSend(const std::string& mime_type, base::ScopedFD fd) override; + + void OnCancelled() override; + + void OnDndDropPerformed() override {} + + void OnDndFinished() override; + + void OnAction(DndAction dnd_action) override {} + + bool CanAcceptDataEventsForSurface(Surface* surface) const override; + + void SetData(const std::string& mime_type, std::vector<uint8_t> data); + + private: + bool cancelled_ = false; + bool finished_ = false; + base::flat_map<std::string, std::vector<uint8_t>> data_map_; +}; + } // namespace exo #endif // COMPONENTS_EXO_TEST_EXO_TEST_DATA_EXCHANGE_DELEGATE_H_
diff --git a/components/exo/wayland/protocol/aura-shell.xml b/components/exo/wayland/protocol/aura-shell.xml index d179af5..4156e70 100644 --- a/components/exo/wayland/protocol/aura-shell.xml +++ b/components/exo/wayland/protocol/aura-shell.xml
@@ -616,7 +616,7 @@ </event> </interface> - <interface name="zaura_toplevel" version="28"> + <interface name="zaura_toplevel" version="29"> <description summary="aura shell interface to the toplevel shell"> An interface to the toplevel shell, which allows the client to access shell specific functionality. @@ -650,6 +650,57 @@ scale transform for the submitted buffers to be composited correctly. </description> </request> + + <request name="set_supports_screen_coordinates" since="29"> + <description summary="enables screen coordinates in window bounds"> + Requesting this will enable screen coordinates in surfaces + associated with aura_toplevel including sub surfaces and popup + windows who added this toplevel as a parent. This should be + set before first commit. + </description> + </request> + + <request name="set_window_bounds" since="29"> + <description summary="set window size and position"> + Request a new location and bounds of the surface in DP screen + coordinates. The size will be applied to visible bounds used + in set_geometry. The output is a hint for the compositor to + determine which output the window should move to. These + parameters are just a request and the compositor may ignore, + adjust the size and position based on the rule imposed by the + window manager, or may preserve it for future operations. For + example, the compositor will not allow a position outside of + the output, or the compositor may just store it if the + toplevel surface is in maximiezd state, and may use it upon + unmaximized. + </description> + <arg name="x" type="int"/> + <arg name="y" type="int"/> + <arg name="width" type="int"/> + <arg name="height" type="int"/> + <arg name="output" type="object" interface="wl_output" summary="the output"/> + </request> + + <event name="configure" since="29"> + <description summary="suggest a surface change"> + A configuration change that also includes the window origin in screen coordinates. + </description> + <arg name="x" type="int"/> + <arg name="y" type="int"/> + <arg name="width" type="int"/> + <arg name="height" type="int"/> + <arg name="states" type="array"/> + </event> + + <event name="origin_change" since="29"> + <description summary="window origin change"> + A notification sent when the window origin has changed. Unlike a configure, + this does not imply the client needs to resize. The values are in screen + coordinates. + </description> + <arg name="x" type="int" /> + <arg name="y" type="int" /> + </event> </interface> <interface name="zaura_popup" version="28">
diff --git a/components/exo/wayland/wl_shell.cc b/components/exo/wayland/wl_shell.cc index 96fe71d..41883a6 100644 --- a/components/exo/wayland/wl_shell.cc +++ b/components/exo/wayland/wl_shell.cc
@@ -124,13 +124,13 @@ uint32_t HandleShellSurfaceConfigureCallback( wl_resource* resource, - const gfx::Size& size, + const gfx::Rect& bounds, chromeos::WindowStateType state_type, bool resizing, bool activated, const gfx::Vector2d& origin_offset) { wl_shell_surface_send_configure(resource, WL_SHELL_SURFACE_RESIZE_NONE, - size.width(), size.height()); + bounds.width(), bounds.height()); wl_client_flush(wl_resource_get_client(resource)); return 0; }
diff --git a/components/exo/wayland/xdg_shell.cc b/components/exo/wayland/xdg_shell.cc index 46cc00a..39ec305f 100644 --- a/components/exo/wayland/xdg_shell.cc +++ b/components/exo/wayland/xdg_shell.cc
@@ -133,14 +133,14 @@ wl_resource* resource, SerialTracker* serial_tracker, const XdgSurfaceConfigureCallback& callback, - const gfx::Size& size, + const gfx::Rect& bounds, chromeos::WindowStateType state_type, bool resizing, bool activated, const gfx::Vector2d& origin_offset) { uint32_t serial = serial_tracker->GetNextSerial(SerialTracker::EventType::OTHER_EVENT); - callback.Run(size, state_type, resizing, activated); + callback.Run(bounds.size(), state_type, resizing, activated); xdg_surface_send_configure(resource, serial); wl_client_flush(wl_resource_get_client(resource)); return serial; @@ -165,16 +165,18 @@ // xdg surface resource is destroyed before the toplevel resource. class WaylandToplevel : public aura::WindowObserver { public: - WaylandToplevel(wl_resource* resource, wl_resource* surface_resource) - : resource_(resource), + WaylandToplevel(wl_resource* xdg_toplevel_resource, + wl_resource* xdg_surface_resource) + : xdg_toplevel_resource_(xdg_toplevel_resource), + xdg_surface_resource_(xdg_surface_resource), shell_surface_data_( - GetUserDataAs<WaylandXdgSurface>(surface_resource)) { + GetUserDataAs<WaylandXdgSurface>(xdg_surface_resource)) { shell_surface_data_->shell_surface->host_window()->AddObserver(this); shell_surface_data_->shell_surface->set_close_callback(base::BindRepeating( &WaylandToplevel::OnClose, weak_ptr_factory_.GetWeakPtr())); shell_surface_data_->shell_surface->set_configure_callback( base::BindRepeating( - &HandleXdgSurfaceConfigureCallback, surface_resource, + &HandleXdgSurfaceConfigureCallback, xdg_surface_resource, shell_surface_data_->serial_tracker, base::BindRepeating(&WaylandToplevel::OnConfigure, weak_ptr_factory_.GetWeakPtr()))); @@ -277,14 +279,16 @@ shell_surface_data_->shell_surface->OnSetFrame(type); } - ShellSurfaceBase* GetShellSurface() { - return shell_surface_data_->shell_surface.get(); + ShellSurfaceData GetShellSurfaceData() { + return ShellSurfaceData(shell_surface_data_->shell_surface.get(), + shell_surface_data_->serial_tracker, + xdg_surface_resource_); } private: void OnClose() { - xdg_toplevel_send_close(resource_); - wl_client_flush(wl_resource_get_client(resource_)); + xdg_toplevel_send_close(xdg_toplevel_resource_); + wl_client_flush(wl_resource_get_client(xdg_toplevel_resource_)); } static void AddState(wl_array* states, xdg_toplevel_state state) { @@ -310,12 +314,13 @@ AddState(&states, XDG_TOPLEVEL_STATE_RESIZING); if (activated) AddState(&states, XDG_TOPLEVEL_STATE_ACTIVATED); - xdg_toplevel_send_configure(resource_, size.width(), size.height(), - &states); + xdg_toplevel_send_configure(xdg_toplevel_resource_, size.width(), + size.height(), &states); wl_array_release(&states); } - wl_resource* const resource_; + wl_resource* const xdg_toplevel_resource_; + wl_resource* const xdg_surface_resource_; WaylandXdgSurface* shell_surface_data_; base::WeakPtrFactory<WaylandToplevel> weak_ptr_factory_{this}; }; @@ -550,11 +555,13 @@ } void xdg_surface_get_toplevel(wl_client* client, - wl_resource* resource, + wl_resource* xdg_surface_resource, uint32_t id) { - auto* shell_surface_data = GetUserDataAs<WaylandXdgSurface>(resource); + auto* shell_surface_data = + GetUserDataAs<WaylandXdgSurface>(xdg_surface_resource); if (shell_surface_data->shell_surface->GetEnabled()) { - wl_resource_post_error(resource, XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED, + wl_resource_post_error(xdg_surface_resource, + XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED, "surface has already been constructed"); return; } @@ -565,9 +572,9 @@ wl_resource* xdg_toplevel_resource = wl_resource_create(client, &xdg_toplevel_interface, 1, id); - SetImplementation( - xdg_toplevel_resource, &xdg_toplevel_implementation, - std::make_unique<WaylandToplevel>(xdg_toplevel_resource, resource)); + SetImplementation(xdg_toplevel_resource, &xdg_toplevel_implementation, + std::make_unique<WaylandToplevel>(xdg_toplevel_resource, + xdg_surface_resource)); } void xdg_surface_get_popup(wl_client* client, @@ -806,9 +813,9 @@ nullptr); } -ShellSurfaceBase* GetShellSurfaceFromToplevelResource(wl_resource* resource) { +ShellSurfaceData GetShellSurfaceFromToplevelResource(wl_resource* resource) { auto* toplevel = GetUserDataAs<WaylandToplevel>(resource); - return toplevel->GetShellSurface(); + return toplevel->GetShellSurfaceData(); } ShellSurfaceBase* GetShellSurfaceFromPopupResource(wl_resource* resource) {
diff --git a/components/exo/wayland/xdg_shell.h b/components/exo/wayland/xdg_shell.h index bd0ae531..fb29e26 100644 --- a/components/exo/wayland/xdg_shell.h +++ b/components/exo/wayland/xdg_shell.h
@@ -13,6 +13,7 @@ namespace exo { class Display; class ShellSurfaceBase; +class ShellSurface; namespace wayland { class SerialTracker; @@ -36,7 +37,26 @@ uint32_t version, uint32_t id); -ShellSurfaceBase* GetShellSurfaceFromToplevelResource( +struct ShellSurfaceData { + ShellSurfaceData(ShellSurface* shell_surface, + SerialTracker* serial_tracker, + wl_resource* surface_resource) + : shell_surface(shell_surface), + serial_tracker(serial_tracker), + surface_resource(surface_resource) {} + + ShellSurfaceData(const ShellSurfaceData&) = delete; + ShellSurfaceData& operator=(const ShellSurfaceData&) = delete; + + ShellSurface* const shell_surface; + + // Owned by Server, which always outlives xdg_shell. + SerialTracker* const serial_tracker; + + wl_resource* const surface_resource; +}; + +ShellSurfaceData GetShellSurfaceFromToplevelResource( wl_resource* surface_resource); ShellSurfaceBase* GetShellSurfaceFromPopupResource(
diff --git a/components/exo/wayland/zaura_shell.cc b/components/exo/wayland/zaura_shell.cc index c41e7988..b3e05d7 100644 --- a/components/exo/wayland/zaura_shell.cc +++ b/components/exo/wayland/zaura_shell.cc
@@ -7,6 +7,7 @@ #include <aura-shell-server-protocol.h> #include <wayland-server-core.h> #include <wayland-server-protocol-core.h> +#include <xdg-shell-server-protocol.h> #include <algorithm> #include <limits> @@ -19,11 +20,13 @@ #include "base/logging.h" #include "base/strings/string_number_conversions.h" #include "build/chromeos_buildflags.h" +#include "chromeos/ui/base/window_state_type.h" #include "components/exo/display.h" #include "components/exo/seat.h" #include "components/exo/seat_observer.h" #include "components/exo/shell_surface.h" #include "components/exo/shell_surface_base.h" +#include "components/exo/wayland/serial_tracker.h" #include "components/exo/wayland/server_util.h" #include "components/exo/wayland/wayland_display_observer.h" #include "components/exo/wayland/wl_output.h" @@ -649,8 +652,37 @@ return chromeos::OrientationType::kAny; } -AuraToplevel::AuraToplevel(ShellSurfaceBase* shell_surface) - : shell_surface_(shell_surface) { +using AuraSurfaceConfigureCallback = + base::RepeatingCallback<void(const gfx::Rect& bounds, + chromeos::WindowStateType state_type, + bool resizing, + bool activated)>; + +uint32_t HandleAuraSurfaceConfigureCallback( + wl_resource* resource, + SerialTracker* serial_tracker, + const AuraSurfaceConfigureCallback& callback, + const gfx::Rect& bounds, + chromeos::WindowStateType state_type, + bool resizing, + bool activated, + const gfx::Vector2d& origin_offset) { + uint32_t serial = + serial_tracker->GetNextSerial(SerialTracker::EventType::OTHER_EVENT); + callback.Run(bounds, state_type, resizing, activated); + xdg_surface_send_configure(resource, serial); + wl_client_flush(wl_resource_get_client(resource)); + return serial; +} + +AuraToplevel::AuraToplevel(ShellSurface* shell_surface, + SerialTracker* const serial_tracker, + wl_resource* xdg_toplevel_resource, + wl_resource* aura_toplevel_resource) + : shell_surface_(shell_surface), + serial_tracker_(serial_tracker), + xdg_toplevel_resource_(xdg_toplevel_resource), + aura_toplevel_resource_(aura_toplevel_resource) { DCHECK(shell_surface); } @@ -664,6 +696,62 @@ shell_surface_->set_client_submits_surfaces_in_pixel_coordinates(enable); } +void AuraToplevel::SetWindowBounds(int32_t x, + int32_t y, + int32_t width, + int32_t height) { + if (!shell_surface_->IsDragged()) + shell_surface_->SetWindowBounds(gfx::Rect(x, y, width, height)); +} + +void AuraToplevel::OnOriginChange(const gfx::Point& origin) { + zaura_toplevel_send_origin_change(aura_toplevel_resource_, origin.x(), + origin.y()); + wl_client_flush(wl_resource_get_client(aura_toplevel_resource_)); +} + +void AuraToplevel::SetClientUsesScreenCoordinates() { + supports_window_bounds_ = true; + shell_surface_->set_client_supports_window_bounds(true); + shell_surface_->set_configure_callback( + base::BindRepeating(&HandleAuraSurfaceConfigureCallback, + xdg_toplevel_resource_, serial_tracker_, + base::BindRepeating(&AuraToplevel::OnConfigure, + weak_ptr_factory_.GetWeakPtr()))); + shell_surface_->set_origin_change_callback(base::BindRepeating( + &AuraToplevel::OnOriginChange, weak_ptr_factory_.GetWeakPtr())); +} + +void AddState(wl_array* states, xdg_toplevel_state state) { + xdg_toplevel_state* value = static_cast<xdg_toplevel_state*>( + wl_array_add(states, sizeof(xdg_toplevel_state))); + DCHECK(value); + *value = state; +} + +void AuraToplevel::OnConfigure(const gfx::Rect& bounds, + chromeos::WindowStateType state_type, + bool resizing, + bool activated) { + wl_array states; + wl_array_init(&states); + if (state_type == chromeos::WindowStateType::kMaximized) + AddState(&states, XDG_TOPLEVEL_STATE_MAXIMIZED); + // TODO(crbug/1250129): Pinned states need to be handled properly. + // TODO(crbug/1250129): Support snapped state. + if (IsFullscreenOrPinnedWindowStateType(state_type)) { + AddState(&states, XDG_TOPLEVEL_STATE_FULLSCREEN); + } + if (resizing) + AddState(&states, XDG_TOPLEVEL_STATE_RESIZING); + if (activated) + AddState(&states, XDG_TOPLEVEL_STATE_ACTIVATED); + + zaura_toplevel_send_configure(aura_toplevel_resource_, bounds.x(), bounds.y(), + bounds.width(), bounds.height(), &states); + wl_array_release(&states); +} + AuraPopup::AuraPopup(ShellSurfaceBase* shell_surface) : shell_surface_(shell_surface) { DCHECK(shell_surface); @@ -943,6 +1031,11 @@ GetUserDataAs<AuraToplevel>(resource)->SetOrientationLock(orientation_lock); } +void aura_toplevel_set_client_supports_window_bounds(wl_client* client, + wl_resource* resource) { + GetUserDataAs<AuraToplevel>(resource)->SetClientUsesScreenCoordinates(); +} + void aura_toplevel_surface_submission_in_pixel_coordinates( wl_client* client, wl_resource* resource) { @@ -950,9 +1043,23 @@ ->SetClientSubmitsSurfacesInPixelCoordinates(true); } +void aura_toplevel_set_window_bounds(wl_client* client, + wl_resource* resource, + int32_t x, + int32_t y, + int32_t width, + int32_t height, + wl_resource* output) { + // TODO(crbug.com/1261321): Use output hint. + GetUserDataAs<AuraToplevel>(resource)->SetWindowBounds(x, y, width, height); +} + const struct zaura_toplevel_interface aura_toplevel_implementation = { aura_toplevel_set_orientation_lock, - aura_toplevel_surface_submission_in_pixel_coordinates}; + aura_toplevel_surface_submission_in_pixel_coordinates, + aura_toplevel_set_client_supports_window_bounds, + aura_toplevel_set_window_bounds, +}; void aura_popup_surface_submission_in_pixel_coordinates(wl_client* client, wl_resource* resource) { @@ -967,14 +1074,17 @@ void aura_shell_get_aura_toplevel(wl_client* client, wl_resource* resource, uint32_t id, - wl_resource* surface_resource) { - ShellSurfaceBase* shell_surface = - GetShellSurfaceFromToplevelResource(surface_resource); + wl_resource* xdg_toplevel_resource) { + ShellSurfaceData shell_surface_data = + GetShellSurfaceFromToplevelResource(xdg_toplevel_resource); wl_resource* aura_toplevel_resource = wl_resource_create( client, &zaura_toplevel_interface, wl_resource_get_version(resource), id); - SetImplementation(aura_toplevel_resource, &aura_toplevel_implementation, - std::make_unique<AuraToplevel>(shell_surface)); + SetImplementation( + aura_toplevel_resource, &aura_toplevel_implementation, + std::make_unique<AuraToplevel>( + shell_surface_data.shell_surface, shell_surface_data.serial_tracker, + shell_surface_data.surface_resource, aura_toplevel_resource)); } void aura_shell_get_aura_popup(wl_client* client,
diff --git a/components/exo/wayland/zaura_shell.h b/components/exo/wayland/zaura_shell.h index 3676965b..88c681ab 100644 --- a/components/exo/wayland/zaura_shell.h +++ b/components/exo/wayland/zaura_shell.h
@@ -7,6 +7,7 @@ #include <stdint.h> +#include "chromeos/ui/base/window_state_type.h" #include "components/exo/surface.h" #include "components/exo/surface_observer.h" #include "ui/gfx/geometry/size_f.h" @@ -17,9 +18,11 @@ namespace exo { +class ShellSurface; class ShellSurfaceBase; namespace wayland { +class SerialTracker; constexpr uint32_t kZAuraShellVersion = 29; @@ -100,16 +103,34 @@ // Provides an implementation for top level operations on the shell. class AuraToplevel { public: - AuraToplevel(ShellSurfaceBase* shell_surface); + AuraToplevel(ShellSurface* shell_surface, + SerialTracker* const serial_tracker, + wl_resource* aura_toplevel_resource, + wl_resource* xdg_toplevel_resource); + AuraToplevel(const AuraToplevel&) = delete; AuraToplevel& operator=(const AuraToplevel&) = delete; - ~AuraToplevel(); + + virtual ~AuraToplevel(); void SetOrientationLock(uint32_t lock_type); void SetClientSubmitsSurfacesInPixelCoordinates(bool enable); + void SetClientUsesScreenCoordinates(); + void SetWindowBounds(int32_t x, int32_t y, int32_t width, int32_t height); - private: - ShellSurfaceBase* shell_surface_; + void OnConfigure(const gfx::Rect& bounds, + chromeos::WindowStateType state_type, + bool resizing, + bool activated); + virtual void OnOriginChange(const gfx::Point& origin); + + ShellSurface* shell_surface_; + SerialTracker* const serial_tracker_; + wl_resource* xdg_toplevel_resource_; + wl_resource* aura_toplevel_resource_; + bool supports_window_bounds_ = false; + + base::WeakPtrFactory<AuraToplevel> weak_ptr_factory_{this}; }; class AuraPopup {
diff --git a/components/exo/wayland/zxdg_shell.cc b/components/exo/wayland/zxdg_shell.cc index ff856327..64a17e5 100644 --- a/components/exo/wayland/zxdg_shell.cc +++ b/components/exo/wayland/zxdg_shell.cc
@@ -153,14 +153,14 @@ wl_resource* resource, SerialTracker* serial_tracker, const XdgSurfaceConfigureCallback& callback, - const gfx::Size& size, + const gfx::Rect& bounds, chromeos::WindowStateType state_type, bool resizing, bool activated, const gfx::Vector2d& origin_offset) { uint32_t serial = serial_tracker->GetNextSerial(SerialTracker::EventType::OTHER_EVENT); - callback.Run(size, state_type, resizing, activated); + callback.Run(bounds.size(), state_type, resizing, activated); zxdg_surface_v6_send_configure(resource, serial); wl_client_flush(wl_resource_get_client(resource)); return serial;
diff --git a/components/optimization_guide/core/optimization_guide_features.cc b/components/optimization_guide/core/optimization_guide_features.cc index d2c0590..706692fa 100644 --- a/components/optimization_guide/core/optimization_guide_features.cc +++ b/components/optimization_guide/core/optimization_guide_features.cc
@@ -424,7 +424,7 @@ bool IsUnrestrictedModelDownloadingEnabled() { return base::GetFieldTrialParamByFeatureAsBool( kOptimizationGuideModelDownloading, "unrestricted_model_downloading", - false); + true); } bool IsPageContentAnnotationEnabled() {
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoAdPersonalizationPreference.java b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoAdPersonalizationPreference.java index 15d9345..a73e10af 100644 --- a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoAdPersonalizationPreference.java +++ b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoAdPersonalizationPreference.java
@@ -43,7 +43,7 @@ @Override public void onCreatePreferences(Bundle bundle, String s) { // Remove this Preference if it is restored without SiteSettingsDelegate. - if (getSiteSettingsDelegate() == null) { + if (!hasSiteSettingsDelegate()) { getParentFragmentManager().beginTransaction().remove(this).commit(); return; }
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoCookiesPreference.java b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoCookiesPreference.java index a1c42a8..99a0b2f 100644 --- a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoCookiesPreference.java +++ b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoCookiesPreference.java
@@ -50,7 +50,7 @@ @Override public void onCreatePreferences(Bundle bundle, String s) { // Remove this Preference if it is restored without SiteSettingsDelegate. - if (getSiteSettingsDelegate() == null) { + if (!hasSiteSettingsDelegate()) { getParentFragmentManager().beginTransaction().remove(this).commit(); return; }
diff --git a/components/password_manager/core/common/BUILD.gn b/components/password_manager/core/common/BUILD.gn index 21b66a3..0427ab0b 100644 --- a/components/password_manager/core/common/BUILD.gn +++ b/components/password_manager/core/common/BUILD.gn
@@ -2,6 +2,10 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +if (is_android) { + import("//build/config/android/rules.gni") +} + static_library("common") { sources = [ "credential_manager_types.cc", @@ -33,6 +37,10 @@ "password_manager_features.h", ] + if (is_android) { + sources += [ "password_manager_feature_variations_android.h" ] + } + deps = [ "//base" ] } @@ -52,3 +60,15 @@ ] } } + +if (is_android) { + java_cpp_enum("java_enums_srcjar") { + visibility = [ ":*" ] + sources = [ "password_manager_feature_variations_android.h" ] + } + + android_library("password_manager_common_java_enums") { + deps = [ "//third_party/androidx:androidx_annotation_annotation_java" ] + srcjar_deps = [ ":java_enums_srcjar" ] + } +}
diff --git a/components/password_manager/core/common/password_manager_feature_variations_android.h b/components/password_manager/core/common/password_manager_feature_variations_android.h new file mode 100644 index 0000000..7a8d4d5 --- /dev/null +++ b/components/password_manager/core/common/password_manager_feature_variations_android.h
@@ -0,0 +1,30 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_PASSWORD_MANAGER_CORE_COMMON_PASSWORD_MANAGER_FEATURE_VARIATIONS_ANDROID_H_ +#define COMPONENTS_PASSWORD_MANAGER_CORE_COMMON_PASSWORD_MANAGER_FEATURE_VARIATIONS_ANDROID_H_ + +namespace password_manager::features { + +// This enum supports enabling specific parts of the Unified Password Manager +// via command line flag and configuration alike. +// Do not reassign or delete indices but mark them deprecated since they are +// used to parse the enum in java. Keep the order consistent with +// `kUpmExperimentStageOption` below, with java helpers, and with +// `kUnifiedPasswordManagerAndroidVariations` in about_flags.cc +// +// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.password_manager +enum class UpmExperimentVariation { + // Default variation. Make the Android backend default for syncing users for + // all requests. Uses updated UI and no shadow traffic. + kEnableForSyncingUsers = 0, + + // Read-only shadow traffic to Android backend for syncing users. The built-in + // backend remains the default for all requests. Uses legacy UI. + kShadowSyncingUsers = 1, +}; + +} // namespace password_manager::features + +#endif // COMPONENTS_PASSWORD_MANAGER_CORE_COMMON_PASSWORD_MANAGER_FEATURE_VARIATIONS_ANDROID_H_
diff --git a/components/password_manager/core/common/password_manager_features.cc b/components/password_manager/core/common/password_manager_features.cc index dbd0db7e..c405068 100644 --- a/components/password_manager/core/common/password_manager_features.cc +++ b/components/password_manager/core/common/password_manager_features.cc
@@ -6,11 +6,9 @@ #include "build/build_config.h" -namespace password_manager { - +namespace password_manager::features { // NOTE: It is strongly recommended to use UpperCamelCase style for feature // names, e.g. "MyGreatFeature". -namespace features { // Enables Biometrics for the Touch To Fill feature. This only effects Android. const base::Feature kBiometricTouchToFill = {"BiometricTouchToFill", @@ -285,6 +283,12 @@ base::FeatureList::IsEnabled(kPasswordDomainCapabilitiesFetching); } -} // namespace features +#if BUILDFLAG(IS_ANDROID) +bool UsesUnifiedPasswordManagerUi() { + return base::FeatureList::IsEnabled(kUnifiedPasswordManagerAndroid) && + kUpmExperimentVariationParam.Get() != + UpmExperimentVariation::kShadowSyncingUsers; +} +#endif // IS_ANDROID -} // namespace password_manager +} // namespace password_manager::features
diff --git a/components/password_manager/core/common/password_manager_features.h b/components/password_manager/core/common/password_manager_features.h index d45cba6d..ca70abd2 100644 --- a/components/password_manager/core/common/password_manager_features.h +++ b/components/password_manager/core/common/password_manager_features.h
@@ -12,9 +12,11 @@ #include "base/metrics/field_trial_params.h" #include "build/build_config.h" -namespace password_manager { +#if BUILDFLAG(IS_ANDROID) +#include "components/password_manager/core/common/password_manager_feature_variations_android.h" +#endif -namespace features { +namespace password_manager::features { // All features in alphabetical order. The features should be documented // alongside the definition of their values in the .cc file. @@ -75,6 +77,16 @@ extern const base::FeatureParam<bool> kPasswordChangeLiveExperimentParam; #if BUILDFLAG(IS_ANDROID) extern const base::FeatureParam<int> kMigrationVersion; +constexpr base::FeatureParam<UpmExperimentVariation>::Option + kUpmExperimentVariationOption[] = { + {UpmExperimentVariation::kEnableForSyncingUsers, "0"}, + {UpmExperimentVariation::kShadowSyncingUsers, "1"}}; + +constexpr base::FeatureParam<UpmExperimentVariation> + kUpmExperimentVariationParam{&kUnifiedPasswordManagerAndroid, "stage", + UpmExperimentVariation::kEnableForSyncingUsers, + &kUpmExperimentVariationOption}; + #endif // Field trial and corresponding parameters. @@ -98,8 +110,12 @@ // enabled. bool IsPasswordScriptsFetchingEnabled(); -} // namespace features +#if BUILDFLAG(IS_ANDROID) +// Returns true if the unified password manager feature is active and in a stage +// that allows to use the new UI. +bool UsesUnifiedPasswordManagerUi(); +#endif // IS_ANDROID -} // namespace password_manager +} // namespace password_manager::features #endif // COMPONENTS_PASSWORD_MANAGER_CORE_COMMON_PASSWORD_MANAGER_FEATURES_H_
diff --git a/components/pdf/renderer/BUILD.gn b/components/pdf/renderer/BUILD.gn index 651c7be6..fb73ef42 100644 --- a/components/pdf/renderer/BUILD.gn +++ b/components/pdf/renderer/BUILD.gn
@@ -38,10 +38,6 @@ "//pdf:buildflags", "//pdf:features", "//pdf:pdf_view_web_plugin", - "//ppapi/host", - "//ppapi/proxy", - "//ppapi/proxy:ipc", - "//ppapi/shared_impl", "//printing/buildflags", "//third_party/blink/public:blink", "//third_party/blink/public/strings:accessibility_strings",
diff --git a/components/pdf/renderer/DEPS b/components/pdf/renderer/DEPS index 31597bd..8a20e16 100644 --- a/components/pdf/renderer/DEPS +++ b/components/pdf/renderer/DEPS
@@ -11,7 +11,6 @@ "+pdf/pdf_accessibility_data_handler.h", "+pdf/pdf_features.h", "+pdf/pdf_view_web_plugin.h", - "+ppapi", "+printing/buildflags/buildflags.h", "+third_party/blink/public", "+ui/accessibility",
diff --git a/components/policy/core/common/policy_pref_names.cc b/components/policy/core/common/policy_pref_names.cc index e297ce3..30ca9f8 100644 --- a/components/policy/core/common/policy_pref_names.cc +++ b/components/policy/core/common/policy_pref_names.cc
@@ -94,5 +94,8 @@ // required). If false, the API gets blocked unconditionally. const char kEnableDirectSockets[] = "policy.enable_direct_sockets"; +// Boolean policy to force WebSQL to be enabled. +const char kWebSQLAccess[] = "policy.web_sql_access"; + } // namespace policy_prefs } // namespace policy
diff --git a/components/policy/core/common/policy_pref_names.h b/components/policy/core/common/policy_pref_names.h index 71bbdea0..c73af2e8 100644 --- a/components/policy/core/common/policy_pref_names.h +++ b/components/policy/core/common/policy_pref_names.h
@@ -36,6 +36,7 @@ POLICY_EXPORT extern const char kBackForwardCacheEnabled[]; #endif // BUILDFLAG(IS_ANDROID) POLICY_EXPORT extern const char kEnableDirectSockets[]; +POLICY_EXPORT extern const char kWebSQLAccess[]; } // namespace policy_prefs } // namespace policy
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json index 1de506f..5ea417ac 100644 --- a/components/policy/resources/policy_templates.json +++ b/components/policy/resources/policy_templates.json
@@ -30280,6 +30280,35 @@ 'desc': '''Setting the policy to Enabled or leaving it unset will enable the fetching of page load metadata and machine learning models that enhance the browsing experience. Setting the policy to Disabled may cause some features to not work appropriately.''', }, + { + 'name': 'WebSQLAccess', + 'owners': ['arichiv@chromium.org'], + 'type': 'main', + 'schema': { 'type': 'boolean' }, + 'supported_on': ['android:101-', 'chrome.*:101-', 'chrome_os:101-'], + 'features': { + 'dynamic_refresh': False, + 'per_profile': False, + }, + 'items': [ + { + 'value': True, + 'caption': 'Force WebSQL to be enabled.', + }, + { + 'value': False, + 'caption': 'Allow WebSQL to be disabled by Chrome flag.', + }, + ], + 'default': False, + 'example_value': True, + 'id': 966, + 'caption': '''Force WebSQL to be enabled.''', + 'tags': [], + 'desc': '''WebSQL is on by default as of M101, but can be disabled via Chrome flag. + If this policy is set to false or unset, WebSQL can be disabled. + If this policy is set to true, WebSQL cannot be disabled.''', + }, ], 'messages': { # Messages that are not associated to any policies. @@ -31276,6 +31305,6 @@ 'placeholders': [], 'deleted_policy_ids': [114, 115, 204, 205, 206, 341, 412, 476, 544, 546, 562, 569, 578, 583, 585, 586, 587, 588, 589, 590, 591, 600, 668, 669, 872], 'deleted_atomic_policy_group_ids': [19], - 'highest_id_currently_used': 965, + 'highest_id_currently_used': 966, 'highest_atomic_group_id_currently_used': 42 }
diff --git a/components/remote_cocoa/app_shim/BUILD.gn b/components/remote_cocoa/app_shim/BUILD.gn index 7f00934..06246a1 100644 --- a/components/remote_cocoa/app_shim/BUILD.gn +++ b/components/remote_cocoa/app_shim/BUILD.gn
@@ -40,6 +40,8 @@ "native_widget_mac_nswindow.mm", "native_widget_ns_window_bridge.h", "native_widget_ns_window_bridge.mm", + "native_widget_ns_window_fullscreen_controller.h", + "native_widget_ns_window_fullscreen_controller.mm", "native_widget_ns_window_host_helper.h", "ns_view_ids.h", "ns_view_ids.mm",
diff --git a/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h b/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h index a101b19..1b0cc28 100644 --- a/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h +++ b/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h
@@ -12,6 +12,7 @@ #import "base/mac/scoped_nsobject.h" #import "components/remote_cocoa/app_shim/mouse_capture_delegate.h" +#include "components/remote_cocoa/app_shim/native_widget_ns_window_fullscreen_controller.h" #include "components/remote_cocoa/app_shim/ns_view_ids.h" #include "components/remote_cocoa/app_shim/remote_cocoa_app_shim_export.h" #include "components/remote_cocoa/common/native_widget_ns_window.mojom.h" @@ -44,6 +45,7 @@ class TextInputHost; } // namespace mojom +class NativeWidgetNSWindowFullscreenController; class NativeWidgetNSWindowHostHelper; class CocoaMouseCapture; class CocoaWindowMoveLoop; @@ -131,10 +133,6 @@ // does not match |actual_fullscreen_state|, a new transition will begin. void OnFullscreenTransitionComplete(bool actual_fullscreen_state); - // Transition the window into or out of fullscreen. This will immediately - // invert the value of target_fullscreen_state(). - void ToggleDesiredFullscreenState(bool async = false); - // Called by the NSWindowDelegate when the size of the window changes. void OnSizeChanged(); @@ -179,10 +177,18 @@ return child_windows_; } - bool target_fullscreen_state() const { return target_fullscreen_state_; } + NativeWidgetNSWindowFullscreenController& fullscreen_controller() { + return fullscreen_controller_; + } + + bool target_fullscreen_state() const { + return fullscreen_controller_.GetTargetFullscreenState(); + } bool window_visible() const { return window_visible_; } bool wants_to_be_visible() const { return wants_to_be_visible_; } - bool in_fullscreen_transition() const { return in_fullscreen_transition_; } + bool in_fullscreen_transition() const { + return fullscreen_controller_.IsInFullscreenTransition(); + } // Whether to run a custom animation for the provided |transition|. bool ShouldRunCustomAnimationFor( @@ -273,6 +279,7 @@ private: friend class views::test::BridgedNativeWidgetTestApi; + friend class NativeWidgetNSWindowFullscreenController; // Attach child windows, if the window is visible (see comment inline). void OrderChildren(); @@ -364,20 +371,8 @@ remote_cocoa::mojom::VisibilityTransition transitions_to_animate_ = remote_cocoa::mojom::VisibilityTransition::kBoth; - // Whether this window wants to be fullscreen. If a fullscreen animation is in - // progress then it might not be actually fullscreen. - bool target_fullscreen_state_ = false; - - // Whether this window is in a fullscreen transition, and the fullscreen state - // can not currently be changed. - bool in_fullscreen_transition_ = false; - - // Trying to close an NSWindow during a fullscreen transition will cause the - // window to lock up. Use this to track if CloseWindow was called during a - // fullscreen transition, to defer the -[NSWindow close] call until the - // transition is complete. - // https://crbug.com/945237 - bool has_deferred_window_close_ = false; + // Manager of fullscreen state transitions. + NativeWidgetNSWindowFullscreenController fullscreen_controller_{this}; // Stores the value last read from -[NSWindow isVisible], to detect visibility // changes.
diff --git a/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm b/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm index cb82b91e..8a431b6 100644 --- a/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm +++ b/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm
@@ -25,6 +25,7 @@ #import "components/remote_cocoa/app_shim/mouse_capture.h" #import "components/remote_cocoa/app_shim/native_widget_mac_frameless_nswindow.h" #import "components/remote_cocoa/app_shim/native_widget_mac_nswindow.h" +#include "components/remote_cocoa/app_shim/native_widget_ns_window_fullscreen_controller.h" #import "components/remote_cocoa/app_shim/native_widget_ns_window_host_helper.h" #include "components/remote_cocoa/app_shim/select_file_dialog_bridge.h" #import "components/remote_cocoa/app_shim/views_nswindow_delegate.h" @@ -586,7 +587,7 @@ } void NativeWidgetNSWindowBridge::CloseWindow() { - if (has_deferred_window_close_) + if (fullscreen_controller_.HasDeferredWindowClose()) return; // Keep |window| on the stack so that the ObjectiveC block below can capture @@ -630,10 +631,9 @@ [window orderOut:nil]; // Defer closing windows until after fullscreen transitions complete. - if (in_fullscreen_transition_) { - has_deferred_window_close_ = true; + fullscreen_controller_.OnWindowWantsToClose(); + if (fullscreen_controller_.HasDeferredWindowClose()) return; - } // Many tests assume that base::RunLoop().RunUntilIdle() is always sufficient // to execute a close. However, in rare cases, -performSelector:..afterDelay:0 @@ -880,13 +880,7 @@ } void NativeWidgetNSWindowBridge::OnWindowWillClose() { - // If a window closes while in a fullscreen transition, then the window will - // hang in a zombie-like state. - // https://crbug.com/945237 - if (in_fullscreen_transition_) { - DLOG(ERROR) << "-[NSWindow close] while in fullscreen transition will " - "trigger zombie windows."; - } + fullscreen_controller_.OnWindowWillClose(); [window_ setCommandHandler:nil]; [window_ setCommandDispatcherDelegate:nil]; @@ -927,85 +921,14 @@ void NativeWidgetNSWindowBridge::OnFullscreenTransitionStart( bool target_fullscreen_state) { - DCHECK_NE(target_fullscreen_state, target_fullscreen_state_); - target_fullscreen_state_ = target_fullscreen_state; - in_fullscreen_transition_ = true; - host_->OnWindowFullscreenTransitionStart(target_fullscreen_state); } void NativeWidgetNSWindowBridge::OnFullscreenTransitionComplete( bool actual_fullscreen_state) { - in_fullscreen_transition_ = false; - // Add any children that were skipped during the fullscreen transition. OrderChildren(); - - if (has_deferred_window_close_) { - [ns_window() close]; - return; - } - - if (target_fullscreen_state_ == actual_fullscreen_state) { - host_->OnWindowFullscreenTransitionComplete(actual_fullscreen_state); - return; - } - - // The transition completed, but into the wrong state. This can happen when - // there are calls to change the fullscreen state whilst mid-transition. - // First update to reflect reality so that OnTargetFullscreenStateChanged() - // expects the change. - target_fullscreen_state_ = actual_fullscreen_state; - ToggleDesiredFullscreenState(true /* async */); -} - -void NativeWidgetNSWindowBridge::ToggleDesiredFullscreenState(bool async) { - // If there is currently an animation into or out of fullscreen, then AppKit - // emits the string "not in fullscreen state" to stdio and does nothing. For - // this case, schedule a transition back into the desired state when the - // animation completes. - if (in_fullscreen_transition_) { - target_fullscreen_state_ = !target_fullscreen_state_; - return; - } - - // Going fullscreen implicitly makes the window visible. AppKit does this. - // That is, -[NSWindow isVisible] is always true after a call to -[NSWindow - // toggleFullScreen:]. Unfortunately, this change happens after AppKit calls - // -[NSWindowDelegate windowWillEnterFullScreen:], and AppKit doesn't send an - // orderWindow message. So intercepting the implicit change is hard. - // Luckily, to trigger externally, the window typically needs to be visible in - // the first place. So we can just ensure the window is visible here instead - // of relying on AppKit to do it, and not worry that OnVisibilityChanged() - // won't be called for externally triggered fullscreen requests. - if (!window_visible_) - SetVisibilityState(WindowVisibilityState::kShowInactive); - - // Enable fullscreen collection behavior because: - // 1: -[NSWindow toggleFullscreen:] would otherwise be ignored, - // 2: the fullscreen button must be enabled so the user can leave fullscreen. - // This will be reset when a transition out of fullscreen completes. - gfx::SetNSWindowCanFullscreen(window_, true); - - // Until 10.13, AppKit would obey a call to -toggleFullScreen: made inside - // OnFullscreenTransitionComplete(). Starting in 10.13, it behaves as though - // the transition is still in progress and just emits "not in a fullscreen - // state" when trying to exit fullscreen in the same runloop that entered it. - // To handle this case, invoke -toggleFullScreen: asynchronously. - if (async) { - [window_ performSelector:@selector(toggleFullScreen:) - withObject:nil - afterDelay:0]; - } else { - // Suppress synchronous CA transactions during AppKit fullscreen transition - // since there is no need for updates during such transition. - // Re-layout and re-paint will be done after the transtion. See - // https://crbug.com/875707 for potiential problems if we don't suppress. - // |ca_transaction_sync_suppressed_| will be reset to false when the next - // frame comes in. - ca_transaction_sync_suppressed_ = true; - [window_ toggleFullScreen:nil]; - } + host_->OnWindowFullscreenTransitionComplete(actual_fullscreen_state); } void NativeWidgetNSWindowBridge::OnSizeChanged() { @@ -1078,10 +1001,7 @@ const gfx::Size& max_size, bool is_resizable, bool is_maximizable) { - // Don't modify the size constraints or fullscreen collection behavior while - // in fullscreen or during a transition. OnFullscreenTransitionComplete will - // reset these after leaving fullscreen. - if (target_fullscreen_state_ || in_fullscreen_transition_) + if (!fullscreen_controller_.CanResize()) return; bool shows_resize_controls = @@ -1294,9 +1214,31 @@ } void NativeWidgetNSWindowBridge::SetFullscreen(bool fullscreen) { - if (fullscreen == target_fullscreen_state_) - return; - ToggleDesiredFullscreenState(); + if (fullscreen) { + // Going fullscreen implicitly makes the window visible. AppKit does this. + // That is, -[NSWindow isVisible] is always true after a call to -[NSWindow + // toggleFullScreen:]. Unfortunately, this change happens after AppKit calls + // -[NSWindowDelegate windowWillEnterFullScreen:], and AppKit doesn't send + // an orderWindow message. So intercepting the implicit change is hard. + // Luckily, to trigger externally, the window typically needs to be visible + // in the first place. So we can just ensure the window is visible here + // instead of relying on AppKit to do it, and not worry that + // OnVisibilityChanged() won't be called for externally triggered fullscreen + // requests. + if (!window_visible_) + SetVisibilityState(WindowVisibilityState::kShowInactive); + + // Enable fullscreen collection behavior because: + // 1: -[NSWindow toggleFullscreen:] would otherwise be ignored, + // 2: the fullscreen button must be enabled so the user can leave + // fullscreen. This will be reset when a transition out of fullscreen + // completes. + gfx::SetNSWindowCanFullscreen(window_, true); + + fullscreen_controller_.EnterFullscreen(); + } else { + fullscreen_controller_.ExitFullscreen(); + } } void NativeWidgetNSWindowBridge::SetCanAppearInExistingFullscreenSpaces(
diff --git a/components/remote_cocoa/app_shim/native_widget_ns_window_fullscreen_controller.h b/components/remote_cocoa/app_shim/native_widget_ns_window_fullscreen_controller.h new file mode 100644 index 0000000..4658c1cf --- /dev/null +++ b/components/remote_cocoa/app_shim/native_widget_ns_window_fullscreen_controller.h
@@ -0,0 +1,128 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_REMOTE_COCOA_APP_SHIM_NATIVE_WIDGET_NS_WINDOW_FULLSCREEN_CONTROLLER_H_ +#define COMPONENTS_REMOTE_COCOA_APP_SHIM_NATIVE_WIDGET_NS_WINDOW_FULLSCREEN_CONTROLLER_H_ + +#include "base/memory/raw_ptr.h" +#include "base/memory/weak_ptr.h" +#include "components/remote_cocoa/app_shim/remote_cocoa_app_shim_export.h" +#include "third_party/abseil-cpp/absl/types/optional.h" + +namespace remote_cocoa { + +class NativeWidgetNSWindowBridge; + +class REMOTE_COCOA_APP_SHIM_EXPORT NativeWidgetNSWindowFullscreenController { + public: + explicit NativeWidgetNSWindowFullscreenController( + NativeWidgetNSWindowBridge* bridge); + NativeWidgetNSWindowFullscreenController( + const NativeWidgetNSWindowFullscreenController&) = delete; + NativeWidgetNSWindowFullscreenController& operator=( + const NativeWidgetNSWindowFullscreenController&) = delete; + ~NativeWidgetNSWindowFullscreenController(); + + // Called by NativeWidget::SetFullscreen. + void EnterFullscreen(); + void ExitFullscreen(); + + // Called from NativeWidgetNSWindowBridge:CloseWindow, indicating that the + // window has been requested to be closed. If a transition is in progress, + // then the close will be deferred until after the transition completes. + void OnWindowWantsToClose(); + + // Return true if an active transition has caused closing of the window to be + // deferred. + bool HasDeferredWindowClose() const { return has_deferred_window_close_; } + + // Called by NativeWidgetNSWindowBridge::OnWindowWillClose. + void OnWindowWillClose(); + + // Called by -[NSWindowDelegate windowWill/DidEnter/ExitFullScreen:]. + void OnWindowWillEnterFullscreen(); + void OnWindowDidEnterFullscreen(); + void OnWindowWillExitFullscreen(); + void OnWindowDidExitFullscreen(); + + // Return false unless the state is kWindowed or kFullscreen. + bool IsInFullscreenTransition() const; + + // Return true if the window can be resized. The window cannot be resized + // while fullscreen or during a transition. + bool CanResize() const; + + // Return the fullscreen state that will be arrived at when all transition + // is done. + bool GetTargetFullscreenState() const; + + private: + enum class State { + // In windowed mode. + kWindowed, + // In transition to enter fullscreen mode. This encompases the following + // states: + // - From the kWindowed state, a task for ToggleFullscreen has been + // posted. + // - OnWindowWillEnterFullscreen has been called (either as a result of + // ToggleFullscreen, or as a result of user interaction), but neither + // OnWindowDidEnterFullscreen nor OnWindowDidExitFullscreen have been + // called yet. + kEnterFullscreenTransition, + // In fullscreen mode. + kFullscreen, + // In transition to exit fullscreen mode. This encompases the following + // states: + // - From the kFullscreen state, a task for ToggleFullscreen has been + // posted. + // - OnWindowWillExitFullscreen has been called (either as a result of + // ToggleFullscreen, or as a result of user interaction), but neither + // OnWindowDidExitFullscreen nor OnWindowDidEnterFullscreen have been + // called yet. + kExitFullscreenTransition, + // The window has been closed. + kClosed, + }; + struct PendingState { + bool is_fullscreen = false; + }; + + // Helper function wrapping -[NSWindow toggleFullscreen:]. + void ToggleFullscreen(); + + // If not currently in transition, consume `pending_state_` and start a + // transition to the state it specifies. + void HandlePendingState(); + + // If there exists a deferred close, then close the window, set the + // current state to kClosed, and return true. + bool HandleDeferredClose(); + + // Set `state` to `new_state`, and invalidate any posted tasks. Posted tasks + // exist to transition from the current state to a new state, and so if the + // current state changes, then those tasks are no longer applicable. + void SetStateAndCancelPostedTasks(State new_state); + + State state_ = State::kWindowed; + + // If a call to EnterFullscreen or ExitFullscreen happens during a + // transition, then that final requested state is stored in `pending_state_`. + absl::optional<PendingState> pending_state_; + + // Trying to close an NSWindow during a fullscreen transition will cause the + // window to lock up. Use this to track if CloseWindow was called during a + // fullscreen transition, to defer the -[NSWindow close] call until the + // transition is complete. + // https://crbug.com/945237 + bool has_deferred_window_close_ = false; + + // Weak, owns `this`. + const raw_ptr<NativeWidgetNSWindowBridge> window_bridge_; + base::WeakPtrFactory<NativeWidgetNSWindowFullscreenController> weak_factory_{ + this}; +}; + +} // namespace remote_cocoa + +#endif // COMPONENTS_REMOTE_COCOA_APP_SHIM_NATIVE_WIDGET_NS_WINDOW_FULLSCREEN_CONTROLLER_H_
diff --git a/components/remote_cocoa/app_shim/native_widget_ns_window_fullscreen_controller.mm b/components/remote_cocoa/app_shim/native_widget_ns_window_fullscreen_controller.mm new file mode 100644 index 0000000..f33a25ec --- /dev/null +++ b/components/remote_cocoa/app_shim/native_widget_ns_window_fullscreen_controller.mm
@@ -0,0 +1,217 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/remote_cocoa/app_shim/native_widget_ns_window_fullscreen_controller.h" + +#import "components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h" + +namespace remote_cocoa { + +NativeWidgetNSWindowFullscreenController:: + NativeWidgetNSWindowFullscreenController( + NativeWidgetNSWindowBridge* window_bridge) + : window_bridge_(window_bridge) {} + +NativeWidgetNSWindowFullscreenController:: + ~NativeWidgetNSWindowFullscreenController() {} + +void NativeWidgetNSWindowFullscreenController::EnterFullscreen() { + if (state_ == State::kFullscreen) + return; + const bool notify_transition_start = state_ == State::kWindowed; + pending_state_ = PendingState(); + pending_state_->is_fullscreen = true; + HandlePendingState(); + if (notify_transition_start) { + DCHECK_NE(state_, State::kWindowed); + window_bridge_->OnFullscreenTransitionStart(true); + } +} + +void NativeWidgetNSWindowFullscreenController::ExitFullscreen() { + if (state_ == State::kWindowed) + return; + const bool notify_transition_start = state_ == State::kFullscreen; + pending_state_ = PendingState(); + pending_state_->is_fullscreen = false; + HandlePendingState(); + if (notify_transition_start) { + DCHECK_NE(state_, State::kFullscreen); + window_bridge_->OnFullscreenTransitionStart(false); + } +} + +void NativeWidgetNSWindowFullscreenController::ToggleFullscreen() { + // Suppress synchronous CA transactions during AppKit fullscreen transition + // since there is no need for updates during such transition. + // Re-layout and re-paint will be done after the transition. See + // https://crbug.com/875707 for potiential problems if we don't suppress. + // `ca_transaction_sync_suppressed_` will be reset to false when the next + // frame comes in. + window_bridge_->ca_transaction_sync_suppressed_ = true; + + // Note that OnWindowWillEnterFullscreen or OnWindowWillExitFullscreen will + // be called within the below call. + [window_bridge_->window_ toggleFullScreen:nil]; +} + +bool NativeWidgetNSWindowFullscreenController::CanResize() const { + // Don't modify the size constraints or fullscreen collection behavior while + // in fullscreen or during a transition. OnFullscreenTransitionComplete will + // reset these after leaving fullscreen. + return state_ == State::kWindowed; +} + +void NativeWidgetNSWindowFullscreenController::SetStateAndCancelPostedTasks( + State new_state) { + weak_factory_.InvalidateWeakPtrs(); + state_ = new_state; +} + +void NativeWidgetNSWindowFullscreenController::OnWindowWantsToClose() { + if (state_ == State::kEnterFullscreenTransition || + state_ == State::kExitFullscreenTransition) { + has_deferred_window_close_ = true; + } +} + +void NativeWidgetNSWindowFullscreenController::OnWindowWillClose() { + // If a window closes while in a fullscreen transition, then the window will + // hang in a zombie-like state. + // https://crbug.com/945237 + if (state_ != State::kWindowed && state_ != State::kFullscreen) { + DLOG(ERROR) << "-[NSWindow close] while in fullscreen transition will " + "trigger zombie windows."; + } +} + +void NativeWidgetNSWindowFullscreenController::OnWindowWillEnterFullscreen() { + // If OnWindowWillEnterFullscreen is called from the kWindowed state, then + // this was not triggered by EnterFullscreen (and is not being called from + // inside ToggleFullscreen). Therefore, we need to notify `window_bridge_` + // that a transition is starting, and suppress CATranscation sync. + const bool notify_transition_start = state_ == State::kWindowed; + SetStateAndCancelPostedTasks(State::kEnterFullscreenTransition); + if (notify_transition_start) { + window_bridge_->ca_transaction_sync_suppressed_ = true; + window_bridge_->OnFullscreenTransitionStart( + /*target_fullscreen_state=*/true); + } +} + +void NativeWidgetNSWindowFullscreenController::OnWindowDidEnterFullscreen() { + if (HandleDeferredClose()) + return; + SetStateAndCancelPostedTasks(State::kFullscreen); + HandlePendingState(); + if (!IsInFullscreenTransition()) { + window_bridge_->OnFullscreenTransitionComplete( + /*target_fullscreen_state=*/true); + } +} + +void NativeWidgetNSWindowFullscreenController::OnWindowWillExitFullscreen() { + // See notes in OnWindowWillEnterFullscreen. + const bool notify_transition_start = state_ == State::kFullscreen; + SetStateAndCancelPostedTasks(State::kExitFullscreenTransition); + if (notify_transition_start) { + window_bridge_->ca_transaction_sync_suppressed_ = true; + window_bridge_->OnFullscreenTransitionStart( + /*target_fullscreen_state=*/false); + } +} + +void NativeWidgetNSWindowFullscreenController::OnWindowDidExitFullscreen() { + if (HandleDeferredClose()) + return; + SetStateAndCancelPostedTasks(State::kWindowed); + HandlePendingState(); + if (!IsInFullscreenTransition()) { + window_bridge_->OnFullscreenTransitionComplete( + /*actual_fullscreen_state=*/false); + } +} + +void NativeWidgetNSWindowFullscreenController::HandlePendingState() { + // Early-out for no-ops. + if (!pending_state_) + return; + + // If in kWindowed or kFullscreen, then consume `pending_state_`. + switch (state_) { + case State::kClosed: + pending_state_.reset(); + return; + case State::kWindowed: + if (!pending_state_->is_fullscreen) { + pending_state_.reset(); + return; + } + pending_state_.reset(); + SetStateAndCancelPostedTasks(State::kEnterFullscreenTransition); + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce( + &NativeWidgetNSWindowFullscreenController::ToggleFullscreen, + weak_factory_.GetWeakPtr())); + return; + case State::kFullscreen: + if (pending_state_->is_fullscreen) { + pending_state_.reset(); + return; + } + pending_state_.reset(); + SetStateAndCancelPostedTasks(State::kExitFullscreenTransition); + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce( + &NativeWidgetNSWindowFullscreenController::ToggleFullscreen, + weak_factory_.GetWeakPtr())); + return; + default: + // Leave `pending_state_` unchanged. It will be re-examined when our + // transition completes. + break; + } +} + +bool NativeWidgetNSWindowFullscreenController::HandleDeferredClose() { + CHECK_NE(state_, State::kClosed); + if (has_deferred_window_close_) { + SetStateAndCancelPostedTasks(State::kClosed); + // Note that `this` may be deleted by the below call to `close`. + [window_bridge_->window_ close]; + return true; + } + return false; +} + +bool NativeWidgetNSWindowFullscreenController::GetTargetFullscreenState() + const { + if (pending_state_) + return pending_state_->is_fullscreen; + switch (state_) { + case State::kWindowed: + case State::kExitFullscreenTransition: + case State::kClosed: + return false; + case State::kEnterFullscreenTransition: + case State::kFullscreen: + return true; + } +} + +bool NativeWidgetNSWindowFullscreenController::IsInFullscreenTransition() + const { + switch (state_) { + case State::kWindowed: + case State::kFullscreen: + case State::kClosed: + return false; + default: + return true; + } +} + +} // namespace remote_cocoa
diff --git a/components/remote_cocoa/app_shim/views_nswindow_delegate.mm b/components/remote_cocoa/app_shim/views_nswindow_delegate.mm index 4e419c6..2578994 100644 --- a/components/remote_cocoa/app_shim/views_nswindow_delegate.mm +++ b/components/remote_cocoa/app_shim/views_nswindow_delegate.mm
@@ -10,6 +10,7 @@ #include "base/threading/thread_task_runner_handle.h" #import "components/remote_cocoa/app_shim/bridged_content_view.h" #import "components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h" +#include "components/remote_cocoa/app_shim/native_widget_ns_window_fullscreen_controller.h" #include "components/remote_cocoa/app_shim/native_widget_ns_window_host_helper.h" #include "components/remote_cocoa/common/native_widget_ns_window_host.mojom.h" #include "ui/gfx/geometry/resize_utils.h" @@ -204,15 +205,15 @@ } - (void)windowWillEnterFullScreen:(NSNotification*)notification { - _parent->OnFullscreenTransitionStart(true); + _parent->fullscreen_controller().OnWindowWillEnterFullscreen(); } - (void)windowDidEnterFullScreen:(NSNotification*)notification { - _parent->OnFullscreenTransitionComplete(true); + _parent->fullscreen_controller().OnWindowDidEnterFullscreen(); } - (void)windowWillExitFullScreen:(NSNotification*)notification { - _parent->OnFullscreenTransitionStart(false); + _parent->fullscreen_controller().OnWindowWillExitFullscreen(); } - (void)windowDidExitFullScreen:(NSNotification*)notification { @@ -227,7 +228,7 @@ afterDelay:0]; } - _parent->OnFullscreenTransitionComplete(false); + _parent->fullscreen_controller().OnWindowDidExitFullscreen(); } // Allow non-resizable windows (without NSResizableWindowMask) to fill the
diff --git a/components/services/app_service/public/cpp/app_registry_cache_unittest.cc b/components/services/app_service/public/cpp/app_registry_cache_unittest.cc index bcab93d0..ac39100f2 100644 --- a/components/services/app_service/public/cpp/app_registry_cache_unittest.cc +++ b/components/services/app_service/public/cpp/app_registry_cache_unittest.cc
@@ -175,7 +175,7 @@ } static void ExpectEq(const AppUpdate& outer, const AppUpdate& inner) { - EXPECT_EQ(outer.GetAppType(), inner.GetAppType()); + EXPECT_EQ(outer.AppType(), inner.AppType()); EXPECT_EQ(outer.AppId(), inner.AppId()); EXPECT_EQ(outer.StateIsNull(), inner.StateIsNull()); EXPECT_EQ(outer.Readiness(), inner.Readiness());
diff --git a/components/services/app_service/public/cpp/app_update.cc b/components/services/app_service/public/cpp/app_update.cc index 310f4a16..60c2337d 100644 --- a/components/services/app_service/public/cpp/app_update.cc +++ b/components/services/app_service/public/cpp/app_update.cc
@@ -14,8 +14,19 @@ namespace { -void ClonePermissions(const std::vector<apps::mojom::PermissionPtr>& clone_from, - std::vector<apps::mojom::PermissionPtr>* clone_to) { +std::vector<apps::PermissionPtr> ConvertMojomPermissionsToPermissions( + const std::vector<apps::mojom::PermissionPtr>& mojom_permissions) { + std::vector<apps::PermissionPtr> permissions; + for (const auto& mojom_permission : mojom_permissions) { + permissions.push_back( + apps::ConvertMojomPermissionToPermission(mojom_permission)); + } + return permissions; +} + +void CloneMojomPermissions( + const std::vector<apps::mojom::PermissionPtr>& clone_from, + std::vector<apps::mojom::PermissionPtr>* clone_to) { for (const auto& permission : clone_from) { clone_to->push_back(permission->Clone()); } @@ -101,7 +112,7 @@ DCHECK(state->permissions.empty() || (delta->permissions.size() == state->permissions.size())); state->permissions.clear(); - ::ClonePermissions(delta->permissions, &state->permissions); + ::CloneMojomPermissions(delta->permissions, &state->permissions); } if (delta->install_reason != apps::mojom::InstallReason::kUnknown) { state->install_reason = delta->install_reason; @@ -267,12 +278,12 @@ return mojom_state_ == nullptr; } -apps::mojom::AppType AppUpdate::AppType() const { - return mojom_delta_ ? mojom_delta_->app_type : mojom_state_->app_type; -} - -apps::AppType AppUpdate::GetAppType() const { - return delta_ ? delta_->app_type : state_->app_type; +apps::AppType AppUpdate::AppType() const { + if (ShouldUseNonMojom()) { + return delta_ ? delta_->app_type : state_->app_type; + } + return ConvertMojomAppTypToAppType(mojom_delta_ ? mojom_delta_->app_type + : mojom_state_->app_type); } const std::string& AppUpdate::AppId() const { @@ -532,28 +543,22 @@ (mojom_delta_->install_time != mojom_state_->install_time)); } -std::vector<apps::mojom::PermissionPtr> AppUpdate::Permissions() const { - std::vector<apps::mojom::PermissionPtr> permissions; +apps::Permissions AppUpdate::Permissions() const { + if (ShouldUseNonMojom()) { + if (delta_ && !delta_->permissions.empty()) { + return ClonePermissions(delta_->permissions); + } else if (state_ && !state_->permissions.empty()) { + return ClonePermissions(state_->permissions); + } + return std::vector<PermissionPtr>{}; + } if (mojom_delta_ && !mojom_delta_->permissions.empty()) { - ::ClonePermissions(mojom_delta_->permissions, &permissions); + return ::ConvertMojomPermissionsToPermissions(mojom_delta_->permissions); } else if (mojom_state_ && !mojom_state_->permissions.empty()) { - ::ClonePermissions(mojom_state_->permissions, &permissions); + return ::ConvertMojomPermissionsToPermissions(mojom_state_->permissions); } - - return permissions; -} - -apps::Permissions AppUpdate::GetPermissions() const { - apps::Permissions permissions; - - if (delta_ && !delta_->permissions.empty()) { - permissions = ClonePermissions(delta_->permissions); - } else if (state_ && !state_->permissions.empty()) { - permissions = ClonePermissions(state_->permissions); - } - - return permissions; + return std::vector<PermissionPtr>{}; } bool AppUpdate::PermissionsChanged() const { @@ -976,7 +981,7 @@ } std::ostream& operator<<(std::ostream& out, const AppUpdate& app) { - out << "AppType: " << app.AppType() << std::endl; + out << "AppType: " << static_cast<int>(app.AppType()) << std::endl; out << "AppId: " << app.AppId() << std::endl; out << "Readiness: " << static_cast<int>(app.Readiness()) << std::endl; out << "Name: " << app.Name() << std::endl; @@ -996,15 +1001,7 @@ out << "Permissions:" << std::endl; for (const auto& permission : app.Permissions()) { - out << " ID: " << permission->permission_type; - out << " value: " << std::endl; - if (permission->value->is_bool_value()) { - out << " bool_value: " << permission->value->get_bool_value(); - } - if (permission->value->is_tristate_value()) { - out << " tristate_value: " << permission->value->get_tristate_value(); - } - out << " is_managed: " << permission->is_managed << std::endl; + out << permission->ToString(); } out << "InstallReason: " << static_cast<int>(app.InstallReason())
diff --git a/components/services/app_service/public/cpp/app_update.h b/components/services/app_service/public/cpp/app_update.h index 07ef563..fdab66f 100644 --- a/components/services/app_service/public/cpp/app_update.h +++ b/components/services/app_service/public/cpp/app_update.h
@@ -76,8 +76,7 @@ // Equivalently, there are no previous deltas for the AppId. bool StateIsNull() const; - apps::mojom::AppType AppType() const; - apps::AppType GetAppType() const; + apps::AppType AppType() const; const std::string& AppId() const; @@ -115,8 +114,7 @@ base::Time InstallTime() const; bool InstallTimeChanged() const; - std::vector<apps::mojom::PermissionPtr> Permissions() const; - apps::Permissions GetPermissions() const; + apps::Permissions Permissions() const; bool PermissionsChanged() const; apps::InstallReason InstallReason() const;
diff --git a/components/services/app_service/public/cpp/app_update_mojom_unittest.cc b/components/services/app_service/public/cpp/app_update_mojom_unittest.cc index 21a9c261..4a8fdd1 100644 --- a/components/services/app_service/public/cpp/app_update_mojom_unittest.cc +++ b/components/services/app_service/public/cpp/app_update_mojom_unittest.cc
@@ -57,7 +57,7 @@ base::Time expect_install_time_; bool expect_install_time_changed_; - std::vector<apps::mojom::PermissionPtr> expect_permissions_; + apps::Permissions expect_permissions_; bool expect_permissions_changed_; apps::InstallReason expect_install_reason_; @@ -191,7 +191,7 @@ EXPECT_EQ(expect_install_time_, u.InstallTime()); EXPECT_EQ(expect_install_time_changed_, u.InstallTimeChanged()); - EXPECT_EQ(expect_permissions_, u.Permissions()); + EXPECT_TRUE(IsEqual(expect_permissions_, u.Permissions())); EXPECT_EQ(expect_permissions_changed_, u.PermissionsChanged()); EXPECT_EQ(expect_install_reason_, u.InstallReason()); @@ -254,7 +254,7 @@ void TestAppUpdate(apps::mojom::App* state, apps::mojom::App* delta) { apps::AppUpdate u(state, delta, account_id_); - EXPECT_EQ(app_type, u.AppType()); + EXPECT_EQ(app_type, apps::ConvertAppTypeToMojomAppType(u.AppType())); EXPECT_EQ(app_id, u.AppId()); EXPECT_EQ(state == nullptr, u.StateIsNull()); @@ -828,8 +828,10 @@ apps::mojom::TriState::kAllow); state->permissions.push_back(p0.Clone()); state->permissions.push_back(p1.Clone()); - expect_permissions_.push_back(p0.Clone()); - expect_permissions_.push_back(p1.Clone()); + expect_permissions_.push_back( + apps::ConvertMojomPermissionToPermission(p0)); + expect_permissions_.push_back( + apps::ConvertMojomPermissionToPermission(p1)); expect_permissions_changed_ = false; CheckExpects(u); } @@ -843,8 +845,10 @@ delta->permissions.push_back(p0.Clone()); delta->permissions.push_back(p1.Clone()); - expect_permissions_.push_back(p0.Clone()); - expect_permissions_.push_back(p1.Clone()); + expect_permissions_.push_back( + apps::ConvertMojomPermissionToPermission(p0)); + expect_permissions_.push_back( + apps::ConvertMojomPermissionToPermission(p1)); expect_permissions_changed_ = true; CheckExpects(u); }
diff --git a/components/services/app_service/public/cpp/app_update_unittest.cc b/components/services/app_service/public/cpp/app_update_unittest.cc index 4d3d2c4..261f7eb 100644 --- a/components/services/app_service/public/cpp/app_update_unittest.cc +++ b/components/services/app_service/public/cpp/app_update_unittest.cc
@@ -200,7 +200,7 @@ EXPECT_EQ(expect_install_time_, u.InstallTime()); EXPECT_EQ(expect_install_time_changed_, u.InstallTimeChanged()); - EXPECT_TRUE(IsEqual(expect_permissions_, u.GetPermissions())); + EXPECT_TRUE(IsEqual(expect_permissions_, u.Permissions())); EXPECT_EQ(expect_permissions_changed_, u.PermissionsChanged()); EXPECT_EQ(expect_install_reason_, u.InstallReason()); @@ -263,7 +263,7 @@ void TestAppUpdate(App* state, App* delta) { AppUpdate u(state, delta, account_id_); - EXPECT_EQ(app_type, u.GetAppType()); + EXPECT_EQ(app_type, u.AppType()); EXPECT_EQ(app_id, u.AppId()); expect_readiness_ = Readiness::kUnknown;
diff --git a/components/services/app_service/public/cpp/icon_cache.cc b/components/services/app_service/public/cpp/icon_cache.cc index c5666711..5ae66185e5 100644 --- a/components/services/app_service/public/cpp/icon_cache.cc +++ b/components/services/app_service/public/cpp/icon_cache.cc
@@ -190,8 +190,7 @@ } } -void IconCache::RemoveIcon(apps::mojom::AppType app_type, - const std::string& app_id) { +void IconCache::RemoveIcon(AppType app_type, const std::string& app_id) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (gc_policy_ != GarbageCollectionPolicy::kExplicit) { return; @@ -199,8 +198,7 @@ auto iter = map_.begin(); while (iter != map_.end()) { - if (iter->first.app_type_ == ConvertMojomAppTypToAppType(app_type) && - iter->first.app_id_ == app_id) { + if (iter->first.app_type_ == app_type && iter->first.app_id_ == app_id) { iter = map_.erase(iter); } else { ++iter;
diff --git a/components/services/app_service/public/cpp/icon_cache.h b/components/services/app_service/public/cpp/icon_cache.h index da81c99..d07a088 100644 --- a/components/services/app_service/public/cpp/icon_cache.h +++ b/components/services/app_service/public/cpp/icon_cache.h
@@ -13,6 +13,7 @@ #include "base/memory/raw_ptr.h" #include "base/memory/weak_ptr.h" #include "base/sequence_checker.h" +#include "components/services/app_service/public/cpp/app_types.h" #include "components/services/app_service/public/cpp/icon_loader.h" #include "components/services/app_service/public/mojom/app_service.mojom.h" #include "components/services/app_service/public/mojom/types.mojom.h" @@ -112,7 +113,7 @@ // actively held. void SweepReleasedIcons(); - void RemoveIcon(apps::mojom::AppType app_type, const std::string& app_id); + void RemoveIcon(AppType app_type, const std::string& app_id); private: class Value {
diff --git a/components/services/app_service/public/cpp/icon_cache_unittest.cc b/components/services/app_service/public/cpp/icon_cache_unittest.cc index 3e5d998..4aaad9e 100644 --- a/components/services/app_service/public/cpp/icon_cache_unittest.cc +++ b/components/services/app_service/public/cpp/icon_cache_unittest.cc
@@ -133,8 +133,8 @@ HitOrMiss expect_hom = kHit; if (gc_policy == apps::IconCache::GarbageCollectionPolicy::kExplicit) { if (remove_icon) { - cache.RemoveIcon(apps::mojom::AppType::kWeb, "cherry"); - cache.RemoveIcon(apps::mojom::AppType::kWeb, "apricot"); + cache.RemoveIcon(apps::AppType::kWeb, "cherry"); + cache.RemoveIcon(apps::AppType::kWeb, "apricot"); expect_hom = kMiss; } else { cache.SweepReleasedIcons(); @@ -147,7 +147,7 @@ if (gc_policy == apps::IconCache::GarbageCollectionPolicy::kExplicit) { if (remove_icon) { - cache.RemoveIcon(apps::mojom::AppType::kWeb, "cherry"); + cache.RemoveIcon(apps::AppType::kWeb, "cherry"); } else { cache.SweepReleasedIcons(); } @@ -223,7 +223,7 @@ if (gc_policy == apps::IconCache::GarbageCollectionPolicy::kExplicit) { if (remove_icon) { - cache.RemoveIcon(apps::mojom::AppType::kWeb, "watermelon"); + cache.RemoveIcon(apps::AppType::kWeb, "watermelon"); } else { cache.SweepReleasedIcons(); }
diff --git a/components/services/app_service/public/cpp/permission.cc b/components/services/app_service/public/cpp/permission.cc index 383b241..e47e8735 100644 --- a/components/services/app_service/public/cpp/permission.cc +++ b/components/services/app_service/public/cpp/permission.cc
@@ -37,7 +37,7 @@ return nullptr; } -bool PermissionValue::IsPermissionEnabled() { +bool PermissionValue::IsPermissionEnabled() const { if (tristate_value.has_value()) { return tristate_value.value() == TriState::kAllow; } else if (bool_value.has_value()) { @@ -74,6 +74,25 @@ is_managed); } +bool Permission::IsPermissionEnabled() const { + return value && value->IsPermissionEnabled(); +} + +std::string Permission::ToString() const { + std::stringstream out; + out << " permission type: " << static_cast<int>(permission_type); + out << " value: " << std::endl; + if (value && value->bool_value.has_value()) { + out << " bool_value: " << (value->bool_value.value() ? "true" : "false"); + } + if (value && value->tristate_value.has_value()) { + out << " tristate_value: " + << static_cast<int>(value->tristate_value.value()); + } + out << " is_managed: " << (is_managed ? "true" : "false") << std::endl; + return out.str(); +} + Permissions ClonePermissions(const Permissions& source_permissions) { Permissions permissions; for (const auto& permission : source_permissions) {
diff --git a/components/services/app_service/public/cpp/permission.h b/components/services/app_service/public/cpp/permission.h index c46b91c6..6472746 100644 --- a/components/services/app_service/public/cpp/permission.h +++ b/components/services/app_service/public/cpp/permission.h
@@ -46,7 +46,7 @@ // Checks whether this is equal to permission enabled. If it is TriState, only // Allow represent permission enabled. - bool IsPermissionEnabled(); + bool IsPermissionEnabled() const; absl::optional<bool> bool_value; absl::optional<TriState> tristate_value; @@ -67,6 +67,12 @@ std::unique_ptr<Permission> Clone() const; + // Checks whether this is equal to permission enabled. If it is TriState, only + // Allow represent permission enabled. + bool IsPermissionEnabled() const; + + std::string ToString() const; + PermissionType permission_type; std::unique_ptr<PermissionValue> value; // If the permission is managed by an enterprise policy.
diff --git a/components/services/app_service/public/cpp/types_util.cc b/components/services/app_service/public/cpp/types_util.cc index 12a2a3f..cf94385 100644 --- a/components/services/app_service/public/cpp/types_util.cc +++ b/components/services/app_service/public/cpp/types_util.cc
@@ -78,23 +78,23 @@ NOTREACHED(); } -bool AppTypeUsesWebContents(apps::mojom::AppType app_type) { +bool AppTypeUsesWebContents(apps::AppType app_type) { switch (app_type) { - case apps::mojom::AppType::kWeb: - case apps::mojom::AppType::kSystemWeb: - case apps::mojom::AppType::kChromeApp: - case apps::mojom::AppType::kExtension: + case apps::AppType::kWeb: + case apps::AppType::kSystemWeb: + case apps::AppType::kChromeApp: + case apps::AppType::kExtension: return true; - case apps::mojom::AppType::kUnknown: - case apps::mojom::AppType::kArc: - case apps::mojom::AppType::kBuiltIn: - case apps::mojom::AppType::kCrostini: - case apps::mojom::AppType::kMacOs: - case apps::mojom::AppType::kPluginVm: - case apps::mojom::AppType::kStandaloneBrowser: - case apps::mojom::AppType::kRemote: - case apps::mojom::AppType::kBorealis: - case apps::mojom::AppType::kStandaloneBrowserChromeApp: + case apps::AppType::kUnknown: + case apps::AppType::kArc: + case apps::AppType::kBuiltIn: + case apps::AppType::kCrostini: + case apps::AppType::kMacOs: + case apps::AppType::kPluginVm: + case apps::AppType::kStandaloneBrowser: + case apps::AppType::kRemote: + case apps::AppType::kBorealis: + case apps::AppType::kStandaloneBrowserChromeApp: return false; } NOTREACHED();
diff --git a/components/services/app_service/public/cpp/types_util.h b/components/services/app_service/public/cpp/types_util.h index 097992c..32b465b 100644 --- a/components/services/app_service/public/cpp/types_util.h +++ b/components/services/app_service/public/cpp/types_util.h
@@ -18,7 +18,7 @@ // Checks if an app of |app_type| runs in Browser/WebContents (web apps, hosted // apps, and packaged v1 apps). -bool AppTypeUsesWebContents(apps::mojom::AppType app_type); +bool AppTypeUsesWebContents(apps::AppType app_type); } // namespace apps_util
diff --git a/components/shared_highlighting/core/common/shared_highlighting_metrics.h b/components/shared_highlighting/core/common/shared_highlighting_metrics.h index 24e9864..7830b48 100644 --- a/components/shared_highlighting/core/common/shared_highlighting_metrics.h +++ b/components/shared_highlighting/core/common/shared_highlighting_metrics.h
@@ -73,7 +73,11 @@ // cannot be established. Android only. kNoRemoteConnection = 13, - kMaxValue = kNoRemoteConnection + // TODO(crbug.com/1301794): This shouldn't happen, but sometimes browser side + // requests link to text when generation was never started. + kNotGenerated = 14, + + kMaxValue = kNotGenerated }; // These values are persisted to logs. Entries should not be renumbered and
diff --git a/components/sync/driver/glue/sync_engine_backend.cc b/components/sync/driver/glue/sync_engine_backend.cc index ab5b484..f5605e0 100644 --- a/components/sync/driver/glue/sync_engine_backend.cc +++ b/components/sync/driver/glue/sync_engine_backend.cc
@@ -71,6 +71,16 @@ const std::string payload_; }; +void RecordInvalidationPerModelType(ModelType type) { + UMA_HISTOGRAM_ENUMERATION("Sync.InvalidationPerModelType", + ModelTypeHistogramValue(type)); +} + +void RecordIncomingInvalidationStatus( + SyncEngineBackend::IncomingInvalidationStatus status) { + UMA_HISTOGRAM_ENUMERATION("Sync.IncomingInvalidationStatus", status); +} + } // namespace SyncEngineBackend::RestoredLocalTransportData::RestoredLocalTransportData() = @@ -168,14 +178,19 @@ ModelType type; if (!NotificationTypeToRealModelType(topic, &type)) { DLOG(WARNING) << "Notification has invalid topic: " << topic; + RecordIncomingInvalidationStatus( + IncomingInvalidationStatus::kUnknownModelType); } else { - UMA_HISTOGRAM_ENUMERATION("Sync.InvalidationPerModelType", - ModelTypeHistogramValue(type)); + RecordInvalidationPerModelType(type); invalidation::SingleTopicInvalidationSet invalidation_set = invalidation_map.ForTopic(topic); for (invalidation::Invalidation invalidation : invalidation_set) { - RecordRedundantInvalidationsMetric(invalidation, type); + // Topic-based invalidations contain only one data type, hence this + // metric should be recorded for each incoming invalidation to represent + // all incoming messages. + RecordIncomingInvalidationStatus(IncomingInvalidationStatus::kSuccess); + RecordRedundantInvalidationsMetric(invalidation, type); std::unique_ptr<SyncInvalidation> inv_adapter( new InvalidationAdapter(invalidation)); sync_manager_->OnIncomingInvalidation(type, std::move(inv_adapter)); @@ -460,12 +475,19 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(base::FeatureList::IsEnabled(kSyncSendInterestedDataTypes) && base::FeatureList::IsEnabled(kUseSyncInvalidations)); + const IncomingInvalidationStatus status = + DoOnInvalidationReceivedImpl(payload); + RecordIncomingInvalidationStatus(status); +} +SyncEngineBackend::IncomingInvalidationStatus +SyncEngineBackend::DoOnInvalidationReceivedImpl(const std::string& payload) { sync_pb::SyncInvalidationsPayload payload_message; - // TODO(crbug.com/1119804): Track parsing failures in a histogram. if (!payload_message.ParseFromString(payload)) { - return; + return IncomingInvalidationStatus::kPayloadParseFailed; } + + bool contains_valid_model_type = false; for (const auto& data_type_invalidation : payload_message.data_type_invalidations()) { const int field_number = data_type_invalidation.data_type_id(); @@ -475,11 +497,17 @@ continue; } + contains_valid_model_type = true; // TODO(crbug.com/1119798): Use only enabled data types. + RecordInvalidationPerModelType(model_type); std::unique_ptr<SyncInvalidation> inv_adapter = std::make_unique<SyncInvalidationAdapter>(payload_message.hint()); sync_manager_->OnIncomingInvalidation(model_type, std::move(inv_adapter)); } + if (contains_valid_model_type) { + return IncomingInvalidationStatus::kSuccess; + } + return IncomingInvalidationStatus::kUnknownModelType; } void SyncEngineBackend::DoOnActiveDevicesChanged(
diff --git a/components/sync/driver/glue/sync_engine_backend.h b/components/sync/driver/glue/sync_engine_backend.h index d7526b8..31dd257 100644 --- a/components/sync/driver/glue/sync_engine_backend.h +++ b/components/sync/driver/glue/sync_engine_backend.h
@@ -59,6 +59,24 @@ base::TimeDelta poll_interval; }; + // Used to record result of handling of incoming sync invalidations. These + // values are persisted to logs. Entries should not be renumbered and numeric + // values should never be reused. + enum class IncomingInvalidationStatus { + // The payload parsed successfully and contains at least one valid data + // type. + kSuccess = 0, + + // Failed to parse incoming payload, relevant only for sync standalone + // invalidations. + kPayloadParseFailed = 1, + + // All data types in the payload are unknown. + kUnknownModelType = 2, + + kMaxValue = kUnknownModelType, + }; + SyncEngineBackend(const std::string& name, const base::FilePath& sync_data_folder, const base::WeakPtr<SyncEngineImpl>& host); @@ -155,8 +173,9 @@ // Notify about change in client id. void DoOnInvalidatorClientIdChange(const std::string& client_id); - // Forwards an invalidation to the sync manager for all data types from the - // |payload|. + // Forwards an invalidation to the sync manager for all data types extracted + // from the |payload|. This method is called for sync standalone + // invalidations. void DoOnInvalidationReceived(const std::string& payload); // Returns a ListValue representing Nigori node. @@ -182,6 +201,9 @@ void LoadAndConnectNigoriController(); + IncomingInvalidationStatus DoOnInvalidationReceivedImpl( + const std::string& payload); + // Name used for debugging. const std::string name_;
diff --git a/components/test/data/payments/change_payment_method.html b/components/test/data/payments/change_payment_method.html index 5852599..c78c365 100644 --- a/components/test/data/payments/change_payment_method.html +++ b/components/test/data/payments/change_payment_method.html
@@ -6,6 +6,8 @@ --> <html lang="en"> <head> + <script src="util.js"></script> + <script src="change_payment_method.js"></script> <meta charset="utf-8"> <meta name="viewport" @@ -38,7 +40,5 @@ </button> </div> <pre id="result"></pre> - <script src="util.js"></script> - <script src="change_payment_method.js"></script> </body> </html>
diff --git a/components/test/data/payments/empty_parameters_test.html b/components/test/data/payments/empty_parameters_test.html index c755ba30..36833d37 100644 --- a/components/test/data/payments/empty_parameters_test.html +++ b/components/test/data/payments/empty_parameters_test.html
@@ -6,6 +6,7 @@ --> <html> <head> +<script src="empty_parameters.js"></script> <title>Empty Parameters Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -14,6 +15,5 @@ <body> <p>Regression test for <a href="https://crbug.com/1022810">Issue 1022810</a>.</p> <div><button onclick="runTest()" id="runTest">Run Test</button></div> -<script src="empty_parameters.js"></script> </body> </html>
diff --git a/components/test/data/payments/initiated_test.html b/components/test/data/payments/initiated_test.html index 32cb67e8..3046b34 100644 --- a/components/test/data/payments/initiated_test.html +++ b/components/test/data/payments/initiated_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="initiated.js"></script> <title>Initiated Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -15,7 +17,5 @@ <button onclick="show()" id="show">Show</button><div> <button onclick="abort()" id="abort">Abort</button><div> <pre id="result"></pre> -<script src="util.js"></script> -<script src="initiated.js"></script> </body> </html>
diff --git a/components/test/data/payments/journey_logger_test.html b/components/test/data/payments/journey_logger_test.html index f6b7d87..1e48be35 100644 --- a/components/test/data/payments/journey_logger_test.html +++ b/components/test/data/payments/journey_logger_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="journey_logger.js"></script> <title>Bob Pay and Cards Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -15,7 +17,5 @@ <div><button onclick="testBasicCard()" id="testBasicCard">Test basic-card</button></div> <div><button onclick="testGPay()" id="testGPay">Test (fake) GPay</button></div> <pre id="result"></pre> -<script src="util.js"></script> -<script src="journey_logger.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_handler.html b/components/test/data/payments/payment_handler.html index 8a1543e..ab331c4 100644 --- a/components/test/data/payments/payment_handler.html +++ b/components/test/data/payments/payment_handler.html
@@ -6,6 +6,7 @@ --> <html lang="en"> <head> +<script src="payment_handler.js"></script> <meta charset="utf-8"> <meta name="viewport" @@ -21,6 +22,5 @@ <div> <button onclick="launch()" id="testNoHandler">Launch Payment Handler</button> </div> - <script src="payment_handler.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request.html b/components/test/data/payments/payment_request.html index 455c56b..f32d1e9 100644 --- a/components/test/data/payments/payment_request.html +++ b/components/test/data/payments/payment_request.html
@@ -7,6 +7,7 @@ <html lang="en"> <head> + <script src="payment_request.js"></script> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> <title>US-only delivery with e-mail address</title> @@ -20,7 +21,6 @@ <p><button id="buy" onclick="onBuyClicked()">Buy</button></p> </div> <pre id="msg"></pre> - <script src="payment_request.js"></script> </body> </html> \ No newline at end of file
diff --git a/components/test/data/payments/payment_request_abort_test.html b/components/test/data/payments/payment_request_abort_test.html index 869268b..a4386ea3 100644 --- a/components/test/data/payments/payment_request_abort_test.html +++ b/components/test/data/payments/payment_request_abort_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="abort.js"></script> <title>Abort Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -14,7 +16,5 @@ <div><button onclick="buy()" id="buy">Buy</button></div> <button onclick="abort()" id="abort">Abort</button> <pre id="result"></pre> -<script src="util.js"></script> -<script src="abort.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_alicepay_bobpay_charliepay_test.html b/components/test/data/payments/payment_request_alicepay_bobpay_charliepay_test.html index 6ea6a51..1ab8bf4 100644 --- a/components/test/data/payments/payment_request_alicepay_bobpay_charliepay_test.html +++ b/components/test/data/payments/payment_request_alicepay_bobpay_charliepay_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="alicepay_bobpay_charliepay.js"></script> <title>Alice Pay, Bob Pay, Charlie Pay Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -16,7 +18,5 @@ <button onclick="buy()" id="buy">Multiple apps Test</button> </div> <pre id="result"></pre> -<script src="util.js"></script> -<script src="alicepay_bobpay_charliepay.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_blob_url_test.html b/components/test/data/payments/payment_request_blob_url_test.html index e96f3419..5da6612 100644 --- a/components/test/data/payments/payment_request_blob_url_test.html +++ b/components/test/data/payments/payment_request_blob_url_test.html
@@ -6,12 +6,12 @@ --> <html> <head> +<script src="blob_url.js"></script> <title>Blob URL Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> </head> <body> <button onclick="buy()" id="buy">Blob URL Test</button> -<script src="blob_url.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_bobpay_and_basic_card_with_modifier_optional_data_test.html b/components/test/data/payments/payment_request_bobpay_and_basic_card_with_modifier_optional_data_test.html index 895033b..2df9dcd 100644 --- a/components/test/data/payments/payment_request_bobpay_and_basic_card_with_modifier_optional_data_test.html +++ b/components/test/data/payments/payment_request_bobpay_and_basic_card_with_modifier_optional_data_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="bobpay_and_basic_card_with_modifier_optional_data.js"></script> <title>Bob Pay and basic-card with modifier optional data test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -20,7 +22,5 @@ <button onclick="buyWithContactRequested()" id="buy_with_contact_requested">Contact details requested test</button> <button onclick="buyWithShippingAndContactRequested()" id="buy_with_shipping_and_contact_requested">Shipping and contact details requested test</button> <pre id="result"></pre> -<script src="util.js"></script> -<script src="bobpay_and_basic_card_with_modifier_optional_data.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_bobpay_and_basic_card_with_modifiers_test.html b/components/test/data/payments/payment_request_bobpay_and_basic_card_with_modifiers_test.html index 98db200..469b0f5c7 100644 --- a/components/test/data/payments/payment_request_bobpay_and_basic_card_with_modifiers_test.html +++ b/components/test/data/payments/payment_request_bobpay_and_basic_card_with_modifiers_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="bobpay_and_basic_card_with_modifiers.js"></script> <title>Bob Pay and basic-card with Basic-Card modifiers Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -19,7 +21,5 @@ <button onclick="mastercardAnySupportedType()" id="mastercard_any_supported_type">Bob Pay and Basic-Card with Basic-Card modifiers Test with mastercard supported network and any supported type</button> <button onclick="noTotal()" id="no_total">No Total</button> <pre id="result"></pre> -<script src="util.js"></script> -<script src="bobpay_and_basic_card_with_modifiers.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_bobpay_and_cards_test.html b/components/test/data/payments/payment_request_bobpay_and_cards_test.html index 93f7115..2598354 100644 --- a/components/test/data/payments/payment_request_bobpay_and_cards_test.html +++ b/components/test/data/payments/payment_request_bobpay_and_cards_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="bobpay_and_cards.js"></script> <title>Bob Pay and Cards Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -15,7 +17,5 @@ <div><button onclick="buy()" id="buy">Bob Pay and Cards Test</button></div> <div><button onclick="testInstallableAppAndCard()" id="installable-app">Installable App</button></div> <pre id="result"></pre> -<script src="util.js"></script> -<script src="bobpay_and_cards.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_bobpay_test.html b/components/test/data/payments/payment_request_bobpay_test.html index ce2a5b8..bc510bf 100644 --- a/components/test/data/payments/payment_request_bobpay_test.html +++ b/components/test/data/payments/payment_request_bobpay_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="bobpay.js"></script> <title>Bob Pay Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -19,7 +21,5 @@ </button> </div> <pre id="result"></pre> -<script src="util.js"></script> -<script src="bobpay.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_bobpay_ui_skip_preload_test.html b/components/test/data/payments/payment_request_bobpay_ui_skip_preload_test.html index 5a30fa44..8aaf440 100644 --- a/components/test/data/payments/payment_request_bobpay_ui_skip_preload_test.html +++ b/components/test/data/payments/payment_request_bobpay_ui_skip_preload_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="bobpay_ui_skip_preload.js"></script> <title>UI skip, preload test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -14,7 +16,5 @@ <body> <div><button onclick="buy()" id="buy">UI skip, preload test</button></div> <pre id="result"></pre> -<script src="util.js"></script> -<script src="bobpay_ui_skip_preload.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_bobpay_ui_skip_test.html b/components/test/data/payments/payment_request_bobpay_ui_skip_test.html index 7b172a49..5827f056 100644 --- a/components/test/data/payments/payment_request_bobpay_ui_skip_test.html +++ b/components/test/data/payments/payment_request_bobpay_ui_skip_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="bobpay_ui_skip.js"></script> <title>Bob Pay UI skip Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -16,7 +18,5 @@ <div><button onclick="buyFail()" id="buyFail">Failure Test</button></div> <div><button onclick="buyWithRequestedEmail()" id="buyWithRequestedEmail">Bob Pay Test</button></div> <pre id="result"></pre> -<script src="util.js"></script> -<script src="bobpay_ui_skip.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_can_make_payment_metrics_test.html b/components/test/data/payments/payment_request_can_make_payment_metrics_test.html index 9e4239b..a6665b51d 100644 --- a/components/test/data/payments/payment_request_can_make_payment_metrics_test.html +++ b/components/test/data/payments/payment_request_can_make_payment_metrics_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="can_make_payment_metrics.js"></script> <title>Can Make Payment Metrics Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -28,7 +30,5 @@ </div> <div><button onclick="abort()" id="abort">Abort</button></div> <pre id="result"></pre> -<script src="util.js"></script> -<script src="can_make_payment_metrics.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_can_make_payment_query_bobpay_test.html b/components/test/data/payments/payment_request_can_make_payment_query_bobpay_test.html index a89b070..6c4a617 100644 --- a/components/test/data/payments/payment_request_can_make_payment_query_bobpay_test.html +++ b/components/test/data/payments/payment_request_can_make_payment_query_bobpay_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="can_make_payment_query_bobpay.js"></script> <title>Active Payment Query Bob Pay Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -15,7 +17,5 @@ <button onclick="otherBuy()" id="otherBuy">Check BobPay and AlicePay</button> <button onclick="hasEnrolledInstrument()" id="hasEnrolledInstrument">Check hasEnrolledInstrument on BobPay and AlicePay</button> <pre id="result"></pre> -<script src="util.js"></script> -<script src="can_make_payment_query_bobpay.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_can_make_payment_query_cc_test.html b/components/test/data/payments/payment_request_can_make_payment_query_cc_test.html index 6072c1a6..9fe5714 100644 --- a/components/test/data/payments/payment_request_can_make_payment_query_cc_test.html +++ b/components/test/data/payments/payment_request_can_make_payment_query_cc_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="can_make_payment_query_cc.js"></script> <title>Active Payment Query Credit Card Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -20,7 +22,5 @@ Mastercard hasEnrolledInstrument Test </button> <pre id="result"></pre> -<script src="util.js"></script> -<script src="can_make_payment_query_cc.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_can_make_payment_query_test.html b/components/test/data/payments/payment_request_can_make_payment_query_test.html index d704ad1..1812d9e 100644 --- a/components/test/data/payments/payment_request_can_make_payment_query_test.html +++ b/components/test/data/payments/payment_request_can_make_payment_query_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="can_make_payment_query.js"></script> <title>Active Payment Query Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -15,7 +17,5 @@ <button onclick="buy()" id="buy">Active Payment Query Test</button> <button onclick="hasEnrolledInstrument()" id="hasEnrolledInstrument">Check hasEnrolledInstrument</button> <pre id="result"></pre> -<script src="util.js"></script> -<script src="can_make_payment_query.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_contact_details_and_free_shipping_test.html b/components/test/data/payments/payment_request_contact_details_and_free_shipping_test.html index f8b9e3a..71b9a65 100644 --- a/components/test/data/payments/payment_request_contact_details_and_free_shipping_test.html +++ b/components/test/data/payments/payment_request_contact_details_and_free_shipping_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="contact_details_and_free_shipping.js"></script> <title>Contact Details and Free Shipping Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -14,7 +16,5 @@ <body> <button onclick="buy()" id="buy">Contact Details and Free Shipping Test</button> <pre id="result"></pre> -<script src="util.js"></script> -<script src="contact_details_and_free_shipping.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_contact_details_test.html b/components/test/data/payments/payment_request_contact_details_test.html index 17c8bcf..9d3e276 100644 --- a/components/test/data/payments/payment_request_contact_details_test.html +++ b/components/test/data/payments/payment_request_contact_details_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="contact_details.js"></script> <title>Contact Details Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -14,7 +16,5 @@ <body> <button onclick="buy()" id="buy">Contact Details Test</button> <pre id="result"></pre> -<script src="util.js"></script> -<script src="contact_details.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_dynamic_shipping_test.html b/components/test/data/payments/payment_request_dynamic_shipping_test.html index 8a35c2c..9974eac 100644 --- a/components/test/data/payments/payment_request_dynamic_shipping_test.html +++ b/components/test/data/payments/payment_request_dynamic_shipping_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="dynamic_shipping.js"></script> <title>Dynamic Shipping Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -14,7 +16,5 @@ <body> <button onclick="buy()" id="buy">Dynamic Shipping Test</button> <pre id="result"></pre> -<script src="util.js"></script> -<script src="dynamic_shipping.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_email_and_free_shipping_test.html b/components/test/data/payments/payment_request_email_and_free_shipping_test.html index 3652190..5aec7ea 100644 --- a/components/test/data/payments/payment_request_email_and_free_shipping_test.html +++ b/components/test/data/payments/payment_request_email_and_free_shipping_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="email_and_free_shipping.js"></script> <title>Email and Free Shipping Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -14,7 +16,5 @@ <body> <button onclick="buy()" id="buy">Email and Free Shipping Test</button> <pre id="result"></pre> -<script src="util.js"></script> -<script src="email_and_free_shipping.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_email_and_phone_test.html b/components/test/data/payments/payment_request_email_and_phone_test.html index b4e481b..a7a97c85 100644 --- a/components/test/data/payments/payment_request_email_and_phone_test.html +++ b/components/test/data/payments/payment_request_email_and_phone_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="email_and_phone.js"></script> <title>Email and Phone Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -14,7 +16,5 @@ <body> <button onclick="buy()" id="buy">Email and Phone Test</button> <pre id="result"></pre> -<script src="util.js"></script> -<script src="email_and_phone.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_email_test.html b/components/test/data/payments/payment_request_email_test.html index 0f5b8e1..dd3f045 100644 --- a/components/test/data/payments/payment_request_email_test.html +++ b/components/test/data/payments/payment_request_email_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="email.js"></script> <title>Email Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -14,7 +16,5 @@ <body> <button onclick="buy()" id="buy">Email Test</button> <pre id="result"></pre> -<script src="util.js"></script> -<script src="email.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_empty_update_test.html b/components/test/data/payments/payment_request_empty_update_test.html index 85048d9..88ec74c 100644 --- a/components/test/data/payments/payment_request_empty_update_test.html +++ b/components/test/data/payments/payment_request_empty_update_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="empty_update.js"></script> <title>Empty Update Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -14,7 +16,5 @@ <body> <button onclick="buy()" id="buy">Empty Update Test</button> <pre id="result"></pre> -<script src="util.js"></script> -<script src="empty_update.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_extra_shipping_options_test.html b/components/test/data/payments/payment_request_extra_shipping_options_test.html index ca17d28..eb2f41f 100644 --- a/components/test/data/payments/payment_request_extra_shipping_options_test.html +++ b/components/test/data/payments/payment_request_extra_shipping_options_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="extra_shipping_options.js"></script> <title>Extra Shipping Options Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -14,7 +16,5 @@ <body> <button onclick="buy()" id="buy">Extra Shipping Options Test</button> <pre id="result"></pre> -<script src="util.js"></script> -<script src="extra_shipping_options.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_fail_complete_test.html b/components/test/data/payments/payment_request_fail_complete_test.html index 67e21824..fcd5436bb 100644 --- a/components/test/data/payments/payment_request_fail_complete_test.html +++ b/components/test/data/payments/payment_request_fail_complete_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="fail_complete.js"></script> <title>No Shipping Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -14,7 +16,5 @@ <body> <button onclick="buy()" id="buy">Fail Complete Test</button> <pre id="result"></pre> -<script src="util.js"></script> -<script src="fail_complete.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_free_shipping_test.html b/components/test/data/payments/payment_request_free_shipping_test.html index dd7282b..f433190 100644 --- a/components/test/data/payments/payment_request_free_shipping_test.html +++ b/components/test/data/payments/payment_request_free_shipping_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="free_shipping.js"></script> <title>Free Shipping Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -14,7 +16,5 @@ <body> <button onclick="buy()" id="buy">Free Shipping Test</button> <pre id="result"></pre> -<script src="util.js"></script> -<script src="free_shipping.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_free_shipping_with_iframe_test.html b/components/test/data/payments/payment_request_free_shipping_with_iframe_test.html index 11e9e196..c7187ce 100644 --- a/components/test/data/payments/payment_request_free_shipping_with_iframe_test.html +++ b/components/test/data/payments/payment_request_free_shipping_with_iframe_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="free_shipping.js"></script> <title>Free Shipping With Iframe Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -15,7 +17,5 @@ <button onclick="buy()" id="buy">Free Shipping Test</button> <pre id="result"></pre> <iframe id="theIframe"></iframe> -<script src="util.js"></script> -<script src="free_shipping.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_id_test.html b/components/test/data/payments/payment_request_id_test.html index 811ed7898..bc202a70 100644 --- a/components/test/data/payments/payment_request_id_test.html +++ b/components/test/data/payments/payment_request_id_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="payment_request_id.js"></script> <title>Payment Request Id Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -14,7 +16,5 @@ <body> <button onclick="buy()" id="buy">Payment Request Id Test</button> <pre id="result"></pre> -<script src="util.js"></script> -<script src="payment_request_id.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_long_id_test.html b/components/test/data/payments/payment_request_long_id_test.html index 7eb1e28..5a295d2 100644 --- a/components/test/data/payments/payment_request_long_id_test.html +++ b/components/test/data/payments/payment_request_long_id_test.html
@@ -7,6 +7,8 @@ <html> <head> +<script src="util.js"></script> +<script src="long_id.js"></script> <meta charset="utf-8"> <title>Long ID Test</title> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -16,8 +18,6 @@ <body> <div><button onclick="buy()" id="buy">Long ID Test</button></div> <pre id="result"></pre> - <script src="util.js"></script> - <script src="long_id.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_metrics_test.html b/components/test/data/payments/payment_request_metrics_test.html index b360491c..6a575bcb 100644 --- a/components/test/data/payments/payment_request_metrics_test.html +++ b/components/test/data/payments/payment_request_metrics_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="metrics.js"></script> <title>Metrics Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -20,7 +22,5 @@ <div> <button onclick="contactInfoBuy()" id="contactInfoBuy">Contact Info Buy Test</button> </div> <button onclick="abort()" id="abort">Abort</button> <pre id="result"></pre> -<script src="util.js"></script> -<script src="metrics.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_modifier_test.html b/components/test/data/payments/payment_request_modifier_test.html index 109f8a2..2546cb9b 100644 --- a/components/test/data/payments/payment_request_modifier_test.html +++ b/components/test/data/payments/payment_request_modifier_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="modifier.js"></script> <title>Modifier Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -13,7 +15,5 @@ <body> <div><button onclick="buy()" id="buy">Modifier Test</button></div> <pre id="result"></pre> -<script src="util.js"></script> -<script src="modifier.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_multiple_show_test.html b/components/test/data/payments/payment_request_multiple_show_test.html index ea12b22c..f95ef95 100644 --- a/components/test/data/payments/payment_request_multiple_show_test.html +++ b/components/test/data/payments/payment_request_multiple_show_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="multiple_show.js"></script> <title>Multiple Show Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -16,7 +18,5 @@ <button onclick="showAgain()" id="showAgain">Show Again</button> <button onclick="showSecondRequest()" id="showSecondRequest">Show Second Request</button> <pre id="result"></pre> -<script src="util.js"></script> -<script src="multiple_show.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_name_and_free_shipping_test.html b/components/test/data/payments/payment_request_name_and_free_shipping_test.html index fc8cab3..fd4133a4 100644 --- a/components/test/data/payments/payment_request_name_and_free_shipping_test.html +++ b/components/test/data/payments/payment_request_name_and_free_shipping_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="name_and_free_shipping.js"></script> <title>Name and Free Shipping Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -14,7 +16,5 @@ <body> <div><button onclick="buy()" id="buy">Name and Free Shipping Test</button></div> <pre id="result"></pre> -<script src="util.js"></script> -<script src="name_and_free_shipping.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_name_test.html b/components/test/data/payments/payment_request_name_test.html index aa9b68c..b76ab52 100644 --- a/components/test/data/payments/payment_request_name_test.html +++ b/components/test/data/payments/payment_request_name_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="name.js"></script> <title>Name Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -14,7 +16,5 @@ <body> <button onclick="buy()" id="buy">Name Test</button> <pre id="result"></pre> -<script src="util.js"></script> -<script src="name.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_no_shipping_options_test.html b/components/test/data/payments/payment_request_no_shipping_options_test.html index e59e9e0..9a88024 100644 --- a/components/test/data/payments/payment_request_no_shipping_options_test.html +++ b/components/test/data/payments/payment_request_no_shipping_options_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="no_shipping_options.js"></script> <title>No Shipping Options Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -14,7 +16,5 @@ <body> <button onclick="buy()" id="buy">No Shipping Options Test</button> <pre id="result"></pre> - <script src="util.js"></script> - <script src="no_shipping_options.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_no_shipping_test.html b/components/test/data/payments/payment_request_no_shipping_test.html index 5e20348..21b16288 100644 --- a/components/test/data/payments/payment_request_no_shipping_test.html +++ b/components/test/data/payments/payment_request_no_shipping_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="no_shipping.js"></script> <title>No Shipping Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -14,7 +16,5 @@ <body> <button onclick="buy()" id="buy">No Shipping Test</button> <pre id="result"></pre> -<script src="util.js"></script> -<script src="no_shipping.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_no_update_with_test.html b/components/test/data/payments/payment_request_no_update_with_test.html index 3696e4a..b84a3f0b 100644 --- a/components/test/data/payments/payment_request_no_update_with_test.html +++ b/components/test/data/payments/payment_request_no_update_with_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="no_update_with.js"></script> <title>No updateWith() Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -16,7 +18,5 @@ <button onclick="buyWithoutCallingUpdateWith()" id="buyWithoutCallingUpdateWith">Buy without calling updateWith()</button> <button onclick="buyWithoutPromises()" id="buyWithoutPromises">Buy without promises</button> <pre id="result"></pre> -<script src="util.js"></script> -<script src="no_update_with.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_onpayerdetailchange.html b/components/test/data/payments/payment_request_onpayerdetailchange.html index 160380fc..b1001b86 100644 --- a/components/test/data/payments/payment_request_onpayerdetailchange.html +++ b/components/test/data/payments/payment_request_onpayerdetailchange.html
@@ -6,6 +6,9 @@ --> <html> <head> +<script src="util.js"></script> +<script src="retry_helper.js"></script> +<script src="onpayerdetailchange.js"></script> <title>Retry test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -14,8 +17,5 @@ <body> <div><button onclick="buy()" id="buy">onpayerdetailchange test</button></div> <pre id="result"></pre> -<script src="util.js"></script> -<script src="retry_helper.js"></script> -<script src="onpayerdetailchange.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_payment_method_identifier_test.html b/components/test/data/payments/payment_request_payment_method_identifier_test.html index a7162be8..b9fa2af 100644 --- a/components/test/data/payments/payment_request_payment_method_identifier_test.html +++ b/components/test/data/payments/payment_request_payment_method_identifier_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="payment_method_identifier.js"></script> <title>PMI Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -28,7 +30,5 @@ <button onclick="buyHelper([basicMastercardMethod])" id="buyBasicMasterCard"> Buy With Basic MasterCardTest</button> <pre id="result"></pre> -<script src="util.js"></script> -<script src="payment_method_identifier.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_phone_and_free_shipping_test.html b/components/test/data/payments/payment_request_phone_and_free_shipping_test.html index b51354f3..39d96536 100644 --- a/components/test/data/payments/payment_request_phone_and_free_shipping_test.html +++ b/components/test/data/payments/payment_request_phone_and_free_shipping_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="phone_and_free_shipping.js"></script> <title>Phone and Free Shipping Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -14,7 +16,5 @@ <body> <button onclick="buy()" id="buy">Phone and Free Shipping Test</button> <pre id="result"></pre> -<script src="util.js"></script> -<script src="phone_and_free_shipping.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_phone_test.html b/components/test/data/payments/payment_request_phone_test.html index 328fdf9..d325262 100644 --- a/components/test/data/payments/payment_request_phone_test.html +++ b/components/test/data/payments/payment_request_phone_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="phone.js"></script> <title>Phone Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -14,7 +16,5 @@ <body> <button onclick="buy()" id="buy">Phone Test</button> <pre id="result"></pre> -<script src="util.js"></script> -<script src="phone.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_retry.html b/components/test/data/payments/payment_request_retry.html index 6d0f4a4a..ad99c3d 100644 --- a/components/test/data/payments/payment_request_retry.html +++ b/components/test/data/payments/payment_request_retry.html
@@ -6,6 +6,9 @@ --> <html> <head> +<script src="util.js"></script> +<script src="retry_helper.js"></script> +<script src="retry.js"></script> <title>Retry test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -15,8 +18,5 @@ <div><button onclick="buy()" id="buy">Retry test</button></div> <div><button onclick="buyWithUrlMethod()" id="buyWithUrlMethod">Retry test (with Url Method)</button></div> <pre id="result"></pre> -<script src="util.js"></script> -<script src="retry_helper.js"></script> -<script src="retry.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_retry_with_no_payment_options.html b/components/test/data/payments/payment_request_retry_with_no_payment_options.html index 61de42b..ddaf07e 100644 --- a/components/test/data/payments/payment_request_retry_with_no_payment_options.html +++ b/components/test/data/payments/payment_request_retry_with_no_payment_options.html
@@ -6,6 +6,9 @@ --> <html> <head> +<script src="util.js"></script> +<script src="retry_helper.js"></script> +<script src="retry_with_no_payment_options.js"></script> <title>Retry with no payment options test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -14,8 +17,5 @@ <body> <div><button onclick="buy()" id="buy">Retry with no payment options test</button></div> <pre id="result"></pre> -<script src="util.js"></script> -<script src="retry_helper.js"></script> -<script src="retry_with_no_payment_options.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_retry_with_payer_errors.html b/components/test/data/payments/payment_request_retry_with_payer_errors.html index 24e7ee2..8893dee 100644 --- a/components/test/data/payments/payment_request_retry_with_payer_errors.html +++ b/components/test/data/payments/payment_request_retry_with_payer_errors.html
@@ -6,6 +6,9 @@ --> <html> <head> +<script src="util.js"></script> +<script src="retry_helper.js"></script> +<script src="retry_with_payer_errors.js"></script> <title>Retry with payer errors test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -14,8 +17,5 @@ <body> <div><button onclick="buy()" id="buy">Retry with payer errors test</button></div> <pre id="result"></pre> -<script src="util.js"></script> -<script src="retry_helper.js"></script> -<script src="retry_with_payer_errors.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_retry_with_shipping_address_errors.html b/components/test/data/payments/payment_request_retry_with_shipping_address_errors.html index 7fc895d0..2c50165a 100644 --- a/components/test/data/payments/payment_request_retry_with_shipping_address_errors.html +++ b/components/test/data/payments/payment_request_retry_with_shipping_address_errors.html
@@ -6,6 +6,9 @@ --> <html> <head> +<script src="util.js"></script> +<script src="retry_helper.js"></script> +<script src="retry_with_shipping_address_errors.js"></script> <title>Retry with shipping address errors test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -14,8 +17,5 @@ <body> <div><button onclick="buy()" id="buy">Retry with shipping address errors test</button></div> <pre id="result"></pre> -<script src="util.js"></script> -<script src="retry_helper.js"></script> -<script src="retry_with_shipping_address_errors.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_shipping_address_change_test.html b/components/test/data/payments/payment_request_shipping_address_change_test.html index e645abc3..c87eb02 100644 --- a/components/test/data/payments/payment_request_shipping_address_change_test.html +++ b/components/test/data/payments/payment_request_shipping_address_change_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="shipping_address_change.js"></script> <title>Shipping Address Change Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -14,7 +16,5 @@ <body> <button onclick="buy()" id="buy">Shipping Address Change Test</button> <pre id="result"></pre> -<script src="util.js"></script> -<script src="shipping_address_change.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_shipping_address_instance_test.html b/components/test/data/payments/payment_request_shipping_address_instance_test.html index 95d0cda..9100e78 100644 --- a/components/test/data/payments/payment_request_shipping_address_instance_test.html +++ b/components/test/data/payments/payment_request_shipping_address_instance_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="shipping_address_instance.js"></script> <title>Shipping Address Instance Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -14,7 +16,5 @@ <body> <button onclick="buy()" id="buy">Shipping Address Instance Test</button> <pre id="result"></pre> -<script src="util.js"></script> -<script src="shipping_address_instance.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_show_promise.html b/components/test/data/payments/payment_request_show_promise.html index 00670cb..bb90e18e 100644 --- a/components/test/data/payments/payment_request_show_promise.html +++ b/components/test/data/payments/payment_request_show_promise.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="show_promise.js"></script> <title>Show Promise Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -16,7 +18,5 @@ <button onclick="buyWithResolvingPromise()" id="buyWithResolvingPromise">Buy with resolving promise</button> <button onclick="buyWithRejectingPromise()" id="buyWithRejectingPromise">Buy with rejecting promise</button> <pre id="result"></pre> -<script src="util.js"></script> -<script src="show_promise.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_show_twice_test.html b/components/test/data/payments/payment_request_show_twice_test.html index 2877bff0..9102834 100644 --- a/components/test/data/payments/payment_request_show_twice_test.html +++ b/components/test/data/payments/payment_request_show_twice_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="show_twice.js"></script> <title>Show Twice Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -14,7 +16,5 @@ <body> <button onclick="buy()" id="buy">Show Twice Test</button> <pre id="result"></pre> -<script src="util.js"></script> -<script src="show_twice.js"></script> </body> </html>
diff --git a/components/test/data/payments/payment_request_update_with_test.html b/components/test/data/payments/payment_request_update_with_test.html index 216090e..c24cdc52 100644 --- a/components/test/data/payments/payment_request_update_with_test.html +++ b/components/test/data/payments/payment_request_update_with_test.html
@@ -6,6 +6,8 @@ --> <html> <head> +<script src="util.js"></script> +<script src="update_with.js"></script> <title>updateWith() Test</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> @@ -21,7 +23,5 @@ <button class="small" onclick="updateWithModifiers('basic-card')" id="updateWithModifiers">updateWithModifiers</button> <button class="small" onclick="updateWithError('basic-card')" id="updateWithError">updateWithError</button> <pre id="result"></pre> -<script src="util.js"></script> -<script src="update_with.js"></script> </body> </html>
diff --git a/components/test/data/payments/show_promise/digital_goods.html b/components/test/data/payments/show_promise/digital_goods.html index 57d5eb4..94a462a 100644 --- a/components/test/data/payments/show_promise/digital_goods.html +++ b/components/test/data/payments/show_promise/digital_goods.html
@@ -6,6 +6,9 @@ --> <html lang="en"> <head> + <script src="../util.js"></script> + <script src="app_installer.js"></script> + <script src="digital_goods.js"></script> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> <title>Show Promise Test For Digital Goods</title> @@ -16,8 +19,5 @@ <div><button onclick="create()" id="create">Create</button></div> <div><button onclick="buy()" id="buy">Buy</button></div> <pre id="result"></pre> - <script src="../util.js"></script> - <script src="app_installer.js"></script> - <script src="digital_goods.js"></script> </body> </html> \ No newline at end of file
diff --git a/components/test/data/payments/show_promise/invalid_details.html b/components/test/data/payments/show_promise/invalid_details.html index c66c17e..902015bd 100644 --- a/components/test/data/payments/show_promise/invalid_details.html +++ b/components/test/data/payments/show_promise/invalid_details.html
@@ -6,6 +6,10 @@ --> <html lang="en"> <head> + <script src="../util.js"></script> + <script src="helper.js"></script> + <script src="app_installer.js"></script> + <script src="invalid_details.js"></script> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> <title>Test for Show Promise with Invalid Details</title> @@ -15,9 +19,5 @@ <body> <div><button onclick="buy()" id="buy">Buy</button></div> <pre id="result"></pre> - <script src="../util.js"></script> - <script src="helper.js"></script> - <script src="app_installer.js"></script> - <script src="invalid_details.js"></script> </body> </html> \ No newline at end of file
diff --git a/components/test/data/payments/show_promise/reject.html b/components/test/data/payments/show_promise/reject.html index 38969fd..6a1a036a 100644 --- a/components/test/data/payments/show_promise/reject.html +++ b/components/test/data/payments/show_promise/reject.html
@@ -6,6 +6,9 @@ --> <html lang="en"> <head> + <script src="../util.js"></script> + <script src="app_installer.js"></script> + <script src="reject.js"></script> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> <title>Test for Rejecting the Show Promise</title> @@ -15,8 +18,5 @@ <body> <div><button onclick="buy()" id="buy">Buy</button></div> <pre id="result"></pre> - <script src="../util.js"></script> - <script src="app_installer.js"></script> - <script src="reject.js"></script> </body> </html> \ No newline at end of file
diff --git a/components/test/data/payments/show_promise/resolve_with_empty_dictionary.html b/components/test/data/payments/show_promise/resolve_with_empty_dictionary.html index fb9e01d..15494168 100644 --- a/components/test/data/payments/show_promise/resolve_with_empty_dictionary.html +++ b/components/test/data/payments/show_promise/resolve_with_empty_dictionary.html
@@ -6,6 +6,10 @@ --> <html lang="en"> <head> + <script src="../util.js"></script> + <script src="helper.js"></script> + <script src="app_installer.js"></script> + <script src="resolve_with_empty_dictionary.js"></script> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> <title>Test For Show Promise That Resolves With Empty Dictionary</title> @@ -17,9 +21,5 @@ <div><button onclick="buyWithCurrentUrlMethod()" id="buyWithCurrentUrlMethod">Buy using the current URL as the method</button></div> <div><button onclick="buyWithUrlMethod()" id="buyWithUrlMethod">Buy with URL method</button></div> <pre id="result"></pre> - <script src="../util.js"></script> - <script src="helper.js"></script> - <script src="app_installer.js"></script> - <script src="resolve_with_empty_dictionary.js"></script> </body> </html> \ No newline at end of file
diff --git a/components/test/data/payments/show_promise/resolve_with_empty_lists.html b/components/test/data/payments/show_promise/resolve_with_empty_lists.html index 11d90102..ee7d80a 100644 --- a/components/test/data/payments/show_promise/resolve_with_empty_lists.html +++ b/components/test/data/payments/show_promise/resolve_with_empty_lists.html
@@ -6,6 +6,10 @@ --> <html lang="en"> <head> + <script src="../util.js"></script> + <script src="helper.js"></script> + <script src="app_installer.js"></script> + <script src="resolve_with_empty_lists.js"></script> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> <title>Test For Resolving The Show Promise With Empty Lists Items</title> @@ -15,9 +19,5 @@ <body> <div><button onclick="buy()" id="buy">Buy</button></div> <pre id="result"></pre> - <script src="../util.js"></script> - <script src="helper.js"></script> - <script src="app_installer.js"></script> - <script src="resolve_with_empty_lists.js"></script> </body> </html> \ No newline at end of file
diff --git a/components/test/data/payments/show_promise/single_option_shipping.html b/components/test/data/payments/show_promise/single_option_shipping.html index a6444d52..dd73ac9 100644 --- a/components/test/data/payments/show_promise/single_option_shipping.html +++ b/components/test/data/payments/show_promise/single_option_shipping.html
@@ -6,6 +6,10 @@ --> <html lang="en"> <head> + <script src="../util.js"></script> + <script src="helper.js"></script> + <script src="app_installer.js"></script> + <script src="single_option_shipping.js"></script> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> <title>Show Promise Test For Single-Option Shipping</title> @@ -15,9 +19,5 @@ <body> <div><button onclick="buy()" id="buy">Buy</button></div> <pre id="result"></pre> - <script src="../util.js"></script> - <script src="helper.js"></script> - <script src="app_installer.js"></script> - <script src="single_option_shipping.js"></script> </body> </html> \ No newline at end of file
diff --git a/components/test/data/payments/show_promise/single_option_shipping_with_update.html b/components/test/data/payments/show_promise/single_option_shipping_with_update.html index d667c6b..4f574d37 100644 --- a/components/test/data/payments/show_promise/single_option_shipping_with_update.html +++ b/components/test/data/payments/show_promise/single_option_shipping_with_update.html
@@ -6,6 +6,10 @@ --> <html lang="en"> <head> + <script src="../util.js"></script> + <script src="helper.js"></script> + <script src="app_installer.js"></script> + <script src="single_option_shipping_with_update.js"></script> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> <title>Show Promise Test For Single-Option Shipping With Update</title> @@ -15,9 +19,5 @@ <body> <div><button onclick="buy()" id="buy">Buy</button></div> <pre id="result"></pre> - <script src="../util.js"></script> - <script src="helper.js"></script> - <script src="app_installer.js"></script> - <script src="single_option_shipping_with_update.js"></script> </body> </html> \ No newline at end of file
diff --git a/components/test/data/payments/show_promise/timeout.html b/components/test/data/payments/show_promise/timeout.html index 258b020..d4f37900 100644 --- a/components/test/data/payments/show_promise/timeout.html +++ b/components/test/data/payments/show_promise/timeout.html
@@ -6,6 +6,9 @@ --> <html lang="en"> <head> + <script src="../util.js"></script> + <script src="app_installer.js"></script> + <script src="timeout.js"></script> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> <title>Test for Timing Out the Show Promise</title> @@ -15,8 +18,5 @@ <body> <div><button onclick="buy()" id="buy">Buy</button></div> <pre id="result"></pre> - <script src="../util.js"></script> - <script src="app_installer.js"></script> - <script src="timeout.js"></script> </body> </html> \ No newline at end of file
diff --git a/components/test/data/payments/show_promise/unsupported.html b/components/test/data/payments/show_promise/unsupported.html index 8fca49a..8d1dfe6 100644 --- a/components/test/data/payments/show_promise/unsupported.html +++ b/components/test/data/payments/show_promise/unsupported.html
@@ -6,6 +6,8 @@ --> <html lang="en"> <head> + <script src="../util.js"></script> + <script src="unsupported.js"></script> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> <title>Test for Show Promise with Unsupported Payment Method Identifier</title> @@ -15,7 +17,5 @@ <body> <div><button onclick="buy()" id="buy">Buy</button></div> <pre id="result"></pre> - <script src="../util.js"></script> - <script src="unsupported.js"></script> </body> </html> \ No newline at end of file
diff --git a/components/test/data/payments/show_promise/us_only_shipping.html b/components/test/data/payments/show_promise/us_only_shipping.html index 2a9154b..ef23fc2 100644 --- a/components/test/data/payments/show_promise/us_only_shipping.html +++ b/components/test/data/payments/show_promise/us_only_shipping.html
@@ -6,6 +6,10 @@ --> <html lang="en"> <head> + <script src="../util.js"></script> + <script src="helper.js"></script> + <script src="app_installer.js"></script> + <script src="us_only_shipping.js"></script> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5"> <title>Show Promise Test For US-Only Shipping</title> @@ -15,9 +19,5 @@ <body> <div><button onclick="buy()" id="buy">Buy</button></div> <pre id="result"></pre> - <script src="../util.js"></script> - <script src="helper.js"></script> - <script src="app_installer.js"></script> - <script src="us_only_shipping.js"></script> </body> </html> \ No newline at end of file
diff --git a/components/ui_devtools/OWNERS b/components/ui_devtools/OWNERS index 1b23f492..3b961a1d 100644 --- a/components/ui_devtools/OWNERS +++ b/components/ui_devtools/OWNERS
@@ -1,3 +1,2 @@ sadrul@chromium.org lgrey@chromium.org -weili@chromium.org
diff --git a/components/ui_devtools/views/OWNERS b/components/ui_devtools/views/OWNERS index 1b23f492..3b961a1d 100644 --- a/components/ui_devtools/views/OWNERS +++ b/components/ui_devtools/views/OWNERS
@@ -1,3 +1,2 @@ sadrul@chromium.org lgrey@chromium.org -weili@chromium.org
diff --git a/components/user_notes/DEPS b/components/user_notes/DEPS index f0bf3d9..81267e5 100644 --- a/components/user_notes/DEPS +++ b/components/user_notes/DEPS
@@ -1,3 +1,4 @@ include_rules = [ "+components/keyed_service/core", + "+ui", ]
diff --git a/components/user_notes/browser/BUILD.gn b/components/user_notes/browser/BUILD.gn index a165dce..e341cab 100644 --- a/components/user_notes/browser/BUILD.gn +++ b/components/user_notes/browser/BUILD.gn
@@ -10,12 +10,13 @@ "user_note_service.h", "user_notes_manager.cc", "user_notes_manager.h", - "user_notes_ui_delegate.h", ] deps = [ "//components/keyed_service/core", "//components/user_notes:features", + "//components/user_notes/interfaces", + "//components/user_notes/model", "//content/public/browser", ] }
diff --git a/components/user_notes/browser/user_note_service.cc b/components/user_notes/browser/user_note_service.cc index 3ffb6ab2..b9e6b62 100644 --- a/components/user_notes/browser/user_note_service.cc +++ b/components/user_notes/browser/user_note_service.cc
@@ -5,6 +5,7 @@ #include "components/user_notes/browser/user_note_service.h" #include "base/notreached.h" +#include "components/user_notes/browser/user_notes_manager.h" #include "components/user_notes/user_notes_features.h" namespace user_notes { @@ -13,6 +14,33 @@ UserNoteService::~UserNoteService() = default; +void UserNoteService::OnNoteInstanceAddedToPage(const std::string& guid, + UserNotesManager* manager) { + DCHECK(IsUserNotesEnabled()); + DCHECK(model_map_.find(guid) != model_map_.end()) + << "A note instance without backing model was added to a page"; + + model_map_.at(guid).second.insert(manager); +} + +void UserNoteService::OnNoteInstanceRemovedFromPage(const std::string& guid, + UserNotesManager* manager) { + DCHECK(IsUserNotesEnabled()); + + auto model = model_map_.find(guid); + DCHECK(model != model_map_.end()) + << "A note model was destroyed before all its instances"; + + auto deleteCount = (*model).second.second.erase(manager); + DCHECK(deleteCount > 0) << "Attempted to remove a ref to a note manager that " + "wasn't in the model map"; + + // If there are no longer any pages displaying this model, destroy it. + if ((*model).second.second.empty()) { + model_map_.erase(guid); + } +} + void UserNoteService::OnNoteFocused(const std::string& guid) { DCHECK(IsUserNotesEnabled()); NOTIMPLEMENTED();
diff --git a/components/user_notes/browser/user_note_service.h b/components/user_notes/browser/user_note_service.h index 006720a..141a673 100644 --- a/components/user_notes/browser/user_note_service.h +++ b/components/user_notes/browser/user_note_service.h
@@ -7,13 +7,24 @@ #include "components/keyed_service/core/keyed_service.h" +#include <memory> #include <string> +#include <unordered_map> +#include <unordered_set> +#include <utility> -#include "components/user_notes/browser/user_notes_ui_delegate.h" +#include "components/user_notes/interfaces/user_notes_ui_delegate.h" +#include "components/user_notes/model/user_note.h" namespace user_notes { -// Keyed service cooridnating the different parts (Renderer, UI layer, storage +class UserNotesManager; + +typedef std::pair<std::unique_ptr<UserNote>, + std::unordered_set<UserNotesManager*>> + ModelMapEntry; + +// Keyed service coordinating the different parts (Renderer, UI layer, storage // layer) of the User Notes feature for the current user profile. class UserNoteService : public KeyedService, public UserNotesUIDelegate { public: @@ -22,11 +33,33 @@ UserNoteService(const UserNoteService&) = delete; UserNoteService& operator=(const UserNoteService&) = delete; + // Called by |UserNotesManager| objects when a |UserNoteInstance| is added to + // the page they're attached to. Updates the model map to add a ref to the + // given |UserNotesManager| for the note with the specified GUID. + void OnNoteInstanceAddedToPage(const std::string& guid, + UserNotesManager* manager); + + // Same as |OnNoteInstanceAddedToPage|, except for when a note is removed from + // a page. Updates the model map to remove the ref to the given + // |UserNotesManager|. If this is the last page where the note was displayed, + // also deletes the model from the model map. + void OnNoteInstanceRemovedFromPage(const std::string& guid, + UserNotesManager* manager); + // UserNotesUIDelegate implementation. void OnNoteFocused(const std::string& guid) override; void OnNoteCreationDone(const std::string& guid, const std::string& note_content) override; void OnNoteCreationCancelled(const std::string& guid) override; + + private: + // Source of truth for the in-memory note models. Any note currently being + // displayed in a tab is stored in this data structure. Each entry also + // contains a set of pointers to all |UserNotesManager| objects holding an + // instance of that note, which is necessary to clean up the models when + // they're no longer in use and to remove notes from affected web pages when + // they're deleted by the user. + std::unordered_map<std::string, ModelMapEntry> model_map_; }; } // namespace user_notes
diff --git a/components/user_notes/interfaces/BUILD.gn b/components/user_notes/interfaces/BUILD.gn new file mode 100644 index 0000000..e22b04e --- /dev/null +++ b/components/user_notes/interfaces/BUILD.gn
@@ -0,0 +1,12 @@ +# Copyright 2022 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +source_set("interfaces") { + sources = [ + "user_notes_ui.h", + "user_notes_ui_delegate.h", + ] + + deps = [ "//ui/gfx/geometry:geometry" ] +}
diff --git a/components/user_notes/interfaces/user_notes_ui.h b/components/user_notes/interfaces/user_notes_ui.h new file mode 100644 index 0000000..e54fa3a --- /dev/null +++ b/components/user_notes/interfaces/user_notes_ui.h
@@ -0,0 +1,45 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_USER_NOTES_INTERFACES_USER_NOTES_UI_H_ +#define COMPONENTS_USER_NOTES_INTERFACES_USER_NOTES_UI_H_ + +#include <string> + +#include "ui/gfx/geometry/rect.h" + +namespace user_notes { + +// Interface that the UI layer of User Notes must implement. Used by the +// business logic in the service to send commands to the UI. +class UserNotesUI { + public: + UserNotesUI() = default; + UserNotesUI(const UserNotesUI&) = delete; + UserNotesUI& operator=(const UserNotesUI&) = delete; + virtual ~UserNotesUI() = default; + + // Called when a note in the UI should be scrolled to / brought to the + // foreground, and focused. + virtual void FocusNote(const std::string& guid) = 0; + + // Called when the note creation UX should be shown in the UI layer. |bounds| + // corresponds to the location in the webpage where the associated highlight + // is, and should be compared with existing notes in the UI to determine where + // the new note should be inserted. + virtual void StartNoteCreation(const std::string& guid, gfx::Rect bounds) = 0; + + // Called when the model has changed and the UI should consequently refresh + // the notes it is displaying. The new model must be polled from the active + // tab's primary page. + virtual void Invalidate() = 0; + + // Called by the UserNoteService when the user triggers one of the feature's + // entry points, indicating the Notes UI should show itself. + virtual void Show() = 0; +}; + +} // namespace user_notes + +#endif // COMPONENTS_USER_NOTES_INTERFACES_USER_NOTES_UI_H_
diff --git a/components/user_notes/browser/user_notes_ui_delegate.h b/components/user_notes/interfaces/user_notes_ui_delegate.h similarity index 83% rename from components/user_notes/browser/user_notes_ui_delegate.h rename to components/user_notes/interfaces/user_notes_ui_delegate.h index 74992248..b5997ef1 100644 --- a/components/user_notes/browser/user_notes_ui_delegate.h +++ b/components/user_notes/interfaces/user_notes_ui_delegate.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_USER_NOTES_BROWSER_USER_NOTES_UI_DELEGATE_H_ -#define COMPONENTS_USER_NOTES_BROWSER_USER_NOTES_UI_DELEGATE_H_ +#ifndef COMPONENTS_USER_NOTES_INTERFACES_USER_NOTES_UI_DELEGATE_H_ +#define COMPONENTS_USER_NOTES_INTERFACES_USER_NOTES_UI_DELEGATE_H_ #include <string> @@ -31,4 +31,4 @@ } // namespace user_notes -#endif // COMPONENTS_USER_NOTES_BROWSER_USER_NOTES_UI_DELEGATE_H_ +#endif // COMPONENTS_USER_NOTES_INTERFACES_USER_NOTES_UI_DELEGATE_H_
diff --git a/components/viz/common/features.cc b/components/viz/common/features.cc index 8bd4b80..a7d468f 100644 --- a/components/viz/common/features.cc +++ b/components/viz/common/features.cc
@@ -146,6 +146,9 @@ const base::Feature kUseSurfaceLayerForVideoDefault{ "UseSurfaceLayerForVideoDefault", base::FEATURE_ENABLED_BY_DEFAULT}; +const base::Feature kWebViewNewInvalidateHeuristic{ + "WebViewNewInvalidateHeuristic", base::FEATURE_DISABLED_BY_DEFAULT}; + // Historically media on android hardcoded SRGB color space because of lack of // color space support in surface control. This controls if we want to use real // color space in DisplayCompositor. @@ -304,6 +307,10 @@ #if BUILDFLAG(IS_ANDROID) bool UseSurfaceLayerForVideo() { + // SurfaceLayer video should work fine with new heuristic. + if (base::FeatureList::IsEnabled(kWebViewNewInvalidateHeuristic)) + return true; + // Allow enabling UseSurfaceLayerForVideo if webview is using surface control. if (::features::IsAndroidSurfaceControlEnabled()) { return true;
diff --git a/components/viz/common/features.h b/components/viz/common/features.h index d31bf02..e2eea69 100644 --- a/components/viz/common/features.h +++ b/components/viz/common/features.h
@@ -48,6 +48,7 @@ VIZ_COMMON_EXPORT extern const base::Feature kUsePlatformDelegatedInk; #if BUILDFLAG(IS_ANDROID) VIZ_COMMON_EXPORT extern const base::Feature kUseSurfaceLayerForVideoDefault; +VIZ_COMMON_EXPORT extern const base::Feature kWebViewNewInvalidateHeuristic; #endif VIZ_COMMON_EXPORT extern const base::Feature kSurfaceSyncThrottling; VIZ_COMMON_EXPORT extern const base::Feature kDynamicSchedulerForDraw;
diff --git a/components/viz/service/BUILD.gn b/components/viz/service/BUILD.gn index 03a9986f..15a66c6 100644 --- a/components/viz/service/BUILD.gn +++ b/components/viz/service/BUILD.gn
@@ -308,6 +308,7 @@ "display/overlay_processor_strategy.h", "display/overlay_processor_using_strategy.cc", "display/overlay_processor_using_strategy.h", + "display/overlay_proposed_candidate.cc", "display/overlay_proposed_candidate.h", "display/overlay_strategy_fullscreen.cc", "display/overlay_strategy_fullscreen.h",
diff --git a/components/viz/service/display/delegated_ink_point_renderer_base.cc b/components/viz/service/display/delegated_ink_point_renderer_base.cc index b33677a..db8f9815 100644 --- a/components/viz/service/display/delegated_ink_point_renderer_base.cc +++ b/components/viz/service/display/delegated_ink_point_renderer_base.cc
@@ -35,6 +35,12 @@ DCHECK_NE(metadata->frame_time(), base::TimeTicks()); metadata_ = std::move(metadata); + TRACE_EVENT_WITH_FLOW1( + "delegated_ink_trails", + "DelegatedInkPointRendererBase::SetDelegatedInkMetadata", + TRACE_ID_GLOBAL(metadata_->trace_id()), TRACE_EVENT_FLAG_FLOW_IN, + "metadata", metadata_->ToString()); + // If we already have a cached pointer ID, check if the same pointer ID // matches the new metadata. if (pointer_id_.has_value() && @@ -101,8 +107,13 @@ // Any remaining points must be the points that should be part of the // delegated ink trail std::vector<gfx::DelegatedInkPoint> points_to_draw; - for (auto it : trail_data.GetPoints()) - points_to_draw.emplace_back(it.second, it.first, pointer_id_.value()); + for (auto it : trail_data.GetPoints()) { + gfx::DelegatedInkPoint point{it.second, it.first, pointer_id_.value()}; + points_to_draw.emplace_back(point); + TRACE_EVENT_WITH_FLOW1("delegated_ink_trails", "Filtering to draw point", + TRACE_ID_GLOBAL(point.trace_id()), + TRACE_EVENT_FLAG_FLOW_IN, "point", point.ToString()); + } DCHECK(points_to_draw.front().MatchesDelegatedInkMetadata(metadata_.get())); @@ -131,9 +142,12 @@ void DelegatedInkPointRendererBase::StoreDelegatedInkPoint( const gfx::DelegatedInkPoint& point) { - TRACE_EVENT_INSTANT1("delegated_ink_trails", - "DelegatedInkPointRendererImpl::StoreDelegatedInkPoint", - TRACE_EVENT_SCOPE_THREAD, "point", point.ToString()); + TRACE_EVENT_WITH_FLOW1( + "delegated_ink_trails", + "DelegatedInkPointRendererImpl::StoreDelegatedInkPoint", + TRACE_ID_GLOBAL(point.trace_id()), + TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "point", + point.ToString()); pointer_ids_[point.pointer_id()].AddPoint(point); }
diff --git a/components/viz/service/display/overlay_processor_using_strategy.cc b/components/viz/service/display/overlay_processor_using_strategy.cc index ffd58a06..01e9115 100644 --- a/components/viz/service/display/overlay_processor_using_strategy.cc +++ b/components/viz/service/display/overlay_processor_using_strategy.cc
@@ -18,6 +18,7 @@ #include "base/timer/elapsed_timer.h" #include "base/trace_event/trace_event.h" #include "build/build_config.h" +#include "components/viz/common/display/overlay_strategy.h" #include "components/viz/common/features.h" #include "components/viz/common/quads/aggregated_render_pass.h" #include "components/viz/common/quads/quad_list.h" @@ -86,12 +87,6 @@ UMA_HISTOGRAM_ENUMERATION("Viz.DisplayCompositor.OverlayStrategy", strategy); } -OverlayProcessorUsingStrategy::ProposedCandidateKey -OverlayProcessorUsingStrategy::ToProposeKey( - const OverlayProposedCandidate& proposed) { - return {proposed.candidate.tracking_id, proposed.strategy->GetUMAEnum()}; -} - OverlayProcessorUsingStrategy::OverlayProcessorUsingStrategy() : max_overlays_config_(features::MaxOverlaysConsidered()) {} @@ -448,7 +443,7 @@ // This loop fills in data for the heuristic sort and thresholds candidates. for (auto it = proposed_candidates->begin(); it != proposed_candidates->end();) { - auto key = ToProposeKey(*it); + auto key = OverlayProposedCandidate::ToProposeKey(*it); // If no tracking exists we create a new one here. auto& track_data = tracked_candidates_[key]; DBG_DRAW_TEXT_OPT( @@ -622,7 +617,7 @@ candidate.strategy->AdjustOutputSurfaceOverlay(primary_plane); LogStrategyEnumUMA(candidate.strategy->GetUMAEnum()); last_successful_strategy_ = candidate.strategy; - OnOverlaySwitchUMA(ToProposeKey(candidate)); + OnOverlaySwitchUMA(OverlayProposedCandidate::ToProposeKey(candidate)); UMA_HISTOGRAM_ENUMERATION("Viz.DisplayCompositor.OverlayQuadMaterial", quad_material); if (candidate.candidate.requires_overlay) { @@ -809,7 +804,7 @@ } void OverlayProcessorUsingStrategy::OnOverlaySwitchUMA( - OverlayProcessorUsingStrategy::ProposedCandidateKey overlay_tracking_id) { + ProposedCandidateKey overlay_tracking_id) { auto curr_tick = base::TimeTicks::Now(); if (!(prev_overlay_tracking_id_ == overlay_tracking_id)) { prev_overlay_tracking_id_ = overlay_tracking_id;
diff --git a/components/viz/service/display/overlay_processor_using_strategy.h b/components/viz/service/display/overlay_processor_using_strategy.h index 9c562bd..7e61b42 100644 --- a/components/viz/service/display/overlay_processor_using_strategy.h +++ b/components/viz/service/display/overlay_processor_using_strategy.h
@@ -13,7 +13,6 @@ #include "base/hash/hash.h" #include "base/memory/raw_ptr.h" #include "build/build_config.h" -#include "components/viz/common/display/overlay_strategy.h" #include "components/viz/common/quads/aggregated_render_pass.h" #include "components/viz/service/display/display_resource_provider.h" #include "components/viz/service/display/output_surface.h" @@ -261,26 +260,6 @@ // reflect the overlays that will be promoted this frame in `candidates`. void UpdateOverlayStatusMap(const OverlayCandidateList& candidates); - struct ProposedCandidateKey { - OverlayCandidate::TrackingId tracking_id = - OverlayCandidate::kDefaultTrackingId; - OverlayStrategy strategy_id = OverlayStrategy::kUnknown; - - bool operator==(const ProposedCandidateKey& other) const { - return (tracking_id == other.tracking_id && - strategy_id == other.strategy_id); - } - }; - - struct ProposedCandidateKeyHasher { - std::size_t operator()(const ProposedCandidateKey& k) const { - return base::Hash(&k, sizeof(k)); - } - }; - - static ProposedCandidateKey ToProposeKey( - const OverlayProposedCandidate& proposed); - std::unordered_map<ProposedCandidateKey, OverlayCandidateTemporalTracker, ProposedCandidateKeyHasher>
diff --git a/components/viz/service/display/overlay_proposed_candidate.cc b/components/viz/service/display/overlay_proposed_candidate.cc new file mode 100644 index 0000000..ff0c018 --- /dev/null +++ b/components/viz/service/display/overlay_proposed_candidate.cc
@@ -0,0 +1,16 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/viz/service/display/overlay_proposed_candidate.h" + +#include "components/viz/service/display/overlay_processor_strategy.h" + +namespace viz { + +ProposedCandidateKey OverlayProposedCandidate::ToProposeKey( + const OverlayProposedCandidate& proposed) { + return {proposed.candidate.tracking_id, proposed.strategy->GetUMAEnum()}; +} + +} // namespace viz
diff --git a/components/viz/service/display/overlay_proposed_candidate.h b/components/viz/service/display/overlay_proposed_candidate.h index d85dae1..7f1ae2c 100644 --- a/components/viz/service/display/overlay_proposed_candidate.h +++ b/components/viz/service/display/overlay_proposed_candidate.h
@@ -5,6 +5,7 @@ #ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_OVERLAY_PROPOSED_CANDIDATE_H_ #define COMPONENTS_VIZ_SERVICE_DISPLAY_OVERLAY_PROPOSED_CANDIDATE_H_ +#include "components/viz/common/display/overlay_strategy.h" #include "components/viz/common/quads/quad_list.h" #include "components/viz/service/display/overlay_candidate.h" #include "components/viz/service/viz_service_export.h" @@ -13,6 +14,23 @@ class OverlayProcessorStrategy; +struct ProposedCandidateKey { + OverlayCandidate::TrackingId tracking_id = + OverlayCandidate::kDefaultTrackingId; + OverlayStrategy strategy_id = OverlayStrategy::kUnknown; + + bool operator==(const ProposedCandidateKey& other) const { + return (tracking_id == other.tracking_id && + strategy_id == other.strategy_id); + } +}; + +struct ProposedCandidateKeyHasher { + std::size_t operator()(const ProposedCandidateKey& k) const { + return base::Hash(&k, sizeof(k)); + } +}; + // Represents a candidate that could promote a specific `DrawQuad` to an overlay // using a specific `OverlayProcessorStrategy`. class VIZ_SERVICE_EXPORT OverlayProposedCandidate { @@ -24,6 +42,9 @@ candidate(overlay_candidate), strategy(overlay_strategy) {} + static ProposedCandidateKey ToProposeKey( + const OverlayProposedCandidate& proposed); + // An iterator in the QuadList. QuadList::Iterator quad_iter; OverlayCandidate candidate;
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl.cc b/components/viz/service/display_embedder/skia_output_surface_impl.cc index f4ddac2..145392a 100644 --- a/components/viz/service/display_embedder/skia_output_surface_impl.cc +++ b/components/viz/service/display_embedder/skia_output_surface_impl.cc
@@ -942,8 +942,16 @@ DCHECK(!is_overlay); const auto format_index = static_cast<int>(format); const auto& color_type = capabilities_.sk_color_types[format_index]; - const auto backend_format = gr_context_thread_safe_->defaultBackendFormat( + auto backend_format = gr_context_thread_safe_->defaultBackendFormat( color_type, GrRenderable::kYes); +#if BUILDFLAG(IS_MAC) + DCHECK_EQ(dependency_->gr_context_type(), gpu::GrContextType::kGL); + // For root rander pass, IOSurface will be used, and we may need using + // GL_TEXTURE_RECTANGLE_ARB as texture target. + backend_format = + GrBackendFormat::MakeGL(backend_format.asGLFormatEnum(), + gpu::GetPlatformSpecificTextureTarget()); +#endif DCHECK(color_type != kUnknown_SkColorType) << "SkColorType is invalid for buffer format_index: " << format_index; DCHECK(backend_format.isValid())
diff --git a/components/viz/test/test_gpu_service_holder.cc b/components/viz/test/test_gpu_service_holder.cc index 7aaf497..6460c2b 100644 --- a/components/viz/test/test_gpu_service_holder.cc +++ b/components/viz/test/test_gpu_service_holder.cc
@@ -26,6 +26,7 @@ #include "gpu/config/gpu_util.h" #include "gpu/ipc/service/gpu_watchdog_thread.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/gl/gl_bindings.h" #include "ui/gl/init/gl_factory.h" #if BUILDFLAG(ENABLE_VULKAN) @@ -269,6 +270,20 @@ gpu_feature_info.status_values[gpu::GPU_FEATURE_TYPE_GPU_RASTERIZATION] = gpu::kGpuFeatureStatusEnabled; + // On MacOS, the default texture target for native GpuMemoryBuffers is + // GL_TEXTURE_RECTANGLE_ARB. This is due to CGL's requirements for creating + // a GL surface. However, when ANGLE is used on top of SwiftShader or Metal, + // it's necessary to use GL_TEXTURE_2D instead. + // TODO(crbug.com/1056312): The proper behavior is to check the config + // parameter set by the EGL_ANGLE_iosurface_client_buffer extension +#if BUILDFLAG(IS_MAC) + if (gl::GetGLImplementation() == gl::kGLImplementationEGLANGLE && + (gl::GetANGLEImplementation() == gl::ANGLEImplementation::kSwiftShader || + gl::GetANGLEImplementation() == gl::ANGLEImplementation::kMetal)) { + gpu::SetMacOSSpecificTextureTarget(GL_TEXTURE_2D); + } +#endif // BUILDFLAG(IS_MAC) + // TODO(rivr): Investigate why creating a GPUInfo and GpuFeatureInfo from // the command line causes the test SkiaOutputSurfaceImplTest.SubmitPaint to // fail on Android.
diff --git a/content/browser/attribution_reporting/attribution_filter_data.cc b/content/browser/attribution_reporting/attribution_filter_data.cc index f8a6487..9f56112 100644 --- a/content/browser/attribution_reporting/attribution_filter_data.cc +++ b/content/browser/attribution_reporting/attribution_filter_data.cc
@@ -77,6 +77,15 @@ } // static +AttributionFilterData AttributionFilterData::ForSourceType( + AttributionSourceType source_type) { + return AttributionFilterData({{ + kFilterSourceType, + std::vector<std::string>{AttributionSourceTypeToString(source_type)}, + }}); +} + +// static absl::optional<AttributionFilterData> AttributionFilterData::FromFilterValues( FilterValues&& filter_values, size_t extra_filters_allowed) {
diff --git a/content/browser/attribution_reporting/attribution_filter_data.h b/content/browser/attribution_reporting/attribution_filter_data.h index 8f97265..9eba0c4d 100644 --- a/content/browser/attribution_reporting/attribution_filter_data.h +++ b/content/browser/attribution_reporting/attribution_filter_data.h
@@ -39,6 +39,9 @@ static absl::optional<AttributionFilterData> FromTriggerFilterValues( FilterValues&&); + // Returns filter data that matches only the given source type. + static AttributionFilterData ForSourceType(AttributionSourceType); + // Creates without validation. static AttributionFilterData CreateForTesting(FilterValues);
diff --git a/content/browser/attribution_reporting/attribution_internals.mojom b/content/browser/attribution_reporting/attribution_internals.mojom index 588398a..140cd7dc 100644 --- a/content/browser/attribution_reporting/attribution_internals.mojom +++ b/content/browser/attribution_reporting/attribution_internals.mojom
@@ -43,9 +43,6 @@ kProhibitedByBrowserPolicy, kSent, kNetworkError, - // TODO(apaseltiner): Remove this value once event-trigger matching is - // implemented. - kNoMatchingEventTriggers, kNoMatchingSourceFilterData, };
diff --git a/content/browser/attribution_reporting/attribution_internals_handler_impl.cc b/content/browser/attribution_reporting/attribution_internals_handler_impl.cc index 175a934..77930a4 100644 --- a/content/browser/attribution_reporting/attribution_internals_handler_impl.cc +++ b/content/browser/attribution_reporting/attribution_internals_handler_impl.cc
@@ -324,9 +324,6 @@ status = mojom::WebUIAttributionReport::Status:: kNoReportCapacityForDestinationSite; break; - case AttributionTrigger::EventLevelResult::kNoMatchingEventTriggers: - status = mojom::WebUIAttributionReport::Status::kNoMatchingEventTriggers; - break; case AttributionTrigger::EventLevelResult::kNoMatchingSourceFilterData: status = mojom::WebUIAttributionReport::Status::kNoMatchingSourceFilterData;
diff --git a/content/browser/attribution_reporting/attribution_storage_sql.cc b/content/browser/attribution_reporting/attribution_storage_sql.cc index cfcaa1d1..44e64c5 100644 --- a/content/browser/attribution_reporting/attribution_storage_sql.cc +++ b/content/browser/attribution_reporting/attribution_storage_sql.cc
@@ -903,10 +903,17 @@ uint64_t trigger_data = 0; int64_t priority = 0; - auto event_trigger = - base::ranges::find(trigger.event_triggers(), source_type, - &AttributionTrigger::EventTriggerData::source_type); + auto event_trigger = base::ranges::find_if( + trigger.event_triggers(), + [&](const AttributionTrigger::EventTriggerData& event_trigger) { + return AttributionFiltersMatch(source.common_info().filter_data(), + event_trigger.filters, + event_trigger.not_filters); + }); + // If there's a match, use its data. Otherwise use default values instead of + // returning an error so that a report is still sent. + // TODO(apaseltiner): Consider recording a metric for no match. if (event_trigger != trigger.event_triggers().end()) { // TODO(apaseltiner): Consider informing the manager if the trigger // data was out of range for DevTools issue reporting. @@ -945,14 +952,6 @@ if (!top_level_filters_match) return AttributionTrigger::EventLevelResult::kNoMatchingSourceFilterData; - // Note that this cannot currently occur outside of tests, because all - // triggers have two event triggers, one for each source type, one of which - // must match. In the future, when we have general filtering based on strings, - // this code path will be reachable and we return without performing - // attribution. - if (event_trigger == trigger.event_triggers().end()) - return AttributionTrigger::EventLevelResult::kNoMatchingEventTriggers; - switch (ReportAlreadyStored(report->attribution_info().source.source_id(), dedup_key)) { case ReportAlreadyStoredStatus::kNotStored:
diff --git a/content/browser/attribution_reporting/attribution_storage_unittest.cc b/content/browser/attribution_reporting/attribution_storage_unittest.cc index e48e85e..82d8a57 100644 --- a/content/browser/attribution_reporting/attribution_storage_unittest.cc +++ b/content/browser/attribution_reporting/attribution_storage_unittest.cc
@@ -35,6 +35,7 @@ #include "content/browser/attribution_reporting/attribution_storage_sql.h" #include "content/browser/attribution_reporting/attribution_test_utils.h" #include "content/browser/attribution_reporting/attribution_trigger.h" +#include "content/browser/attribution_reporting/attribution_utils.h" #include "content/browser/attribution_reporting/common_source_info.h" #include "content/browser/attribution_reporting/storable_source.h" #include "content/browser/attribution_reporting/stored_source.h" @@ -94,9 +95,13 @@ const AttributionTrigger& conversion) { // TOO(apaseltiner): Replace this logic with explicit setting of expected // values. - auto event_trigger = base::ranges::find( - conversion.event_triggers(), source.common_info().source_type(), - &AttributionTrigger::EventTriggerData::source_type); + auto event_trigger = base::ranges::find_if( + conversion.event_triggers(), + [&](const AttributionTrigger::EventTriggerData& event_trigger) { + return AttributionFiltersMatch(source.common_info().filter_data(), + event_trigger.filters, + event_trigger.not_filters); + }); CHECK(event_trigger != conversion.event_triggers().end()); return ReportBuilder(AttributionInfoBuilder(source) @@ -2139,7 +2144,7 @@ })))); } -TEST_F(AttributionStorageTest, NoMatchingTriggers) { +TEST_F(AttributionStorageTest, NoMatchingTriggerData_UsesDefaultData) { const auto origin = url::Origin::Create(GURL("https://r.test")); storage()->StoreSource(SourceBuilder() @@ -2148,27 +2153,108 @@ .SetReportingOrigin(origin) .Build()); - EXPECT_EQ( - AttributionTrigger::EventLevelResult::kNoMatchingEventTriggers, - MaybeCreateAndStoreEventLevelReport(AttributionTrigger( - net::SchemefulSite(origin), origin, - /*filters=*/AttributionFilterData(), - /*debug_key=*/absl::nullopt, - {AttributionTrigger::EventTriggerData( - /*data=*/0, - /*priority=*/0, - /*dedup_key=*/absl::nullopt, AttributionSourceType::kEvent)}))); + EXPECT_EQ(AttributionTrigger::EventLevelResult::kSuccess, + MaybeCreateAndStoreEventLevelReport(AttributionTrigger( + net::SchemefulSite(origin), origin, + /*filters=*/AttributionFilterData(), + /*debug_key=*/absl::nullopt, + {AttributionTrigger::EventTriggerData( + /*data=*/11, + /*priority=*/12, + /*dedup_key=*/13, + /*filters=*/ + AttributionFilterData::ForSourceType( + AttributionSourceType::kEvent), + /*not_filters=*/AttributionFilterData())}))); + + EXPECT_THAT(storage()->GetAttributionReports(base::Time::Max()), + ElementsAre(EventLevelDataIs( + AllOf(TriggerDataIs(0), TriggerPriorityIs(0))))); + + EXPECT_THAT(storage()->GetActiveSources(), + ElementsAre(DedupKeysAre(IsEmpty()))); +} + +TEST_F(AttributionStorageTest, MatchingTriggerData_UsesCorrectData) { + const auto origin = url::Origin::Create(GURL("https://r.test")); + + storage()->StoreSource( + SourceBuilder() + .SetSourceType(AttributionSourceType::kNavigation) + .SetConversionOrigin(origin) + .SetReportingOrigin(origin) + .SetFilterData(*AttributionFilterData::FromSourceFilterValues( + {{"abc", {"123"}}})) + .Build()); + + const std::vector<AttributionTrigger::EventTriggerData> event_triggers = { + // Filters don't match. + AttributionTrigger::EventTriggerData( + /*data=*/11, + /*priority=*/12, + /*dedup_key=*/13, + /*filters=*/ + *AttributionFilterData::FromTriggerFilterValues({ + {"abc", {"456"}}, + }), + /*not_filters=*/AttributionFilterData()), + + // Filters match, but negated filters do not. + AttributionTrigger::EventTriggerData( + /*data=*/21, + /*priority=*/22, + /*dedup_key=*/23, + /*filters=*/ + *AttributionFilterData::FromTriggerFilterValues({ + {"abc", {"123"}}, + }), + /*not_filters=*/ + *AttributionFilterData::FromTriggerFilterValues({ + {"source_type", {"navigation"}}, + })), + + // Filters and negated filters match. + AttributionTrigger::EventTriggerData( + /*data=*/31, + /*priority=*/32, + /*dedup_key=*/33, + /*filters=*/ + *AttributionFilterData::FromTriggerFilterValues({ + {"abc", {"123"}}, + }), + /*not_filters=*/ + *AttributionFilterData::FromTriggerFilterValues({ + {"source_type", {"event"}}, + })), + + // Filters and negated filters match, but not the first event + // trigger to match. + AttributionTrigger::EventTriggerData( + /*data=*/41, + /*priority=*/42, + /*dedup_key=*/43, + /*filters=*/ + *AttributionFilterData::FromTriggerFilterValues({ + {"abc", {"123"}}, + }), + /*not_filters=*/ + *AttributionFilterData::FromTriggerFilterValues({ + {"source_type", {"event"}}, + })), + }; EXPECT_EQ(AttributionTrigger::EventLevelResult::kSuccess, - MaybeCreateAndStoreEventLevelReport( - AttributionTrigger(net::SchemefulSite(origin), origin, - /*filters=*/AttributionFilterData(), - /*debug_key=*/absl::nullopt, - {AttributionTrigger::EventTriggerData( - /*data=*/0, - /*priority=*/0, - /*dedup_key=*/absl::nullopt, - AttributionSourceType::kNavigation)}))); + MaybeCreateAndStoreEventLevelReport(AttributionTrigger( + net::SchemefulSite(origin), origin, + /*filters=*/AttributionFilterData(), + /*debug_key=*/absl::nullopt, event_triggers))); + + EXPECT_THAT(storage()->GetAttributionReports(base::Time::Max()), + ElementsAre(EventLevelDataIs( + AllOf(TriggerDataIs(31), TriggerPriorityIs(32))))); + + EXPECT_THAT(storage()->GetActiveSources(), + ElementsAre(DedupKeysAre(ElementsAre(33)))); } TEST_F(AttributionStorageTest, TopLevelTriggerFiltering) { @@ -2182,26 +2268,21 @@ {{"abc", {"123"}}})) .Build()); - const std::vector<AttributionTrigger::EventTriggerData> event_triggers = { - AttributionTrigger::EventTriggerData( - /*data=*/0, - /*priority=*/0, - /*dedup_key=*/absl::nullopt, AttributionSourceType::kNavigation), - }; - AttributionTrigger trigger1(net::SchemefulSite(origin), origin, /*filters=*/ *AttributionFilterData::FromTriggerFilterValues({ {"abc", {"456"}}, }), - /*debug_key=*/absl::nullopt, event_triggers); + /*debug_key=*/absl::nullopt, + /*event_triggers=*/{}); AttributionTrigger trigger2(net::SchemefulSite(origin), origin, /*filters=*/ *AttributionFilterData::FromTriggerFilterValues({ {"abc", {"123"}}, }), - /*debug_key=*/absl::nullopt, event_triggers); + /*debug_key=*/absl::nullopt, + /*event_triggers=*/{}); EXPECT_EQ(AttributionTrigger::EventLevelResult::kNoMatchingSourceFilterData, MaybeCreateAndStoreEventLevelReport(trigger1));
diff --git a/content/browser/attribution_reporting/attribution_test_utils.cc b/content/browser/attribution_reporting/attribution_test_utils.cc index 84ce729e..abc765d 100644 --- a/content/browser/attribution_reporting/attribution_test_utils.cc +++ b/content/browser/attribution_reporting/attribution_test_utils.cc
@@ -686,7 +686,8 @@ bool operator==(const AttributionTrigger::EventTriggerData& a, const AttributionTrigger::EventTriggerData& b) { const auto tie = [](const AttributionTrigger::EventTriggerData& t) { - return std::make_tuple(t.data, t.priority, t.dedup_key, t.source_type); + return std::make_tuple(t.data, t.priority, t.dedup_key, t.filters, + t.not_filters); }; return tie(a) == tie(b); } @@ -845,9 +846,6 @@ case AttributionTrigger::EventLevelResult::kExcessiveReportingOrigins: out << "excessiveReportingOrigins"; break; - case AttributionTrigger::EventLevelResult::kNoMatchingEventTriggers: - out << "noMatchingEventTriggers"; - break; case AttributionTrigger::EventLevelResult::kNoMatchingSourceFilterData: out << "noMatchingSourceFilterData"; break; @@ -907,7 +905,8 @@ << (event_trigger.dedup_key ? base::NumberToString(*event_trigger.dedup_key) : "null") - << ",source_type=" << event_trigger.source_type << "}"; + << ",filters=" << event_trigger.filters + << ",not_filters=" << event_trigger.not_filters << "}"; } std::ostream& operator<<(std::ostream& out,
diff --git a/content/browser/attribution_reporting/attribution_trigger.cc b/content/browser/attribution_reporting/attribution_trigger.cc index be37764..afdf927 100644 --- a/content/browser/attribution_reporting/attribution_trigger.cc +++ b/content/browser/attribution_reporting/attribution_trigger.cc
@@ -7,6 +7,7 @@ #include <utility> #include "base/check.h" +#include "content/browser/attribution_reporting/attribution_source_type.h" namespace content { @@ -14,11 +15,13 @@ uint64_t data, int64_t priority, absl::optional<uint64_t> dedup_key, - AttributionSourceType source_type) + AttributionFilterData filters, + AttributionFilterData not_filters) : data(data), priority(priority), dedup_key(dedup_key), - source_type(source_type) {} + filters(std::move(filters)), + not_filters(std::move(not_filters)) {} AttributionTrigger::AttributionTrigger( net::SchemefulSite conversion_destination, @@ -52,11 +55,17 @@ {EventTriggerData(trigger_data, priority, dedup_key, - AttributionSourceType::kNavigation), + /*filters=*/ + AttributionFilterData::ForSourceType( + AttributionSourceType::kNavigation), + /*not_filters=*/AttributionFilterData()), EventTriggerData(event_source_trigger_data, priority, dedup_key, - AttributionSourceType::kEvent)})) {} + /*filters=*/ + AttributionFilterData::ForSourceType( + AttributionSourceType::kEvent), + /*not_filters=*/AttributionFilterData())})) {} AttributionTrigger::AttributionTrigger(const AttributionTrigger& other) = default;
diff --git a/content/browser/attribution_reporting/attribution_trigger.h b/content/browser/attribution_reporting/attribution_trigger.h index fb00de0..83e86ca 100644 --- a/content/browser/attribution_reporting/attribution_trigger.h +++ b/content/browser/attribution_reporting/attribution_trigger.h
@@ -10,7 +10,6 @@ #include <vector> #include "content/browser/attribution_reporting/attribution_filter_data.h" -#include "content/browser/attribution_reporting/attribution_source_type.h" #include "content/common/content_export.h" #include "net/base/schemeful_site.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -40,10 +39,7 @@ kPriorityTooLow = 7, kDroppedForNoise = 8, kExcessiveReportingOrigins = 9, - // TODO(apaseltiner): Remove this value once event-trigger matching is - // implemented. - kNoMatchingEventTriggers = 10, - kNoMatchingSourceFilterData = 11, + kNoMatchingSourceFilterData = 10, kMaxValue = kNoMatchingSourceFilterData, }; @@ -63,14 +59,19 @@ // performed. absl::optional<uint64_t> dedup_key; - // The source type that this trigger data will match. - // TODO(apaseltiner): Replace this with the generalized filtering mechanism. - AttributionSourceType source_type; + // The filters used to determine whether this `EventTriggerData'`s fields + // are used. + AttributionFilterData filters; + + // The negated filters used to determine whether this `EventTriggerData'`s + // fields are used. + AttributionFilterData not_filters; EventTriggerData(uint64_t data, int64_t priority, absl::optional<uint64_t> dedup_key, - AttributionSourceType source_type); + AttributionFilterData filters, + AttributionFilterData not_filters); }; // Should only be created with values that the browser process has already
diff --git a/content/browser/fenced_frame/fenced_frame.cc b/content/browser/fenced_frame/fenced_frame.cc index 7cca77b..cbf337b 100644 --- a/content/browser/fenced_frame/fenced_frame.cc +++ b/content/browser/fenced_frame/fenced_frame.cc
@@ -189,10 +189,7 @@ void FencedFrame::NotifyNavigationStateChanged(InvalidateTypes changed_flags) {} -void FencedFrame::NotifyBeforeFormRepostWarningShow() { - // TODO(https://crbug.com/1263557): Should we call - // web_contents_->NotifyBeforeFormRepostWarningShow()? -} +void FencedFrame::NotifyBeforeFormRepostWarningShow() {} void FencedFrame::NotifyNavigationEntryCommitted( const LoadCommittedDetails& load_details) {} @@ -206,8 +203,8 @@ void FencedFrame::NotifyNavigationEntriesDeleted() {} void FencedFrame::ActivateAndShowRepostFormWarningDialog() { - // TODO(https://crbug.com/1263557): The continuation callback would goto the - // wrong NavigationController so perhaps we need to pass a callback in? + // Not supported, cancel pending reload. + frame_tree_->controller().CancelPendingReload(); } bool FencedFrame::ShouldPreserveAbortedURLs() {
diff --git a/content/browser/fenced_frame/fenced_frame_url_mapping.cc b/content/browser/fenced_frame/fenced_frame_url_mapping.cc index 45be7e3..c9e76582 100644 --- a/content/browser/fenced_frame/fenced_frame_url_mapping.cc +++ b/content/browser/fenced_frame/fenced_frame_url_mapping.cc
@@ -4,6 +4,7 @@ #include "content/browser/fenced_frame/fenced_frame_url_mapping.h" +#include <cstring> #include <map> #include <string> @@ -28,7 +29,6 @@ } // namespace const char kURNUUIDprefix[] = "urn:uuid:"; -const int kURNUUIDDashLocations[4] = {17, 22, 27, 32}; bool FencedFrameURLMapping::IsValidUrnUuidURL(const GURL& url) { if (!url.is_valid()) @@ -36,10 +36,9 @@ std::string spec = url.spec(); return base::StartsWith(spec, kURNUUIDprefix, base::CompareCase::INSENSITIVE_ASCII) && - spec.at(kURNUUIDDashLocations[0]) == '-' && - spec.at(kURNUUIDDashLocations[1]) == '-' && - spec.at(kURNUUIDDashLocations[2]) == '-' && - spec.at(kURNUUIDDashLocations[3]) == '-'; + base::GUID::ParseCaseInsensitive( + base::StringPiece(spec).substr(std::strlen(kURNUUIDprefix))) + .is_valid(); } FencedFrameURLMapping::PendingAdComponentsMap::PendingAdComponentsMap(
diff --git a/content/browser/indexed_db/indexed_db_leveldb_operations.cc b/content/browser/indexed_db/indexed_db_leveldb_operations.cc index 6c6494c..ba4139f0 100644 --- a/content/browser/indexed_db/indexed_db_leveldb_operations.cc +++ b/content/browser/indexed_db/indexed_db_leveldb_operations.cc
@@ -54,10 +54,18 @@ // static base::FilePath GetBlobStoreFileName(const blink::StorageKey& storage_key) { - // TODO(crbug.com/1199077): This will be replaced when the new storage is - // implemented. - std::string storage_key_id = - storage::GetIdentifierFromOrigin(storage_key.origin()); + std::string storage_key_id; + if (storage_key.IsFirstPartyContext()) { + storage_key_id = storage::GetIdentifierFromOrigin(storage_key.origin()); + } else { + // TODO(crbug.com/1218100): This is a stop-gap to prevent crashes, we need + // to point to a real storage bucket here not a transient one. We only + // hit this case when `kThirdPartyStoragePartitioning` is enabled. + storage_key_id = storage::GetIdentifierFromOrigin(url::Origin()); + } + // TODO(crbug.com/1218100): Desired first and third party paths: + // {{storage_partition}}/IndexedDB/{{serialized_origin}}.blob/ + // {{storage_partition}}/WebStorage/{{bucket_id}}/IndexedDB/indexeddb.blob/ return base::FilePath() .AppendASCII(storage_key_id) .AddExtension(kIndexedDBExtension) @@ -66,10 +74,18 @@ // static base::FilePath GetLevelDBFileName(const blink::StorageKey& storage_key) { - // TODO(crbug.com/1199077): This will be replaced when the new storage is - // implemented. - std::string storage_key_id = - storage::GetIdentifierFromOrigin(storage_key.origin()); + std::string storage_key_id; + if (storage_key.IsFirstPartyContext()) { + storage_key_id = storage::GetIdentifierFromOrigin(storage_key.origin()); + } else { + // TODO(crbug.com/1218100): This is a stop-gap to prevent crashes, we need + // to point to a real storage bucket here not a transient one. We only + // hit this case when `kThirdPartyStoragePartitioning` is enabled. + storage_key_id = storage::GetIdentifierFromOrigin(url::Origin()); + } + // TODO(crbug.com/1218100): Desired first and third party paths: + // {{storage_partition}}/IndexedDB/{{serialized_origin}}.leveldb/ + // {{storage_partition}}/WebStorage/{{bucket_id}}/IndexedDB/indexeddb.leveldb/ return base::FilePath() .AppendASCII(storage_key_id) .AddExtension(kIndexedDBExtension)
diff --git a/content/browser/prerender/prerender_host.cc b/content/browser/prerender/prerender_host.cc index df42bb44..929a7c1 100644 --- a/content/browser/prerender/prerender_host.cc +++ b/content/browser/prerender/prerender_host.cc
@@ -155,7 +155,10 @@ void NotifyNavigationListPruned( const PrunedDetails& pruned_details) override {} void NotifyNavigationEntriesDeleted() override {} - void ActivateAndShowRepostFormWarningDialog() override {} + void ActivateAndShowRepostFormWarningDialog() override { + // Not supported, cancel pending reload. + GetNavigationController().CancelPendingReload(); + } bool ShouldPreserveAbortedURLs() override { return false; } WebContents* DeprecatedGetWebContents() override { return GetWebContents(); } void UpdateOverridingUserAgent() override {}
diff --git a/content/browser/renderer_host/browsing_context_state.cc b/content/browser/renderer_host/browsing_context_state.cc index 2eb45a78..420baee 100644 --- a/content/browser/renderer_host/browsing_context_state.cc +++ b/content/browser/renderer_host/browsing_context_state.cc
@@ -5,6 +5,7 @@ #include "content/browser/renderer_host/browsing_context_state.h" #include "content/browser/renderer_host/frame_tree_node.h" +#include "content/browser/renderer_host/render_frame_host_impl.h" #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/common/content_navigation_policy.h" #include "services/network/public/cpp/web_sandbox_flags.h" @@ -41,12 +42,82 @@ RenderFrameProxyHost* BrowsingContextState::GetRenderFrameProxyHost( SiteInstanceGroup* site_instance_group) const { + if (features::GetBrowsingContextMode() == + features::BrowsingContextStateImplementationType:: + kSwapForCrossBrowsingInstanceNavigations) { + // CHECK to verify that the proxy is being accessed from the correct + // BrowsingContextState. As both BrowsingContextState (in non-legacy mode) + // and RenderFrameProxyHost (via SiteInstance) are tied to a given + // BrowsingInstance, the browsing instance id of the BrowsingContextState + // (in the non-legacy mode) and of the SiteInstanceGroup should match. + // If they do not, the code calling this method has likely chosen the + // wrong BrowsingContextGroup (e.g. one from the current RenderFrameHost + // rather than from speculative or vice versa) – as this can lead to + // various unpredictable bugs in proxy management logic, we want to + // crash the browser here when this condition fails. + // + // Note that the outer delegate and opener proxies are an exception and the + // only cases of a proxy associated with a SiteInstanceGroup from another + // BrowsingInstance. Meanwhile, for openers the opener and openee have to be + // in the same BrowsingInstance as well. + // TODO(crbug.com/1270671): Add exception here for outer delegate proxies. + CHECK_EQ(browsing_instance_id_.value(), + site_instance_group->browsing_instance_id()); + } auto it = proxy_hosts_.find(site_instance_group->GetId()); if (it != proxy_hosts_.end()) return it->second.get(); return nullptr; } +void BrowsingContextState::DeleteRenderFrameProxyHost( + SiteInstanceGroup* site_instance_group) { + if (features::GetBrowsingContextMode() == + features::BrowsingContextStateImplementationType:: + kSwapForCrossBrowsingInstanceNavigations) { + // See comments in GetRenderFrameProxyHost for why this check is needed. + CHECK_EQ(browsing_instance_id_.value(), + site_instance_group->browsing_instance_id()); + } + site_instance_group->RemoveObserver(this); + proxy_hosts_.erase(site_instance_group->GetId()); +} + +RenderFrameProxyHost* BrowsingContextState::CreateRenderFrameProxyHost( + SiteInstance* site_instance, + const scoped_refptr<RenderViewHostImpl>& rvh, + FrameTreeNode* frame_tree_node) { + if (features::GetBrowsingContextMode() == + features::BrowsingContextStateImplementationType:: + kLegacyOneToOneWithFrameTreeNode) { + DCHECK_EQ(this, + frame_tree_node->current_frame_host()->browsing_context_state()); + } + + if (features::GetBrowsingContextMode() == + features::BrowsingContextStateImplementationType:: + kSwapForCrossBrowsingInstanceNavigations) { + // See comments in GetRenderFrameProxyHost for why this check is needed. + CHECK_EQ(browsing_instance_id_.value(), + site_instance->GetBrowsingInstanceId()); + } + + auto site_instance_group_id = + static_cast<SiteInstanceImpl*>(site_instance)->group()->GetId(); + CHECK(proxy_hosts_.find(site_instance_group_id) == proxy_hosts_.end()) + << "A proxy already existed for this SiteInstanceGroup."; + RenderFrameProxyHost* proxy_host = + new RenderFrameProxyHost(site_instance, std::move(rvh), frame_tree_node); + proxy_hosts_[site_instance_group_id] = base::WrapUnique(proxy_host); + static_cast<SiteInstanceImpl*>(site_instance)->group()->AddObserver(this); + + TRACE_EVENT_INSTANT( + "navigation", "BrowsingContextState::CreateRenderFrameProxyHost", + perfetto::protos::pbzero::ChromeTrackEvent::kRenderFrameProxyHost, + *proxy_host); + return proxy_host; +} + size_t BrowsingContextState::GetProxyCount() { return proxy_hosts_.size(); } @@ -222,12 +293,6 @@ ->SetRenderFrameProxyCreated(false); } -void BrowsingContextState::DeleteRenderFrameProxyHost( - SiteInstanceGroup* site_instance_group) { - site_instance_group->RemoveObserver(this); - proxy_hosts_.erase(site_instance_group->GetId()); -} - void BrowsingContextState::SendFramePolicyUpdatesToProxies( SiteInstance* parent_site_instance, const blink::FramePolicy& frame_policy) { @@ -241,45 +306,14 @@ } } -RenderFrameProxyHost* BrowsingContextState::CreateRenderFrameProxyHost( - SiteInstance* site_instance, - const scoped_refptr<RenderViewHostImpl>& rvh, - FrameTreeNode* frame_tree_node) { - if (features::GetBrowsingContextMode() == - features::BrowsingContextStateImplementationType:: - kLegacyOneToOneWithFrameTreeNode) { - DCHECK_EQ(this, - frame_tree_node->current_frame_host()->browsing_context_state()); - } +void BrowsingContextState::OnDidStartLoading() { + for (const auto& pair : proxy_hosts_) + pair.second->GetAssociatedRemoteFrame()->DidStartLoading(); +} - if (features::GetBrowsingContextMode() == - features::BrowsingContextStateImplementationType:: - kSwapForCrossBrowsingInstanceNavigations) { - // CHECK to verify that the proxy is being created in the correct - // BrowsingContextState. BrowsingContextState in non-legacy mode is tied to - // the BrowsingInstance, as well as proxies (via SiteInstance) and the right - // BrowsingContextState is needed to be selected to be able to access the - // proxies. As there will be many BrowsingContextState objects, there is - // greater likelihood of the incorrect BrowsingContextState being selected. - // TODO(crbug.com/1270671): Add exception here for outer delegate proxies. - CHECK(browsing_instance_id_.value() == - site_instance->GetBrowsingInstanceId()); - } - - auto site_instance_group_id = - static_cast<SiteInstanceImpl*>(site_instance)->group()->GetId(); - CHECK(proxy_hosts_.find(site_instance_group_id) == proxy_hosts_.end()) - << "A proxy already existed for this SiteInstanceGroup."; - RenderFrameProxyHost* proxy_host = - new RenderFrameProxyHost(site_instance, std::move(rvh), frame_tree_node); - proxy_hosts_[site_instance_group_id] = base::WrapUnique(proxy_host); - static_cast<SiteInstanceImpl*>(site_instance)->group()->AddObserver(this); - - TRACE_EVENT_INSTANT( - "navigation", "BrowsingContextState::CreateRenderFrameProxyHost", - perfetto::protos::pbzero::ChromeTrackEvent::kRenderFrameProxyHost, - *proxy_host); - return proxy_host; +void BrowsingContextState::OnDidStopLoading() { + for (const auto& pair : proxy_hosts_) + pair.second->GetAssociatedRemoteFrame()->DidStopLoading(); } void BrowsingContextState::ResetProxyHosts() { @@ -289,4 +323,46 @@ proxy_hosts_.clear(); } +void BrowsingContextState::UpdateOpener(SiteInstance* source_site_instance) { + for (const auto& pair : proxy_hosts_) { + if (pair.second->GetSiteInstance() == source_site_instance) + continue; + pair.second->UpdateOpener(); + } +} + +void BrowsingContextState::OnDidUpdateFrameOwnerProperties( + const blink::mojom::FrameOwnerProperties& properties) { + // Notify this frame's proxies if they live in a different process from its + // parent. This is only currently needed for the allowFullscreen property, + // since that can be queried on RemoteFrame ancestors. + // + // TODO(alexmos): It would be sufficient to only send this update to proxies + // in the current FrameTree. + for (const auto& pair : proxy_hosts_) { + if (pair.second->site_instance_group() != + parent_->GetSiteInstance()->group()) { + auto properties_for_remote_frame = properties.Clone(); + RenderFrameProxyHost* proxy = pair.second.get(); + proxy->GetAssociatedRemoteFrame()->SetFrameOwnerProperties( + std::move(properties_for_remote_frame)); + } + } +} + +void BrowsingContextState::ExecuteRemoteFramesBroadcastMethod( + base::RepeatingCallback<void(RenderFrameProxyHost*)> callback, + SiteInstance* instance_to_skip, + RenderFrameProxyHost* outer_delegate_proxy) { + for (const auto& pair : proxy_hosts_) { + if (outer_delegate_proxy == pair.second.get()) + continue; + if (pair.second->GetSiteInstance() == instance_to_skip) + continue; + if (!pair.second->is_render_frame_proxy_live()) + continue; + callback.Run(pair.second.get()); + } +} + } // namespace content \ No newline at end of file
diff --git a/content/browser/renderer_host/browsing_context_state.h b/content/browser/renderer_host/browsing_context_state.h index ca51e754..41220a2 100644 --- a/content/browser/renderer_host/browsing_context_state.h +++ b/content/browser/renderer_host/browsing_context_state.h
@@ -208,6 +208,22 @@ // of WebContentsImpl. void ResetProxyHosts(); + // Notification methods to tell this RenderFrameHostManager that the frame it + // is responsible for has started or stopped loading a document. + void OnDidStartLoading(); + void OnDidStopLoading(); + + // Notify proxies that an opener has been updated. + void UpdateOpener(SiteInstance* source_site_instance); + + void OnDidUpdateFrameOwnerProperties( + const blink::mojom::FrameOwnerProperties& properties); + + void ExecuteRemoteFramesBroadcastMethod( + base::RepeatingCallback<void(RenderFrameProxyHost*)> callback, + SiteInstance* instance_to_skip, + RenderFrameProxyHost* outer_delegate_proxy); + protected: friend class base::RefCounted<BrowsingContextState>;
diff --git a/content/browser/renderer_host/frame_tree_node.cc b/content/browser/renderer_host/frame_tree_node.cc index 6b8be41b..52b24fe 100644 --- a/content/browser/renderer_host/frame_tree_node.cc +++ b/content/browser/renderer_host/frame_tree_node.cc
@@ -543,8 +543,8 @@ if (frame_tree() == frame_tree()->LoadingTree()) DidChangeLoadProgress(blink::kInitialLoadProgress); - // Notify the RenderFrameHostManager of the event. - render_manager()->OnDidStartLoading(); + // Notify the proxies of the event. + current_frame_host()->browsing_context_state()->OnDidStartLoading(); base::UmaHistogramTimes( base::StrCat({"Navigation.DidStartLoading.", IsMainFrame() ? "MainFrame" : "Subframe"}), @@ -563,8 +563,8 @@ if (frame_tree() == frame_tree()->LoadingTree()) DidChangeLoadProgress(blink::kFinalLoadProgress); - // Notify the RenderFrameHostManager of the event. - render_manager()->OnDidStopLoading(); + // Notify the proxies of the event. + current_frame_host()->browsing_context_state()->OnDidStopLoading(); FrameTree* loading_tree = frame_tree()->LoadingTree(); // When loading tree is null, ignore invoking DidStopLoadingNode as the frame
diff --git a/content/browser/renderer_host/render_frame_host_manager.cc b/content/browser/renderer_host/render_frame_host_manager.cc index 1a53ff8..c9cc7f15 100644 --- a/content/browser/renderer_host/render_frame_host_manager.cc +++ b/content/browser/renderer_host/render_frame_host_manager.cc
@@ -602,12 +602,8 @@ frame_tree_node_->SetOpener(opener); - for (const auto& pair : - render_frame_host_->browsing_context_state()->proxy_hosts()) { - if (pair.second->GetSiteInstance() == source_site_instance) - continue; - pair.second->UpdateOpener(); - } + render_frame_host_->browsing_context_state()->UpdateOpener( + source_site_instance); if (render_frame_host_->GetSiteInstance() != source_site_instance) render_frame_host_->UpdateOpener(); @@ -1369,18 +1365,6 @@ speculative_render_frame_host_.reset(); } -void RenderFrameHostManager::OnDidStartLoading() { - for (const auto& pair : - render_frame_host_->browsing_context_state()->proxy_hosts()) - pair.second->GetAssociatedRemoteFrame()->DidStartLoading(); -} - -void RenderFrameHostManager::OnDidStopLoading() { - for (const auto& pair : - render_frame_host_->browsing_context_state()->proxy_hosts()) - pair.second->GetAssociatedRemoteFrame()->DidStopLoading(); -} - void RenderFrameHostManager::OnDidChangeCollapsedState(bool collapsed) { // If we are a MPArch fenced frame root then ask the outer delegate node // to collapse the frame. Note `IsFencedFrameRoot` returns true for @@ -1425,21 +1409,8 @@ std::move(properties_for_local_frame)); } - // Notify this frame's proxies if they live in a different process from its - // parent. This is only currently needed for the allowFullscreen property, - // since that can be queried on RemoteFrame ancestors. - // - // TODO(alexmos): It would be sufficient to only send this update to proxies - // in the current FrameTree. - for (const auto& pair : - render_frame_host_->browsing_context_state()->proxy_hosts()) { - if (pair.second->site_instance_group() != parent_instance->group()) { - auto properties_for_remote_frame = properties.Clone(); - RenderFrameProxyHost* proxy = pair.second.get(); - proxy->GetAssociatedRemoteFrame()->SetFrameOwnerProperties( - std::move(properties_for_remote_frame)); - } - } + render_frame_host_->browsing_context_state()->OnDidUpdateFrameOwnerProperties( + properties); } RenderFrameHostManager::SiteInstanceDescriptor::SiteInstanceDescriptor( @@ -3897,16 +3868,9 @@ // frame as well. RenderFrameProxyHost* outer_delegate_proxy = IsMainFrameForInnerDelegate() ? GetProxyToOuterDelegate() : nullptr; - for (const auto& pair : - render_frame_host_->browsing_context_state()->proxy_hosts()) { - if (outer_delegate_proxy == pair.second.get()) - continue; - if (pair.second->GetSiteInstance() == instance_to_skip) - continue; - if (!pair.second->is_render_frame_proxy_live()) - continue; - callback.Run(pair.second.get()); - } + render_frame_host_->browsing_context_state() + ->ExecuteRemoteFramesBroadcastMethod(callback, instance_to_skip, + outer_delegate_proxy); } void RenderFrameHostManager::EnsureRenderFrameHostVisibilityConsistent() {
diff --git a/content/browser/renderer_host/render_frame_host_manager.h b/content/browser/renderer_host/render_frame_host_manager.h index 0f38225..226b02c2 100644 --- a/content/browser/renderer_host/render_frame_host_manager.h +++ b/content/browser/renderer_host/render_frame_host_manager.h
@@ -383,11 +383,6 @@ // caller must ensure that the RenderFrame has been or will be cleaned up. void DiscardSpeculativeRenderFrameHostForShutdown(); - // Notification methods to tell this RenderFrameHostManager that the frame it - // is responsible for has started or stopped loading a document. - void OnDidStartLoading(); - void OnDidStopLoading(); - // Called when the client changes whether the frame's owner element in the // embedder document should be collapsed, that is, remove from the layout as // if it did not exist. Never called for main frames. Only has an effect for
diff --git a/content/browser/renderer_host/render_frame_proxy_host.cc b/content/browser/renderer_host/render_frame_proxy_host.cc index 659ec1a..a2b57f3 100644 --- a/content/browser/renderer_host/render_frame_proxy_host.cc +++ b/content/browser/renderer_host/render_frame_proxy_host.cc
@@ -43,6 +43,7 @@ #include "services/metrics/public/cpp/ukm_recorder.h" #include "services/network/public/cpp/web_sandbox_flags.h" #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h" +#include "third_party/blink/public/common/storage_key/storage_key.h" #include "third_party/blink/public/mojom/frame/frame_owner_properties.mojom.h" #include "third_party/blink/public/mojom/messaging/transferable_message.mojom.h" #include "third_party/blink/public/mojom/scroll/scroll_into_view_params.mojom.h" @@ -540,6 +541,7 @@ // equivalent RenderFrameProxyHost in the target process. absl::optional<blink::RemoteFrameToken> translated_source_token; ukm::SourceId source_page_ukm_source_id = ukm::kInvalidSourceId; + blink::StorageKey source_storage_key; if (source_frame_token) { RenderFrameHostImpl* source_rfh = RenderFrameHostImpl::FromFrameToken( GetProcess()->GetID(), source_frame_token.value()); @@ -580,13 +582,15 @@ } source_page_ukm_source_id = source_rfh->GetPageUkmSourceId(); + source_storage_key = source_rfh->storage_key(); } } // Record UKM metrics for the postMessage event. - post_message_counter_.RecordMessage(source_page_ukm_source_id, - target_rfh->GetPageUkmSourceId(), - ukm::UkmRecorder::Get()); + post_message_counter_.RecordMessage( + source_page_ukm_source_id, source_storage_key, + target_rfh->GetPageUkmSourceId(), target_rfh->storage_key(), + ukm::UkmRecorder::Get()); target_rfh->PostMessageEvent(translated_source_token, source_origin, target_origin, std::move(message));
diff --git a/content/browser/renderer_host/render_widget_host_input_event_router.cc b/content/browser/renderer_host/render_widget_host_input_event_router.cc index 372543b..6e6955a7 100644 --- a/content/browser/renderer_host/render_widget_host_input_event_router.cc +++ b/content/browser/renderer_host/render_widget_host_input_event_router.cc
@@ -2056,10 +2056,11 @@ gfx::DelegatedInkPoint delegated_ink_point( position, input_event.TimeStamp(), pointer_properties.id); - TRACE_EVENT_INSTANT1("delegated_ink_trails", - "Forwarding delegated ink point from browser.", - TRACE_EVENT_SCOPE_THREAD, "delegated point", - delegated_ink_point.ToString()); + TRACE_EVENT_WITH_FLOW1("delegated_ink_trails", + "Forwarding delegated ink point from browser.", + TRACE_ID_GLOBAL(delegated_ink_point.trace_id()), + TRACE_EVENT_FLAG_FLOW_OUT, "delegated point", + delegated_ink_point.ToString()); // Calling this will result in IPC calls to get |delegated_ink_point| to // viz. The decision to do this here was made with the understanding that
diff --git a/content/browser/resources/attribution_reporting/attribution_internals.js b/content/browser/resources/attribution_reporting/attribution_internals.js index 2b479890..9b445f1c 100644 --- a/content/browser/resources/attribution_reporting/attribution_internals.js +++ b/content/browser/resources/attribution_reporting/attribution_internals.js
@@ -552,9 +552,6 @@ case WebUIAttributionReport_Status.kNetworkError: this.status = 'Network error'; break; - case WebUIAttributionReport_Status.kNoMatchingEventTriggers: - this.status = 'Dropped due to no matching event triggers'; - break; case WebUIAttributionReport_Status.kNoMatchingSourceFilterData: this.status = 'Dropped due to no matching source filter data'; break;
diff --git a/content/browser/site_instance_group.cc b/content/browser/site_instance_group.cc index 57ab9a6c..cc91909 100644 --- a/content/browser/site_instance_group.cc +++ b/content/browser/site_instance_group.cc
@@ -12,8 +12,10 @@ SiteInstanceGroupId::Generator site_instance_group_id_generator; } // namespace -SiteInstanceGroup::SiteInstanceGroup(RenderProcessHost* process) - : id_(site_instance_group_id_generator.GenerateNextId()) { +SiteInstanceGroup::SiteInstanceGroup(BrowsingInstanceId browsing_instance_id, + RenderProcessHost* process) + : id_(site_instance_group_id_generator.GenerateNextId()), + browsing_instance_id_(browsing_instance_id) { SetProcessAndAgentSchedulingGroup(process); }
diff --git a/content/browser/site_instance_group.h b/content/browser/site_instance_group.h index ee9d06a..a07e729 100644 --- a/content/browser/site_instance_group.h +++ b/content/browser/site_instance_group.h
@@ -11,6 +11,7 @@ #include "base/types/id_type.h" #include "content/browser/renderer_host/agent_scheduling_group_host.h" #include "content/common/content_export.h" +#include "content/public/browser/browsing_instance_id.h" #include "content/public/browser/render_process_host_observer.h" #include "third_party/perfetto/include/perfetto/tracing/traced_proto.h" @@ -75,7 +76,8 @@ virtual void RenderProcessHostDestroyed() {} }; - explicit SiteInstanceGroup(RenderProcessHost* process); + SiteInstanceGroup(BrowsingInstanceId browsing_instance_id, + RenderProcessHost* process); SiteInstanceGroup(const SiteInstanceGroup&) = delete; SiteInstanceGroup& operator=(const SiteInstanceGroup&) = delete; @@ -108,6 +110,10 @@ RenderProcessHost* process() const { return process_; } bool has_process() const { return process_ != nullptr; } + BrowsingInstanceId browsing_instance_id() const { + return browsing_instance_id_; + } + AgentSchedulingGroupHost& agent_scheduling_group() { DCHECK(agent_scheduling_group_); DCHECK_EQ(agent_scheduling_group_->GetProcess(), process_); @@ -135,6 +141,9 @@ // A unique ID for this SiteInstanceGroup. SiteInstanceGroupId id_; + // ID of the BrowsingInstance this SiteInstanceGroup belongs to. + const BrowsingInstanceId browsing_instance_id_; + // The number of active frames in this SiteInstanceGroup. size_t active_frame_count_ = 0;
diff --git a/content/browser/site_instance_group_manager.cc b/content/browser/site_instance_group_manager.cc index c2055fb..cb646162 100644 --- a/content/browser/site_instance_group_manager.cc +++ b/content/browser/site_instance_group_manager.cc
@@ -45,7 +45,8 @@ // own SiteInstanceGroup, and we can always create a new group for each new // SiteInstance here. When grouping policies are introduced, this function may // return an existing SiteInstanceGroup for a new SiteInstance. - return base::WrapRefCounted(new SiteInstanceGroup(process)); + return base::WrapRefCounted( + new SiteInstanceGroup(site_instance->GetBrowsingInstanceId(), process)); } void SiteInstanceGroupManager::OnSiteInfoSet(SiteInstanceImpl* site_instance,
diff --git a/content/browser/webid/federated_auth_request_impl.cc b/content/browser/webid/federated_auth_request_impl.cc index 4a001a9..6caa946a 100644 --- a/content/browser/webid/federated_auth_request_impl.cc +++ b/content/browser/webid/federated_auth_request_impl.cc
@@ -254,6 +254,17 @@ start_time_ = base::TimeTicks::Now(); delay_timer_.Reset(); + // TODO(npm): FedCM is currently restricted to contexts where third party + // cookies are not blocked. Once the privacy improvements for the API are + // implemented, remove this restriction. See https://crbug.com/1304396. + if (GetApiPermissionContext() && + GetApiPermissionContext()->AreThirdPartyCookiesBlocked()) { + // TODO(npm): this should probably record to a metric value, and issue a + // distinct console error message. + CompleteRequest(FederatedAuthRequestResult::kError, "", + /*should_call_callback=*/false); + return; + } network_manager_ = CreateNetworkManager(provider); if (!network_manager_) { RecordRequestIdTokenStatus(IdTokenStatus::kNoNetworkManager, @@ -469,18 +480,25 @@ endpoints_.accounts = ResolveManifestUrl(endpoints.accounts); endpoints_.client_metadata = ResolveManifestUrl(endpoints.client_metadata); - if (endpoints_.token.is_empty() || endpoints_.accounts.is_empty() || - endpoints_.client_metadata.is_empty()) { - RecordRequestIdTokenStatus(IdTokenStatus::kManifestInvalidResponse, - render_frame_host_->GetPageUkmSourceId()); - CompleteRequest( - FederatedAuthRequestResult::kErrorFetchingManifestInvalidResponse, "", - /*should_call_callback=*/false); - return; - } - if (!IsEndpointUrlValid(endpoints_.token) || - !IsEndpointUrlValid(endpoints_.accounts) || - !IsEndpointUrlValid(endpoints_.client_metadata)) { + bool is_token_valid = IsEndpointUrlValid(endpoints_.token); + bool is_accounts_valid = IsEndpointUrlValid(endpoints_.accounts); + bool is_client_metadata_valid = + IsEndpointUrlValid(endpoints_.client_metadata); + if (!is_token_valid || !is_accounts_valid || !is_client_metadata_valid) { + std::string message = + "Manifest is missing or has an invalid URL for the following " + "endpoints:\n"; + if (!is_token_valid) { + message += "\"id_token_endpoint\"\n"; + } + if (!is_accounts_valid) { + message += "\"accounts_endpoint\"\n"; + } + if (!is_client_metadata_valid) { + message += "\"client_metadata_endpoint\"\n"; + } + render_frame_host_->AddMessageToConsole( + blink::mojom::ConsoleMessageLevel::kError, message); RecordRequestIdTokenStatus(IdTokenStatus::kManifestInvalidResponse, render_frame_host_->GetPageUkmSourceId()); CompleteRequest( @@ -534,6 +552,10 @@ GURL revocation_url = ResolveManifestUrl(endpoints.revocation); if (!IsEndpointUrlValid(revocation_url)) { + render_frame_host_->AddMessageToConsole( + blink::mojom::ConsoleMessageLevel::kError, + "Manifest is missing or has an invalid URL for the following required " + "endpoint: revocation_endpoint"); RecordRevokeStatus(RevokeStatusForMetrics::kRevokeUrlIsCrossOrigin, render_frame_host_->GetPageUkmSourceId()); CompleteRevokeRequest(RevokeStatus::kError, @@ -975,8 +997,9 @@ AddConsoleErrorMessage(result); } - bool should_run_callback = should_call_callback || - network_manager_->IsMockIdpNetworkRequestManager(); + bool should_run_callback = + should_call_callback || + (network_manager_ && network_manager_->IsMockIdpNetworkRequestManager()); CleanUp(); if (should_run_callback) { @@ -1071,6 +1094,11 @@ sharing_permission_delegate_ = sharing_permission_delegate; } +void FederatedAuthRequestImpl::SetApiPermissionDelegateForTests( + FederatedIdentityApiPermissionContextDelegate* api_permission_delegate) { + api_permission_delegate_ = api_permission_delegate; +} + FederatedIdentityActiveSessionPermissionContextDelegate* FederatedAuthRequestImpl::GetActiveSessionPermissionContext() { if (!active_session_permission_delegate_) {
diff --git a/content/browser/webid/federated_auth_request_impl.h b/content/browser/webid/federated_auth_request_impl.h index 2dc06e60..9c50543 100644 --- a/content/browser/webid/federated_auth_request_impl.h +++ b/content/browser/webid/federated_auth_request_impl.h
@@ -68,6 +68,8 @@ FederatedIdentityRequestPermissionContextDelegate*); void SetSharingPermissionDelegateForTests( FederatedIdentitySharingPermissionContextDelegate*); + void SetApiPermissionDelegateForTests( + FederatedIdentityApiPermissionContextDelegate*); // Rejects the pending request if it has not been resolved naturally yet. void OnRejectRequest();
diff --git a/content/browser/webid/federated_auth_request_impl_unittest.cc b/content/browser/webid/federated_auth_request_impl_unittest.cc index 9f59b13..186b301 100644 --- a/content/browser/webid/federated_auth_request_impl_unittest.cc +++ b/content/browser/webid/federated_auth_request_impl_unittest.cc
@@ -19,6 +19,7 @@ #include "content/browser/webid/fedcm_metrics.h" #include "content/browser/webid/federated_auth_request_service.h" #include "content/browser/webid/test/mock_active_session_permission_delegate.h" +#include "content/browser/webid/test/mock_api_permission_delegate.h" #include "content/browser/webid/test/mock_identity_request_dialog_controller.h" #include "content/browser/webid/test/mock_idp_network_request_manager.h" #include "content/browser/webid/test/mock_request_permission_delegate.h" @@ -164,22 +165,39 @@ static const MockClientIdConfiguration kClientMetadataNoPrivacyPolicyUrl{ FetchStatus::kSuccess, "", ""}; -static const AuthRequestTestCase kMediatedTestCases[]{ - {"Error parsing FedCM manifest for Mediated mode missing token endpoint", - {kIdpTestOrigin, kClientId, kNonce}, - {RequestIdTokenStatus::kError, - FederatedAuthRequestResult::kErrorFetchingManifestInvalidResponse, - kEmptyToken}, - {kToken, FetchStatus::kInvalidResponseError, absl::nullopt, - kAccountsEndpoint, "", kClientMetadataEndpoint, kMediatedNoop}}, +static const AuthRequestTestCase kMissingTokenEndpoint{ + "Error parsing FedCM manifest for Mediated mode missing token endpoint", + {kIdpTestOrigin, kClientId, kNonce}, + {RequestIdTokenStatus::kError, + FederatedAuthRequestResult::kErrorFetchingManifestInvalidResponse, + kEmptyToken}, + {kToken, FetchStatus::kSuccess, absl::nullopt, kAccountsEndpoint, "", + kClientMetadataEndpoint, kMediatedNoop}}; - {"Error parsing FedCM manifest for Mediated mode missing accounts endpoint", - {kIdpTestOrigin, kClientId, kNonce}, - {RequestIdTokenStatus::kError, - FederatedAuthRequestResult::kErrorFetchingManifestInvalidResponse, - kEmptyToken}, - {kToken, FetchStatus::kSuccess, absl::nullopt, "", kTokenEndpoint, - kClientMetadataEndpoint, kMediatedNoop}}, +static const AuthRequestTestCase kMissingAccountsEndpoint{ + "Error parsing FedCM manifest for Mediated mode missing accounts endpoint", + {kIdpTestOrigin, kClientId, kNonce}, + {RequestIdTokenStatus::kError, + FederatedAuthRequestResult::kErrorFetchingManifestInvalidResponse, + kEmptyToken}, + {kToken, FetchStatus::kSuccess, absl::nullopt, "", kTokenEndpoint, + kClientMetadataEndpoint, kMediatedNoop}}; + +static const AuthRequestTestCase kMissingClientMetadata{ + "Error parsing FedCM manifest for Mediated mode missing client metadata " + "endpoint", + {kIdpTestOrigin, kClientId, kNonce}, + {RequestIdTokenStatus::kError, + FederatedAuthRequestResult::kErrorFetchingManifestInvalidResponse, + kEmptyToken}, + {kToken, FetchStatus::kSuccess, absl::nullopt, kAccountsEndpoint, + kTokenEndpoint, "", kMediatedNoop}}; + +static const AuthRequestTestCase kMediatedTestCases[]{ + kMissingTokenEndpoint, + kMissingAccountsEndpoint, + kMissingClientMetadata, + {"Error due to accounts endpoint in different origin than identity " "provider", {kIdpTestOrigin, kClientId, kNonce}, @@ -427,6 +445,12 @@ mock_active_session_permission_delegate_ = std::make_unique<NiceMock<MockActiveSessionPermissionDelegate>>(); + mock_sharing_permission_delegate_ = + std::make_unique<NiceMock<MockSharingPermissionDelegate>>(); + + auth_request_service_->GetImplForTesting() + ->SetSharingPermissionDelegateForTests( + mock_sharing_permission_delegate_.get()); return *auth_request_service_->GetImplForTesting(); } @@ -682,6 +706,8 @@ mock_request_permission_delegate_; std::unique_ptr<NiceMock<MockActiveSessionPermissionDelegate>> mock_active_session_permission_delegate_; + std::unique_ptr<NiceMock<MockSharingPermissionDelegate>> + mock_sharing_permission_delegate_; base::OnceClosure close_idp_window_callback_; @@ -774,11 +800,94 @@ if (!expected_message) { EXPECT_EQ(0u, messages.size()); } else { - ASSERT_EQ(1u, messages.size()); - EXPECT_EQ(expected_message.value(), messages[0]); + ASSERT_LE(1u, messages.size()); + EXPECT_EQ(expected_message.value(), messages[messages.size() - 1]); } } +TEST_F(BasicFederatedAuthRequestImplTest, MissingTokenEndpoint) { + const auto& test_case = kMissingTokenEndpoint; + CreateAuthRequest(GURL(test_case.inputs.provider)); + SetMockExpectations(test_case); + auto auth_response = + PerformAuthRequest(test_case.inputs.client_id, test_case.inputs.nonce, + test_case.inputs.prefer_auto_sign_in); + std::vector<std::string> messages = + RenderFrameHostTester::For(main_rfh())->GetConsoleMessages(); + ASSERT_EQ(2U, messages.size()); + EXPECT_EQ( + "Manifest is missing or has an invalid URL for the following " + "endpoints:\n" + "\"id_token_endpoint\"\n", + messages[0]); + EXPECT_EQ("Provider's FedCM manifest configuration is invalid.", messages[1]); +} + +TEST_F(BasicFederatedAuthRequestImplTest, MissingAccountsEndpoint) { + const auto& test_case = kMissingAccountsEndpoint; + CreateAuthRequest(GURL(test_case.inputs.provider)); + SetMockExpectations(test_case); + auto auth_response = + PerformAuthRequest(test_case.inputs.client_id, test_case.inputs.nonce, + test_case.inputs.prefer_auto_sign_in); + std::vector<std::string> messages = + RenderFrameHostTester::For(main_rfh())->GetConsoleMessages(); + ASSERT_EQ(2U, messages.size()); + EXPECT_EQ( + "Manifest is missing or has an invalid URL for the following " + "endpoints:\n" + "\"accounts_endpoint\"\n", + messages[0]); + EXPECT_EQ("Provider's FedCM manifest configuration is invalid.", messages[1]); +} + +TEST_F(BasicFederatedAuthRequestImplTest, MissingClientMetadataEndpoint) { + const auto& test_case = kMissingClientMetadata; + CreateAuthRequest(GURL(test_case.inputs.provider)); + SetMockExpectations(test_case); + auto auth_response = + PerformAuthRequest(test_case.inputs.client_id, test_case.inputs.nonce, + test_case.inputs.prefer_auto_sign_in); + std::vector<std::string> messages = + RenderFrameHostTester::For(main_rfh())->GetConsoleMessages(); + ASSERT_EQ(2U, messages.size()); + EXPECT_EQ( + "Manifest is missing or has an invalid URL for the following " + "endpoints:\n" + "\"client_metadata_endpoint\"\n", + messages[0]); + EXPECT_EQ("Provider's FedCM manifest configuration is invalid.", messages[1]); +} + +TEST_F(BasicFederatedAuthRequestImplTest, AllInvalidEndpoints) { + // Both an empty url and cross origin urls are invalid endpoints. + AuthRequestTestCase test_case = { + "FedCM manifest missing all endpoints", + {kIdpTestOrigin, kClientId, kNonce}, + {RequestIdTokenStatus::kError, + FederatedAuthRequestResult::kErrorFetchingManifestInvalidResponse, + kEmptyToken}, + {kToken, FetchStatus::kSuccess, absl::nullopt, + "https://cross-origin-1.com", "", "https://cross-origin-2.com", + kMediatedNoop}}; + CreateAuthRequest(GURL(test_case.inputs.provider)); + SetMockExpectations(test_case); + auto auth_response = + PerformAuthRequest(test_case.inputs.client_id, test_case.inputs.nonce, + test_case.inputs.prefer_auto_sign_in); + std::vector<std::string> messages = + RenderFrameHostTester::For(main_rfh())->GetConsoleMessages(); + ASSERT_EQ(2U, messages.size()); + EXPECT_EQ( + "Manifest is missing or has an invalid URL for the following " + "endpoints:\n" + "\"id_token_endpoint\"\n" + "\"accounts_endpoint\"\n" + "\"client_metadata_endpoint\"\n", + messages[0]); + EXPECT_EQ("Provider's FedCM manifest configuration is invalid.", messages[1]); +} + // Test Logout method success with multiple relying parties. TEST_F(BasicFederatedAuthRequestImplTest, LogoutSuccessMultiple) { CreateAuthRequest(GURL(kIdpTestOrigin)); @@ -879,19 +988,15 @@ TEST_F(BasicFederatedAuthRequestImplTest, LoginStateShouldBeSignInForReturningUser) { const auto& test_case = kSuccessfulMediatedSignUpTestCase; - auto& auth_request = CreateAuthRequest(GURL(test_case.inputs.provider)); + CreateAuthRequest(GURL(test_case.inputs.provider)); SetMockExpectations(test_case); - // Set specific expectations for sharing permission: - NiceMock<MockSharingPermissionDelegate> mock_sharing_permission_delegate; - auth_request.SetSharingPermissionDelegateForTests( - &mock_sharing_permission_delegate); // Pretend the sharing permission has been granted for this account. // // TODO(majidvp): Ideally we would use the kRpTestOrigin for second argument // but web contents has not navigated to that URL so origin() is null in // tests. We should fix this. - EXPECT_CALL(mock_sharing_permission_delegate, + EXPECT_CALL(*mock_sharing_permission_delegate_, HasSharingPermissionForAccount( url::Origin::Create(GURL(kIdpTestOrigin)), _, "1234")) .WillOnce(Return(true)); @@ -905,20 +1010,16 @@ TEST_F(BasicFederatedAuthRequestImplTest, LoginStateSuccessfulSignUpGrantsSharingPermission) { const auto& test_case = kSuccessfulMediatedSignUpTestCase; - auto& auth_request = CreateAuthRequest(GURL(test_case.inputs.provider)); + CreateAuthRequest(GURL(test_case.inputs.provider)); SetMockExpectations(test_case); - // Set specific expectations for sharing permission. - NiceMock<MockSharingPermissionDelegate> mock_sharing_permission_delegate; - auth_request.SetSharingPermissionDelegateForTests( - &mock_sharing_permission_delegate); - EXPECT_CALL(mock_sharing_permission_delegate, + EXPECT_CALL(*mock_sharing_permission_delegate_, HasSharingPermissionForAccount(_, _, _)) .WillOnce(Return(false)); // TODO(majidvp): Ideally we would use the kRpTestOrigin for second argument // but web contents has not navigated to that URL so origin() is null in // tests. We should fix this. - EXPECT_CALL(mock_sharing_permission_delegate, + EXPECT_CALL(*mock_sharing_permission_delegate_, GrantSharingPermissionForAccount( url::Origin::Create(GURL(kIdpTestOrigin)), _, "1234")) .Times(1); @@ -931,17 +1032,13 @@ TEST_F(BasicFederatedAuthRequestImplTest, LoginStateFailedSignUpNotGrantSharingPermission) { const auto& test_case = kFailedMediatedSignUpTestCase; - auto& auth_request = CreateAuthRequest(GURL(test_case.inputs.provider)); + CreateAuthRequest(GURL(test_case.inputs.provider)); SetMockExpectations(test_case); - // Set specific expectations for sharing permission. - NiceMock<MockSharingPermissionDelegate> mock_sharing_permission_delegate; - auth_request.SetSharingPermissionDelegateForTests( - &mock_sharing_permission_delegate); - EXPECT_CALL(mock_sharing_permission_delegate, + EXPECT_CALL(*mock_sharing_permission_delegate_, HasSharingPermissionForAccount(_, _, _)) .WillOnce(Return(false)); - EXPECT_CALL(mock_sharing_permission_delegate, + EXPECT_CALL(*mock_sharing_permission_delegate_, GrantSharingPermissionForAccount(_, _, _)) .Times(0); @@ -958,19 +1055,15 @@ AccountList displayed_accounts; const auto& test_case = kSuccessfulMediatedAutoSignInTestCase; - auto& auth_request = CreateAuthRequest(GURL(test_case.inputs.provider)); + CreateAuthRequest(GURL(test_case.inputs.provider)); SetMockExpectations(test_case); - // Set specific expectations for sharing permission: - NiceMock<MockSharingPermissionDelegate> mock_sharing_permission_delegate; - auth_request.SetSharingPermissionDelegateForTests( - &mock_sharing_permission_delegate); // Pretend the sharing permission has been granted for this account. // // TODO(majidvp): Ideally we would use the kRpTestOrigin for second argument // but web contents has not navigated to that URL so origin() is null in // tests. We should fix this. - EXPECT_CALL(mock_sharing_permission_delegate, + EXPECT_CALL(*mock_sharing_permission_delegate_, HasSharingPermissionForAccount( url::Origin::Create(GURL(kIdpTestOrigin)), _, "1234")) .WillOnce(Return(true)); @@ -1043,19 +1136,15 @@ AccountList displayed_accounts; const auto& test_case = kSuccessfulMediatedAutoSignInTestCase; - auto& auth_request = CreateAuthRequest(GURL(test_case.inputs.provider)); + CreateAuthRequest(GURL(test_case.inputs.provider)); SetMockExpectations(test_case); - // Set specific expectations for sharing permission: - NiceMock<MockSharingPermissionDelegate> mock_sharing_permission_delegate; - auth_request.SetSharingPermissionDelegateForTests( - &mock_sharing_permission_delegate); // Pretend the sharing permission has been granted for this account. // // TODO(majidvp): Ideally we would use the kRpTestOrigin for second argument // but web contents has not navigated to that URL so origin() is null in // tests. We should fix this. - EXPECT_CALL(mock_sharing_permission_delegate, + EXPECT_CALL(*mock_sharing_permission_delegate_, HasSharingPermissionForAccount( url::Origin::Create(GURL(kIdpTestOrigin)), _, "1234")) .WillOnce(Return(true)); @@ -1167,12 +1256,8 @@ TEST_F(BasicFederatedAuthRequestImplTest, MetricsForSuccessfulSignUpCase) { const auto& test_case = kSuccessfulMediatedSignUpTestCase; - auto& auth_request = CreateAuthRequest(GURL(test_case.inputs.provider)); + CreateAuthRequest(GURL(test_case.inputs.provider)); SetMockExpectations(test_case); - // Sets specific expectations for sharing permission. - NiceMock<MockSharingPermissionDelegate> mock_sharing_permission_delegate; - auth_request.SetSharingPermissionDelegateForTests( - &mock_sharing_permission_delegate); EXPECT_EQ(test_case.config.Mediated_conf.accounts.size(), 1u); @@ -1211,15 +1296,11 @@ TEST_F(BasicFederatedAuthRequestImplTest, MetricsForSuccessfulSignInCase) { const auto& test_case = kSuccessfulMediatedSignUpTestCase; - auto& auth_request = CreateAuthRequest(GURL(test_case.inputs.provider)); + CreateAuthRequest(GURL(test_case.inputs.provider)); SetMockExpectations(test_case); - // Sets specific expectations for sharing permission. - NiceMock<MockSharingPermissionDelegate> mock_sharing_permission_delegate; - auth_request.SetSharingPermissionDelegateForTests( - &mock_sharing_permission_delegate); // Pretends that the sharing permission has been granted for this account. - EXPECT_CALL(mock_sharing_permission_delegate, + EXPECT_CALL(*mock_sharing_permission_delegate_, HasSharingPermissionForAccount( url::Origin::Create(GURL(kIdpTestOrigin)), _, "1234")) .WillOnce(Return(true)); @@ -1274,12 +1355,8 @@ kClientMetadataEndpoint, {FetchStatus::kSuccess, kAccounts, absl::nullopt, /*customized_dialog=*/true}}}; - auto& auth_request = CreateAuthRequest(GURL(test_case.inputs.provider)); + CreateAuthRequest(GURL(test_case.inputs.provider)); SetMockExpectations(test_case); - // Sets specific expectations for sharing permission: - NiceMock<MockSharingPermissionDelegate> mock_sharing_permission_delegate; - auth_request.SetSharingPermissionDelegateForTests( - &mock_sharing_permission_delegate); EXPECT_CALL(*mock_dialog_controller(), ShowAccountsDialog(_, _, _, _, _, _, _)) @@ -1339,15 +1416,11 @@ ASSERT_EQ(web_contents_impl->GetVisibility(), Visibility::VISIBLE); const auto& test_case = kSuccessfulMediatedSignUpTestCase; - auto& auth_request = CreateAuthRequest(GURL(test_case.inputs.provider)); + CreateAuthRequest(GURL(test_case.inputs.provider)); SetMockExpectations(test_case); - // Sets specific expectations for sharing permission. - NiceMock<MockSharingPermissionDelegate> mock_sharing_permission_delegate; - auth_request.SetSharingPermissionDelegateForTests( - &mock_sharing_permission_delegate); // Pretends that the sharing permission has been granted for this account. - EXPECT_CALL(mock_sharing_permission_delegate, + EXPECT_CALL(*mock_sharing_permission_delegate_, HasSharingPermissionForAccount( url::Origin::Create(GURL(kIdpTestOrigin)), _, "1234")) .WillOnce(Return(true)); @@ -1395,4 +1468,21 @@ histogram_tester.ExpectTotalCount("Blink.FedCm.WebContentsVisible", 1); } +TEST_F(BasicFederatedAuthRequestImplTest, + DisabledWhenThirdPartyCookiesBlocked) { + const auto& test_case = kSuccessfulMediatedAutoSignInTestCase; + CreateAuthRequest(GURL(test_case.inputs.provider)); + NiceMock<MockApiPermissionDelegate> mock_api_permission_delegate; + auth_request_service_->GetImplForTesting()->SetApiPermissionDelegateForTests( + &mock_api_permission_delegate); + // Not calling SetMockExpectations(test_case) because the testcase is rejected + // early on, before the network manager is actually created. + EXPECT_CALL(mock_api_permission_delegate, AreThirdPartyCookiesBlocked()) + .WillOnce(Return(true)); + auto auth_response = + PerformAuthRequest(test_case.inputs.client_id, test_case.inputs.nonce, + test_case.inputs.prefer_auto_sign_in); + EXPECT_EQ(auth_response.first, RequestIdTokenStatus::kError); +} + } // namespace content
diff --git a/content/browser/webid/idp_network_request_manager.cc b/content/browser/webid/idp_network_request_manager.cc index 7277658..876f4be 100644 --- a/content/browser/webid/idp_network_request_manager.cc +++ b/content/browser/webid/idp_network_request_manager.cc
@@ -345,7 +345,10 @@ return nullptr; // Use the browser process URL loader factory because it has cross-origin - // read blocking disabled. + // read blocking disabled. This is safe because even though these are + // renderer-initiated fetches, the browser parses the responses and does not + // leak the values to the renderer. The renderer should only learn information + // when the user selects an account to sign in. return std::make_unique<IdpNetworkRequestManager>( provider, host->GetLastCommittedOrigin(), host->GetStoragePartition()->GetURLLoaderFactoryForBrowserProcess(),
diff --git a/content/browser/webid/test/mock_api_permission_delegate.cc b/content/browser/webid/test/mock_api_permission_delegate.cc new file mode 100644 index 0000000..df7c1f4 --- /dev/null +++ b/content/browser/webid/test/mock_api_permission_delegate.cc
@@ -0,0 +1,13 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/webid/test/mock_api_permission_delegate.h" + +namespace content { + +MockApiPermissionDelegate::MockApiPermissionDelegate() = default; + +MockApiPermissionDelegate::~MockApiPermissionDelegate() = default; + +} // namespace content
diff --git a/content/browser/webid/test/mock_api_permission_delegate.h b/content/browser/webid/test/mock_api_permission_delegate.h new file mode 100644 index 0000000..b3f7b1b --- /dev/null +++ b/content/browser/webid/test/mock_api_permission_delegate.h
@@ -0,0 +1,30 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_WEBID_TEST_MOCK_API_PERMISSION_DELEGATE_H_ +#define CONTENT_BROWSER_WEBID_TEST_MOCK_API_PERMISSION_DELEGATE_H_ + +#include "content/public/browser/federated_identity_api_permission_context_delegate.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace content { + +class MockApiPermissionDelegate + : public FederatedIdentityApiPermissionContextDelegate { + public: + MockApiPermissionDelegate(); + + ~MockApiPermissionDelegate() override; + + MockApiPermissionDelegate(const MockApiPermissionDelegate&) = delete; + MockApiPermissionDelegate& operator=(const MockApiPermissionDelegate&) = + delete; + + MOCK_METHOD(bool, HasApiPermission, (), (override)); + MOCK_METHOD(bool, AreThirdPartyCookiesBlocked, (), (override)); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_WEBID_TEST_MOCK_API_PERMISSION_DELEGATE_H_
diff --git a/content/public/browser/federated_identity_api_permission_context_delegate.h b/content/public/browser/federated_identity_api_permission_context_delegate.h index e377850..5465759 100644 --- a/content/public/browser/federated_identity_api_permission_context_delegate.h +++ b/content/public/browser/federated_identity_api_permission_context_delegate.h
@@ -16,6 +16,9 @@ // Returns whether the FedCM API is enabled in site settings. virtual bool HasApiPermission() = 0; + + // Returns whether third party cookies are blocked. + virtual bool AreThirdPartyCookiesBlocked() = 0; }; } // namespace content
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index ea578c81..ded6a0a 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -2301,6 +2301,8 @@ "../browser/webid/test/fake_identity_request_dialog_controller.h", "../browser/webid/test/mock_active_session_permission_delegate.cc", "../browser/webid/test/mock_active_session_permission_delegate.h", + "../browser/webid/test/mock_api_permission_delegate.cc", + "../browser/webid/test/mock_api_permission_delegate.h", "../browser/webid/test/mock_identity_request_dialog_controller.cc", "../browser/webid/test/mock_identity_request_dialog_controller.h", "../browser/webid/test/mock_idp_network_request_manager.cc",
diff --git a/content/test/attribution_simulator_impl.cc b/content/test/attribution_simulator_impl.cc index a026b4e..a9f3e43 100644 --- a/content/test/attribution_simulator_impl.cc +++ b/content/test/attribution_simulator_impl.cc
@@ -238,7 +238,6 @@ case AttributionTrigger::EventLevelResult::kPriorityTooLow: case AttributionTrigger::EventLevelResult::kDroppedForNoise: case AttributionTrigger::EventLevelResult::kExcessiveReportingOrigins: - case AttributionTrigger::EventLevelResult::kNoMatchingEventTriggers: case AttributionTrigger::EventLevelResult::kNoMatchingSourceFilterData: reason << result.event_level_status(); break;
diff --git a/docs/speed/binary_size/optimization_advice.md b/docs/speed/binary_size/optimization_advice.md index c84e864..1956dcc 100644 --- a/docs/speed/binary_size/optimization_advice.md +++ b/docs/speed/binary_size/optimization_advice.md
@@ -123,8 +123,6 @@ * Would a vector image work? * Images that can be described by a series of paths should generally be stored as vectors. - * The one exception is if the image will be used pre-Lollipop in a - notification or application icon. * For images used in native code: [VectorIcon](https://chromium.googlesource.com/chromium/src/+/HEAD/components/vector_icons/README.md). * For Android drawables: [VectorDrawable](https://developer.android.com/guide/topics/graphics/vector-drawable-resources). * Convert from `.svg` online using https://inloop.github.io/svg2android/.
diff --git "a/infra/config/generated/builders/ci/ASan Debug \05032-bit x86 with V8-ARM\051/properties.json" "b/infra/config/generated/builders/ci/ASan Debug \05032-bit x86 with V8-ARM\051/properties.json" index 1ed296c..77be319 100644 --- "a/infra/config/generated/builders/ci/ASan Debug \05032-bit x86 with V8-ARM\051/properties.json" +++ "b/infra/config/generated/builders/ci/ASan Debug \05032-bit x86 with V8-ARM\051/properties.json"
@@ -1,9 +1,8 @@ { - "$build/goma": { - "enable_ats": true, - "rpc_extra_params": "?prod", - "server_host": "goma.chromium.org", - "use_luci_auth": true + "$build/reclient": { + "instance": "rbe-chromium-trusted", + "jobs": 250, + "metrics_project": "chromium-reclient-metrics" }, "$recipe_engine/resultdb/test_presentation": { "column_keys": [],
diff --git "a/infra/config/generated/builders/ci/ASan Release \05032-bit x86 with V8-ARM\051/properties.json" "b/infra/config/generated/builders/ci/ASan Release \05032-bit x86 with V8-ARM\051/properties.json" index 1ed296c..77be319 100644 --- "a/infra/config/generated/builders/ci/ASan Release \05032-bit x86 with V8-ARM\051/properties.json" +++ "b/infra/config/generated/builders/ci/ASan Release \05032-bit x86 with V8-ARM\051/properties.json"
@@ -1,9 +1,8 @@ { - "$build/goma": { - "enable_ats": true, - "rpc_extra_params": "?prod", - "server_host": "goma.chromium.org", - "use_luci_auth": true + "$build/reclient": { + "instance": "rbe-chromium-trusted", + "jobs": 250, + "metrics_project": "chromium-reclient-metrics" }, "$recipe_engine/resultdb/test_presentation": { "column_keys": [],
diff --git "a/infra/config/generated/builders/ci/ASan Release Media \05032-bit x86 with V8-ARM\051/properties.json" "b/infra/config/generated/builders/ci/ASan Release Media \05032-bit x86 with V8-ARM\051/properties.json" index 1ed296c..77be319 100644 --- "a/infra/config/generated/builders/ci/ASan Release Media \05032-bit x86 with V8-ARM\051/properties.json" +++ "b/infra/config/generated/builders/ci/ASan Release Media \05032-bit x86 with V8-ARM\051/properties.json"
@@ -1,9 +1,8 @@ { - "$build/goma": { - "enable_ats": true, - "rpc_extra_params": "?prod", - "server_host": "goma.chromium.org", - "use_luci_auth": true + "$build/reclient": { + "instance": "rbe-chromium-trusted", + "jobs": 250, + "metrics_project": "chromium-reclient-metrics" }, "$recipe_engine/resultdb/test_presentation": { "column_keys": [],
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg index d4b2eef..9595f4fd 100644 --- a/infra/config/generated/luci/cr-buildbucket.cfg +++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -22787,11 +22787,10 @@ } properties: '{' - ' "$build/goma": {' - ' "enable_ats": true,' - ' "rpc_extra_params": "?prod",' - ' "server_host": "goma.chromium.org",' - ' "use_luci_auth": true' + ' "$build/reclient": {' + ' "instance": "rbe-chromium-trusted",' + ' "jobs": 250,' + ' "metrics_project": "chromium-reclient-metrics"' ' },' ' "$recipe_engine/resultdb/test_presentation": {' ' "column_keys": [],' @@ -22927,11 +22926,10 @@ } properties: '{' - ' "$build/goma": {' - ' "enable_ats": true,' - ' "rpc_extra_params": "?prod",' - ' "server_host": "goma.chromium.org",' - ' "use_luci_auth": true' + ' "$build/reclient": {' + ' "instance": "rbe-chromium-trusted",' + ' "jobs": 250,' + ' "metrics_project": "chromium-reclient-metrics"' ' },' ' "$recipe_engine/resultdb/test_presentation": {' ' "column_keys": [],'
diff --git a/infra/config/subprojects/chromium/ci/chromium.angle.star b/infra/config/subprojects/chromium/ci/chromium.angle.star index 6131ca0..8ad1b40 100644 --- a/infra/config/subprojects/chromium/ci/chromium.angle.star +++ b/infra/config/subprojects/chromium/ci/chromium.angle.star
@@ -4,7 +4,7 @@ """Definitions of builders in the chromium.angle builder group.""" load("//lib/builders.star", "goma", "xcode") -load("//lib/ci.star", "ci") +load("//lib/ci.star", "ci", "rbe_instance", "rbe_jobs") load("//lib/consoles.star", "consoles") ci.defaults.set( @@ -41,6 +41,9 @@ category = "Android|Builder|ANGLE", short_name = "arm64", ), + goma_backend = None, + reclient_instance = rbe_instance.DEFAULT, + reclient_jobs = rbe_jobs.DEFAULT, ) ci.thin_tester( @@ -58,6 +61,9 @@ category = "Android|Builder|Chromium", short_name = "arm64", ), + goma_backend = None, + reclient_instance = rbe_instance.DEFAULT, + reclient_jobs = rbe_jobs.DEFAULT, ) ci.thin_tester(
diff --git a/infra/config/subprojects/chromium/ci/chromium.fuzz.star b/infra/config/subprojects/chromium/ci/chromium.fuzz.star index 47c1af2..a39abae 100644 --- a/infra/config/subprojects/chromium/ci/chromium.fuzz.star +++ b/infra/config/subprojects/chromium/ci/chromium.fuzz.star
@@ -74,6 +74,9 @@ triggering_policy = scheduler.greedy_batching( max_concurrent_invocations = 4, ), + goma_backend = None, + reclient_jobs = rbe_jobs.DEFAULT, + reclient_instance = rbe_instance.DEFAULT, ) ci.builder( @@ -99,6 +102,9 @@ triggering_policy = scheduler.greedy_batching( max_concurrent_invocations = 4, ), + goma_backend = None, + reclient_jobs = rbe_jobs.DEFAULT, + reclient_instance = rbe_instance.DEFAULT, ) ci.builder( @@ -136,6 +142,9 @@ triggering_policy = scheduler.greedy_batching( max_concurrent_invocations = 4, ), + goma_backend = None, + reclient_jobs = rbe_jobs.DEFAULT, + reclient_instance = rbe_instance.DEFAULT, ) ci.builder(
diff --git a/infra/config/subprojects/webrtc/OWNERS b/infra/config/subprojects/webrtc/OWNERS index 35aab6c..49f68ba 100644 --- a/infra/config/subprojects/webrtc/OWNERS +++ b/infra/config/subprojects/webrtc/OWNERS
@@ -1,4 +1,5 @@ jansson@chromium.org +jleconte@google.com landrey@google.com mbonadei@chromium.org terelius@chromium.org
diff --git a/ios/chrome/browser/browser_state/BUILD.gn b/ios/chrome/browser/browser_state/BUILD.gn index 93e08b31..cd4f1bc 100644 --- a/ios/chrome/browser/browser_state/BUILD.gn +++ b/ios/chrome/browser/browser_state/BUILD.gn
@@ -78,6 +78,7 @@ "//components/keyed_service/ios", "//components/metrics", "//components/net_log", + "//components/optimization_guide/core", "//components/password_manager/core/browser", "//components/policy/core/common", "//components/pref_registry",
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state_manager_impl.mm b/ios/chrome/browser/browser_state/chrome_browser_state_manager_impl.mm index 5d23b65c..80fde88 100644 --- a/ios/chrome/browser/browser_state/chrome_browser_state_manager_impl.mm +++ b/ios/chrome/browser/browser_state/chrome_browser_state_manager_impl.mm
@@ -17,6 +17,7 @@ #include "base/task/sequenced_task_runner.h" #include "base/task/thread_pool.h" #include "base/threading/scoped_blocking_call.h" +#include "components/optimization_guide/core/optimization_guide_features.h" #include "components/prefs/pref_service.h" #include "components/signin/ios/browser/active_state_manager.h" #include "components/signin/public/identity_manager/identity_manager.h" @@ -214,11 +215,14 @@ // Initialization needs to happen after the browser context is available // because UnifiedConsentService's dependencies needs the URL context getter. UnifiedConsentServiceFactory::GetForBrowserState(browser_state); + // Initialization needs to happen after the browser context is available // because because IOSChromeMetricsServiceAccessor requires browser_state // to be registered in the ChromeBrowserStateManager. - OptimizationGuideServiceFactory::GetForBrowserState(browser_state) - ->DoFinalInit(browser_state); + if (optimization_guide::features::IsOptimizationHintsEnabled()) { + OptimizationGuideServiceFactory::GetForBrowserState(browser_state) + ->DoFinalInit(); + } } void ChromeBrowserStateManagerImpl::AddBrowserStateToCache(
diff --git a/ios/chrome/browser/optimization_guide/ios_chrome_hints_manager.h b/ios/chrome/browser/optimization_guide/ios_chrome_hints_manager.h index 40cd08ec..ec72d7bef 100644 --- a/ios/chrome/browser/optimization_guide/ios_chrome_hints_manager.h +++ b/ios/chrome/browser/optimization_guide/ios_chrome_hints_manager.h
@@ -7,16 +7,13 @@ #include "components/optimization_guide/core/hints_manager.h" -namespace web { -class BrowserState; -} // namespace web - namespace optimization_guide { class IOSChromeHintsManager : public HintsManager { public: IOSChromeHintsManager( - web::BrowserState* browser_state, + bool off_the_record, + const std::string& application_locale, PrefService* pref_service, base::WeakPtr<optimization_guide::OptimizationGuideStore> hint_store, optimization_guide::TopHostProvider* top_host_provider,
diff --git a/ios/chrome/browser/optimization_guide/ios_chrome_hints_manager.mm b/ios/chrome/browser/optimization_guide/ios_chrome_hints_manager.mm index dc65746d..0934712 100644 --- a/ios/chrome/browser/optimization_guide/ios_chrome_hints_manager.mm +++ b/ios/chrome/browser/optimization_guide/ios_chrome_hints_manager.mm
@@ -4,8 +4,6 @@ #include "ios/chrome/browser/optimization_guide/ios_chrome_hints_manager.h" -#import "ios/chrome/browser/application_context.h" -#import "ios/chrome/browser/browser_state/chrome_browser_state.h" #import "services/network/public/cpp/shared_url_loader_factory.h" #if !defined(__has_feature) || !__has_feature(objc_arc) @@ -15,15 +13,16 @@ namespace optimization_guide { IOSChromeHintsManager::IOSChromeHintsManager( - web::BrowserState* browser_state, + bool off_the_record, + const std::string& application_locale, PrefService* pref_service, base::WeakPtr<optimization_guide::OptimizationGuideStore> hint_store, optimization_guide::TopHostProvider* top_host_provider, optimization_guide::TabUrlProvider* tab_url_provider, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, OptimizationGuideLogger* optimization_guide_logger) - : HintsManager(browser_state->IsOffTheRecord(), - GetApplicationContext()->GetApplicationLocale(), + : HintsManager(off_the_record, + application_locale, pref_service, hint_store, top_host_provider,
diff --git a/ios/chrome/browser/optimization_guide/optimization_guide_service.h b/ios/chrome/browser/optimization_guide/optimization_guide_service.h index 42346e2a..72b89ded 100644 --- a/ios/chrome/browser/optimization_guide/optimization_guide_service.h +++ b/ios/chrome/browser/optimization_guide/optimization_guide_service.h
@@ -8,6 +8,8 @@ #include <vector> #include "base/callback_forward.h" +#include "base/files/file_path.h" +#include "base/memory/weak_ptr.h" #include "base/sequence_checker.h" #include "components/keyed_service/core/keyed_service.h" #include "components/optimization_guide/core/optimization_guide_decision.h" @@ -15,6 +17,14 @@ #include "components/optimization_guide/proto/hints.pb.h" #include "url/gurl.h" +namespace leveldb_proto { +class ProtoDatabaseProvider; +} // namespace leveldb_proto + +namespace network { +class SharedURLLoaderFactory; +} // namespace network + namespace optimization_guide { class TabUrlProvider; class TopHostProvider; @@ -22,8 +32,10 @@ class HintsManager; } // namespace optimization_guide +class BrowserList; class OptimizationGuideLogger; class OptimizationGuideNavigationData; +class PrefService; namespace web { class BrowserState; @@ -39,15 +51,23 @@ // data is cleared. class OptimizationGuideService : public KeyedService { public: - explicit OptimizationGuideService(web::BrowserState* browser_state); + OptimizationGuideService( + leveldb_proto::ProtoDatabaseProvider* proto_db_provider, + const base::FilePath& profile_path, + bool off_the_record, + const std::string& application_locale, + base::WeakPtr<optimization_guide::OptimizationGuideStore> hint_store, + PrefService* pref_service, + BrowserList* browser_list, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory); ~OptimizationGuideService() override; OptimizationGuideService(const OptimizationGuideService&) = delete; OptimizationGuideService& operator=(const OptimizationGuideService&) = delete; - // Some initialization parts must be done once |browser_state| is fully + // Some initialization parts must be done once the browser_state is fully // initialized. - void DoFinalInit(web::BrowserState* browser_state); + void DoFinalInit(); // Registers the optimization types that intend to be queried during the // session. It is expected for this to be called right after the browser has @@ -75,6 +95,9 @@ // Called when browsing data is cleared for the user. void OnBrowsingDataRemoved(); + // Getter for the hint manager. + optimization_guide::HintsManager* GetHintsManager(); + private: friend class OptimizationGuideServiceTest; friend class OptimizationGuideTabHelper; @@ -92,8 +115,6 @@ // KeyedService implementation: void Shutdown() override; - optimization_guide::HintsManager* GetHintsManager(); - // The store of hints. std::unique_ptr<optimization_guide::OptimizationGuideStore> hint_store_; @@ -111,6 +132,12 @@ std::unique_ptr<OptimizationGuideLogger> optimization_guide_logger_; + // The PrefService of the browser state this service is linked to. + PrefService* const pref_service_ = nullptr; + + // Whether the service is linked to an incognito browser state. + const bool off_the_record_ = false; + SEQUENCE_CHECKER(sequence_checker_); };
diff --git a/ios/chrome/browser/optimization_guide/optimization_guide_service.mm b/ios/chrome/browser/optimization_guide/optimization_guide_service.mm index 11cba6b7..96b4b5f3 100644 --- a/ios/chrome/browser/optimization_guide/optimization_guide_service.mm +++ b/ios/chrome/browser/optimization_guide/optimization_guide_service.mm
@@ -18,8 +18,7 @@ #import "components/optimization_guide/core/optimization_guide_store.h" #import "components/optimization_guide/core/optimization_guide_util.h" #import "components/optimization_guide/core/top_host_provider.h" -#import "ios/chrome/browser/application_context.h" -#import "ios/chrome/browser/browser_state/chrome_browser_state.h" +#include "ios/chrome/browser/browser_state/chrome_browser_state.h" #import "ios/chrome/browser/metrics/ios_chrome_metrics_service_accessor.h" #import "ios/chrome/browser/optimization_guide/ios_chrome_hints_manager.h" #import "ios/chrome/browser/optimization_guide/optimization_guide_service_factory.h" @@ -32,36 +31,26 @@ #endif OptimizationGuideService::OptimizationGuideService( - web::BrowserState* browser_state) { + leveldb_proto::ProtoDatabaseProvider* proto_db_provider, + const base::FilePath& profile_path, + bool off_the_record, + const std::string& application_locale, + base::WeakPtr<optimization_guide::OptimizationGuideStore> hint_store, + PrefService* pref_service, + BrowserList* browser_list, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) + : pref_service_(pref_service), off_the_record_(off_the_record) { DCHECK(optimization_guide::features::IsOptimizationHintsEnabled()); - ChromeBrowserState* chrome_browser_state = - ChromeBrowserState::FromBrowserState(browser_state); - DCHECK(chrome_browser_state); - - // Regardless of whether the profile is off the record or not, initialize the - // Optimization Guide with the database associated with the original profile. - auto* proto_db_provider = - chrome_browser_state->GetOriginalChromeBrowserState() - ->GetProtoDatabaseProvider(); - base::FilePath profile_path = - chrome_browser_state->GetOriginalChromeBrowserState()->GetStatePath(); - - base::WeakPtr<optimization_guide::OptimizationGuideStore> hint_store; base::WeakPtr<optimization_guide::OptimizationGuideStore> prediction_model_and_features_store; - if (chrome_browser_state->IsOffTheRecord()) { - OptimizationGuideService* original_ogs = - OptimizationGuideServiceFactory::GetForBrowserState( - chrome_browser_state->GetOriginalChromeBrowserState()); - DCHECK(original_ogs); - hint_store = original_ogs->GetHintsManager()->hint_store(); - } else { + DCHECK(!off_the_record_ || hint_store); + if (!off_the_record_) { // Only create a top host provider from the command line if provided. top_host_provider_ = optimization_guide::CommandLineTopHostProvider::CreateIfEnabled(); tab_url_provider_ = std::make_unique<TabUrlProviderImpl>( - chrome_browser_state, base::DefaultClock::GetInstance()); + browser_list, base::DefaultClock::GetInstance()); hint_store_ = optimization_guide::features::ShouldPersistHintsToDisk() ? std::make_unique<optimization_guide::OptimizationGuideStore>( @@ -75,9 +64,8 @@ } optimization_guide_logger_ = std::make_unique<OptimizationGuideLogger>(); hints_manager_ = std::make_unique<optimization_guide::IOSChromeHintsManager>( - browser_state, chrome_browser_state->GetPrefs(), hint_store, - top_host_provider_.get(), tab_url_provider_.get(), - browser_state->GetSharedURLLoaderFactory(), + off_the_record_, application_locale, pref_service, hint_store, + top_host_provider_.get(), tab_url_provider_.get(), url_loader_factory, optimization_guide_logger_.get()); } @@ -85,14 +73,11 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); } -void OptimizationGuideService::DoFinalInit(web::BrowserState* browser_state) { - ChromeBrowserState* chrome_browser_state = - ChromeBrowserState::FromBrowserState(browser_state); - DCHECK(chrome_browser_state); - if (!chrome_browser_state->IsOffTheRecord()) { +void OptimizationGuideService::DoFinalInit() { + if (!off_the_record_) { bool optimization_guide_fetching_enabled = optimization_guide::IsUserPermittedToFetchFromRemoteOptimizationGuide( - browser_state->IsOffTheRecord(), chrome_browser_state->GetPrefs()); + off_the_record_, pref_service_); base::UmaHistogramBoolean("OptimizationGuide.RemoteFetchingEnabled", optimization_guide_fetching_enabled); IOSChromeMetricsServiceAccessor::RegisterSyntheticFieldTrial(
diff --git a/ios/chrome/browser/optimization_guide/optimization_guide_service_factory.mm b/ios/chrome/browser/optimization_guide/optimization_guide_service_factory.mm index a25144ac..5e3e80a4 100644 --- a/ios/chrome/browser/optimization_guide/optimization_guide_service_factory.mm +++ b/ios/chrome/browser/optimization_guide/optimization_guide_service_factory.mm
@@ -8,10 +8,13 @@ #import "base/no_destructor.h" #import "components/keyed_service/ios/browser_state_dependency_manager.h" #import "components/optimization_guide/core/optimization_guide_features.h" +#import "ios/chrome/browser/application_context.h" #include "ios/chrome/browser/browser_state/browser_state_otr_helper.h" #import "ios/chrome/browser/browser_state/chrome_browser_state.h" #import "ios/chrome/browser/main/browser_list_factory.h" +#include "ios/chrome/browser/optimization_guide/ios_chrome_hints_manager.h" #import "ios/chrome/browser/optimization_guide/optimization_guide_service.h" +#import "services/network/public/cpp/shared_url_loader_factory.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -45,7 +48,31 @@ std::unique_ptr<KeyedService> OptimizationGuideServiceFactory::BuildServiceInstanceFor( web::BrowserState* context) const { - return std::make_unique<OptimizationGuideService>(context); + ChromeBrowserState* chrome_browser_state = + ChromeBrowserState::FromBrowserState(context); + ChromeBrowserState* original_browser_state = + chrome_browser_state->GetOriginalChromeBrowserState(); + DCHECK(chrome_browser_state); + // Regardless of whether the profile is off the record or not, initialize the + // Optimization Guide with the database associated with the original profile. + auto* proto_db_provider = original_browser_state->GetProtoDatabaseProvider(); + base::FilePath profile_path = original_browser_state->GetStatePath(); + + base::WeakPtr<optimization_guide::OptimizationGuideStore> hint_store; + if (chrome_browser_state->IsOffTheRecord()) { + OptimizationGuideService* original_ogs = + OptimizationGuideServiceFactory::GetForBrowserState( + original_browser_state); + DCHECK(original_ogs); + hint_store = original_ogs->GetHintsManager()->hint_store(); + } + + return std::make_unique<OptimizationGuideService>( + proto_db_provider, profile_path, chrome_browser_state->IsOffTheRecord(), + GetApplicationContext()->GetApplicationLocale(), hint_store, + chrome_browser_state->GetPrefs(), + BrowserListFactory::GetForBrowserState(chrome_browser_state), + chrome_browser_state->GetSharedURLLoaderFactory()); } bool OptimizationGuideServiceFactory::ServiceIsCreatedWithBrowserState() const {
diff --git a/ios/chrome/browser/optimization_guide/optimization_guide_service_unittest.mm b/ios/chrome/browser/optimization_guide/optimization_guide_service_unittest.mm index 8ff7161..69585dd6 100644 --- a/ios/chrome/browser/optimization_guide/optimization_guide_service_unittest.mm +++ b/ios/chrome/browser/optimization_guide/optimization_guide_service_unittest.mm
@@ -107,7 +107,7 @@ optimization_guide_service_ = OptimizationGuideServiceFactory::GetForBrowserState( browser_state_.get()); - optimization_guide_service_->DoFinalInit(browser_state_.get()); + optimization_guide_service_->DoFinalInit(); } void PushHintsComponentAndWaitForCompletion() {
diff --git a/ios/chrome/browser/optimization_guide/tab_url_provider_impl.h b/ios/chrome/browser/optimization_guide/tab_url_provider_impl.h index 9ba1ccd7..e1b2a59 100644 --- a/ios/chrome/browser/optimization_guide/tab_url_provider_impl.h +++ b/ios/chrome/browser/optimization_guide/tab_url_provider_impl.h
@@ -15,13 +15,12 @@ } // namespace base class BrowserList; -class ChromeBrowserState; class GURL; // optimization_guide::TabUrlProvider implementation for iOS. class TabUrlProviderImpl : public optimization_guide::TabUrlProvider { public: - TabUrlProviderImpl(ChromeBrowserState* browser_state, base::Clock* clock); + TabUrlProviderImpl(BrowserList* browser_list, base::Clock* clock); ~TabUrlProviderImpl() override; private:
diff --git a/ios/chrome/browser/optimization_guide/tab_url_provider_impl.mm b/ios/chrome/browser/optimization_guide/tab_url_provider_impl.mm index 7b21f43..bd6bcfc 100644 --- a/ios/chrome/browser/optimization_guide/tab_url_provider_impl.mm +++ b/ios/chrome/browser/optimization_guide/tab_url_provider_impl.mm
@@ -7,7 +7,6 @@ #import "base/containers/adapters.h" #import "base/time/clock.h" #import "base/time/time.h" -#import "ios/chrome/browser/browser_state/chrome_browser_state.h" #import "ios/chrome/browser/main/browser.h" #import "ios/chrome/browser/main/browser_list.h" #import "ios/chrome/browser/main/browser_list_factory.h" @@ -20,10 +19,9 @@ #error "This file requires ARC support." #endif -TabUrlProviderImpl::TabUrlProviderImpl(ChromeBrowserState* browser_state, +TabUrlProviderImpl::TabUrlProviderImpl(BrowserList* browser_list, base::Clock* clock) - : browser_list_(BrowserListFactory::GetForBrowserState(browser_state)), - clock_(clock) {} + : browser_list_(browser_list), clock_(clock) {} TabUrlProviderImpl::~TabUrlProviderImpl() = default;
diff --git a/ios/chrome/browser/optimization_guide/tab_url_provider_impl_unittest.mm b/ios/chrome/browser/optimization_guide/tab_url_provider_impl_unittest.mm index dd09c179..8b3247a2 100644 --- a/ios/chrome/browser/optimization_guide/tab_url_provider_impl_unittest.mm +++ b/ios/chrome/browser/optimization_guide/tab_url_provider_impl_unittest.mm
@@ -52,7 +52,7 @@ browser_list_->AddIncognitoBrowser(incognito_browser_.get()); tab_url_provider_ = - std::make_unique<TabUrlProviderImpl>(browser_state_.get(), &clock_); + std::make_unique<TabUrlProviderImpl>(browser_list_, &clock_); } // Add a fake web state with certain URL and timestamp to be the last
diff --git a/ios/chrome/browser/passwords/well_known_change_password_tab_helper_unittest.mm b/ios/chrome/browser/passwords/well_known_change_password_tab_helper_unittest.mm index 2aeb9d6..1525127 100644 --- a/ios/chrome/browser/passwords/well_known_change_password_tab_helper_unittest.mm +++ b/ios/chrome/browser/passwords/well_known_change_password_tab_helper_unittest.mm
@@ -5,10 +5,7 @@ #import <Foundation/Foundation.h> -#include "base/run_loop.h" -#include "base/task/current_thread.h" #include "base/test/bind.h" -#import "base/test/ios/wait_util.h" #include "base/test/scoped_feature_list.h" #include "components/password_manager/core/browser/site_affiliation/mock_affiliation_service.h" #include "components/password_manager/core/browser/well_known_change_password_util.h" @@ -21,6 +18,7 @@ #import "ios/web/public/test/fakes/fake_web_state_delegate.h" #import "ios/web/public/test/navigation_test_util.h" #import "ios/web/public/test/scoped_testing_web_client.h" +#import "ios/web/public/test/task_observer_util.h" #include "ios/web/public/test/web_task_environment.h" #import "ios/web/public/test/web_view_content_test_util.h" #include "net/cert/x509_certificate.h" @@ -76,8 +74,7 @@ // This test uses a mockserver to simulate different response. To handle the // url_loader requests we also mock the response for the url_loader_factory. -class WellKnownChangePasswordTabHelperTest : public PlatformTest, - public base::TaskObserver { +class WellKnownChangePasswordTabHelperTest : public PlatformTest { public: using UkmBuilder = ukm::builders::PasswordManager_WellKnownChangePasswordResult; @@ -154,55 +151,12 @@ std::unique_ptr<ukm::TestAutoSetUkmRecorder> test_recorder_; protected: - // base::TaskObserver overide - void WillProcessTask(const base::PendingTask&, bool) override { - // Nothing to do. - } - void DidProcessTask(const base::PendingTask&) override { - processed_a_task_ = true; - } - - void WaitForBackgroundTasks() { - // Because tasks can add new tasks to either queue, the loop continues until - // the first pass where no activity is seen from either queue. - bool activitySeen = false; - base::CurrentThread messageLoop = base::CurrentThread::Get(); - messageLoop->AddTaskObserver(this); - do { - activitySeen = false; - - // Yield to the iOS message queue, e.g. [NSObject performSelector:] - // events. - if (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true) == - kCFRunLoopRunHandledSource) - activitySeen = true; - - // Yield to the Chromium message queue, e.g. WebThread::PostTask() - // events. - processed_a_task_ = false; - base::RunLoop().RunUntilIdle(); - if (processed_a_task_) // Set in TaskObserver method. - activitySeen = true; - - } while (activitySeen); - messageLoop->RemoveTaskObserver(this); - } - - bool WaitUntilLoaded() { - return WaitUntilConditionOrTimeout(base::test::ios::kWaitForPageLoadTimeout, - ^{ - WaitForBackgroundTasks(); - return !web_state()->IsLoading(); - }); - } - web::WebState* web_state() const { return web_state_.get(); } web::ScopedTestingWebClient web_client_; web::WebTaskEnvironment task_environment_; std::unique_ptr<TestChromeBrowserState> browser_state_; std::unique_ptr<web::WebState> web_state_; - bool processed_a_task_ = false; private: // Returns a response for the given request. Uses |path_response_map_| to @@ -255,7 +209,7 @@ web::test::LoadUrl(web_state(), test_server_->GetURL(kWellKnownChangePasswordPath)); - ASSERT_TRUE(WaitUntilLoaded()); + ASSERT_TRUE(web::test::WaitUntilLoaded(web_state())); EXPECT_EQ(GetNavigatedUrl().path(), kWellKnownChangePasswordPath); ExpectUkmMetric(WellKnownChangePasswordResult::kUsedWellKnownChangePassword); } @@ -271,7 +225,7 @@ web::test::LoadUrl(web_state(), test_server_->GetURL(kWellKnownChangePasswordPath)); - ASSERT_TRUE(WaitUntilLoaded()); + ASSERT_TRUE(web::test::WaitUntilLoaded(web_state())); EXPECT_EQ(GetNavigatedUrl().path(), "/change-password"); ExpectUkmMetric(WellKnownChangePasswordResult::kUsedWellKnownChangePassword); } @@ -284,7 +238,7 @@ web::test::LoadUrl(web_state(), test_server_->GetURL(kWellKnownChangePasswordPath)); - ASSERT_TRUE(WaitUntilLoaded()); + ASSERT_TRUE(web::test::WaitUntilLoaded(web_state())); EXPECT_EQ(GetNavigatedUrl().path(), "/"); ExpectUkmMetric(WellKnownChangePasswordResult::kFallbackToOriginUrl); } @@ -296,7 +250,7 @@ web::test::LoadUrl(web_state(), test_server_->GetURL(kWellKnownChangePasswordPath)); - ASSERT_TRUE(WaitUntilLoaded()); + ASSERT_TRUE(web::test::WaitUntilLoaded(web_state())); EXPECT_EQ(GetNavigatedUrl().path(), "/"); ExpectUkmMetric(WellKnownChangePasswordResult::kFallbackToOriginUrl); } @@ -309,7 +263,7 @@ SetUrlLoaderResponse(kWellKnownNotExistingResourcePath, net::HTTP_OK); web::test::LoadUrl(web_state(), test_server_->GetURL(kWellKnownChangePasswordPath)); - ASSERT_TRUE(WaitUntilLoaded()); + ASSERT_TRUE(web::test::WaitUntilLoaded(web_state())); EXPECT_EQ(GetNavigatedUrl().path(), "/"); ExpectUkmMetric(WellKnownChangePasswordResult::kFallbackToOriginUrl); } @@ -324,7 +278,7 @@ SetUrlLoaderResponse(kWellKnownNotExistingResourcePath, net::HTTP_OK); web::test::LoadUrl(web_state(), test_server_->GetURL(kWellKnownChangePasswordPath)); - ASSERT_TRUE(WaitUntilLoaded()); + ASSERT_TRUE(web::test::WaitUntilLoaded(web_state())); EXPECT_EQ(GetNavigatedUrl().path(), kMockChangePasswordPath); ExpectUkmMetric(WellKnownChangePasswordResult::kFallbackToOverrideUrl); } @@ -335,7 +289,7 @@ LoadUrlWithTransition(web_state(), test_server_->GetURL(kWellKnownChangePasswordPath), ui::PAGE_TRANSITION_LINK); - ASSERT_TRUE(WaitUntilLoaded()); + ASSERT_TRUE(web::test::WaitUntilLoaded(web_state())); EXPECT_EQ(GetNavigatedUrl().path(), kWellKnownChangePasswordPath); // In the case of PAGE_TRANSITION_LINK the tab helper should not be active and @@ -353,7 +307,7 @@ web::test::LoadUrl(web_state(), test_server_->GetURL(kWellKnownChangePasswordPath)); - ASSERT_TRUE(WaitUntilLoaded()); + ASSERT_TRUE(web::test::WaitUntilLoaded(web_state())); EXPECT_EQ(GetNavigatedUrl().path(), kWellKnownChangePasswordPath); ExpectUkmMetric(WellKnownChangePasswordResult::kUsedWellKnownChangePassword); }
diff --git a/ios/chrome/browser/ui/authentication/enterprise/BUILD.gn b/ios/chrome/browser/ui/authentication/enterprise/BUILD.gn index 053d5d734..ed8e3c1 100644 --- a/ios/chrome/browser/ui/authentication/enterprise/BUILD.gn +++ b/ios/chrome/browser/ui/authentication/enterprise/BUILD.gn
@@ -16,7 +16,6 @@ "//components/sync/base", "//components/sync/driver", "//ios/chrome/browser", - "//ios/chrome/browser/browser_state", "//ios/chrome/browser/policy:policy_util", "//ios/chrome/browser/sync", ]
diff --git a/ios/chrome/browser/ui/authentication/enterprise/enterprise_utils.h b/ios/chrome/browser/ui/authentication/enterprise/enterprise_utils.h index fc96097..def5c8c 100644 --- a/ios/chrome/browser/ui/authentication/enterprise/enterprise_utils.h +++ b/ios/chrome/browser/ui/authentication/enterprise/enterprise_utils.h
@@ -9,7 +9,10 @@ #include "ios/chrome/browser/sync/sync_setup_service.h" -class ChromeBrowserState; +class PrefService; +namespace syncer { +class SyncService; +} // List of Enterprise restriction options. typedef NS_OPTIONS(NSUInteger, EnterpriseSignInRestrictions) { @@ -28,17 +31,17 @@ bool IsForceSignInEnabled(); // Returns true if the |dataType| is managed by policies (i.e. is not syncable). -bool IsManagedSyncDataType(ChromeBrowserState* browserState, +bool IsManagedSyncDataType(PrefService* pref_service, SyncSetupService::SyncableDatatype dataType); // Returns true if any data type is managed by policies (i.e. is not syncable). -bool HasManagedSyncDataType(ChromeBrowserState* browserState); +bool HasManagedSyncDataType(PrefService* pref_service); // Returns current EnterpriseSignInRestrictions. EnterpriseSignInRestrictions GetEnterpriseSignInRestrictions( - ChromeBrowserState* browserState); + PrefService* pref_service); // true if sync is disabled. -bool IsSyncDisabledByPolicy(ChromeBrowserState* browserState); +bool IsSyncDisabledByPolicy(syncer::SyncService* sync_service); #endif // IOS_CHROME_BROWSER_UI_AUTHENTICATION_ENTERPRISE_ENTERPRISE_UTILS_H_
diff --git a/ios/chrome/browser/ui/authentication/enterprise/enterprise_utils.mm b/ios/chrome/browser/ui/authentication/enterprise/enterprise_utils.mm index 6d4d076..bfcdc84 100644 --- a/ios/chrome/browser/ui/authentication/enterprise/enterprise_utils.mm +++ b/ios/chrome/browser/ui/authentication/enterprise/enterprise_utils.mm
@@ -11,7 +11,6 @@ #include "components/sync/base/pref_names.h" #include "components/sync/driver/sync_service.h" #include "ios/chrome/browser/application_context.h" -#import "ios/chrome/browser/browser_state/chrome_browser_state.h" #include "ios/chrome/browser/policy/policy_util.h" #include "ios/chrome/browser/pref_names.h" #import "ios/chrome/browser/sync/sync_service_factory.h" @@ -51,39 +50,36 @@ return policy_mode == BrowserSigninMode::kForced; } -bool IsManagedSyncDataType(ChromeBrowserState* browserState, - SyncSetupService::SyncableDatatype dataType) { - return browserState->GetPrefs() - ->FindPreference(kSyncableItemTypes.at(dataType)) +bool IsManagedSyncDataType(PrefService* pref_service, + SyncSetupService::SyncableDatatype data_type) { + return pref_service->FindPreference(kSyncableItemTypes.at(data_type)) ->IsManaged(); } -bool HasManagedSyncDataType(ChromeBrowserState* browserState) { +bool HasManagedSyncDataType(PrefService* pref_service) { for (int type = 0; type != SyncSetupService::kNumberOfSyncableDatatypes; type++) { - SyncSetupService::SyncableDatatype dataType = + SyncSetupService::SyncableDatatype data_type = static_cast<SyncSetupService::SyncableDatatype>(type); - if (IsManagedSyncDataType(browserState, dataType)) + if (IsManagedSyncDataType(pref_service, data_type)) return true; } return false; } EnterpriseSignInRestrictions GetEnterpriseSignInRestrictions( - ChromeBrowserState* browserState) { + PrefService* pref_service) { EnterpriseSignInRestrictions restrictions = kNoEnterpriseRestriction; if (IsForceSignInEnabled()) restrictions |= kEnterpriseForceSignIn; if (IsRestrictAccountsToPatternsEnabled()) restrictions |= kEnterpriseRestrictAccounts; - if (HasManagedSyncDataType(browserState)) + if (HasManagedSyncDataType(pref_service)) restrictions |= kEnterpriseSyncTypesListDisabled; return restrictions; } -bool IsSyncDisabledByPolicy(ChromeBrowserState* browserState) { - syncer::SyncService* syncService = - SyncServiceFactory::GetForBrowserState(browserState); - return syncService->GetDisableReasons().Has( +bool IsSyncDisabledByPolicy(syncer::SyncService* sync_service) { + return sync_service->GetDisableReasons().Has( syncer::SyncService::DISABLE_REASON_ENTERPRISE_POLICY); }
diff --git a/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_coordinator.mm b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_coordinator.mm index b2ceb7a..9e20512 100644 --- a/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_coordinator.mm +++ b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_coordinator.mm
@@ -30,15 +30,16 @@ @implementation ConsistencyDefaultAccountCoordinator - (void)start { + ChromeBrowserState* browserState = self.browser->GetBrowserState(); self.mediator = [[ConsistencyDefaultAccountMediator alloc] initWithAccountManagerService:ChromeAccountManagerServiceFactory:: - GetForBrowserState( - self.browser->GetBrowserState())]; + GetForBrowserState(browserState)]; self.mediator.delegate = self; self.defaultAccountViewController = [[ConsistencyDefaultAccountViewController alloc] init]; + PrefService* prefService = browserState->GetPrefs(); self.defaultAccountViewController.enterpriseSignInRestrictions = - GetEnterpriseSignInRestrictions(self.browser->GetBrowserState()); + GetEnterpriseSignInRestrictions(prefService); self.mediator.consumer = self.defaultAccountViewController; self.defaultAccountViewController.actionDelegate = self; self.defaultAccountViewController.layoutDelegate = self.layoutDelegate;
diff --git a/ios/chrome/browser/ui/authentication/signin_sync/signin_sync_coordinator.mm b/ios/chrome/browser/ui/authentication/signin_sync/signin_sync_coordinator.mm index be7c1ba..cc68267 100644 --- a/ios/chrome/browser/ui/authentication/signin_sync/signin_sync_coordinator.mm +++ b/ios/chrome/browser/ui/authentication/signin_sync/signin_sync_coordinator.mm
@@ -155,7 +155,9 @@ [self finishPresentingAndSkipRemainingScreens:NO]; return; } - if (IsSyncDisabledByPolicy(browserState)) { + syncer::SyncService* syncService = + SyncServiceFactory::GetForBrowserState(browserState); + if (IsSyncDisabledByPolicy(syncService)) { // Skip the screen if sync is disabled by policy. self.attemptStatus = first_run::SignInAttemptStatus::SKIPPED_BY_POLICY; [self finishPresentingAndSkipRemainingScreens:NO]; @@ -182,8 +184,9 @@ self.viewController = [[SigninSyncViewController alloc] init]; self.viewController.delegate = self; + PrefService* prefService = browserState->GetPrefs(); self.viewController.enterpriseSignInRestrictions = - GetEnterpriseSignInRestrictions(browserState); + GetEnterpriseSignInRestrictions(prefService); self.viewController.identitySwitcherPosition = fre_field_trial::GetSigninSyncScreenUIIdentitySwitcherPosition(); self.viewController.stringsSet =
diff --git a/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.mm b/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.mm index 0b8135d..f911fcc 100644 --- a/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.mm +++ b/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.mm
@@ -5,6 +5,7 @@ #include "ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.h" #include "base/check_op.h" +#import "ios/chrome/browser/browser_state/chrome_browser_state.h" #import "ios/chrome/browser/main/browser.h" #import "ios/chrome/browser/signin/authentication_service.h" #import "ios/chrome/browser/signin/authentication_service_factory.h" @@ -106,7 +107,9 @@ } - (BOOL)hasManagedSyncDataType { - return HasManagedSyncDataType(self.browser->GetBrowserState()); + ChromeBrowserState* browserState = self.browser->GetBrowserState(); + PrefService* prefService = browserState->GetPrefs(); + return HasManagedSyncDataType(prefService); } - (BOOL)hasAccountRestrictions {
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_home_mediator.mm b/ios/chrome/browser/ui/bookmarks/bookmark_home_mediator.mm index f02d7dd..018fa8665 100644 --- a/ios/chrome/browser/ui/bookmarks/bookmark_home_mediator.mm +++ b/ios/chrome/browser/ui/bookmarks/bookmark_home_mediator.mm
@@ -560,8 +560,9 @@ DCHECK(self.syncService); bool syncDisabledPolicy = self.syncService->GetDisableReasons().Has( syncer::SyncService::DISABLE_REASON_ENTERPRISE_POLICY); - bool syncTypesDisabledPolicy = IsManagedSyncDataType( - self.browserState, SyncSetupService::kSyncBookmarks); + PrefService* prefService = self.browserState->GetPrefs(); + bool syncTypesDisabledPolicy = + IsManagedSyncDataType(prefService, SyncSetupService::kSyncBookmarks); return syncDisabledPolicy || syncTypesDisabledPolicy; } @end
diff --git a/ios/chrome/browser/ui/first_run/signin/signin_screen_coordinator.mm b/ios/chrome/browser/ui/first_run/signin/signin_screen_coordinator.mm index 44df680..d0b1fde 100644 --- a/ios/chrome/browser/ui/first_run/signin/signin_screen_coordinator.mm +++ b/ios/chrome/browser/ui/first_run/signin/signin_screen_coordinator.mm
@@ -108,9 +108,9 @@ return; } + ChromeBrowserState* browserState = self.browser->GetBrowserState(); AuthenticationService* authenticationService = - AuthenticationServiceFactory::GetForBrowserState( - self.browser->GetBrowserState()); + AuthenticationServiceFactory::GetForBrowserState(browserState); if (authenticationService->GetPrimaryIdentity( signin::ConsentLevel::kSignin)) { @@ -126,12 +126,12 @@ self.viewController = [[SigninScreenViewController alloc] init]; self.viewController.delegate = self; + PrefService* prefService = browserState->GetPrefs(); self.viewController.enterpriseSignInRestrictions = - GetEnterpriseSignInRestrictions(self.browser->GetBrowserState()); + GetEnterpriseSignInRestrictions(prefService); self.accountManagerService = - ChromeAccountManagerServiceFactory::GetForBrowserState( - self.browser->GetBrowserState()); + ChromeAccountManagerServiceFactory::GetForBrowserState(browserState); self.mediator = [[SigninScreenMediator alloc] initWithAccountManagerService:self.accountManagerService
diff --git a/ios/chrome/browser/ui/first_run/sync/sync_screen_coordinator.mm b/ios/chrome/browser/ui/first_run/sync/sync_screen_coordinator.mm index bd88a8fe..b2f7696 100644 --- a/ios/chrome/browser/ui/first_run/sync/sync_screen_coordinator.mm +++ b/ios/chrome/browser/ui/first_run/sync/sync_screen_coordinator.mm
@@ -131,8 +131,8 @@ self.viewController = [[SyncScreenViewController alloc] init]; self.viewController.delegate = self; - self.viewController.syncTypesRestricted = - HasManagedSyncDataType(browserState); + PrefService* prefService = browserState->GetPrefs(); + self.viewController.syncTypesRestricted = HasManagedSyncDataType(prefService); // Setup mediator. self.mediator = [[SyncScreenMediator alloc] initWithAuthenticationService:authenticationService
diff --git a/ios/chrome/browser/ui/follow/BUILD.gn b/ios/chrome/browser/ui/follow/BUILD.gn index 46fc690..ea5a29f 100644 --- a/ios/chrome/browser/ui/follow/BUILD.gn +++ b/ios/chrome/browser/ui/follow/BUILD.gn
@@ -5,8 +5,11 @@ source_set("follow") { configs += [ "//build/config/compiler:enable_arc" ] sources = [ + "follow_block_types.h", "follow_site_info.h", "follow_site_info.mm", + "followed_web_channel.h", + "followed_web_channel.mm", ] deps = [] }
diff --git a/ios/chrome/browser/ui/follow/follow_block_types.h b/ios/chrome/browser/ui/follow/follow_block_types.h new file mode 100644 index 0000000..691a536 --- /dev/null +++ b/ios/chrome/browser/ui/follow/follow_block_types.h
@@ -0,0 +1,18 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_UI_FOLLOW_FOLLOW_BLOCK_TYPES_H_ +#define IOS_CHROME_BROWSER_UI_FOLLOW_FOLLOW_BLOCK_TYPES_H_ + +#import <Foundation/Foundation.h> + +// Completion callback for a request. +// |success| is YES if the operation was successful. +typedef void (^RequestCompletionBlock)(BOOL success); + +// Block to call for unfollowing a web channel. +// |completion| is called at completion of the request. +typedef void (^UnfollowRequestBlock)(RequestCompletionBlock completion); + +#endif // IOS_CHROME_BROWSER_UI_FOLLOW_FOLLOW_BLOCK_TYPES_H_
diff --git a/ios/chrome/browser/ui/follow/followed_web_channel.h b/ios/chrome/browser/ui/follow/followed_web_channel.h new file mode 100644 index 0000000..131df9d1 --- /dev/null +++ b/ios/chrome/browser/ui/follow/followed_web_channel.h
@@ -0,0 +1,34 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_UI_FOLLOW_FOLLOWED_WEB_CHANNEL_H_ +#define IOS_CHROME_BROWSER_UI_FOLLOW_FOLLOWED_WEB_CHANNEL_H_ + +#import <Foundation/Foundation.h> + +#include "ios/chrome/browser/ui/follow/follow_block_types.h" + +@class CrURL; + +// A view model representing a followed web channel. +@interface FollowedWebChannel : NSObject + +// Title of the web channel. +@property(nonatomic, copy) NSString* title; + +// The host name for the web channel. +@property(nonatomic, copy) NSString* hostname; + +// CrURL from which to retrieve a favicon. +@property(nonatomic, strong) CrURL* faviconURL; + +// YES if the web channel is unavailable. +@property(nonatomic, assign) BOOL unavailable; + +// Used to request to unfollow this web channel. +@property(nonatomic, copy) UnfollowRequestBlock unfollowRequestBlock; + +@end + +#endif // IOS_CHROME_BROWSER_UI_FOLLOW_FOLLOWED_WEB_CHANNEL_H_
diff --git a/ios/chrome/browser/ui/ntp/feed_management/web_channel.mm b/ios/chrome/browser/ui/follow/followed_web_channel.mm similarity index 73% rename from ios/chrome/browser/ui/ntp/feed_management/web_channel.mm rename to ios/chrome/browser/ui/follow/followed_web_channel.mm index 86b9967..9ddee389 100644 --- a/ios/chrome/browser/ui/ntp/feed_management/web_channel.mm +++ b/ios/chrome/browser/ui/follow/followed_web_channel.mm
@@ -2,11 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import "ios/chrome/browser/ui/ntp/feed_management/web_channel.h" +#import "ios/chrome/browser/ui/follow/followed_web_channel.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." #endif -@implementation WebChannel -@end +@implementation FollowedWebChannel +@end \ No newline at end of file
diff --git a/ios/chrome/browser/ui/ntp/feed_management/BUILD.gn b/ios/chrome/browser/ui/ntp/feed_management/BUILD.gn index c835819..02522e5 100644 --- a/ios/chrome/browser/ui/ntp/feed_management/BUILD.gn +++ b/ios/chrome/browser/ui/ntp/feed_management/BUILD.gn
@@ -49,19 +49,17 @@ source_set("follow_management_ui") { sources = [ - "follow_management_delegate.h", "follow_management_view_controller.h", "follow_management_view_controller.mm", "followed_web_channel_item.h", "followed_web_channel_item.mm", "followed_web_channels_data_source.h", - "web_channel.h", - "web_channel.mm", ] configs += [ "//build/config/compiler:enable_arc" ] deps = [ "//base", "//ios/chrome/app/strings:ios_strings_grit", + "//ios/chrome/browser/ui/follow", "//ios/chrome/browser/ui/table_view", "//ios/chrome/browser/ui/table_view/cells", "//ui/base",
diff --git a/ios/chrome/browser/ui/ntp/feed_management/feed_management_coordinator.mm b/ios/chrome/browser/ui/ntp/feed_management/feed_management_coordinator.mm index cfa6ddc..32af0f73 100644 --- a/ios/chrome/browser/ui/ntp/feed_management/feed_management_coordinator.mm +++ b/ios/chrome/browser/ui/ntp/feed_management/feed_management_coordinator.mm
@@ -67,7 +67,6 @@ initWithStyle:UITableViewStyleInsetGrouped]; FollowManagementMediator* mediator = [[FollowManagementMediator alloc] init]; followManagementViewController.dataSource = mediator; - followManagementViewController.delegate = mediator; self.followManagementMediator = mediator; [self.navigationController pushViewController:followManagementViewController animated:YES];
diff --git a/ios/chrome/browser/ui/ntp/feed_management/follow_management_delegate.h b/ios/chrome/browser/ui/ntp/feed_management/follow_management_delegate.h deleted file mode 100644 index ed6822a..0000000 --- a/ios/chrome/browser/ui/ntp/feed_management/follow_management_delegate.h +++ /dev/null
@@ -1,21 +0,0 @@ -// Copyright 2022 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_UI_NTP_FEED_MANAGEMENT_FOLLOW_MANAGEMENT_DELEGATE_H_ -#define IOS_CHROME_BROWSER_UI_NTP_FEED_MANAGEMENT_FOLLOW_MANAGEMENT_DELEGATE_H_ - -#import <Foundation/Foundation.h> - -@class WebChannel; - -// Actions taken on the follow management UI. -@protocol FollowManagementDelegate - -// User requested to unfollow a WebChannel. -- (void)unfollowWebChannel:(WebChannel*)channel - completion:(void (^)(BOOL success))completion; - -@end - -#endif // IOS_CHROME_BROWSER_UI_NTP_FEED_MANAGEMENT_FOLLOW_MANAGEMENT_DELEGATE_H_
diff --git a/ios/chrome/browser/ui/ntp/feed_management/follow_management_mediator.h b/ios/chrome/browser/ui/ntp/feed_management/follow_management_mediator.h index b9924166..84e3439 100644 --- a/ios/chrome/browser/ui/ntp/feed_management/follow_management_mediator.h +++ b/ios/chrome/browser/ui/ntp/feed_management/follow_management_mediator.h
@@ -7,13 +7,11 @@ #import <Foundation/Foundation.h> -#import "ios/chrome/browser/ui/ntp/feed_management/follow_management_delegate.h" #import "ios/chrome/browser/ui/ntp/feed_management/followed_web_channels_data_source.h" // The intermediary between the model and view layers for the follow management // UI. -@interface FollowManagementMediator - : NSObject <FollowedWebChannelsDataSource, FollowManagementDelegate> +@interface FollowManagementMediator : NSObject <FollowedWebChannelsDataSource> @end #endif // IOS_CHROME_BROWSER_UI_NTP_FEED_MANAGEMENT_FOLLOW_MANAGEMENT_MEDIATOR_H_
diff --git a/ios/chrome/browser/ui/ntp/feed_management/follow_management_mediator.mm b/ios/chrome/browser/ui/ntp/feed_management/follow_management_mediator.mm index ea67f54..bb72503 100644 --- a/ios/chrome/browser/ui/ntp/feed_management/follow_management_mediator.mm +++ b/ios/chrome/browser/ui/ntp/feed_management/follow_management_mediator.mm
@@ -4,8 +4,6 @@ #import "ios/chrome/browser/ui/ntp/feed_management/follow_management_mediator.h" -#import "ios/chrome/browser/ui/ntp/feed_management/web_channel.h" - #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." #endif @@ -14,19 +12,9 @@ #pragma mark - FollowedWebChannelsDataSource -- (NSArray<WebChannel*>*)followedWebChannels { +- (NSArray<FollowedWebChannel*>*)followedWebChannels { // TODO(crbug.com/1296745): Call provider API to get followed channels. return @[]; } -#pragma mark - FollowManagementDelegate - -- (void)unfollowWebChannel:(WebChannel*)channel - completion:(void (^)(BOOL success))completion { - // TODO(crbug.com/1296745): Call provider API to unfollow channel. - dispatch_async(dispatch_get_main_queue(), ^{ - completion(NO); - }); -} - @end
diff --git a/ios/chrome/browser/ui/ntp/feed_management/follow_management_view_controller.h b/ios/chrome/browser/ui/ntp/feed_management/follow_management_view_controller.h index a57ba14..008c977 100644 --- a/ios/chrome/browser/ui/ntp/feed_management/follow_management_view_controller.h +++ b/ios/chrome/browser/ui/ntp/feed_management/follow_management_view_controller.h
@@ -5,19 +5,16 @@ #ifndef IOS_CHROME_BROWSER_UI_NTP_FEED_MANAGEMENT_FOLLOW_MANAGEMENT_VIEW_CONTROLLER_H_ #define IOS_CHROME_BROWSER_UI_NTP_FEED_MANAGEMENT_FOLLOW_MANAGEMENT_VIEW_CONTROLLER_H_ -#import "ios/chrome/browser/ui/ntp/feed_management/follow_management_delegate.h" -#import "ios/chrome/browser/ui/ntp/feed_management/followed_web_channels_data_source.h" #import "ios/chrome/browser/ui/table_view/chrome_table_view_controller.h" +@protocol FollowedWebChannelsDataSource; + // The UI that displays the web channels that the user is following. @interface FollowManagementViewController : ChromeTableViewController // DataSource for followed web channels. @property(nonatomic, weak) id<FollowedWebChannelsDataSource> dataSource; -// Delegate for meaningful user actions. -@property(nonatomic, weak) id<FollowManagementDelegate> delegate; - @end #endif // IOS_CHROME_BROWSER_UI_NTP_FEED_MANAGEMENT_FOLLOW_MANAGEMENT_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/ntp/feed_management/follow_management_view_controller.mm b/ios/chrome/browser/ui/ntp/feed_management/follow_management_view_controller.mm index eafd6df..3a3fb4fd 100644 --- a/ios/chrome/browser/ui/ntp/feed_management/follow_management_view_controller.mm +++ b/ios/chrome/browser/ui/ntp/feed_management/follow_management_view_controller.mm
@@ -5,8 +5,10 @@ #import "ios/chrome/browser/ui/ntp/feed_management/follow_management_view_controller.h" #include "base/mac/foundation_util.h" +#import "ios/chrome/browser/ui/follow/follow_block_types.h" +#import "ios/chrome/browser/ui/follow/followed_web_channel.h" #import "ios/chrome/browser/ui/ntp/feed_management/followed_web_channel_item.h" -#import "ios/chrome/browser/ui/ntp/feed_management/web_channel.h" +#import "ios/chrome/browser/ui/ntp/feed_management/followed_web_channels_data_source.h" #import "ios/chrome/grit/ios_strings.h" #import "ui/base/l10n/l10n_util_mac.h" @@ -40,14 +42,15 @@ - (void)loadModel { [super loadModel]; - NSArray<WebChannel*>* webChannels = self.dataSource.followedWebChannels; + NSArray<FollowedWebChannel*>* followedWebChannels = + self.dataSource.followedWebChannels; TableViewModel* model = self.tableViewModel; [model addSectionWithIdentifier:DefaultSectionIdentifier]; - for (WebChannel* webChannel in webChannels) { + for (FollowedWebChannel* followedWebChannel in followedWebChannels) { FollowedWebChannelItem* item = [[FollowedWebChannelItem alloc] initWithType:FollowedWebChannelItemType]; - item.webChannel = webChannel; + item.followedWebChannel = followedWebChannel; [model addItem:item toSectionWithIdentifier:DefaultSectionIdentifier]; } } @@ -91,17 +94,16 @@ FollowedWebChannelItem* item = base::mac::ObjCCastStrict<FollowedWebChannelItem>( [self.tableViewModel itemAtIndexPath:indexPath]); - WebChannel* webChannel = item.webChannel; - [self.delegate unfollowWebChannel:webChannel - completion:^(BOOL success) { - if (success) { - // TODO(crbug.com/1296745): Show success snackbar - // with undo button. - } else { - // TODO(crbug.com/1296745): Show failure snackbar - // with try again button. - } - }]; + + item.followedWebChannel.unfollowRequestBlock(^(BOOL success) { + if (success) { + // TODO(crbug.com/1296745): Show success snackbar + // with undo button. Also remove row. + } else { + // TODO(crbug.com/1296745): Show failure snackbar + // with try again button. + } + }); } @end
diff --git a/ios/chrome/browser/ui/ntp/feed_management/followed_web_channel_item.h b/ios/chrome/browser/ui/ntp/feed_management/followed_web_channel_item.h index 6410e7b..21ee2291 100644 --- a/ios/chrome/browser/ui/ntp/feed_management/followed_web_channel_item.h +++ b/ios/chrome/browser/ui/ntp/feed_management/followed_web_channel_item.h
@@ -7,13 +7,13 @@ #import "ios/chrome/browser/ui/table_view/cells/table_view_image_item.h" -@class WebChannel; +@class FollowedWebChannel; // A table view item representing a web channel. @interface FollowedWebChannelItem : TableViewImageItem // Web channel associated with this table view item. -@property(nonatomic, strong) WebChannel* webChannel; +@property(nonatomic, strong) FollowedWebChannel* followedWebChannel; @end
diff --git a/ios/chrome/browser/ui/ntp/feed_management/followed_web_channel_item.mm b/ios/chrome/browser/ui/ntp/feed_management/followed_web_channel_item.mm index 81d82e0..ed2ce79 100644 --- a/ios/chrome/browser/ui/ntp/feed_management/followed_web_channel_item.mm +++ b/ios/chrome/browser/ui/ntp/feed_management/followed_web_channel_item.mm
@@ -5,7 +5,7 @@ #import "ios/chrome/browser/ui/ntp/feed_management/followed_web_channel_item.h" #include "base/mac/foundation_util.h" -#import "ios/chrome/browser/ui/ntp/feed_management/web_channel.h" +#import "ios/chrome/browser/ui/follow/followed_web_channel.h" #import "ios/chrome/grit/ios_strings.h" #import "ui/base/l10n/l10n_util_mac.h" @@ -22,11 +22,11 @@ @implementation FollowedWebChannelItem -- (void)setWebChannel:(WebChannel*)webChannel { - _webChannel = webChannel; - self.title = webChannel.title; - if (!_webChannel.unavailable) { - self.detailText = _webChannel.hostname; +- (void)setFollowedWebChannel:(FollowedWebChannel*)followedWebChannel { + _followedWebChannel = followedWebChannel; + self.title = followedWebChannel.title; + if (!_followedWebChannel.unavailable) { + self.detailText = _followedWebChannel.hostname; return; } @@ -38,7 +38,8 @@ initWithString:[NSString stringWithFormat:@"\n%@", unavailableText] attributes:@{NSForegroundColorAttributeName : UIColor.redColor}]; NSMutableAttributedString* concatenatedString = - [[NSMutableAttributedString alloc] initWithString:_webChannel.hostname]; + [[NSMutableAttributedString alloc] + initWithString:_followedWebChannel.hostname]; [concatenatedString appendAttributedString:unavailableString]; _detailAttributedString = concatenatedString; }
diff --git a/ios/chrome/browser/ui/ntp/feed_management/followed_web_channels_data_source.h b/ios/chrome/browser/ui/ntp/feed_management/followed_web_channels_data_source.h index 3fa7baf..a54272f3 100644 --- a/ios/chrome/browser/ui/ntp/feed_management/followed_web_channels_data_source.h +++ b/ios/chrome/browser/ui/ntp/feed_management/followed_web_channels_data_source.h
@@ -7,13 +7,14 @@ #import <Foundation/Foundation.h> -@class WebChannel; +@class FollowedWebChannel; // A data source from which the UI can pull a list of followed web channels. @protocol FollowedWebChannelsDataSource // Returns an array of WebChannels. This must be synchronous. -@property(nonatomic, readonly) NSArray<WebChannel*>* followedWebChannels; +@property(nonatomic, readonly) + NSArray<FollowedWebChannel*>* followedWebChannels; @end
diff --git a/ios/chrome/browser/ui/ntp/feed_management/web_channel.h b/ios/chrome/browser/ui/ntp/feed_management/web_channel.h deleted file mode 100644 index f7e6443d..0000000 --- a/ios/chrome/browser/ui/ntp/feed_management/web_channel.h +++ /dev/null
@@ -1,24 +0,0 @@ -// Copyright 2022 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_UI_NTP_FEED_MANAGEMENT_WEB_CHANNEL_H_ -#define IOS_CHROME_BROWSER_UI_NTP_FEED_MANAGEMENT_WEB_CHANNEL_H_ - -#import <Foundation/Foundation.h> - -// A view model representing a web channel. -@interface WebChannel : NSObject - -// Title of the web channel. -@property(nonatomic, copy) NSString* title; - -// The hostname to display. -@property(nonatomic, copy) NSString* hostname; - -// YES if the web channel is unavailable. -@property(nonatomic, assign) BOOL unavailable; - -@end - -#endif // IOS_CHROME_BROWSER_UI_NTP_FEED_MANAGEMENT_WEB_CHANNEL_H_
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.mm b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.mm index 5189253..aa7b54d 100644 --- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.mm +++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.mm
@@ -88,6 +88,7 @@ self.model = [[PopupModel alloc] initWithMatches:@[] headers:@[] delegate:self.mediator]; + self.mediator.model = self.model; self.popupViewController = [OmniboxPopupViewProvider makeViewControllerWithModel:self.model]; [self.browser->GetCommandDispatcher()
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_mediator.h b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_mediator.h index 8fddbb0..68995b6 100644 --- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_mediator.h +++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_mediator.h
@@ -18,6 +18,7 @@ @protocol BrowserCommands; @class DefaultBrowserPromoNonModalScheduler; @class OmniboxPopupPresenter; +@class PopupModel; class FaviconLoader; class WebStateList; @@ -74,6 +75,8 @@ // Whether the default search engine is Google impacts which icon is used in // some cases @property(nonatomic, assign) BOOL defaultSearchEngineIsGoogle; +// The model for this mediator, if one exists. +@property(nonatomic, weak) PopupModel* model; // Designated initializer. Takes ownership of |imageFetcher|. - (instancetype)initWithFetcher:
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_mediator.mm b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_mediator.mm index 392d798..1b717a1 100644 --- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_mediator.mm +++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_mediator.mm
@@ -75,6 +75,8 @@ groupWithTitle:nil suggestions:matches] ] withAnimation:animation]; + + [self loadModelImages]; } - (NSArray<id<AutocompleteSuggestion>>*)wrappedMatches { @@ -179,6 +181,32 @@ _delegate->OnScroll(); } +- (void)loadModelImages { + for (PopupMatchSection* section in self.model.sections) { + for (PopupMatch* match in section.matches) { + PopupImage* popupImage = match.image; + switch (popupImage.icon.iconType) { + case OmniboxIconTypeSuggestionIcon: + break; + case OmniboxIconTypeImage: { + [self fetchImage:popupImage.icon.imageURL.gurl + completion:^(UIImage* image) { + popupImage.iconUIImageFromURL = image; + }]; + break; + } + case OmniboxIconTypeFavicon: { + [self fetchFavicon:popupImage.icon.imageURL.gurl + completion:^(UIImage* image) { + popupImage.iconUIImageFromURL = image; + }]; + break; + } + } + } + } +} + #pragma mark - ImageFetcher - (void)fetchImage:(GURL)imageURL completion:(void (^)(UIImage*))completion {
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_provider.swift b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_provider.swift index e306f90..76c95e5d 100644 --- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_provider.swift +++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_provider.swift
@@ -17,6 +17,6 @@ class OmniboxPopupHostingController: UIHostingController<PopupView>, ContentProviding { var hasContent: Bool { - return !rootView.model.matches.isEmpty + return !rootView.model.sections.isEmpty } }
diff --git a/ios/chrome/browser/ui/omnibox/popup/shared/popup_image.swift b/ios/chrome/browser/ui/omnibox/popup/shared/popup_image.swift index c99e9e9b..48350c7 100644 --- a/ios/chrome/browser/ui/omnibox/popup/shared/popup_image.swift +++ b/ios/chrome/browser/ui/omnibox/popup/shared/popup_image.swift
@@ -10,7 +10,7 @@ /// can be absent. @objcMembers public class PopupImage: NSObject, ObservableObject { /// The underlying icon for this image. - let icon: OmniboxIcon + public let icon: OmniboxIcon /// The SwiftUI `Image` and tint color for the main static image. public var iconImage: Image? {
diff --git a/ios/chrome/browser/ui/omnibox/popup/shared/popup_match_image_view.swift b/ios/chrome/browser/ui/omnibox/popup/shared/popup_match_image_view.swift index 7adfb24..a5bd880 100644 --- a/ios/chrome/browser/ui/omnibox/popup/shared/popup_match_image_view.swift +++ b/ios/chrome/browser/ui/omnibox/popup/shared/popup_match_image_view.swift
@@ -12,7 +12,7 @@ } /// The image model object for this view. - let image: PopupImage + @ObservedObject var image: PopupImage var body: some View { ZStack {
diff --git a/ios/chrome/browser/ui/omnibox/popup/shared/popup_model.swift b/ios/chrome/browser/ui/omnibox/popup/shared/popup_model.swift index e90c7198..3658d57 100644 --- a/ios/chrome/browser/ui/omnibox/popup/shared/popup_model.swift +++ b/ios/chrome/browser/ui/omnibox/popup/shared/popup_model.swift
@@ -7,10 +7,17 @@ /// A match group consists of a title and a list of matches. /// Use empty string to hide the section header. -typealias PopupMatchGroup = (header: String, matches: [PopupMatch]) +@objcMembers public class PopupMatchSection: NSObject { + let header: String + let matches: [PopupMatch] + public init(header: String, matches: [PopupMatch]) { + self.header = header + self.matches = matches + } +} @objcMembers public class PopupModel: NSObject, ObservableObject, AutocompleteResultConsumer { - @Published var matches: [PopupMatchGroup] + @Published var sections: [PopupMatchSection] @Published var highlightedMatchIndexPath: IndexPath? @@ -20,7 +27,9 @@ matches: [[PopupMatch]], headers: [String], delegate: AutocompleteResultConsumerDelegate? ) { assert(headers.count == matches.count) - self.matches = zip(headers, matches).map { tuple in (header: tuple.0, matches: tuple.1) } + self.sections = zip(headers, matches).map { tuple in + PopupMatchSection(header: tuple.0, matches: tuple.1) + } self.delegate = delegate } @@ -30,8 +39,8 @@ // Reset highlight state. self.highlightedMatchIndexPath = nil - self.matches = matchGroups.map { group in - ( + self.sections = matchGroups.map { group in + PopupMatchSection( header: group.title ?? String(), matches: group.suggestions.map { match in PopupMatch(suggestion: match, pedal: nil) } ) @@ -65,7 +74,7 @@ if indexPath.row == 0 && indexPath.section > 0 { // Move to the previous section indexPath.section -= 1 - indexPath.row = matches[indexPath.section].matches.count - 1 + indexPath.row = sections[indexPath.section].matches.count - 1 } else { indexPath.row -= 1 } @@ -81,9 +90,9 @@ var indexPath = self.highlightedMatchIndexPath ?? IndexPath(row: -1, section: 0) // If there's a row below in current section, move highlight there - if indexPath.row < matches[indexPath.section].matches.count - 1 { + if indexPath.row < sections[indexPath.section].matches.count - 1 { indexPath.row += 1 - } else if indexPath.section < matches.count - 1 { + } else if indexPath.section < sections.count - 1 { // Move to the next section indexPath.row = 0 indexPath.section += 1
diff --git a/ios/chrome/browser/ui/omnibox/popup/shared/popup_view.swift b/ios/chrome/browser/ui/omnibox/popup/shared/popup_view.swift index 924e317..e3db8d06 100644 --- a/ios/chrome/browser/ui/omnibox/popup/shared/popup_view.swift +++ b/ios/chrome/browser/ui/omnibox/popup/shared/popup_view.swift
@@ -13,7 +13,7 @@ var body: some View { VStack { List { - ForEach(Array(zip(model.matches.indices, model.matches)), id: \.0) { + ForEach(Array(zip(model.sections.indices, model.sections)), id: \.0) { sectionIndex, section in let sectionContents = @@ -46,8 +46,8 @@ } // Split the suggestions into sections, but only add a header text if the header isn't empty - if !model.matches[sectionIndex].header.isEmpty { - Section(header: Text(model.matches[sectionIndex].header)) { + if !section.header.isEmpty { + Section(header: Text(section.header)) { sectionContents } } else {
diff --git a/ios/chrome/browser/ui/overlays/overlay_presentation_context_fullscreen_disabler_unittest.mm b/ios/chrome/browser/ui/overlays/overlay_presentation_context_fullscreen_disabler_unittest.mm index 8d17550..7e5dbd2 100644 --- a/ios/chrome/browser/ui/overlays/overlay_presentation_context_fullscreen_disabler_unittest.mm +++ b/ios/chrome/browser/ui/overlays/overlay_presentation_context_fullscreen_disabler_unittest.mm
@@ -47,9 +47,10 @@ web_view_ = [[WKWebView alloc] initWithFrame:scoped_window_.Get().bounds configuration:[[WKWebViewConfiguration alloc] init]]; - content_view_ = - [[CRWWebViewContentView alloc] initWithWebView:web_view_ - scrollView:web_view_.scrollView]; + content_view_ = [[CRWWebViewContentView alloc] + initWithWebView:web_view_ + scrollView:web_view_.scrollView + fullscreenState:CrFullscreenState::kNotInFullScreen]; // Set up the fake presentation context so OverlayPresenterObserver // callbacks are sent. overlay_presenter()->SetPresentationContext(&presentation_context_);
diff --git a/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm b/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm index b59b5628..40204135 100644 --- a/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm +++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm
@@ -277,8 +277,9 @@ DCHECK(self.syncService); bool syncDisabledPolicy = self.syncService->GetDisableReasons().Has( syncer::SyncService::DISABLE_REASON_ENTERPRISE_POLICY); + PrefService* prefService = self.browserState->GetPrefs(); bool syncTypesDisabledPolicy = - IsManagedSyncDataType(self.browserState, SyncSetupService::kSyncOpenTabs); + IsManagedSyncDataType(prefService, SyncSetupService::kSyncOpenTabs); return syncDisabledPolicy || syncTypesDisabledPolicy; }
diff --git a/ios/chrome/browser/ui/settings/settings_table_view_controller.mm b/ios/chrome/browser/ui/settings/settings_table_view_controller.mm index 34f68959..4ba3a2fa 100644 --- a/ios/chrome/browser/ui/settings/settings_table_view_controller.mm +++ b/ios/chrome/browser/ui/settings/settings_table_view_controller.mm
@@ -658,7 +658,8 @@ AccountSignInItem* signInTextItem = [[AccountSignInItem alloc] initWithType:SettingsItemTypeSignInButton]; signInTextItem.accessibilityIdentifier = kSettingsSignInCellId; - if (!HasManagedSyncDataType(_browserState)) { + PrefService* prefService = _browserState->GetPrefs(); + if (!HasManagedSyncDataType(prefService)) { signInTextItem.detailText = l10n_util::GetNSString(IDS_IOS_SIGN_IN_TO_CHROME_SETTING_SUBTITLE); } else {
diff --git a/ios/chrome/browser/ui/side_swipe/card_side_swipe_view.mm b/ios/chrome/browser/ui/side_swipe/card_side_swipe_view.mm index ba68ad8f..11ddda7b 100644 --- a/ios/chrome/browser/ui/side_swipe/card_side_swipe_view.mm +++ b/ios/chrome/browser/ui/side_swipe/card_side_swipe_view.mm
@@ -180,27 +180,53 @@ toolbarSideSwipeSnapshotForWebState:webState]; [card setBottomToolbarImage:bottomToolbarSnapshot]; + __weak CardSideSwipeView* weakSelf = self; + web::WebState::Getter webStateGetter = webState->CreateDefaultGetter(); + SnapshotTabHelper::FromWebState(webState)->RetrieveColorSnapshot( + ^(UIImage* image) { + [weakSelf colorSnapshotRetrieved:image + card:card + webStateGetter:webStateGetter]; + }); +} + +// Helper method that is invoked once the color snapshot has been fetched +// for the WebState returned by |webStateGetter|. As the fetching is done +// asynchronously, it is possible for the WebState to have been destroyed +// and thus for |webStateGetter| to return nullptr. +- (void)colorSnapshotRetrieved:(UIImage*)image + card:(SwipeView*)card + webStateGetter:(web::WebState::Getter)webStateGetter { + // If the WebState has been destroyed, the card will be dropped, so + // the image can be dropped. + web::WebState* webState = webStateGetter.Run(); + if (!webState) { + return; + } + // Converting snapshotted images to grey takes too much time for single core // devices. Instead, show the colored image for single core devices and the // grey image for multi core devices. - dispatch_queue_t priorityQueue = - dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul); - SnapshotTabHelper::FromWebState(webState)->RetrieveColorSnapshot( - ^(UIImage* image) { - if (PagePlaceholderTabHelper::FromWebState(webState) - ->will_add_placeholder_for_next_navigation() && - !ios::device_util::IsSingleCoreDevice()) { - [card setImage:nil]; - dispatch_async(priorityQueue, ^{ - UIImage* greyImage = [self smallGreyImage:image]; - dispatch_async(dispatch_get_main_queue(), ^{ - [card setImage:greyImage]; - }); - }); - } else { - [card setImage:image]; - } - }); + const bool use_color_image = + ios::device_util::IsSingleCoreDevice() || + !PagePlaceholderTabHelper::FromWebState(webState) + ->will_add_placeholder_for_next_navigation(); + + if (use_color_image) { + [card setImage:image]; + return; + } + + __weak CardSideSwipeView* weakSelf = self; + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul), + ^{ + UIImage* greyImage = [weakSelf smallGreyImage:image]; + if (greyImage) { + dispatch_async(dispatch_get_main_queue(), ^{ + [card setImage:greyImage]; + }); + } + }); } // Move cards according to |currentPoint_.x|. Edge cards only drag
diff --git a/ios/chrome/browser/ui/side_swipe/side_swipe_controller_unittest.mm b/ios/chrome/browser/ui/side_swipe/side_swipe_controller_unittest.mm index fe16931..10bb87c8 100644 --- a/ios/chrome/browser/ui/side_swipe/side_swipe_controller_unittest.mm +++ b/ios/chrome/browser/ui/side_swipe/side_swipe_controller_unittest.mm
@@ -46,7 +46,8 @@ configuration:[[WKWebViewConfiguration alloc] init]]), content_view_([[CRWWebViewContentView alloc] initWithWebView:web_view_ - scrollView:web_view_.scrollView]) { + scrollView:web_view_.scrollView + fullscreenState:CrFullscreenState::kNotInFullScreen]) { auto original_web_state(std::make_unique<web::FakeWebState>()); original_web_state->SetView(content_view_); CRWWebViewScrollViewProxy* scroll_view_proxy =
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_constants.h b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_constants.h index 8d0dc70..bd030d5b 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_constants.h +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_constants.h
@@ -61,6 +61,7 @@ // GridHeader styling. // The GridHeader height. extern const CGFloat kGridHeaderHeight; +extern const CGFloat kGridHeaderAccessibilityHeight; // The GridHeader title label Color. extern const int kGridHeaderTitleColor; // The GridHeader value label Color.
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_constants.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_constants.mm index 3718d879..5ce547a 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_constants.mm +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_constants.mm
@@ -57,6 +57,7 @@ // GridHeader styling. const CGFloat kGridHeaderHeight = 32.0f; +const CGFloat kGridHeaderAccessibilityHeight = 58.0f; const int kGridHeaderTitleColor = 0xFFFFFF; const int kGridHeaderValueColor = 0xEBEBF5; const CGFloat kGridHeaderContentSpacing = 4.0f;
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_context_menu_helper.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_context_menu_helper.mm index a0b105a5..fb0d5491 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_context_menu_helper.mm +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_context_menu_helper.mm
@@ -94,6 +94,9 @@ GridItem* item = [self.actionsDataSource gridItemForCellIdentifier:gridCell.itemIdentifier]; + if (!item) { + return @[]; + } NSMutableArray<UIMenuElement*>* menuElements = [[NSMutableArray alloc] init];
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller.mm index c632b8b..5a0eddf 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller.mm +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller.mm
@@ -598,7 +598,12 @@ !_searchText.length) { return CGSizeZero; } - return CGSizeMake(collectionView.bounds.size.width, kGridHeaderHeight); + CGFloat height = UIContentSizeCategoryIsAccessibilityCategory( + self.traitCollection.preferredContentSizeCategory) + ? kGridHeaderAccessibilityHeight + : kGridHeaderHeight; + + return CGSizeMake(collectionView.bounds.size.width, height); } // This prevents the user from dragging a cell past the plus sign cell (the last
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/suggested_actions/suggested_actions_view_controller.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/suggested_actions/suggested_actions_view_controller.mm index 289c541a..bad8acb 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/suggested_actions/suggested_actions_view_controller.mm +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/suggested_actions/suggested_actions_view_controller.mm
@@ -24,8 +24,7 @@ #endif namespace { - -const CGFloat kEstimatedRowHeight = 56; +const CGFloat kEstimatedRowMaxHeight = 150; NSString* const kSuggestedActionsViewControllerAccessibilityIdentifier = @"search_suggestions_view_controller"; const int kSectionIdentifierSuggestedActions = kSectionIdentifierEnumZero + 1; @@ -67,7 +66,7 @@ self.view.accessibilityIdentifier = kSuggestedActionsViewControllerAccessibilityIdentifier; self.tableView.cellLayoutMarginsFollowReadableWidth = YES; - self.tableView.estimatedRowHeight = kEstimatedRowHeight; + self.tableView.estimatedRowHeight = kEstimatedRowMaxHeight; self.tableView.estimatedSectionHeaderHeight = 0.0; self.tableView.rowHeight = UITableViewAutomaticDimension; self.tableView.sectionFooterHeight = 0.0;
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_mediator.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_mediator.mm index aab0f4b..750c9d4 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_mediator.mm +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_mediator.mm
@@ -841,6 +841,10 @@ - (GridItem*)gridItemForCellIdentifier:(NSString*)identifier { web::WebState* webState = GetWebStateWithId(self.browserState, identifier); + if (!webState) { + return nil; + } + GridItem* item = [[GridItem alloc] initWithTitle:tab_util::GetTabTitle(webState) url:webState->GetVisibleURL()];
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_top_toolbar.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_top_toolbar.mm index 7fc4c02..aa874d27f 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_top_toolbar.mm +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_top_toolbar.mm
@@ -21,7 +21,7 @@ // approximately 33 pts between the plus button and the done button. const int kIconButtonAdditionalSpace = 20; const int kSelectionModeButtonSize = 17; -const int kSearchBarTrailingSpace = 40; +const int kSearchBarTrailingSpace = 24; } @interface TabGridTopToolbar () <UIToolbarDelegate> @@ -72,6 +72,13 @@ // Reset the Select All button to its default title. [self configureSelectAllButtonTitle]; [self setItemsForTraitCollection:self.traitCollection]; + if (mode == TabGridModeSearch) { + // Focus the search bar, and make it a first responder once the user enter + // to search mode. Doing that here instead in |setItemsForTraitCollection| + // makes sure it's only called once and allows the voicOver to transition + // smoothly and to say that there is a search field opened. + [_searchBar becomeFirstResponder]; + } } - (void)setSelectedTabsCount:(int)count { @@ -232,8 +239,11 @@ if (![self shouldUseCompactLayout:traitCollection]) widthModifier = kTabGridSearchBarNonCompactWidthRatioModifier; - CGFloat cancelWidth = - [_cancelSearchButton.title sizeWithAttributes:nil].width; + CGFloat cancelWidth = [_cancelSearchButton.title sizeWithAttributes:@{ + NSFontAttributeName : [UIFont + preferredFontForTextStyle:UIFontTextStyleBody] + }] + .width; CGFloat barWidth = (self.bounds.size.width - kSearchBarTrailingSpace - cancelWidth) * kTabGridSearchBarWidthRatio * widthModifier; @@ -243,7 +253,6 @@ [self setNeedsLayout]; [self setItems:@[ _searchBarItem, _spaceItem, _cancelSearchButton ] animated:YES]; - [_searchBar becomeFirstResponder]; } - (void)setItemsForTraitCollection:(UITraitCollection*)traitCollection {
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_view_controller.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_view_controller.mm index b6effcd..5f6f9fd 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_view_controller.mm +++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_view_controller.mm
@@ -993,8 +993,18 @@ _currentPage = currentPage; self.currentPageViewController.view.accessibilityElementsHidden = NO; // Force VoiceOver to update its accessibility element tree immediately. - UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, - nil); + if (self.tabGridMode == TabGridModeSearch) { + // |UIAccessibilityLayoutChangedNotification| doesn't change the current + // item focused by the voiceOver if the notification argument provided with + // it is |nil|. In search mode, the item focused by the voiceOver needs to + // be reset and to do that |UIAccessibilityScreenChangedNotification| should + // be posted instead. + UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, + nil); + } else { + UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, + nil); + } } // Sets the value of |currentPage|, adjusting the position of the scroll view
diff --git a/ios/testing/BUILD.gn b/ios/testing/BUILD.gn index cc728e43..52d6d17 100644 --- a/ios/testing/BUILD.gn +++ b/ios/testing/BUILD.gn
@@ -131,6 +131,9 @@ "data/http_server_files/onload_replacestate_reload.html", "data/http_server_files/onload_replacestate_reload.js", "data/http_server_files/opensearch.xml", + "data/http_server_files/permissions/camera_and_microphone.html", + "data/http_server_files/permissions/camera_only.html", + "data/http_server_files/permissions/microphone_only.html", "data/http_server_files/pony.html", "data/http_server_files/profile_form.html", "data/http_server_files/readonly_form.html",
diff --git a/ios/testing/data/http_server_files/permissions/camera_and_microphone.html b/ios/testing/data/http_server_files/permissions/camera_and_microphone.html new file mode 100644 index 0000000..08a0084 --- /dev/null +++ b/ios/testing/data/http_server_files/permissions/camera_and_microphone.html
@@ -0,0 +1,48 @@ +<!DOCTYPE html> + +<!-- Copyright 2022 The Chromium Authors. All rights reserved. +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. --> + +<html> +<head> + <meta charset="utf-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> + <meta name="viewport" content="width=device-width"> + <title>Requesting Camera and Microphone Permissions</title> +</head> + +<body> + <div id="container"> + <video autoplay="true" id="videoElement" width="480px" height="270px" muted> + </video> + <p>Current volume: <span id="volume">0</span></p> + </div> + <script type="text/javascript"> + const video = document.querySelector("#videoElement"); + const audio = document.querySelector("#volume"); + navigator.mediaDevices.getUserMedia({ audio: true, video: true }) + .then(function(stream) { + // Video. + video.srcObject = stream; + + // Audio. + const audioCtx = new AudioContext(); + const source = audioCtx.createMediaStreamSource(stream); + + const analyser = audioCtx.createAnalyser(); + analyser.fftSize = 64; + const bufferLength = analyser.frequencyBinCount; + let dataArray = new Uint8Array(bufferLength); + + // Connect the source to be analysed. + source.connect(analyser); + setInterval(function () { + analyser.getByteFrequencyData(dataArray); + let averageVolume = dataArray.reduce((a, b) => a + b) / bufferLength; + audio.innerHTML = averageVolume; + }, 500); + }); +</script> +</body> +</html>
diff --git a/ios/testing/data/http_server_files/permissions/camera_only.html b/ios/testing/data/http_server_files/permissions/camera_only.html new file mode 100644 index 0000000..362ed96 --- /dev/null +++ b/ios/testing/data/http_server_files/permissions/camera_only.html
@@ -0,0 +1,28 @@ +<!DOCTYPE html> + +<!-- Copyright 2022 The Chromium Authors. All rights reserved. +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. --> + +<html> +<head> + <meta charset="utf-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> + <meta name="viewport" content="width=device-width"> + <title>Requesting Camera Permissions</title> +</head> + +<body> + <div id="container"> + <video autoplay="true" id="videoElement" width="480px" height="270px"> + </video> + </div> + <script type="text/javascript"> + var video = document.querySelector("#videoElement"); + navigator.mediaDevices.getUserMedia({ video: true }) + .then(function(stream) { + video.srcObject = stream; + }); +</script> +</body> +</html>
diff --git a/ios/testing/data/http_server_files/permissions/microphone_only.html b/ios/testing/data/http_server_files/permissions/microphone_only.html new file mode 100644 index 0000000..31b0ed0 --- /dev/null +++ b/ios/testing/data/http_server_files/permissions/microphone_only.html
@@ -0,0 +1,40 @@ +<!DOCTYPE html> + +<!-- Copyright 2022 The Chromium Authors. All rights reserved. +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. --> + +<html> +<head> + <meta charset="utf-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> + <meta name="viewport" content="width=device-width"> + + <title>Requesting Microphone Permissions</title> +</head> + +<body> + <p>Current volume: <span id="volume">0</span></p> + <script type="text/javascript"> + const volumeNode = document.getElementById("volume"); + navigator.mediaDevices.getUserMedia({ audio: true }).then( + function(stream) { + const audioCtx = new AudioContext(); + const source = audioCtx.createMediaStreamSource(stream); + + const analyser = audioCtx.createAnalyser(); + analyser.fftSize = 64; + const bufferLength = analyser.frequencyBinCount; + let dataArray = new Uint8Array(bufferLength); + + // Connect the source to be analysed. + source.connect(analyser); + setInterval(function () { + analyser.getByteFrequencyData(dataArray); + let averageVolume = dataArray.reduce((a, b) => a + b) / bufferLength; + volumeNode.innerHTML = averageVolume; + }, 500); + }); +</script> +</body> +</html>
diff --git a/ios/web/BUILD.gn b/ios/web/BUILD.gn index a3ae1c7..3b279608 100644 --- a/ios/web/BUILD.gn +++ b/ios/web/BUILD.gn
@@ -579,6 +579,7 @@ "//ios/web/navigation:wk_navigation_util", "//ios/web/public/find_in_page", "//ios/web/public/js_messaging", + "//ios/web/public/permissions", "//ios/web/public/security", "//ios/web/public/session", "//ios/web/public/test", @@ -619,6 +620,7 @@ "web_state/error_page_inttest.mm", "web_state/http_auth_inttest.mm", "web_state/keep_render_process_alive_inttest.mm", + "web_state/permissions_inttest.mm", "web_state/ui/crw_context_menu_element_fetcher_inttest.mm", "web_state/web_state_observer_inttest.mm", "webui/web_ui_inttest.mm",
diff --git a/ios/web/common/crw_content_view.h b/ios/web/common/crw_content_view.h index 69a90a7..8ace43e 100644 --- a/ios/web/common/crw_content_view.h +++ b/ios/web/common/crw_content_view.h
@@ -7,6 +7,17 @@ #import <UIKit/UIKit.h> +// For devices running on a version >= iOS 15.4, WKFullScreenState is converted +// into CrFullscreenState. Once min version supported is iOS 15.4, +// uses of this enum should be be replaced with WKFullScreenState and this enum +// declaration should be removed. +enum class CrFullscreenState { + kEnteringFullscreen, + kExitingFullscreen, + kInFullscreen, + kNotInFullScreen, +}; + // UIViews conforming to CRWScrollableContent (i.e. CRWContentViews) are used // to display content within a WebState. @protocol CRWScrollableContent <NSObject>
diff --git a/ios/web/common/crw_web_view_content_view.h b/ios/web/common/crw_web_view_content_view.h index 8b248b9..11d88a9e 100644 --- a/ios/web/common/crw_web_view_content_view.h +++ b/ios/web/common/crw_web_view_content_view.h
@@ -16,22 +16,16 @@ // The webView passed to |-initWithWebView|. @property(nonatomic, strong, readonly) UIView* webView; -#if defined(__IPHONE_15_4) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_15_4 // The fullscreen state of this view -@property(nonatomic, readonly) - WKFullscreenState fullscreenState API_AVAILABLE(ios(15)); +@property(nonatomic, readonly) CrFullscreenState fullscreenState; // Initializes the CRWWebViewContentView to display |webView| and passes state -// of fullscreen mode. This should become the default constructor when we -// start building with the 15.4 SDK and pass in a default value of -// WKFullscreenState (e.g., WKFullscreenStateNotInFullscreen). Additionally, -// code in initWithWebView:scrollView should be moved into this constructor at -// that time. +// of fullscreen mode. This should pass in a default value of +// CrFullscreenState (e.g., kNotInFullScreen). - (instancetype)initWithWebView:(UIView*)webView scrollView:(UIScrollView*)scrollView - fullscreenState:(WKFullscreenState)fullscreenState - API_AVAILABLE(ios(15)); -#endif // defined(__IPHONE_15_4) + fullscreenState:(CrFullscreenState)fullscreenState + NS_DESIGNATED_INITIALIZER; // Initializes the CRWWebViewContentView to display |webView|. - (instancetype)initWithWebView:(UIView*)webView @@ -46,10 +40,7 @@ - (instancetype)initWithCoder:(NSCoder*)decoder NS_UNAVAILABLE; - (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE; -#if defined(__IPHONE_15_4) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_15_4 -- (void)updateFullscreenState:(WKFullscreenState)fullscreenState - API_AVAILABLE(ios(15)); -#endif // defined(__IPHONE_15_4) +- (void)updateFullscreenState:(CrFullscreenState)fullscreenState; @end
diff --git a/ios/web/common/crw_web_view_content_view.mm b/ios/web/common/crw_web_view_content_view.mm index a5eb3293..18fa0b6 100644 --- a/ios/web/common/crw_web_view_content_view.mm +++ b/ios/web/common/crw_web_view_content_view.mm
@@ -34,10 +34,7 @@ @synthesize viewportEdgesAffectedBySafeArea = _viewportEdgesAffectedBySafeArea; @synthesize viewportInsets = _viewportInsets; @synthesize webView = _webView; - -#if defined(__IPHONE_15_4) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_15_4 @synthesize fullscreenState = _fullscreenState; -#endif // defined(__IPHONE_15_4) - (instancetype)initWithWebView:(UIView*)webView scrollView:(UIScrollView*)scrollView { @@ -52,17 +49,20 @@ return self; } -#if defined(__IPHONE_15_4) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_15_4 - (instancetype)initWithWebView:(UIView*)webView scrollView:(UIScrollView*)scrollView - fullscreenState:(WKFullscreenState)fullscreenState { - self = [self initWithWebView:webView scrollView:scrollView]; + fullscreenState:(CrFullscreenState)fullscreenState { + self = [super initWithFrame:CGRectZero]; if (self) { + DCHECK(webView); + DCHECK(scrollView); + DCHECK([scrollView isDescendantOfView:webView]); + _webView = webView; + _scrollView = scrollView; _fullscreenState = fullscreenState; } return self; } -#endif // defined(__IPHONE_15_4) - (instancetype)initForTesting { return [super initWithFrame:CGRectZero]; @@ -95,11 +95,9 @@ return [_webView becomeFirstResponder]; } -#if defined(__IPHONE_15_4) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_15_4 -- (void)updateFullscreenState:(WKFullscreenState)fullscreenState { +- (void)updateFullscreenState:(CrFullscreenState)fullscreenState { _fullscreenState = fullscreenState; } -#endif // defined(__IPHONE_15_4) #pragma mark Layout
diff --git a/ios/web/public/test/BUILD.gn b/ios/web/public/test/BUILD.gn index 4bd2d44..838e831a 100644 --- a/ios/web/public/test/BUILD.gn +++ b/ios/web/public/test/BUILD.gn
@@ -138,6 +138,8 @@ "js_test_util.mm", "navigation_test_util.h", "navigation_test_util.mm", + "task_observer_util.h", + "task_observer_util.mm", "url_test_util.h", "web_view_content_test_util.h", "web_view_content_test_util.mm",
diff --git a/ios/web/public/test/task_observer_util.h b/ios/web/public/test/task_observer_util.h new file mode 100644 index 0000000..20b6605 --- /dev/null +++ b/ios/web/public/test/task_observer_util.h
@@ -0,0 +1,24 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_WEB_PUBLIC_TEST_TASK_OBSERVER_UTIL_H_ +#define IOS_WEB_PUBLIC_TEST_TASK_OBSERVER_UTIL_H_ + +namespace web { +class WebState; + +namespace test { + +// Blocks until both known NSRunLoop-based and known message-loop-based +// background tasks have completed +void WaitForBackgroundTasks(); + +// Blocks until |web_state| navigation and background tasks are +// completed. Returns false when timed out. +bool WaitUntilLoaded(WebState* web_state); + +} // namespace test +} // namespace web + +#endif // IOS_WEB_PUBLIC_TEST_TASK_OBSERVER_UTIL_H_
diff --git a/ios/web/public/test/task_observer_util.mm b/ios/web/public/test/task_observer_util.mm new file mode 100644 index 0000000..60564d9 --- /dev/null +++ b/ios/web/public/test/task_observer_util.mm
@@ -0,0 +1,82 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/web/public/test/task_observer_util.h" + +#include "base/pending_task.h" +#include "base/run_loop.h" +#include "base/task/current_thread.h" +#include "base/test/ios/wait_util.h" +#include "ios/web/public/web_state.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +using base::test::ios::kWaitForPageLoadTimeout; +using base::test::ios::WaitUntilConditionOrTimeout; + +namespace { +class WaitForBackgroundTasksTaskObserver : public base::TaskObserver { + public: + // base::TaskObserver overide + void WillProcessTask(const base::PendingTask&, bool) override { + // Nothing to do. + } + void DidProcessTask(const base::PendingTask&) override { + processed_a_task_ = true; + } + + // An accessor method that returns whether the task + // has been processed. + bool has_processed_task() const { return processed_a_task_; } + + void clear_has_processed_task() { processed_a_task_ = false; } + + protected: + // is true if a task has been processed. + bool processed_a_task_ = false; +}; +} + +namespace web { +namespace test { + +void WaitForBackgroundTasks() { + // Because tasks can add new tasks to either queue, the loop continues until + // the first pass where no activity is seen from either queue. + WaitForBackgroundTasksTaskObserver observer; + bool activity_seen = false; + base::CurrentThread message_loop = base::CurrentThread::Get(); + message_loop->AddTaskObserver(&observer); + + do { + activity_seen = false; + + // Yield to the iOS message queue, e.g. [NSObject performSelector:] + // events. + if (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true) == + kCFRunLoopRunHandledSource) + activity_seen = true; + + // Yield to the Chromium message queue, e.g. WebThread::PostTask() + // events. + observer.clear_has_processed_task(); + base::RunLoop().RunUntilIdle(); + if (observer.has_processed_task()) + activity_seen = true; + + } while (activity_seen); + message_loop->RemoveTaskObserver(&observer); +} + +bool WaitUntilLoaded(WebState* web_state) { + return WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^{ + WaitForBackgroundTasks(); + return !web_state->IsLoading(); + }); +} + +} // namespace test +} // namespace web
diff --git a/ios/web/public/test/web_test_with_web_state.h b/ios/web/public/test/web_test_with_web_state.h index 68f5651..8e48c12 100644 --- a/ios/web/public/test/web_test_with_web_state.h +++ b/ios/web/public/test/web_test_with_web_state.h
@@ -20,7 +20,7 @@ class WebState; // Base test fixture that provides WebState for testing. -class WebTestWithWebState : public WebTest, public base::TaskObserver { +class WebTestWithWebState : public WebTest { public: // Destroys underlying WebState. web_state() will return null after this call. void DestroyWebState(); @@ -94,15 +94,8 @@ const web::WebState* web_state() const; private: - // base::TaskObserver overrides. - void WillProcessTask(const base::PendingTask& pending_task, - bool was_blocked_or_low_priority) override; - void DidProcessTask(const base::PendingTask& pending_task) override; - // The web state for testing. std::unique_ptr<WebState> web_state_; - // true if a task has been processed. - bool processed_a_task_; }; } // namespace web
diff --git a/ios/web/public/test/web_test_with_web_state.mm b/ios/web/public/test/web_test_with_web_state.mm index d013c7e..ee13183 100644 --- a/ios/web/public/test/web_test_with_web_state.mm +++ b/ios/web/public/test/web_test_with_web_state.mm
@@ -15,6 +15,7 @@ #import "ios/web/navigation/wk_navigation_util.h" #include "ios/web/public/deprecated/url_verification_constants.h" #import "ios/web/public/test/js_test_util.h" +#import "ios/web/public/test/task_observer_util.h" #import "ios/web/public/test/web_state_test_util.h" #import "ios/web/public/test/web_view_interaction_test_util.h" #import "ios/web/public/web_client.h" @@ -148,28 +149,7 @@ } void WebTestWithWebState::WaitForBackgroundTasks() { - // Because tasks can add new tasks to either queue, the loop continues until - // the first pass where no activity is seen from either queue. - bool activitySeen = false; - base::CurrentThread messageLoop = base::CurrentThread::Get(); - messageLoop->AddTaskObserver(this); - do { - activitySeen = false; - - // Yield to the iOS message queue, e.g. [NSObject performSelector:] events. - if (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true) == - kCFRunLoopRunHandledSource) - activitySeen = true; - - // Yield to the Chromium message queue, e.g. WebThread::PostTask() - // events. - processed_a_task_ = false; - base::RunLoop().RunUntilIdle(); - if (processed_a_task_) // Set in TaskObserver method. - activitySeen = true; - - } while (activitySeen); - messageLoop->RemoveTaskObserver(this); + web::test::WaitForBackgroundTasks(); } void WebTestWithWebState::WaitForCondition(ConditionBlock condition) { @@ -177,10 +157,7 @@ } bool WebTestWithWebState::WaitUntilLoaded() { - return WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^{ - WaitForBackgroundTasks(); - return !web_state()->IsLoading(); - }); + return web::test::WaitUntilLoaded(web_state()); } std::unique_ptr<base::Value> WebTestWithWebState::CallJavaScriptFunction( @@ -240,12 +217,4 @@ return web_state_.get(); } -void WebTestWithWebState::WillProcessTask(const base::PendingTask&, bool) { - // Nothing to do. -} - -void WebTestWithWebState::DidProcessTask(const base::PendingTask&) { - processed_a_task_ = true; -} - } // namespace web
diff --git a/ios/web/web_state/permissions_inttest.mm b/ios/web/web_state/permissions_inttest.mm new file mode 100644 index 0000000..e753d9c0 --- /dev/null +++ b/ios/web/web_state/permissions_inttest.mm
@@ -0,0 +1,411 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "base/test/ios/wait_util.h" +#include "base/test/scoped_feature_list.h" +#include "ios/testing/scoped_block_swizzler.h" +#include "ios/web/common/features.h" +#import "ios/web/public/navigation/navigation_manager.h" +#include "ios/web/public/navigation/reload_type.h" +#import "ios/web/public/permissions/permissions.h" +#import "ios/web/public/test/navigation_test_util.h" +#import "ios/web/public/web_state.h" +#include "ios/web/public/web_state_observer.h" +#import "ios/web/test/web_test_with_web_controller.h" +#import "ios/web/web_state/ui/crw_web_controller.h" +#import "ios/web/web_state/ui/crw_wk_ui_handler.h" +#import "ios/web/web_state/ui/crw_wk_ui_handler_delegate.h" +#include "net/test/embedded_test_server/embedded_test_server.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/gtest_mac.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +using base::test::ios::kWaitForPageLoadTimeout; + +namespace { + +// This is the timeout used to wait for the WKUIDelegate's decision handler +// block of the to respond to permissions requests. The web state's permission +// states would only update after the decision handler blocks responds, so all +// checks should be ran after this timeout. +const CGFloat kWebViewDecisionHandlingTimeout = 0.1; + +// Mocks WebStateObserver callbacks. +class WebStateObserverMock : public web::WebStateObserver { + public: + WebStateObserverMock() = default; + + WebStateObserverMock(const WebStateObserverMock&) = delete; + WebStateObserverMock& operator=(const WebStateObserverMock&) = delete; + + MOCK_METHOD2(PermissionStateChanged, void(web::WebState*, web::Permission)); + void WebStateDestroyed(web::WebState* web_state) override { NOTREACHED(); } +}; + +// Verifies that the current permission states matches expected. +ACTION_P3(VerifyPermissionState, web_state, permission, permission_state) { + EXPECT_EQ(web_state, arg0); + EXPECT_EQ(web_state->GetStateForPermission(permission), permission_state); +} + +} // namespace + +// Fake WKUIDelegate for WKWebView to override media permissions. +API_AVAILABLE(ios(15.0)) +@interface FakeCRWWKUIHandler : CRWWKUIHandler + +@property(nonatomic, assign) WKPermissionDecision decision; +@property(nonatomic, assign) BOOL decisionMade; + +@end + +@implementation FakeCRWWKUIHandler + +// Method for WKUIDelegate to allow media permissions when requested. +- (void)webView:(WKWebView*)webView + requestMediaCapturePermissionForOrigin:(WKSecurityOrigin*)origin + initiatedByFrame:(WKFrameInfo*)frame + type:(WKMediaCaptureType)type + decisionHandler: + (void (^)(WKPermissionDecision decision)) + decisionHandler { + decisionHandler(self.decision); + // Adds timeout to make sure self.decisionMade is set after the decision + // handler completes. + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, + kWebViewDecisionHandlingTimeout * NSEC_PER_SEC), + dispatch_get_main_queue(), ^{ + self.decisionMade = YES; + }); +} + +@end + +namespace web { + +// Tests fixture to test permissions handling for web state and its observer. +class PermissionsInttest : public WebTestWithWebController { + public: + void SetUp() override { + WebTestWithWebState::SetUp(); + if (@available(iOS 15.0, *)) { + // Turn on media permissions feature. + scoped_feature_list_.InitWithFeatures( + {features::kMediaPermissionsControl}, {}); + + // Switch actual objects to fakes/mocks for testing purposes. + handler_ = [[FakeCRWWKUIHandler alloc] init]; + handler_.delegate = (id<CRWWKUIHandlerDelegate>)web_controller(); + swizzler_ = std::make_unique<ScopedBlockSwizzler>( + [CRWWebController class], NSSelectorFromString(@"UIHandler"), ^{ + return handler_; + }); + + web_state()->AddObserver(&observer_); + + // Set up test server. + test_server_ = std::make_unique<net::EmbeddedTestServer>(); + test_server_->ServeFilesFromSourceDirectory( + base::FilePath("ios/testing/data/http_server_files/permissions")); + ASSERT_TRUE(test_server_->Start()); + } + } + + void TearDown() override { + web_state()->RemoveObserver(&observer_); + WebTestWithWebState::TearDown(); + } + + protected: + base::test::ScopedFeatureList scoped_feature_list_; + std::unique_ptr<ScopedBlockSwizzler> swizzler_; + std::unique_ptr<net::EmbeddedTestServer> test_server_; + testing::NiceMock<WebStateObserverMock> observer_; + FakeCRWWKUIHandler* handler_ API_AVAILABLE(ios(15.0)); +}; + +using base::test::ios::WaitUntilConditionOrTimeout; + +// Disabling tests on real devices as it would wait for a user to respond to +// "ios_web_inttests Would Like to Access the Camera" prompt. This is currently +// not supported by gtest. Related logic and behaviors would be tested on real +// devices in integration tests. +#if TARGET_OS_SIMULATOR + +// Tests that web state observer gets invoked for camera only when the website +// only requests for camera permissions and changed via web_state() setter +// API afterwards. +TEST_F(PermissionsInttest, + TestsThatPermissionStateChangedObserverInvokedForCameraOnly) { + if (@available(iOS 15.0, *)) { + EXPECT_CALL(observer_, + PermissionStateChanged(web_state(), PermissionCamera)) + .Times(testing::Exactly(2)) + .WillOnce(VerifyPermissionState(web_state(), PermissionCamera, + PermissionStateAllowed)); + EXPECT_CALL(observer_, + PermissionStateChanged(web_state(), PermissionMicrophone)) + .Times(0); + + // Initial load. + handler_.decision = WKPermissionDecisionGrant; + test::LoadUrl(web_state(), test_server_->GetURL("/camera_only.html")); + EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^bool { + return handler_.decisionMade; + })); + + // Update permission through web state API. + web_state()->SetStateForPermission(PermissionStateBlocked, + PermissionCamera); + EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^bool { + return web_state()->GetStateForPermission(PermissionCamera) == + PermissionStateBlocked; + })); + } +} + +// Tests that web state observer gets invoked for microphone only when the +// website only requests for microphone permissions and changed via web_state() +// setter API afterwards. +TEST_F(PermissionsInttest, + TestsThatPermissionStateChangedObserverInvokedForMicrophoneOnly) { + if (@available(iOS 15.0, *)) { + EXPECT_CALL(observer_, + PermissionStateChanged(web_state(), PermissionCamera)) + .Times(0); + EXPECT_CALL(observer_, + PermissionStateChanged(web_state(), PermissionMicrophone)) + .Times(testing::Exactly(2)) + .WillOnce(VerifyPermissionState(web_state(), PermissionMicrophone, + PermissionStateAllowed)); + + // Initial load. + handler_.decision = WKPermissionDecisionGrant; + test::LoadUrl(web_state(), test_server_->GetURL("/microphone_only.html")); + EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^bool { + return handler_.decisionMade; + })); + + // Update permission through web state API. + web_state()->SetStateForPermission(PermissionStateNotAccessible, + PermissionMicrophone); + EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^bool { + return web_state()->GetStateForPermission(PermissionMicrophone) == + PermissionStateNotAccessible; + })); + } +} + +// Tests that web state observer gets invoked for both camera and microphone, +// when both are requested by the web page and set via web_state() afterwards. +TEST_F(PermissionsInttest, + TestsThatPermissionStateChangedObserverInvokedForCameraAndMicrophone) { + if (@available(iOS 15.0, *)) { + EXPECT_CALL(observer_, + PermissionStateChanged(web_state(), PermissionCamera)) + .Times(testing::Exactly(2)) + .WillOnce(VerifyPermissionState(web_state(), PermissionCamera, + PermissionStateAllowed)); + EXPECT_CALL(observer_, + PermissionStateChanged(web_state(), PermissionMicrophone)) + .Times(testing::Exactly(1)) + .WillOnce(VerifyPermissionState(web_state(), PermissionMicrophone, + PermissionStateAllowed)); + + // Initial load. + handler_.decision = WKPermissionDecisionGrant; + test::LoadUrl(web_state(), + test_server_->GetURL("/camera_and_microphone.html")); + EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^bool { + return handler_.decisionMade; + })); + + // Only block one of them (camera in this case). + web_state()->SetStateForPermission(PermissionStateBlocked, + PermissionCamera); + EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^bool { + return web_state()->GetStateForPermission(PermissionCamera) == + PermissionStateBlocked; + })); + EXPECT_EQ(web_state()->GetStateForPermission(PermissionMicrophone), + PermissionStateAllowed); + } +} + +// Tests that web state observer should not be invoked when permission is +// denied. +TEST_F(PermissionsInttest, + TestsThatPermissionStateChangedObserverNotInvokedWhenPermissionDenied) { + if (@available(iOS 15.0, *)) { + EXPECT_CALL(observer_, + PermissionStateChanged(web_state(), PermissionCamera)) + .Times(0); + + handler_.decision = WKPermissionDecisionDeny; + test::LoadUrl(web_state(), test_server_->GetURL("/camera_only.html")); + EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^bool { + return handler_.decisionMade; + })); + EXPECT_EQ([web_controller() ensureWebViewCreated].cameraCaptureState, + WKMediaCaptureStateNone); + } +} + +// Tests that permission could not be manually altered if it has never been +// granted by WKUIDelegate in the first place. +TEST_F(PermissionsInttest, + TestsThatWebStateShouldNotAlterPermissionIfNotAccessible) { + if (@available(iOS 15.0, *)) { + handler_.decision = WKPermissionDecisionDeny; + test::LoadUrl(web_state(), test_server_->GetURL("/camera_only.html")); + EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^bool { + return handler_.decisionMade; + })); + web_state()->SetStateForPermission(PermissionStateAllowed, + PermissionCamera); + web_state()->SetStateForPermission(PermissionStateBlocked, + PermissionMicrophone); + // Neither permission should be changed. + EXPECT_FALSE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^bool { + // Camera permission asked but denied. + BOOL cameraPermissionChanged = + web_state()->GetStateForPermission(PermissionCamera) != + PermissionStateNotAccessible; + // Microphone permission never asked. + BOOL microphonePermissionChanged = + web_state()->GetStateForPermission(PermissionMicrophone) != + PermissionStateNotAccessible; + + return cameraPermissionChanged || microphonePermissionChanged; + })); + EXPECT_EQ([web_controller() ensureWebViewCreated].cameraCaptureState, + WKMediaCaptureStateNone); + EXPECT_EQ([web_controller() ensureWebViewCreated].microphoneCaptureState, + WKMediaCaptureStateNone); + } +} + +// Tests that page reload resets permission states. +TEST_F(PermissionsInttest, TestsThatPageReloadResetsPermissionState) { + if (@available(iOS 15.0, *)) { + // Initial load should allow permission. + handler_.decision = WKPermissionDecisionGrant; + test::LoadUrl(web_state(), test_server_->GetURL("/camera_only.html")); + EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^bool { + return web_state()->GetStateForPermission(PermissionCamera) == + PermissionStateAllowed; + })); + + // Reload should reset permission. Handler should be called again, and + // permission state should be NotAccessible. + handler_.decisionMade = NO; + handler_.decision = WKPermissionDecisionDeny; + web_state()->GetNavigationManager()->Reload(ReloadType::NORMAL, + /*check_for_repost=*/false); + EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^bool { + return web_state()->GetStateForPermission(PermissionCamera) == + PermissionStateNotAccessible; + })); + EXPECT_EQ([web_controller() ensureWebViewCreated].cameraCaptureState, + WKMediaCaptureStateNone); + } +} + +// Tests that the web state does not preserve permission states between +// navigations. +TEST_F(PermissionsInttest, TestsThatWebStateDoesNotPreservePermissionState) { + if (@available(iOS 15.0, *)) { + // Initial load should allow permission. + handler_.decision = WKPermissionDecisionGrant; + test::LoadUrl(web_state(), test_server_->GetURL("/camera_only.html")); + EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^bool { + return web_state()->GetStateForPermission(PermissionCamera) == + PermissionStateAllowed; + })); + + // Navigating to another page should reset permission. Handler should be + // called again, permission state should be NotAccessible and the observer + // should NOT be invoked. + handler_.decisionMade = NO; + handler_.decision = WKPermissionDecisionDeny; + test::LoadUrl(web_state(), + test_server_->GetURL("/camera_and_microphone.html")); + EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^bool { + return handler_.decisionMade && + web_state()->GetStateForPermission(PermissionCamera) == + PermissionStateNotAccessible; + })); + EXPECT_EQ([web_controller() ensureWebViewCreated].cameraCaptureState, + WKMediaCaptureStateNone); + EXPECT_EQ([web_controller() ensureWebViewCreated].microphoneCaptureState, + WKMediaCaptureStateNone); + } +} + +// Tests that hitting "go back" and "go forward" resets permission states for +// pages with existing accessible permission states. +TEST_F(PermissionsInttest, + TestsThatMovingBackwardOrForwardResetsPermissionState) { + if (@available(iOS 15.0, *)) { + // Initial load for both pages should allow permission. + handler_.decision = WKPermissionDecisionGrant; + test::LoadUrl(web_state(), test_server_->GetURL("/microphone_only.html")); + EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^bool { + return web_state()->GetStateForPermission(PermissionMicrophone) == + PermissionStateAllowed; + })); + test::LoadUrl(web_state(), + test_server_->GetURL("/camera_and_microphone.html")); + EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^bool { + return web_state()->GetStateForPermission(PermissionCamera) == + PermissionStateAllowed && + web_state()->GetStateForPermission(PermissionMicrophone) == + PermissionStateAllowed; + })); + // To cover more cases, block microphone on the second page. + web_state()->SetStateForPermission(PermissionStateBlocked, + PermissionMicrophone); + EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^bool { + return [web_controller() ensureWebViewCreated].microphoneCaptureState == + WKMediaCaptureStateMuted; + })); + + // Permissions should be reset when you go backward or forward. + + // Note: There's currently an existing WebKit bug that WKUIDelegate method + // |requestMediaCapturePermissionForOrigin:| would not be invoked when the + // user hits backward/forward; instead, iOS sets them automatically to + // WKMediaCaptureStateNone. The two following lines of code should be + // uncommented when this is fixed. + + // handler_.decisionMade = NO; + // handler_.decision = WKPermissionDecisionDeny; + web_state()->GetNavigationManager()->GoBack(); + EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^bool { + return web_state()->GetStateForPermission(PermissionMicrophone) == + PermissionStateNotAccessible; + })); + EXPECT_EQ([web_controller() ensureWebViewCreated].microphoneCaptureState, + WKMediaCaptureStateNone); + + web_state()->GetNavigationManager()->GoForward(); + EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^bool { + return web_state()->GetStateForPermission(PermissionCamera) == + PermissionStateNotAccessible && + web_state()->GetStateForPermission(PermissionMicrophone) == + PermissionStateNotAccessible; + })); + EXPECT_EQ([web_controller() ensureWebViewCreated].cameraCaptureState, + WKMediaCaptureStateNone); + EXPECT_EQ([web_controller() ensureWebViewCreated].microphoneCaptureState, + WKMediaCaptureStateNone); + } +} +#endif // TARGET_OS_SIMULATOR + +} // namespace web
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm index 2e04aeb..07bd108c 100644 --- a/ios/web/web_state/ui/crw_web_controller.mm +++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -481,15 +481,13 @@ }]; } -#if defined(__IPHONE_15_4) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_15_4 - if (@available(iOS 15, *)) { + if (@available(iOS 15.4, *)) { if (base::FeatureList::IsEnabled(web::features::kEnableFullscreenAPI)) { [observers addEntriesFromDictionary:@{ @"fullscreenState" : @"fullscreenStateDidChange" }]; } } -#endif // defined(__IPHONE_15_4) return observers; } @@ -1501,6 +1499,25 @@ } } +#if defined(__IPHONE_15_4) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_15_4 +CrFullscreenState CrFullscreenStateFromWKFullscreenState( + WKFullscreenState state) API_AVAILABLE(ios(15.4)) { + switch (state) { + case WKFullscreenStateEnteringFullscreen: + return CrFullscreenState::kEnteringFullscreen; + case WKFullscreenStateExitingFullscreen: + return CrFullscreenState::kExitingFullscreen; + case WKFullscreenStateInFullscreen: + return CrFullscreenState::kInFullscreen; + case WKFullscreenStateNotInFullscreen: + return CrFullscreenState::kNotInFullScreen; + default: + NOTREACHED(); + return CrFullscreenState::kNotInFullScreen; + } +} +#endif // defined (__IPHONE_15_4) + #pragma mark - Security Helpers - (void)updateSSLStatusForCurrentNavigationItem { @@ -1649,14 +1666,18 @@ CRWWebViewContentView* webViewContentView = [[CRWWebViewContentView alloc] initWithWebView:self.webView scrollView:self.webScrollView - fullscreenState:self.webView.fullscreenState]; + fullscreenState:CrFullscreenStateFromWKFullscreenState( + self.webView.fullscreenState)]; [_containerView displayWebViewContentView:webViewContentView]; return; } #endif // defined(__IPHONE_15_4) - CRWWebViewContentView* webViewContentView = - [[CRWWebViewContentView alloc] initWithWebView:self.webView - scrollView:self.webScrollView]; + + CRWWebViewContentView* webViewContentView = [[CRWWebViewContentView alloc] + initWithWebView:self.webView + scrollView:self.webScrollView + fullscreenState:CrFullscreenState::kNotInFullScreen]; + [_containerView displayWebViewContentView:webViewContentView]; } @@ -1817,12 +1838,15 @@ self.webStateImpl->OnStateChangedForPermission(web::PermissionMicrophone); } +- (void)fullscreenStateDidChange { #if defined(__IPHONE_15_4) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_15_4 -- (void)fullscreenStateDidChange API_AVAILABLE(ios(15.0)) { - [_containerView - updateWebViewContentViewFullscreenState:self.webView.fullscreenState]; -} + if (@available(iOS 15.4, *)) { + [_containerView updateWebViewContentViewFullscreenState: + CrFullscreenStateFromWKFullscreenState( + self.webView.fullscreenState)]; + } #endif // defined (__IPHONE_15_4) +} #pragma mark - CRWWebViewHandlerDelegate
diff --git a/ios/web/web_state/ui/crw_web_controller_container_view.h b/ios/web/web_state/ui/crw_web_controller_container_view.h index a2e2b785..01f374e 100644 --- a/ios/web/web_state/ui/crw_web_controller_container_view.h +++ b/ios/web/web_state/ui/crw_web_controller_container_view.h
@@ -69,11 +69,9 @@ // doesn't suspend it's counterpart process. - (void)updateWebViewContentViewForContainerWindow:(UIWindow*)window; -#if defined(__IPHONE_15_4) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_15_4 // Updates |webViewContentView| with the current fullscreen state - (void)updateWebViewContentViewFullscreenState: - (WKFullscreenState)fullscreenState API_AVAILABLE(ios(15)); -#endif // defined(__IPHONE_15_4) + (CrFullscreenState)fullscreenState; @end
diff --git a/ios/web/web_state/ui/crw_web_controller_container_view.mm b/ios/web/web_state/ui/crw_web_controller_container_view.mm index 811bd2d..db12ab1 100644 --- a/ios/web/web_state/ui/crw_web_controller_container_view.mm +++ b/ios/web/web_state/ui/crw_web_controller_container_view.mm
@@ -149,15 +149,11 @@ [self setNeedsLayout]; } -#if defined(__IPHONE_15_4) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_15_4 - (void)updateWebViewContentViewFullscreenState: - (WKFullscreenState)fullscreenState { + (CrFullscreenState)fullscreenState { DCHECK(_webViewContentView); - if (@available(iOS 15.4, *)) { - [self.webViewContentView updateFullscreenState:fullscreenState]; - } + [self.webViewContentView updateFullscreenState:fullscreenState]; } -#endif // defined(__IPHONE_15_4) #pragma mark UIView (printing)
diff --git a/ios/web/web_state/ui/crw_web_view_content_view_unittest.mm b/ios/web/web_state/ui/crw_web_view_content_view_unittest.mm index def046b..63d2477 100644 --- a/ios/web/web_state/ui/crw_web_view_content_view_unittest.mm +++ b/ios/web/web_state/ui/crw_web_view_content_view_unittest.mm
@@ -24,9 +24,10 @@ UIView* webView = [[UIView alloc] init]; UIScrollView* scrollView = [[UIScrollView alloc] init]; [webView addSubview:scrollView]; - CRWWebViewContentView* contentView = - [[CRWWebViewContentView alloc] initWithWebView:webView - scrollView:scrollView]; + CRWWebViewContentView* contentView = [[CRWWebViewContentView alloc] + initWithWebView:webView + scrollView:scrollView + fullscreenState:CrFullscreenState::kNotInFullScreen]; contentView.shouldUseViewContentInset = YES; const UIEdgeInsets contentInset = UIEdgeInsetsMake(10, 10, 10, 10);
diff --git a/media/gpu/v4l2/BUILD.gn b/media/gpu/v4l2/BUILD.gn index 837b0ba..65e5f58 100644 --- a/media/gpu/v4l2/BUILD.gn +++ b/media/gpu/v4l2/BUILD.gn
@@ -147,6 +147,8 @@ executable("v4l2_stateless_decoder") { testonly = true sources = [ + "test/av1_decoder.cc", + "test/av1_decoder.h", "test/v4l2_ioctl_shim.cc", "test/v4l2_ioctl_shim.h", "test/v4l2_stateless_decoder.cc",
diff --git a/media/gpu/v4l2/test/av1_decoder.cc b/media/gpu/v4l2/test/av1_decoder.cc new file mode 100644 index 0000000..d5c1301 --- /dev/null +++ b/media/gpu/v4l2/test/av1_decoder.cc
@@ -0,0 +1,78 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/gpu/v4l2/test/av1_decoder.h" + +#include "base/logging.h" +#include "base/memory/ptr_util.h" +#include "media/filters/ivf_parser.h" + +namespace media { + +namespace v4l2_test { + +Av1Decoder::Av1Decoder(std::unique_ptr<IvfParser> ivf_parser, + std::unique_ptr<V4L2IoctlShim> v4l2_ioctl, + std::unique_ptr<V4L2Queue> OUTPUT_queue, + std::unique_ptr<V4L2Queue> CAPTURE_queue) + : VideoDecoder::VideoDecoder(std::move(ivf_parser), + std::move(v4l2_ioctl), + std::move(OUTPUT_queue), + std::move(CAPTURE_queue)) {} + +Av1Decoder::~Av1Decoder() = default; + +// static +std::unique_ptr<Av1Decoder> Av1Decoder::Create( + std::unique_ptr<IvfParser> ivf_parser, + const media::IvfFileHeader& file_header) { + auto v4l2_ioctl = std::make_unique<V4L2IoctlShim>(); + + constexpr uint32_t kDriverCodecFourcc = V4L2_PIX_FMT_AV1_FRAME; + + // MM21 is an uncompressed opaque format that is produced by MediaTek + // video decoders. + constexpr uint32_t kUncompressedFourcc = v4l2_fourcc('M', 'M', '2', '1'); + + // TODO(stevecho): this might need some driver patches to support AV1F + if (!v4l2_ioctl->VerifyCapabilities(kDriverCodecFourcc, + kUncompressedFourcc)) { + LOG(ERROR) << "Device doesn't support the provided FourCCs."; + return nullptr; + } + + LOG(INFO) << "Ivf file header: " << file_header.width << " x " + << file_header.height; + + // TODO(stevecho): might need to consider using more than 1 file descriptor + // (fd) & buffer with the output queue for 4K60 requirement. + // https://buganizer.corp.google.com/issues/202214561#comment31 + auto OUTPUT_queue = std::make_unique<V4L2Queue>( + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, kDriverCodecFourcc, + gfx::Size(file_header.width, file_header.height), /*num_planes=*/1, + V4L2_MEMORY_MMAP, /*num_buffers=*/1); + + // TODO(stevecho): enable V4L2_MEMORY_DMABUF memory for CAPTURE queue. + // |num_planes| represents separate memory buffers, not planes for Y, U, V. + // https://www.kernel.org/doc/html/v5.16/userspace-api/media/v4l/pixfmt-v4l2-mplane.html#c.V4L.v4l2_plane_pix_format + auto CAPTURE_queue = std::make_unique<V4L2Queue>( + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, kUncompressedFourcc, + gfx::Size(file_header.width, file_header.height), /*num_planes=*/2, + V4L2_MEMORY_MMAP, /*num_buffers=*/10); + + return base::WrapUnique( + new Av1Decoder(std::move(ivf_parser), std::move(v4l2_ioctl), + std::move(OUTPUT_queue), std::move(CAPTURE_queue))); +} + +VideoDecoder::Result Av1Decoder::DecodeNextFrame(std::vector<char>& y_plane, + std::vector<char>& u_plane, + std::vector<char>& v_plane, + gfx::Size& size, + const int frame_number) { + return VideoDecoder::kOk; +} + +} // namespace v4l2_test +} // namespace media
diff --git a/media/gpu/v4l2/test/av1_decoder.h b/media/gpu/v4l2/test/av1_decoder.h new file mode 100644 index 0000000..9c2ba1ab --- /dev/null +++ b/media/gpu/v4l2/test/av1_decoder.h
@@ -0,0 +1,64 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_GPU_V4L2_TEST_AV1_DECODER_H_ +#define MEDIA_GPU_V4L2_TEST_AV1_DECODER_H_ + +#include "media/gpu/v4l2/test/v4l2_ioctl_shim.h" +#include "media/gpu/v4l2/test/video_decoder.h" + +#include "media/filters/ivf_parser.h" + +// TODO(stevecho): This is temporary until the change to define +// V4L2_PIX_FMT_AV1_FRAME lands in videodev2.h. +// https://patchwork.linuxtv.org/project/linux-media/patch/20210810220552.298140-2-daniel.almeida@collabora.com/ +#ifndef V4L2_PIX_FMT_AV1 +#define V4L2_PIX_FMT_AV1 v4l2_fourcc('A', 'V', '0', '1') /* AV1 */ +#endif +#ifndef V4L2_PIX_FMT_AV1_FRAME +#define V4L2_PIX_FMT_AV1_FRAME \ + v4l2_fourcc('A', 'V', '1', 'F') /* AV1 parsed frame \ + */ +#endif + +namespace media { + +class IvfParser; + +namespace v4l2_test { + +// A Av1Decoder decodes AV1-encoded IVF streams using v4l2 ioctl calls. +class Av1Decoder : public VideoDecoder { + public: + Av1Decoder(const Av1Decoder&) = delete; + Av1Decoder& operator=(const Av1Decoder&) = delete; + ~Av1Decoder() override; + + // Creates a Av1Decoder after verifying that the underlying implementation + // supports AV1 stateless decoding. + static std::unique_ptr<Av1Decoder> Create( + std::unique_ptr<IvfParser> ivf_parser, + const media::IvfFileHeader& file_header); + + // TODO(stevecho): implement DecodeNextFrame() function + // Parses next frame from IVF stream and decodes the frame. This method will + // place the Y, U, and V values into the respective vectors and update the + // size with the display area size of the decoded frame. + VideoDecoder::Result DecodeNextFrame(std::vector<char>& y_plane, + std::vector<char>& u_plane, + std::vector<char>& v_plane, + gfx::Size& size, + const int frame_number) override; + + private: + Av1Decoder(std::unique_ptr<IvfParser> ivf_parser, + std::unique_ptr<V4L2IoctlShim> v4l2_ioctl, + std::unique_ptr<V4L2Queue> OUTPUT_queue, + std::unique_ptr<V4L2Queue> CAPTURE_queue); +}; + +} // namespace v4l2_test +} // namespace media + +#endif // MEDIA_GPU_V4L2_TEST_AV1_DECODER_H_
diff --git a/media/gpu/v4l2/test/v4l2_stateless_decoder.cc b/media/gpu/v4l2/test/v4l2_stateless_decoder.cc index dddb16a..fbe3784c 100644 --- a/media/gpu/v4l2/test/v4l2_stateless_decoder.cc +++ b/media/gpu/v4l2/test/v4l2_stateless_decoder.cc
@@ -17,9 +17,11 @@ #include "base/strings/stringprintf.h" #include "media/base/video_types.h" #include "media/filters/ivf_parser.h" +#include "media/gpu/v4l2/test/av1_decoder.h" #include "media/gpu/v4l2/test/video_decoder.h" #include "media/gpu/v4l2/test/vp9_decoder.h" +using media::v4l2_test::Av1Decoder; using media::v4l2_test::VideoDecoder; using media::v4l2_test::Vp9Decoder; @@ -38,7 +40,7 @@ constexpr char kHelpMsg[] = "This binary decodes the IVF video in <video> path with specified \n" "video <profile> via thinly wrapped v4l2 calls.\n" - "Supported codecs: VP9 (profile 0)\n" + "Supported codecs: VP9 (profile 0), and AV1 (profile 0)\n" "\nThe following arguments are supported:\n" " --video=<path>\n" " Required. Path to IVF-formatted video to decode.\n" @@ -63,13 +65,17 @@ } // namespace // For stateless API, fourcc |VP9F| is needed instead of |VP90| for VP9 codec. +// Fourcc |AV1F| is needed instead of |AV10| for AV1 codec. // https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/pixfmt-compressed.html -// Converts fourcc |VP90| from file header to fourcc |VP9F|, which is -// a format supported on driver. +// Converts fourcc |VP90| or |AV01| from file header to fourcc |VP9F| or |AV1F|, +// which is a format supported on driver. uint32_t FileFourccToDriverFourcc(uint32_t header_fourcc) { if (header_fourcc == V4L2_PIX_FMT_VP9) { LOG(INFO) << "OUTPUT format mapped from VP90 to VP9F."; return V4L2_PIX_FMT_VP9_FRAME; + } else if (header_fourcc == V4L2_PIX_FMT_AV1) { + LOG(INFO) << "OUTPUT format mapped from AV01 to AV1F."; + return V4L2_PIX_FMT_AV1_FRAME; } return header_fourcc; @@ -85,7 +91,7 @@ // Creates the appropriate decoder for |stream|, which points to IVF data. // Returns nullptr on failure. -std::unique_ptr<VideoDecoder> CreateVp9Decoder( +std::unique_ptr<VideoDecoder> CreateVideoDecoder( const base::MemoryMappedFile& stream) { CHECK(stream.IsValid()); @@ -102,17 +108,18 @@ VLOG(1) << "Creating decoder with codec " << media::FourccToString(file_header.fourcc); - LOG_ASSERT(file_header.fourcc == v4l2_fourcc('V', 'P', '9', '0')) - << "Codec " << media::FourccToString(file_header.fourcc) - << " not supported." << kUsageMsg; - const auto driver_codec_fourcc = FileFourccToDriverFourcc(file_header.fourcc); - CHECK_EQ(driver_codec_fourcc, V4L2_PIX_FMT_VP9_FRAME) - << "Only VP9 is supported, got: " - << media::FourccToString(driver_codec_fourcc); + if (driver_codec_fourcc == V4L2_PIX_FMT_AV1_FRAME) { + return Av1Decoder::Create(std::move(ivf_parser), file_header); + } else if (driver_codec_fourcc == V4L2_PIX_FMT_VP9_FRAME) { + return Vp9Decoder::Create(std::move(ivf_parser), file_header); + } - return Vp9Decoder::Create(std::move(ivf_parser), file_header); + LOG(ERROR) << "Codec " << media::FourccToString(file_header.fourcc) + << " not supported.\n" + << kUsageMsg; + return nullptr; } int main(int argc, char** argv) { @@ -152,12 +159,11 @@ if (!stream.Initialize(video_path)) LOG(FATAL) << "Couldn't open file: " << video_path; - const std::unique_ptr<VideoDecoder> dec = CreateVp9Decoder(stream); + const std::unique_ptr<VideoDecoder> dec = CreateVideoDecoder(stream); if (!dec) LOG(FATAL) << "Failed to create decoder for file: " << video_path; - if (!dec->Initialize()) - LOG(FATAL) << "Initialization for decoding failed."; + dec->Initialize(); for (int i = 0; i < n_frames || n_frames == 0; i++) { LOG(INFO) << "Frame " << i << "...";
diff --git a/media/gpu/v4l2/test/video_decoder.cc b/media/gpu/v4l2/test/video_decoder.cc index d53bac166..deaad7db 100644 --- a/media/gpu/v4l2/test/video_decoder.cc +++ b/media/gpu/v4l2/test/video_decoder.cc
@@ -20,19 +20,19 @@ VideoDecoder::~VideoDecoder() = default; -bool VideoDecoder::Initialize() { +void VideoDecoder::Initialize() { // TODO(stevecho): remove VIDIOC_ENUM_FRAMESIZES ioctl call // after b/193237015 is resolved. if (!v4l2_ioctl_->EnumFrameSizes(OUTPUT_queue_->fourcc())) - LOG(ERROR) << "EnumFrameSizes for OUTPUT queue failed."; + LOG(FATAL) << "EnumFrameSizes for OUTPUT queue failed."; if (!v4l2_ioctl_->SetFmt(OUTPUT_queue_)) - LOG(ERROR) << "SetFmt for OUTPUT queue failed."; + LOG(FATAL) << "SetFmt for OUTPUT queue failed."; gfx::Size coded_size; uint32_t num_planes; if (!v4l2_ioctl_->GetFmt(CAPTURE_queue_->type(), &coded_size, &num_planes)) - LOG(ERROR) << "GetFmt for CAPTURE queue failed."; + LOG(FATAL) << "GetFmt for CAPTURE queue failed."; CAPTURE_queue_->set_coded_size(coded_size); CAPTURE_queue_->set_num_planes(num_planes); @@ -43,41 +43,39 @@ // Chromium V4L2VideoDecoder backend, see b/190733055#comment78. // TODO(b/190733055): try and remove it after landing all the code. if (!v4l2_ioctl_->TryFmt(CAPTURE_queue_)) - LOG(ERROR) << "TryFmt for CAPTURE queue failed."; + LOG(FATAL) << "TryFmt for CAPTURE queue failed."; if (!v4l2_ioctl_->SetFmt(CAPTURE_queue_)) - LOG(ERROR) << "SetFmt for CAPTURE queue failed."; + LOG(FATAL) << "SetFmt for CAPTURE queue failed."; if (!v4l2_ioctl_->ReqBufs(OUTPUT_queue_)) - LOG(ERROR) << "ReqBufs for OUTPUT queue failed."; + LOG(FATAL) << "ReqBufs for OUTPUT queue failed."; if (!v4l2_ioctl_->QueryAndMmapQueueBuffers(OUTPUT_queue_)) - LOG(ERROR) << "QueryAndMmapQueueBuffers for OUTPUT queue failed"; + LOG(FATAL) << "QueryAndMmapQueueBuffers for OUTPUT queue failed"; if (!v4l2_ioctl_->ReqBufs(CAPTURE_queue_)) - LOG(ERROR) << "ReqBufs for CAPTURE queue failed."; + LOG(FATAL) << "ReqBufs for CAPTURE queue failed."; if (!v4l2_ioctl_->QueryAndMmapQueueBuffers(CAPTURE_queue_)) - LOG(ERROR) << "QueryAndMmapQueueBuffers for CAPTURE queue failed."; + LOG(FATAL) << "QueryAndMmapQueueBuffers for CAPTURE queue failed."; // Only 1 CAPTURE buffer is needed for 1st key frame decoding. Remaining // CAPTURE buffers will be queued after that. if (!v4l2_ioctl_->QBuf(CAPTURE_queue_, 0)) - LOG(ERROR) << "VIDIOC_QBUF failed for CAPTURE queue."; + LOG(FATAL) << "VIDIOC_QBUF failed for CAPTURE queue."; int media_request_fd; if (!v4l2_ioctl_->MediaIocRequestAlloc(&media_request_fd)) - LOG(ERROR) << "MEDIA_IOC_REQUEST_ALLOC failed"; + LOG(FATAL) << "MEDIA_IOC_REQUEST_ALLOC failed"; OUTPUT_queue_->set_media_request_fd(media_request_fd); if (!v4l2_ioctl_->StreamOn(OUTPUT_queue_->type())) - LOG(ERROR) << "StreamOn for OUTPUT queue failed."; + LOG(FATAL) << "StreamOn for OUTPUT queue failed."; if (!v4l2_ioctl_->StreamOn(CAPTURE_queue_->type())) - LOG(ERROR) << "StreamOn for CAPTURE queue failed."; - - return true; + LOG(FATAL) << "StreamOn for CAPTURE queue failed."; } } // namespace v4l2_test
diff --git a/media/gpu/v4l2/test/video_decoder.h b/media/gpu/v4l2/test/video_decoder.h index 518f51cd..a87b60e6 100644 --- a/media/gpu/v4l2/test/video_decoder.h +++ b/media/gpu/v4l2/test/video_decoder.h
@@ -35,12 +35,9 @@ VideoDecoder(const VideoDecoder&) = delete; VideoDecoder& operator=(const VideoDecoder&) = delete; - // TODO(stevecho): consider void return type instead - // This function only ever returns true, even if an error occurs. - // Initializes setup needed for decoding. // https://www.kernel.org/doc/html/v5.10/userspace-api/media/v4l/dev-stateless-decoder.html#initialization - bool Initialize(); + void Initialize(); virtual Result DecodeNextFrame(std::vector<char>& y_plane, std::vector<char>& u_plane,
diff --git a/media/gpu/v4l2/test/vp9_decoder.cc b/media/gpu/v4l2/test/vp9_decoder.cc index bffe223..76116e9 100644 --- a/media/gpu/v4l2/test/vp9_decoder.cc +++ b/media/gpu/v4l2/test/vp9_decoder.cc
@@ -539,7 +539,7 @@ OUTPUT_queue_->GetBuffer(0)->set_frame_number(frame_number); if (!v4l2_ioctl_->QBuf(OUTPUT_queue_, 0)) - LOG(ERROR) << "VIDIOC_QBUF failed for OUTPUT queue."; + LOG(FATAL) << "VIDIOC_QBUF failed for OUTPUT queue."; struct v4l2_ctrl_vp9_frame_decode_params v4l2_frame_params; memset(&v4l2_frame_params, 0, sizeof(v4l2_frame_params)); @@ -547,15 +547,15 @@ SetupFrameParams(frame_hdr, &v4l2_frame_params); if (!v4l2_ioctl_->SetExtCtrls(OUTPUT_queue_, v4l2_frame_params)) - LOG(ERROR) << "VIDIOC_S_EXT_CTRLS failed."; + LOG(FATAL) << "VIDIOC_S_EXT_CTRLS failed."; if (!v4l2_ioctl_->MediaRequestIocQueue(OUTPUT_queue_)) - LOG(ERROR) << "MEDIA_REQUEST_IOC_QUEUE failed."; + LOG(FATAL) << "MEDIA_REQUEST_IOC_QUEUE failed."; uint32_t index; if (!v4l2_ioctl_->DQBuf(CAPTURE_queue_, &index)) - LOG(ERROR) << "VIDIOC_DQBUF failed for CAPTURE queue."; + LOG(FATAL) << "VIDIOC_DQBUF failed for CAPTURE queue."; scoped_refptr<MmapedBuffer> buffer = CAPTURE_queue_->GetBuffer(index); CHECK_EQ(buffer->mmaped_planes().size(), 2u) @@ -591,7 +591,7 @@ } if (!v4l2_ioctl_->DQBuf(OUTPUT_queue_, &index)) - LOG(ERROR) << "VIDIOC_DQBUF failed for OUTPUT queue."; + LOG(FATAL) << "VIDIOC_DQBUF failed for OUTPUT queue."; // TODO(stevecho): With current VP9 API, VIDIOC_G_EXT_CTRLS ioctl call is // needed when forward probabilities update is used. With new VP9 API landing @@ -599,7 +599,7 @@ // https://lwn.net/Articles/855419/ if (!v4l2_ioctl_->MediaRequestIocReinit(OUTPUT_queue_)) - LOG(ERROR) << "MEDIA_REQUEST_IOC_REINIT failed."; + LOG(FATAL) << "MEDIA_REQUEST_IOC_REINIT failed."; return Vp9Decoder::kOk; }
diff --git a/media/gpu/v4l2/test/vp9_decoder.h b/media/gpu/v4l2/test/vp9_decoder.h index 336e357..9c478372 100644 --- a/media/gpu/v4l2/test/vp9_decoder.h +++ b/media/gpu/v4l2/test/vp9_decoder.h
@@ -25,7 +25,7 @@ public: Vp9Decoder(const Vp9Decoder&) = delete; Vp9Decoder& operator=(const Vp9Decoder&) = delete; - ~Vp9Decoder(); + ~Vp9Decoder() override; // Creates a Vp9Decoder after verifying that the underlying implementation // supports VP9 stateless decoding.
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc index 2aefaab..40c19e8 100644 --- a/pdf/pdfium/pdfium_engine.cc +++ b/pdf/pdfium/pdfium_engine.cc
@@ -48,7 +48,6 @@ #include "pdf/pdfium/pdfium_mem_buffer_file_write.h" #include "pdf/pdfium/pdfium_permissions.h" #include "pdf/pdfium/pdfium_unsupported_features.h" -#include "pdf/ppapi_migration/bitmap.h" #include "pdf/ppapi_migration/url_loader.h" #include "pdf/url_loader_wrapper_impl.h" #include "printing/mojom/print.mojom-shared.h"
diff --git a/services/network/sct_auditing/sct_auditing_handler.cc b/services/network/sct_auditing/sct_auditing_handler.cc index 8fdbe98a..9e90a94 100644 --- a/services/network/sct_auditing/sct_auditing_handler.cc +++ b/services/network/sct_auditing/sct_auditing_handler.cc
@@ -359,7 +359,7 @@ // processes can fail to report metrics during shutdown). The timer should // only be running if SCT auditing is enabled. if (mode != mojom::SCTAuditingMode::kDisabled) { - histogram_timer_.Start(FROM_HERE, base::Hours(1), this, + histogram_timer_.Start(FROM_HERE, hwm_metrics_period_, this, &SCTAuditingHandler::ReportHWMMetrics); } else { histogram_timer_.Stop();
diff --git a/services/network/sct_auditing/sct_auditing_handler.h b/services/network/sct_auditing/sct_auditing_handler.h index 7b21c36..df604d7 100644 --- a/services/network/sct_auditing/sct_auditing_handler.h +++ b/services/network/sct_auditing/sct_auditing_handler.h
@@ -126,6 +126,10 @@ base::ImportantFileWriter* GetFileWriterForTesting() { return writer_.get(); } + void set_hwm_metrics_period_for_testing(base::TimeDelta hwm_metrics_period) { + hwm_metrics_period_ = hwm_metrics_period; + } + base::WeakPtr<SCTAuditingHandler> GetWeakPtr(); private: @@ -162,6 +166,9 @@ bool is_after_startup_ = false; bool persisted_reports_read_ = false; + // How often the high-water-mark metrics get logged. + base::TimeDelta hwm_metrics_period_ = base::Hours(1); + base::WeakPtrFactory<SCTAuditingHandler> weak_factory_{this}; };
diff --git a/services/network/sct_auditing/sct_auditing_handler_unittest.cc b/services/network/sct_auditing/sct_auditing_handler_unittest.cc index 54782c7..be7ee5c1 100644 --- a/services/network/sct_auditing/sct_auditing_handler_unittest.cc +++ b/services/network/sct_auditing/sct_auditing_handler_unittest.cc
@@ -52,6 +52,8 @@ constexpr base::TimeDelta kTestLogMMD = base::Seconds(42); +constexpr base::TimeDelta kTestHWMPeriod = base::Seconds(1); + class SCTAuditingHandlerTest : public testing::Test { public: SCTAuditingHandlerTest() @@ -64,6 +66,7 @@ void SetUp() override { ASSERT_TRUE(persistence_dir_.CreateUniqueTempDir()); persistence_path_ = persistence_dir_.GetPath().AppendASCII("SCT Auditing"); + SCTAuditingReporter::SetRetryDelayForTesting(base::TimeDelta()); // Set up a NetworkContext. mojom::NetworkContextParamsPtr context_params = @@ -110,6 +113,7 @@ handler_ = std::make_unique<SCTAuditingHandler>(network_context_.get(), persistence_path_); + handler_->set_hwm_metrics_period_for_testing(kTestHWMPeriod); handler_->SetMode(mojom::SCTAuditingMode::kEnhancedSafeBrowsingReporting); mojo::PendingRemote<network::mojom::URLLoaderFactory> factory_remote; @@ -253,6 +257,10 @@ // Tests when the report server returns an HTTP error code. TEST_F(SCTAuditingHandlerTest, ReportSentWithServerError) { + // Set a long retry delay to allow inspecting the handler between an error and + // resending the report. + SCTAuditingReporter::SetRetryDelayForTesting(base::Seconds(1)); + // Enqueue a report which will trigger a send. const net::HostPortPair host_port_pair("example.com", 443); net::SignedCertificateTimestampAndStatusList sct_list; @@ -434,19 +442,19 @@ /*content=*/"", /*status=*/net::HTTP_TOO_MANY_REQUESTS); - EXPECT_EQ(0, url_loader_factory_.NumPending()); + // The retry timer is set to zero, so a retry should have been scheduled + // already. + EXPECT_EQ(1, url_loader_factory_.NumPending()); + // With retry enabled, the pending reporter should remain on failure. EXPECT_EQ(1u, handler_->GetPendingReportersForTesting()->size()); - // Simulate the server returning 200 OK to the report request. The request is - // not yet pending, so set the "default" response. Then when - // FastForwardUntilNoTasksRemain() is called, the retry will trigger and - // succeed. This is more robust than manually advancing the mock time due to - // the jitter specified by the backoff policy and the timeout set on the - // SimpleURLLoader. - url_loader_factory_.AddResponse("https://example.test", - /*content=*/"", - /*status=*/net::HTTP_OK); + // Simulate the server returning 200 OK to the report request. + url_loader_factory_.SimulateResponseForPendingRequest( + "https://example.test", + /*content=*/"", + /*status=*/net::HTTP_OK); + // Wait for second request. WaitForRequests(2u); @@ -529,29 +537,22 @@ base::HistogramTester histograms; // Send two reports. - // Use the NetworkContext's handler to avoid repeating histograms. - handler_.reset(); const net::HostPortPair host_port_pair("example.com", 443); net::SignedCertificateTimestampAndStatusList sct_list1; MakeTestSCTAndStatus(net::ct::SignedCertificateTimestamp::SCT_EMBEDDED, "extensions1", "signature1", base::Time::Now(), net::ct::SCT_STATUS_OK, &sct_list1); - network_context_->sct_auditing_handler()->MaybeEnqueueReport( - host_port_pair, chain_.get(), sct_list1); + handler_->MaybeEnqueueReport(host_port_pair, chain_.get(), sct_list1); net::SignedCertificateTimestampAndStatusList sct_list2; MakeTestSCTAndStatus(net::ct::SignedCertificateTimestamp::SCT_EMBEDDED, "extensions2", "signature2", base::Time::Now(), net::ct::SCT_STATUS_OK, &sct_list2); - network_context_->sct_auditing_handler()->MaybeEnqueueReport( - host_port_pair, chain_.get(), sct_list2); + handler_->MaybeEnqueueReport(host_port_pair, chain_.get(), sct_list2); - EXPECT_EQ(2u, network_context_->sct_auditing_handler() - ->GetPendingReportersForTesting() - ->size()); + EXPECT_EQ(2u, handler_->GetPendingReportersForTesting()->size()); - // High-water-mark metrics are recorded once an hour. - task_environment_.FastForwardBy(base::Hours(1)); + task_environment_.FastForwardBy(kTestHWMPeriod); // The bucket for a HWM of 2 should have a single sample. histograms.ExpectUniqueSample("Security.SCTAuditing.OptIn.ReportersHWM", 2,
diff --git a/sql/database.cc b/sql/database.cc index 0b75c2e..ddf132c 100644 --- a/sql/database.cc +++ b/sql/database.cc
@@ -1756,23 +1756,25 @@ int Database::OnSqliteError(int sqlite_error_code, sql::Statement* statement, - const char* sql) const { + const char* sql_statement) { TRACE_EVENT0("sql", "Database::OnSqliteError"); + DCHECK_NE(statement != nullptr, sql_statement != nullptr) + << "OnSqliteError() should either get a Statement or a raw SQL string"; + bool is_expected_error = IsExpectedSqliteError(sqlite_error_code); if (!is_expected_error) { // Log unexpected errors. - if (!sql && statement) - sql = statement->GetSQLStatement(); - if (!sql) - sql = "(SQL unknown)"; + if (statement) + sql_statement = statement->GetSQLStatement(); + DCHECK(sql_statement); std::string id = histogram_tag_; if (id.empty()) id = DbPath().BaseName().AsUTF8Unsafe(); LOG(ERROR) << id << " SQLite error: code " << sqlite_error_code << " errno " << GetLastErrno() << ": " << GetErrorMessage() - << " sql: " << sql; + << " sql: " << sql_statement; } if (!error_callback_.is_null()) {
diff --git a/sql/database.h b/sql/database.h index c20f07fe..5d8f1604 100644 --- a/sql/database.h +++ b/sql/database.h
@@ -718,17 +718,28 @@ void StatementRefCreated(StatementRef* ref); void StatementRefDeleted(StatementRef* ref); - // Called when a sqlite function returns an error, which is passed - // as |err|. The return value is the error code to be reflected - // back to client code. |stmt| is non-null if the error relates to - // an sql::Statement instance. |sql| is non-nullptr if the error - // relates to non-statement sql code (Execute, for instance). Both - // can be null, but both should never be set. + // Used by sql:: internals to report a SQLite error related to this database. + // + // `sqlite_error_code` contains the error code reported by SQLite. Possible + // values are documented at https://www.sqlite.org/rescode.html + // + // `statement` is non-null if the error is associated with a sql::Statement. + // Otherwise, `sql_statement` will be a non-null string pointing to a + // statically-allocated (valid for the entire duration of the process) buffer + // pointing to either a SQL statement or a SQL comment (starting with "-- ") + // pointing to a "sqlite3_" function name. + // + // This method always returns a valid SQLite error code, which is passed to + // the users of the sql:: method that encountered the SQLite error. This + // gives OnSqliteError() the ability to translate / mask SQLite errors. + // // NOTE(shess): Originally, the return value was intended to allow // error handlers to transparently convert errors into success. // Unfortunately, transactions are not generally restartable, so // this did not work out. - int OnSqliteError(int err, Statement* stmt, const char* sql) const; + int OnSqliteError(int sqlite_error_code, + Statement* statement, + const char* sql_statement); // Like Execute(), but returns the error code given by SQLite. //
diff --git a/testing/libfuzzer/fuzzers/javascript_parser_proto_fuzzer.cc b/testing/libfuzzer/fuzzers/javascript_parser_proto_fuzzer.cc index 0f050d5..e891ca5 100644 --- a/testing/libfuzzer/fuzzers/javascript_parser_proto_fuzzer.cc +++ b/testing/libfuzzer/fuzzers/javascript_parser_proto_fuzzer.cc
@@ -30,9 +30,9 @@ // Explicitly specify some attributes to avoid issues with the linker dead- // stripping the following function on macOS, as it is not called directly // by fuzz target. LibFuzzer runtime uses dlsym() to resolve that function. -#if V8_OS_MACOSX +#if V8_OS_MACOS __attribute__((used)) __attribute__((visibility("default"))) -#endif // V8_OS_MACOSX +#endif // V8_OS_MACOS extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { v8::V8::InitializeICUDefaultLocation((*argv)[0]);
diff --git a/testing/rust_gtest_interop/BUILD.gn b/testing/rust_gtest_interop/BUILD.gn index b5e27b3..823fc0f 100644 --- a/testing/rust_gtest_interop/BUILD.gn +++ b/testing/rust_gtest_interop/BUILD.gn
@@ -57,7 +57,6 @@ "//testing/gtest", ] - rs_crate_root = "rust_gtest_interop_unittest.rs" rs_sources = [ "rust_gtest_interop_unittest.rs" ] } }
diff --git a/testing/rust_gtest_interop/README.md b/testing/rust_gtest_interop/README.md index 9b96dda3..dd1cc2a 100644 --- a/testing/rust_gtest_interop/README.md +++ b/testing/rust_gtest_interop/README.md
@@ -22,9 +22,9 @@ } ``` -To add a Rust file to the test suite, simply add it to the `rs_sources`, and to -the _crate root_. If this is the first Rust file being added, then you will have -to write the crate root as well. +To add a Rust file to the test suite, simply add it to the `rs_sources`. Unlike +other Rust crates, the `crate_root` is not specified, since it is generated from +the sources list. `BUILD.gn`: ```gn @@ -34,27 +34,14 @@ "another_cpp_file.cc", ] rs_sources = [ - "some_unittests.rs", "a_rust_file.rs", ] - crate_root = "some_unittests.rs" deps = [ "//testing/gtest", ] } ``` -The crate root is named after the unit test target. In this case, it is -`some_unittests.rs`. The file just lists the modules in the test suite. By -default the test files are expected to be in the crate root's directory, but you -can use the `#[path]` attribute to add tests in subdirectories too. - -`some_unittests.rs`: -```rs -#[path = "a_rust_file.rs"] -mod a_rust_file; -``` - ## To write a Gtest unit test in Rust To write a unit test, you simply write a function an decorate it with the @@ -131,3 +118,24 @@ Ok(()) } ``` + +### Shared helper utilities + +Sometimes tests across different test files want to share helper utilities. Such +helpers should be placed in a separate GN target, typically named with a +`_test_support` suffix, such as `starship_test_support` for the +`starship_unittests`. And would also usually be found in a `test/` subdirectory. + +#### Example +The `starship_unittests` test() target would include any unit test files, such as +`starship_unittest.rs`. And the `starship_test_support` static_library() target +would include the files in the `test/` subdirectory, such as +`starship_test_helper.rs` and `starship_test_things.rs`. +``` +src/ + starship/ + starship_unittest.rs + test/ + starship_test_helper.rs + starship_test_things.rs +```
diff --git a/testing/test.gni b/testing/test.gni index fc7644f94..a7682c6 100644 --- a/testing/test.gni +++ b/testing/test.gni
@@ -59,6 +59,10 @@ } rs_configs += [ "//build/rust:test" ] + # The crate_root is generated and should not be specified. + assert(!defined(rs_crate_root)) + rs_generate_crate_root = true + # We could automatically add `rs_deps += [ "//testing/rust_gtest_interop" ]` # if `rs_sources` is non-empty. But we don't automatically provide # //testing/gtest either so it would be asymmetric and could break in that
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index d852f6b3..b9f527ba 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -2553,12 +2553,13 @@ ], "experiments": [ { - "name": "RecipeTasksRuleBasedDiscountDrivePhotos_Enabled", + "name": "RecipeTasksRuleBasedDiscountDriveManagedUsersPhotos_Enabled", "params": { "NtpChromeCartModuleAbandonedCartDiscountParam": "true", "NtpChromeCartModuleAbandonedCartDiscountUseUtmParam": "true", "NtpChromeCartModuleHeuristicsImprovementParam": "true", "NtpDriveModuleExperimentGroupParam": "foo:bar", + "NtpDriveModuleManagedUsersOnlyParam": "true", "NtpModulesLoadTimeoutMillisecondsParam": "3000", "NtpModulesOrderParam": "", "discount-fetch-delay": "1h" @@ -5280,6 +5281,24 @@ ] } ], + "PasswordsCapabilitiesFetching": [ + { + "platforms": [ + "android" + ], + "experiments": [ + { + "name": "Enabled_20220217", + "params": { + "live_experiment": "true" + }, + "enable_features": [ + "PasswordDomainCapabilitiesFetching" + ] + } + ] + } + ], "Path2DPaintCache": [ { "platforms": [
diff --git a/third_party/.gitignore b/third_party/.gitignore index 68c4328..629b1f6 100644 --- a/third_party/.gitignore +++ b/third_party/.gitignore
@@ -12,9 +12,6 @@ /amd/ /android_build_tools/aapt2/aapt2 /android_build_tools/aapt2/lib64/*.so -/android_build_tools/art/dexlayout -/android_build_tools/art/lib/*.so -/android_build_tools/art/profman /android_build_tools/bundletool/*.jar /android_ndk/ /android_prebuilts/build_tools
diff --git a/third_party/android_build_tools/art/DIR_METADATA b/third_party/android_build_tools/art/DIR_METADATA deleted file mode 100644 index c914ddc4..0000000 --- a/third_party/android_build_tools/art/DIR_METADATA +++ /dev/null
@@ -1,5 +0,0 @@ -monorail { - component: "Build" -} - -team_email: "build@chromium.org"
diff --git a/third_party/android_build_tools/art/NOTICE b/third_party/android_build_tools/art/NOTICE deleted file mode 100644 index 6d357b0..0000000 --- a/third_party/android_build_tools/art/NOTICE +++ /dev/null
@@ -1,189 +0,0 @@ - Copyright (c) 2005-2008, The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS -
diff --git a/third_party/android_build_tools/art/OWNERS b/third_party/android_build_tools/art/OWNERS deleted file mode 100644 index db1598a..0000000 --- a/third_party/android_build_tools/art/OWNERS +++ /dev/null
@@ -1,3 +0,0 @@ -agrieve@chromium.org -lizeb@chromium.org -mheikal@chromium.org
diff --git a/third_party/android_build_tools/art/README.chromium b/third_party/android_build_tools/art/README.chromium deleted file mode 100644 index cf8bcc11..0000000 --- a/third_party/android_build_tools/art/README.chromium +++ /dev/null
@@ -1,26 +0,0 @@ -Name: Android ART build utilities -Short name: art -Version: unknown -URL: repo init -u persistent-https://googleplex-android.git.corp.google.com/platform/manifest -b master-art-host -Revision hash: goog/master:35a39d95a55457aa8d2217f6bb2682b0641d68f1 -Security Critical: no -License: Apache Version 2.0 -License file: NOT_SHIPPED - -Description: -The Chrome build process uses ART host binaries to perform DEX file -layout. These are not shipped as part of any SDK and so are built manually -from the ART source tree and included here. The URL line above gives the -repo command necessary to download the source tree. The branch and revision -used to build the tools is given in the revision hash (goog/master is the -standard tip-of-tree branch you get using the given repo command). See -https://sites.google.com/a/google.com/dalvik/getting-started-on-dalvik/getting-source -for more information. - -The tool source is located in the art/ project, eg -art/dexlayout and art/profman and the binaries are copied from the build -directory out/host/linux-x86/bin/. The lib/ directory is copied from the -build directory out/host/linux-x86/lib64/ - -Local Modifications: -None
diff --git a/third_party/android_build_tools/art/cipd.yaml b/third_party/android_build_tools/art/cipd.yaml deleted file mode 100644 index 8ef9247..0000000 --- a/third_party/android_build_tools/art/cipd.yaml +++ /dev/null
@@ -1,12 +0,0 @@ -# Copyright 2018 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. - -# To create CIPD package run the following command. -# cipd create --pkg-def cipd.yaml -package: chromium/third_party/android_build_tools/art -description: Android ART build utilities -data: - - file: dexlayout - - file: profman - - dir: "lib"
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc index 5a4389e..6ffdbb8 100644 --- a/third_party/blink/common/features.cc +++ b/third_party/blink/common/features.cc
@@ -1318,5 +1318,9 @@ const base::Feature kUserAgentOverrideExperiment{ "UserAgentOverrideExperiment", base::FEATURE_DISABLED_BY_DEFAULT}; +// Allow access to WebSQL APIs. +const base::Feature kWebSQLAccess{"kWebSQLAccess", + base::FEATURE_ENABLED_BY_DEFAULT}; + } // namespace features } // namespace blink
diff --git a/third_party/blink/common/link_to_text/link_to_text_mojom_traits.cc b/third_party/blink/common/link_to_text/link_to_text_mojom_traits.cc index 379f68f..6299f71 100644 --- a/third_party/blink/common/link_to_text/link_to_text_mojom_traits.cc +++ b/third_party/blink/common/link_to_text/link_to_text_mojom_traits.cc
@@ -41,6 +41,8 @@ return blink::mojom::LinkGenerationError::kBlockList; case shared_highlighting::LinkGenerationError::kNoRemoteConnection: return blink::mojom::LinkGenerationError::kNoRemoteConnection; + case shared_highlighting::LinkGenerationError::kNotGenerated: + return blink::mojom::LinkGenerationError::kNotGenerated; } NOTREACHED(); @@ -97,6 +99,9 @@ case blink::mojom::LinkGenerationError::kNoRemoteConnection: *output = shared_highlighting::LinkGenerationError::kNoRemoteConnection; return true; + case blink::mojom::LinkGenerationError::kNotGenerated: + *output = shared_highlighting::LinkGenerationError::kNotGenerated; + return true; } NOTREACHED();
diff --git a/third_party/blink/common/metrics/post_message_counter.cc b/third_party/blink/common/metrics/post_message_counter.cc index a422eae..71d848c4 100644 --- a/third_party/blink/common/metrics/post_message_counter.cc +++ b/third_party/blink/common/metrics/post_message_counter.cc
@@ -13,11 +13,13 @@ namespace blink { -void PostMessageCounter::RecordMessage(ukm::SourceId source, - ukm::SourceId target, +void PostMessageCounter::RecordMessage(ukm::SourceId source_id, + const StorageKey& source_storage_key, + ukm::SourceId target_id, + const StorageKey& target_storage_key, ukm::UkmRecorder* recorder) { DCHECK_LE(recorded_posts_.size(), kMaxRecordedPostsSize); - std::pair<ukm::SourceId, ukm::SourceId> new_pair(source, target); + std::pair<ukm::SourceId, ukm::SourceId> new_pair(source_id, target_id); if (base::Contains(recorded_posts_, new_pair)) return; @@ -27,20 +29,96 @@ switch (partition_) { case PostMessagePartition::kCrossProcess: { - ukm::builders::PostMessage_Incoming_Page builder(target); - if (source != ukm::kInvalidSourceId) - builder.SetSourcePageSourceId(source); + ukm::builders::PostMessage_Incoming_Page builder(target_id); + builder.SetSourcePageSourceId(source_id); builder.Record(recorder); break; } case PostMessagePartition::kSameProcess: { - ukm::builders::PostMessage_Incoming_Frame builder(target); - if (source != ukm::kInvalidSourceId) - builder.SetSourceFrameSourceId(source); + ukm::builders::PostMessage_Incoming_Frame builder(target_id); + builder.SetSourceFrameSourceId(source_id); builder.Record(recorder); break; } } + + // We want these storage keys to behave as though storage partitioning is on + // for convenience. + StorageKey source_3psp_key = + source_storage_key.CopyWithForceEnabledThirdPartyStoragePartitioning(); + StorageKey target_3psp_key = + target_storage_key.CopyWithForceEnabledThirdPartyStoragePartitioning(); + if (source_3psp_key.origin().opaque() || + source_3psp_key.top_level_site().opaque() || + target_3psp_key.origin().opaque() || + target_3psp_key.top_level_site().opaque()) { + ukm::builders::PostMessage_Incoming_Opaque builder(target_id); + builder.SetSourceFrameSourceId(source_id); + builder.Record(recorder); + } else if (source_3psp_key.IsFirstPartyContext() && + target_3psp_key.IsFirstPartyContext()) { + if (source_3psp_key == target_3psp_key) { + ukm::builders::PostMessage_Incoming_FirstPartyToFirstParty_SameBucket + builder(target_id); + builder.SetSourceFrameSourceId(source_id); + builder.Record(recorder); + } else { + ukm::builders::PostMessage_Incoming_FirstPartyToFirstParty_DifferentBucket + builder(target_id); + builder.SetSourceFrameSourceId(source_id); + builder.Record(recorder); + } + } else if (source_3psp_key.IsFirstPartyContext() && + target_3psp_key.IsThirdPartyContext()) { + if (source_3psp_key.origin() == target_3psp_key.origin()) { + ukm::builders:: + PostMessage_Incoming_FirstPartyToThirdParty_DifferentBucket_SameOrigin + builder(target_id); + builder.SetSourceFrameSourceId(source_id); + builder.Record(recorder); + } else { + ukm::builders:: + PostMessage_Incoming_FirstPartyToThirdParty_DifferentBucket_DifferentOrigin + builder(target_id); + builder.SetSourceFrameSourceId(source_id); + builder.Record(recorder); + } + } else if (source_3psp_key.IsThirdPartyContext() && + target_3psp_key.IsFirstPartyContext()) { + if (source_3psp_key.origin() == target_3psp_key.origin()) { + ukm::builders:: + PostMessage_Incoming_ThirdPartyToFirstParty_DifferentBucket_SameOrigin + builder(target_id); + builder.SetSourceFrameSourceId(source_id); + builder.Record(recorder); + } else { + ukm::builders:: + PostMessage_Incoming_ThirdPartyToFirstParty_DifferentBucket_DifferentOrigin + builder(target_id); + builder.SetSourceFrameSourceId(source_id); + builder.Record(recorder); + } + } else if (source_3psp_key.IsThirdPartyContext() && + target_3psp_key.IsThirdPartyContext()) { + if (source_3psp_key == target_3psp_key) { + ukm::builders::PostMessage_Incoming_ThirdPartyToThirdParty_SameBucket + builder(target_id); + builder.SetSourceFrameSourceId(source_id); + builder.Record(recorder); + } else if (source_3psp_key.origin() == target_3psp_key.origin()) { + ukm::builders:: + PostMessage_Incoming_ThirdPartyToThirdParty_DifferentBucket_SameOrigin + builder(target_id); + builder.SetSourceFrameSourceId(source_id); + builder.Record(recorder); + } else { + ukm::builders:: + PostMessage_Incoming_ThirdPartyToThirdParty_DifferentBucket_DifferentOrigin + builder(target_id); + builder.SetSourceFrameSourceId(source_id); + builder.Record(recorder); + } + } } } // namespace blink
diff --git a/third_party/blink/common/metrics/post_message_counter_unittest.cc b/third_party/blink/common/metrics/post_message_counter_unittest.cc index 6968443..e3a1e59 100644 --- a/third_party/blink/common/metrics/post_message_counter_unittest.cc +++ b/third_party/blink/common/metrics/post_message_counter_unittest.cc
@@ -5,7 +5,6 @@ #include "third_party/blink/public/common/metrics/post_message_counter.h" #include "components/ukm/test_ukm_recorder.h" -#include "services/metrics/public/cpp/ukm_source_id.h" #include "testing/gtest/include/gtest/gtest.h" namespace blink { @@ -21,68 +20,43 @@ ukm::TestUkmRecorder recorder_; }; -TEST_F(PostMessageCounterTest, UsageWithValidSourceIds) { +TEST_F(PostMessageCounterTest, UsageWithoutStorageKey) { // Initial state check EXPECT_EQ(recorder_.entries_count(), 0u); EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Frame").size(), 0u); + EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Opaque").size(), + 0u); EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Page").size(), 0u); // Check frame counter state - frame_counter_.RecordMessage(1, 2, &recorder_); - EXPECT_EQ(recorder_.entries_count(), 1u); + frame_counter_.RecordMessage(1, blink::StorageKey(), 2, blink::StorageKey(), + &recorder_); + EXPECT_EQ(recorder_.entries_count(), 2u); EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Frame").size(), 1u); EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Frame")[0] ->metrics.size(), 1u); + EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Opaque").size(), + 1u); EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Page").size(), 0u); // Check page counter state - page_counter_.RecordMessage(1, 2, &recorder_); - EXPECT_EQ(recorder_.entries_count(), 2u); - EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Frame").size(), - 1u); - EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Frame")[0] - ->metrics.size(), - 1u); - EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Page").size(), 1u); - EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Page")[0] - ->metrics.size(), - 1u); -} - -TEST_F(PostMessageCounterTest, UsageWithInvalidSourceIds) { - // Initial state check - EXPECT_EQ(recorder_.entries_count(), 0u); - EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Frame").size(), - 0u); - EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Page").size(), 0u); - - // Check frame counter state (and verify metrics are empty) - frame_counter_.RecordMessage(ukm::kInvalidSourceId, ukm::kInvalidSourceId, - &recorder_); - EXPECT_EQ(recorder_.entries_count(), 1u); - EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Frame").size(), - 1u); - EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Frame")[0] - ->metrics.size(), - 0u); - EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Page").size(), 0u); - - // Check page counter state (and verify metrics are empty) - page_counter_.RecordMessage(ukm::kInvalidSourceId, ukm::kInvalidSourceId, + page_counter_.RecordMessage(1, blink::StorageKey(), 2, blink::StorageKey(), &recorder_); - EXPECT_EQ(recorder_.entries_count(), 2u); + EXPECT_EQ(recorder_.entries_count(), 4u); EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Frame").size(), 1u); EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Frame")[0] ->metrics.size(), - 0u); + 1u); + EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Opaque").size(), + 2u); EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Page").size(), 1u); EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Page")[0] ->metrics.size(), - 0u); + 1u); } TEST_F(PostMessageCounterTest, UsageWithDeduplicationRecall) { @@ -90,34 +64,48 @@ EXPECT_EQ(recorder_.entries_count(), 0u); EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Frame").size(), 0u); + EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Opaque").size(), + 0u); EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Page").size(), 0u); // Check frame counter state after first bump - frame_counter_.RecordMessage(1, 2, &recorder_); - EXPECT_EQ(recorder_.entries_count(), 1u); + frame_counter_.RecordMessage(1, blink::StorageKey(), 2, blink::StorageKey(), + &recorder_); + EXPECT_EQ(recorder_.entries_count(), 2u); EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Frame").size(), 1u); + EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Opaque").size(), + 1u); EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Page").size(), 0u); // Check frame counter state after second bump - frame_counter_.RecordMessage(1, 2, &recorder_); - EXPECT_EQ(recorder_.entries_count(), 1u); + frame_counter_.RecordMessage(1, blink::StorageKey(), 2, blink::StorageKey(), + &recorder_); + EXPECT_EQ(recorder_.entries_count(), 2u); EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Frame").size(), 1u); + EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Opaque").size(), + 1u); EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Page").size(), 0u); // Check page counter state after first bump - page_counter_.RecordMessage(1, 2, &recorder_); - EXPECT_EQ(recorder_.entries_count(), 2u); + page_counter_.RecordMessage(1, blink::StorageKey(), 2, blink::StorageKey(), + &recorder_); + EXPECT_EQ(recorder_.entries_count(), 4u); EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Frame").size(), 1u); + EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Opaque").size(), + 2u); EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Page").size(), 1u); // Check page counter state after second bump - page_counter_.RecordMessage(1, 2, &recorder_); - EXPECT_EQ(recorder_.entries_count(), 2u); + page_counter_.RecordMessage(1, blink::StorageKey(), 2, blink::StorageKey(), + &recorder_); + EXPECT_EQ(recorder_.entries_count(), 4u); EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Frame").size(), 1u); + EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Opaque").size(), + 2u); EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Page").size(), 1u); } @@ -126,53 +114,299 @@ EXPECT_EQ(recorder_.entries_count(), 0u); EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Frame").size(), 0u); + EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Opaque").size(), + 0u); EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Page").size(), 0u); // Check frame counter state after first bump - frame_counter_.RecordMessage(1, 2, &recorder_); - EXPECT_EQ(recorder_.entries_count(), 1u); + frame_counter_.RecordMessage(1, blink::StorageKey(), 2, blink::StorageKey(), + &recorder_); + EXPECT_EQ(recorder_.entries_count(), 2u); EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Frame").size(), 1u); + EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Opaque").size(), + 1u); EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Page").size(), 0u); // Bump frame counter twenty times - for (int i = 0; i < 20; i++) - frame_counter_.RecordMessage(i + 2, i + 3, &recorder_); - EXPECT_EQ(recorder_.entries_count(), 21u); + for (int i = 0; i < 20; i++) { + frame_counter_.RecordMessage(i + 2, blink::StorageKey(), i + 3, + blink::StorageKey(), &recorder_); + } + EXPECT_EQ(recorder_.entries_count(), 42u); EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Frame").size(), 21u); + EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Opaque").size(), + 21u); EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Page").size(), 0u); // Check frame counter state with same source and target as first bump - frame_counter_.RecordMessage(1, 2, &recorder_); - EXPECT_EQ(recorder_.entries_count(), 22u); + frame_counter_.RecordMessage(1, blink::StorageKey(), 2, blink::StorageKey(), + &recorder_); + EXPECT_EQ(recorder_.entries_count(), 44u); EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Frame").size(), 22u); + EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Opaque").size(), + 22u); EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Page").size(), 0u); // Check page counter state after first bump - page_counter_.RecordMessage(1, 2, &recorder_); - EXPECT_EQ(recorder_.entries_count(), 23u); + page_counter_.RecordMessage(1, blink::StorageKey(), 2, blink::StorageKey(), + &recorder_); + EXPECT_EQ(recorder_.entries_count(), 46u); EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Frame").size(), 22u); + EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Opaque").size(), + 23u); EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Page").size(), 1u); // Bump page counter twenty times - for (int i = 0; i < 20; i++) - page_counter_.RecordMessage(i + 2, i + 3, &recorder_); - EXPECT_EQ(recorder_.entries_count(), 43u); + for (int i = 0; i < 20; i++) { + page_counter_.RecordMessage(i + 2, blink::StorageKey(), i + 3, + blink::StorageKey(), &recorder_); + } + EXPECT_EQ(recorder_.entries_count(), 86u); EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Frame").size(), 22u); + EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Opaque").size(), + 43u); EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Page").size(), 21u); // Check page counter state with same source and target as first bump - page_counter_.RecordMessage(1, 2, &recorder_); - EXPECT_EQ(recorder_.entries_count(), 44u); + page_counter_.RecordMessage(1, blink::StorageKey(), 2, blink::StorageKey(), + &recorder_); + EXPECT_EQ(recorder_.entries_count(), 88u); EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Frame").size(), 22u); + EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Opaque").size(), + 44u); EXPECT_EQ(recorder_.GetEntriesByName("PostMessage.Incoming.Page").size(), 22u); } +TEST_F(PostMessageCounterTest, FirstPartyToFirstPartyDifferentBucket) { + // Initial state check + EXPECT_EQ(recorder_.entries_count(), 0u); + EXPECT_EQ( + recorder_ + .GetEntriesByName( + "PostMessage.Incoming.FirstPartyToFirstParty.DifferentBucket") + .size(), + 0u); + + // Check storage key counter state + frame_counter_.RecordMessage( + 1, blink::StorageKey(url::Origin::Create(GURL("https://foo.com/"))), 2, + blink::StorageKey(url::Origin::Create(GURL("https://bar.com/"))), + &recorder_); + EXPECT_EQ(recorder_.entries_count(), 2u); + EXPECT_EQ( + recorder_ + .GetEntriesByName( + "PostMessage.Incoming.FirstPartyToFirstParty.DifferentBucket") + .size(), + 1u); +} + +TEST_F(PostMessageCounterTest, FirstPartyToFirstPartySameBucket) { + // Initial state check + EXPECT_EQ(recorder_.entries_count(), 0u); + EXPECT_EQ(recorder_ + .GetEntriesByName( + "PostMessage.Incoming.FirstPartyToFirstParty.SameBucket") + .size(), + 0u); + + // Check storage key counter state + frame_counter_.RecordMessage( + 1, blink::StorageKey(url::Origin::Create(GURL("https://foo.com/"))), 2, + blink::StorageKey(url::Origin::Create(GURL("https://foo.com/"))), + &recorder_); + EXPECT_EQ(recorder_.entries_count(), 2u); + EXPECT_EQ(recorder_ + .GetEntriesByName( + "PostMessage.Incoming.FirstPartyToFirstParty.SameBucket") + .size(), + 1u); +} + +TEST_F(PostMessageCounterTest, + FirstPartyToThirdPartyDifferentBucketDifferentOrigin) { + // Initial state check + EXPECT_EQ(recorder_.entries_count(), 0u); + EXPECT_EQ(recorder_ + .GetEntriesByName("PostMessage.Incoming.FirstPartyToThirdParty." + "DifferentBucket.DifferentOrigin") + .size(), + 0u); + + // Check storage key counter state + frame_counter_.RecordMessage( + 1, blink::StorageKey(url::Origin::Create(GURL("https://foo.com/"))), 2, + blink::StorageKey(url::Origin::Create(GURL("https://qux.com/")), + url::Origin::Create(GURL("https://bar.com/"))), + &recorder_); + EXPECT_EQ(recorder_.entries_count(), 2u); + EXPECT_EQ(recorder_ + .GetEntriesByName("PostMessage.Incoming.FirstPartyToThirdParty." + "DifferentBucket.DifferentOrigin") + .size(), + 1u); +} + +TEST_F(PostMessageCounterTest, + FirstPartyToThirdPartyDifferentBucketSameOrigin) { + // Initial state check + EXPECT_EQ(recorder_.entries_count(), 0u); + EXPECT_EQ(recorder_ + .GetEntriesByName("PostMessage.Incoming.FirstPartyToThirdParty." + "DifferentBucket.SameOrigin") + .size(), + 0u); + + // Check storage key counter state + frame_counter_.RecordMessage( + 1, blink::StorageKey(url::Origin::Create(GURL("https://foo.com/"))), 2, + blink::StorageKey(url::Origin::Create(GURL("https://foo.com/")), + url::Origin::Create(GURL("https://qux.com/"))), + &recorder_); + EXPECT_EQ(recorder_.entries_count(), 2u); + EXPECT_EQ(recorder_ + .GetEntriesByName("PostMessage.Incoming.FirstPartyToThirdParty." + "DifferentBucket.SameOrigin") + .size(), + 1u); +} + +TEST_F(PostMessageCounterTest, + ThirdPartyToFirstPartyDifferentBucketDifferentOrigin) { + // Initial state check + EXPECT_EQ(recorder_.entries_count(), 0u); + EXPECT_EQ(recorder_ + .GetEntriesByName("PostMessage.Incoming.ThirdPartyToFirstParty." + "DifferentBucket.DifferentOrigin") + .size(), + 0u); + + // Check storage key counter state + frame_counter_.RecordMessage( + 1, + blink::StorageKey(url::Origin::Create(GURL("https://qux.com/")), + url::Origin::Create(GURL("https://bar.com/"))), + 2, blink::StorageKey(url::Origin::Create(GURL("https://foo.com/"))), + &recorder_); + EXPECT_EQ(recorder_.entries_count(), 2u); + EXPECT_EQ(recorder_ + .GetEntriesByName("PostMessage.Incoming.ThirdPartyToFirstParty." + "DifferentBucket.DifferentOrigin") + .size(), + 1u); +} + +TEST_F(PostMessageCounterTest, + ThirdPartyToFirstPartyDifferentBucketSameOrigin) { + // Initial state check + EXPECT_EQ(recorder_.entries_count(), 0u); + EXPECT_EQ(recorder_ + .GetEntriesByName("PostMessage.Incoming.ThirdPartyToFirstParty." + "DifferentBucket.SameOrigin") + .size(), + 0u); + + // Check storage key counter state + frame_counter_.RecordMessage( + 1, + blink::StorageKey(url::Origin::Create(GURL("https://foo.com/")), + url::Origin::Create(GURL("https://qux.com/"))), + 2, blink::StorageKey(url::Origin::Create(GURL("https://foo.com/"))), + &recorder_); + EXPECT_EQ(recorder_.entries_count(), 2u); + EXPECT_EQ(recorder_ + .GetEntriesByName("PostMessage.Incoming.ThirdPartyToFirstParty." + "DifferentBucket.SameOrigin") + .size(), + 1u); +} + +TEST_F(PostMessageCounterTest, + ThirdPartyToThirdPartyDifferentBucketDifferentOrigin) { + // Initial state check + EXPECT_EQ(recorder_.entries_count(), 0u); + EXPECT_EQ(recorder_ + .GetEntriesByName("PostMessage.Incoming.ThirdPartyToThirdParty." + "DifferentBucket.DifferentOrigin") + .size(), + 0u); + + // Check storage key counter state + frame_counter_.RecordMessage( + 1, + blink::StorageKey(url::Origin::Create(GURL("https://foo.com/")), + url::Origin::Create(GURL("https://qux.com/"))), + 2, + blink::StorageKey(url::Origin::Create(GURL("https://bar.com/")), + url::Origin::Create(GURL("https://qux.com/"))), + &recorder_); + EXPECT_EQ(recorder_.entries_count(), 2u); + EXPECT_EQ(recorder_ + .GetEntriesByName("PostMessage.Incoming.ThirdPartyToThirdParty." + "DifferentBucket.DifferentOrigin") + .size(), + 1u); +} + +TEST_F(PostMessageCounterTest, + ThirdPartyToThirdPartyDifferentBucketSameOrigin) { + // Initial state check + EXPECT_EQ(recorder_.entries_count(), 0u); + EXPECT_EQ(recorder_ + .GetEntriesByName("PostMessage.Incoming.ThirdPartyToThirdParty." + "DifferentBucket.SameOrigin") + .size(), + 0u); + + // Check storage key counter state + frame_counter_.RecordMessage( + 1, + blink::StorageKey(url::Origin::Create(GURL("https://foo.com/")), + url::Origin::Create(GURL("https://qux.com/"))), + 2, + blink::StorageKey(url::Origin::Create(GURL("https://foo.com/")), + url::Origin::Create(GURL("https://bar.com/"))), + &recorder_); + EXPECT_EQ(recorder_.entries_count(), 2u); + EXPECT_EQ(recorder_ + .GetEntriesByName("PostMessage.Incoming.ThirdPartyToThirdParty." + "DifferentBucket.SameOrigin") + .size(), + 1u); +} + +TEST_F(PostMessageCounterTest, ThirdPartyToThirdPartySameBucket) { + // Initial state check + EXPECT_EQ(recorder_.entries_count(), 0u); + EXPECT_EQ(recorder_ + .GetEntriesByName("PostMessage.Incoming.ThirdPartyToThirdParty." + "SameBucket") + .size(), + 0u); + + // Check storage key counter state + frame_counter_.RecordMessage( + 1, + blink::StorageKey(url::Origin::Create(GURL("https://foo.com/")), + url::Origin::Create(GURL("https://bar.com/"))), + 2, + blink::StorageKey(url::Origin::Create(GURL("https://foo.com/")), + url::Origin::Create(GURL("https://bar.com/"))), + &recorder_); + EXPECT_EQ(recorder_.entries_count(), 2u); + EXPECT_EQ(recorder_ + .GetEntriesByName("PostMessage.Incoming.ThirdPartyToThirdParty." + "SameBucket") + .size(), + 1u); +} + } // namespace blink
diff --git a/third_party/blink/common/storage_key/storage_key_unittest.cc b/third_party/blink/common/storage_key/storage_key_unittest.cc index 6d192754..a0e77c9 100644 --- a/third_party/blink/common/storage_key/storage_key_unittest.cc +++ b/third_party/blink/common/storage_key/storage_key_unittest.cc
@@ -710,4 +710,26 @@ } } +TEST(StorageKeyTest, CopyWithForceEnabledThirdPartyStoragePartitioning) { + const url::Origin kOrigin = url::Origin::Create(GURL("https://foo.com")); + const url::Origin kOtherOrigin = url::Origin::Create(GURL("https://bar.com")); + + for (const bool toggle : {false, true}) { + base::test::ScopedFeatureList scope_feature_list; + scope_feature_list.InitWithFeatureState( + features::kThirdPartyStoragePartitioning, toggle); + + const StorageKey storage_key(kOrigin, kOtherOrigin); + EXPECT_EQ(storage_key.IsThirdPartyContext(), toggle); + EXPECT_EQ(storage_key.top_level_site(), + net::SchemefulSite(toggle ? kOtherOrigin : kOrigin)); + + const StorageKey storage_key_with_3psp = + storage_key.CopyWithForceEnabledThirdPartyStoragePartitioning(); + EXPECT_TRUE(storage_key_with_3psp.IsThirdPartyContext()); + EXPECT_EQ(storage_key_with_3psp.top_level_site(), + net::SchemefulSite(kOtherOrigin)); + } +} + } // namespace blink
diff --git a/third_party/blink/common/switches.cc b/third_party/blink/common/switches.cc index c8a2594..6e56aaf 100644 --- a/third_party/blink/common/switches.cc +++ b/third_party/blink/common/switches.cc
@@ -138,5 +138,8 @@ // Specifies the flags passed to JS engine. const char kJavaScriptFlags[] = "js-flags"; +// Controls whether WebSQL is force enabled. +const char kWebSQLAccess[] = "web-sql-access"; + } // namespace switches } // namespace blink
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h index 524f778..d41d3b7 100644 --- a/third_party/blink/public/common/features.h +++ b/third_party/blink/public/common/features.h
@@ -677,6 +677,8 @@ // appending or prepending to the original User-Agent string. BLINK_COMMON_EXPORT extern const base::Feature kUserAgentOverrideExperiment; +BLINK_COMMON_EXPORT extern const base::Feature kWebSQLAccess; + } // namespace features } // namespace blink
diff --git a/third_party/blink/public/common/metrics/post_message_counter.h b/third_party/blink/public/common/metrics/post_message_counter.h index b8478b9..3875dbd 100644 --- a/third_party/blink/public/common/metrics/post_message_counter.h +++ b/third_party/blink/public/common/metrics/post_message_counter.h
@@ -9,6 +9,7 @@ #include "services/metrics/public/cpp/ukm_recorder.h" #include "services/metrics/public/cpp/ukm_source_id.h" #include "third_party/blink/public/common/common_export.h" +#include "third_party/blink/public/common/storage_key/storage_key.h" namespace blink { @@ -25,8 +26,10 @@ : partition_(partition) {} ~PostMessageCounter() = default; - void RecordMessage(ukm::SourceId source, - ukm::SourceId target, + void RecordMessage(ukm::SourceId source_id, + const StorageKey& source_storage_key, + ukm::SourceId target_id, + const StorageKey& target_storage_key, ukm::UkmRecorder* recorder); private:
diff --git a/third_party/blink/public/common/storage_key/storage_key.h b/third_party/blink/public/common/storage_key/storage_key.h index 87efdaf..11d1883 100644 --- a/third_party/blink/public/common/storage_key/storage_key.h +++ b/third_party/blink/public/common/storage_key/storage_key.h
@@ -158,6 +158,20 @@ // components/services/storage/service_worker/service_worker_database.cc static bool ShouldSkipKeyDueToPartitioning(const std::string& reg_key_string); + // Returns a copy of what this storage key would have been if + // `kThirdPartyStoragePartitioning` were enabled. This is a convenience + // function for callsites that benefit from future functionality that + // should be removed when storage partitioning is fully launched. + // TODO(crbug.com/1159586): Add support in BlinkStorageKey if needed. + StorageKey CopyWithForceEnabledThirdPartyStoragePartitioning() const { + StorageKey storage_key = *this; + storage_key.top_level_site_ = + storage_key.top_level_site_if_third_party_enabled_; + storage_key.ancestor_chain_bit_ = + storage_key.ancestor_chain_bit_if_third_party_enabled_; + return storage_key; + } + private: // This enum represents the different type of encodable partitioning // attributes. @@ -177,10 +191,12 @@ top_level_site_(IsThirdPartyStoragePartitioningEnabled() ? top_level_site : net::SchemefulSite(origin)), + top_level_site_if_third_party_enabled_(top_level_site), nonce_(nonce ? absl::make_optional(*nonce) : absl::nullopt), ancestor_chain_bit_(IsThirdPartyStoragePartitioningEnabled() ? ancestor_chain_bit - : blink::mojom::AncestorChainBit::kSameSite) {} + : blink::mojom::AncestorChainBit::kSameSite), + ancestor_chain_bit_if_third_party_enabled_(ancestor_chain_bit) {} // Converts the attribute type into the separator + uint8_t byte // serialization. E.x.: kTopLevelSite becomes "^0" @@ -216,6 +232,13 @@ // flag `kThirdPartyStoragePartitioning` is enabled. net::SchemefulSite top_level_site_; + // Stores the value `top_level_site_` would have had if + // `kThirdPartyStoragePartitioning` were enabled. This isn't used in + // serialization or comparison, and this information is lost if you convert + // to a BlinkStorageKey or send it via mojom. + // TODO(crbug.com/1159586): Add support in BlinkStorageKey if needed. + net::SchemefulSite top_level_site_if_third_party_enabled_; + // An optional nonce, forcing a partitioned storage from anything else. Used // by anonymous iframes: // https://github.com/camillelamy/explainers/blob/master/anonymous_iframes.md @@ -225,6 +248,13 @@ // cross-site with the current frame. kSameSite if entire ancestor // chain is same-site with the current frame. Used by service workers. blink::mojom::AncestorChainBit ancestor_chain_bit_; + + // Stores the value `ancestor_chain_bit_` would have had if + // `kThirdPartyStoragePartitioning` were enabled. This isn't used in + // serialization or comparison, and this information is lost if you convert + // to a BlinkStorageKey or send it via mojom. + // TODO(crbug.com/1159586): Add support in BlinkStorageKey if needed. + blink::mojom::AncestorChainBit ancestor_chain_bit_if_third_party_enabled_; }; BLINK_COMMON_EXPORT
diff --git a/third_party/blink/public/common/switches.h b/third_party/blink/public/common/switches.h index 0e46da2..6ba3db30 100644 --- a/third_party/blink/public/common/switches.h +++ b/third_party/blink/public/common/switches.h
@@ -50,6 +50,7 @@ BLINK_COMMON_EXPORT extern const char kShowLayoutShiftRegions[]; BLINK_COMMON_EXPORT extern const char kShowPaintRects[]; BLINK_COMMON_EXPORT extern const char kTouchTextSelectionStrategy[]; +BLINK_COMMON_EXPORT extern const char kWebSQLAccess[]; } // namespace switches } // namespace blink
diff --git a/third_party/blink/public/devtools_protocol/browser_protocol.pdl b/third_party/blink/public/devtools_protocol/browser_protocol.pdl index 7b91f4eb..c681ef2 100644 --- a/third_party/blink/public/devtools_protocol/browser_protocol.pdl +++ b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
@@ -756,13 +756,14 @@ properties optional AffectedFrame affectedFrame SourceCodeLocation sourceCodeLocation - # The content of the deprecation issue (this won't be translated), + # The content of an untranslated deprecation issue, # e.g. "window.inefficientLegacyStorageMethod will be removed in M97, # around January 2022. Please use Web Storage or Indexed Database # instead. This standard was abandoned in January, 1970. See # https://www.chromestatus.com/feature/5684870116278272 for more details." deprecated optional string message - string deprecationType + # The id of an untranslated deprecation issue e.g. PrefixedStorageInfo. + deprecated string deprecationType type ClientHintIssueReason extends string enum
diff --git a/third_party/blink/public/mojom/link_to_text/link_to_text.mojom b/third_party/blink/public/mojom/link_to_text/link_to_text.mojom index 42af035..b2220c18 100644 --- a/third_party/blink/public/mojom/link_to_text/link_to_text.mojom +++ b/third_party/blink/public/mojom/link_to_text/link_to_text.mojom
@@ -29,7 +29,8 @@ kIFrame = 10, kTimeout = 11, kBlockList = 12, - kNoRemoteConnection = 13 + kNoRemoteConnection = 13, + kNotGenerated = 14 }; // TextFragmentReceiver is used for requesting renderer to perform text fragment
diff --git a/third_party/blink/public/platform/modules/video_capture/web_video_capture_impl_manager.h b/third_party/blink/public/platform/modules/video_capture/web_video_capture_impl_manager.h index bacaba1..75a28b3 100644 --- a/third_party/blink/public/platform/modules/video_capture/web_video_capture_impl_manager.h +++ b/third_party/blink/public/platform/modules/video_capture/web_video_capture_impl_manager.h
@@ -110,9 +110,6 @@ void OnFrameDropped(const media::VideoCaptureSessionId& id, media::VideoCaptureFrameDropReason reason); - virtual std::unique_ptr<VideoCaptureImpl> CreateVideoCaptureImplForTesting( - const media::VideoCaptureSessionId& session_id) const; - // Get the feedback callback for the corresponding capture session. // Consumers may call the returned callback in any thread to provide // the capturer with feedback information. @@ -123,6 +120,10 @@ // Holds bookkeeping info for each VideoCaptureImpl shared by clients. struct DeviceEntry; + virtual std::unique_ptr<VideoCaptureImpl> CreateVideoCaptureImpl( + const media::VideoCaptureSessionId& session_id, + BrowserInterfaceBrokerProxy* browser_interface_broker) const; + static void ProcessFeedback(VideoCaptureFeedbackCB callback_to_io_thread, const media::VideoCaptureFeedback& feedback);
diff --git a/third_party/blink/public/web/modules/autofill_assistant/node_signals.h b/third_party/blink/public/web/modules/autofill_assistant/node_signals.h index c3ca8df8..b7f24bd 100644 --- a/third_party/blink/public/web/modules/autofill_assistant/node_signals.h +++ b/third_party/blink/public/web/modules/autofill_assistant/node_signals.h
@@ -42,6 +42,8 @@ struct BLINK_MODULES_EXPORT AutofillAssistantContextFeatures { // Text of headers. WebVector<WebString> header_text; + // Form the element is part of. + WebString form_type; }; struct BLINK_MODULES_EXPORT AutofillAssistantNodeSignals {
diff --git a/third_party/blink/renderer/core/animation/keyframe_effect.cc b/third_party/blink/renderer/core/animation/keyframe_effect.cc index d48e3dd..1e3dc0c 100644 --- a/third_party/blink/renderer/core/animation/keyframe_effect.cc +++ b/third_party/blink/renderer/core/animation/keyframe_effect.cc
@@ -50,11 +50,13 @@ #include "third_party/blink/renderer/core/frame/web_feature.h" #include "third_party/blink/renderer/core/paint/paint_layer.h" #include "third_party/blink/renderer/core/style/computed_style.h" +#include "third_party/blink/renderer/core/style/computed_style_constants.h" #include "third_party/blink/renderer/core/svg/svg_element.h" #include "third_party/blink/renderer/platform/animation/compositor_animation.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" +#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h" namespace blink { @@ -126,8 +128,14 @@ effect->target_pseudo_ = pseudo; if (element) { element->GetDocument().UpdateStyleAndLayoutTreeForNode(element); - effect->effect_target_ = element->GetPseudoElement( - CSSSelectorParser::ParsePseudoElement(pseudo, element)); + PseudoId pseudo_id = + CSSSelectorParser::ParsePseudoElement(pseudo, element); + AtomicString pseudo_argument = + PseudoElementHasArguments(pseudo_id) + ? CSSSelectorParser::ParsePseudoElementArgument(pseudo) + : WTF::g_null_atom; + effect->effect_target_ = + element->GetNestedPseudoElement(pseudo_id, pseudo_argument); } } return effect;
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc index 980651077..6aa72717 100644 --- a/third_party/blink/renderer/core/exported/web_view_impl.cc +++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -2423,7 +2423,7 @@ frame = frame->Tree().TraverseNext()) { auto* local_frame = DynamicTo<LocalFrame>(frame); if (local_frame && local_frame->View()) { - local_frame->IncrementNavigationCounter(); + local_frame->IncrementNavigationId(); } } }
diff --git a/third_party/blink/renderer/core/fragment_directive/text_fragment_handler.cc b/third_party/blink/renderer/core/fragment_directive/text_fragment_handler.cc index 0559194..d1c745f 100644 --- a/third_party/blink/renderer/core/fragment_directive/text_fragment_handler.cc +++ b/third_party/blink/renderer/core/fragment_directive/text_fragment_handler.cc
@@ -46,20 +46,29 @@ DCHECK(shared_highlighting::ShouldOfferLinkToText( GetFrame()->GetDocument()->Url())); DCHECK(!GetFrame()->Selection().SelectedText().IsEmpty()); - DCHECK(GetTextFragmentSelectorGenerator()); - GetTextFragmentSelectorGenerator()->RecordSelectorStateUma(); - + response_callback_ = std::move(callback); selector_ready_status_ = preemptive_generation_result_.has_value() ? shared_highlighting::LinkGenerationReadyStatus::kRequestedAfterReady : shared_highlighting::LinkGenerationReadyStatus:: kRequestedBeforeReady; - response_callback_ = std::move(callback); - // If generation finished simply - // respond with the result. Otherwise, the response callback is stored so - // that we reply on completion. + if (!GetTextFragmentSelectorGenerator()) { + // TODO(crbug.com/1303881): This shouldn't happen, but sometimes browser + // side requests link to text when generation was never started. + // See crash in crbug.com/1301794. + error_ = shared_highlighting::LinkGenerationError::kNotGenerated; + InvokeReplyCallback( + TextFragmentSelector(TextFragmentSelector::SelectorType::kInvalid), + error_); + return; + } + + GetTextFragmentSelectorGenerator()->RecordSelectorStateUma(); + + // If generation finished simply respond with the result. Otherwise, the + // response callback is stored so that we reply on completion. if (selector_ready_status_.value() == shared_highlighting::LinkGenerationReadyStatus::kRequestedAfterReady) InvokeReplyCallback(preemptive_generation_result_.value(), error_); @@ -240,7 +249,8 @@ .Run(selector.ToString(), error, selector_ready_status_.value()); // After reply is sent it is safe to reset the generator. - GetTextFragmentSelectorGenerator()->Reset(); + if (GetTextFragmentSelectorGenerator()) + GetTextFragmentSelectorGenerator()->Reset(); } TextFragmentAnchor* TextFragmentHandler::GetTextFragmentAnchor() {
diff --git a/third_party/blink/renderer/core/fragment_directive/text_fragment_handler.h b/third_party/blink/renderer/core/fragment_directive/text_fragment_handler.h index fa3fb1b..6b7c14d18 100644 --- a/third_party/blink/renderer/core/fragment_directive/text_fragment_handler.h +++ b/third_party/blink/renderer/core/fragment_directive/text_fragment_handler.h
@@ -60,7 +60,7 @@ private: FRIEND_TEST_ALL_PREFIXES(TextFragmentHandlerTest, IfGeneratorResetShouldRecordCorrectError); - + FRIEND_TEST_ALL_PREFIXES(TextFragmentHandlerTest, NotGenerated); // Returns whether preemptive generation should run for the given frame. static bool ShouldPreemptivelyGenerateFor(LocalFrame* frame);
diff --git a/third_party/blink/renderer/core/fragment_directive/text_fragment_handler_test.cc b/third_party/blink/renderer/core/fragment_directive/text_fragment_handler_test.cc index c9e13e8..f2a98f3 100644 --- a/third_party/blink/renderer/core/fragment_directive/text_fragment_handler_test.cc +++ b/third_party/blink/renderer/core/fragment_directive/text_fragment_handler_test.cc
@@ -1145,4 +1145,28 @@ EXPECT_EQ(expected_error, GetTextFragmentHandler().error_); } +// crbug.com/1301794 If generation didn't start requesting selector shouldn't +// crash. +TEST_F(TextFragmentHandlerTest, NotGenerated) { + SimRequest request("https://example.com/test.html", "text/html"); + LoadURL("https://example.com/test.html"); + request.Complete(R"HTML( + <!DOCTYPE html> + <div>Test page</div> + <p id='first'>First paragraph text that is longer than 20 chars</p> + <p id='second'>Second paragraph text</p> + )HTML"); + + Node* first_paragraph = GetDocument().getElementById("first")->firstChild(); + const auto& selected_start = Position(first_paragraph, 5); + const auto& selected_end = Position(first_paragraph, 6); + ASSERT_EQ(" ", PlainText(EphemeralRange(selected_start, selected_end))); + + SetSelection(selected_start, selected_end); + EXPECT_EQ(RequestSelector(), ""); + + shared_highlighting::LinkGenerationError expected_error = + shared_highlighting::LinkGenerationError::kNotGenerated; + EXPECT_EQ(expected_error, GetTextFragmentHandler().error_); +} } // namespace blink
diff --git a/third_party/blink/renderer/core/frame/deprecation.cc b/third_party/blink/renderer/core/frame/deprecation.cc index fda17513..417b5b9 100644 --- a/third_party/blink/renderer/core/frame/deprecation.cc +++ b/third_party/blink/renderer/core/frame/deprecation.cc
@@ -188,8 +188,7 @@ static const DeprecationInfo WithDetails(const String& id, const Milestone milestone, const String& details) { - return DeprecationInfo(id, milestone, String(), String(), details, String(), - details); + return DeprecationInfo(id, details); } // Use this to inform developers of any `details` for the deprecation with @@ -201,7 +200,7 @@ const String& details, const String& chrome_status_id) { return DeprecationInfo( - id, milestone, String(), String(), details, chrome_status_id, + id, String::Format( "%s See https://www.chromestatus.com/feature/%s for more details.", details.Ascii().c_str(), chrome_status_id.Ascii().c_str())); @@ -214,7 +213,7 @@ const String& feature, const String& replacement) { return DeprecationInfo( - id, milestone, feature, replacement, String(), String(), + id, String::Format("%s is deprecated. Please use %s instead.", feature.Ascii().c_str(), replacement.Ascii().c_str())); } @@ -227,7 +226,7 @@ const String& feature, const String& chrome_status_id) { return DeprecationInfo( - id, milestone, feature, String(), String(), chrome_status_id, + id, String::Format( "%s is deprecated and will be removed in %s. See " "https://www.chromestatus.com/feature/%s for more details.", @@ -244,7 +243,7 @@ const String& replacement, const String& chrome_status_id) { return DeprecationInfo( - id, milestone, feature, replacement, String(), chrome_status_id, + id, String::Format( "%s is deprecated and will be removed in %s. Please use %s " "instead. See https://www.chromestatus.com/feature/%s for more " @@ -254,32 +253,11 @@ } const String id_; - const Milestone milestone_; - const String feature_; - const String replacement_; - const String details_; - const String chrome_status_id_; const String message_; private: - DeprecationInfo(const String& id, - const Milestone milestone, - const String& feature, - const String& replacement, - const String& details, - const String& chrome_status_id, - const String& message) - : id_(id), - milestone_(milestone), - feature_(feature), - replacement_(replacement), - details_(details), - chrome_status_id_(chrome_status_id), - message_(message) { - for (wtf_size_t i = 0; i < chrome_status_id_.length(); ++i) { - DCHECK(IsASCIIDigit(chrome_status_id_[i])); - } - } + DeprecationInfo(const String& id, const String& message) + : id_(id), message_(message) {} }; const DeprecationInfo GetDeprecationInfo(const WebFeature feature) { @@ -762,16 +740,8 @@ Report* CreateReportInternal(const KURL& context_url, const DeprecationInfo& info) { - absl::optional<base::Time> optional_removal_date; - if (info.milestone_ != kUnknown) { - base::Time removal_date; - bool result = base::Time::FromUTCExploded(MilestoneDate(info.milestone_), - &removal_date); - DCHECK(result); - optional_removal_date = removal_date; - } DeprecationReportBody* body = MakeGarbageCollected<DeprecationReportBody>( - info.id_, optional_removal_date, info.message_); + info.id_, absl::nullopt, info.message_); return MakeGarbageCollected<Report>(ReportType::kDeprecation, context_url, body); }
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.cc b/third_party/blink/renderer/core/frame/local_dom_window.cc index 3f019be..b38b09c2 100644 --- a/third_party/blink/renderer/core/frame/local_dom_window.cc +++ b/third_party/blink/renderer/core/frame/local_dom_window.cc
@@ -1046,8 +1046,9 @@ LocalDOMWindow* source = posted_message->source; // Record UKM metrics for postMessage event. - post_message_counter_.RecordMessage(source->UkmSourceID(), UkmSourceID(), - UkmRecorder()); + post_message_counter_.RecordMessage(source->UkmSourceID(), + source->GetStorageKey(), UkmSourceID(), + GetStorageKey(), UkmRecorder()); // Convert the posted message to a MessageEvent so it can be unpacked for // local dispatch. @@ -1846,7 +1847,7 @@ } bool LocalDOMWindow::isSecureContext() const { - return GetFrame() && IsSecureContext(); + return IsSecureContext(); } void LocalDOMWindow::ClearIsolatedWorldCSPForTesting(int32_t world_id) {
diff --git a/third_party/blink/renderer/core/frame/local_frame.h b/third_party/blink/renderer/core/frame/local_frame.h index 3fb5525..87dd610 100644 --- a/third_party/blink/renderer/core/frame/local_frame.h +++ b/third_party/blink/renderer/core/frame/local_frame.h
@@ -728,8 +728,8 @@ // Invokes on first paint, this method could be invoked multiple times, refer // to FrameFirstPaint. void OnFirstPaint(bool text_painted, bool image_painted); - void IncrementNavigationCounter() { navigation_counter_++; } - uint32_t GetNavigationCounter() { return navigation_counter_; } + void IncrementNavigationId() { navigation_id_++; } + uint32_t GetNavigationId() { return navigation_id_; } #if BUILDFLAG(IS_MAC) void ResetTextInputHostForTesting(); @@ -965,7 +965,7 @@ bool notified_color_scheme_ = false; // Tracks the number of times this document has been retrieved from the // bfcache. - uint32_t navigation_counter_ = 0; + uint32_t navigation_id_ = 1; }; inline FrameLoader& LocalFrame::Loader() const {
diff --git a/third_party/blink/renderer/core/frame/local_frame_test.cc b/third_party/blink/renderer/core/frame/local_frame_test.cc index 57d295b..2765783 100644 --- a/third_party/blink/renderer/core/frame/local_frame_test.cc +++ b/third_party/blink/renderer/core/frame/local_frame_test.cc
@@ -223,10 +223,10 @@ #endif TEST_F(LocalFrameTest, NavigationCounter) { auto page_holder = std::make_unique<DummyPageHolder>(); - EXPECT_EQ(0u, page_holder->GetFrame().GetNavigationCounter()); - page_holder->GetFrame().IncrementNavigationCounter(); - EXPECT_EQ(1u, page_holder->GetFrame().GetNavigationCounter()); - page_holder->GetFrame().IncrementNavigationCounter(); - EXPECT_EQ(2u, page_holder->GetFrame().GetNavigationCounter()); + EXPECT_EQ(1u, page_holder->GetFrame().GetNavigationId()); + page_holder->GetFrame().IncrementNavigationId(); + EXPECT_EQ(2u, page_holder->GetFrame().GetNavigationId()); + page_holder->GetFrame().IncrementNavigationId(); + EXPECT_EQ(3u, page_holder->GetFrame().GetNavigationId()); } } // namespace blink
diff --git a/third_party/blink/renderer/core/html/html_script_element.cc b/third_party/blink/renderer/core/html/html_script_element.cc index c05c7246..804f2a6d 100644 --- a/third_party/blink/renderer/core/html/html_script_element.cc +++ b/third_party/blink/renderer/core/html/html_script_element.cc
@@ -132,6 +132,10 @@ void HTMLScriptElement::RemovedFrom(ContainerNode& insertion_point) { HTMLElement::RemovedFrom(insertion_point); loader_->ReleaseWebBundleResource(); + if (GetDocument().GetRenderBlockingResourceManager()) { + GetDocument().GetRenderBlockingResourceManager()->RemovePendingScript( + *this); + } } void HTMLScriptElement::DidNotifySubtreeInsertionsToDocument() {
diff --git a/third_party/blink/renderer/core/html/html_script_element.h b/third_party/blink/renderer/core/html/html_script_element.h index 92e9255..6a5b774 100644 --- a/third_party/blink/renderer/core/html/html_script_element.h +++ b/third_party/blink/renderer/core/html/html_script_element.h
@@ -115,6 +115,9 @@ bool ElementHasDuplicateAttributes() const override { return HasDuplicateAttribute(); } + bool IsRenderBlocking() const override { + return blocking_attribute_->IsRenderBlocking(); + } bool AllowInlineScriptForCSP(const AtomicString& nonce, const WTF::OrdinalNumber&, const String& script_content) override;
diff --git a/third_party/blink/renderer/core/layout/ng/table/ng_table_constraint_space_data.h b/third_party/blink/renderer/core/layout/ng/table/ng_table_constraint_space_data.h index 9153845..67fc663 100644 --- a/third_party/blink/renderer/core/layout/ng/table/ng_table_constraint_space_data.h +++ b/third_party/blink/renderer/core/layout/ng/table/ng_table_constraint_space_data.h
@@ -88,18 +88,19 @@ // Data needed to layout a single cell. struct Cell { Cell(NGBoxStrut borders, - LayoutUnit block_size, + LayoutUnit rowspan_block_size, wtf_size_t start_column, bool has_grown, bool is_constrained) : borders(borders), - block_size(block_size), + rowspan_block_size(rowspan_block_size), start_column(start_column), has_grown(has_grown), is_constrained(is_constrained) {} bool operator==(const Cell& other) const { - return borders == other.borders && block_size == other.block_size && + return borders == other.borders && + rowspan_block_size == other.rowspan_block_size && start_column == other.start_column && has_grown == other.has_grown && is_constrained == other.is_constrained; @@ -109,7 +110,7 @@ // Size of borders drawn on the inside of the border box. const NGBoxStrut borders; // Size of the cell. Need this for cells that span multiple rows. - const LayoutUnit block_size; + const LayoutUnit rowspan_block_size; const wtf_size_t start_column; const bool has_grown; const bool is_constrained;
diff --git a/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm.cc index 98a2ab8..eb62377 100644 --- a/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm.cc
@@ -308,17 +308,25 @@ section.start_row + section.row_count - row_index; wtf_size_t rowspan = std::min(cell_block_constraints[cell_index].rowspan, max_rowspan); - // Compute cell's size. + + // Determine the cell's block-size. LayoutUnit cell_block_size; for (wtf_size_t i = 0; i < rowspan; ++i) { - if (!rows[row_index + i].is_collapsed) { - cell_block_size += rows[row_index + i].block_size; - if (i != 0) - cell_block_size += border_spacing.block_size; - } + if (rows[row_index + i].is_collapsed) + continue; + cell_block_size += rows[row_index + i].block_size; + if (i != 0) + cell_block_size += border_spacing.block_size; } + + // Confusingly a rowspanned cell originating from a collapsed-row will + // have no block-size. + LayoutUnit rowspan_block_size = rowspan > 1 && !row.is_collapsed + ? cell_block_size + : kIndefiniteSize; + data->cells.emplace_back( - cell_block_constraints[cell_index].borders, cell_block_size, + cell_block_constraints[cell_index].borders, rowspan_block_size, cell_block_constraints[cell_index].column_index, /* has_grown */ cell_block_size > cell_block_constraints[cell_index].min_block_size,
diff --git a/third_party/blink/renderer/core/layout/ng/table/ng_table_row_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/table/ng_table_row_layout_algorithm.cc index b8fc063..7115a43 100644 --- a/third_party/blink/renderer/core/layout/ng/table/ng_table_row_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/ng/table/ng_table_row_layout_algorithm.cc
@@ -64,7 +64,9 @@ table_data.column_locations[cell_location_end_column].inline_size - table_data.column_locations[cell_location_start_column].offset; const LayoutUnit cell_block_size = - row.is_collapsed ? LayoutUnit() : cell_data.block_size; + cell_data.rowspan_block_size != kIndefiniteSize + ? cell_data.rowspan_block_size + : row.block_size; // Our initial block-size is definite if this cell has a fixed block-size, // or we have grown and the table has a specified block-size.
diff --git a/third_party/blink/renderer/core/layout/ng/table/ng_table_section_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/table/ng_table_section_layout_algorithm.cc index f33e06b..9d0311f4 100644 --- a/third_party/blink/renderer/core/layout/ng/table/ng_table_section_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/ng/table/ng_table_section_layout_algorithm.cc
@@ -39,7 +39,7 @@ const LogicalSize available_size = {container_builder_.InlineSize(), kIndefiniteSize}; LogicalOffset offset; - bool is_first_row = true; + bool is_first_non_collapsed_row = true; const wtf_size_t start_row_index = table_data.sections[section_index].start_row_index; NGBlockChildIterator child_iterator(Node().FirstChild(), BreakToken(), @@ -51,8 +51,9 @@ wtf_size_t row_index = start_row_index + *entry.index; DCHECK_LT(row_index, table_data.sections[section_index].start_row_index + table_data.sections[section_index].row_count); + bool is_row_collapsed = table_data.rows[row_index].is_collapsed; - if (!is_first_row && !table_data.rows[row_index].is_collapsed) + if (!is_first_non_collapsed_row && !is_row_collapsed) offset.block_offset += table_data.table_border_spacing.block_size; NGConstraintSpaceBuilder row_space_builder( @@ -79,7 +80,7 @@ ConstraintSpace().FragmentainerOffsetAtBfc() + offset.block_offset; NGBreakStatus break_status = BreakBeforeChildIfNeeded( ConstraintSpace(), row, *row_result, fragmentainer_block_offset, - !is_first_row, &container_builder_); + !is_first_non_collapsed_row, &container_builder_); if (break_status != NGBreakStatus::kContinue) break; } @@ -88,13 +89,13 @@ table_data.table_writing_direction, To<NGPhysicalBoxFragment>(row_result->PhysicalFragment())); - if (is_first_row) { + if (!section_baseline) { DCHECK(fragment.Baseline()); section_baseline = fragment.Baseline(); } container_builder_.AddResult(*row_result, offset); offset.block_offset += fragment.BlockSize(); - is_first_row = false; + is_first_non_collapsed_row &= is_row_collapsed; if (container_builder_.HasInflowChildBreakInside()) break;
diff --git a/third_party/blink/renderer/core/loader/render_blocking_resource_manager.cc b/third_party/blink/renderer/core/loader/render_blocking_resource_manager.cc index de7098f4..f232e8e0 100644 --- a/third_party/blink/renderer/core/loader/render_blocking_resource_manager.cc +++ b/third_party/blink/renderer/core/loader/render_blocking_resource_manager.cc
@@ -11,6 +11,7 @@ #include "third_party/blink/renderer/core/html/html_document.h" #include "third_party/blink/renderer/core/loader/document_loader.h" #include "third_party/blink/renderer/core/loader/resource/font_resource.h" +#include "third_party/blink/renderer/core/script/script_element_base.h" #include "third_party/blink/renderer/platform/loader/fetch/resource_finish_observer.h" namespace blink { @@ -181,9 +182,26 @@ return true; } +void RenderBlockingResourceManager::AddPendingScript( + const ScriptElementBase& script) { + if (document_->body()) + return; + pending_scripts_.insert(&script); +} + +void RenderBlockingResourceManager::RemovePendingScript( + const ScriptElementBase& script) { + auto iter = pending_scripts_.find(&script); + if (iter == pending_scripts_.end()) + return; + pending_scripts_.erase(iter); + document_->RenderBlockingResourceUnblocked(); +} + void RenderBlockingResourceManager::Trace(Visitor* visitor) const { visitor->Trace(document_); visitor->Trace(pending_stylesheet_owner_nodes_); + visitor->Trace(pending_scripts_); visitor->Trace(font_preload_finish_observers_); visitor->Trace(font_preload_timer_); }
diff --git a/third_party/blink/renderer/core/loader/render_blocking_resource_manager.h b/third_party/blink/renderer/core/loader/render_blocking_resource_manager.h index d6b3b78b..dbabefd3 100644 --- a/third_party/blink/renderer/core/loader/render_blocking_resource_manager.h +++ b/third_party/blink/renderer/core/loader/render_blocking_resource_manager.h
@@ -17,6 +17,7 @@ class FontFace; class Node; class ResourceFinishObserver; +class ScriptElementBase; // https://html.spec.whatwg.org/#render-blocking-mechanism with some extensions. class CORE_EXPORT RenderBlockingResourceManager final @@ -30,13 +31,12 @@ const RenderBlockingResourceManager&) = delete; bool HasRenderBlockingResources() const { - return pending_stylesheet_owner_nodes_.size() || + return pending_stylesheet_owner_nodes_.size() || pending_scripts_.size() || font_preload_finish_observers_.size() || imperative_font_loading_count_; } - // TODO(crbug.com/1271296): Use this class to handle render-blocking scripts - // and preloads. + // TODO(crbug.com/1271296): Use this class to handle render-blocking preloads. bool HasPendingStylesheets() const { return pending_stylesheet_owner_nodes_.size(); @@ -48,6 +48,9 @@ // otherwise, returns false with no operation. bool RemovePendingStylesheet(const Node& owner_node); + void AddPendingScript(const ScriptElementBase& script); + void RemovePendingScript(const ScriptElementBase& script); + // We additionally allow font preloading (via <link rel="preload"> or Font // Loading API) to block rendering for a short period, so that preloaded fonts // have a higher chance to be used by the first paint. @@ -76,6 +79,9 @@ // https://html.spec.whatwg.org/multipage/semantics.html#update-a-style-block HeapHashSet<Member<const Node>> pending_stylesheet_owner_nodes_; + // Tracks the currently pending render-blocking script elements. + HeapHashSet<Member<const ScriptElementBase>> pending_scripts_; + // Need to hold strong references here, otherwise they'll be GC-ed immediately // as Resource only holds weak references. HeapHashSet<Member<ResourceFinishObserver>> font_preload_finish_observers_;
diff --git a/third_party/blink/renderer/core/paint/image_paint_timing_detector_test.cc b/third_party/blink/renderer/core/paint/image_paint_timing_detector_test.cc index 22f8fe7..4376c220 100644 --- a/third_party/blink/renderer/core/paint/image_paint_timing_detector_test.cc +++ b/third_party/blink/renderer/core/paint/image_paint_timing_detector_test.cc
@@ -367,28 +367,25 @@ EXPECT_TRUE(events[0]->HasArg("frame")); - EXPECT_TRUE(events[0]->HasArg("data")); - base::Value arg; - EXPECT_TRUE(events[0]->GetArgAsValue("data", &arg)); - base::DictionaryValue* arg_dict; - EXPECT_TRUE(arg.GetAsDictionary(&arg_dict)); - EXPECT_GT(arg_dict->FindIntKey("DOMNodeId").value_or(-1), 0); - EXPECT_GT(arg_dict->FindIntKey("size").value_or(-1), 0); - EXPECT_EQ(arg_dict->FindIntKey("candidateIndex").value_or(-1), 2); - absl::optional<bool> isMainFrame = arg_dict->FindBoolKey("isMainFrame"); + ASSERT_TRUE(events[0]->HasDictArg("data")); + base::Value::Dict arg_dict = events[0]->GetKnownArgAsDict("data"); + EXPECT_GT(arg_dict.FindInt("DOMNodeId").value_or(-1), 0); + EXPECT_GT(arg_dict.FindInt("size").value_or(-1), 0); + EXPECT_EQ(arg_dict.FindInt("candidateIndex").value_or(-1), 2); + absl::optional<bool> isMainFrame = arg_dict.FindBool("isMainFrame"); EXPECT_TRUE(isMainFrame.has_value()); EXPECT_EQ(true, isMainFrame.value()); - absl::optional<bool> isOOPIF = arg_dict->FindBoolKey("isOOPIF"); + absl::optional<bool> isOOPIF = arg_dict.FindBool("isOOPIF"); EXPECT_TRUE(isOOPIF.has_value()); EXPECT_EQ(false, isOOPIF.value()); - EXPECT_EQ(arg_dict->FindIntKey("frame_x").value_or(-1), 8); - EXPECT_EQ(arg_dict->FindIntKey("frame_y").value_or(-1), 8); - EXPECT_EQ(arg_dict->FindIntKey("frame_width").value_or(-1), 5); - EXPECT_EQ(arg_dict->FindIntKey("frame_height").value_or(-1), 5); - EXPECT_EQ(arg_dict->FindIntKey("root_x").value_or(-1), 8); - EXPECT_EQ(arg_dict->FindIntKey("root_y").value_or(-1), 8); - EXPECT_EQ(arg_dict->FindIntKey("root_width").value_or(-1), 5); - EXPECT_EQ(arg_dict->FindIntKey("root_height").value_or(-1), 5); + EXPECT_EQ(arg_dict.FindInt("frame_x").value_or(-1), 8); + EXPECT_EQ(arg_dict.FindInt("frame_y").value_or(-1), 8); + EXPECT_EQ(arg_dict.FindInt("frame_width").value_or(-1), 5); + EXPECT_EQ(arg_dict.FindInt("frame_height").value_or(-1), 5); + EXPECT_EQ(arg_dict.FindInt("root_x").value_or(-1), 8); + EXPECT_EQ(arg_dict.FindInt("root_y").value_or(-1), 8); + EXPECT_EQ(arg_dict.FindInt("root_width").value_or(-1), 5); + EXPECT_EQ(arg_dict.FindInt("root_height").value_or(-1), 5); } TEST_P(ImagePaintTimingDetectorTest, @@ -419,28 +416,25 @@ EXPECT_TRUE(events[0]->HasArg("frame")); - EXPECT_TRUE(events[0]->HasArg("data")); - base::Value arg; - EXPECT_TRUE(events[0]->GetArgAsValue("data", &arg)); - base::DictionaryValue* arg_dict; - EXPECT_TRUE(arg.GetAsDictionary(&arg_dict)); - EXPECT_GT(arg_dict->FindIntKey("DOMNodeId").value_or(-1), 0); - EXPECT_GT(arg_dict->FindIntKey("size").value_or(-1), 0); - EXPECT_EQ(arg_dict->FindIntKey("candidateIndex").value_or(-1), 2); - absl::optional<bool> isMainFrame = arg_dict->FindBoolKey("isMainFrame"); + ASSERT_TRUE(events[0]->HasDictArg("data")); + base::Value::Dict arg_dict = events[0]->GetKnownArgAsDict("data"); + EXPECT_GT(arg_dict.FindInt("DOMNodeId").value_or(-1), 0); + EXPECT_GT(arg_dict.FindInt("size").value_or(-1), 0); + EXPECT_EQ(arg_dict.FindInt("candidateIndex").value_or(-1), 2); + absl::optional<bool> isMainFrame = arg_dict.FindBool("isMainFrame"); EXPECT_TRUE(isMainFrame.has_value()); EXPECT_EQ(false, isMainFrame.value()); - absl::optional<bool> isOOPIF = arg_dict->FindBoolKey("isOOPIF"); + absl::optional<bool> isOOPIF = arg_dict.FindBool("isOOPIF"); EXPECT_TRUE(isOOPIF.has_value()); EXPECT_EQ(false, isOOPIF.value()); - EXPECT_EQ(arg_dict->FindIntKey("frame_x").value_or(-1), 10); - EXPECT_EQ(arg_dict->FindIntKey("frame_y").value_or(-1), 10); - EXPECT_EQ(arg_dict->FindIntKey("frame_width").value_or(-1), 200); - EXPECT_EQ(arg_dict->FindIntKey("frame_height").value_or(-1), 200); - EXPECT_GT(arg_dict->FindIntKey("root_x").value_or(-1), 40); - EXPECT_GT(arg_dict->FindIntKey("root_y").value_or(-1), 60); - EXPECT_EQ(arg_dict->FindIntKey("root_width").value_or(-1), 200); - EXPECT_EQ(arg_dict->FindIntKey("root_height").value_or(-1), 200); + EXPECT_EQ(arg_dict.FindInt("frame_x").value_or(-1), 10); + EXPECT_EQ(arg_dict.FindInt("frame_y").value_or(-1), 10); + EXPECT_EQ(arg_dict.FindInt("frame_width").value_or(-1), 200); + EXPECT_EQ(arg_dict.FindInt("frame_height").value_or(-1), 200); + EXPECT_GT(arg_dict.FindInt("root_x").value_or(-1), 40); + EXPECT_GT(arg_dict.FindInt("root_y").value_or(-1), 60); + EXPECT_EQ(arg_dict.FindInt("root_width").value_or(-1), 200); + EXPECT_EQ(arg_dict.FindInt("root_height").value_or(-1), 200); } TEST_P(ImagePaintTimingDetectorTest, LargestImagePaint_TraceEvent_NoCandidate) { @@ -465,14 +459,11 @@ EXPECT_EQ("loading", events[0]->category); EXPECT_TRUE(events[0]->HasArg("frame")); - EXPECT_TRUE(events[0]->HasArg("data")); - base::Value arg; - EXPECT_TRUE(events[0]->GetArgAsValue("data", &arg)); - base::DictionaryValue* arg_dict; - EXPECT_TRUE(arg.GetAsDictionary(&arg_dict)); - EXPECT_EQ(arg_dict->FindIntKey("candidateIndex").value_or(-1), 1); - EXPECT_THAT(arg_dict->FindBoolKey("isMainFrame"), Optional(true)); - EXPECT_THAT(arg_dict->FindBoolKey("isOOPIF"), Optional(false)); + ASSERT_TRUE(events[0]->HasDictArg("data")); + base::Value::Dict arg_dict = events[0]->GetKnownArgAsDict("data"); + EXPECT_EQ(arg_dict.FindInt("candidateIndex").value_or(-1), 1); + EXPECT_THAT(arg_dict.FindBool("isMainFrame"), Optional(true)); + EXPECT_THAT(arg_dict.FindBool("isOOPIF"), Optional(false)); } TEST_P(ImagePaintTimingDetectorTest, UpdatePerformanceTiming) {
diff --git a/third_party/blink/renderer/core/paint/text_paint_timing_detector_test.cc b/third_party/blink/renderer/core/paint/text_paint_timing_detector_test.cc index 2e216913..66355a74 100644 --- a/third_party/blink/renderer/core/paint/text_paint_timing_detector_test.cc +++ b/third_party/blink/renderer/core/paint/text_paint_timing_detector_test.cc
@@ -296,28 +296,25 @@ EXPECT_TRUE(events[0]->HasArg("frame")); - EXPECT_TRUE(events[0]->HasArg("data")); - base::Value arg; - EXPECT_TRUE(events[0]->GetArgAsValue("data", &arg)); - base::DictionaryValue* arg_dict; - EXPECT_TRUE(arg.GetAsDictionary(&arg_dict)); - EXPECT_GT(arg_dict->FindIntKey("DOMNodeId").value_or(-1), 0); - EXPECT_GT(arg_dict->FindIntKey("size").value_or(-1), 0); - EXPECT_EQ(arg_dict->FindIntKey("candidateIndex").value_or(-1), 1); - absl::optional<bool> is_main_frame = arg_dict->FindBoolKey("isMainFrame"); + ASSERT_TRUE(events[0]->HasDictArg("data")); + base::Value::Dict arg_dict = events[0]->GetKnownArgAsDict("data"); + EXPECT_GT(arg_dict.FindInt("DOMNodeId").value_or(-1), 0); + EXPECT_GT(arg_dict.FindInt("size").value_or(-1), 0); + EXPECT_EQ(arg_dict.FindInt("candidateIndex").value_or(-1), 1); + absl::optional<bool> is_main_frame = arg_dict.FindBool("isMainFrame"); EXPECT_TRUE(is_main_frame.has_value()); EXPECT_EQ(true, is_main_frame.value()); - absl::optional<bool> is_oopif = arg_dict->FindBoolKey("isOOPIF"); + absl::optional<bool> is_oopif = arg_dict.FindBool("isOOPIF"); EXPECT_TRUE(is_oopif.has_value()); EXPECT_EQ(false, is_oopif.value()); - EXPECT_GT(arg_dict->FindIntKey("frame_x").value_or(-1), 0); - EXPECT_GT(arg_dict->FindIntKey("frame_y").value_or(-1), 0); - EXPECT_GT(arg_dict->FindIntKey("frame_width").value_or(-1), 0); - EXPECT_GT(arg_dict->FindIntKey("frame_height").value_or(-1), 0); - EXPECT_GT(arg_dict->FindIntKey("root_x").value_or(-1), 0); - EXPECT_GT(arg_dict->FindIntKey("root_y").value_or(-1), 0); - EXPECT_GT(arg_dict->FindIntKey("root_width").value_or(-1), 0); - EXPECT_GT(arg_dict->FindIntKey("root_height").value_or(-1), 0); + EXPECT_GT(arg_dict.FindInt("frame_x").value_or(-1), 0); + EXPECT_GT(arg_dict.FindInt("frame_y").value_or(-1), 0); + EXPECT_GT(arg_dict.FindInt("frame_width").value_or(-1), 0); + EXPECT_GT(arg_dict.FindInt("frame_height").value_or(-1), 0); + EXPECT_GT(arg_dict.FindInt("root_x").value_or(-1), 0); + EXPECT_GT(arg_dict.FindInt("root_y").value_or(-1), 0); + EXPECT_GT(arg_dict.FindInt("root_width").value_or(-1), 0); + EXPECT_GT(arg_dict.FindInt("root_height").value_or(-1), 0); } TEST_F(TextPaintTimingDetectorTest, @@ -347,30 +344,27 @@ EXPECT_TRUE(events[0]->HasArg("frame")); - EXPECT_TRUE(events[0]->HasArg("data")); - base::Value arg; - EXPECT_TRUE(events[0]->GetArgAsValue("data", &arg)); - base::DictionaryValue* arg_dict; - EXPECT_TRUE(arg.GetAsDictionary(&arg_dict)); - EXPECT_GT(arg_dict->FindIntKey("DOMNodeId").value_or(-1), 0); - EXPECT_GT(arg_dict->FindIntKey("size").value_or(-1), 0); - EXPECT_EQ(arg_dict->FindIntKey("candidateIndex").value_or(-1), 1); - absl::optional<bool> is_main_frame = arg_dict->FindBoolKey("isMainFrame"); + ASSERT_TRUE(events[0]->HasDictArg("data")); + base::Value::Dict arg_dict = events[0]->GetKnownArgAsDict("data"); + EXPECT_GT(arg_dict.FindInt("DOMNodeId").value_or(-1), 0); + EXPECT_GT(arg_dict.FindInt("size").value_or(-1), 0); + EXPECT_EQ(arg_dict.FindInt("candidateIndex").value_or(-1), 1); + absl::optional<bool> is_main_frame = arg_dict.FindBool("isMainFrame"); EXPECT_TRUE(is_main_frame.has_value()); EXPECT_EQ(false, is_main_frame.value()); - absl::optional<bool> is_oopif = arg_dict->FindBoolKey("isOOPIF"); + absl::optional<bool> is_oopif = arg_dict.FindBool("isOOPIF"); EXPECT_TRUE(is_oopif.has_value()); EXPECT_EQ(false, is_oopif.value()); // There's sometimes a 1 pixel offset for the y dimensions. - EXPECT_EQ(arg_dict->FindIntKey("frame_x").value_or(-1), 10); - EXPECT_GE(arg_dict->FindIntKey("frame_y").value_or(-1), 9); - EXPECT_LE(arg_dict->FindIntKey("frame_y").value_or(-1), 10); - EXPECT_GT(arg_dict->FindIntKey("frame_width").value_or(-1), 0); - EXPECT_GT(arg_dict->FindIntKey("frame_height").value_or(-1), 0); - EXPECT_GT(arg_dict->FindIntKey("root_x").value_or(-1), 25); - EXPECT_GT(arg_dict->FindIntKey("root_y").value_or(-1), 50); - EXPECT_GT(arg_dict->FindIntKey("root_width").value_or(-1), 0); - EXPECT_GT(arg_dict->FindIntKey("root_height").value_or(-1), 0); + EXPECT_EQ(arg_dict.FindInt("frame_x").value_or(-1), 10); + EXPECT_GE(arg_dict.FindInt("frame_y").value_or(-1), 9); + EXPECT_LE(arg_dict.FindInt("frame_y").value_or(-1), 10); + EXPECT_GT(arg_dict.FindInt("frame_width").value_or(-1), 0); + EXPECT_GT(arg_dict.FindInt("frame_height").value_or(-1), 0); + EXPECT_GT(arg_dict.FindInt("root_x").value_or(-1), 25); + EXPECT_GT(arg_dict.FindInt("root_y").value_or(-1), 50); + EXPECT_GT(arg_dict.FindInt("root_width").value_or(-1), 0); + EXPECT_GT(arg_dict.FindInt("root_height").value_or(-1), 0); } TEST_F(TextPaintTimingDetectorTest, AggregationBySelfPaintingInlineElement) {
diff --git a/third_party/blink/renderer/core/script/mock_script_element_base.h b/third_party/blink/renderer/core/script/mock_script_element_base.h index 717d6ab..5186d1dc 100644 --- a/third_party/blink/renderer/core/script/mock_script_element_base.h +++ b/third_party/blink/renderer/core/script/mock_script_element_base.h
@@ -42,6 +42,7 @@ MOCK_CONST_METHOD0(GetNonceForElement, const AtomicString&()); MOCK_CONST_METHOD0(ElementHasDuplicateAttributes, bool()); MOCK_CONST_METHOD0(InitiatorName, AtomicString()); + MOCK_CONST_METHOD0(IsRenderBlocking, bool()); MOCK_METHOD3(AllowInlineScriptForCSP, bool(const AtomicString&, const WTF::OrdinalNumber&,
diff --git a/third_party/blink/renderer/core/script/pending_script.cc b/third_party/blink/renderer/core/script/pending_script.cc index c698d52..f478790 100644 --- a/third_party/blink/renderer/core/script/pending_script.cc +++ b/third_party/blink/renderer/core/script/pending_script.cc
@@ -185,6 +185,12 @@ Document* context_document = To<LocalDOMWindow>(element_document.GetExecutionContext())->document(); + // Unblock rendering on scriptElement. + if (element_document.GetRenderBlockingResourceManager()) { + element_document.GetRenderBlockingResourceManager()->RemovePendingScript( + *element); + } + // <spec step="2">If the script's script is null, fire an event named error at // the element, and return.</spec> if (!script) {
diff --git a/third_party/blink/renderer/core/script/script_element_base.h b/third_party/blink/renderer/core/script/script_element_base.h index 628135d..66ab870fa 100644 --- a/third_party/blink/renderer/core/script/script_element_base.h +++ b/third_party/blink/renderer/core/script/script_element_base.h
@@ -67,6 +67,7 @@ virtual bool HasChildren() const = 0; virtual const AtomicString& GetNonceForElement() const = 0; virtual bool ElementHasDuplicateAttributes() const = 0; + virtual bool IsRenderBlocking() const = 0; // Whether the inline script is allowed by the CSP. Must be called // synchronously to ensure the correct Javascript world is used for CSP
diff --git a/third_party/blink/renderer/core/script/script_loader.cc b/third_party/blink/renderer/core/script/script_loader.cc index 19fdf4c..30702ca9 100644 --- a/third_party/blink/renderer/core/script/script_loader.cc +++ b/third_party/blink/renderer/core/script/script_loader.cc
@@ -619,6 +619,14 @@ return false; } + // If the element is render-blocking, block rendering on the element. + if (RuntimeEnabledFeatures::BlockingAttributeEnabled() && + element_->IsRenderBlocking() && + element_document.GetRenderBlockingResourceManager()) { + element_document.GetRenderBlockingResourceManager()->AddPendingScript( + *element_); + } + // <spec step="24.6">Switch on the script's type:</spec> switch (GetScriptType()) { case ScriptTypeAtPrepare::kInvalid:
diff --git a/third_party/blink/renderer/core/style/computed_style_constants.h b/third_party/blink/renderer/core/style/computed_style_constants.h index a4c9d2ff..7676090 100644 --- a/third_party/blink/renderer/core/style/computed_style_constants.h +++ b/third_party/blink/renderer/core/style/computed_style_constants.h
@@ -124,6 +124,10 @@ inline bool PseudoElementHasArguments(PseudoId pseudo_id) { switch (pseudo_id) { case kPseudoIdHighlight: + case kPseudoIdPageTransitionContainer: + case kPseudoIdPageTransitionImageWrapper: + case kPseudoIdPageTransitionIncomingImage: + case kPseudoIdPageTransitionOutgoingImage: return true; default: return false;
diff --git a/third_party/blink/renderer/core/svg/svg_script_element.h b/third_party/blink/renderer/core/svg/svg_script_element.h index f6ffe53b..7b968a14 100644 --- a/third_party/blink/renderer/core/svg/svg_script_element.h +++ b/third_party/blink/renderer/core/svg/svg_script_element.h
@@ -94,6 +94,7 @@ bool ElementHasDuplicateAttributes() const override { return HasDuplicateAttribute(); } + bool IsRenderBlocking() const override { return false; } bool AllowInlineScriptForCSP(const AtomicString& nonce, const WTF::OrdinalNumber&, const String& script_content) override;
diff --git a/third_party/blink/renderer/core/testing/wait_for_event.cc b/third_party/blink/renderer/core/testing/wait_for_event.cc index e7dccae..e422aa8 100644 --- a/third_party/blink/renderer/core/testing/wait_for_event.cc +++ b/third_party/blink/renderer/core/testing/wait_for_event.cc
@@ -12,7 +12,6 @@ WaitForEvent::WaitForEvent(Element* element, const AtomicString& name) : element_(element), event_name_(name) { element_->addEventListener(event_name_, this, /*use_capture=*/false); - HeapPointersOnStackScope scan_stack(ThreadState::Current()); run_loop_.Run(); }
diff --git a/third_party/blink/renderer/core/timing/performance_entry.cc b/third_party/blink/renderer/core/timing/performance_entry.cc index fff7775..99567cbc 100644 --- a/third_party/blink/renderer/core/timing/performance_entry.cc +++ b/third_party/blink/renderer/core/timing/performance_entry.cc
@@ -46,22 +46,22 @@ PerformanceEntry::PerformanceEntry(const AtomicString& name, double start_time, double finish_time, - uint32_t navigation_count) + uint32_t navigation_id) : duration_(finish_time - start_time), name_(name), start_time_(start_time), index_(index_seq.GetNext()), - navigation_count_(navigation_count) {} + navigation_id_(navigation_id) {} PerformanceEntry::PerformanceEntry(double duration, const AtomicString& name, double start_time, - uint32_t navigation_count) + uint32_t navigation_id) : duration_(duration), name_(name), start_time_(start_time), index_(index_seq.GetNext()), - navigation_count_(navigation_count) { + navigation_id_(navigation_id) { DCHECK_GE(duration_, 0.0); } @@ -75,8 +75,8 @@ return duration_; } -uint32_t PerformanceEntry::navigationCount() const { - return navigation_count_; +uint32_t PerformanceEntry::navigationId() const { + return navigation_id_; } mojom::blink::PerformanceMarkOrMeasurePtr @@ -126,12 +126,12 @@ return kInvalid; } -uint32_t PerformanceEntry::GetNavigationCounter(ScriptState* script_state) { +uint32_t PerformanceEntry::GetNavigationId(ScriptState* script_state) { const auto* local_dom_window = LocalDOMWindow::From(script_state); if (!local_dom_window || !local_dom_window->GetFrame()) { - return 0; + return 1; } - return local_dom_window->GetFrame()->GetNavigationCounter(); + return local_dom_window->GetFrame()->GetNavigationId(); } ScriptValue PerformanceEntry::toJSONForBinding( @@ -146,8 +146,8 @@ builder.AddString("entryType", entryType()); builder.AddNumber("startTime", startTime()); builder.AddNumber("duration", duration()); - if (RuntimeEnabledFeatures::NavigationCounterEnabled()) { - builder.AddNumber("navigationCount", navigationCount()); + if (RuntimeEnabledFeatures::NavigationIdEnabled()) { + builder.AddNumber("navigationId", navigationId()); } }
diff --git a/third_party/blink/renderer/core/timing/performance_entry.h b/third_party/blink/renderer/core/timing/performance_entry.h index 83d0d8a2..de6b2a3 100644 --- a/third_party/blink/renderer/core/timing/performance_entry.h +++ b/third_party/blink/renderer/core/timing/performance_entry.h
@@ -73,7 +73,7 @@ const AtomicString& name() const { return name_; } DOMHighResTimeStamp startTime() const; - uint32_t navigationCount() const; + uint32_t navigationId() const; virtual AtomicString entryType() const = 0; virtual PerformanceEntryType EntryTypeEnum() const = 0; // PerformanceNavigationTiming will override this due to @@ -114,7 +114,7 @@ return valid_timeline_entry_types.Contains(entry_type); } - static uint32_t GetNavigationCounter(ScriptState* script_state); + static uint32_t GetNavigationId(ScriptState* script_state); // PerformanceMark/Measure override this and it returns Mojo structure pointer // which has all members of PerformanceMark/Measure. Common data members are @@ -127,11 +127,11 @@ PerformanceEntry(const AtomicString& name, double start_time, double finish_time, - uint32_t navigation_count = 0); + uint32_t navigation_id = 1); PerformanceEntry(double duration, const AtomicString& name, double start_time, - uint32_t navigation_count = 0); + uint32_t navigation_id = 1); virtual void BuildJSONValue(V8ObjectBuilder&) const; @@ -142,7 +142,7 @@ const AtomicString name_; const double start_time_; const int index_; - const uint32_t navigation_count_; + const uint32_t navigation_id_; }; } // namespace blink
diff --git a/third_party/blink/renderer/core/timing/performance_entry.idl b/third_party/blink/renderer/core/timing/performance_entry.idl index 06da7d23..8c8d8bd8 100644 --- a/third_party/blink/renderer/core/timing/performance_entry.idl +++ b/third_party/blink/renderer/core/timing/performance_entry.idl
@@ -36,6 +36,6 @@ readonly attribute DOMString entryType; readonly attribute DOMHighResTimeStamp startTime; readonly attribute DOMHighResTimeStamp duration; - [RuntimeEnabled=NavigationCounter] readonly attribute unsigned long navigationCount; + [RuntimeEnabled=NavigationId] readonly attribute unsigned long navigationId; [CallWith=ScriptState, ImplementedAs=toJSONForBinding] object toJSON(); };
diff --git a/third_party/blink/renderer/core/timing/performance_entry_test.cc b/third_party/blink/renderer/core/timing/performance_entry_test.cc index 090e40a..42d6ad4c 100644 --- a/third_party/blink/renderer/core/timing/performance_entry_test.cc +++ b/third_party/blink/renderer/core/timing/performance_entry_test.cc
@@ -17,12 +17,12 @@ V8TestingScope scope; ScriptState* script_state = scope.GetScriptState(); - EXPECT_EQ(0u, PerformanceEntry::GetNavigationCounter(script_state)); + EXPECT_EQ(1u, PerformanceEntry::GetNavigationId(script_state)); - scope.GetFrame().IncrementNavigationCounter(); - EXPECT_EQ(1u, PerformanceEntry::GetNavigationCounter(script_state)); + scope.GetFrame().IncrementNavigationId(); + EXPECT_EQ(2u, PerformanceEntry::GetNavigationId(script_state)); - scope.GetFrame().IncrementNavigationCounter(); - EXPECT_EQ(2u, PerformanceEntry::GetNavigationCounter(script_state)); + scope.GetFrame().IncrementNavigationId(); + EXPECT_EQ(3u, PerformanceEntry::GetNavigationId(script_state)); } } // namespace blink
diff --git a/third_party/blink/renderer/core/timing/performance_mark.cc b/third_party/blink/renderer/core/timing/performance_mark.cc index 85f7289e..baaae73 100644 --- a/third_party/blink/renderer/core/timing/performance_mark.cc +++ b/third_party/blink/renderer/core/timing/performance_mark.cc
@@ -23,8 +23,8 @@ base::TimeTicks unsafe_time_for_traces, scoped_refptr<SerializedScriptValue> serialized_detail, ExceptionState& exception_state, - uint32_t navigation_count) - : PerformanceEntry(name, start_time, start_time, navigation_count), + uint32_t navigation_id) + : PerformanceEntry(name, start_time, start_time, navigation_id), serialized_detail_(std::move(serialized_detail)), unsafe_time_for_traces_(unsafe_time_for_traces) {} @@ -90,11 +90,10 @@ if (exception_state.HadException()) return nullptr; - uint32_t navigation_count = - PerformanceEntry::GetNavigationCounter(script_state); + uint32_t navigation_id = PerformanceEntry::GetNavigationId(script_state); return MakeGarbageCollected<PerformanceMark>( mark_name, start, unsafe_start_for_traces, std::move(serialized_detail), - exception_state, navigation_count); + exception_state, navigation_id); } AtomicString PerformanceMark::entryType() const {
diff --git a/third_party/blink/renderer/core/timing/performance_mark_test.cc b/third_party/blink/renderer/core/timing/performance_mark_test.cc index 9f953c7..ff0c634 100644 --- a/third_party/blink/renderer/core/timing/performance_mark_test.cc +++ b/third_party/blink/renderer/core/timing/performance_mark_test.cc
@@ -50,7 +50,7 @@ ASSERT_EQ(SerializedScriptValue::NullValue()->Deserialize(isolate), pm->detail(script_state).V8Value()); - ASSERT_EQ(1u, pm->navigationCount()); + ASSERT_EQ(1u, pm->navigationId()); } TEST(PerformanceMarkTest, ConstructionWithDetail) {
diff --git a/third_party/blink/renderer/core/timing/performance_measure.cc b/third_party/blink/renderer/core/timing/performance_measure.cc index 337f7f4..7a05d7c 100644 --- a/third_party/blink/renderer/core/timing/performance_measure.cc +++ b/third_party/blink/renderer/core/timing/performance_measure.cc
@@ -23,7 +23,7 @@ : PerformanceEntry(name, start_time, end_time, - PerformanceEntry::GetNavigationCounter(script_state)), + PerformanceEntry::GetNavigationId(script_state)), serialized_detail_(serialized_detail) {} // static
diff --git a/third_party/blink/renderer/modules/autofill_assistant/node_signals.cc b/third_party/blink/renderer/modules/autofill_assistant/node_signals.cc index 4b10944..ea255d57 100644 --- a/third_party/blink/renderer/modules/autofill_assistant/node_signals.cc +++ b/third_party/blink/renderer/modules/autofill_assistant/node_signals.cc
@@ -29,6 +29,7 @@ #include "third_party/blink/renderer/platform/wtf/hash_map.h" #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h" #include "third_party/blink/renderer/platform/wtf/text/string_builder.h" +#include "third_party/blink/renderer/platform/wtf/text/string_impl.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" namespace blink { @@ -38,6 +39,10 @@ constexpr double kToleranceForGeometry = 1e-5; constexpr int kMaxCSSPixelDistance = 30; +constexpr char kShippingFormType[] = "SHIPPING"; +constexpr char kBillingFormType[] = "BILLING"; +constexpr char kAfterLabel[] = "AFTRLBL"; + WebString JoinStrings(const WebVector<WebString>& strings, const char* separator) { StringBuilder builder; @@ -166,13 +171,9 @@ // Add label name based on ancestors. // Example: <label>Label <input></label> WebString GetLabelRelatedChild(const Element& element) { - Node* document = element.ownerDocument(); Node* node = element.parentNode(); - while (node != document) { - if (!node) { - break; - } - if (node->IsElementNode() && node->HasTagName(html_names::kLabelTag)) { + while (node) { + if (node->HasTagName(html_names::kLabelTag)) { Element* label = DynamicTo<Element>(node); if (!IsVisible(*label)) { return WebString(); @@ -281,7 +282,7 @@ continue; } - WebString text = DynamicTo<Text>(node)->wholeText(); + WebString text(DynamicTo<Text>(node)->wholeText()); if (!text.IsNull() && !text.IsEmpty()) { distance_and_text.push_back({distance, text}); if (distance < closest_distance) { @@ -338,16 +339,12 @@ // Example: <fieldset><legend>Legend</legend><input/><fieldset> void GetFieldsetLegends(const Element& element, AutofillAssistantContextFeatures* features) { - Node* document = element.ownerDocument(); Node* node = element.parentNode(); - while (node != document) { - if (!node) { + while (node) { + if (node->HasTagName(html_names::kFormTag)) { break; } - if (node->IsElementNode() && node->HasTagName(html_names::kFormTag)) { - break; - } - if (node->IsElementNode() && node->HasTagName(html_names::kFieldsetTag)) { + if (node->HasTagName(html_names::kFieldsetTag)) { AddFirstLegendOfFieldset(node, &features->header_text); } node = node->parentNode(); @@ -391,11 +388,120 @@ } } +bool HasVisibleParent(const Node& node) { + if (!node.parentNode() || !node.parentNode()->IsElementNode()) { + return false; + } + + return IsVisible(*DynamicTo<Element>(*node.parentNode())); +} + +bool IsShippingFormObjective(const AtomicString& text) { + return text.Contains("ship", kTextCaseUnicodeInsensitive) || + text.Contains("deliver", kTextCaseUnicodeInsensitive); +} + +bool IsBillingFormObjective(const AtomicString& text) { + return text.Contains("billing", kTextCaseUnicodeInsensitive) || + text.Contains("payment", kTextCaseUnicodeInsensitive); +} + +WebVector<WebString> GetObjectivesFromAtomicString(const AtomicString& text) { + WebVector<WebString> objectives; + if (IsShippingFormObjective(text)) { + objectives.push_back(WebString::FromUTF8(kShippingFormType)); + } + if (IsBillingFormObjective(text)) { + objectives.push_back(WebString::FromUTF8(kBillingFormType)); + } + return objectives; +} + +WebVector<WebString> GetObjectivesFromTextNode(const Node& node) { + return GetObjectivesFromAtomicString( + AtomicString(DynamicTo<Text>(node)->wholeText())); +} + +WebVector<WebString> GetObjectivesFromElementNode(const Node& node) { + const Element* element = DynamicTo<Element>(node); + return GetObjectivesFromAtomicString(AtomicString( + String::FromUTF8(element->getAttribute(html_names::kIdAttr).Utf8() + " " + + element->getAttribute(html_names::kNameAttr).Utf8()))); +} + +bool HasLabelAncestor(const Node& node) { + const Node* iter = &node; + while (iter) { + if (iter->HasTagName(html_names::kLabelTag)) { + return true; + } + iter = iter->parentNode(); + } + return false; +} + +void AddFormTypeForContext(const Element& element, + AutofillAssistantContextFeatures* features) { + WebVector<WebString> best_objectives; + // First attempt: Look at text nodes. + // |after_label| captures the presence of a label between the header and the + // input, typically a checkbox "billing same as shipping". + bool after_label = false; + for (Node& node : NodeTraversal::DescendantsOf(*element.ownerDocument())) { + if (&node == &element) { + break; + } + if (!node.IsTextNode() || !HasVisibleParent(node)) { + continue; + } + + WebVector<WebString> objectives = GetObjectivesFromTextNode(node); + if (objectives.empty()) { + continue; + } + + if (HasLabelAncestor(node)) { + after_label = true; + } else { + after_label = false; + best_objectives = objectives; + } + } + + if (best_objectives.empty()) { + // Second attempt: Try with id and names of ancestor nodes. + after_label = false; + Node* iter = element.parentNode(); + while (iter && !iter->IsDocumentNode()) { + if (iter->IsElementNode()) { + WebVector<WebString> objectives = GetObjectivesFromElementNode(*iter); + if (!objectives.empty()) { + best_objectives = objectives; + } + } + iter = iter->parentNode(); + } + } + + if (best_objectives.empty()) { + return; + } + + WebVector<WebString> form_type; + if (after_label) { + form_type.push_back(kAfterLabel); + } + for (const WebString& objective : best_objectives) { + form_type.push_back(objective); + } + features->form_type = JoinStrings(form_type, " "); +} + void CollectContextFeatures(const Element& element, AutofillAssistantContextFeatures* features) { GetFieldsetLegends(element, features); AddHeaders(element, features); - // TODO(b/204839535): Implement form type. + AddFormTypeForContext(element, features); } void CollectSignalsForNode(
diff --git a/third_party/blink/renderer/modules/autofill_assistant/node_signals_test.cc b/third_party/blink/renderer/modules/autofill_assistant/node_signals_test.cc index 00dfa5c7..ef8805e6 100644 --- a/third_party/blink/renderer/modules/autofill_assistant/node_signals_test.cc +++ b/third_party/blink/renderer/modules/autofill_assistant/node_signals_test.cc
@@ -413,4 +413,126 @@ EXPECT_TRUE(results[0].context_features.header_text.empty()); } +TEST_F(NodeSignalsTest, GetShippingFormTypeFromText) { + SetBodyContent(R"( + <div>Shipping</div> + <input> + )"); + + WebVector<AutofillAssistantNodeSignals> results = + GetAutofillAssistantNodeSignals(WebDocument(&GetDocument())); + ASSERT_EQ(results.size(), 1u); + + EXPECT_EQ(results[0].context_features.form_type, "SHIPPING"); +} + +TEST_F(NodeSignalsTest, GetBillingFormTypeFromText) { + SetBodyContent(R"( + <div>Billing</div> + <input> + )"); + + WebVector<AutofillAssistantNodeSignals> results = + GetAutofillAssistantNodeSignals(WebDocument(&GetDocument())); + ASSERT_EQ(results.size(), 1u); + + EXPECT_EQ(results[0].context_features.form_type, "BILLING"); +} + +TEST_F(NodeSignalsTest, DoNotGetFormTypeFromUnrelatedText) { + SetBodyContent(R"( + <div>Enter Address</div> + <input> + )"); + + WebVector<AutofillAssistantNodeSignals> results = + GetAutofillAssistantNodeSignals(WebDocument(&GetDocument())); + ASSERT_EQ(results.size(), 1u); + + EXPECT_TRUE(results[0].context_features.form_type.IsEmpty()); +} + +TEST_F(NodeSignalsTest, DoNotGetFormTypeFromTextBelow) { + SetBodyContent(R"( + <input> + <div>Shipping</div> + )"); + + WebVector<AutofillAssistantNodeSignals> results = + GetAutofillAssistantNodeSignals(WebDocument(&GetDocument())); + ASSERT_EQ(results.size(), 1u); + + EXPECT_TRUE(results[0].context_features.form_type.IsEmpty()); +} + +TEST_F(NodeSignalsTest, GetFormTypeFromAncestorId) { + SetBodyContent(R"( + <div id="shipping_address"> + <input> + </div> + )"); + + WebVector<AutofillAssistantNodeSignals> results = + GetAutofillAssistantNodeSignals(WebDocument(&GetDocument())); + ASSERT_EQ(results.size(), 1u); + + EXPECT_EQ(results[0].context_features.form_type, "SHIPPING"); +} + +TEST_F(NodeSignalsTest, GetFormTypeFromAncestorName) { + SetBodyContent(R"( + <div name="shipping_address"> + <input> + </div> + )"); + + WebVector<AutofillAssistantNodeSignals> results = + GetAutofillAssistantNodeSignals(WebDocument(&GetDocument())); + ASSERT_EQ(results.size(), 1u); + + EXPECT_EQ(results[0].context_features.form_type, "SHIPPING"); +} + +TEST_F(NodeSignalsTest, GetFormTypeFromTextOverAncestor) { + SetBodyContent(R"( + <div name="shipping_address"> + <div>Billing</div> + <input> + </div> + )"); + + WebVector<AutofillAssistantNodeSignals> results = + GetAutofillAssistantNodeSignals(WebDocument(&GetDocument())); + ASSERT_EQ(results.size(), 1u); + + EXPECT_EQ(results[0].context_features.form_type, "BILLING"); +} + +TEST_F(NodeSignalsTest, DoNotGetFormTypeFromLabel) { + SetBodyContent(R"( + <label>Shipping</label> + <input> + )"); + + WebVector<AutofillAssistantNodeSignals> results = + GetAutofillAssistantNodeSignals(WebDocument(&GetDocument())); + ASSERT_EQ(results.size(), 1u); + + EXPECT_TRUE(results[0].context_features.form_type.IsEmpty()); +} + +TEST_F(NodeSignalsTest, GetFormTypeAfterLabel) { + SetBodyContent(R"( + <div>Billing</div> + <label>Shipping address is the same</label> + <input> + )"); + + WebVector<AutofillAssistantNodeSignals> results = + GetAutofillAssistantNodeSignals(WebDocument(&GetDocument())); + ASSERT_EQ(results.size(), 1u); + + EXPECT_EQ(results[0].context_features.form_type, "AFTRLBL BILLING"); +} + } // namespace blink
diff --git a/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc b/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc index 84bc6e2..54c6492 100644 --- a/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc +++ b/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc
@@ -1118,8 +1118,9 @@ return promise; } - FederatedCredential* credential = - FederatedCredential::Create(provider_url, client_id, options); + FederatedCredential* credential = FederatedCredential::Create( + provider_url, client_id, federated_identity_provider->getHintOr(""), + options); resolver->Resolve(credential); return promise; }
diff --git a/third_party/blink/renderer/modules/credentialmanager/federated_credential.cc b/third_party/blink/renderer/modules/credentialmanager/federated_credential.cc index 113ac96..d6ebdba 100644 --- a/third_party/blink/renderer/modules/credentialmanager/federated_credential.cc +++ b/third_party/blink/renderer/modules/credentialmanager/federated_credential.cc
@@ -166,9 +166,10 @@ FederatedCredential* FederatedCredential::Create( const KURL& provider_url, const String& client_id, + const String& hint, const CredentialRequestOptions* options) { return MakeGarbageCollected<FederatedCredential>(provider_url, client_id, - options); + hint, options); } FederatedCredential::FederatedCredential( @@ -186,9 +187,9 @@ FederatedCredential::FederatedCredential( const KURL& provider_url, const String& client_id, + const String& hint, const CredentialRequestOptions* options) - : Credential(/* id = */ options->federated()->getHintOr(""), - kFederatedCredentialType), + : Credential(/* id = */ hint, kFederatedCredentialType), provider_origin_(SecurityOrigin::Create(provider_url)), provider_url_(provider_url), client_id_(client_id),
diff --git a/third_party/blink/renderer/modules/credentialmanager/federated_credential.h b/third_party/blink/renderer/modules/credentialmanager/federated_credential.h index 3a70261b..4f640fd 100644 --- a/third_party/blink/renderer/modules/credentialmanager/federated_credential.h +++ b/third_party/blink/renderer/modules/credentialmanager/federated_credential.h
@@ -33,6 +33,7 @@ static FederatedCredential* Create(const KURL& provider_url, const String& client_id, + const String& hint, const CredentialRequestOptions* options); FederatedCredential(const String& id, @@ -42,6 +43,7 @@ FederatedCredential(const KURL& provider_url, const String& client_id, + const String& hint, const CredentialRequestOptions* options); void Trace(Visitor*) const override;
diff --git a/third_party/blink/renderer/modules/credentialmanager/federated_credential_request_options.idl b/third_party/blink/renderer/modules/credentialmanager/federated_credential_request_options.idl index 5076b637..e572171 100644 --- a/third_party/blink/renderer/modules/credentialmanager/federated_credential_request_options.idl +++ b/third_party/blink/renderer/modules/credentialmanager/federated_credential_request_options.idl
@@ -7,5 +7,4 @@ sequence<(DOMString or FederatedIdentityProvider)> providers; sequence<DOMString> protocols; boolean preferAutoSignIn = false; - DOMString hint; };
diff --git a/third_party/blink/renderer/modules/credentialmanager/federated_identity_provider.idl b/third_party/blink/renderer/modules/credentialmanager/federated_identity_provider.idl index d64dd3f..970e910 100644 --- a/third_party/blink/renderer/modules/credentialmanager/federated_identity_provider.idl +++ b/third_party/blink/renderer/modules/credentialmanager/federated_identity_provider.idl
@@ -8,4 +8,6 @@ // URL for the Identity Provider. required USVString url; required USVString clientId; + // Optional hint for the account ID. + USVString hint; };
diff --git a/third_party/blink/renderer/modules/delegated_ink/delegated_ink_trail_presenter.cc b/third_party/blink/renderer/modules/delegated_ink/delegated_ink_trail_presenter.cc index 8e0d9dc8b..1d8035b 100644 --- a/third_party/blink/renderer/modules/delegated_ink/delegated_ink_trail_presenter.cc +++ b/third_party/blink/renderer/modules/delegated_ink/delegated_ink_trail_presenter.cc
@@ -137,10 +137,11 @@ point, diameter_in_physical_pixels, color.Rgb(), evt->PlatformTimeStamp(), area, is_hovering); - TRACE_EVENT_INSTANT1("delegated_ink_trails", - "DelegatedInkTrailPresenter::updateInkTrailStartPoint", - TRACE_EVENT_SCOPE_THREAD, "ink metadata", - metadata->ToString()); + TRACE_EVENT_WITH_FLOW1("delegated_ink_trails", + "DelegatedInkTrailPresenter::updateInkTrailStartPoint", + TRACE_ID_GLOBAL(metadata->trace_id()), + TRACE_EVENT_FLAG_FLOW_OUT, "metadata", + metadata->ToString()); Page* page = local_frame_->GetPage(); page->GetChromeClient().SetDelegatedInkMetadata(local_frame_,
diff --git a/third_party/blink/renderer/modules/font_access/font_manager.cc b/third_party/blink/renderer/modules/font_access/font_manager.cc index 9afa081..d949fe5 100644 --- a/third_party/blink/renderer/modules/font_access/font_manager.cc +++ b/third_party/blink/renderer/modules/font_access/font_manager.cc
@@ -40,7 +40,13 @@ } ScriptPromise FontManager::query(ScriptState* script_state, - const QueryOptions* options) { + const QueryOptions* options, + ExceptionState& exception_state) { + if (!remote_manager_.is_bound()) { + exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, + "FontAccessManager backend went away"); + return ScriptPromise(); + } DCHECK(options->hasSelect()); auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state); ScriptPromise promise = resolver->Promise();
diff --git a/third_party/blink/renderer/modules/font_access/font_manager.h b/third_party/blink/renderer/modules/font_access/font_manager.h index 0785e1c..7ab8499 100644 --- a/third_party/blink/renderer/modules/font_access/font_manager.h +++ b/third_party/blink/renderer/modules/font_access/font_manager.h
@@ -32,7 +32,9 @@ FontManager operator=(const FontManager&) = delete; // FontManager IDL interface implementation. - ScriptPromise query(ScriptState*, const QueryOptions* options); + ScriptPromise query(ScriptState*, + const QueryOptions* options, + ExceptionState& exception_state); void Trace(blink::Visitor*) const override;
diff --git a/third_party/blink/renderer/modules/font_access/font_manager.idl b/third_party/blink/renderer/modules/font_access/font_manager.idl index 08e5b63a..d6978ca 100644 --- a/third_party/blink/renderer/modules/font_access/font_manager.idl +++ b/third_party/blink/renderer/modules/font_access/font_manager.idl
@@ -8,5 +8,5 @@ SecureContext, RuntimeEnabled=FontAccess ] interface FontManager { - [CallWith=ScriptState, Measure] Promise<sequence<FontMetadata>> query(optional QueryOptions options = {}); + [CallWith=ScriptState, RaisesException, Measure] Promise<sequence<FontMetadata>> query(optional QueryOptions options = {}); };
diff --git a/third_party/blink/renderer/modules/mediastream/remote_media_stream_track_adapter.cc b/third_party/blink/renderer/modules/mediastream/remote_media_stream_track_adapter.cc index fca1ab1..03368c2f 100644 --- a/third_party/blink/renderer/modules/mediastream/remote_media_stream_track_adapter.cc +++ b/third_party/blink/renderer/modules/mediastream/remote_media_stream_track_adapter.cc
@@ -53,11 +53,10 @@ main_thread_, std::move(observer)); MediaStreamRemoteVideoSource* video_source = video_source_ptr.get(); InitializeTrack( - MediaStreamSource::kTypeVideo, + MediaStreamSource::kTypeVideo, std::move(video_source_ptr), std::make_unique<MediaStreamVideoTrack>( video_source, MediaStreamVideoSource::ConstraintsOnceCallback(), enabled)); - track()->Source()->SetPlatformSource(std::move(video_source_ptr)); MediaStreamSource::Capabilities capabilities; capabilities.device_id = id(); @@ -99,14 +98,13 @@ void RemoteAudioTrackAdapter::InitializeWebAudioTrack( const scoped_refptr<base::SingleThreadTaskRunner>& main_thread) { - // TODO(crbug.com/1302689): Create and pass a MediaStreamAudioTrack here, - // rather than relying on the source to create and set it in ConnectToTrack(). - InitializeTrack(MediaStreamSource::kTypeAudio, /*platform_track=*/nullptr); - auto source = std::make_unique<PeerConnectionRemoteAudioSource>( observed_track().get(), main_thread); auto* source_ptr = source.get(); - track()->Source()->SetPlatformSource(std::move(source)); + // TODO(crbug.com/1302689): Create and pass a MediaStreamAudioTrack here, + // rather than relying on the source to create and set it in ConnectToTrack(). + InitializeTrack(MediaStreamSource::kTypeAudio, std::move(source), + /*platform_track=*/nullptr); MediaStreamSource::Capabilities capabilities; capabilities.device_id = id();
diff --git a/third_party/blink/renderer/modules/mediastream/remote_media_stream_track_adapter.h b/third_party/blink/renderer/modules/mediastream/remote_media_stream_track_adapter.h index 895509e..5289899 100644 --- a/third_party/blink/renderer/modules/mediastream/remote_media_stream_track_adapter.h +++ b/third_party/blink/renderer/modules/mediastream/remote_media_stream_track_adapter.h
@@ -83,12 +83,13 @@ void InitializeTrack( MediaStreamSource::StreamType type, + std::unique_ptr<WebPlatformMediaStreamSource> platform_source, std::unique_ptr<MediaStreamTrackPlatform> platform_track) { DCHECK(main_thread_->BelongsToCurrentThread()); DCHECK(!component_); - auto* source = MakeGarbageCollected<MediaStreamSource>(id_, type, id_, - true /*remote*/); + auto* source = MakeGarbageCollected<MediaStreamSource>( + id_, type, id_, true /*remote*/, std::move(platform_source)); if (platform_track) { component_ = MakeGarbageCollected<MediaStreamComponent>( id_, source, std::move(platform_track));
diff --git a/third_party/blink/renderer/modules/wake_lock/wake_lock_test_utils.cc b/third_party/blink/renderer/modules/wake_lock/wake_lock_test_utils.cc index c184102..c539bcff4 100644 --- a/third_party/blink/renderer/modules/wake_lock/wake_lock_test_utils.cc +++ b/third_party/blink/renderer/modules/wake_lock/wake_lock_test_utils.cc
@@ -33,7 +33,6 @@ namespace { void RunWithStack(base::RunLoop* run_loop) { - HeapPointersOnStackScope scan_stack(ThreadState::Current()); run_loop->Run(); }
diff --git a/third_party/blink/renderer/modules/webcodecs/codec_pressure_manager_test.cc b/third_party/blink/renderer/modules/webcodecs/codec_pressure_manager_test.cc index eef7e25..5acd99ec 100644 --- a/third_party/blink/renderer/modules/webcodecs/codec_pressure_manager_test.cc +++ b/third_party/blink/renderer/modules/webcodecs/codec_pressure_manager_test.cc
@@ -97,7 +97,6 @@ base::RunLoop run_loop; base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE, run_loop.QuitClosure()); - HeapPointersOnStackScope pointers_on_stack(ThreadState::Current()); run_loop.Run(); }
diff --git a/third_party/blink/renderer/modules/webdatabase/DEPS b/third_party/blink/renderer/modules/webdatabase/DEPS index 0d01ddac..b146f93c567 100644 --- a/third_party/blink/renderer/modules/webdatabase/DEPS +++ b/third_party/blink/renderer/modules/webdatabase/DEPS
@@ -1,6 +1,8 @@ include_rules = [ + "+base/command_line.h", "+base/files/file.h", "+base/task/task_traits.h", + "+base/test/scoped_command_line.h", "-third_party/blink/renderer/modules", "+third_party/blink/renderer/modules/modules_export.h", "+third_party/blink/renderer/modules/webdatabase",
diff --git a/third_party/blink/renderer/modules/webdatabase/dom_window_web_database.cc b/third_party/blink/renderer/modules/webdatabase/dom_window_web_database.cc index 977b1ac..93756b0 100644 --- a/third_party/blink/renderer/modules/webdatabase/dom_window_web_database.cc +++ b/third_party/blink/renderer/modules/webdatabase/dom_window_web_database.cc
@@ -26,6 +26,10 @@ #include "third_party/blink/renderer/modules/webdatabase/dom_window_web_database.h" +#include "base/command_line.h" +#include "base/feature_list.h" +#include "third_party/blink/public/common/features.h" +#include "third_party/blink/public/common/switches.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_database_callback.h" #include "third_party/blink/renderer/core/frame/local_dom_window.h" #include "third_party/blink/renderer/core/frame/web_feature.h" @@ -71,6 +75,14 @@ UseCounter::Count(window, WebFeature::kOpenWebDatabaseInsecureContext); } + if (!base::FeatureList::IsEnabled(blink::features::kWebSQLAccess) && + !base::CommandLine::ForCurrentProcess()->HasSwitch( + blink::switches::kWebSQLAccess)) { + exception_state.ThrowSecurityError( + "Access to the WebDatabase API is denied."); + return nullptr; + } + if (window.IsCrossSiteSubframeIncludingScheme()) { exception_state.ThrowSecurityError( "Access to the WebDatabase API is denied in third party contexts.");
diff --git a/third_party/blink/renderer/modules/webdatabase/dom_window_web_database_test.cc b/third_party/blink/renderer/modules/webdatabase/dom_window_web_database_test.cc index cceaf55c..fde19c2 100644 --- a/third_party/blink/renderer/modules/webdatabase/dom_window_web_database_test.cc +++ b/third_party/blink/renderer/modules/webdatabase/dom_window_web_database_test.cc
@@ -4,8 +4,13 @@ #include "third_party/blink/renderer/modules/webdatabase/dom_window_web_database.h" +#include "base/feature_list.h" #include "base/strings/strcat.h" +#include "base/test/scoped_command_line.h" +#include "base/test/scoped_feature_list.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/common/features.h" +#include "third_party/blink/public/common/switches.h" #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h" #include "third_party/blink/renderer/core/frame/frame_test_helpers.h" #include "third_party/blink/renderer/core/frame/local_dom_window.h" @@ -43,7 +48,19 @@ url_test_helpers::UnregisterAllURLsAndClearMemoryCache(); } -TEST(DOMWindowWebDatabaseTest, FirstPartyContextWebSQLIFrame) { +TEST(DOMWindowWebDatabaseTest, WebSQLThirdPartyContext) { + V8TestingScope scope; + OpenWebDatabaseInIFrame("http://not-example.test:0/", + "first_party/nested-originA.html", + "http://example.test:0/", "first_party/empty.html", + scope.GetExceptionState()); + // This error means the database opening was rejected. + EXPECT_TRUE(scope.GetExceptionState().HadException()); + EXPECT_EQ(scope.GetExceptionState().Code(), + static_cast<int>(DOMExceptionCode::kSecurityError)); +} + +TEST(DOMWindowWebDatabaseTest, WebSQLDefault) { V8TestingScope scope; OpenWebDatabaseInIFrame("http://example.test:0/", "first_party/nested-originA.html", @@ -56,9 +73,68 @@ static_cast<int>(DOMExceptionCode::kInvalidStateError)); } -TEST(DOMWindowWebDatabaseTest, ThirdPartyContextWebSQLIFrame) { +TEST(DOMWindowWebDatabaseTest, WebSQLSwitchOnFeatureOn) { + base::test::ScopedCommandLine scoped_command_line; + scoped_command_line.GetProcessCommandLine()->AppendSwitch( + blink::switches::kWebSQLAccess); + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeature(blink::features::kWebSQLAccess); V8TestingScope scope; - OpenWebDatabaseInIFrame("http://not-example.test:0/", + OpenWebDatabaseInIFrame("http://example.test:0/", + "first_party/nested-originA.html", + "http://example.test:0/", "first_party/empty.html", + scope.GetExceptionState()); + // Insufficient state exists to actually open a database, but this error + // means it was tried. + EXPECT_TRUE(scope.GetExceptionState().HadException()); + EXPECT_EQ(scope.GetExceptionState().Code(), + static_cast<int>(DOMExceptionCode::kInvalidStateError)); +} + +TEST(DOMWindowWebDatabaseTest, WebSQLSwitchOnFeatureOff) { + base::test::ScopedCommandLine scoped_command_line; + scoped_command_line.GetProcessCommandLine()->AppendSwitch( + blink::switches::kWebSQLAccess); + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndDisableFeature(blink::features::kWebSQLAccess); + V8TestingScope scope; + OpenWebDatabaseInIFrame("http://example.test:0/", + "first_party/nested-originA.html", + "http://example.test:0/", "first_party/empty.html", + scope.GetExceptionState()); + // Insufficient state exists to actually open a database, but this error + // means it was tried. + EXPECT_TRUE(scope.GetExceptionState().HadException()); + EXPECT_EQ(scope.GetExceptionState().Code(), + static_cast<int>(DOMExceptionCode::kInvalidStateError)); +} + +TEST(DOMWindowWebDatabaseTest, WebSQLSwitchOffFeatureOn) { + base::test::ScopedCommandLine scoped_command_line; + scoped_command_line.GetProcessCommandLine()->RemoveSwitch( + blink::switches::kWebSQLAccess); + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeature(blink::features::kWebSQLAccess); + V8TestingScope scope; + OpenWebDatabaseInIFrame("http://example.test:0/", + "first_party/nested-originA.html", + "http://example.test:0/", "first_party/empty.html", + scope.GetExceptionState()); + // Insufficient state exists to actually open a database, but this error + // means it was tried. + EXPECT_TRUE(scope.GetExceptionState().HadException()); + EXPECT_EQ(scope.GetExceptionState().Code(), + static_cast<int>(DOMExceptionCode::kInvalidStateError)); +} + +TEST(DOMWindowWebDatabaseTest, WebSQLSwitchOffFeatureOff) { + base::test::ScopedCommandLine scoped_command_line; + scoped_command_line.GetProcessCommandLine()->RemoveSwitch( + blink::switches::kWebSQLAccess); + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndDisableFeature(blink::features::kWebSQLAccess); + V8TestingScope scope; + OpenWebDatabaseInIFrame("http://example.test:0/", "first_party/nested-originA.html", "http://example.test:0/", "first_party/empty.html", scope.GetExceptionState());
diff --git a/third_party/blink/renderer/platform/exported/video_capture/web_video_capture_impl_manager.cc b/third_party/blink/renderer/platform/exported/video_capture/web_video_capture_impl_manager.cc index 4c326ee..37171db 100644 --- a/third_party/blink/renderer/platform/exported/video_capture/web_video_capture_impl_manager.cc +++ b/third_party/blink/renderer/platform/exported/video_capture/web_video_capture_impl_manager.cc
@@ -101,11 +101,7 @@ devices_.emplace_back(DeviceEntry()); it = devices_.end() - 1; it->session_id = id; - it->impl = CreateVideoCaptureImplForTesting(id); - if (!it->impl) { - it->impl = std::make_unique<VideoCaptureImpl>( - id, render_main_task_runner_, browser_interface_broker); - } + it->impl = CreateVideoCaptureImpl(id, browser_interface_broker); } ++it->client_count; @@ -217,9 +213,11 @@ } std::unique_ptr<VideoCaptureImpl> -WebVideoCaptureImplManager::CreateVideoCaptureImplForTesting( - const media::VideoCaptureSessionId& session_id) const { - return nullptr; +WebVideoCaptureImplManager::CreateVideoCaptureImpl( + const media::VideoCaptureSessionId& session_id, + BrowserInterfaceBrokerProxy* browser_interface_broker) const { + return std::make_unique<VideoCaptureImpl>( + session_id, render_main_task_runner_, browser_interface_broker); } void WebVideoCaptureImplManager::StopCapture(
diff --git a/third_party/blink/renderer/platform/exported/video_capture/web_video_capture_impl_manager_test.cc b/third_party/blink/renderer/platform/exported/video_capture/web_video_capture_impl_manager_test.cc index 9dbc862..e655dd8 100644 --- a/third_party/blink/renderer/platform/exported/video_capture/web_video_capture_impl_manager_test.cc +++ b/third_party/blink/renderer/platform/exported/video_capture/web_video_capture_impl_manager_test.cc
@@ -127,8 +127,9 @@ ~MockVideoCaptureImplManager() override {} private: - std::unique_ptr<VideoCaptureImpl> CreateVideoCaptureImplForTesting( - const media::VideoCaptureSessionId& session_id) const override { + std::unique_ptr<VideoCaptureImpl> CreateVideoCaptureImpl( + const media::VideoCaptureSessionId& session_id, + BrowserInterfaceBrokerProxy*) const override { auto video_capture_impl = std::make_unique<MockVideoCaptureImpl>( session_id, pause_callback_, stop_capture_callback_); video_capture_impl->SetVideoCaptureHostForTesting(video_capture_impl.get());
diff --git a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc index 99dc3caf..8ba35e8 100644 --- a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc +++ b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc
@@ -615,7 +615,9 @@ return false; DCHECK(!ResourceProvider()); - layer_->ClearTexture(); + if (layer_) + layer_->ClearTexture(); + base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper = SharedGpuContext::ContextProviderWrapper();
diff --git a/third_party/blink/renderer/platform/loader/BUILD.gn b/third_party/blink/renderer/platform/loader/BUILD.gn index 517afd8..b19b71ef 100644 --- a/third_party/blink/renderer/platform/loader/BUILD.gn +++ b/third_party/blink/renderer/platform/loader/BUILD.gn
@@ -277,6 +277,7 @@ "//third_party/blink/public:blink_headers", "//third_party/blink/renderer/platform:platform", "//third_party/blink/renderer/platform/blob:generator", + "//third_party/blink/renderer/platform/heap:test_support", "//third_party/blink/renderer/platform/scheduler:test_support", "//third_party/icu", ]
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index 8833778..36e25896 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -746,7 +746,7 @@ }, { name: "CSSPseudoHas", - status: "test", + status: "experimental", }, { name: "CSSPseudoHasInSnapshotProfile", @@ -1558,7 +1558,7 @@ status: "stable", }, { - name: "NavigationCounter", + name: "NavigationId", status: "experimental", }, {
diff --git a/third_party/blink/renderer/platform/testing/blink_perf_test_suite.h b/third_party/blink/renderer/platform/testing/blink_perf_test_suite.h index d1d263e2..7ca65919 100644 --- a/third_party/blink/renderer/platform/testing/blink_perf_test_suite.h +++ b/third_party/blink/renderer/platform/testing/blink_perf_test_suite.h
@@ -11,6 +11,8 @@ namespace blink { class BlinkPerfTestSuite : public base::TestSuite { + STACK_ALLOCATED(); + public: BlinkPerfTestSuite(int argc, char** argv);
diff --git a/third_party/blink/renderer/platform/testing/testing_platform_support.cc b/third_party/blink/renderer/platform/testing/testing_platform_support.cc index a9498d2..9587724 100644 --- a/third_party/blink/renderer/platform/testing/testing_platform_support.cc +++ b/third_party/blink/renderer/platform/testing/testing_platform_support.cc
@@ -135,7 +135,6 @@ } void TestingPlatformSupport::RunUntilIdle() { - HeapPointersOnStackScope scan_stack(ThreadState::Current()); base::RunLoop().RunUntilIdle(); } @@ -195,6 +194,7 @@ v8_platform_for_heap_testing_ = std::make_unique<HeapTestingPlatformAdapter>(gin::V8Platform::Get()); ThreadState::AttachMainThreadForTesting(v8_platform_for_heap_testing_.get()); + conservative_gc_scope_.emplace(ThreadState::Current()); http_names::Init(); fetch_initiator_type_names::Init();
diff --git a/third_party/blink/renderer/platform/testing/testing_platform_support.h b/third_party/blink/renderer/platform/testing/testing_platform_support.h index 556342ed..ba9131e 100644 --- a/third_party/blink/renderer/platform/testing/testing_platform_support.h +++ b/third_party/blink/renderer/platform/testing/testing_platform_support.h
@@ -38,6 +38,7 @@ #include "base/callback.h" #include "base/memory/scoped_refptr.h" #include "third_party/blink/public/platform/platform.h" +#include "third_party/blink/renderer/platform/heap/heap_test_utilities.h" #include "third_party/blink/renderer/platform/platform_export.h" #include "third_party/blink/renderer/platform/testing/code_cache_loader_mock.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" @@ -155,6 +156,8 @@ }; class ScopedUnittestsEnvironmentSetup final { + STACK_ALLOCATED(); + public: ScopedUnittestsEnvironmentSetup(int argc, char** argv); ScopedUnittestsEnvironmentSetup(const ScopedUnittestsEnvironmentSetup&) = @@ -169,6 +172,7 @@ std::unique_ptr<Platform> dummy_platform_; std::unique_ptr<v8::Platform> v8_platform_for_heap_testing_; std::unique_ptr<TestingPlatformSupport> testing_platform_support_; + absl::optional<HeapPointersOnStackScope> conservative_gc_scope_; }; } // namespace blink
diff --git a/third_party/blink/renderer/platform/testing/unit_test_helpers.cc b/third_party/blink/renderer/platform/testing/unit_test_helpers.cc index 0bfefb6..cbe10b84 100644 --- a/third_party/blink/renderer/platform/testing/unit_test_helpers.cc +++ b/third_party/blink/renderer/platform/testing/unit_test_helpers.cc
@@ -73,9 +73,6 @@ } void EnterRunLoop() { - // The following runloop can execute non-nested tasks with heap pointers - // living on stack, so we force both Oilpan and unified GC to visit the stack. - HeapPointersOnStackScope scan_stack(ThreadState::Current()); base::RunLoop().Run(); }
diff --git a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py index a23d0a29..2b6cdf4 100755 --- a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py +++ b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
@@ -1649,6 +1649,14 @@ }, { 'paths': [ + 'third_party/blink/renderer/modules/webdatabase/dom_window_web_database.cc', + ], + 'allowed': [ + 'base::CommandLine', + ] + }, + { + 'paths': [ 'third_party/blink/renderer/controller/blink_shutdown.cc', ], 'allowed': [
diff --git a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng index 421e473..aef99bd 100644 --- a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng +++ b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
@@ -371,13 +371,6 @@ crbug.com/1045599 http/tests/devtools/elements/highlight/highlight-css-grid.js [ Failure ] crbug.com/1045599 http/tests/devtools/elements/highlight/highlight-display-locked-grid.js [ Failure ] crbug.com/1045599 http/tests/devtools/elements/highlight/highlight-multiple-css-grid.js [ Failure ] -crbug.com/1045599 virtual/shared_array_buffer_on_desktop/http/tests/devtools/elements/highlight/highlight-css-grid-area.js [ Failure ] -crbug.com/1045599 virtual/shared_array_buffer_on_desktop/http/tests/devtools/elements/highlight/highlight-css-grid-direction.js [ Failure ] -crbug.com/1045599 virtual/shared_array_buffer_on_desktop/http/tests/devtools/elements/highlight/highlight-css-grid-huge.js [ Failure ] -crbug.com/1045599 virtual/shared_array_buffer_on_desktop/http/tests/devtools/elements/highlight/highlight-css-grid-line-names.js [ Failure ] -crbug.com/1045599 virtual/shared_array_buffer_on_desktop/http/tests/devtools/elements/highlight/highlight-css-grid.js [ Failure ] -crbug.com/1045599 virtual/shared_array_buffer_on_desktop/http/tests/devtools/elements/highlight/highlight-display-locked-grid.js [ Failure ] -crbug.com/1045599 virtual/shared_array_buffer_on_desktop/http/tests/devtools/elements/highlight/highlight-multiple-css-grid.js [ Failure ] ### Subgrid will not be implemented in legacy. crbug.com/618969 external/wpt/css/css-grid/subgrid/* [ Skip ] @@ -1152,7 +1145,6 @@ crbug.com/1035582 virtual/scalefactor200withzoom/fast/hidpi/static/popup-menu-appearance.html [ Failure Timeout ] crbug.com/1035582 virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance.html [ Failure Timeout ] crbug.com/1035582 http/tests/devtools/sources/debugger-breakpoints/disable-breakpoints.js [ Failure Timeout ] -crbug.com/1035582 virtual/shared_array_buffer_on_desktop/http/tests/devtools/sources/debugger-breakpoints/disable-breakpoints.js [ Failure Timeout ] crbug.com/1035582 paint/invalidation/forms/checkbox-focus-by-mouse-then-keydown.html [ Failure ] crbug.com/1035582 paint/invalidation/forms/radio-focus-by-mouse-then-keydown.html [ Failure ] crbug.com/1035582 editing/input/linux_rtl_composition_underline.html [ Failure ] @@ -1309,6 +1301,7 @@ crbug.com/377847 external/wpt/css/css-tables/subpixel-table-width-001.html [ Failure ] crbug.com/598134 external/wpt/css/css-tables/table-has-box-sizing-border-box-002.html [ Failure ] crbug.com/764031 external/wpt/css/css-tables/toggle-row-display-property-001.html [ Failure ] +crbug.com/591099 external/wpt/css/css-tables/visibility-collapse-border-spacing.html [ Failure ] crbug.com/174167 external/wpt/css/css-tables/visibility-collapse-col-001.html [ Failure ] crbug.com/174167 external/wpt/css/css-tables/visibility-collapse-col-002.html [ Failure ] crbug.com/174167 external/wpt/css/css-tables/visibility-collapse-col-003.html [ Failure ] @@ -1577,7 +1570,6 @@ crbug.com/591099 external/wpt/css/css-sizing/aspect-ratio/flex-aspect-ratio-029.html [ Failure ] crbug.com/591099 external/wpt/css/css-sizing/aspect-ratio/flex-aspect-ratio-030.html [ Failure ] crbug.com/591099 http/tests/devtools/webaudio/graphview-test.js [ Failure ] -crbug.com/591099 virtual/shared_array_buffer_on_desktop/http/tests/devtools/webaudio/graphview-test.js [ Failure ] #unblock wpt-importer crbug.com/591099 external/wpt/css/css-overflow/scrollable-overflow-input-001.html [ Failure ] @@ -1653,6 +1645,10 @@ crbug.com/1275215 external/wpt/svg/text/scripted/getstartpositionofchar-dominant-baseline.html [ Failure ] crbug.com/1179585 svg/custom/visibility-collapse.html [ Failure ] +# layout-ng and SAB are unrelated. No need to spent time on interactions in +# between both. +crbug.com/591099 virtual/shared_array_buffer_on_desktop/* [ Skip ] + # Off by one errors cause by SwiftShader update crbug.com/1266821 compositing/gestures/gesture-tapHighlight-pixel-rotated-div.html [ Failure ] crbug.com/1266821 media/video-zoom-controls.html [ Failure ]
diff --git a/third_party/blink/web_tests/NeverFixTests b/third_party/blink/web_tests/NeverFixTests index 09b9cb2..2e37207 100644 --- a/third_party/blink/web_tests/NeverFixTests +++ b/third_party/blink/web_tests/NeverFixTests
@@ -1860,6 +1860,7 @@ # Remove from virtual tests when FontAccess is turned on by default. external/wpt/font-access/font_access_basic.tentative.https.window.html [ Skip ] external/wpt/font-access/font_access_blob.tentative.https.window.html [ Skip ] +external/wpt/font-access/font_access_detached_iframe.tentative.https.window.html [ Skip ] external/wpt/font-access/font_access_permission.tentative.https.window.html [ Skip ] external/wpt/font-access/font_access_query_select.tentative.https.window.html [ Skip ] external/wpt/font-access/font_access_sorted.tentative.https.window.html [ Skip ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index 59a5e3f8..522f430 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -3533,7 +3533,6 @@ crbug.com/626703 [ Mac11 ] external/wpt/secure-payment-confirmation/authentication-accepted.https.html [ Failure Timeout ] crbug.com/626703 [ Mac11-arm64 ] external/wpt/css/css-shapes/shape-outside/shape-image/shape-image-004.html [ Failure ] crbug.com/626703 [ Mac10.15 ] external/wpt/page-visibility/minimize.html [ Failure Skip Timeout ] -crbug.com/626703 [ Mac10.15 ] virtual/shared_array_buffer_on_desktop/external/wpt/compression/decompression-constructor-error.tentative.any.serviceworker.html [ Timeout ] crbug.com/626703 [ Win10.20h2 ] external/wpt/web-locks/bfcache/abort.tentative.https.html [ Failure Skip Timeout ] crbug.com/626703 [ Mac11 ] virtual/plz-dedicated-worker/external/wpt/html/cross-origin-embedder-policy/reporting-subresource-corp.https.html [ Skip Timeout ] crbug.com/626703 [ Mac11-arm64 ] external/wpt/webrtc/RTCPeerConnection-getStats.https.html [ Skip Timeout ] @@ -4697,12 +4696,10 @@ # Test output varies depending on the bot. A single expectation file doesn't # work. crbug.com/1194557 fast/beacon/beacon-basic.html [ Failure Pass ] -crbug.com/1194557 virtual/shared_array_buffer_on_desktop/fast/beacon/beacon-basic.html [ Pass ] # Tests are failing on CodeMirror 6 update, temporarily disable to re-open the tree. # Restore set-breakpoint-while-blocking-main-thread.js test to previous state [ Pass ] with # crbug.com/1194557 annotation as soon as crbug.com/1270207 has been fixed. -crbug.com/1270207 virtual/shared_array_buffer_on_desktop/http/tests/devtools/sources/debugger-breakpoints/set-breakpoint-while-blocking-main-thread.js [ Skip ] crbug.com/1270207 virtual/portals/http/tests/devtools/portals/portals-sources-activate.js [ Skip ] # This test passes only when the JXL feature is enabled. @@ -6024,9 +6021,6 @@ # Sheriff 2020-08-06 crbug.com/1113791 [ Win ] media/video-zoom.html [ Failure Pass ] -# Sheriff 2020-08-11 -crbug.com/1095540 virtual/threaded-prefer-compositing/fast/scrolling/resize-corner-tracking-touch.html [ Failure Pass ] - # Sheriff 2020-08-17 crbug.com/1069546 [ Mac ] compositing/layer-creation/overflow-scroll-overlap.html [ Failure Pass ] @@ -6486,9 +6480,6 @@ crbug.com/1207709 [ Mac10.13 ] virtual/plz-dedicated-worker/external/wpt/resource-timing/document-domain-no-impact-opener.html [ Failure Pass ] crbug.com/1207709 [ Mac10.13 ] external/wpt/pointerevents/pointerevent_contextmenu_is_a_pointerevent.html?touch [ Failure Pass Timeout ] -# Sheriff 2021-05-12 -crbug.com/1095540 [ Debug Linux ] virtual/compositor-threaded-percent-based-scrolling/fast/scrolling/resize-corner-tracking-touch.html [ Failure Pass ] - # For SkiaRenderer on MacOS crbug.com/1208173 [ Mac ] animations/animation-paused-hardware.html [ Failure ] crbug.com/1208173 [ Mac ] animations/missing-values-first-keyframe.html [ Failure ] @@ -6703,7 +6694,6 @@ crbug.com/1210687 [ Mac ] http/tests/permissions/chromium/test-request-worker.html [ Pass Skip Timeout ] crbug.com/1210687 [ Mac10.15 ] storage/websql/sql-error-codes.html [ Pass Skip Timeout ] crbug.com/1210687 [ Mac10.15 ] external/wpt/html/user-activation/propagation-crossorigin.sub.tentative.html [ Pass Skip Timeout ] -crbug.com/1210687 [ Win ] virtual/shared_array_buffer_on_desktop/http/tests/devtools/a11y-axe-core/sources/scope-pane-a11y-test.js [ Pass Skip Timeout ] # Sheriff 2021-06-02 crbug.com/1215575 [ Mac11 ] fast/peerconnection/RTCPeerConnection-applyConstraints-remoteVideoTrack.html [ Pass Timeout ] @@ -6935,9 +6925,6 @@ # Sheriff 2021-08-26 crbug.com/1243707 [ Debug Linux ] http/tests/inspector-protocol/target/auto-attach-related-sw.js [ Crash Pass ] -# Sheriff 2021-08-26 -crbug.com/1243933 [ Win7 ] virtual/shared_array_buffer_on_desktop/http/tests/devtools/elements/accessibility/edit-aria-attributes.js [ Failure ] - # Sheriff 2021-09-03 crbug.com/1246351 http/tests/misc/scroll-cross-origin-iframes-scrollbar.html [ Failure Pass Timeout ] @@ -6988,9 +6975,6 @@ crbug.com/1249176 [ Mac11-arm64 ] transforms/transformed-document-element.html [ Failure ] crbug.com/1249176 [ Mac11-arm64 ] virtual/no-alloc-direct-call/external/wpt/html/canvas/element/manual/drawing-images-to-the-canvas/image-orientation/drawImage-from-blob.tentative.html [ Failure ] crbug.com/1249176 [ Mac11-arm64 ] virtual/plz-dedicated-worker/external/wpt/service-workers/service-worker/clients-matchall-order.https.html [ Failure ] -crbug.com/1249176 [ Mac11-arm64 ] virtual/shared_array_buffer_on_desktop/http/tests/devtools/tracing/console-timeline.js [ Failure ] -crbug.com/1249176 [ Mac11-arm64 ] virtual/shared_array_buffer_on_desktop/http/tests/devtools/tracing/timeline-paint/paint-profiler-update.js [ Failure ] -crbug.com/1249176 [ Mac11-arm64 ] virtual/shared_array_buffer_on_desktop/http/tests/devtools/tracing/timeline-time/timeline-usertiming.js [ Failure ] crbug.com/1249176 [ Mac11-arm64 ] virtual/threaded/http/tests/devtools/tracing/timeline-paint/paint-profiler-update.js [ Failure ] crbug.com/1249176 [ Mac11-arm64 ] virtual/threaded/http/tests/devtools/tracing/timeline-time/timeline-usertiming.js [ Failure ] crbug.com/1249176 [ Mac11-arm64 ] webaudio/codec-tests/webm/webm-decode.html [ Failure ] @@ -7143,8 +7127,6 @@ crbug.com/1250457 [ Mac ] virtual/prerender/wpt_internal/prerender/csp-prefetch-src-allow.html [ Skip Timeout ] crbug.com/1250457 [ Mac ] virtual/scalefactor200/css3/filters/filter-animation-multi-hw.html [ Timeout ] crbug.com/1250457 [ Mac ] virtual/scroll-unification/fast/events/space-scroll-textinput-canceled.html [ Timeout ] -crbug.com/1250457 [ Mac ] virtual/shared_array_buffer_on_desktop/fast/css/text-overflow-ellipsis-bidi.html [ Timeout ] -crbug.com/1250457 [ Mac ] virtual/shared_array_buffer_on_desktop/storage/indexeddb/keypath-arrays.html [ Timeout ] crbug.com/1250457 [ Mac ] external/wpt/html/syntax/speculative-parsing/generated/document-write/meta-viewport-link-stylesheet-media.tentative.sub.html [ Failure ] crbug.com/1249622 external/wpt/largest-contentful-paint/initially-invisible-images.html [ Failure ] @@ -7328,7 +7310,6 @@ crbug.com/894077 [ Linux ] virtual/android/fullscreen/video-fixed-background.html [ Failure Pass ] crbug.com/1271336 external/wpt/native-io/detach_iframe_during_open.https.window.html [ Crash Pass ] crbug.com/1197465 virtual/scroll-unification/fast/events/mouse-cursor-no-mousemove.html [ Skip ] -crbug.com/1272017 [ Mac11-arm64 ] virtual/shared_array_buffer_on_desktop/http/tests/devtools/sources/debugger-ui/reveal-not-skipped.js [ Skip ] # Sheriff 2021-11-22 crbug.com/1272352 virtual/threaded/http/tests/devtools/isolated-code-cache/same-origin-test.js [ Skip ] @@ -7529,9 +7510,6 @@ crbug.com/1290978 [ Mac ] external/wpt/css/CSS2/normal-flow/crashtests/block-in-inline-ax-crash.html [ Crash Failure Pass Timeout ] crbug.com/1290978 [ Win7 ] http/tests/devtools/elements/accessibility/edit-aria-attributes.js [ Crash Failure Pass Skip Timeout ] -# Sheriff 2022-01-27 Flaky test -crbug.com/1291488 virtual/shared_array_buffer_on_desktop/fast/peerconnection/RTCPeerConnection-addMultipleTracks.html [ Skip ] - # Now flaky due to a timing issue. crbug.com/1292296 http/tests/inspector-protocol/accessibility/accessibility-getRootNode.js [ Failure Pass ] @@ -7559,11 +7537,6 @@ crbug.com/1271296 virtual/no-forced-frame-updates/external/wpt/html/dom/render-blocking/parser-inserted-preload-link.tentative.html [ Skip ] crbug.com/1271296 virtual/no-forced-frame-updates/external/wpt/html/dom/render-blocking/render-blocked-apis-by-preload-link.tentative.html [ Skip ] crbug.com/1271296 virtual/no-forced-frame-updates/external/wpt/html/dom/render-blocking/script-inserted-preload-link.tentative.html [ Skip ] -crbug.com/1271296 virtual/no-forced-frame-updates/external/wpt/html/dom/render-blocking/parser-inserted-async-script.tentative.html [ Skip ] -crbug.com/1271296 virtual/no-forced-frame-updates/external/wpt/html/dom/render-blocking/parser-inserted-defer-script.tentative.html [ Skip ] -crbug.com/1271296 virtual/no-forced-frame-updates/external/wpt/html/dom/render-blocking/parser-inserted-module-script.tentative.html [ Skip ] -crbug.com/1271296 virtual/no-forced-frame-updates/external/wpt/html/dom/render-blocking/script-inserted-module-script.tentative.html [ Skip ] -crbug.com/1271296 virtual/no-forced-frame-updates/external/wpt/html/dom/render-blocking/script-inserted-script.html [ Skip ] # Need to unblock scripts on style elements when media doesn't match crbug.com/1296736 external/wpt/html/semantics/document-metadata/interactions-of-styling-and-scripting/style-element-media-not-match-does-not-block-script.html [ Failure ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites index 1ab7e2d..7f9b722 100644 --- a/third_party/blink/web_tests/VirtualTestSuites +++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -158,31 +158,12 @@ }, { "prefix": "shared_array_buffer_on_desktop", - "bases": ["crypto", - "external/wpt/compression", - "external/wpt/encoding", - "external/wpt/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism", - "external/wpt/html/browsers/origin/origin-keyed-agent-clusters", - "external/wpt/orientation-sensor", + "bases": ["external/wpt/html/browsers/origin/origin-keyed-agent-clusters", "external/wpt/wasm/jsapi/memory", - "external/wpt/webaudio/the-audio-api/the-audiobuffer-interface", - "external/wpt/webaudio/the-audio-api/the-audioworklet-interface", - "external/wpt/xhr", - "fast/beacon", - "fast/css/", - "fast/dom", - "fast/encoding", - "fast/events/constructors", - "fast/files", - "fast/peerconnection", - "fast/webgl", - "fast/workers", - "fast/xmlhttprequest", - "http/tests/devtools", - "http/tests/inspector-protocol/issues", - "http/tests/websocket", - "storage/indexeddb", - "webaudio"], + "fast/workers/worker-atomics-wait.html", + "fast/workers/worker-sharedarraybuffer-transfer.html", + "fast/workers/chromium/worker-sharedarraybuffer-transfer-two-workers.html", + "http/tests/inspector-protocol/issues"], "args": ["--enable-features=SharedArrayBuffer"] }, { @@ -782,7 +763,8 @@ "external/wpt/service-workers/service-worker/partitioned-service-worker-matchAll.tentative.https.html", "external/wpt/service-workers/service-worker/partitioned-service-worker-claim.tentative.https.html", "external/wpt/webstorage/localstorage-basic-partitioned.tentative.sub.html", - "external/wpt/webmessaging/broadcastchannel/cross-partition.https.tentative.html" + "external/wpt/webmessaging/broadcastchannel/cross-partition.https.tentative.html", + "external/wpt/IndexedDB/idb-partitioned-basic.tentative.sub.html" ], "args": [ "--enable-features=ThirdPartyStoragePartitioning" ] },
diff --git a/third_party/blink/web_tests/external/wpt/credential-management/fedcm-revoke.https.html b/third_party/blink/web_tests/external/wpt/credential-management/fedcm-revoke.https.html index f3a4eac..84a20b0 100644 --- a/third_party/blink/web_tests/external/wpt/credential-management/fedcm-revoke.https.html +++ b/third_party/blink/web_tests/external/wpt/credential-management/fedcm-revoke.https.html
@@ -13,11 +13,11 @@ const provider = { url: provider_url || "https://idp.example/", clientId: "1234", + hint: "foo@bar.com", }; return await navigator.credentials.get({ federated: { providers: [provider], - hint: "foo@bar.com", }, }); }
diff --git a/third_party/blink/web_tests/external/wpt/css/css-tables/visibility-collapse-border-spacing.html b/third_party/blink/web_tests/external/wpt/css/css-tables/visibility-collapse-border-spacing.html new file mode 100644 index 0000000..738cea1 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-tables/visibility-collapse-border-spacing.html
@@ -0,0 +1,14 @@ +<!DOCTYPE html> +<link rel="help" href="https://drafts.csswg.org/css-tables-3/"> +<link rel="match" href="../reference/ref-filled-green-100px-square.xht"> +<p>Test passes if there is a filled green square and <strong>no red</strong>.</p> +<table style="width: 100px; border-spacing: 10px; background: red;"> + <tbody style="outline: solid green 10px;"> + <tr style="visibility: collapse;"> + <td style="padding: 0;"></td> + </tr> + <tr> + <td style="padding: 0;"><div style="height: 80px; background: green;"></div></td> + </tr> + </tbody> +</table>
diff --git a/third_party/blink/web_tests/external/wpt/font-access/font_access_basic.tentative.https.window.js b/third_party/blink/web_tests/external/wpt/font-access/font_access_basic.tentative.https.window.js index 3ae49bc6..7d94afc 100644 --- a/third_party/blink/web_tests/external/wpt/font-access/font_access_basic.tentative.https.window.js +++ b/third_party/blink/web_tests/external/wpt/font-access/font_access_basic.tentative.https.window.js
@@ -11,7 +11,7 @@ const testData = getTestData(); // Get the system fonts. - let fonts = await navigator.fonts.query(); + const fonts = await navigator.fonts.query(); assert_true(Array.isArray(fonts), 'Result of query() should be an Array'); assert_greater_than_equal(fonts.length, 1, 'Need a least one font');
diff --git a/third_party/blink/web_tests/external/wpt/font-access/font_access_detached_iframe.tentative.https.window.js b/third_party/blink/web_tests/external/wpt/font-access/font_access_detached_iframe.tentative.https.window.js new file mode 100644 index 0000000..9d0c8bc --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/font-access/font_access_detached_iframe.tentative.https.window.js
@@ -0,0 +1,30 @@ +//META: script=/resources/testdriver.js +//META: script=/resources/testdriver-vendor.js +//META: script=resources/font-test-utils.js + +'use strict'; + +font_access_test(async t => { + const iframe = document.createElement('iframe'); + document.body.appendChild(iframe); + + const iframeFontManager = iframe.contentWindow.navigator.fonts; + const frameDOMException = iframe.contentWindow.DOMException; + iframe.remove(); + + await promise_rejects_dom( + t, 'InvalidStateError', frameDOMException, iframeFontManager.query()); +}, 'query() must return an error when called from a detached iframe.'); + +font_access_test(async t => { + const iframe = document.createElement('iframe'); + document.body.appendChild(iframe); + + const iframeFontManager = iframe.contentWindow.navigator.fonts; + iframeFontManager.query(); + iframe.remove(); + + // Call query() in the main frame. This should keep the test running long + // enough to catch any crash from the query() call in the removed iframe. + await navigator.fonts.query(); +}, 'Detaching iframe while query() settles.'); \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/remove-pending-async-render-blocking-script.html b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/remove-pending-async-render-blocking-script.html new file mode 100644 index 0000000..5f6e8b34 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/remove-pending-async-render-blocking-script.html
@@ -0,0 +1,19 @@ +<!DOCTYPE html> +<title>Removed render-blocking script should not indefinitely block rendering</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script id="target" async blocking="render" + src="support/dummy-1.js?pipe=trickle(d1)"></script> +<script> +promise_test(async () => { + const target = document.getElementById('target'); + const newDoc = document.implementation.createHTMLDocument('new document'); + newDoc.documentElement.appendChild(target); + + await new Promise(resolve => requestAnimationFrame(resolve)); + + // reqeustAnimationFrame() should be eventually run, but the script removed + // while pending should not be run. + assert_equals(window.dummy, undefined); +}); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/navigation-counter.helper.js b/third_party/blink/web_tests/external/wpt/performance-timeline/navigation-id.helper.js similarity index 67% rename from third_party/blink/web_tests/external/wpt/performance-timeline/navigation-counter.helper.js rename to third_party/blink/web_tests/external/wpt/performance-timeline/navigation-id.helper.js index 81cf33f..fd6e24d 100644 --- a/third_party/blink/web_tests/external/wpt/performance-timeline/navigation-counter.helper.js +++ b/third_party/blink/web_tests/external/wpt/performance-timeline/navigation-id.helper.js
@@ -3,11 +3,11 @@ // '/html/browsers/browsing-the-web/back-forward-cache/resources/helper.sub.js' // which should be included before this file to use these functions. -function runNavigationCounterTest(params, description) { +function runNavigationIdTest(params, description) { const defaultParams = { constants: { - performanceMarkName: 'mark_navigation_counter', - performanceMeasureName: 'measure_navigation_counter', + performanceMarkName: 'mark_navigation_id', + performanceMeasureName: 'measure_navigation_id', }, // This function is to make and obtain the navigation counter value for a // performance entries of mark and measure type. It is to be extended for @@ -16,24 +16,24 @@ window.performance.mark(constants.performanceMarkName); return window.performance .getEntriesByName(constants.performanceMarkName)[0] - .navigationCount; + .navigationId; }, - funcAfterBFCacheLoad: (expectedNavigationCount, constants) => { + funcAfterBFCacheLoad: (expectedNavigationId, constants) => { window.performance.mark( - constants.performanceMarkName + expectedNavigationCount); + constants.performanceMarkName + expectedNavigationId); window.performance.measure( - constants.performanceMeasureName + expectedNavigationCount, + constants.performanceMeasureName + expectedNavigationId, constants.performanceMarkName, - constants.performanceMarkName + expectedNavigationCount); + constants.performanceMarkName + expectedNavigationId); return [ window.performance .getEntriesByName( - constants.performanceMarkName + expectedNavigationCount)[0] - .navigationCount, + constants.performanceMarkName + expectedNavigationId)[0] + .navigationId, window.performance .getEntriesByName( - constants.performanceMeasureName + expectedNavigationCount)[0] - .navigationCount + constants.performanceMeasureName + expectedNavigationId)[0] + .navigationId ]; }, }; @@ -63,20 +63,20 @@ await pageA.execute_script(waitForPageShow); - // Assert navigation counter is 0 when the document is loaded first time. - let navigationCount = await pageA.execute_script( + // Assert navigation id is 1 when the document is loaded first time. + let navigationId = await pageA.execute_script( params.funcBeforeNavigation, [params.constants]) assert_implements_optional( - navigationCount === 0, 'NavigationCount should be 0.'); + navigationId === 1, 'Navigation Id should be 0.'); - for (i = 0; i < params.navigationTimes; i++) { + for (i = 1; i <= params.navigationTimes; i++) { await navigateAndThenBack(pageA, pageB, urlB); - let navigationCounts = await pageA.execute_script( + let navigationIds = await pageA.execute_script( params.funcAfterBFCacheLoad, [i + 1, params.constants]); assert_implements_optional( - navigationCounts.every(t => t === (i + 1)), - 'NavigationCount should all be ' + (i + 1) + '.'); + navigationIds.every(t => t === (i + 1)), + 'Navigation Id should all be ' + (i + 1) + '.'); } }, description); }
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/navigation-counter.tentative.html b/third_party/blink/web_tests/external/wpt/performance-timeline/navigation-id.tentative.html similarity index 78% rename from third_party/blink/web_tests/external/wpt/performance-timeline/navigation-counter.tentative.html rename to third_party/blink/web_tests/external/wpt/performance-timeline/navigation-id.tentative.html index 0ddc8033..08dbd4b0 100644 --- a/third_party/blink/web_tests/external/wpt/performance-timeline/navigation-counter.tentative.html +++ b/third_party/blink/web_tests/external/wpt/performance-timeline/navigation-id.tentative.html
@@ -5,9 +5,9 @@ <script src="/common/utils.js"></script> <script src="/common/dispatcher/dispatcher.js"></script> <script src="/html/browsers/browsing-the-web/back-forward-cache/resources/helper.sub.js"></script> -<script src="navigation-counter.helper.js"></script> +<script src="navigation-id.helper.js"></script> <script> - runNavigationCounterTest({ + runNavigationIdTest({ navigationTimes: 4, - }, "bfcache counter test"); + }, "navigation id test"); </script>
diff --git a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-navigated-expected.txt b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-navigated-expected.txt index 160edc9b..8b3c795 100644 --- a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-navigated-expected.txt +++ b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-navigated-expected.txt
@@ -1,4 +1,4 @@ -Tests access of cached DOMWindow properties after the associated frame is navigated. Test should not crash and properties should be set to sane defaults. +Tests access of cached DOMWindow properties after the associated frame is navigated. Test should not crash and properties should be set to reasonable defaults as appropriate. On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". @@ -11,16 +11,16 @@ PASS window.cached_appHistory.onnavigatesuccess is null PASS window.cached_appHistory.transition is null PASS window.cached_cookieStore.onchange is null -FAIL window.cached_location.hash should be (of type string). Was undefined (of type undefined). -FAIL window.cached_location.host should be (of type string). Was undefined (of type undefined). -FAIL window.cached_location.hostname should be (of type string). Was undefined (of type undefined). -FAIL window.cached_location.href should be about:blank (of type string). Was undefined (of type undefined). -FAIL window.cached_location.origin should be null (of type string). Was undefined (of type undefined). -FAIL window.cached_location.pathname should be blank (of type string). Was undefined (of type undefined). -FAIL window.cached_location.port should be (of type string). Was undefined (of type undefined). -FAIL window.cached_location.protocol should be about: (of type string). Was undefined (of type undefined). -FAIL window.cached_location.search should be (of type string). Was undefined (of type undefined). -PASS window.cached_location_ancestorOrigins.length is 1 +PASS window.cached_location.hash is undefined +PASS window.cached_location.host is undefined +PASS window.cached_location.hostname is undefined +PASS window.cached_location.href is undefined +PASS window.cached_location.origin is undefined +PASS window.cached_location.pathname is undefined +PASS window.cached_location.port is undefined +PASS window.cached_location.protocol is undefined +PASS window.cached_location.search is undefined +FAIL window.cached_location_ancestorOrigins.length should be 0. Was 1. PASS window.cached_locationbar.visible is false PASS window.cached_menubar.visible is false PASS window.cached_navigator.appCodeName is window.navigator.appCodeName @@ -42,11 +42,15 @@ PASS window.cached_navigator.vendorSub is '' PASS window.cached_navigator.webdriver is false PASS window.cached_navigator_bluetooth.onadvertisementreceived is null +PASS window.cached_navigator_connection.downlinkMax is window.navigator.connection.downlinkMax +PASS window.cached_navigator_connection.effectiveType is window.navigator.connection.effectiveType PASS window.cached_navigator_connection.onchange is null PASS window.cached_navigator_connection.ontypechange is null +PASS window.cached_navigator_connection.rtt is window.navigator.connection.rtt PASS window.cached_navigator_connection.saveData is false +PASS window.cached_navigator_connection.type is window.navigator.connection.type PASS window.cached_navigator_devicePosture.onchange is null -PASS window.cached_navigator_devicePosture.type is 'continuous' +PASS window.cached_navigator_devicePosture.type is window.navigator.devicePosture.type PASS window.cached_navigator_hid.onconnect is null PASS window.cached_navigator_hid.ondisconnect is null PASS window.cached_navigator_managed.onmanagedconfigurationchange is null @@ -120,7 +124,7 @@ PASS window.cached_screen.width is 0 PASS window.cached_screen_orientation.angle is 0 PASS window.cached_screen_orientation.onchange is null -PASS window.cached_screen_orientation.type is 'portrait-primary' +PASS window.cached_screen_orientation.type is window.screen.orientation.type PASS window.cached_scrollbars.visible is false PASS window.cached_speechSynthesis.onvoiceschanged is null PASS window.cached_speechSynthesis.paused is false
diff --git a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-navigated.html b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-navigated.html index 411301b..39c47ff8 100644 --- a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-navigated.html +++ b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-navigated.html
@@ -28,10 +28,9 @@ function runTest() { frame = document.getElementById("test_frame"); - description("Tests access of cached DOMWindow properties after the associated frame is navigated. Test should not crash and properties should be set to sane defaults."); + description("Tests access of cached DOMWindow properties after the associated frame is navigated. Test should not crash and properties should be set to reasonable defaults as appropriate."); childWindow = frame.contentWindow; - // Have expected results assume that the frame hasn't been closed (=> window.closed = false.) - collectProperties(document.getElementById("src_frame").contentWindow, false); + collectProperties(document.getElementById("src_frame").contentWindow); frame.onload = testFrameLoaded; frame.src = 'data:text/plain,'; }
diff --git a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-and-gced-expected.txt b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-and-gced-expected.txt index 68f5613..b6d42f4 100644 --- a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-and-gced-expected.txt +++ b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-and-gced-expected.txt
@@ -1,4 +1,4 @@ -Tests access of cached DOMWindow properties after the associated frame is removed from a web page and garbage collected. Test should not crash and properties should be set to sane defaults. +Tests access of cached DOMWindow properties after the associated frame is removed from a web page and garbage collected. Test should not crash and properties should be set to reasonable defaults as appropriate. On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". @@ -11,16 +11,16 @@ PASS window.cached_appHistory.onnavigatesuccess is null PASS window.cached_appHistory.transition is null PASS window.cached_cookieStore.onchange is null -FAIL window.cached_location.hash should be (of type string). Was undefined (of type undefined). -FAIL window.cached_location.host should be (of type string). Was undefined (of type undefined). -FAIL window.cached_location.hostname should be (of type string). Was undefined (of type undefined). -FAIL window.cached_location.href should be about:blank (of type string). Was undefined (of type undefined). -FAIL window.cached_location.origin should be null (of type string). Was undefined (of type undefined). -FAIL window.cached_location.pathname should be blank (of type string). Was undefined (of type undefined). -FAIL window.cached_location.port should be (of type string). Was undefined (of type undefined). -FAIL window.cached_location.protocol should be about: (of type string). Was undefined (of type undefined). -FAIL window.cached_location.search should be (of type string). Was undefined (of type undefined). -PASS window.cached_location_ancestorOrigins.length is 1 +PASS window.cached_location.hash is undefined +PASS window.cached_location.host is undefined +PASS window.cached_location.hostname is undefined +PASS window.cached_location.href is undefined +PASS window.cached_location.origin is undefined +PASS window.cached_location.pathname is undefined +PASS window.cached_location.port is undefined +PASS window.cached_location.protocol is undefined +PASS window.cached_location.search is undefined +FAIL window.cached_location_ancestorOrigins.length should be 0. Was 1. PASS window.cached_locationbar.visible is false PASS window.cached_menubar.visible is false PASS window.cached_navigator.appCodeName is window.navigator.appCodeName @@ -42,11 +42,15 @@ PASS window.cached_navigator.vendorSub is '' PASS window.cached_navigator.webdriver is false PASS window.cached_navigator_bluetooth.onadvertisementreceived is null +PASS window.cached_navigator_connection.downlinkMax is window.navigator.connection.downlinkMax +PASS window.cached_navigator_connection.effectiveType is window.navigator.connection.effectiveType PASS window.cached_navigator_connection.onchange is null PASS window.cached_navigator_connection.ontypechange is null +PASS window.cached_navigator_connection.rtt is window.navigator.connection.rtt PASS window.cached_navigator_connection.saveData is false +PASS window.cached_navigator_connection.type is window.navigator.connection.type PASS window.cached_navigator_devicePosture.onchange is null -PASS window.cached_navigator_devicePosture.type is 'continuous' +PASS window.cached_navigator_devicePosture.type is window.navigator.devicePosture.type PASS window.cached_navigator_hid.onconnect is null PASS window.cached_navigator_hid.ondisconnect is null PASS window.cached_navigator_managed.onmanagedconfigurationchange is null @@ -120,7 +124,7 @@ PASS window.cached_screen.width is 0 PASS window.cached_screen_orientation.angle is 0 PASS window.cached_screen_orientation.onchange is null -PASS window.cached_screen_orientation.type is 'portrait-primary' +PASS window.cached_screen_orientation.type is window.screen.orientation.type PASS window.cached_scrollbars.visible is false PASS window.cached_speechSynthesis.onvoiceschanged is null PASS window.cached_speechSynthesis.paused is false
diff --git a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-and-gced.html b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-and-gced.html index 07f2fd6..060c686 100644 --- a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-and-gced.html +++ b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-and-gced.html
@@ -27,11 +27,10 @@ function runTest() { - description("Tests access of cached DOMWindow properties after the associated frame is removed from a web page and garbage collected. Test should not crash and properties should be set to sane defaults."); + description("Tests access of cached DOMWindow properties after the associated frame is removed from a web page and garbage collected. Test should not crash and properties should be set to reasonable defaults as appropriate."); var frame = document.getElementById("test_frame"); childWindow = frame.contentWindow; - // Have expected results assume that the frame has been closed (=> window.closed = true.) - collectProperties(document.getElementById("src_frame").contentWindow, true); + collectProperties(document.getElementById("src_frame").contentWindow); frame.parentNode.removeChild(frame); asyncGC(function () { for (var i = 0; i < propertiesToVerify.length; ++i)
diff --git a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-expected.txt b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-expected.txt index dd7c792..810e9e0 100644 --- a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-expected.txt +++ b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-expected.txt
@@ -1,4 +1,4 @@ -Tests access of cached DOMWindow properties after the associated frame is no longer in a web page. Test should not crash and properties should be set to sane defaults. +Tests access of cached DOMWindow properties after the associated frame is no longer in a web page. Test should not crash and properties should be set to reasonable defaults as appropriate. On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". @@ -11,16 +11,16 @@ PASS window.cached_appHistory.onnavigatesuccess is null PASS window.cached_appHistory.transition is null PASS window.cached_cookieStore.onchange is null -FAIL window.cached_location.hash should be (of type string). Was undefined (of type undefined). -FAIL window.cached_location.host should be (of type string). Was undefined (of type undefined). -FAIL window.cached_location.hostname should be (of type string). Was undefined (of type undefined). -FAIL window.cached_location.href should be about:blank (of type string). Was undefined (of type undefined). -FAIL window.cached_location.origin should be null (of type string). Was undefined (of type undefined). -FAIL window.cached_location.pathname should be blank (of type string). Was undefined (of type undefined). -FAIL window.cached_location.port should be (of type string). Was undefined (of type undefined). -FAIL window.cached_location.protocol should be about: (of type string). Was undefined (of type undefined). -FAIL window.cached_location.search should be (of type string). Was undefined (of type undefined). -PASS window.cached_location_ancestorOrigins.length is 1 +PASS window.cached_location.hash is undefined +PASS window.cached_location.host is undefined +PASS window.cached_location.hostname is undefined +PASS window.cached_location.href is undefined +PASS window.cached_location.origin is undefined +PASS window.cached_location.pathname is undefined +PASS window.cached_location.port is undefined +PASS window.cached_location.protocol is undefined +PASS window.cached_location.search is undefined +FAIL window.cached_location_ancestorOrigins.length should be 0. Was 1. PASS window.cached_locationbar.visible is false PASS window.cached_menubar.visible is false PASS window.cached_navigator.appCodeName is window.navigator.appCodeName @@ -42,11 +42,15 @@ PASS window.cached_navigator.vendorSub is '' PASS window.cached_navigator.webdriver is false PASS window.cached_navigator_bluetooth.onadvertisementreceived is null +PASS window.cached_navigator_connection.downlinkMax is window.navigator.connection.downlinkMax +PASS window.cached_navigator_connection.effectiveType is window.navigator.connection.effectiveType PASS window.cached_navigator_connection.onchange is null PASS window.cached_navigator_connection.ontypechange is null +PASS window.cached_navigator_connection.rtt is window.navigator.connection.rtt PASS window.cached_navigator_connection.saveData is false +PASS window.cached_navigator_connection.type is window.navigator.connection.type PASS window.cached_navigator_devicePosture.onchange is null -PASS window.cached_navigator_devicePosture.type is 'continuous' +PASS window.cached_navigator_devicePosture.type is window.navigator.devicePosture.type PASS window.cached_navigator_hid.onconnect is null PASS window.cached_navigator_hid.ondisconnect is null PASS window.cached_navigator_managed.onmanagedconfigurationchange is null @@ -120,7 +124,7 @@ PASS window.cached_screen.width is 0 PASS window.cached_screen_orientation.angle is 0 PASS window.cached_screen_orientation.onchange is null -PASS window.cached_screen_orientation.type is 'portrait-primary' +PASS window.cached_screen_orientation.type is window.screen.orientation.type PASS window.cached_scrollbars.visible is false PASS window.cached_speechSynthesis.onvoiceschanged is null PASS window.cached_speechSynthesis.paused is false
diff --git a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed.html b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed.html index e158acd..d1f3b45 100644 --- a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed.html +++ b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed.html
@@ -26,11 +26,10 @@ function runTest() { - description("Tests access of cached DOMWindow properties after the associated frame is no longer in a web page. Test should not crash and properties should be set to sane defaults."); + description("Tests access of cached DOMWindow properties after the associated frame is no longer in a web page. Test should not crash and properties should be set to reasonable defaults as appropriate."); var frame = document.getElementById("test_frame"); childWindow = frame.contentWindow; - // Have expected results assume that the frame hasn't been closed (=> window.closed = false.) - collectProperties(document.getElementById("src_frame").contentWindow, false); + collectProperties(document.getElementById("src_frame").contentWindow); frame.parentNode.removeChild(frame); for (var i = 0; i < propertiesToVerify.length; ++i) shouldBe(propertiesToVerify[i].property, propertiesToVerify[i].expected);
diff --git a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt index ebbac44..def9db9 100644 --- a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt +++ b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt
@@ -38,9 +38,13 @@ PASS oldChildWindow.navigator.appName is newChildWindow.navigator.appName PASS oldChildWindow.navigator.appVersion is newChildWindow.navigator.appVersion PASS oldChildWindow.navigator.bluetooth.onadvertisementreceived is newChildWindow.navigator.bluetooth.onadvertisementreceived +PASS oldChildWindow.navigator.connection.downlinkMax is newChildWindow.navigator.connection.downlinkMax +PASS oldChildWindow.navigator.connection.effectiveType is newChildWindow.navigator.connection.effectiveType PASS oldChildWindow.navigator.connection.onchange is newChildWindow.navigator.connection.onchange PASS oldChildWindow.navigator.connection.ontypechange is newChildWindow.navigator.connection.ontypechange +PASS oldChildWindow.navigator.connection.rtt is newChildWindow.navigator.connection.rtt PASS oldChildWindow.navigator.connection.saveData is newChildWindow.navigator.connection.saveData +PASS oldChildWindow.navigator.connection.type is newChildWindow.navigator.connection.type PASS oldChildWindow.navigator.cookieEnabled is newChildWindow.navigator.cookieEnabled PASS oldChildWindow.navigator.deviceMemory is newChildWindow.navigator.deviceMemory PASS oldChildWindow.navigator.devicePosture.onchange is newChildWindow.navigator.devicePosture.onchange
diff --git a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated.html b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated.html index 9feb6148..ba8facf3 100644 --- a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated.html +++ b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated.html
@@ -21,8 +21,7 @@ frame = document.getElementById("test_frame"); description("Tests property access on a cached DOMWindow after the associated frame is navigated. Test should not crash and properties read from the cached DOMWindow should be identical to properties through the 'current' DOMWindow."); oldChildWindow = frame.contentWindow; - // Have expected results assume that the frame hasn't been closed (=> window.closed = false.) - collectProperties(document.getElementById("src_frame").contentWindow, false); + collectProperties(document.getElementById("src_frame").contentWindow); frame.onload = testFrameLoaded; frame.src = 'about:blank'; }
diff --git a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt index a7b3615..6276636 100644 --- a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt +++ b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt
@@ -1,4 +1,4 @@ -Tests property access on a cached DOMWindow after the associated frame is removed from a web page and garbage collected. Test should not crash and properties should be set to sane defaults. +Tests property access on a cached DOMWindow after the associated frame is removed from a web page and garbage collected. Test should not crash and properties should be set to reasonable defaults as appropriate. On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". @@ -11,16 +11,16 @@ PASS childWindow.appHistory.onnavigateerror is null PASS childWindow.appHistory.onnavigatesuccess is null PASS childWindow.appHistory.transition is null -PASS childWindow.closed is true +FAIL childWindow.closed should be false. Was true. PASS childWindow.crossOriginIsolated is false PASS childWindow.defaultStatus is '' PASS childWindow.defaultstatus is '' PASS childWindow.devicePixelRatio is 0 PASS childWindow.innerHeight is 0 PASS childWindow.innerWidth is 0 -PASS childWindow.isSecureContext is false +PASS childWindow.isSecureContext is true PASS childWindow.length is 0 -FAIL childWindow.location.href should be about:blank (of type string). Was undefined (of type undefined). +PASS childWindow.location.href is undefined PASS childWindow.locationbar.visible is false PASS childWindow.menubar.visible is false PASS childWindow.name is ''
diff --git a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced.html b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced.html index 3b2821d..2636377 100644 --- a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced.html +++ b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced.html
@@ -12,18 +12,15 @@ function insertExpectedResult(path, expected) { var property = path.join("."); - if (property == "location.ancestorOrigins.length") - expected = '0'; propertiesToVerify.push({"path": path.slice(0), "property": property, "expected": expected}); } function runTest() { - description("Tests property access on a cached DOMWindow after the associated frame is removed from a web page and garbage collected. Test should not crash and properties should be set to sane defaults."); + description("Tests property access on a cached DOMWindow after the associated frame is removed from a web page and garbage collected. Test should not crash and properties should be set to reasonable defaults as appropriate."); var frame = document.getElementById("test_frame"); childWindow = frame.contentWindow; - // Have expected results assume that the frame has been closed and GCed (=> window.closed = true.) - collectProperties(document.getElementById("src_frame").contentWindow, true); + collectProperties(document.getElementById("src_frame").contentWindow); frame.parentNode.removeChild(frame); asyncGC(function () { for (var i = 0; i < propertiesToVerify.length; ++i) {
diff --git a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt index c217152..53ba93d3 100644 --- a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt +++ b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt
@@ -1,4 +1,4 @@ -Tests property access on a cached DOMWindow after the associated frame is no longer in a web page. Test should not crash and properties should be set to sane defaults. +Tests property access on a cached DOMWindow after the associated frame is no longer in a web page. Test should not crash and properties should be set to reasonable defaults as appropriate. On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". @@ -11,16 +11,16 @@ PASS childWindow.appHistory.onnavigateerror is null PASS childWindow.appHistory.onnavigatesuccess is null PASS childWindow.appHistory.transition is null -PASS childWindow.closed is true +FAIL childWindow.closed should be false. Was true. PASS childWindow.crossOriginIsolated is false PASS childWindow.defaultStatus is '' PASS childWindow.defaultstatus is '' PASS childWindow.devicePixelRatio is 0 PASS childWindow.innerHeight is 0 PASS childWindow.innerWidth is 0 -PASS childWindow.isSecureContext is false +PASS childWindow.isSecureContext is true PASS childWindow.length is 0 -FAIL childWindow.location.href should be about:blank (of type string). Was undefined (of type undefined). +PASS childWindow.location.href is undefined PASS childWindow.locationbar.visible is false PASS childWindow.menubar.visible is false PASS childWindow.name is ''
diff --git a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed.html b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed.html index 1570aab..074a1c16 100644 --- a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed.html +++ b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed.html
@@ -11,18 +11,15 @@ function insertExpectedResult(path, expected) { var property = path.join("."); - if (property == "location.ancestorOrigins.length") - expected = '0'; propertiesToVerify.push({"path": path.slice(0), "property": property, "expected": expected}); } function runTest() { - description("Tests property access on a cached DOMWindow after the associated frame is no longer in a web page. Test should not crash and properties should be set to sane defaults."); + description("Tests property access on a cached DOMWindow after the associated frame is no longer in a web page. Test should not crash and properties should be set to reasonable defaults as appropriate."); var frame = document.getElementById("test_frame"); childWindow = frame.contentWindow; - // Have expected results assume that the frame has been closed (=> window.closed = true.) - collectProperties(document.getElementById("src_frame").contentWindow, true); + collectProperties(document.getElementById("src_frame").contentWindow); frame.parentNode.removeChild(frame); for (var i = 0; i < propertiesToVerify.length; ++i) { // It's ok if the property no longer exists.
diff --git a/third_party/blink/web_tests/fast/dom/Window/resources/window-property-collector.js b/third_party/blink/web_tests/fast/dom/Window/resources/window-property-collector.js index 15973ea..52c7c34 100644 --- a/third_party/blink/web_tests/fast/dom/Window/resources/window-property-collector.js +++ b/third_party/blink/web_tests/fast/dom/Window/resources/window-property-collector.js
@@ -1,6 +1,6 @@ -function collectProperties(object, windowHasBeenGCed) +function collectProperties(object) { - collectPropertiesHelper(object, object, windowHasBeenGCed, []); + collectPropertiesHelper(object, object, []); propertiesToVerify.sort(function (a, b) { @@ -28,9 +28,7 @@ function emitExpectedResult(path, expected) { - // Skip internals properties, since they aren't web accessible. - if (path[0] == 'internals' - || path[0] == 'clientInformation' // Just an alias for navigator. + if (path[0] == 'clientInformation' // Just an alias for navigator. || path[0] == 'testRunner' // Skip testRunner since they are only for testing. || path[0] == 'eventSender'// Skip eventSender since they are only for testing. || path[1] == 'gpuBenchmarking') { // Skip gpuBenchmarking since they're only for testing. @@ -59,46 +57,33 @@ if (path[path.length - 1].toUpperCase() == path[path.length - 1]) return; - // Various special cases for legacy reasons. Please do not add entries to this list. + // Special cases where the properties might return something other than the + // "expected" default (e.g. bool property defaulting to false). Please do + // not add exceptions to this list without documenting them. var propertyPath = path.join('.'); - // Connection type depends on the host, skip. - if (propertyPath == 'navigator.connection.type') - return; - if (propertyPath == 'navigator.connection.downlinkMax') - return; - if (propertyPath == 'navigator.connection.effectiveType') - return; - if (propertyPath == 'navigator.connection.rtt') - return; - if (propertyPath == 'navigator.connection.downlink') - return; - // timeOrigin is variable, skip. - if (propertyPath == 'performance.timeOrigin') - return; + // Properties that are skipped because they are unstable due to dependency + // on system global state that is variable between test runs. + switch (propertyPath) { + // navigator.connection.downlink is an estimate based on recently observed + // application layer throughput across recently active connections. + case "navigator.connection.downlink": + // performance.timeOrigin depends on when the page is loaded and is variable. + case "performance.timeOrigin": + return; + } switch (propertyPath) { - case "location.href": - expected = "'about:blank'"; - break; - case "location.origin": - expected = "'null'"; - break; - case "origin": - expected = "'file://'"; - break; - case "location.pathname": - expected = "'blank'"; - break; - case "location.protocol": - expected = "'about:'"; - break; - case "location.ancestorOrigins.length": - expected = "1"; - break; + // Various navigator properties that depend on the host. Check that they + // match the property values of the top-level window. case "navigator.appCodeName": case "navigator.appName": + case 'navigator.connection.type': + case 'navigator.connection.downlinkMax': + case 'navigator.connection.effectiveType': + case 'navigator.connection.rtt': case "navigator.deviceMemory": + case "navigator.devicePosture.type": case "navigator.hardwareConcurrency": case "navigator.language": case "navigator.onLine": @@ -106,26 +91,40 @@ case "navigator.product": case "navigator.productSub": case "navigator.vendor": + case "screen.orientation.type": expected = "window." + propertyPath; break; - case "navigator.devicePosture.type": - expected = "'continuous'"; + + // Whether or not an execution context is secure should not be affected by + // detachment. + case "isSecureContext": + expected = "true"; + break; + // TODO(dcheng): Figure out why these become undefined... + case "location.hash": + case "location.host": + case "location.hostname": + case "location.href": + case "location.origin": + case "location.pathname": + case "location.port": + case "location.protocol": + case "location.search": + expected = "undefined"; break; case "navigator.mediaSession.playbackState": expected = "'none'"; break; - case "screen.orientation.type": - expected = "'portrait-primary'"; - break; - case "history.scrollRestoration": - expected = "'auto'"; + // Web tests are loaded from the local filesystem. + case "origin": + expected = "'file://'"; break; } insertExpectedResult(path, expected); } -function collectPropertiesHelper(global, object, windowHasBeenGCed, path) +function collectPropertiesHelper(global, object, path) { if (path.length > 20) throw 'Error: probably looping'; @@ -145,17 +144,14 @@ && !(object[property] instanceof global.PluginArray) && !(object[property] instanceof HTMLElement)) { // Skip some traversing through types that will end up in cycles... - collectPropertiesHelper(global, object[property], windowHasBeenGCed, path); + collectPropertiesHelper(global, object[property], path); } } else if (type == "string") { emitExpectedResult(path, "''"); } else if (type == "number") { emitExpectedResult(path, "0"); } else if (type == "boolean") { - expected = "false"; - if (path == "closed" && windowHasBeenGCed ) - expected = "true"; - emitExpectedResult(path, expected); + emitExpectedResult(path, "false"); } path.pop(); }
diff --git a/third_party/blink/web_tests/fast/scrolling/resize-corner-tracking-touch.html b/third_party/blink/web_tests/fast/scrolling/resize-corner-tracking-touch.html index d81334f0..9cfd024 100644 --- a/third_party/blink/web_tests/fast/scrolling/resize-corner-tracking-touch.html +++ b/third_party/blink/web_tests/fast/scrolling/resize-corner-tracking-touch.html
@@ -4,119 +4,169 @@ <script src="../../resources/testharnessreport.js"></script> <style> div { - overflow: auto; - resize: both; - border: blue 2px solid; + overflow: auto; + resize: both; + border: blue 2px solid; } textarea { - resize: both; + resize: both; } iframe { - border: blue 2px solid; + border: blue 2px solid; } + </style> -<div id="placeholder" style="width: 150px; height: 150px;">a placeholder so that we have enough elements to scroll the page</div> -<div id="div" style="width: 150px; height: 100px;;"></div> +<div id="placeholder" style="width: 150px; height: 150px;">a placeholder so that +we have enough elements to scroll the page</div> +<div id="div" style="width: 150px; height: 100px;"></div> <textarea id="textarea1" style="width: 150px; height: 100px;"></textarea> <br> -<iframe id="iframe1" src="resources/resize-corner-tracking-touch-iframe.html" style="resize:both; width: 200px; height: 200px"></iframe> - +<iframe id="iframe1" src="resources/resize-corner-tracking-touch-iframe.html" + style="resize:both; width: 200px; height: 200px"></iframe> <script type="text/javascript"> - async function resize(target, offset, touch_delta, device) - { - var rect = target.getBoundingClientRect(); - if (typeof(device) == "undefined") - device = GestureSourceType.TOUCH_INPUT; - await smoothScrollWithXY(-touch_delta.touch_delta_x, -touch_delta.touch_delta_y, - rect.right + offset.x, rect.bottom + offset.y, device, - SPEED_INSTANT); - } + async function touchDrag(target, offset, delta) { + const rect = target.getBoundingClientRect(); + const x0 = rect.right + offset.x; + const y0 = rect.bottom + offset.y; + drag = { + start_x: x0, + start_y: y0, + end_x: x0 + delta.dx, + end_y: y0 + delta.dy + }; + await touchDragTo(drag); + + return waitForCompositorCommit(); + } + + async function touchpadScroll(target, offset, delta, device) { + var rect = target.getBoundingClientRect(); + const precise_scroll_delta = true; + await smoothScrollWithXY(-delta.dx, -delta.dy, + rect.right + offset.x, rect.bottom + offset.y, + GestureSourceType.TOUCHPAD_INPUT, SPEED_INSTANT, + precise_scroll_delta); + return waitForCompositorCommit(); + } + + function assert_resize(target, oldBounds) { + const newBounds = target.getBoundingClientRect(); + assert_true(newBounds.width != oldBounds.width && + newBounds.height != oldBounds.height, + 'Element failed to resize'); + } + + function assert_no_resize(target, oldBounds) { + const newBounds = target.getBoundingClientRect(); + assert_true(newBounds.width == oldBounds.width && + newBounds.height == oldBounds.height, + 'Element unexpectedly resized'); + } + + function resetStyle(element_id, style) { + const element = document.getElementById(element_id); + element.style = style; + } + + async function setupTest(scrollTop = 50) { + resetStyle('div', 'width: 150px; height: 100px;'); + resetStyle('textarea1', 'width: 150px; height: 100px;'); + resetStyle('iframe1', 'resize:both; width: 200px; height: 200px;'); + + // Scroll the page first to test that resize works with a scrolled page. + document.scrollingElement.scrollTop = scrollTop; + + return waitForCompositorCommit(); + } + + window.onload = () => { + promise_test(async () => { + await setupTest(); + + // Touch scrolling starting at inside the object, and within the normal + // resizer area (15x15), e.g. offset (-6, -7) from bottom right corner of + // the object, will do the resize. + const target = document.getElementById("div"); + const oldBounds = target.getBoundingClientRect(); + + await touchDrag(target, {x: -6, y: -7}, {dx: -20, dy: -10}); + assert_resize(target, oldBounds); + }, 'Touch drag inside the resizer area of div will do the resize.'); promise_test(async () => { - // Scroll the page first to test that resize works with scrolled page. - document.scrollingElement.scrollTop = 50; + await setupTest(); - // Touch scrolling starting at inside the object, and within the normal - // resizer area (15x15), e.g. offset (-6, -7) from bottom right corner of - // the object, will do the resize. - var target = document.getElementById("div"); - var old_width = target.offsetWidth; - var old_height = target.offsetHeight; - await resize(target, {x: -6, y: -7}, {touch_delta_x: 20, touch_delta_y: 10}); - // The resize expectation includes the touch slop region and is one frame - // in the future based on the addition of the values of position and delta. - assert_equals(target.offsetWidth - old_width, 53); - assert_equals(target.offsetHeight - old_height, 17); - }, 'Touch scrolling inside the resizer area of div will do the resize.'); + // Touch scrolling starting at outside of the object, e.g. offset (6, 7) + // from bottom right corner of the object, won't do the resize. + const target = document.getElementById("div"); + const oldBounds = target.getBoundingClientRect(); + + await touchDrag(target, {x: 6, y: 7}, {dx: -20, dy: -10}); + assert_no_resize(target, oldBounds); + }, 'Touch drag outside of div will not do the resize.'); promise_test(async () => { - // Touch scrolling starting at outside of the object, e.g. offset (6, 7) - // from bottom right corner of the object, won't do the resize. - var target = document.getElementById("div"); - var old_width = target.offsetWidth; - var old_height = target.offsetHeight; - await resize(target, {x: 6, y: 7}, {touch_delta_x: 20, touch_delta_y: 10}); - assert_equals(target.offsetWidth - old_width, 0); - assert_equals(target.offsetHeight - old_height, 0); - }, 'Touch scrolling outside of div will not do the resize.'); + await setupTest(); + + // Touch scrolling starting at inside the object, and only a little bit + // off the resizer area, e.g. offset (-20, -20) from bottom right corner + // of the object, will do the resize. + // Do not require an exact hit on the resizer due to touch fuzzing. + const target = document.getElementById("textarea1"); + const oldBounds = target.getBoundingClientRect(); + + await touchDrag(target, {x: -20, y: -20}, {dx: -20, dy: -10}); + assert_resize(target, oldBounds); + }, 'Touch drag a little off the resizer area of textarea will do ' + + 'the resize.'); promise_test(async () => { - // Touch scrolling starting at inside the object, and only a little bit - // off the resizer area, e.g. offset (-20, -20) from bottom right corner of - // the object, will do the resize. - var target = document.getElementById("textarea1"); - var old_width = target.offsetWidth; - var old_height = target.offsetHeight; - await resize(target, {x: -20, y: -20}, {touch_delta_x: 20, touch_delta_y: 10}); - // The resize expectation includes the touch slop region and is one frame - // in the future based on the addition of the values of position and delta. - assert_equals(target.offsetWidth - old_width, 53); - assert_equals(target.offsetHeight - old_height, 17); - }, 'Touch scrolling a little off the resizer area of textarea will do the resize.'); + await setupTest(); + + const target = document.getElementById("textarea1"); + const oldBounds = target.getBoundingClientRect(); + + await touchpadScroll(target, {x: -6, y: -7}, {dx: 20, dy: 10}); + assert_no_resize(target, oldBounds); + }, 'Touchpad scroll should not resize the textarea.'); promise_test(async () => { - var target = document.getElementById("textarea1"); - var old_width = target.offsetWidth; - var old_height = target.offsetHeight; - await resize(target, {x: -6, y: -7}, {touch_delta_x: 20, touch_delta_y: 10}, - GestureSourceType.TOUCHPAD_INPUT); - assert_equals(target.offsetWidth - old_width, 0); - assert_equals(target.offsetHeight - old_height, 0); - }, 'Touchpad scroll should not resize textarea'); + await setupTest(/* scrollTop */ 150); + + const iframe = document.getElementById("iframe1"); + const oldBounds = iframe.getBoundingClientRect(); + + await touchDrag(iframe, {x: -6, y: -7}, {dx: -20, dy: -10}); + assert_resize(iframe, oldBounds); + }, 'Touch drag inside the resizer area of iframe resizes the iframe.'); promise_test(async () => { - // Scroll the page again - document.scrollingElement.scrollTop += 100; + await setupTest(/* scrollTop */ 150); - var iframe = document.getElementById("iframe1"); - var old_width = iframe.offsetWidth; - var old_height = iframe.offsetHeight; - await resize(iframe, {x: -6, y: -7}, {touch_delta_x: 20, touch_delta_y: 10}); - assert_equals(iframe.offsetWidth - old_width, 53); - assert_equals(iframe.offsetHeight - old_height, 17); - }, 'Touch scrolling inside the resizer area of iframe will do the resize after scroll.'); + const iframe = document.getElementById("iframe1"); + const oldBounds = iframe.getBoundingClientRect(); + + // Do not require an exact hit on the resizer due to touch fuzzing. + await touchDrag(iframe, {x: -20, y: -20}, {dx: -20, dy: -10}); + assert_resize(iframe, oldBounds); + }, 'Touch drag a little off the resizer area of an iframe will resize ' + + ' the iframe.'); promise_test(async () => { - var iframe = document.getElementById("iframe1"); - var old_width = iframe.offsetWidth; - var old_height = iframe.offsetHeight; - await resize(iframe, {x: -20, y: -20}, {touch_delta_x: 20, touch_delta_y: 10}); - assert_equals(iframe.offsetWidth - old_width, 53); - assert_equals(iframe.offsetHeight - old_height, 17); - }, 'Touch scrolling a little off the resizer area of iframe will do the resize after scroll.'); + await setupTest(/* scrollTop */ 150); - promise_test(async () => { - var iframe = document.getElementById("iframe1"); - var rect = iframe.getBoundingClientRect(); - var target = iframe.contentDocument.getElementById("textarea2"); - var old_width = target.offsetWidth; - var old_height = target.offsetHeight; - await resize(target, {x: rect.left - 6, y: rect.top - 7}, - {touch_delta_x: 20, touch_delta_y: 10}); - assert_equals(target.offsetWidth - old_width, 53); - assert_equals(target.offsetHeight - old_height, 17); - }, 'Touch scrolling inside the resizer area of textarea in iframe will do the resize after scroll.'); + const iframe = document.getElementById("iframe1"); + const rect = iframe.getBoundingClientRect(); + const target = iframe.contentDocument.getElementById("textarea2"); + const oldBounds = target.getBoundingClientRect(); + + await touchDrag(target, {x: rect.left - 6, y: rect.top - 7}, + {dx: 20, dy: 10}); + assert_resize(target, oldBounds); + }, 'Touch drag inside the resizer area of a textarea inside an iframe ' + + 'will resize the textarea.'); +}; </script>
diff --git a/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt index f61691b..c1ab5fa 100644 --- a/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt +++ b/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -1131,7 +1131,7 @@ getter duration getter entryType getter name - getter navigationCount + getter navigationId getter startTime method constructor method toJSON
diff --git a/third_party/blink/web_tests/virtual/shared_array_buffer_on_desktop/fast/css/rgb-float-expected.png b/third_party/blink/web_tests/virtual/shared_array_buffer_on_desktop/fast/css/rgb-float-expected.png deleted file mode 100644 index 136f589..0000000 --- a/third_party/blink/web_tests/virtual/shared_array_buffer_on_desktop/fast/css/rgb-float-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/virtual/shared_array_buffer_on_desktop/fast/webgl/texImage-imageBitmap-from-imageData-resize-expected.png b/third_party/blink/web_tests/virtual/shared_array_buffer_on_desktop/fast/webgl/texImage-imageBitmap-from-imageData-resize-expected.png deleted file mode 100644 index 1d3c367d..0000000 --- a/third_party/blink/web_tests/virtual/shared_array_buffer_on_desktop/fast/webgl/texImage-imageBitmap-from-imageData-resize-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-properties-after-frame-navigated-expected.txt b/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-properties-after-frame-navigated-expected.txt index cc4b9505..2d48c2c 100644 --- a/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-properties-after-frame-navigated-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-properties-after-frame-navigated-expected.txt
@@ -1,18 +1,18 @@ -Tests access of cached DOMWindow properties after the associated frame is navigated. Test should not crash and properties should be set to sane defaults. +Tests access of cached DOMWindow properties after the associated frame is navigated. Test should not crash and properties should be set to reasonable defaults as appropriate. On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". PASS window.cached_cookieStore.onchange is null -FAIL window.cached_location.hash should be (of type string). Was undefined (of type undefined). -FAIL window.cached_location.host should be (of type string). Was undefined (of type undefined). -FAIL window.cached_location.hostname should be (of type string). Was undefined (of type undefined). -FAIL window.cached_location.href should be about:blank (of type string). Was undefined (of type undefined). -FAIL window.cached_location.origin should be null (of type string). Was undefined (of type undefined). -FAIL window.cached_location.pathname should be blank (of type string). Was undefined (of type undefined). -FAIL window.cached_location.port should be (of type string). Was undefined (of type undefined). -FAIL window.cached_location.protocol should be about: (of type string). Was undefined (of type undefined). -FAIL window.cached_location.search should be (of type string). Was undefined (of type undefined). -PASS window.cached_location_ancestorOrigins.length is 1 +PASS window.cached_location.hash is undefined +PASS window.cached_location.host is undefined +PASS window.cached_location.hostname is undefined +PASS window.cached_location.href is undefined +PASS window.cached_location.origin is undefined +PASS window.cached_location.pathname is undefined +PASS window.cached_location.port is undefined +PASS window.cached_location.protocol is undefined +PASS window.cached_location.search is undefined +FAIL window.cached_location_ancestorOrigins.length should be 0. Was 1. PASS window.cached_locationbar.visible is false PASS window.cached_menubar.visible is false PASS window.cached_navigator.appCodeName is window.navigator.appCodeName @@ -33,7 +33,9 @@ PASS window.cached_navigator.vendor is window.navigator.vendor PASS window.cached_navigator.vendorSub is '' PASS window.cached_navigator.webdriver is false +PASS window.cached_navigator_connection.effectiveType is window.navigator.connection.effectiveType PASS window.cached_navigator_connection.onchange is null +PASS window.cached_navigator_connection.rtt is window.navigator.connection.rtt PASS window.cached_navigator_connection.saveData is false PASS window.cached_navigator_hid.onconnect is null PASS window.cached_navigator_hid.ondisconnect is null @@ -105,7 +107,7 @@ PASS window.cached_screen.width is 0 PASS window.cached_screen_orientation.angle is 0 PASS window.cached_screen_orientation.onchange is null -PASS window.cached_screen_orientation.type is 'portrait-primary' +PASS window.cached_screen_orientation.type is window.screen.orientation.type PASS window.cached_scrollbars.visible is false PASS window.cached_speechSynthesis.onvoiceschanged is null PASS window.cached_speechSynthesis.paused is false
diff --git a/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-and-gced-expected.txt b/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-and-gced-expected.txt index 7e963534..a74021c 100644 --- a/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-and-gced-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-and-gced-expected.txt
@@ -1,18 +1,18 @@ -Tests access of cached DOMWindow properties after the associated frame is removed from a web page and garbage collected. Test should not crash and properties should be set to sane defaults. +Tests access of cached DOMWindow properties after the associated frame is removed from a web page and garbage collected. Test should not crash and properties should be set to reasonable defaults as appropriate. On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". PASS window.cached_cookieStore.onchange is null -FAIL window.cached_location.hash should be (of type string). Was undefined (of type undefined). -FAIL window.cached_location.host should be (of type string). Was undefined (of type undefined). -FAIL window.cached_location.hostname should be (of type string). Was undefined (of type undefined). -FAIL window.cached_location.href should be about:blank (of type string). Was undefined (of type undefined). -FAIL window.cached_location.origin should be null (of type string). Was undefined (of type undefined). -FAIL window.cached_location.pathname should be blank (of type string). Was undefined (of type undefined). -FAIL window.cached_location.port should be (of type string). Was undefined (of type undefined). -FAIL window.cached_location.protocol should be about: (of type string). Was undefined (of type undefined). -FAIL window.cached_location.search should be (of type string). Was undefined (of type undefined). -PASS window.cached_location_ancestorOrigins.length is 1 +PASS window.cached_location.hash is undefined +PASS window.cached_location.host is undefined +PASS window.cached_location.hostname is undefined +PASS window.cached_location.href is undefined +PASS window.cached_location.origin is undefined +PASS window.cached_location.pathname is undefined +PASS window.cached_location.port is undefined +PASS window.cached_location.protocol is undefined +PASS window.cached_location.search is undefined +FAIL window.cached_location_ancestorOrigins.length should be 0. Was 1. PASS window.cached_locationbar.visible is false PASS window.cached_menubar.visible is false PASS window.cached_navigator.appCodeName is window.navigator.appCodeName @@ -33,7 +33,9 @@ PASS window.cached_navigator.vendor is window.navigator.vendor PASS window.cached_navigator.vendorSub is '' PASS window.cached_navigator.webdriver is false +PASS window.cached_navigator_connection.effectiveType is window.navigator.connection.effectiveType PASS window.cached_navigator_connection.onchange is null +PASS window.cached_navigator_connection.rtt is window.navigator.connection.rtt PASS window.cached_navigator_connection.saveData is false PASS window.cached_navigator_hid.onconnect is null PASS window.cached_navigator_hid.ondisconnect is null @@ -105,7 +107,7 @@ PASS window.cached_screen.width is 0 PASS window.cached_screen_orientation.angle is 0 PASS window.cached_screen_orientation.onchange is null -PASS window.cached_screen_orientation.type is 'portrait-primary' +PASS window.cached_screen_orientation.type is window.screen.orientation.type PASS window.cached_scrollbars.visible is false PASS window.cached_speechSynthesis.onvoiceschanged is null PASS window.cached_speechSynthesis.paused is false
diff --git a/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-expected.txt b/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-expected.txt index eebf654d..0e9e3363 100644 --- a/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-expected.txt
@@ -1,18 +1,18 @@ -Tests access of cached DOMWindow properties after the associated frame is no longer in a web page. Test should not crash and properties should be set to sane defaults. +Tests access of cached DOMWindow properties after the associated frame is no longer in a web page. Test should not crash and properties should be set to reasonable defaults as appropriate. On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". PASS window.cached_cookieStore.onchange is null -FAIL window.cached_location.hash should be (of type string). Was undefined (of type undefined). -FAIL window.cached_location.host should be (of type string). Was undefined (of type undefined). -FAIL window.cached_location.hostname should be (of type string). Was undefined (of type undefined). -FAIL window.cached_location.href should be about:blank (of type string). Was undefined (of type undefined). -FAIL window.cached_location.origin should be null (of type string). Was undefined (of type undefined). -FAIL window.cached_location.pathname should be blank (of type string). Was undefined (of type undefined). -FAIL window.cached_location.port should be (of type string). Was undefined (of type undefined). -FAIL window.cached_location.protocol should be about: (of type string). Was undefined (of type undefined). -FAIL window.cached_location.search should be (of type string). Was undefined (of type undefined). -PASS window.cached_location_ancestorOrigins.length is 1 +PASS window.cached_location.hash is undefined +PASS window.cached_location.host is undefined +PASS window.cached_location.hostname is undefined +PASS window.cached_location.href is undefined +PASS window.cached_location.origin is undefined +PASS window.cached_location.pathname is undefined +PASS window.cached_location.port is undefined +PASS window.cached_location.protocol is undefined +PASS window.cached_location.search is undefined +FAIL window.cached_location_ancestorOrigins.length should be 0. Was 1. PASS window.cached_locationbar.visible is false PASS window.cached_menubar.visible is false PASS window.cached_navigator.appCodeName is window.navigator.appCodeName @@ -33,7 +33,9 @@ PASS window.cached_navigator.vendor is window.navigator.vendor PASS window.cached_navigator.vendorSub is '' PASS window.cached_navigator.webdriver is false +PASS window.cached_navigator_connection.effectiveType is window.navigator.connection.effectiveType PASS window.cached_navigator_connection.onchange is null +PASS window.cached_navigator_connection.rtt is window.navigator.connection.rtt PASS window.cached_navigator_connection.saveData is false PASS window.cached_navigator_hid.onconnect is null PASS window.cached_navigator_hid.ondisconnect is null @@ -105,7 +107,7 @@ PASS window.cached_screen.width is 0 PASS window.cached_screen_orientation.angle is 0 PASS window.cached_screen_orientation.onchange is null -PASS window.cached_screen_orientation.type is 'portrait-primary' +PASS window.cached_screen_orientation.type is window.screen.orientation.type PASS window.cached_scrollbars.visible is false PASS window.cached_speechSynthesis.onvoiceschanged is null PASS window.cached_speechSynthesis.paused is false
diff --git a/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt b/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt index 58ffc06..34d2eb2 100644 --- a/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt
@@ -28,7 +28,9 @@ PASS oldChildWindow.navigator.appCodeName is newChildWindow.navigator.appCodeName PASS oldChildWindow.navigator.appName is newChildWindow.navigator.appName PASS oldChildWindow.navigator.appVersion is newChildWindow.navigator.appVersion +PASS oldChildWindow.navigator.connection.effectiveType is newChildWindow.navigator.connection.effectiveType PASS oldChildWindow.navigator.connection.onchange is newChildWindow.navigator.connection.onchange +PASS oldChildWindow.navigator.connection.rtt is newChildWindow.navigator.connection.rtt PASS oldChildWindow.navigator.connection.saveData is newChildWindow.navigator.connection.saveData PASS oldChildWindow.navigator.cookieEnabled is newChildWindow.navigator.cookieEnabled PASS oldChildWindow.navigator.deviceMemory is newChildWindow.navigator.deviceMemory
diff --git a/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt b/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt index 5b5da5e..6b892526 100644 --- a/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt
@@ -1,17 +1,17 @@ -Tests property access on a cached DOMWindow after the associated frame is removed from a web page and garbage collected. Test should not crash and properties should be set to sane defaults. +Tests property access on a cached DOMWindow after the associated frame is removed from a web page and garbage collected. Test should not crash and properties should be set to reasonable defaults as appropriate. On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". -PASS childWindow.closed is true +FAIL childWindow.closed should be false. Was true. PASS childWindow.crossOriginIsolated is false PASS childWindow.defaultStatus is '' PASS childWindow.defaultstatus is '' PASS childWindow.devicePixelRatio is 0 PASS childWindow.innerHeight is 0 PASS childWindow.innerWidth is 0 -PASS childWindow.isSecureContext is false +PASS childWindow.isSecureContext is true PASS childWindow.length is 0 -FAIL childWindow.location.href should be about:blank (of type string). Was undefined (of type undefined). +PASS childWindow.location.href is undefined PASS childWindow.locationbar.visible is false PASS childWindow.menubar.visible is false PASS childWindow.name is ''
diff --git a/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt b/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt index 158521f3..c77c8a4 100644 --- a/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt
@@ -1,17 +1,17 @@ -Tests property access on a cached DOMWindow after the associated frame is no longer in a web page. Test should not crash and properties should be set to sane defaults. +Tests property access on a cached DOMWindow after the associated frame is no longer in a web page. Test should not crash and properties should be set to reasonable defaults as appropriate. On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". -PASS childWindow.closed is true +FAIL childWindow.closed should be false. Was true. PASS childWindow.crossOriginIsolated is false PASS childWindow.defaultStatus is '' PASS childWindow.defaultstatus is '' PASS childWindow.devicePixelRatio is 0 PASS childWindow.innerHeight is 0 PASS childWindow.innerWidth is 0 -PASS childWindow.isSecureContext is false +PASS childWindow.isSecureContext is true PASS childWindow.length is 0 -FAIL childWindow.location.href should be about:blank (of type string). Was undefined (of type undefined). +PASS childWindow.location.href is undefined PASS childWindow.locationbar.visible is false PASS childWindow.menubar.visible is false PASS childWindow.name is ''
diff --git a/third_party/blink/web_tests/virtual/third-party-storage-partitioning/external/wpt/IndexedDB/README.txt b/third_party/blink/web_tests/virtual/third-party-storage-partitioning/external/wpt/IndexedDB/README.txt new file mode 100644 index 0000000..3665aad0 --- /dev/null +++ b/third_party/blink/web_tests/virtual/third-party-storage-partitioning/external/wpt/IndexedDB/README.txt
@@ -0,0 +1 @@ +This suite runs IndexedDB tests with ThirdPartyStoragePartitioning enabled.
diff --git a/third_party/blink/web_tests/virtual/shared_array_buffer_on_desktop/fast/xmlhttprequest/xmlhttprequest-send-sharedarraybuffer-expected.txt b/third_party/blink/web_tests/virtual/third-party-storage-partitioning/external/wpt/IndexedDB/idb-partitioned-basic.tentative.sub-expected.txt similarity index 63% rename from third_party/blink/web_tests/virtual/shared_array_buffer_on_desktop/fast/xmlhttprequest/xmlhttprequest-send-sharedarraybuffer-expected.txt rename to third_party/blink/web_tests/virtual/third-party-storage-partitioning/external/wpt/IndexedDB/idb-partitioned-basic.tentative.sub-expected.txt index cb3bb84..1b9cfad 100644 --- a/third_party/blink/web_tests/virtual/shared_array_buffer_on_desktop/fast/xmlhttprequest/xmlhttprequest-send-sharedarraybuffer-expected.txt +++ b/third_party/blink/web_tests/virtual/third-party-storage-partitioning/external/wpt/IndexedDB/idb-partitioned-basic.tentative.sub-expected.txt
@@ -1,4 +1,4 @@ This is a testharness.js-based test. -PASS sending SharedArrayBuffer +PASS Simple test for partitioned IndexedDB Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt index a51281a..c0c757d 100644 --- a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt +++ b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -1174,7 +1174,7 @@ [Worker] getter duration [Worker] getter entryType [Worker] getter name -[Worker] getter navigationCount +[Worker] getter navigationId [Worker] getter startTime [Worker] method constructor [Worker] method toJSON
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt index 8c36dc40..2ef899fa 100644 --- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt +++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -6355,7 +6355,7 @@ getter duration getter entryType getter name - getter navigationCount + getter navigationId getter startTime method constructor method toJSON
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt index f9304b5..ccde2f6 100644 --- a/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt +++ b/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -1036,7 +1036,7 @@ [Worker] getter duration [Worker] getter entryType [Worker] getter name -[Worker] getter navigationCount +[Worker] getter navigationId [Worker] getter startTime [Worker] method constructor [Worker] method toJSON
diff --git a/third_party/blink/web_tests/wpt_internal/document-transition/web-animations-api-ref.html b/third_party/blink/web_tests/wpt_internal/document-transition/web-animations-api-ref.html new file mode 100644 index 0000000..391e377 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/document-transition/web-animations-api-ref.html
@@ -0,0 +1,26 @@ +<!DOCTYPE html> +<title>Shared transitions: one element captured for two tags (ref)</title> +<link rel="help" href="https://github.com/WICG/shared-element-transitions"> +<link rel="author" href="mailto:vmpstr@chromium.org"> +<style> +div { + position: fixed; + top: 0; + left: 0; +} +#first { + background: blue; + width: 100px; + height: 100px; + transform: translate(100px); +} +#second { + background: green; + width: 100px; + height: 100px; + transform: translate(150px); +} +</style> +<div id=first></div> +<div id=second></div> +
diff --git a/third_party/blink/web_tests/wpt_internal/document-transition/web-animations-api.html b/third_party/blink/web_tests/wpt_internal/document-transition/web-animations-api.html new file mode 100644 index 0000000..2eceaa6 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/document-transition/web-animations-api.html
@@ -0,0 +1,50 @@ +<!DOCTYPE html> +<html class=reftest-wait> +<title>Shared transitions: capture opacity elements</title> +<link rel="help" href="https://github.com/WICG/shared-element-transitions"> +<link rel="author" href="mailto:khushalsagar@chromium.org"> +<link rel="match" href="web-animations-api-ref.html"> + +<script src="/common/reftest-wait.js"></script> +<style> +#first { + background: blue; + width: 100px; + height: 100px; + contain: paint; +} +#second { + background: green; + width: 100px; + height: 100px; + contain: paint; +} + +/* Unset all animations since the test drives it using WA-API */ +html::page-transition-container(*), +html::page-transition-image-wrapper(*), +html::page-transition-incoming-image(*), +html::page-transition-outgoing-image(*) { + animation: unset; +} +</style> +<div id=first></div> +<div id=second></div> +<script> +function setAnimation() { + document.documentElement.animate({ transform: ['translate(100px)', 'translate(100px)'] }, { duration: 10000, pseudoElement: '::page-transition-container(first)'}); + document.documentElement.animate({ transform: ['translate(150px)', 'translate(150px)'] }, { duration: 10000, pseudoElement: '::page-transition-container(second)'}); + requestAnimationFrame(takeScreenshot); +} + +async function runTest() { + let t = document.createDocumentTransition(); + t.setElement(document.getElementById("first"), "first"); + t.start(() => { + t.setElement(document.getElementById("second"), "second"); + requestAnimationFrame(setAnimation); + }); +} +onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest)); +</script> +
diff --git a/third_party/crashpad/README.chromium b/third_party/crashpad/README.chromium index 59f05f4..497e788b 100644 --- a/third_party/crashpad/README.chromium +++ b/third_party/crashpad/README.chromium
@@ -2,7 +2,7 @@ Short Name: crashpad URL: https://crashpad.chromium.org/ Version: unknown -Revision: 13202c2ffe4b02303c721bb2f6e8efda1999aa1e +Revision: 12b35ebde8699d49f3bbef7c82f55c334993aa00 License: Apache 2.0 License File: crashpad/LICENSE Security Critical: yes
diff --git a/third_party/crashpad/crashpad/client/crashpad_client.h b/third_party/crashpad/crashpad/client/crashpad_client.h index 54acfba..1063dcf 100644 --- a/third_party/crashpad/crashpad/client/crashpad_client.h +++ b/third_party/crashpad/crashpad/client/crashpad_client.h
@@ -563,6 +563,13 @@ //! multiple Crashpad clients can be started and stopped. Not expected to //! be used in a shipping application. static void ResetForTesting(); + + //! \brief Inject a callback into Mach handling. Intended to be used by + //! tests to trigger a reentrant exception. + static void SetMachExceptionCallbackForTesting(void (*callback)()); + + //! \brief Returns the thread id of the Mach exception thread, used by tests. + static uint64_t GetThreadIdForTesting(); #endif #if BUILDFLAG(IS_APPLE) || DOXYGEN
diff --git a/third_party/crashpad/crashpad/client/crashpad_client_ios.cc b/third_party/crashpad/crashpad/client/crashpad_client_ios.cc index ae0ddf1..7a4f2a2 100644 --- a/third_party/crashpad/crashpad/client/crashpad_client_ios.cc +++ b/third_party/crashpad/crashpad/client/crashpad_client_ios.cc
@@ -84,10 +84,31 @@ // generate intermediate dumps for anything manually calling // raise(SIG*). In practice, this doesn’t actually happen for crash // signals that originate as hardware faults. - !Signals::InstallHandler(SIGABRT, CatchSignal, 0, &old_action_)) { + !Signals::InstallHandler( + SIGABRT, CatchAndReraiseSignal, 0, &old_action_)) { LOG(ERROR) << "Unable to initialize Crashpad."; return false; } + + // For applications that haven't ignored or set a handler for SIGPIPE: + // It’s OK for an application to set its own SIGPIPE handler (including + // SIG_IGN) before initializing Crashpad, because Crashpad will discover the + // existing handler and not install its own. + // It’s OK for Crashpad to install its own SIGPIPE handler and for the + // application to subsequently install its own (including SIG_IGN) + // afterwards, because its handler will replace Crashpad’s. + // This is useful to cover the default situation where nobody installs a + // SIGPIPE handler and the disposition is at SIG_DFL, because SIGPIPE is a + // “kill” signal (bsd/sys/signalvar.h sigprop). In that case, without + // Crashpad, SIGPIPE results in a silent and unreported kill (and not even + // ReportCrash will record it), but developers probably want to be alerted + // to the conditon. + struct sigaction sa; + if (sigaction(SIGPIPE, nullptr, &sa) == 0 && sa.sa_handler == SIG_DFL) { + Signals::InstallHandler( + SIGPIPE, CatchAndReraiseSignalDefaultAction, 0, nullptr); + } + InstallObjcExceptionPreprocessor(this); INITIALIZATION_STATE_SET_VALID(initialized_); return true; @@ -104,35 +125,14 @@ in_process_handler_.ProcessIntermediateDump(file, annotations); } - void DumpWithContext(NativeCPUContext* context) { - const mach_exception_data_type_t code[2] = {}; - static constexpr int kSimulatedException = -1; - HandleMachException(MACH_EXCEPTION_CODES, - mach_thread_self(), - kSimulatedException, - code, - std::size(code), - MACHINE_THREAD_STATE, - reinterpret_cast<ConstThreadState>(context), - MACHINE_THREAD_STATE_COUNT); - } - void DumpWithoutCrash(NativeCPUContext* context, bool process_dump) { INITIALIZATION_STATE_DCHECK_VALID(initialized_); base::FilePath path; - { - // Ensure ScopedAlternateWriter's destructor is invoked before processing - // the dump, or else any crashes handled during dump processing cannot be - // written. - internal::InProcessHandler::ScopedAlternateWriter scoper( - &in_process_handler_); - if (!scoper.Open()) { - LOG(ERROR) << "Could not open writer, ignoring dump request."; - return; - } - DumpWithContext(context); - path = scoper.path(); + if (!in_process_handler_.DumpExceptionFromSimulatedMachException( + system_data_, context, &path)) { + return; } + if (process_dump) { in_process_handler_.ProcessIntermediateDump(path); } @@ -140,10 +140,8 @@ void DumpWithoutCrashAtPath(NativeCPUContext* context, const base::FilePath& path) { - internal::InProcessHandler::ScopedAlternateWriter scoper( - &in_process_handler_); - if (scoper.OpenAtPath(path)) - DumpWithContext(context); + in_process_handler_.DumpExceptionFromSimulatedMachExceptionAtPath( + system_data_, context, path); } void StartProcessingPendingReports() { @@ -151,6 +149,12 @@ in_process_handler_.StartProcessingPendingReports(); } + void SetMachExceptionCallbackForTesting(void (*callback)()) { + in_process_handler_.SetMachExceptionCallbackForTesting(callback); + } + + uint64_t GetThreadIdForTesting() { return Thread::GetThreadIdForTesting(); } + private: CrashHandler() = default; @@ -287,7 +291,7 @@ void HandleUncaughtNSException(const uint64_t* frames, const size_t num_frames) override { - in_process_handler_.DumpExceptionFromNSExceptionFrames( + in_process_handler_.DumpExceptionFromNSExceptionWithFrames( system_data_, frames, num_frames); // After uncaught exceptions are reported, the system immediately triggers a // call to std::terminate()/abort(). Remove the abort handler so a second @@ -297,17 +301,8 @@ void HandleUncaughtNSExceptionWithContext( NativeCPUContext* context) override { - const mach_exception_data_type_t code[2] = {0, 0}; - in_process_handler_.DumpExceptionFromMachException( - system_data_, - MACH_EXCEPTION_CODES, - mach_thread_self(), - kMachExceptionFromNSException, - code, - std::size(code), - MACHINE_THREAD_STATE, - reinterpret_cast<ConstThreadState>(context), - MACHINE_THREAD_STATE_COUNT); + in_process_handler_.DumpExceptionFromNSExceptionWithContext(system_data_, + context); // After uncaught exceptions are reported, the system immediately triggers a // call to std::terminate()/abort(). Remove the abort handler so a second @@ -316,18 +311,30 @@ } // The signal handler installed at OS-level. - static void CatchSignal(int signo, siginfo_t* siginfo, void* context) { + static void CatchAndReraiseSignal(int signo, + siginfo_t* siginfo, + void* context) { + Get()->HandleAndReraiseSignal(signo, + siginfo, + reinterpret_cast<ucontext_t*>(context), + &(Get()->old_action_)); + } + + static void CatchAndReraiseSignalDefaultAction(int signo, + siginfo_t* siginfo, + void* context) { Get()->HandleAndReraiseSignal( - signo, siginfo, reinterpret_cast<ucontext_t*>(context)); + signo, siginfo, reinterpret_cast<ucontext_t*>(context), nullptr); } void HandleAndReraiseSignal(int signo, siginfo_t* siginfo, - ucontext_t* context) { + ucontext_t* context, + struct sigaction* old_action) { in_process_handler_.DumpExceptionFromSignal(system_data_, siginfo, context); // Always call system handler. - Signals::RestoreHandlerAndReraiseSignalOnReturn(siginfo, &old_action_); + Signals::RestoreHandlerAndReraiseSignalOnReturn(siginfo, old_action); } base::mac::ScopedMachReceiveRight exception_port_; @@ -412,4 +419,16 @@ crash_handler->ResetForTesting(); } +void CrashpadClient::SetMachExceptionCallbackForTesting(void (*callback)()) { + CrashHandler* crash_handler = CrashHandler::Get(); + DCHECK(crash_handler); + crash_handler->SetMachExceptionCallbackForTesting(callback); +} + +uint64_t CrashpadClient::GetThreadIdForTesting() { + CrashHandler* crash_handler = CrashHandler::Get(); + DCHECK(crash_handler); + return crash_handler->GetThreadIdForTesting(); +} + } // namespace crashpad
diff --git a/third_party/crashpad/crashpad/client/crashpad_client_ios_test.mm b/third_party/crashpad/crashpad/client/crashpad_client_ios_test.mm index 9800d40..596f4b8 100644 --- a/third_party/crashpad/crashpad/client/crashpad_client_ios_test.mm +++ b/third_party/crashpad/crashpad/client/crashpad_client_ios_test.mm
@@ -25,6 +25,7 @@ #include "gtest/gtest.h" #include "test/scoped_temp_dir.h" #include "testing/platform_test.h" +#include "util/thread/thread.h" namespace crashpad { namespace test { @@ -100,6 +101,37 @@ ASSERT_EQ(reports.size(), 1u); } +class RaceThread : public Thread { + public: + explicit RaceThread() : Thread() {} + + private: + void ThreadMain() override { + for (int i = 0; i < 10; ++i) { + CRASHPAD_SIMULATE_CRASH(); + } + } +}; + +TEST_F(CrashpadIOSClient, MultipleThreadsSimulateCrash) { + RaceThread race_threads[2]; + for (RaceThread& race_thread : race_threads) { + race_thread.Start(); + } + + for (int i = 0; i < 10; ++i) { + CRASHPAD_SIMULATE_CRASH(); + } + for (RaceThread& race_thread : race_threads) { + race_thread.Join(); + } + + std::vector<CrashReportDatabase::Report> reports; + ASSERT_EQ(Database()->GetPendingReports(&reports), + CrashReportDatabase::kNoError); + EXPECT_EQ(reports.size(), 30u); +} + // This test is covered by a similar XCUITest, but for development purposes it's // sometimes easier and faster to run in Google Test. However, there's no way // to correctly run this in Google Test. Leave the test here, disabled, for use
diff --git a/third_party/crashpad/crashpad/client/ios_handler/in_process_handler.cc b/third_party/crashpad/crashpad/client/ios_handler/in_process_handler.cc index ea86f39e..2ed3113 100644 --- a/third_party/crashpad/crashpad/client/ios_handler/in_process_handler.cc +++ b/third_party/crashpad/crashpad/client/ios_handler/in_process_handler.cc
@@ -17,6 +17,9 @@ #include <stdio.h> #include <sys/stat.h> +#include <algorithm> + +#include "base/cxx17_backports.h" #include "base/logging.h" #include "client/ios_handler/in_process_intermediate_dump_handler.h" #include "client/prune_crash_reports.h" @@ -47,6 +50,10 @@ // uuid in the intermediate dump file name. constexpr char kBundleSeperator[] = "@"; +// Zero-ed codes used by kMachExceptionFromNSException and +// kMachExceptionSimulated. +constexpr mach_exception_data_type_t kEmulatedMachExceptionCodes[2] = {}; + } // namespace namespace crashpad { @@ -105,9 +112,16 @@ system_data.IsExtension())); prune_thread_->Start(); - if (!OpenNewFile()) + base::FilePath cached_writer_path = NewLockedFilePath(); + cached_writer_ = CreateWriterWithPath(cached_writer_path); + if (!cached_writer_.get()) return false; + // Cache the locked and unlocked path here so no allocations are needed during + // any exceptions. + cached_writer_path_ = cached_writer_path.value(); + cached_writer_unlocked_path_ = + cached_writer_path.RemoveFinalExtension().value(); INITIALIZATION_STATE_SET_VALID(initialized_); return true; } @@ -117,16 +131,16 @@ siginfo_t* siginfo, ucontext_t* context) { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - if (!writer_) { - CRASHPAD_RAW_LOG("Cannot DumpExceptionFromSignal without writer_"); + ScopedLockedWriter writer(GetCachedWriter(), + cached_writer_path_.c_str(), + cached_writer_unlocked_path_.c_str()); + if (!writer.GetWriter()) { + CRASHPAD_RAW_LOG("Cannot DumpExceptionFromSignal without writer"); return; } - { - ScopedReport report(writer_.get(), system_data, annotations_); - InProcessIntermediateDumpHandler::WriteExceptionFromSignal( - writer_.get(), system_data, siginfo, context); - } - PostReportCleanup(); + ScopedReport report(writer.GetWriter(), system_data, annotations_); + InProcessIntermediateDumpHandler::WriteExceptionFromSignal( + writer.GetWriter(), system_data, siginfo, context); } void InProcessHandler::DumpExceptionFromMachException( @@ -140,43 +154,123 @@ ConstThreadState old_state, mach_msg_type_number_t old_state_count) { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - if (!writer_) { - CRASHPAD_RAW_LOG("Cannot DumpExceptionFromMachException without writer_"); + ScopedLockedWriter writer(GetCachedWriter(), + cached_writer_path_.c_str(), + cached_writer_unlocked_path_.c_str()); + if (!writer.GetWriter()) { + CRASHPAD_RAW_LOG("Cannot DumpExceptionFromMachException without writer"); return; } - { - ScopedReport report(writer_.get(), system_data, annotations_); - InProcessIntermediateDumpHandler::WriteExceptionFromMachException( - writer_.get(), - behavior, - thread, - exception, - code, - code_count, - flavor, - old_state, - old_state_count); + + if (mach_exception_callback_for_testing_) { + mach_exception_callback_for_testing_(); } - PostReportCleanup(); + + ScopedReport report(writer.GetWriter(), system_data, annotations_); + InProcessIntermediateDumpHandler::WriteExceptionFromMachException( + writer.GetWriter(), + behavior, + thread, + exception, + code, + code_count, + flavor, + old_state, + old_state_count); } -void InProcessHandler::DumpExceptionFromNSExceptionFrames( +void InProcessHandler::DumpExceptionFromNSExceptionWithContext( + const IOSSystemDataCollector& system_data, + NativeCPUContext* context) { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + // This does not use the cached writer. NSExceptionWithContext comes from + // the objective-c preprocessor and uses a best-guess approach to detecting + // uncaught exceptions, and may be called multiple times. + base::FilePath writer_path = NewLockedFilePath(); + base::FilePath writer_path_unlocked = writer_path.RemoveFinalExtension(); + std::unique_ptr<IOSIntermediateDumpWriter> unsafe_writer = + CreateWriterWithPath(writer_path); + ScopedLockedWriter writer(unsafe_writer.get(), + writer_path.value().c_str(), + writer_path_unlocked.value().c_str()); + if (!writer.GetWriter()) { + CRASHPAD_RAW_LOG("Cannot DumpExceptionFromNSException without writer"); + return; + } + + ScopedReport report(writer.GetWriter(), system_data, annotations_); + InProcessIntermediateDumpHandler::WriteExceptionFromMachException( + writer.GetWriter(), + MACH_EXCEPTION_CODES, + mach_thread_self(), + kMachExceptionFromNSException, + kEmulatedMachExceptionCodes, + std::size(kEmulatedMachExceptionCodes), + MACHINE_THREAD_STATE, + reinterpret_cast<ConstThreadState>(context), + MACHINE_THREAD_STATE_COUNT); +} + +void InProcessHandler::DumpExceptionFromNSExceptionWithFrames( const IOSSystemDataCollector& system_data, const uint64_t* frames, const size_t num_frames) { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - if (!writer_) { + ScopedLockedWriter writer(GetCachedWriter(), + cached_writer_path_.c_str(), + cached_writer_unlocked_path_.c_str()); + if (!writer.GetWriter()) { CRASHPAD_RAW_LOG( - "Cannot DumpExceptionFromNSExceptionFrames without writer_"); + "Cannot DumpExceptionFromNSExceptionWithFrames without writer"); return; } - { - ScopedReport report( - writer_.get(), system_data, annotations_, frames, num_frames); - InProcessIntermediateDumpHandler::WriteExceptionFromNSException( - writer_.get()); + ScopedReport report( + writer.GetWriter(), system_data, annotations_, frames, num_frames); + InProcessIntermediateDumpHandler::WriteExceptionFromNSException( + writer.GetWriter()); +} + +bool InProcessHandler::DumpExceptionFromSimulatedMachException( + const IOSSystemDataCollector& system_data, + const NativeCPUContext* context, + base::FilePath* path) { + base::FilePath locked_path = NewLockedFilePath(); + *path = locked_path.RemoveFinalExtension(); + return DumpExceptionFromSimulatedMachExceptionAtPath( + system_data, context, locked_path); +} + +bool InProcessHandler::DumpExceptionFromSimulatedMachExceptionAtPath( + const IOSSystemDataCollector& system_data, + const NativeCPUContext* context, + const base::FilePath& path) { + // This does not use the cached writer. It's expected that simulated + // exceptions can be called multiple times and there is no expectation that + // the application is in an unsafe state, or will be terminated after this + // call. + std::unique_ptr<IOSIntermediateDumpWriter> unsafe_writer = + CreateWriterWithPath(path); + base::FilePath writer_path_unlocked = path.RemoveFinalExtension(); + ScopedLockedWriter writer(unsafe_writer.get(), + path.value().c_str(), + writer_path_unlocked.value().c_str()); + if (!writer.GetWriter()) { + CRASHPAD_RAW_LOG( + "Cannot DumpExceptionFromSimulatedMachExceptionAtPath without writer"); + return false; } - PostReportCleanup(); + ScopedReport report(writer.GetWriter(), system_data, annotations_); + InProcessIntermediateDumpHandler::WriteExceptionFromMachException( + writer.GetWriter(), + MACH_EXCEPTION_CODES, + mach_thread_self(), + kMachExceptionSimulated, + kEmulatedMachExceptionCodes, + std::size(kEmulatedMachExceptionCodes), + MACHINE_THREAD_STATE, + reinterpret_cast<ConstThreadState>(context), + MACHINE_THREAD_STATE_COUNT); + return true; } void InProcessHandler::ProcessIntermediateDumps( @@ -258,6 +352,7 @@ // intermediate dumps into never getting processed. std::vector<base::FilePath> other_files; + base::FilePath cached_writer_path(cached_writer_path_); while ((result = reader.NextFile(&file)) == DirectoryReader::Result::kSuccess) { // Don't try to process files marked as 'locked' from a different bundle id. @@ -269,9 +364,9 @@ continue; } - // Never process the current file. + // Never process the current cached writer path. file = base_dir_.Append(file); - if (file == current_file_) + if (file == cached_writer_path) continue; // Otherwise, include any other unlocked, or locked files matching @@ -292,35 +387,51 @@ return files; } -InProcessHandler::ScopedAlternateWriter::ScopedAlternateWriter( - InProcessHandler* handler) - : handler_(handler) {} +IOSIntermediateDumpWriter* InProcessHandler::GetCachedWriter() { + static_assert( + std::atomic<uint64_t>::is_always_lock_free, + "std::atomic_compare_exchange_strong uint64_t may not be signal-safe"); + uint64_t thread_self; + // This is only safe when passing pthread_self(), otherwise this can lock. + pthread_threadid_np(pthread_self(), &thread_self); + uint64_t expected = 0; + if (!std::atomic_compare_exchange_strong( + &exception_thread_id_, &expected, thread_self)) { + if (expected == thread_self) { + // Another exception came in from this thread, which means it's likely + // that our own handler crashed. We could open up a new intermediate dump + // and try to save this dump, but we could end up endlessly writing dumps. + // Instead, give up. + } else { + // Another thread is handling a crash. Sleep forever. + while (1) { + sleep(std::numeric_limits<unsigned int>::max()); + } + } + return nullptr; + } -bool InProcessHandler::ScopedAlternateWriter::Open() { + return cached_writer_.get(); +} + +std::unique_ptr<IOSIntermediateDumpWriter> +InProcessHandler::CreateWriterWithPath(const base::FilePath& writer_path) { + std::unique_ptr<IOSIntermediateDumpWriter> writer = + std::make_unique<IOSIntermediateDumpWriter>(); + if (!writer->Open(writer_path)) { + DLOG(ERROR) << "Unable to open intermediate dump file: " + << writer_path.value(); + return nullptr; + } + return writer; +} + +const base::FilePath InProcessHandler::NewLockedFilePath() { UUID uuid; uuid.InitializeWithNew(); - const std::string uuid_string = uuid.ToString(); - return OpenAtPath(handler_->base_dir_.Append(uuid_string)); -} - -bool InProcessHandler::ScopedAlternateWriter::OpenAtPath( - const base::FilePath& path) { - path_ = path; - handler_->SetOpenNewFileAfterReport(false); - original_writer_ = handler_->GetWriter(); - auto writer = std::make_unique<IOSIntermediateDumpWriter>(); - if (!writer->Open(path_)) { - DLOG(ERROR) << "Unable to open alternate intermediate dump file: " - << path_.value(); - return false; - } - handler_->SetWriter(std::move(writer)); - return true; -} - -InProcessHandler::ScopedAlternateWriter::~ScopedAlternateWriter() { - handler_->SetWriter(std::move(original_writer_)); - handler_->SetOpenNewFileAfterReport(true); + const std::string file_string = + bundle_identifier_and_seperator_ + uuid.ToString() + kLockedExtension; + return base_dir_.Append(file_string); } InProcessHandler::ScopedReport::ScopedReport( @@ -347,34 +458,24 @@ InProcessIntermediateDumpHandler::WriteModuleInfo(writer_); } -bool InProcessHandler::OpenNewFile() { - if (!current_file_.empty()) { - // Remove .lock extension so this dump can be processed on next run by this - // client, or a client with a different bundle id that can access this dump. - base::FilePath new_path = current_file_.RemoveFinalExtension(); - MoveFileOrDirectory(current_file_, new_path); - } - UUID uuid; - uuid.InitializeWithNew(); - const std::string file_string = - bundle_identifier_and_seperator_ + uuid.ToString() + kLockedExtension; - current_file_ = base_dir_.Append(file_string); - writer_ = std::make_unique<IOSIntermediateDumpWriter>(); - if (!writer_->Open(current_file_)) { - DLOG(ERROR) << "Unable to open intermediate dump file: " - << current_file_.value(); - return false; - } - return true; -} +InProcessHandler::ScopedLockedWriter::ScopedLockedWriter( + IOSIntermediateDumpWriter* writer, + const char* writer_path, + const char* writer_unlocked_path) + : writer_path_(writer_path), + writer_unlocked_path_(writer_unlocked_path), + writer_(writer) {} -void InProcessHandler::PostReportCleanup() { - if (writer_) { - writer_->Close(); - writer_.reset(); +InProcessHandler::ScopedLockedWriter::~ScopedLockedWriter() { + if (!writer_) + return; + + writer_->Close(); + if (rename(writer_path_, writer_unlocked_path_) != 0) { + CRASHPAD_RAW_LOG("Could not remove locked extension."); + CRASHPAD_RAW_LOG(writer_path_); + CRASHPAD_RAW_LOG(writer_unlocked_path_); } - if (open_new_file_after_report_) - OpenNewFile(); } } // namespace internal
diff --git a/third_party/crashpad/crashpad/client/ios_handler/in_process_handler.h b/third_party/crashpad/crashpad/client/ios_handler/in_process_handler.h index d94f19e7..fe638452 100644 --- a/third_party/crashpad/crashpad/client/ios_handler/in_process_handler.h +++ b/third_party/crashpad/crashpad/client/ios_handler/in_process_handler.h
@@ -12,8 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include <mach/mach.h> #include <stdint.h> +#include <atomic> #include <map> #include <string> #include <vector> @@ -24,6 +26,7 @@ #include "snapshot/ios/process_snapshot_ios_intermediate_dump.h" #include "util/ios/ios_intermediate_dump_writer.h" #include "util/ios/ios_system_data_collector.h" +#include "util/misc/capture_context.h" #include "util/misc/initialization_state_dcheck.h" namespace crashpad { @@ -55,6 +58,9 @@ const IOSSystemDataCollector& system_data); //! \brief Generate an intermediate dump from a signal handler exception. + //! Writes the dump with the cached writer does not allow concurrent + //! exceptions to be written. It is expected the system will terminate + //! the application after this call. //! //! \param[in] system_data An object containing various system data points. //! \param[in] siginfo A pointer to a `siginfo_t` object received by a signal @@ -65,7 +71,10 @@ siginfo_t* siginfo, ucontext_t* context); - //! \brief Generate an intermediate dump from a mach exception. + //! \brief Generate an intermediate dump from a mach exception. Writes the + //! dump with the cached writer does not allow concurrent exceptions to be + //! written. It is expected the system will terminate the application + //! after this call. //! //! \param[in] system_data An object containing various system data points. //! \param[in] behavior @@ -86,21 +95,62 @@ ConstThreadState old_state, mach_msg_type_number_t old_state_count); + //! \brief Generate an intermediate dump from a NSException caught with its + //! associated CPU context. Because the method for intercepting + //! exceptions is imperfect, uses a new writer for the intermediate dump, + //! as it is possible for further exceptions to happen. + //! + //! \param[in] system_data An object containing various system data points. + //! \param[in] context + void DumpExceptionFromNSExceptionWithContext( + const IOSSystemDataCollector& system_data, + NativeCPUContext* context); + //! \brief Generate an intermediate dump from an uncaught NSException. //! //! When the ObjcExceptionPreprocessor does not detect an NSException as it is //! thrown, the last-chance uncaught exception handler passes a list of call //! stack frame addresses. Record them in the intermediate dump so a minidump - //! with a 'fake' call stack is generated. + //! with a 'fake' call stack is generated. Writes the dump with the cached + //! writer does not allow concurrent exceptions to be written. It is expected + //! the system will terminate the application after this call. + //! //! \param[in] system_data An object containing various system data points. //! \param[in] frames An array of call stack frame addresses. //! \param[in] num_frames The number of frames in |frames|. - void DumpExceptionFromNSExceptionFrames( + void DumpExceptionFromNSExceptionWithFrames( const IOSSystemDataCollector& system_data, const uint64_t* frames, const size_t num_frames); + //! \brief Generate a simulated intermediate dump similar to a Mach exception + //! in the same base directory as other exceptions. Does not use the + //! cached writer. + //! + //! \param[in] system_data An object containing various system data points. + //! \param[in] context A pointer to a NativeCPUContext object for this + //! simulated exception. + //! \param[out] path The path of the intermediate dump generated. + //! \return `true` if the pending intermediate dump could be written. + bool DumpExceptionFromSimulatedMachException( + const IOSSystemDataCollector& system_data, + const NativeCPUContext* context, + base::FilePath* path); + + //! \brief Generate a simulated intermediate dump similar to a Mach exception + //! at a specific path. Does not use the cached writer. + //! + //! \param[in] system_data An object containing various system data points. + //! \param[in] context A pointer to a NativeCPUContext object for this + //! simulated exception. + //! \param[in] path Path to where the intermediate dump should be written. + //! \return `true` if the pending intermediate dump could be written. + bool DumpExceptionFromSimulatedMachExceptionAtPath( + const IOSSystemDataCollector& system_data, + const NativeCPUContext* context, + const base::FilePath& path); + //! \brief Requests that the handler convert all intermediate dumps into //! minidumps and trigger an upload if possible. //! @@ -121,34 +171,11 @@ //! pending reports. void StartProcessingPendingReports(); - //! \brief Helper that swaps out the InProcessHandler's |writer_| with an - //! alternate writer so DumpWithContext does not interfere with the - //! |writer_| created on startup. This is useful for -DumpWithoutCrash, - //! which may write to an alternate location. - class ScopedAlternateWriter { - public: - ScopedAlternateWriter(InProcessHandler* handler); - ~ScopedAlternateWriter(); - ScopedAlternateWriter(const ScopedAlternateWriter&) = delete; - ScopedAlternateWriter& operator=(const ScopedAlternateWriter&) = delete; - //! \brief Open's an alternate dump writer in the same directory as the - //! default InProcessHandler's dump writer, so the file will be - //! processed with -ProcessIntermediateDumps() - bool Open(); - - //! \brief Open's an alternate dump writer in the client provided |path|. - //! The file will only be processed by calling - //! ProcessIntermediateDump(path) - bool OpenAtPath(const base::FilePath& path); - - //! \brief The path of the alternate dump writer. - const base::FilePath& path() { return path_; } - - private: - InProcessHandler* handler_; - std::unique_ptr<IOSIntermediateDumpWriter> original_writer_; - base::FilePath path_; - }; + //! \brief Inject a callback into Mach handling. Intended to be used by + //! tests to trigger a reentrant exception. + void SetMachExceptionCallbackForTesting(void (*callback)()) { + mach_exception_callback_for_testing_ = callback; + } private: //! \brief Helper to start and end intermediate reports. @@ -170,34 +197,64 @@ IOSIntermediateDumpWriter::ScopedRootMap rootMap_; }; - std::unique_ptr<IOSIntermediateDumpWriter> GetWriter() { - return std::move(writer_); - } + //! \brief Helper to manage closing the intermediate dump writer and unlocking + //! the dump file (renaming the file) after the report is written. + class ScopedLockedWriter { + public: + ScopedLockedWriter(IOSIntermediateDumpWriter* writer, + const char* writer_path, + const char* writer_unlocked_path); - void SetWriter(std::unique_ptr<IOSIntermediateDumpWriter> writer) { - writer_ = std::move(writer); - } + //! \brief Close the writer_ and rename to the file with path without the + //! .locked extension. + ~ScopedLockedWriter(); - void SetOpenNewFileAfterReport(bool open_new_file_after_report) { - open_new_file_after_report_ = open_new_file_after_report; - } + ScopedLockedWriter(const ScopedLockedWriter&) = delete; + ScopedLockedWriter& operator=(const ScopedLockedWriter&) = delete; + IOSIntermediateDumpWriter* GetWriter() { return writer_; } + + private: + const char* writer_path_; + const char* writer_unlocked_path_; + IOSIntermediateDumpWriter* writer_; + }; + + //! \brief Writes a minidump to the Crashpad database from the + //! \a process_snapshot, and triggers the upload_thread_ if started. void SaveSnapshot(ProcessSnapshotIOSIntermediateDump& process_snapshot); - // Process a maximum of 20 pending intermediate dumps. Dumps named with our - // bundle id get first priority to prevent spamming. + //! \brief Process a maximum of 20 pending intermediate dumps. Dumps named + //! with our bundle id get first priority to prevent spamming. std::vector<base::FilePath> PendingFiles(); - bool OpenNewFile(); - void PostReportCleanup(); + //! \brief Lock access to the cached intermediate dump writer from + //! concurrent signal, Mach exception and uncaught NSExceptions so that + //! the first exception wins. If the same thread triggers another + //! reentrant exception, ignore it. If a different thread triggers a + //! concurrent exception, sleep indefinitely. + IOSIntermediateDumpWriter* GetCachedWriter(); + + //! \brief Open a new intermediate dump writer from \a writer_path. + std::unique_ptr<IOSIntermediateDumpWriter> CreateWriterWithPath( + const base::FilePath& writer_path); + + //! \brief Generates a new file path to be used by an intermediate dump + //! writer built from base_dir_,, bundle_identifier_and_seperator_, a new + //! UUID, with a .locked extension. + const base::FilePath NewLockedFilePath(); + + // Intended to be used by tests triggering a reentrant exception. Called + // in DumpExceptionFromMachException after aquiring the cached_writer_. + void (*mach_exception_callback_for_testing_)() = nullptr; bool upload_thread_started_ = false; - bool open_new_file_after_report_ = true; std::map<std::string, std::string> annotations_; base::FilePath base_dir_; - base::FilePath current_file_; - std::unique_ptr<IOSIntermediateDumpWriter> writer_; - std::unique_ptr<IOSIntermediateDumpWriter> alternate_mach_writer_; + std::string cached_writer_path_; + std::string cached_writer_unlocked_path_; + std::unique_ptr<IOSIntermediateDumpWriter> cached_writer_; + std::atomic<uint64_t> exception_thread_id_ = 0; std::unique_ptr<CrashReportUploadThread> upload_thread_; std::unique_ptr<PruneIntermediateDumpsAndCrashReportsThread> prune_thread_; std::unique_ptr<CrashReportDatabase> database_;
diff --git a/third_party/crashpad/crashpad/client/ios_handler/in_process_intermediate_dump_handler.cc b/third_party/crashpad/crashpad/client/ios_handler/in_process_intermediate_dump_handler.cc index e4d6223..88d5eb0 100644 --- a/third_party/crashpad/crashpad/client/ios_handler/in_process_intermediate_dump_handler.cc +++ b/third_party/crashpad/crashpad/client/ios_handler/in_process_intermediate_dump_handler.cc
@@ -647,7 +647,7 @@ IntermediateDumpKey::kSystemTime, &task_thread_times.system_time); } else { - CRASHPAD_RAW_LOG("task_info task_basic_info"); + CRASHPAD_RAW_LOG("task_info thread_times_info"); } if (!annotations.empty()) {
diff --git a/third_party/crashpad/crashpad/test/file.cc b/third_party/crashpad/crashpad/test/file.cc index a0ec470d..bcfb987 100644 --- a/third_party/crashpad/crashpad/test/file.cc +++ b/third_party/crashpad/crashpad/test/file.cc
@@ -17,10 +17,16 @@ #include <errno.h> #include <sys/stat.h> +#include "base/logging.h" +#include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "gtest/gtest.h" #include "test/errors.h" +#if BUILDFLAG(IS_WIN) +#include <windows.h> +#endif + namespace crashpad { namespace test { @@ -44,6 +50,24 @@ return true; } +bool RemoveFileIfExists(const base::FilePath& path) { +#if BUILDFLAG(IS_POSIX) + if (unlink(path.value().c_str()) != 0 && errno != ENOENT) { + PLOG(ERROR) << "unlink " << path.value(); + return false; + } +#elif BUILDFLAG(IS_WIN) + if (!DeleteFile(path.value().c_str()) && + GetLastError() != ERROR_FILE_NOT_FOUND) { + PLOG(ERROR) << "DeleteFile " << base::WideToUTF8(path.value()); + return false; + } +#else +#error "Not implemented" +#endif + return true; +} + FileOffset FileSize(const base::FilePath& path) { #if BUILDFLAG(IS_POSIX) struct stat st;
diff --git a/third_party/crashpad/crashpad/test/file.h b/third_party/crashpad/crashpad/test/file.h index 918cc39..451588a 100644 --- a/third_party/crashpad/crashpad/test/file.h +++ b/third_party/crashpad/crashpad/test/file.h
@@ -30,6 +30,12 @@ //! `false` with a Google Test failure added. bool FileExists(const base::FilePath& path); +//! \brief Removes a file if it exists, logging a message on failure. +//! +//! \param[in] path The path to the file to remove. +//! \return `true` on success. `false` on failure with a message logged. +bool RemoveFileIfExists(const base::FilePath& path); + //! \brief Determines the size of a file. //! //! \param[in] path The path of the file to check. The file must exist.
diff --git a/third_party/crashpad/crashpad/test/ios/crash_type_xctest.mm b/third_party/crashpad/crashpad/test/ios/crash_type_xctest.mm index 1022d29..45d96310 100644 --- a/third_party/crashpad/crashpad/test/ios/crash_type_xctest.mm +++ b/third_party/crashpad/crashpad/test/ios/crash_type_xctest.mm
@@ -103,6 +103,9 @@ NSNumber* report_exception; XCTAssertTrue([rootObject_ pendingReportException:&report_exception]); XCTAssertEqual(report_exception.unsignedIntValue, exception); + + NSString* stderrContents = [rootObject_ stderrContents]; + XCTAssertFalse([stderrContents containsString:@"allocator used in handler."]); } - (void)testEDO { @@ -299,4 +302,67 @@ isEqualToString:@"moocow"]); } +- (void)testDumpWithoutCrash { + [rootObject_ generateDumpWithoutCrash:10 threads:3]; + + // The app should not crash + XCTAssertTrue(app_.state == XCUIApplicationStateRunningForeground); + + XCTAssertEqual([rootObject_ pendingReportCount], 30); +} + +- (void)testSimultaneousCrash { + [rootObject_ crashConcurrentSignalAndMach]; + + // Confirm the app is not running. + XCTAssertTrue([app_ waitForState:XCUIApplicationStateNotRunning timeout:15]); + XCTAssertTrue(app_.state == XCUIApplicationStateNotRunning); + + [app_ launch]; + XCTAssertTrue(app_.state == XCUIApplicationStateRunningForeground); + rootObject_ = [EDOClientService rootObjectWithPort:12345]; + XCTAssertEqual([rootObject_ pendingReportCount], 1); +} + +- (void)testCrashInHandlerReentrant { + XCTAssertTrue(app_.state == XCUIApplicationStateRunningForeground); + rootObject_ = [EDOClientService rootObjectWithPort:12345]; + + [rootObject_ crashInHandlerReentrant]; + + // Confirm the app is not running. + XCTAssertTrue([app_ waitForState:XCUIApplicationStateNotRunning timeout:15]); + XCTAssertTrue(app_.state == XCUIApplicationStateNotRunning); + + [app_ launch]; + XCTAssertTrue(app_.state == XCUIApplicationStateRunningForeground); + rootObject_ = [EDOClientService rootObjectWithPort:12345]; + + XCTAssertEqual([rootObject_ pendingReportCount], 0); + + NSString* stderrContents = [rootObject_ stderrContents]; + NSString* errmsg = @"Cannot DumpExceptionFromSignal without writer"; + XCTAssertTrue([stderrContents containsString:errmsg]); +} + +- (void)testFailureWhenHandlerAllocates { + XCTAssertTrue(app_.state == XCUIApplicationStateRunningForeground); + rootObject_ = [EDOClientService rootObjectWithPort:12345]; + + [rootObject_ allocateWithForbiddenAllocators]; + + // Confirm the app is not running. + XCTAssertTrue([app_ waitForState:XCUIApplicationStateNotRunning timeout:15]); + XCTAssertTrue(app_.state == XCUIApplicationStateNotRunning); + + [app_ launch]; + XCTAssertTrue(app_.state == XCUIApplicationStateRunningForeground); + rootObject_ = [EDOClientService rootObjectWithPort:12345]; + + XCTAssertEqual([rootObject_ pendingReportCount], 0); + + NSString* stderrContents = [rootObject_ stderrContents]; + XCTAssertTrue([stderrContents containsString:@"allocator used in handler."]); +} + @end
diff --git a/third_party/crashpad/crashpad/test/ios/host/BUILD.gn b/third_party/crashpad/crashpad/test/ios/host/BUILD.gn index 77842a98..a5e04ee7 100644 --- a/third_party/crashpad/crashpad/test/ios/host/BUILD.gn +++ b/third_party/crashpad/crashpad/test/ios/host/BUILD.gn
@@ -35,6 +35,8 @@ "cptest_application_delegate.mm", "cptest_crash_view_controller.h", "cptest_crash_view_controller.mm", + "handler_forbidden_allocators.cc", + "handler_forbidden_allocators.h", "main.mm", ] configs += [ "../../..:crashpad_config" ] @@ -43,6 +45,7 @@ "../../../build:ios_enable_arc", "../../../client", "../../../snapshot", + "../../../test", "../../../third_party/edo", ] frameworks = [
diff --git a/third_party/crashpad/crashpad/test/ios/host/cptest_application_delegate.mm b/third_party/crashpad/crashpad/test/ios/host/cptest_application_delegate.mm index 212ab69..5604732c 100644 --- a/third_party/crashpad/crashpad/test/ios/host/cptest_application_delegate.mm +++ b/third_party/crashpad/crashpad/test/ios/host/cptest_application_delegate.mm
@@ -19,6 +19,7 @@ #include <mach-o/dyld_images.h> #include <mach-o/nlist.h> #include <signal.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> @@ -28,6 +29,7 @@ #import "Service/Sources/EDOHostNamingService.h" #import "Service/Sources/EDOHostService.h" #import "Service/Sources/NSObject+EDOValueObject.h" +#include "base/logging.h" #include "base/strings/sys_string_conversions.h" #include "client/annotation.h" #include "client/annotation_list.h" @@ -35,9 +37,14 @@ #include "client/crashpad_client.h" #include "client/crashpad_info.h" #include "client/simple_string_dictionary.h" +#include "client/simulate_crash.h" #include "snapshot/minidump/process_snapshot_minidump.h" +#include "test/file.h" #import "test/ios/host/cptest_crash_view_controller.h" #import "test/ios/host/cptest_shared_object.h" +#import "test/ios/host/handler_forbidden_allocators.h" +#include "util/file/filesystem.h" +#include "util/thread/thread.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -56,6 +63,14 @@ return database_dir.Append("crashpad"); } +base::FilePath GetStderrOutputFile() { + base::FilePath stderr_output([NSFileManager.defaultManager + URLsForDirectory:NSDocumentDirectory + inDomains:NSUserDomainMask] + .lastObject.path.UTF8String); + return stderr_output.Append("stderr_output.txt"); +} + std::unique_ptr<crashpad::CrashReportDatabase> GetDatabase() { base::FilePath database_dir = GetDatabaseDir(); std::unique_ptr<crashpad::CrashReportDatabase> database = @@ -99,6 +114,7 @@ @interface CPTestApplicationDelegate () - (void)processIntermediateDumps; +@property(copy, nonatomic) NSString* last_stderr_output; @end @implementation CPTestApplicationDelegate { @@ -120,6 +136,16 @@ {"plat", "macOS"}, {"crashpad", "no"}}; } + + NSString* path = + [NSString stringWithUTF8String:GetStderrOutputFile().value().c_str()]; + self.last_stderr_output = + [[NSString alloc] initWithContentsOfFile:path + encoding:NSUTF8StringEncoding + error:NULL]; + crashpad::test::RemoveFileIfExists(GetStderrOutputFile()); + CHECK(freopen(GetStderrOutputFile().value().c_str(), "a", stderr) != nullptr); + if (client_.StartCrashpadInProcessHandler( GetDatabaseDir(), "", annotations)) { client_.ProcessIntermediateDumps(); @@ -248,14 +274,17 @@ } - (void)crashKillAbort { + crashpad::test::ReplaceAllocatorsWithHandlerForbidden(); kill(getpid(), SIGABRT); } - (void)crashTrap { + crashpad::test::ReplaceAllocatorsWithHandlerForbidden(); __builtin_trap(); } - (void)crashAbort { + crashpad::test::ReplaceAllocatorsWithHandlerForbidden(); abort(); } @@ -265,7 +294,8 @@ } - (void)crashNSException { - // EDO has its own sinkhole, so dispatch this away. + // EDO has its own sinkhole which will suppress this attempt at an NSException + // crash, so dispatch this out of the sinkhole. dispatch_async(dispatch_get_main_queue(), ^{ NSError* error = [NSError errorWithDomain:@"com.crashpad.xcuitests" code:200 @@ -294,7 +324,8 @@ } - (void)crashCoreAutoLayoutSinkhole { - // EDO has its own sinkhole, so dispatch this away. + // EDO has its own sinkhole which will suppress this attempt at an NSException + // crash, so dispatch this out of the sinkhole. dispatch_async(dispatch_get_main_queue(), ^{ UIView* unattachedView = [[UIView alloc] init]; UIWindow* window = [UIApplication sharedApplication].windows[0]; @@ -354,4 +385,76 @@ abort(); } +class RaceThread : public crashpad::Thread { + public: + explicit RaceThread() : Thread() {} + + void SetCount(int count) { count_ = count; } + + private: + void ThreadMain() override { + for (int i = 0; i < count_; ++i) { + CRASHPAD_SIMULATE_CRASH(); + } + } + + int count_; +}; + +- (void)generateDumpWithoutCrash:(int)dump_count threads:(int)threads { + std::vector<RaceThread> race_threads(threads); + for (RaceThread& race_thread : race_threads) { + race_thread.SetCount(dump_count); + race_thread.Start(); + } + + for (RaceThread& race_thread : race_threads) { + race_thread.Join(); + } +} + +class CrashThread : public crashpad::Thread { + public: + explicit CrashThread(bool signal) : Thread(), signal_(signal) {} + + private: + void ThreadMain() override { + sleep(1); + if (signal_) { + abort(); + } else { + __builtin_trap(); + } + } + bool signal_; +}; + +- (void)crashConcurrentSignalAndMach { + CrashThread signal_thread(true); + CrashThread mach_thread(false); + signal_thread.Start(); + mach_thread.Start(); + signal_thread.Join(); + mach_thread.Join(); +} + +- (void)crashInHandlerReentrant { + crashpad::CrashpadClient client_; + client_.SetMachExceptionCallbackForTesting(abort); + + // Trigger a Mach exception. + [self crashTrap]; +} + +- (void)allocateWithForbiddenAllocators { + crashpad::test::ReplaceAllocatorsWithHandlerForbidden(); + (void)malloc(10); +} + +- (NSString*)stderrContents { + CPTestApplicationDelegate* delegate = + (CPTestApplicationDelegate*)UIApplication.sharedApplication.delegate; + return delegate.last_stderr_output; +} + @end
diff --git a/third_party/crashpad/crashpad/test/ios/host/cptest_shared_object.h b/third_party/crashpad/crashpad/test/ios/host/cptest_shared_object.h index 2fe36c5..0041c58 100644 --- a/third_party/crashpad/crashpad/test/ios/host/cptest_shared_object.h +++ b/third_party/crashpad/crashpad/test/ios/host/cptest_shared_object.h
@@ -55,13 +55,16 @@ // Triggers an EXC_BAD_ACCESS exception and crash. - (void)crashBadAccess; -// Triggers a crash with a call to kill(SIGABRT). +// Triggers a crash with a call to kill(SIGABRT). This crash runs with +// ReplaceAllocatorsWithHandlerForbidden. - (void)crashKillAbort; -// Trigger a crash with a __builtin_trap. +// Trigger a crash with a __builtin_trap. This crash runs with +// ReplaceAllocatorsWithHandlerForbidden. - (void)crashTrap; -// Trigger a crash with an abort(). +// Trigger a crash with an abort(). This crash runs with +// ReplaceAllocatorsWithHandlerForbidden. - (void)crashAbort; // Trigger a crash with an uncaught exception. @@ -91,6 +94,24 @@ // Trigger a crash after writing various annotations. - (void)crashWithAnnotations; +// Triggers a DumpWithoutCrash |dump_count| times in each of |threads| threads. +- (void)generateDumpWithoutCrash:(int)dump_count threads:(int)threads; + +// Triggers a simulataneous Mach exception and signal in different threads. +- (void)crashConcurrentSignalAndMach; + +// Triggers a SIGABRT signal while handling an NSException to test reentrant +// exceptions. +- (void)crashInHandlerReentrant; + +// Runs with ReplaceAllocatorsWithHandlerForbidden and allocates memory, testing +// that the handler forbidden allocator works. +- (void)allocateWithForbiddenAllocators; + +// Return the contents of the stderr output from the previous run of the host +// application. +- (NSString*)stderrContents; + @end #endif // CRASHPAD_TEST_IOS_HOST_SHARED_OBJECT_H_
diff --git a/third_party/crashpad/crashpad/test/ios/host/handler_forbidden_allocators.cc b/third_party/crashpad/crashpad/test/ios/host/handler_forbidden_allocators.cc new file mode 100644 index 0000000..dbb499a --- /dev/null +++ b/third_party/crashpad/crashpad/test/ios/host/handler_forbidden_allocators.cc
@@ -0,0 +1,295 @@ +// Copyright 2022 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "test/ios/host/handler_forbidden_allocators.h" + +#include <CoreFoundation/CoreFoundation.h> +#include <malloc/malloc.h> +#include <pthread.h> +#include <limits> + +#include "base/mac/mach_logging.h" +#include "client/crashpad_client.h" +#include "util/ios/raw_logging.h" + +namespace crashpad { +namespace test { + +namespace { + +uint64_t g_main_thread = 0; +uint64_t g_mach_exception_thread = 0; +malloc_zone_t g_old_zone; + +bool is_handler_thread() { + uint64_t thread_self; + pthread_threadid_np(pthread_self(), &thread_self); + return (thread_self == g_main_thread || + thread_self == g_mach_exception_thread); +} + +void* handler_forbidden_malloc(struct _malloc_zone_t* zone, size_t size) { + if (is_handler_thread()) { + CRASHPAD_RAW_LOG("handler_forbidden_malloc allocator used in handler."); + exit(EXIT_FAILURE); + } + return g_old_zone.malloc(zone, size); +} + +void* handler_forbidden_calloc(struct _malloc_zone_t* zone, + size_t num_items, + size_t size) { + if (is_handler_thread()) { + CRASHPAD_RAW_LOG("handler_forbidden_calloc allocator used in handler."); + exit(EXIT_FAILURE); + } + return g_old_zone.calloc(zone, num_items, size); +} + +void* handler_forbidden_valloc(struct _malloc_zone_t* zone, size_t size) { + if (is_handler_thread()) { + CRASHPAD_RAW_LOG("handler_forbidden_valloc allocator used in handler."); + exit(EXIT_FAILURE); + } + return g_old_zone.valloc(zone, size); +} + +void handler_forbidden_free(struct _malloc_zone_t* zone, void* ptr) { + if (is_handler_thread()) { + CRASHPAD_RAW_LOG("handler_forbidden_free allocator used in handler."); + exit(EXIT_FAILURE); + } + g_old_zone.free(zone, ptr); +} + +void* handler_forbidden_realloc(struct _malloc_zone_t* zone, + void* ptr, + size_t size) { + if (is_handler_thread()) { + CRASHPAD_RAW_LOG("handler_forbidden_realloc allocator used in handler."); + exit(EXIT_FAILURE); + } + return g_old_zone.realloc(zone, ptr, size); +} + +void handler_forbidden_destroy(struct _malloc_zone_t* zone) { + if (is_handler_thread()) { + CRASHPAD_RAW_LOG("handler_forbidden_destroy allocator used in handler."); + exit(EXIT_FAILURE); + } + g_old_zone.destroy(zone); +} + +void* handler_forbidden_memalign(struct _malloc_zone_t* zone, + size_t alignment, + size_t size) { + if (is_handler_thread()) { + CRASHPAD_RAW_LOG("handler_forbidden_memalign allocator used in handler."); + exit(EXIT_FAILURE); + } + return g_old_zone.memalign(zone, alignment, size); +} + +unsigned handler_forbidden_batch_malloc(struct _malloc_zone_t* zone, + size_t size, + void** results, + unsigned num_requested) { + if (is_handler_thread()) { + CRASHPAD_RAW_LOG( + "handler_forbidden_batch_malloc allocator used in handler."); + exit(EXIT_FAILURE); + } + return g_old_zone.batch_malloc(zone, size, results, num_requested); +} + +void handler_forbidden_batch_free(struct _malloc_zone_t* zone, + void** to_be_freed, + unsigned num_to_be_freed) { + if (is_handler_thread()) { + CRASHPAD_RAW_LOG("handler_forbidden_batch_free allocator used in handler."); + exit(EXIT_FAILURE); + } + g_old_zone.batch_free(zone, to_be_freed, num_to_be_freed); +} + +void handler_forbidden_free_definite_size(struct _malloc_zone_t* zone, + void* ptr, + size_t size) { + if (is_handler_thread()) { + CRASHPAD_RAW_LOG( + "handler_forbidden_free_definite_size allocator used in handler."); + exit(EXIT_FAILURE); + } + g_old_zone.free_definite_size(zone, ptr, size); +} + +size_t handler_forbidden_pressure_relief(struct _malloc_zone_t* zone, + size_t goal) { + if (is_handler_thread()) { + CRASHPAD_RAW_LOG( + "handler_forbidden_pressure_relief allocator used in handler."); + exit(EXIT_FAILURE); + } + return g_old_zone.pressure_relief(zone, goal); +} + +boolean_t handler_forbidden_claimed_address(struct _malloc_zone_t* zone, + void* ptr) { + if (is_handler_thread()) { + CRASHPAD_RAW_LOG( + "handler_forbidden_claimed_address allocator used in handler."); + exit(EXIT_FAILURE); + } + return g_old_zone.claimed_address(zone, ptr); +} + +size_t handler_forbidden_size(struct _malloc_zone_t* zone, const void* ptr) { + if (is_handler_thread()) { + CRASHPAD_RAW_LOG("handler_forbidden_size allocator used in handler."); + exit(EXIT_FAILURE); + } + return g_old_zone.size(zone, ptr); +} + +bool DeprotectMallocZone(malloc_zone_t* default_zone, + vm_address_t* reprotection_start, + vm_size_t* reprotection_length, + vm_prot_t* reprotection_value) { + mach_port_t unused; + *reprotection_start = reinterpret_cast<vm_address_t>(default_zone); + struct vm_region_basic_info_64 info; + mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64; + kern_return_t result = vm_region_64(mach_task_self(), + reprotection_start, + reprotection_length, + VM_REGION_BASIC_INFO_64, + reinterpret_cast<vm_region_info_t>(&info), + &count, + &unused); + if (result != KERN_SUCCESS) { + MACH_LOG(ERROR, result) << "vm_region_64"; + return false; + } + + // The kernel always returns a null object for VM_REGION_BASIC_INFO_64, but + // balance it with a deallocate in case this ever changes. See + // the VM_REGION_BASIC_INFO_64 case in vm_map_region() in 10.15's + // https://opensource.apple.com/source/xnu/xnu-6153.11.26/osfmk/vm/vm_map.c . + mach_port_deallocate(mach_task_self(), unused); + + if (!(info.max_protection & VM_PROT_WRITE)) { + LOG(ERROR) << "Invalid max_protection " << info.max_protection; + return false; + } + + // Does the region fully enclose the zone pointers? Possibly unwarranted + // simplification used: using the size of a full version 10 malloc zone rather + // than the actual smaller size if the passed-in zone is not version 10. + DCHECK_LE(*reprotection_start, reinterpret_cast<vm_address_t>(default_zone)); + vm_size_t zone_offset = reinterpret_cast<vm_address_t>(default_zone) - + reinterpret_cast<vm_address_t>(*reprotection_start); + DCHECK_LE(zone_offset + sizeof(malloc_zone_t), *reprotection_length); + + if (info.protection & VM_PROT_WRITE) { + // No change needed; the zone is already writable. + *reprotection_start = 0; + *reprotection_length = 0; + *reprotection_value = VM_PROT_NONE; + } else { + *reprotection_value = info.protection; + result = vm_protect(mach_task_self(), + *reprotection_start, + *reprotection_length, + false, + info.protection | VM_PROT_WRITE); + if (result != KERN_SUCCESS) { + MACH_LOG(ERROR, result) << "vm_protect"; + return false; + } + } + return true; +} + +void ReplaceZoneFunctions(malloc_zone_t* zone, const malloc_zone_t* functions) { + // Remove protection. + vm_address_t reprotection_start = 0; + vm_size_t reprotection_length = 0; + vm_prot_t reprotection_value = VM_PROT_NONE; + bool success = DeprotectMallocZone( + zone, &reprotection_start, &reprotection_length, &reprotection_value); + if (!success) { + return; + } + + zone->size = functions->size; + zone->malloc = functions->malloc; + zone->calloc = functions->calloc; + zone->valloc = functions->valloc; + zone->free = functions->free; + zone->realloc = functions->realloc; + zone->destroy = functions->destroy; + zone->batch_malloc = functions->batch_malloc; + zone->batch_free = functions->batch_free; + zone->introspect = functions->introspect; + zone->memalign = functions->memalign; + zone->free_definite_size = functions->free_definite_size; + zone->pressure_relief = functions->pressure_relief; + zone->claimed_address = functions->claimed_address; + + // Restore protection if it was active. + if (reprotection_start) { + kern_return_t result = vm_protect(mach_task_self(), + reprotection_start, + reprotection_length, + false, + reprotection_value); + if (result != KERN_SUCCESS) { + MACH_LOG(ERROR, result) << "vm_protect"; + return; + } + } +} + +} // namespace + +void ReplaceAllocatorsWithHandlerForbidden() { + pthread_threadid_np(pthread_self(), &g_main_thread); + + CrashpadClient crashpad_client; + g_mach_exception_thread = crashpad_client.GetThreadIdForTesting(); + + malloc_zone_t* default_zone = malloc_default_zone(); + memcpy(&g_old_zone, default_zone, sizeof(g_old_zone)); + malloc_zone_t new_functions = {}; + new_functions.size = handler_forbidden_size; + new_functions.malloc = handler_forbidden_malloc; + new_functions.calloc = handler_forbidden_calloc; + new_functions.valloc = handler_forbidden_valloc; + new_functions.free = handler_forbidden_free; + new_functions.realloc = handler_forbidden_realloc; + new_functions.destroy = handler_forbidden_destroy; + new_functions.batch_malloc = handler_forbidden_batch_malloc; + new_functions.batch_free = handler_forbidden_batch_free; + new_functions.memalign = handler_forbidden_memalign; + new_functions.free_definite_size = handler_forbidden_free_definite_size; + new_functions.pressure_relief = handler_forbidden_pressure_relief; + new_functions.claimed_address = handler_forbidden_claimed_address; + ReplaceZoneFunctions(default_zone, &new_functions); + + malloc_zone_t* purgeable_zone = malloc_default_purgeable_zone(); + ReplaceZoneFunctions(purgeable_zone, &new_functions); +} + +} // namespace test +} // namespace crashpad
diff --git a/third_party/crashpad/crashpad/test/ios/host/handler_forbidden_allocators.h b/third_party/crashpad/crashpad/test/ios/host/handler_forbidden_allocators.h new file mode 100644 index 0000000..c32a092 --- /dev/null +++ b/third_party/crashpad/crashpad/test/ios/host/handler_forbidden_allocators.h
@@ -0,0 +1,31 @@ +// Copyright 2022 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef CRASHPAD_TEST_IOS_HANDLER_FORBIDDEN_ALLOCATIONS_H_ +#define CRASHPAD_TEST_IOS_HANDLER_FORBIDDEN_ALLOCATIONS_H_ + +namespace crashpad { +namespace test { + +// Override malloc_default_zone and malloc_default_purgeable_zone with functions +// that immediately exit if called from the same thread that this helper is +// called from or from the Crashpad Mach exception handler thread indicated by +// GetThreadIdForTesting. This is used to ensure the allocator is not used by +// the Crashpad InProcessHandler. +void ReplaceAllocatorsWithHandlerForbidden(); + +} // namespace test +} // namespace crashpad + +#endif // CRASHPAD_TEST_IOS_HANDLER_FORBIDDEN_ALLOCATIONS_H_
diff --git a/third_party/crashpad/crashpad/util/thread/thread.h b/third_party/crashpad/crashpad/util/thread/thread.h index 25fccb8..6f93ed09 100644 --- a/third_party/crashpad/crashpad/util/thread/thread.h +++ b/third_party/crashpad/crashpad/util/thread/thread.h
@@ -19,10 +19,13 @@ #if BUILDFLAG(IS_POSIX) #include <pthread.h> +#include <stdint.h> #elif BUILDFLAG(IS_WIN) #include <windows.h> #endif // BUILDFLAG(IS_POSIX) +#include "build/build_config.h" + namespace crashpad { //! \brief Basic thread abstraction. Users should derive from this @@ -44,6 +47,11 @@ //! Must paired with a call to Start(). void Join(); +#if BUILDFLAG(IS_APPLE) + //! \brief Returns the thread id of the Thread pthread_t. + uint64_t GetThreadIdForTesting(); +#endif // BUILDFLAG(IS_APPLE) + private: //! \brief The thread entry point to be implemented by the subclass. virtual void ThreadMain() = 0;
diff --git a/third_party/crashpad/crashpad/util/thread/thread_posix.cc b/third_party/crashpad/crashpad/util/thread/thread_posix.cc index fe50050c7..8e00c21 100644 --- a/third_party/crashpad/crashpad/util/thread/thread_posix.cc +++ b/third_party/crashpad/crashpad/util/thread/thread_posix.cc
@@ -19,6 +19,7 @@ #include <ostream> #include "base/check.h" +#include "build/build_config.h" namespace crashpad { @@ -35,6 +36,15 @@ platform_thread_ = 0; } +#if BUILDFLAG(IS_APPLE) +uint64_t Thread::GetThreadIdForTesting() { + uint64_t thread_self; + errno = pthread_threadid_np(pthread_self(), &thread_self); + PCHECK(errno == 0) << "pthread_threadid_np"; + return thread_self; +} +#endif // BUILDFLAG(IS_APPLE) + // static void* Thread::ThreadEntryThunk(void* argument) { Thread* self = reinterpret_cast<Thread*>(argument);
diff --git a/third_party/minigbm/OWNERS b/third_party/minigbm/OWNERS index 6223bd5..3269f17 100644 --- a/third_party/minigbm/OWNERS +++ b/third_party/minigbm/OWNERS
@@ -1,5 +1,4 @@ marcheu@chromium.org spang@chromium.org -gurchetansingh@chromium.org servolk@chromium.org dnicoara@chromium.org
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py index bd2cf234..d22944d8 100755 --- a/tools/clang/scripts/update.py +++ b/tools/clang/scripts/update.py
@@ -35,7 +35,7 @@ # https://chromium.googlesource.com/chromium/src/+/main/docs/updating_clang.md # Reverting problematic clang rolls is safe, though. # This is the output of `git describe` and is usable as a commit-ish. -CLANG_REVISION = 'llvmorg-15-init-3540-g85c53c70' +CLANG_REVISION = 'llvmorg-15-init-3677-g8133778d' CLANG_SUB_REVISION = 1 PACKAGE_VERSION = '%s-%s' % (CLANG_REVISION, CLANG_SUB_REVISION)
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl index 6d19da7..bc7017e3 100644 --- a/tools/mb/mb_config.pyl +++ b/tools/mb/mb_config.pyl
@@ -132,8 +132,8 @@ }, 'chromium.angle': { - 'android-angle-arm64-builder': 'angle_deqp_android_release_trybot_dcheck_always_on_arm64', - 'android-angle-chromium-arm64-builder': 'gpu_tests_android_release_bot_dcheck_always_on_arm64_fastbuild', + 'android-angle-arm64-builder': 'angle_deqp_android_release_trybot_dcheck_always_on_arm64_reclient', + 'android-angle-chromium-arm64-builder': 'gpu_tests_android_release_bot_dcheck_always_on_arm64_fastbuild_reclient', 'fuchsia-angle-builder': 'angle_deqp_release_bot_dcheck_always_on_fuchsia', 'ios-angle-builder': 'angle_deqp_release_bot_dcheck_always_on_ios', 'linux-angle-builder': 'angle_deqp_release_trybot', @@ -241,9 +241,9 @@ 'ASAN Debug': 'asan_lsan_debug_bot_reclient', 'ASAN Release Media': 'asan_lsan_fuzzer_v8_heap_chromeos_codecs_release_bot_reclient', 'ASAN Release': 'asan_lsan_fuzzer_v8_heap_release_bot_reclient', - 'ASan Debug (32-bit x86 with V8-ARM)': 'asan_v8_heap_debug_bot_hybrid', - 'ASan Release (32-bit x86 with V8-ARM)': 'asan_fuzzer_v8_heap_release_bot_hybrid', - 'ASan Release Media (32-bit x86 with V8-ARM)': 'asan_fuzzer_v8_heap_chromeos_codecs_release_bot_hybrid', + 'ASan Debug (32-bit x86 with V8-ARM)': 'asan_v8_heap_debug_bot_hybrid_reclient', + 'ASan Release (32-bit x86 with V8-ARM)': 'asan_fuzzer_v8_heap_release_bot_hybrid_reclient', + 'ASan Release Media (32-bit x86 with V8-ARM)': 'asan_fuzzer_v8_heap_chromeos_codecs_release_bot_hybrid_reclient', 'Afl Upload Linux ASan': 'afl_asan_shared_release_bot', 'ChromiumOS ASAN Release': 'chromeos_asan_lsan_fuzzer_v8_heap_release_bot', 'Libfuzzer Upload Chrome OS ASan': 'libfuzzer_chromeos_asan_release_bot', @@ -1714,9 +1714,9 @@ 'angle_deqp_tests', 'shared_release_trybot', 'x86', ], - 'angle_deqp_android_release_trybot_dcheck_always_on_arm64': [ + 'angle_deqp_android_release_trybot_dcheck_always_on_arm64_reclient': [ 'angle_deqp_tests', 'android_without_codecs', - 'shared_release_bot_dcheck_always_on', 'arm64', + 'shared_release_bot_dcheck_always_on_reclient', 'arm64', ], 'angle_deqp_release_bot_dcheck_always_on_fuchsia': [ @@ -1767,20 +1767,20 @@ 'asan', 'disable_nacl', 'fuzzer', 'v8_heap', 'release_bot', ], - 'asan_fuzzer_v8_heap_chromeos_codecs_release_bot_hybrid': [ - 'asan', 'fuzzer', 'v8_heap', 'chromeos_codecs', 'release_bot', 'hybrid', + 'asan_fuzzer_v8_heap_chromeos_codecs_release_bot_hybrid_reclient': [ + 'asan', 'fuzzer', 'v8_heap', 'chromeos_codecs', 'release_bot_reclient', 'hybrid', ], - 'asan_fuzzer_v8_heap_release_bot_hybrid': [ - 'asan', 'fuzzer', 'v8_heap', 'release_bot', 'hybrid', + 'asan_fuzzer_v8_heap_release_bot_hybrid_reclient': [ + 'asan', 'fuzzer', 'v8_heap', 'release_bot_reclient', 'hybrid', ], 'asan_lsan_bot_fuchsia': [ 'asan', 'lsan', 'release_bot', 'fuchsia', ], - 'asan_v8_heap_debug_bot_hybrid': [ - 'asan', 'v8_heap', 'debug_bot', 'hybrid', + 'asan_v8_heap_debug_bot_hybrid_reclient': [ + 'asan', 'v8_heap', 'debug_bot_reclient', 'hybrid', ], 'asan_minimal_symbols_disable_nacl_release_bot_dcheck_always_on': [ @@ -2410,11 +2410,6 @@ 'gpu_tests', 'android', 'release_trybot_minimal_symbols_reclient', 'arm64', 'static_angle', ], - 'gpu_tests_android_release_bot_dcheck_always_on_arm64_fastbuild': [ - 'gpu_tests', 'android', 'release_trybot_minimal_symbols', 'arm64', 'static_angle', - 'android_fastbuild', - ], - 'gpu_tests_android_release_bot_dcheck_always_on_arm64_fastbuild_reclient': [ 'gpu_tests', 'android', 'release_trybot_minimal_symbols_reclient', 'arm64', 'static_angle', 'android_fastbuild',
diff --git a/tools/mb/mb_config_expectations/chromium.angle.json b/tools/mb/mb_config_expectations/chromium.angle.json index e54ac68..e9d52b1 100644 --- a/tools/mb/mb_config_expectations/chromium.angle.json +++ b/tools/mb/mb_config_expectations/chromium.angle.json
@@ -8,7 +8,8 @@ "symbol_level": 1, "target_cpu": "arm64", "target_os": "android", - "use_goma": true + "use_rbe": true, + "use_remoteexec": true } }, "android-angle-chromium-arm64-builder": { @@ -24,7 +25,8 @@ "target_cpu": "arm64", "target_os": "android", "use_errorprone_java_compiler": false, - "use_goma": true, + "use_rbe": true, + "use_remoteexec": true, "use_static_angle": true } },
diff --git a/tools/mb/mb_config_expectations/chromium.fuzz.json b/tools/mb/mb_config_expectations/chromium.fuzz.json index aaac8b4..4c025a8 100644 --- a/tools/mb/mb_config_expectations/chromium.fuzz.json +++ b/tools/mb/mb_config_expectations/chromium.fuzz.json
@@ -45,7 +45,8 @@ "is_debug": true, "symbol_level": 1, "target_cpu": "x86", - "use_goma": true, + "use_rbe": true, + "use_remoteexec": true, "v8_enable_verify_heap": true, "v8_target_cpu": "arm" } @@ -59,7 +60,8 @@ "is_component_build": false, "is_debug": false, "target_cpu": "x86", - "use_goma": true, + "use_rbe": true, + "use_remoteexec": true, "v8_enable_verify_heap": true, "v8_target_cpu": "arm" } @@ -75,7 +77,8 @@ "is_debug": false, "proprietary_codecs": true, "target_cpu": "x86", - "use_goma": true, + "use_rbe": true, + "use_remoteexec": true, "v8_enable_verify_heap": true, "v8_target_cpu": "arm" }
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 0632d00..afd0718 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -6154,6 +6154,12 @@ <int value="3" label="Ignored"/> </enum> +<enum name="AutofillCreditCardMessageDialogPrompt"> + <int value="0" label="Accepted"/> + <int value="1" label="Denied"/> + <int value="2" label="Ignored"/> +</enum> + <enum name="AutofillCreditCardOfferSelection"> <int value="0" label="Selected card without offer"/> <int value="1" label="Selected card with offer"/> @@ -28829,6 +28835,7 @@ <int value="963" label="OptimizationGuideFetchingEnabled"/> <int value="964" label="WebAuthnFactors"/> <int value="965" label="WebAuthenticationRemoteProxiedRequestsAllowed"/> + <int value="966" label="WebSQLAccess"/> </enum> <enum name="EnterprisePolicyDeviceIdValidity"> @@ -50440,6 +50447,7 @@ <int value="11" label="Timeout"/> <int value="12" label="BlockList"/> <int value="13" label="NoRemoteConnection"/> + <int value="14" label="NotGenerated"/> </enum> <enum name="LinkGenerationSharedStatus"> @@ -52479,6 +52487,7 @@ <int value="-1460561942" label="SystemEmojiPicker:disabled"/> <int value="-1460462432" label="disable-media-source"/> <int value="-1459907288" label="DesksTemplates:enabled"/> + <int value="-1459246132" label="kWebSQLAccess:disabled"/> <int value="-1458056084" label="SyncUndecryptablePasswordsLinux:enabled"/> <int value="-1457775295" label="PasswordSearchMobile:disabled"/> <int value="-1456789591" label="MediaFoundationVideoCapture:enabled"/> @@ -52744,6 +52753,7 @@ <int value="-1288130734" label="OpenVR:disabled"/> <int value="-1287511172" label="OmniboxUIExperimentHideSteadyStateUrlSchemeAndSubdomains:disabled"/> + <int value="-1287060518" label="web-sql-access"/> <int value="-1286038936" label="AutofillEnableCardNicknameManagement:enabled"/> <int value="-1285790931" label="FencedFrames:disabled"/> @@ -52909,6 +52919,7 @@ <int value="-1176748003" label="FramebustingNeedsSameOriginOrUserGesture:disabled"/> <int value="-1176493523" label="enable-md-extensions"/> + <int value="-1175552430" label="WebViewNewInvalidateHeuristic:enabled"/> <int value="-1174292609" label="SystemProxyForSystemServices:disabled"/> <int value="-1174267639" label="ClientLoFi:disabled"/> <int value="-1173823468" label="FullUserAgent:enabled"/> @@ -54430,6 +54441,7 @@ <int value="-100702864" label="PageInfoAboutThisSite:disabled"/> <int value="-100148609" label="EvDetailsInPageInfo:disabled"/> <int value="-99781021" label="disable-roboto-font-ui"/> + <int value="-97599565" label="WebViewNewInvalidateHeuristic:disabled"/> <int value="-97145978" label="DesktopPWAsStayInWindow:enabled"/> <int value="-94335249" label="UseAAudioDriver:enabled"/> <int value="-93619449" label="video-tutorials-instant-fetch"/> @@ -56686,6 +56698,7 @@ <int value="1467322206" label="AssistAutoCorrect:enabled"/> <int value="1467583815" label="AVIF:disabled"/> <int value="1469407485" label="disable-accelerated-2d-canvas"/> + <int value="1471169381" label="kWebSQLAccess:enabled"/> <int value="1472938299" label="WellKnownChangePassword:disabled"/> <int value="1473379096" label="NearbySharingReceiveWifiCredentials:disabled"/> <int value="1473838479" label="EnableVirtualKeyboardMdUi:disabled"/> @@ -87002,6 +87015,13 @@ <int value="2" label="No conflict, same global and unique id pair"/> </enum> +<enum name="SyncIncomingInvalidationStatus"> + <summary>Possible outcomes of handling incoming sync invalidations.</summary> + <int value="0" label="Success"/> + <int value="1" label="Failed to parse payload"/> + <int value="2" label="Contains only unknown data types"/> +</enum> + <enum name="SyncInitialState"> <int value="0" label="Can attempt to start"/> <int value="1" label="No signed in user"/>
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml index 4a66271c..c61106df 100644 --- a/tools/metrics/histograms/metadata/ash/histograms.xml +++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -1130,6 +1130,39 @@ variants="ContextualNudgesCategories"/> </histogram> +<histogram name="Ash.DarkTheme.Settings.IsDarkModeEnabled" enum="Boolean" + expires_after="2023-03-01"> + <owner>minch@chromium.org</owner> + <owner>changmar@chromium.org</owner> + <summary> + Emitted true when the user switched to dark mode through (Dark theme) page + inside settings. Emitted false if the user switched to light mode in this + case. ChromeOS only. + </summary> +</histogram> + +<histogram name="Ash.DarkTheme.Settings.IsThemed" enum="Boolean" + expires_after="2023-03-01"> + <owner>minch@chromium.org</owner> + <owner>changmar@chromium.org</owner> + <summary> + Emitted true if the user checked (Based on your wallpaper) radio button + inside (Dark theme) page of the settings. Emitted false if the user checked + (Neutral) radio button inside the page. ChromeOS only. + </summary> +</histogram> + +<histogram name="Ash.DarkTheme.SystemTray.IsDarkModeEnabled" enum="Boolean" + expires_after="2023-03-01"> + <owner>minch@chromium.org</owner> + <owner>changmar@chromium.org</owner> + <summary> + Emitted true when the user switched to dark mode through toggling the (Dark + theme) feature pod button inside system tray menu. Emitted false if the user + switched to light mode through toggling this button. ChromeOS only. + </summary> +</histogram> + <histogram name="Ash.Desks.AnimationSmoothness.DeskActivation" units="%" expires_after="2022-04-17"> <owner>afakhry@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/autofill/histograms.xml b/tools/metrics/histograms/metadata/autofill/histograms.xml index e152ac9..37244aa 100644 --- a/tools/metrics/histograms/metadata/autofill/histograms.xml +++ b/tools/metrics/histograms/metadata/autofill/histograms.xml
@@ -814,6 +814,32 @@ </token> </histogram> +<histogram + name="Autofill.CreditCardMessage.DialogPrompt{SaveSituation}{DialogInteraction}" + enum="AutofillCreditCardMessageDialogPrompt" expires_after="M110"> + <owner>lazzzis@google.com</owner> + <owner>jsaul@google.com</owner> + <owner>chrome-autofill-alerts@google.com</owner> + <summary> + The relative frequency with which users accept, deny, or ignore the Autofill + credit card message prompt when card is saved to server and users see the + dialog prompt followed by the Message UI. Message prompt is an alternative + UI to info bar prompt. + </summary> + <token key="SaveSituation"> + <variant name=".ConfirmInfo" summary="confirm card info"/> + <variant name=".RequestingCardholderName" + summary="explicitly requesting cardholder name"/> + <variant name=".RequestingExpirationDate" + summary="explicitly requesting expiration date"/> + </token> + <token key="DialogInteraction"> + <variant name="" summary="aggregated across all situations"/> + <variant name=".DidClickLinks" + summary="user clicked on links in the dialog"/> + </token> +</histogram> + <histogram name="Autofill.CreditCardMessage.{SaveDestination}{SaveSituation}" enum="AutofillCreditCardMessage" expires_after="M110"> <owner>lazzzis@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/cryptohome/histograms.xml b/tools/metrics/histograms/metadata/cryptohome/histograms.xml index 9e2f0884..f1d9105 100644 --- a/tools/metrics/histograms/metadata/cryptohome/histograms.xml +++ b/tools/metrics/histograms/metadata/cryptohome/histograms.xml
@@ -195,7 +195,8 @@ </histogram> <histogram name="Cryptohome.DiskCleanupProgress" - enum="CryptohomeDiskCleanupProgress" expires_after="2022-04-03"> + enum="CryptohomeDiskCleanupProgress" expires_after="2023-02-01"> + <owner>vsavu@google.com</owner> <owner>dlunev@chromium.org</owner> <owner>sarthakkukreti@chromium.org</owner> <summary> @@ -207,7 +208,7 @@ </histogram> <histogram name="Cryptohome.DiskCleanupResult" - enum="CryptohomeDiskCleanupResult" expires_after="2022-04-17"> + enum="CryptohomeDiskCleanupResult" expires_after="2023-02-01"> <owner>vsavu@google.com</owner> <owner>dlunev@chromium.org</owner> <summary>Records the result of triggering disk cleanup.</summary> @@ -221,7 +222,7 @@ </histogram> <histogram name="Cryptohome.FreedCacheVaultDiskSpaceInMb" units="MB" - expires_after="2022-06-01"> + expires_after="2023-02-01"> <owner>vsavu@google.com</owner> <owner>weifangsun@chromium.org</owner> <summary> @@ -232,7 +233,7 @@ </histogram> <histogram name="Cryptohome.FreeDiskSpaceTotalFreedInMb" units="MiB" - expires_after="2022-07-13"> + expires_after="2023-02-01"> <owner>vsavu@chromium.org</owner> <owner>dlunev@chromium.org</owner> <summary> @@ -243,7 +244,8 @@ </histogram> <histogram name="Cryptohome.FreeDiskSpaceTotalTime2" units="ms" - expires_after="2022-07-13"> + expires_after="2023-02-01"> + <owner>vsavu@chromium.org</owner> <owner>dlunev@chromium.org</owner> <owner>sarthakkukreti@chromium.org</owner> <summary> @@ -255,7 +257,7 @@ </histogram> <histogram name="Cryptohome.GCache.FreedDiskSpaceInMb" units="MB" - expires_after="2022-07-13"> + expires_after="2023-02-01"> <owner>dlunev@chromium.org</owner> <owner>sarthakkukreti@chromium.org</owner> <summary> @@ -466,7 +468,7 @@ </histogram> <histogram name="Cryptohome.TimeBetweenFreeDiskSpace" units="s" - expires_after="2022-05-01"> + expires_after="2023-02-01"> <owner>vsavu@google.com</owner> <owner>dlunev@chromium.org</owner> <owner>sarthakkukreti@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/media/histograms.xml b/tools/metrics/histograms/metadata/media/histograms.xml index 0e18a33..06a7763 100644 --- a/tools/metrics/histograms/metadata/media/histograms.xml +++ b/tools/metrics/histograms/metadata/media/histograms.xml
@@ -294,7 +294,7 @@ <histogram name="Media.Audio.Capture.Mac.MicSystemPermission.FixedTime.SinceFirstFailure" - units="ms" expires_after="2020-03-01"> + units="ms" expires_after="2023-03-01"> <owner>grunell@chromium.org</owner> <owner>engedy@chromium.org</owner> <owner>hkamila@chromium.org</owner> @@ -302,12 +302,14 @@ The time from the first microphone access failure due to blocked system permission before the last browser restart to startup after browser restart. Logged once at browser startup if the system permission then is allowed. + Warning: this histogram was expired from 2020-03-01 to 2022-03-09; data may + be missing. </summary> </histogram> <histogram name="Media.Audio.Capture.Mac.MicSystemPermission.FixedTime.SinceLastFailure" - units="ms" expires_after="2020-03-01"> + units="ms" expires_after="2023-03-01"> <owner>grunell@chromium.org</owner> <owner>engedy@chromium.org</owner> <owner>hkamila@chromium.org</owner> @@ -315,11 +317,13 @@ The time from the last microphone access failure due to blocked system permission before the last browser restart to startup after browser restart. Logged once at browser startup if the system permission then is allowed. + Warning: this histogram was expired from 2020-03-01 to 2022-03-09; data may + be missing. </summary> </histogram> <histogram name="Media.Audio.Capture.Mac.MicSystemPermission.Startup" - enum="SystemMediaCapturePermission" expires_after="2020-03-01"> + enum="SystemMediaCapturePermission" expires_after="2023-03-01"> <owner>grunell@chromium.org</owner> <owner>engedy@chromium.org</owner> <owner>hkamila@chromium.org</owner> @@ -327,12 +331,14 @@ The Mac system permission state for microphone. Logged once at browser startup. For more information on the values, see https://developer.apple.com/documentation/avfoundation/avauthorizationstatus. + Warning: this histogram was expired from 2020-03-01 to 2022-03-09; data may + be missing. </summary> </histogram> <histogram name="Media.Audio.Capture.Mac.MicSystemPermission.StartupAfterFailure" - enum="SystemMediaCapturePermission" expires_after="2020-03-01"> + enum="SystemMediaCapturePermission" expires_after="2023-03-01"> <owner>grunell@chromium.org</owner> <owner>engedy@chromium.org</owner> <owner>hkamila@chromium.org</owner> @@ -342,11 +348,13 @@ system permission before the last browser restart. For more information on the values, see https://developer.apple.com/documentation/avfoundation/avauthorizationstatus. + Warning: this histogram was expired from 2020-03-01 to 2022-03-09; data may + be missing. </summary> </histogram> <histogram name="Media.Audio.Capture.Mac.MicSystemPermission.UserMedia" - enum="SystemMediaCapturePermission" expires_after="2020-03-01"> + enum="SystemMediaCapturePermission" expires_after="2023-03-01"> <owner>grunell@chromium.org</owner> <owner>engedy@chromium.org</owner> <owner>hkamila@chromium.org</owner> @@ -357,6 +365,8 @@ resulting permission (from the user response) is also logged. For more information on the values, see https://developer.apple.com/documentation/avfoundation/avauthorizationstatus. + Warning: this histogram was expired from 2020-03-01 to 2022-03-09; data may + be missing. </summary> </histogram> @@ -4312,7 +4322,7 @@ <histogram name="Media.Video.Capture.Mac.CameraSystemPermission.FixedTime.SinceFirstFailure" - units="ms" expires_after="2020-03-01"> + units="ms" expires_after="2023-03-01"> <owner>grunell@chromium.org</owner> <owner>engedy@chromium.org</owner> <owner>hkamila@chromium.org</owner> @@ -4320,12 +4330,14 @@ The time from the first camera access failure due to blocked system permission before the last browser restart to startup after browser restart. Logged once at browser startup if the system permission then is allowed. + Warning: this histogram was expired from 2020-03-01 to 2022-03-09; data may + be missing. </summary> </histogram> <histogram name="Media.Video.Capture.Mac.CameraSystemPermission.FixedTime.SinceLastFailure" - units="ms" expires_after="2020-03-01"> + units="ms" expires_after="2023-03-01"> <owner>grunell@chromium.org</owner> <owner>engedy@chromium.org</owner> <owner>hkamila@chromium.org</owner> @@ -4333,11 +4345,13 @@ The time from the last camera access failure due to blocked system permission before the last browser restart to startup after browser restart. Logged once at browser startup if the system permission then is allowed. + Warning: this histogram was expired from 2020-03-01 to 2022-03-09; data may + be missing. </summary> </histogram> <histogram name="Media.Video.Capture.Mac.CameraSystemPermission.Startup" - enum="SystemMediaCapturePermission" expires_after="2020-03-01"> + enum="SystemMediaCapturePermission" expires_after="2023-03-01"> <owner>grunell@chromium.org</owner> <owner>engedy@chromium.org</owner> <owner>hkamila@chromium.org</owner> @@ -4345,12 +4359,14 @@ The Mac system permission state for camera. Logged once at browser startup. For more information on the values, see https://developer.apple.com/documentation/avfoundation/avauthorizationstatus. + Warning: this histogram was expired from 2020-03-01 to 2022-03-09; data may + be missing. </summary> </histogram> <histogram name="Media.Video.Capture.Mac.CameraSystemPermission.StartupAfterFailure" - enum="SystemMediaCapturePermission" expires_after="2020-03-01"> + enum="SystemMediaCapturePermission" expires_after="2023-03-01"> <owner>grunell@chromium.org</owner> <owner>engedy@chromium.org</owner> <owner>hkamila@chromium.org</owner> @@ -4359,11 +4375,13 @@ if there was a failure accessing the camera due to blocked system permission before the last browser restart. For more information on the values, see https://developer.apple.com/documentation/avfoundation/avauthorizationstatus. + Warning: this histogram was expired from 2020-03-01 to 2022-03-09; data may + be missing. </summary> </histogram> <histogram name="Media.Video.Capture.Mac.CameraSystemPermission.UserMedia" - enum="SystemMediaCapturePermission" expires_after="2020-03-01"> + enum="SystemMediaCapturePermission" expires_after="2023-03-01"> <owner>grunell@chromium.org</owner> <owner>engedy@chromium.org</owner> <owner>hkamila@chromium.org</owner> @@ -4374,6 +4392,8 @@ resulting permission (from the user response) is also logged. For more information on the values, see https://developer.apple.com/documentation/avfoundation/avauthorizationstatus. + Warning: this histogram was expired from 2020-03-01 to 2022-03-09; data may + be missing. </summary> </histogram>
diff --git a/tools/metrics/histograms/metadata/navigation/OWNERS b/tools/metrics/histograms/metadata/navigation/OWNERS index d986862c..7e4fc00 100644 --- a/tools/metrics/histograms/metadata/navigation/OWNERS +++ b/tools/metrics/histograms/metadata/navigation/OWNERS
@@ -6,3 +6,4 @@ cthomp@chromium.org tbansal@chromium.org toyoshim@chromium.org +wanderview@chromium.org
diff --git a/tools/metrics/histograms/metadata/network/histograms.xml b/tools/metrics/histograms/metadata/network/histograms.xml index d2e6c48..fa7a6491 100644 --- a/tools/metrics/histograms/metadata/network/histograms.xml +++ b/tools/metrics/histograms/metadata/network/histograms.xml
@@ -1351,7 +1351,7 @@ <histogram name="Network.Shill.DarkResumeActionResult" enum="ShillSuspendTerminationDarkResumeActionResult" - expires_after="2022-04-03"> + expires_after="2022-12-01"> <owner>stevenjb@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -1361,7 +1361,7 @@ </histogram> <histogram name="Network.Shill.DarkResumeActionsTimeTaken" units="ms" - expires_after="2021-12-01"> + expires_after="2022-12-01"> <owner>stevenjb@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -1370,28 +1370,6 @@ </summary> </histogram> -<histogram name="Network.Shill.DarkResumeScanNumRetries" units="units" - expires_after="2021-12-01"> - <owner>stevenjb@chromium.org</owner> - <owner>cros-network-metrics@google.com</owner> - <summary> - Chrome OS network metric sampling the number of times a dark resume scan is - retried in a single dark resume. - </summary> -</histogram> - -<histogram name="Network.Shill.DarkResumeScanRetryResult" - enum="DarkResumeScanRetryResult" expires_after="2021-12-01"> - <owner>stevenjb@chromium.org</owner> - <owner>cros-network-metrics@google.com</owner> - <summary> - Chrome OS network metric that tracks whether dark resume scan retries led to - the system suspending from dark resume in a connected state. This metric is - only recorded in dark resumes when at least one dark resume scan retry was - launched. - </summary> -</histogram> - <histogram name="Network.Shill.DeviceConnectionStatus" enum="ConnectionStatus" expires_after="2022-04-17"> <owner>stevenjb@chromium.org</owner> @@ -2080,7 +2058,7 @@ </histogram> <histogram name="Network.Shill.Wifi.Channel" enum="NetworkChannelType" - expires_after="2022-04-17"> + expires_after="2022-12-01"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -2090,7 +2068,7 @@ </histogram> <histogram name="Network.Shill.WiFi.ClientDisconnectReason" - enum="WiFiReasonCode" expires_after="2022-04-03"> + enum="WiFiReasonCode" expires_after="2022-12-01"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -2100,7 +2078,7 @@ </histogram> <histogram name="Network.Shill.WiFi.ClientDisconnectType" enum="WiFiStatusType" - expires_after="2022-04-17"> + expires_after="2022-12-01"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -2110,7 +2088,7 @@ </histogram> <histogram name="Network.Shill.WiFi.CQMNotification" - enum="WiFiCQMNotificationType" expires_after="2022-09-01"> + enum="WiFiCQMNotificationType" expires_after="2022-12-01"> <owner>kuabhs@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -2121,8 +2099,30 @@ </summary> </histogram> +<histogram name="Network.Shill.WiFi.DarkResumeScanNumRetries" units="units" + expires_after="2022-12-01"> + <owner>norvez@chromium.org</owner> + <owner>cros-network-metrics@google.com</owner> + <summary> + Chrome OS network metric sampling the number of times a dark resume scan is + retried in a single dark resume. + </summary> +</histogram> + +<histogram name="Network.Shill.WiFi.DarkResumeScanRetryResult" + enum="DarkResumeScanRetryResult" expires_after="2022-12-01"> + <owner>norvez@chromium.org</owner> + <owner>cros-network-metrics@google.com</owner> + <summary> + Chrome OS network metric that tracks whether dark resume scan retries led to + the system suspending from dark resume in a connected state. This metric is + only recorded in dark resumes when at least one dark resume scan retry was + launched. + </summary> +</histogram> + <histogram name="Network.Shill.WiFi.DarkResumeUnmatchedScanResultsReceived" - enum="DarkResumeUnmatchedScanResultReceived" expires_after="2022-05-01"> + enum="DarkResumeUnmatchedScanResultReceived" expires_after="2022-12-01"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -2143,7 +2143,7 @@ </histogram> <histogram name="Network.Shill.Wifi.DevicePresenceStatus" enum="BooleanPresent" - expires_after="2022-04-24"> + expires_after="2022-12-01"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -2153,7 +2153,7 @@ </histogram> <histogram name="Network.Shill.Wifi.Disconnect" enum="NetworkDisconnectType" - expires_after="2022-04-17"> + expires_after="2022-12-01"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -2164,7 +2164,7 @@ </histogram> <histogram name="Network.Shill.Wifi.EapInnerProtocol" enum="EAPInnerProtocol" - expires_after="2022-04-17"> + expires_after="2022-12-01"> <owner>matthewmwang@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -2174,7 +2174,7 @@ </histogram> <histogram name="Network.Shill.Wifi.EapOuterProtocol" enum="EAPOuterProtocol" - expires_after="2022-04-17"> + expires_after="2022-12-01"> <owner>matthewmwang@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -2263,7 +2263,7 @@ </histogram> <histogram name="Network.Shill.WiFi.HS20Support" enum="HotspotSupport" - expires_after="2022-04-24"> + expires_after="2022-12-01"> <owner>kglund@google.com</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -2275,7 +2275,7 @@ </histogram> <histogram name="Network.Shill.Wifi.IPv6ConnectivityStatus" - enum="IPv6ConnectivityStatus" expires_after="2022-05-01"> + enum="IPv6ConnectivityStatus" expires_after="2022-12-01"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -2349,7 +2349,7 @@ </histogram> <histogram name="Network.Shill.Wifi.PortalAttemptsToOnline" units="units" - expires_after="2022-04-17"> + expires_after="2022-12-01"> <owner>matthewmwang@chromium.org</owner> <owner>stevenjb@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> @@ -2362,7 +2362,7 @@ </histogram> <histogram name="Network.Shill.Wifi.PortalResult" enum="NetworkPortalResult" - expires_after="2022-04-10"> + expires_after="2022-12-01"> <owner>matthewmwang@chromium.org</owner> <owner>stevenjb@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> @@ -2384,7 +2384,7 @@ </histogram> <histogram name="Network.Shill.WiFi.RememberedNetworkCount" units="units" - expires_after="2022-04-03"> + expires_after="2022-12-01"> <owner>matthewmwang@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -2396,7 +2396,7 @@ </histogram> <histogram name="Network.Shill.WiFi.RememberedSystemNetworkCount" units="units" - expires_after="2022-04-17"> + expires_after="2022-12-01"> <owner>matthewmwang@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -2412,7 +2412,7 @@ </histogram> <histogram name="Network.Shill.WiFi.RememberedUserNetworkCount" units="units" - expires_after="2022-04-24"> + expires_after="2022-12-01"> <owner>matthewmwang@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -2449,7 +2449,7 @@ </histogram> <histogram name="Network.Shill.WiFi.ScanResult" enum="WiFiScanResult" - expires_after="2022-04-10"> + expires_after="2022-12-01"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -2469,7 +2469,7 @@ </histogram> <histogram name="Network.Shill.Wifi.Security" enum="NetworkSecurityType" - expires_after="2022-04-10"> + expires_after="2022-12-01"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -2479,7 +2479,7 @@ </histogram> <histogram name="Network.Shill.Wifi.ServiceErrors" enum="NetworkServiceError" - expires_after="2023-01-01"> + expires_after="2022-12-01"> <owner>kuabhs@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -2501,7 +2501,7 @@ </histogram> <histogram name="Network.Shill.Wifi.SignalAtDisconnect" units="negative dBm" - expires_after="2022-04-24"> + expires_after="2022-12-01"> <owner>kuabhs@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -2511,7 +2511,7 @@ </histogram> <histogram name="Network.Shill.Wifi.SignalStrength" units="negative dBm" - expires_after="2022-04-17"> + expires_after="2022-12-01"> <owner>kuabhs@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -2521,7 +2521,7 @@ </histogram> <histogram name="Network.Shill.WiFi.SupplicantAttempts" units="attempts" - expires_after="2022-04-17"> + expires_after="2022-12-01"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -2538,7 +2538,7 @@ </histogram> <histogram name="Network.Shill.WiFi.SuspendDurationWoWOffConnected" - units="seconds" expires_after="2022-05-01"> + units="seconds" expires_after="2022-12-01"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -2549,7 +2549,7 @@ </histogram> <histogram name="Network.Shill.WiFi.SuspendDurationWoWOffDisconnected" - units="seconds" expires_after="2022-05-01"> + units="seconds" expires_after="2022-12-01"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -2592,7 +2592,7 @@ </histogram> <histogram name="Network.Shill.Wifi.TimeOnline" units="seconds" - expires_after="2022-04-24"> + expires_after="2022-12-01"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -2603,7 +2603,7 @@ </histogram> <histogram name="Network.Shill.Wifi.TimeResumeToReady" units="ms" - expires_after="2022-04-03"> + expires_after="2022-12-01"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -2624,7 +2624,7 @@ </histogram> <histogram name="Network.Shill.Wifi.TimeToConnect" units="ms" - expires_after="2022-04-24"> + expires_after="2022-12-01"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -2635,7 +2635,7 @@ </histogram> <histogram name="Network.Shill.Wifi.TimeToInitialize" units="ms" - expires_after="2022-05-01"> + expires_after="2022-12-01"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -2645,7 +2645,7 @@ </histogram> <histogram name="Network.Shill.Wifi.TimeToJoin" units="ms" - expires_after="2022-04-17"> + expires_after="2022-12-01"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -2655,7 +2655,7 @@ </histogram> <histogram name="Network.Shill.Wifi.TimeToOnline" units="ms" - expires_after="2022-04-24"> + expires_after="2022-12-01"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -2665,7 +2665,7 @@ </histogram> <histogram name="Network.Shill.Wifi.TimeToPortal" units="ms" - expires_after="2022-05-01"> + expires_after="2022-12-01"> <owner>matthewmwang@chromium.org</owner> <owner>hugobenichi@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> @@ -2689,7 +2689,7 @@ </histogram> <histogram name="Network.Shill.Wifi.TimeToScan" units="ms" - expires_after="2022-04-03"> + expires_after="2022-12-01"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -2699,7 +2699,7 @@ </histogram> <histogram name="Network.Shill.Wifi.TimeToScanAndConnect" units="ms" - expires_after="2022-04-10"> + expires_after="2022-12-01"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -2711,7 +2711,7 @@ </histogram> <histogram name="Network.Shill.WiFi.TransmitBitrateMbps" units="Mbps" - expires_after="2022-04-24"> + expires_after="2022-12-01"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -2722,7 +2722,7 @@ </histogram> <histogram name="Network.Shill.Wifi.UnreliableLinkSignalStrength" units="units" - expires_after="2022-04-24"> + expires_after="2022-12-01"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -2733,7 +2733,7 @@ </histogram> <histogram name="Network.Shill.WiFi.UserInitiatedConnectionFailureReason" - enum="ConnectionFailureReason" expires_after="2022-04-24"> + enum="ConnectionFailureReason" expires_after="2022-12-01"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -2745,7 +2745,7 @@ </histogram> <histogram name="Network.Shill.WiFi.UserInitiatedConnectionResult" - enum="ConnectionResult" expires_after="2022-04-24"> + enum="ConnectionResult" expires_after="2022-12-01"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -2767,7 +2767,7 @@ </histogram> <histogram name="Network.Shill.WiFi.WakeOnWiFiFeaturesEnabledState" - enum="WakeOnWiFiFeaturesEnabledState" expires_after="2022-04-10"> + enum="WakeOnWiFiFeaturesEnabledState" expires_after="2022-12-01"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -2799,7 +2799,7 @@ </histogram> <histogram name="Network.Shill.WiFi.WiFiConnectionStatusAfterWake" - enum="WiFiConnectionStatusAfterWake" expires_after="2022-04-10"> + enum="WiFiConnectionStatusAfterWake" expires_after="2022-12-01"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/platform/histograms.xml b/tools/metrics/histograms/metadata/platform/histograms.xml index 69cada0..10b172a1 100644 --- a/tools/metrics/histograms/metadata/platform/histograms.xml +++ b/tools/metrics/histograms/metadata/platform/histograms.xml
@@ -1431,7 +1431,7 @@ </histogram> <histogram name="Platform.WiFiDeviceCount" units="wifi devices" - expires_after="2022-04-24"> + expires_after="2022-12-01"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -1441,7 +1441,7 @@ </histogram> <histogram name="Platform.WiFiDisapppearedFromPCI" units="units" - expires_after="2022-04-17"> + expires_after="2022-12-01"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -1454,7 +1454,7 @@ </histogram> <histogram name="Platform.WiFiStatusAfterForcedPCIRescan" enum="WiFiPCIStatus" - expires_after="2022-04-10"> + expires_after="2022-12-01"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/sync/histograms.xml b/tools/metrics/histograms/metadata/sync/histograms.xml index cc333fa..389b7ff 100644 --- a/tools/metrics/histograms/metadata/sync/histograms.xml +++ b/tools/metrics/histograms/metadata/sync/histograms.xml
@@ -404,6 +404,19 @@ </token> </histogram> +<histogram name="Sync.IncomingInvalidationStatus" + enum="SyncIncomingInvalidationStatus" expires_after="2022-09-10"> + <owner>rushans@google.com</owner> + <owner>treib@chromium.org</owner> + <component>Services>Sync</component> + <summary> + An outcome of handling incoming sync invalidations, recorded for each + incoming FCM message when sync engine is registered for invalidations. This + metric shows only the number of incoming messages regardless of the number + of invalidated data types. + </summary> +</histogram> + <histogram name="Sync.InitialState" enum="SyncInitialState" expires_after="2022-08-28"> <owner>treib@chromium.org</owner>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml index b94baa1..935ce1c 100644 --- a/tools/metrics/ukm/ukm.xml +++ b/tools/metrics/ukm/ukm.xml
@@ -15398,6 +15398,64 @@ </metric> </event> +<event name="PostMessage.Incoming.FirstPartyToFirstParty.DifferentBucket"> + <owner>arichiv@chromium.org</owner> + <owner>miketaylr@chromium.org</owner> + <summary> + A top level frame received an incoming postMessage event from another top + level frame with a different storage key and a different origin. + </summary> + <metric name="SourceFrameSourceId"> + <summary> + The UKM source ID of the postMessage event's source frame, as an integer. + </summary> + </metric> +</event> + +<event name="PostMessage.Incoming.FirstPartyToFirstParty.SameBucket"> + <owner>arichiv@chromium.org</owner> + <owner>miketaylr@chromium.org</owner> + <summary> + A top level frame received an incoming postMessage event from another top + level frame with the same storage key. + </summary> + <metric name="SourceFrameSourceId"> + <summary> + The UKM source ID of the postMessage event's source frame, as an integer. + </summary> + </metric> +</event> + +<event + name="PostMessage.Incoming.FirstPartyToThirdParty.DifferentBucket.DifferentOrigin"> + <owner>arichiv@chromium.org</owner> + <owner>miketaylr@chromium.org</owner> + <summary> + A child frame received an incoming postMessage event from a top level frame + with a different storage key and a different origin. + </summary> + <metric name="SourceFrameSourceId"> + <summary> + The UKM source ID of the postMessage event's source frame, as an integer. + </summary> + </metric> +</event> + +<event + name="PostMessage.Incoming.FirstPartyToThirdParty.DifferentBucket.SameOrigin"> + <owner>arichiv@chromium.org</owner> + <owner>miketaylr@chromium.org</owner> + <summary> + A child frame received an incoming postMessage event from a top level frame + with a different storage key and the same origin. + </summary> + <metric name="SourceFrameSourceId"> + <summary> + The UKM source ID of the postMessage event's source frame, as an integer. + </summary> + </metric> +</event> + <event name="PostMessage.Incoming.Frame"> <owner>arichiv@chromium.org</owner> <owner>miketaylr@chromium.org</owner> @@ -15412,6 +15470,20 @@ </metric> </event> +<event name="PostMessage.Incoming.Opaque"> + <owner>arichiv@chromium.org</owner> + <owner>miketaylr@chromium.org</owner> + <summary> + A frame received an incoming postMessage event from another frame where + either of their origins or top level origins are opaque. + </summary> + <metric name="SourceFrameSourceId"> + <summary> + The UKM source ID of the postMessage event's source frame, as an integer. + </summary> + </metric> +</event> + <event name="PostMessage.Incoming.Page"> <owner>arichiv@chromium.org</owner> <owner>miketaylr@chromium.org</owner> @@ -15427,6 +15499,80 @@ </metric> </event> +<event + name="PostMessage.Incoming.ThirdPartyToFirstParty.DifferentBucket.DifferentOrigin"> + <owner>arichiv@chromium.org</owner> + <owner>miketaylr@chromium.org</owner> + <summary> + A top level frame received an incoming postMessage event from a child frame + with a different storage key and a different origin. + </summary> + <metric name="SourceFrameSourceId"> + <summary> + The UKM source ID of the postMessage event's source frame, as an integer. + </summary> + </metric> +</event> + +<event + name="PostMessage.Incoming.ThirdPartyToFirstParty.DifferentBucket.SameOrigin"> + <owner>arichiv@chromium.org</owner> + <owner>miketaylr@chromium.org</owner> + <summary> + A top level frame received an incoming postMessage event from a child frame + with a different storage key and the same origin. + </summary> + <metric name="SourceFrameSourceId"> + <summary> + The UKM source ID of the postMessage event's source frame, as an integer. + </summary> + </metric> +</event> + +<event + name="PostMessage.Incoming.ThirdPartyToThirdParty.DifferentBucket.DifferentOrigin"> + <owner>arichiv@chromium.org</owner> + <owner>miketaylr@chromium.org</owner> + <summary> + A child frame received an incoming postMessage event from another child + frame with a different storage key and a different origin. + </summary> + <metric name="SourceFrameSourceId"> + <summary> + The UKM source ID of the postMessage event's source frame, as an integer. + </summary> + </metric> +</event> + +<event + name="PostMessage.Incoming.ThirdPartyToThirdParty.DifferentBucket.SameOrigin"> + <owner>arichiv@chromium.org</owner> + <owner>miketaylr@chromium.org</owner> + <summary> + A child frame received an incoming postMessage event from another child + frame with a different storage key and the same origin. + </summary> + <metric name="SourceFrameSourceId"> + <summary> + The UKM source ID of the postMessage event's source frame, as an integer. + </summary> + </metric> +</event> + +<event name="PostMessage.Incoming.ThirdPartyToThirdParty.SameBucket"> + <owner>arichiv@chromium.org</owner> + <owner>miketaylr@chromium.org</owner> + <summary> + A child frame received an incoming postMessage event from another child + frame with the same storage key. + </summary> + <metric name="SourceFrameSourceId"> + <summary> + The UKM source ID of the postMessage event's source frame, as an integer. + </summary> + </metric> +</event> + <event name="PowerUsageScenariosIntervalData"> <owner>fdoray@chromium.org</owner> <owner>sebmarchand@chromium.org</owner>
diff --git a/ui/color/color_provider.cc b/ui/color/color_provider.cc index 1d57682d..8c7ff44e 100644 --- a/ui/color/color_provider.cc +++ b/ui/color/color_provider.cc
@@ -12,6 +12,7 @@ #include "base/logging.h" #include "ui/color/color_mixer.h" #include "ui/color/color_provider_utils.h" +#include "ui/color/color_recipe.h" #include "ui/gfx/color_palette.h" namespace ui { @@ -92,6 +93,16 @@ first_postprocessing_mixer_ = mixers_.before_begin(); } +void ColorProvider::SetColorForTesting(ColorId id, SkColor color) { + if (color_map_) { + (*color_map_)[id] = color; + } else { + if (mixers_.empty()) + AddMixer(); + (*std::next(first_postprocessing_mixer_, 1))[id] = {color}; + } +} + const ColorMixer* ColorProvider::GetLastNonPostprocessingMixer() const { const auto it = std::next(first_postprocessing_mixer_, 1); return (it == mixers_.cend()) ? nullptr : &(*it);
diff --git a/ui/color/color_provider.h b/ui/color/color_provider.h index 01c26e40..5b3e057 100644 --- a/ui/color/color_provider.h +++ b/ui/color/color_provider.h
@@ -55,6 +55,7 @@ // provider after this has been called. void GenerateColorMap(); + void SetColorForTesting(ColorId id, SkColor color); const ColorMap& color_map_for_testing() { return *color_map_; } private:
diff --git a/ui/color/color_provider_manager.cc b/ui/color/color_provider_manager.cc index 5b2a4006..ee572e2 100644 --- a/ui/color/color_provider_manager.cc +++ b/ui/color/color_provider_manager.cc
@@ -46,16 +46,19 @@ : Key(ColorMode::kLight, ContrastMode::kNormal, SystemTheme::kDefault, + FrameType::kChromium, nullptr) {} ColorProviderManager::Key::Key(ColorMode color_mode, ContrastMode contrast_mode, SystemTheme system_theme, + FrameType frame_type, scoped_refptr<InitializerSupplier> custom_theme) : color_mode(color_mode), contrast_mode(contrast_mode), elevation_mode(ElevationMode::kLow), system_theme(system_theme), + frame_type(frame_type), custom_theme(std::move(custom_theme)) {} ColorProviderManager::Key::Key(const Key&) = default;
diff --git a/ui/color/color_provider_manager.h b/ui/color/color_provider_manager.h index fab67fc7..c6d3f45f 100644 --- a/ui/color/color_provider_manager.h +++ b/ui/color/color_provider_manager.h
@@ -41,9 +41,18 @@ kHigh, }; enum class SystemTheme { + // Classic theme, used in the default or users' chosen theme. kDefault, + // Custom theme that follow the system style, + // currently used only when GTK theme is on. kCustom, }; + enum class FrameType { + // Chrome renders the browser frame. + kChromium, + // Native system renders the browser frame. Currently GTK only. + kNative, + }; // Threadsafe not because ColorProviderManager requires it but because a // concrete subclass does. @@ -73,6 +82,7 @@ Key(ColorMode color_mode, ContrastMode contrast_mode, SystemTheme system_theme, + FrameType frame_type, scoped_refptr<InitializerSupplier> custom_theme); Key(const Key&); Key& operator=(const Key&); @@ -81,6 +91,7 @@ ContrastMode contrast_mode; ElevationMode elevation_mode; SystemTheme system_theme; + FrameType frame_type; scoped_refptr<InitializerSupplier> custom_theme; bool operator<(const Key& other) const {
diff --git a/ui/color/color_provider_manager_unittest.cc b/ui/color/color_provider_manager_unittest.cc index d3651333..a32144e7 100644 --- a/ui/color/color_provider_manager_unittest.cc +++ b/ui/color/color_provider_manager_unittest.cc
@@ -31,7 +31,8 @@ return ColorProviderManager::GetForTesting().GetColorProviderFor( {ColorProviderManager::ColorMode::kLight, ColorProviderManager::ContrastMode::kNormal, - ColorProviderManager::SystemTheme::kDefault, nullptr}); + ColorProviderManager::SystemTheme::kDefault, + ColorProviderManager::FrameType::kChromium, nullptr}); } } // namespace
diff --git a/ui/color/color_provider_source_observer_unittest.cc b/ui/color/color_provider_source_observer_unittest.cc index d5f79c4a..4ed1648b 100644 --- a/ui/color/color_provider_source_observer_unittest.cc +++ b/ui/color/color_provider_source_observer_unittest.cc
@@ -39,13 +39,13 @@ EXPECT_CALL(observer_1, OnColorProviderChanged()).Times(2); EXPECT_CALL(observer_2, OnColorProviderChanged()).Times(2); - auto set_observaton = [&](MockColorProviderSourceObserver* observer) { + auto set_observation = [&](MockColorProviderSourceObserver* observer) { observer->ObserveForTesting(source.get()); EXPECT_EQ(source.get(), observer->GetColorProviderSourceForTesting()); EXPECT_TRUE(source->observers_for_testing().HasObserver(observer)); }; - set_observaton(&observer_1); - set_observaton(&observer_2); + set_observation(&observer_1); + set_observation(&observer_2); // When the source is destroyed the observer's source() method should return // nullptr. @@ -66,13 +66,13 @@ EXPECT_CALL(*observer_1, OnColorProviderChanged()).Times(1); EXPECT_CALL(*observer_2, OnColorProviderChanged()).Times(1); - auto set_observaton = [&](MockColorProviderSourceObserver* observer) { + auto set_observation = [&](MockColorProviderSourceObserver* observer) { observer->ObserveForTesting(&source); EXPECT_EQ(&source, observer->GetColorProviderSourceForTesting()); EXPECT_TRUE(source.observers_for_testing().HasObserver(observer)); }; - set_observaton(observer_1.get()); - set_observaton(observer_2.get()); + set_observation(observer_1.get()); + set_observation(observer_2.get()); // When the observer is destroyed it should be removed from the source's list // of observers. Other observers should remain. @@ -100,15 +100,15 @@ EXPECT_CALL(observer_1, OnColorProviderChanged()).Times(4); EXPECT_CALL(observer_2, OnColorProviderChanged()).Times(3); - auto set_observaton_and_notify = + auto set_observation_and_notify = [&](MockColorProviderSourceObserver* observer) { observer->ObserveForTesting(&source); EXPECT_EQ(&source, observer->GetColorProviderSourceForTesting()); EXPECT_TRUE(source.observers_for_testing().HasObserver(observer)); source.NotifyColorProviderChanged(); }; - set_observaton_and_notify(&observer_1); - set_observaton_and_notify(&observer_2); + set_observation_and_notify(&observer_1); + set_observation_and_notify(&observer_2); observer_2.ObserveForTesting(nullptr);
diff --git a/ui/color/color_provider_unittest.cc b/ui/color/color_provider_unittest.cc index ff596e1..83d5bfd 100644 --- a/ui/color/color_provider_unittest.cc +++ b/ui/color/color_provider_unittest.cc
@@ -102,5 +102,15 @@ EXPECT_FALSE(color_utils::IsDark(provider.GetColor(kColorTest1))); } +TEST(ColorProviderTest, SetColorForTesting) { + ColorProvider provider; + provider.SetColorForTesting(kColorTest0, SK_ColorGREEN); + provider.GenerateColorMap(); + EXPECT_EQ(SK_ColorGREEN, provider.GetColor(kColorTest0)); + EXPECT_EQ(gfx::kPlaceholderColor, provider.GetColor(kColorTest1)); + provider.SetColorForTesting(kColorTest1, SK_ColorBLUE); + EXPECT_EQ(SK_ColorBLUE, provider.GetColor(kColorTest1)); +} + } // namespace } // namespace ui
diff --git a/ui/gfx/delegated_ink_metadata.h b/ui/gfx/delegated_ink_metadata.h index 1904f4f..3952ec97 100644 --- a/ui/gfx/delegated_ink_metadata.h +++ b/ui/gfx/delegated_ink_metadata.h
@@ -62,7 +62,12 @@ bool is_hovering() const { return is_hovering_; } void set_frame_time(base::TimeTicks frame_time) { frame_time_ = frame_time; } - + uint64_t trace_id() const { + // Use mask to distinguish from DelegatedInkPoint::trace_id(). + // Using microseconds provides uniqueness of trace_id per + // DelegatedInkMetadata. + return timestamp_.since_origin().InMicroseconds() | (uint64_t{1} << 63); + } std::string ToString() const; private:
diff --git a/ui/gfx/delegated_ink_point.h b/ui/gfx/delegated_ink_point.h index 4167cfac..4879e71 100644 --- a/ui/gfx/delegated_ink_point.h +++ b/ui/gfx/delegated_ink_point.h
@@ -44,6 +44,12 @@ std::string ToString() const; bool MatchesDelegatedInkMetadata(const DelegatedInkMetadata* metadata) const; + uint64_t trace_id() const { + // Use mask to distinguish from DelegatedInkMetadata::trace_id(). + // Using microseconds provides uniqueness of trace_id per + // DelegatedInkPoint. + return timestamp_.since_origin().InMicroseconds() & 0x7fffffffffffffff; + } private: friend struct mojo::StructTraits<mojom::DelegatedInkPointDataView,
diff --git a/ui/gtk/gtk_ui.cc b/ui/gtk/gtk_ui.cc index 878f012..cb9f2e5 100644 --- a/ui/gtk/gtk_ui.cc +++ b/ui/gtk/gtk_ui.cc
@@ -920,7 +920,11 @@ (color_scheme == ui::NativeTheme::ColorScheme::kPlatformHighContrast) ? ui::ColorProviderManager::ContrastMode::kHigh : ui::ColorProviderManager::ContrastMode::kNormal, - ui::ColorProviderManager::SystemTheme::kCustom, nullptr}); + ui::ColorProviderManager::SystemTheme::kCustom, + // Some theme colors, e.g. COLOR_NTP_LINK, are derived from color + // provider colors. We assume that those sources' colors won't change + // with frame type. + ui::ColorProviderManager::FrameType::kChromium, nullptr}); SkColor location_bar_border = GetBorderColor("GtkEntry#entry"); if (SkColorGetA(location_bar_border))
diff --git a/ui/native_theme/native_theme.cc b/ui/native_theme/native_theme.cc index f3b25e58..d359277 100644 --- a/ui/native_theme/native_theme.cc +++ b/ui/native_theme/native_theme.cc
@@ -38,8 +38,8 @@ #endif ColorProviderManager::Key NativeTheme::GetColorProviderKey( - scoped_refptr<ColorProviderManager::InitializerSupplier> custom_theme) - const { + scoped_refptr<ColorProviderManager::InitializerSupplier> custom_theme, + bool use_custom_frame) const { return ColorProviderManager::Key( (GetDefaultSystemColorScheme() == ColorScheme::kDark) ? ColorProviderManager::ColorMode::kDark @@ -48,6 +48,8 @@ : ColorProviderManager::ContrastMode::kNormal, is_custom_system_theme_ ? ColorProviderManager::SystemTheme::kCustom : ColorProviderManager::SystemTheme::kDefault, + use_custom_frame ? ui::ColorProviderManager::FrameType::kChromium + : ui::ColorProviderManager::FrameType::kNative, std::move(custom_theme)); }
diff --git a/ui/native_theme/native_theme.h b/ui/native_theme/native_theme.h index beadf20..7e5e569 100644 --- a/ui/native_theme/native_theme.h +++ b/ui/native_theme/native_theme.h
@@ -385,9 +385,11 @@ }; // Returns the key corresponding to this native theme object. + // Use `use_custom_frame` == true when Chromium renders the titlebar. + // False when the window manager renders the titlebar (currently GTK only). ColorProviderManager::Key GetColorProviderKey( - scoped_refptr<ColorProviderManager::InitializerSupplier> custom_theme) - const; + scoped_refptr<ColorProviderManager::InitializerSupplier> custom_theme, + bool use_custom_frame = true) const; // Returns a shared instance of the native theme that should be used for web // rendering. Do not use it in a normal application context (i.e. browser).
diff --git a/ui/views/cocoa/bridged_native_widget_unittest.mm b/ui/views/cocoa/bridged_native_widget_unittest.mm index 14a62d94..b5d5b631 100644 --- a/ui/views/cocoa/bridged_native_widget_unittest.mm +++ b/ui/views/cocoa/bridged_native_widget_unittest.mm
@@ -1982,14 +1982,13 @@ [center postNotificationName:NSWindowWillEnterFullScreenNotification object:window]; - // On a failure, Cocoa starts by sending an unexpected *exit* fullscreen, and - // NativeWidgetNSWindowBridge will think it's just a delayed transition and - // try to go back into fullscreen but get ignored by Cocoa. + // On a failure, Cocoa starts by sending an unexpected *exit* fullscreen. + // NativeWidgetNSWindowBridge recognize this failure and set its state + // back to windowed mode. EXPECT_EQ(0, [window ignoredToggleFullScreenCount]); EXPECT_TRUE(bridge()->target_fullscreen_state()); [center postNotificationName:NSWindowDidExitFullScreenNotification object:window]; - EXPECT_EQ(1, [window ignoredToggleFullScreenCount]); EXPECT_FALSE(bridge()->target_fullscreen_state()); // Cocoa follows up with a failure message sent to the NSWindowDelegate (there @@ -2018,7 +2017,7 @@ EXPECT_FALSE(bridge()->target_fullscreen_state()); [center postNotificationName:NSWindowDidExitFullScreenNotification object:window]; - EXPECT_EQ(1, [window ignoredToggleFullScreenCount]); // No change. + EXPECT_EQ(0, [window ignoredToggleFullScreenCount]); // No change. EXPECT_FALSE(bridge()->target_fullscreen_state()); widget_->CloseNow();
diff --git a/ui/webui/resources/cr_components/app_management/BUILD.gn b/ui/webui/resources/cr_components/app_management/BUILD.gn index 0d4df03..1f61e9b 100644 --- a/ui/webui/resources/cr_components/app_management/BUILD.gn +++ b/ui/webui/resources/cr_components/app_management/BUILD.gn
@@ -56,6 +56,10 @@ cpp = "::apps::AppType" }, { + mojom = "app_management.mojom.PermissionType" + cpp = "::apps::PermissionType" + }, + { mojom = "app_management.mojom.Permission" cpp = "::apps::PermissionPtr" move_only = true
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/NavigationControllerImpl.java b/weblayer/browser/java/org/chromium/weblayer_private/NavigationControllerImpl.java index 5dcefd7..f6e0d99 100644 --- a/weblayer/browser/java/org/chromium/weblayer_private/NavigationControllerImpl.java +++ b/weblayer/browser/java/org/chromium/weblayer_private/NavigationControllerImpl.java
@@ -5,10 +5,8 @@ package org.chromium.weblayer_private; import android.os.RemoteException; -import android.os.SystemClock; import android.webkit.WebResourceResponse; -import org.chromium.base.TimeUtilsJni; import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; import org.chromium.base.annotations.NativeMethods; @@ -35,10 +33,6 @@ private long mNativeNavigationController; private INavigationControllerClient mNavigationControllerClient; - // Conversion between native TimeTicks and SystemClock.uptimeMillis(). - private long mNativeTickOffsetUs; - private boolean mNativeTickOffsetUsComputed; - private Map<Long, PageImpl> mPages = new HashMap<>(); public NavigationControllerImpl(TabImpl tab, INavigationControllerClient client) { @@ -272,22 +266,20 @@ @CalledByNative private void onFirstContentfulPaint2( - long navigationStartTick, long firstContentfulPaintDurationMs) throws RemoteException { + long navigationStartMs, long firstContentfulPaintDurationMs) throws RemoteException { if (WebLayerFactoryImpl.getClientMajorVersion() < 88) return; mNavigationControllerClient.onFirstContentfulPaint2( - (navigationStartTick - getNativeTickOffsetUs()) / 1000, - firstContentfulPaintDurationMs); + navigationStartMs, firstContentfulPaintDurationMs); } @CalledByNative - private void onLargestContentfulPaint(long navigationStartTick, - long largestContentfulPaintDurationMs) throws RemoteException { + private void onLargestContentfulPaint( + long navigationStartMs, long largestContentfulPaintDurationMs) throws RemoteException { if (WebLayerFactoryImpl.getClientMajorVersion() < 88) return; mNavigationControllerClient.onLargestContentfulPaint( - (navigationStartTick - getNativeTickOffsetUs()) / 1000, - largestContentfulPaintDurationMs); + navigationStartMs, largestContentfulPaintDurationMs); } @CalledByNative @@ -302,18 +294,6 @@ mNavigationControllerClient.onPageLanguageDetermined(page.getClientPage(), language); } - private long getNativeTickOffsetUs() { - // See logic in CustomTabsConnection.java that this was based on. - if (!mNativeTickOffsetUsComputed) { - // Compute offset from time ticks to uptimeMillis. - mNativeTickOffsetUsComputed = true; - long nativeNowUs = TimeUtilsJni.get().getTimeTicksNowUs(); - long javaNowUs = SystemClock.uptimeMillis() * 1000; - mNativeTickOffsetUs = nativeNowUs - javaNowUs; - } - return mNativeTickOffsetUs; - } - private static final class NavigateParamsImpl extends INavigateParams.Stub { private boolean mReplaceCurrentEntry; private boolean mIntentProcessingDisabled;
diff --git a/weblayer/browser/navigation_controller_impl.cc b/weblayer/browser/navigation_controller_impl.cc index ff333ce3..fdff0f0 100644 --- a/weblayer/browser/navigation_controller_impl.cc +++ b/weblayer/browser/navigation_controller_impl.cc
@@ -150,8 +150,7 @@ int64_t first_contentful_paint_ms = first_contentful_paint.InMilliseconds(); Java_NavigationControllerImpl_onFirstContentfulPaint2( AttachCurrentThread(), java_controller_, - (navigation_start - base::TimeTicks()).InMicroseconds(), - first_contentful_paint_ms); + navigation_start.ToUptimeMillis(), first_contentful_paint_ms); #endif for (auto& observer : observers_) @@ -168,8 +167,7 @@ largest_contentful_paint.InMilliseconds(); Java_NavigationControllerImpl_onLargestContentfulPaint( AttachCurrentThread(), java_controller_, - (navigation_start - base::TimeTicks()).InMicroseconds(), - largest_contentful_paint_ms); + navigation_start.ToUptimeMillis(), largest_contentful_paint_ms); #endif for (auto& observer : observers_)