diff --git a/DEPS b/DEPS index 5841d2e..dfa530b 100644 --- a/DEPS +++ b/DEPS
@@ -177,7 +177,7 @@ # luci-go CIPD package version. # Make sure the revision is uploaded by infra-packagers builder. # https://ci.chromium.org/p/infra-internal/g/infra-packagers/console - 'luci_go': 'git_revision:d8815e36ea7b66a4b8c9d69fcc2322012d25715f', + 'luci_go': 'git_revision:3e796d36914b6ddf5311374284e3ffa06c24fc7e', # This can be overridden, e.g. with custom_vars, to build clang from HEAD # instead of downloading the prebuilt pinned revision. @@ -209,7 +209,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': '72fb3fcdf0a7a7b093271eb8766c7728c17bea1d', + 'skia_revision': '03e783020013caa8fd8fb070a6ea37bb2f756200', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. @@ -221,11 +221,11 @@ # 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': '9459456b09abc2e75c0c9a67e4b653273087e1eb', + 'angle_revision': 'd0dc22fd07e40beb5a771840a8a0d43134aa20c4', # 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': '0cfdf0c272cd1e1ac40e95d797baf216721b9026', + 'swiftshader_revision': 'c1e4abc1bcfeae3ea17279b1f3d419406769c77d', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. @@ -244,7 +244,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling googletest # and whatever else without interference from each other. - 'googletest_revision': 'a3460d1aeeaa43fdf137a6adefef10ba0b59fe4b', + 'googletest_revision': '53495a2a7d6ba7e0691a7f3602e9a5324bba6e45', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling lighttpd # and whatever else without interference from each other. @@ -280,7 +280,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': '053e386fd4017d799b5b9130fa7a0b00b0fb0229', + 'catapult_revision': 'ec690bb8debdc5c03a90654a9eb6d8d762dd26ee', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -288,7 +288,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': '8402fc332631f51cddd1c7562a488e900b0fe59d', + 'devtools_frontend_revision': 'a6df3ab32f4aafc308236619a04a99317dd22b06', # 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. @@ -328,7 +328,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': '59e16c9b02a0ef2a094bef900b83f2785b3c2a43', + 'dawn_revision': '1413b351fac11876fcead0a95f04deb17f5630a5', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -372,11 +372,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'libcxxabi_revision': 'da3e6cbc62dd1e3df45f522ba313d1c581867094', + 'libcxxabi_revision': '7e3b76855b76ce7b4c975df50674734357056612', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'libunwind_revision': 'c0776fc6490f549d1f34a677cb74c3d3181ad0fc', + 'libunwind_revision': '950faeeabc1ee25569e62ec4ce749f013169482d', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -730,7 +730,7 @@ 'packages': [ { 'package': 'chromium/third_party/androidx', - 'version': '5wEAJbMDQJnCxXbN6hMn66IR4akg1G25HQtc_8_7Vz0C', + 'version': '8d-gGcc4KVhOnn2B-Od7eR421Q-sNZQ0U7dMrNz_VX4C', }, ], 'condition': 'checkout_android', @@ -961,12 +961,12 @@ # For Linux and Chromium OS. 'src/third_party/cros_system_api': { - 'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + 'b29188be3069888800b409486c1e47bcf36a8120', + 'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + '23db6947e3198a27f3fcebc9dbac4d1b025c2935', 'condition': 'checkout_linux', }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'cd3696cf7ee983de86583b898785cea56ffd07fe', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'c8f63d390cfda6001a67316869914dca977770b7', 'src/third_party/devtools-frontend/src': Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), @@ -1349,7 +1349,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + '34eb6a14728a870046c2637dbfb909d02936b84c', + Var('android_git') + '/platform/external/perfetto.git' + '@' + '8545284860afe328993751b80a9cf856872463df', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3', @@ -1601,7 +1601,7 @@ 'packages': [ { 'package': 'skia/tools/goldctl/linux-amd64', - 'version': '8A8GVNDvQNly-61PpEBfFpqpG9cscGA9DrHNNoc8tSQC', + 'version': 'SIbSqtgKfmhBASeojfVyHGkIx2ZItagJYLeJt9yef1oC', }, ], 'dep_type': 'cipd', @@ -1611,7 +1611,7 @@ 'packages': [ { 'package': 'skia/tools/goldctl/windows-amd64', - 'version': 'SufM9WryJm4lk56xFxO5xa0VKBqk-rQ7kcVCJl111ecC', + 'version': 'BL1QYX6LBgah6_XEB3KHs9jZiFQtq2z8PUZRswCFvN8C', }, ], 'dep_type': 'cipd', @@ -1621,7 +1621,7 @@ 'packages': [ { 'package': 'skia/tools/goldctl/mac-amd64', - 'version': 'iqXjvpHQMsiYHTsmCxuGGRSb6zp776WuTrwp1k9p_A4C', + 'version': 'WB42GE3e_7-dR5RnBBCICQtMkfpOoJvlT9tMG_6Fj1UC', }, ], 'dep_type': 'cipd', @@ -1635,7 +1635,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@3051bb1cf2055b65b92a93c9f84cf6f189cc6998', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@d86de93cc34524c6dfd3a2e52ff8eaec1bb7ecf4', 'condition': 'checkout_src_internal', },
diff --git a/WATCHLISTS b/WATCHLISTS index 84a4516e..7af6ca7 100644 --- a/WATCHLISTS +++ b/WATCHLISTS
@@ -1094,7 +1094,8 @@ 'ash/system/holding_space|'\ 'chrome/browser/lacros/.*holding_space.*|'\ 'chrome/browser/ui/ash/holding_space|'\ - 'chromeos/crosapi/mojom/.*holding_space.*' + 'chromeos/crosapi/mojom/.*holding_space.*|'\ + 'tools/metrics/histograms/histograms_xml/holding_space' }, 'i18n': { 'filepath': 'base/i18n/|base/string|l10n|icu|'\
diff --git a/android_webview/java/strings/translations/android_webview_strings_hy.xtb b/android_webview/java/strings/translations/android_webview_strings_hy.xtb index 9b01c94f..c79fab3 100644 --- a/android_webview/java/strings/translations/android_webview_strings_hy.xtb +++ b/android_webview/java/strings/translations/android_webview_strings_hy.xtb
@@ -1,6 +1,6 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="hy"> -<translation id="3572484393913897457">Համակարգի WebView արտոնագրեր</translation> +<translation id="3572484393913897457">Համակարգի WebView լիցենզիաներ</translation> <translation id="8916631167640856213">Այս գործառույթը չի աջակցվում Android-ի այս տարբերակում:</translation> </translationbundle> \ No newline at end of file
diff --git a/android_webview/java/strings/translations/android_webview_strings_ru.xtb b/android_webview/java/strings/translations/android_webview_strings_ru.xtb index 4092e1a2..8a3f139 100644 --- a/android_webview/java/strings/translations/android_webview_strings_ru.xtb +++ b/android_webview/java/strings/translations/android_webview_strings_ru.xtb
@@ -1,6 +1,6 @@ <?xml version="1.0" ?> <!DOCTYPE translationbundle> <translationbundle lang="ru"> -<translation id="3572484393913897457">Лицензии системного WebView</translation> +<translation id="3572484393913897457">Лицензии System WebView</translation> <translation id="8916631167640856213">Эта функция не поддерживается в данной версии Android.</translation> </translationbundle> \ No newline at end of file
diff --git a/ash/app_list/BUILD.gn b/ash/app_list/BUILD.gn index fbf8e3d..c5fa9c7b 100644 --- a/ash/app_list/BUILD.gn +++ b/ash/app_list/BUILD.gn
@@ -24,16 +24,16 @@ "app_list_util.cc", "app_list_util.h", "app_list_view_delegate.h", + "bubble/app_list_bubble_apps_page.cc", + "bubble/app_list_bubble_apps_page.h", + "bubble/app_list_bubble_assistant_page.cc", + "bubble/app_list_bubble_assistant_page.h", "bubble/app_list_bubble_event_filter.cc", "bubble/app_list_bubble_event_filter.h", + "bubble/app_list_bubble_search_page.cc", + "bubble/app_list_bubble_search_page.h", "bubble/app_list_bubble_view.cc", "bubble/app_list_bubble_view.h", - "bubble/bubble_apps_page.cc", - "bubble/bubble_apps_page.h", - "bubble/bubble_assistant_page.cc", - "bubble/bubble_assistant_page.h", - "bubble/bubble_search_page.cc", - "bubble/bubble_search_page.h", "bubble/scrollable_apps_grid_view.cc", "bubble/scrollable_apps_grid_view.h", "home_launcher_animation_info.h",
diff --git a/ash/app_list/bubble/bubble_apps_page.cc b/ash/app_list/bubble/app_list_bubble_apps_page.cc similarity index 94% rename from ash/app_list/bubble/bubble_apps_page.cc rename to ash/app_list/bubble/app_list_bubble_apps_page.cc index 97e70b2..8fb47a1 100644 --- a/ash/app_list/bubble/bubble_apps_page.cc +++ b/ash/app_list/bubble/app_list_bubble_apps_page.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/app_list/bubble/bubble_apps_page.h" +#include "ash/app_list/bubble/app_list_bubble_apps_page.h" #include <limits> #include <memory> @@ -32,7 +32,8 @@ } // namespace -BubbleAppsPage::BubbleAppsPage(AppListViewDelegate* view_delegate) { +AppListBubbleAppsPage::AppListBubbleAppsPage( + AppListViewDelegate* view_delegate) { DCHECK(view_delegate); SetUseDefaultFillLayout(true); @@ -97,6 +98,6 @@ scroll->SetContents(std::move(scroll_contents)); } -BubbleAppsPage::~BubbleAppsPage() = default; +AppListBubbleAppsPage::~AppListBubbleAppsPage() = default; } // namespace ash
diff --git a/ash/app_list/bubble/app_list_bubble_apps_page.h b/ash/app_list/bubble/app_list_bubble_apps_page.h new file mode 100644 index 0000000..30ebb62 --- /dev/null +++ b/ash/app_list/bubble/app_list_bubble_apps_page.h
@@ -0,0 +1,30 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_APP_LIST_BUBBLE_APP_LIST_BUBBLE_APPS_PAGE_H_ +#define ASH_APP_LIST_BUBBLE_APP_LIST_BUBBLE_APPS_PAGE_H_ + +#include "ash/ash_export.h" +#include "ui/views/view.h" + +namespace ash { + +class AppListViewDelegate; + +// The default page for the app list bubble / clamshell launcher. Contains a +// scroll view with: +// - Continue section with recent tasks and recent apps +// - Grid of all apps +// Does not include the search box, which is owned by a parent view. +class ASH_EXPORT AppListBubbleAppsPage : public views::View { + public: + explicit AppListBubbleAppsPage(AppListViewDelegate* view_delegate); + AppListBubbleAppsPage(const AppListBubbleAppsPage&) = delete; + AppListBubbleAppsPage& operator=(const AppListBubbleAppsPage&) = delete; + ~AppListBubbleAppsPage() override; +}; + +} // namespace ash + +#endif // ASH_APP_LIST_BUBBLE_APP_LIST_BUBBLE_APPS_PAGE_H_
diff --git a/ash/app_list/bubble/bubble_assistant_page.cc b/ash/app_list/bubble/app_list_bubble_assistant_page.cc similarity index 82% rename from ash/app_list/bubble/bubble_assistant_page.cc rename to ash/app_list/bubble/app_list_bubble_assistant_page.cc index 6079c70..fa511b0 100644 --- a/ash/app_list/bubble/bubble_assistant_page.cc +++ b/ash/app_list/bubble/app_list_bubble_assistant_page.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/app_list/bubble/bubble_assistant_page.h" +#include "ash/app_list/bubble/app_list_bubble_assistant_page.h" #include <memory> #include <utility> @@ -14,7 +14,7 @@ namespace ash { -BubbleAssistantPage::BubbleAssistantPage() { +AppListBubbleAssistantPage::AppListBubbleAssistantPage() { SetLayoutManager( std::make_unique<BoxLayout>(BoxLayout::Orientation::kVertical)); @@ -27,6 +27,6 @@ AddChildView(std::make_unique<views::Label>(u"Assistant")); } -BubbleAssistantPage::~BubbleAssistantPage() = default; +AppListBubbleAssistantPage::~AppListBubbleAssistantPage() = default; } // namespace ash
diff --git a/ash/app_list/bubble/app_list_bubble_assistant_page.h b/ash/app_list/bubble/app_list_bubble_assistant_page.h new file mode 100644 index 0000000..6a3cb50 --- /dev/null +++ b/ash/app_list/bubble/app_list_bubble_assistant_page.h
@@ -0,0 +1,25 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_APP_LIST_BUBBLE_APP_LIST_BUBBLE_ASSISTANT_PAGE_H_ +#define ASH_APP_LIST_BUBBLE_APP_LIST_BUBBLE_ASSISTANT_PAGE_H_ + +#include "ash/ash_export.h" +#include "ui/views/view.h" + +namespace ash { + +// The assistant page for the app list bubble / clamshell launcher. +class ASH_EXPORT AppListBubbleAssistantPage : public views::View { + public: + AppListBubbleAssistantPage(); + AppListBubbleAssistantPage(const AppListBubbleAssistantPage&) = delete; + AppListBubbleAssistantPage& operator=(const AppListBubbleAssistantPage&) = + delete; + ~AppListBubbleAssistantPage() override; +}; + +} // namespace ash + +#endif // ASH_APP_LIST_BUBBLE_APP_LIST_BUBBLE_ASSISTANT_PAGE_H_
diff --git a/ash/app_list/bubble/bubble_search_page.cc b/ash/app_list/bubble/app_list_bubble_search_page.cc similarity index 90% rename from ash/app_list/bubble/bubble_search_page.cc rename to ash/app_list/bubble/app_list_bubble_search_page.cc index 5c0e836..a7a813e2 100644 --- a/ash/app_list/bubble/bubble_search_page.cc +++ b/ash/app_list/bubble/app_list_bubble_search_page.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/app_list/bubble/bubble_search_page.h" +#include "ash/app_list/bubble/app_list_bubble_search_page.h" #include <limits> #include <memory> @@ -18,7 +18,7 @@ namespace ash { -BubbleSearchPage::BubbleSearchPage() { +AppListBubbleSearchPage::AppListBubbleSearchPage() { SetUseDefaultFillLayout(true); // The entire page scrolls. @@ -50,6 +50,6 @@ scroll->SetContents(std::move(scroll_contents)); } -BubbleSearchPage::~BubbleSearchPage() = default; +AppListBubbleSearchPage::~AppListBubbleSearchPage() = default; } // namespace ash
diff --git a/ash/app_list/bubble/app_list_bubble_search_page.h b/ash/app_list/bubble/app_list_bubble_search_page.h new file mode 100644 index 0000000..3fb6024 --- /dev/null +++ b/ash/app_list/bubble/app_list_bubble_search_page.h
@@ -0,0 +1,26 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_APP_LIST_BUBBLE_APP_LIST_BUBBLE_SEARCH_PAGE_H_ +#define ASH_APP_LIST_BUBBLE_APP_LIST_BUBBLE_SEARCH_PAGE_H_ + +#include "ash/ash_export.h" +#include "ui/views/view.h" + +namespace ash { + +// The search results page for the app list bubble / clamshell launcher. +// Contains a scrolling list of search results. Does not include the search box, +// which is owned by a parent view. +class ASH_EXPORT AppListBubbleSearchPage : public views::View { + public: + AppListBubbleSearchPage(); + AppListBubbleSearchPage(const AppListBubbleSearchPage&) = delete; + AppListBubbleSearchPage& operator=(const AppListBubbleSearchPage&) = delete; + ~AppListBubbleSearchPage() override; +}; + +} // namespace ash + +#endif // ASH_APP_LIST_BUBBLE_APP_LIST_BUBBLE_SEARCH_PAGE_H_
diff --git a/ash/app_list/bubble/app_list_bubble_view.cc b/ash/app_list/bubble/app_list_bubble_view.cc index 1983031..1146cc0 100644 --- a/ash/app_list/bubble/app_list_bubble_view.cc +++ b/ash/app_list/bubble/app_list_bubble_view.cc
@@ -6,9 +6,9 @@ #include <memory> -#include "ash/app_list/bubble/bubble_apps_page.h" -#include "ash/app_list/bubble/bubble_assistant_page.h" -#include "ash/app_list/bubble/bubble_search_page.h" +#include "ash/app_list/bubble/app_list_bubble_apps_page.h" +#include "ash/app_list/bubble/app_list_bubble_assistant_page.h" +#include "ash/app_list/bubble/app_list_bubble_search_page.h" #include "ash/public/cpp/shelf_types.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/shelf/shelf.h" @@ -97,12 +97,14 @@ base::BindRepeating(&AppListBubbleView::FlipPage, base::Unretained(this)), u"Flip page")); - apps_page_ = AddChildView(std::make_unique<BubbleAppsPage>(view_delegate)); + apps_page_ = + AddChildView(std::make_unique<AppListBubbleAppsPage>(view_delegate)); - search_page_ = AddChildView(std::make_unique<BubbleSearchPage>()); + search_page_ = AddChildView(std::make_unique<AppListBubbleSearchPage>()); search_page_->SetVisible(false); - assistant_page_ = AddChildView(std::make_unique<BubbleAssistantPage>()); + assistant_page_ = + AddChildView(std::make_unique<AppListBubbleAssistantPage>()); assistant_page_->SetVisible(false); }
diff --git a/ash/app_list/bubble/app_list_bubble_view.h b/ash/app_list/bubble/app_list_bubble_view.h index 07eb8ac..59a8e6c 100644 --- a/ash/app_list/bubble/app_list_bubble_view.h +++ b/ash/app_list/bubble/app_list_bubble_view.h
@@ -14,10 +14,10 @@ namespace ash { +class AppListBubbleAppsPage; +class AppListBubbleAssistantPage; +class AppListBubbleSearchPage; class AppListViewDelegate; -class BubbleAppsPage; -class BubbleAssistantPage; -class BubbleSearchPage; enum class ShelfAlignment; // Contains the views for the bubble version of the launcher. @@ -43,9 +43,9 @@ // TODO(https://crbug.com/1204551): Delete this when search box is hooked up. int visible_page_ = 0; - BubbleAppsPage* apps_page_ = nullptr; - BubbleSearchPage* search_page_ = nullptr; - BubbleAssistantPage* assistant_page_ = nullptr; + AppListBubbleAppsPage* apps_page_ = nullptr; + AppListBubbleSearchPage* search_page_ = nullptr; + AppListBubbleAssistantPage* assistant_page_ = nullptr; }; } // namespace ash
diff --git a/ash/app_list/bubble/bubble_apps_page.h b/ash/app_list/bubble/bubble_apps_page.h deleted file mode 100644 index c97c3a6..0000000 --- a/ash/app_list/bubble/bubble_apps_page.h +++ /dev/null
@@ -1,30 +0,0 @@ -// Copyright 2021 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_APP_LIST_BUBBLE_BUBBLE_APPS_PAGE_H_ -#define ASH_APP_LIST_BUBBLE_BUBBLE_APPS_PAGE_H_ - -#include "ash/ash_export.h" -#include "ui/views/view.h" - -namespace ash { - -class AppListViewDelegate; - -// The default page for the app list bubble / clamshell launcher. Contains a -// scroll view with: -// - Continue section with recent tasks and recent apps -// - Grid of all apps -// Does not include the search box, which is owned by a parent view. -class ASH_EXPORT BubbleAppsPage : public views::View { - public: - explicit BubbleAppsPage(AppListViewDelegate* view_delegate); - BubbleAppsPage(const BubbleAppsPage&) = delete; - BubbleAppsPage& operator=(const BubbleAppsPage&) = delete; - ~BubbleAppsPage() override; -}; - -} // namespace ash - -#endif // ASH_APP_LIST_BUBBLE_BUBBLE_APPS_PAGE_H_
diff --git a/ash/app_list/bubble/bubble_assistant_page.h b/ash/app_list/bubble/bubble_assistant_page.h deleted file mode 100644 index ab3c2f82..0000000 --- a/ash/app_list/bubble/bubble_assistant_page.h +++ /dev/null
@@ -1,24 +0,0 @@ -// Copyright 2021 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_APP_LIST_BUBBLE_BUBBLE_ASSISTANT_PAGE_H_ -#define ASH_APP_LIST_BUBBLE_BUBBLE_ASSISTANT_PAGE_H_ - -#include "ash/ash_export.h" -#include "ui/views/view.h" - -namespace ash { - -// The assistant page for the app list bubble / clamshell launcher. -class ASH_EXPORT BubbleAssistantPage : public views::View { - public: - BubbleAssistantPage(); - BubbleAssistantPage(const BubbleAssistantPage&) = delete; - BubbleAssistantPage& operator=(const BubbleAssistantPage&) = delete; - ~BubbleAssistantPage() override; -}; - -} // namespace ash - -#endif // ASH_APP_LIST_BUBBLE_BUBBLE_ASSISTANT_PAGE_H_
diff --git a/ash/app_list/bubble/bubble_search_page.h b/ash/app_list/bubble/bubble_search_page.h deleted file mode 100644 index d55acbb..0000000 --- a/ash/app_list/bubble/bubble_search_page.h +++ /dev/null
@@ -1,26 +0,0 @@ -// Copyright 2021 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_APP_LIST_BUBBLE_BUBBLE_SEARCH_PAGE_H_ -#define ASH_APP_LIST_BUBBLE_BUBBLE_SEARCH_PAGE_H_ - -#include "ash/ash_export.h" -#include "ui/views/view.h" - -namespace ash { - -// The search results page for the app list bubble / clamshell launcher. -// Contains a scrolling list of search results. Does not include the search box, -// which is owned by a parent view. -class ASH_EXPORT BubbleSearchPage : public views::View { - public: - BubbleSearchPage(); - BubbleSearchPage(const BubbleSearchPage&) = delete; - BubbleSearchPage& operator=(const BubbleSearchPage&) = delete; - ~BubbleSearchPage() override; -}; - -} // namespace ash - -#endif // ASH_APP_LIST_BUBBLE_BUBBLE_SEARCH_PAGE_H_
diff --git a/ash/app_list/bubble/scrollable_apps_grid_view.cc b/ash/app_list/bubble/scrollable_apps_grid_view.cc index 5358020..97bdfc7 100644 --- a/ash/app_list/bubble/scrollable_apps_grid_view.cc +++ b/ash/app_list/bubble/scrollable_apps_grid_view.cc
@@ -82,8 +82,9 @@ return grid_size; } -void ScrollableAppsGridView::MaybeCreateGradientMask() { - // Scrollable apps grid does not have a gradient. +int ScrollableAppsGridView::GetPaddingBetweenPages() const { + // The scrollable apps grid does not use pages. + return 0; } void ScrollableAppsGridView::CalculateIdealBounds() {
diff --git a/ash/app_list/bubble/scrollable_apps_grid_view.h b/ash/app_list/bubble/scrollable_apps_grid_view.h index 9591b3b..58602e2 100644 --- a/ash/app_list/bubble/scrollable_apps_grid_view.h +++ b/ash/app_list/bubble/scrollable_apps_grid_view.h
@@ -29,8 +29,8 @@ gfx::Size GetTileViewSize() const override; gfx::Insets GetTilePadding() const override; gfx::Size GetTileGridSize() const override; + int GetPaddingBetweenPages() const override; void CalculateIdealBounds() override; - void MaybeCreateGradientMask() override; }; } // namespace ash
diff --git a/ash/app_list/views/app_list_item_view.cc b/ash/app_list/views/app_list_item_view.cc index 4c7e2b2..a607356 100644 --- a/ash/app_list/views/app_list_item_view.cc +++ b/ash/app_list/views/app_list_item_view.cc
@@ -21,8 +21,8 @@ #include "ash/strings/grit/ash_strings.h" #include "base/auto_reset.h" #include "base/bind.h" +#include "base/check.h" #include "base/strings/utf_string_conversions.h" -#include "build/build_config.h" #include "cc/paint/paint_flags.h" #include "ui/accessibility/ax_node_data.h" #include "ui/base/l10n/l10n_util.h" @@ -258,8 +258,7 @@ AppListItemView::AppListItemView(AppsGridView* apps_grid_view, AppListItem* item, - AppListViewDelegate* delegate, - bool is_in_folder) + AppListViewDelegate* delegate) : Button(), is_folder_(item->GetItemType() == AppListFolderItem::kItemType), item_weak_(item), @@ -267,6 +266,7 @@ apps_grid_view_(apps_grid_view), is_notification_indicator_enabled_( features::IsNotificationIndicatorEnabled()) { + DCHECK(delegate_); SetFocusBehavior(FocusBehavior::ALWAYS); auto title = std::make_unique<views::Label>(); @@ -283,7 +283,7 @@ // Set background blur for folder icon and use mask layer to clip it into // circle. Note that blur is only enabled in tablet mode to improve dragging // smoothness. - if (apps_grid_view_->IsTabletMode()) + if (delegate_->IsInTabletMode()) SetBackgroundBlurEnabled(true); icon_->SetExtendedState(GetAppListConfig(), false /*extended*/, false /*animate*/); @@ -592,7 +592,7 @@ source_type, metric_params, AppListMenuModelAdapter::FULLSCREEN_APP_GRID, base::BindOnce(&AppListItemView::OnMenuClosed, weak_ptr_factory_.GetWeakPtr()), - apps_grid_view_->IsTabletMode()); + delegate_->IsInTabletMode()); context_menu_->Run(anchor_rect, views::MenuAnchorPosition::kBubbleRight, run_types); apps_grid_view_->SetSelectedView(this);
diff --git a/ash/app_list/views/app_list_item_view.h b/ash/app_list/views/app_list_item_view.h index 5322e86..2e25287b 100644 --- a/ash/app_list/views/app_list_item_view.h +++ b/ash/app_list/views/app_list_item_view.h
@@ -43,8 +43,7 @@ AppListItemView(AppsGridView* apps_grid_view, AppListItem* item, - AppListViewDelegate* delegate, - bool is_in_folder); + AppListViewDelegate* delegate); AppListItemView(const AppListItemView&) = delete; AppListItemView& operator=(const AppListItemView&) = delete; ~AppListItemView() override;
diff --git a/ash/app_list/views/apps_grid_view.cc b/ash/app_list/views/apps_grid_view.cc index 977beed9..050bc25 100644 --- a/ash/app_list/views/apps_grid_view.cc +++ b/ash/app_list/views/apps_grid_view.cc
@@ -33,7 +33,6 @@ #include "ash/public/cpp/app_list/app_list_switches.h" #include "ash/public/cpp/metrics_util.h" #include "ash/public/cpp/pagination/pagination_controller.h" -#include "base/barrier_closure.h" #include "base/bind.h" #include "base/callback_helpers.h" #include "base/guid.h" @@ -47,7 +46,6 @@ #include "ui/aura/window_event_dispatcher.h" #include "ui/base/dragdrop/drag_drop_types.h" #include "ui/base/l10n/l10n_util.h" -#include "ui/compositor/animation_throughput_reporter.h" #include "ui/compositor/layer.h" #include "ui/compositor/scoped_layer_animation_settings.h" #include "ui/display/display.h" @@ -56,7 +54,6 @@ #include "ui/gfx/animation/animation.h" #include "ui/gfx/geometry/vector2d.h" #include "ui/gfx/geometry/vector2d_conversions.h" -#include "ui/gfx/transform_util.h" #include "ui/strings/grit/ui_strings.h" #include "ui/views/accessibility/view_accessibility.h" #include "ui/views/border.h" @@ -87,15 +84,6 @@ // The drag and drop proxy should get scaled by this factor. constexpr float kDragAndDropProxyScale = 1.2f; -// Vertical padding between the apps grid pages in cardified state. -constexpr int kCardifiedPaddingBetweenPages = 12; - -// Horizontal padding of the apps grid page in cardified state. -constexpr int kCardifiedHorizontalPadding = 16; - -// The radius of the corner of the background cards in the apps grid. -constexpr int kBackgroundCardCornerRadius = 12; - // Delays in milliseconds to show re-order preview. constexpr int kReorderDelay = 120; @@ -105,12 +93,6 @@ // Maximum vertical and horizontal spacing between tiles. constexpr int kMaximumTileSpacing = 96; -// The duration in ms for most of the apps grid view animations. -constexpr int kDefaultAnimationDuration = 200; - -// The opacity for the background cards when hidden. -constexpr float kBackgroundCardOpacityHide = 0.0f; - // Animation curve used for fading in the target page when opening or closing // a folder. constexpr gfx::Tween::Type kFolderFadeInTweenType = gfx::Tween::EASE_IN_2; @@ -120,10 +102,6 @@ constexpr gfx::Tween::Type kFolderFadeOutTweenType = gfx::Tween::FAST_OUT_LINEAR_IN; -// Animation curve used for entering and exiting cardified state. -constexpr gfx::Tween::Type kCardifiedStateTweenType = - gfx::Tween::LINEAR_OUT_SLOW_IN; - // RowMoveAnimationDelegate is used when moving an item into a different row. // Before running the animation, the item's layer is re-created and kept in // the original position, then the item is moved to just before its target @@ -195,28 +173,6 @@ DISALLOW_COPY_AND_ASSIGN(ItemRemoveAnimationDelegate); }; -// CardifiedAnimationObserver is used to observe the animation for toggling the -// cardified state of the apps grid view. We used this to ensure app icons are -// repainted with the correct bounds and scale. -class CardifiedAnimationObserver : public ui::ImplicitAnimationObserver { - public: - explicit CardifiedAnimationObserver(base::OnceClosure callback) - : callback_(std::move(callback)) {} - ~CardifiedAnimationObserver() override = default; - - // ui::ImplicitAnimationObserver: - void OnImplicitAnimationsCompleted() override { - if (callback_) - std::move(callback_).Run(); - delete this; - } - - private: - base::OnceClosure callback_; - - DISALLOW_COPY_AND_ASSIGN(CardifiedAnimationObserver); -}; - // ItemMoveAnimationDelegate observes when an item finishes animating when it is // not moving between rows. This is to ensure an item is repainted for the // "zoom out" case when releasing an item being dragged. @@ -312,6 +268,9 @@ // static constexpr float AppsGridView::kCardifiedScale; +// static +constexpr int AppsGridView::kDefaultAnimationDuration; + AppsGridView::AppsGridView(ContentsView* contents_view, AppListViewDelegate* app_list_view_delegate, AppsGridViewFolderDelegate* folder_delegate) @@ -425,14 +384,6 @@ kMaximumTileSpacing * (rows_per_page - 1)); } -int AppsGridView::GetPaddingBetweenPages() const { - // In cardified state, padding between pages should be fixed and it should - // include background card padding. - return cardified_state_ - ? kCardifiedPaddingBetweenPages + 2 * vertical_tile_padding_ - : GetAppListConfig().page_spacing(); -} - void AppsGridView::ResetForShowApps() { ClearDragState(); layer()->SetOpacity(1.0f); @@ -574,8 +525,7 @@ if (!drag_view_) return false; // Drag canceled. - if (!cardified_state_) - StartAppsGridCardifiedView(); + MaybeStartCardifiedView(); gfx::Point drag_point_in_grid_view; ExtractDragLocation(event.root_location(), &drag_point_in_grid_view); @@ -804,7 +754,7 @@ // Compensate drag_source_bounds for the translation of the items_container // during AnimateCardifiedState(). gfx::Point start_position = items_container_->origin(); - EndAppsGridCardifiedView(); + MaybeEndCardifiedView(); drag_source_bounds.Offset( 0, start_position.y() - items_container_->origin().y()); } @@ -899,8 +849,7 @@ // Set the flag in root level grid view. dragging_for_reparent_item_ = true; - if (!cardified_state_) - StartAppsGridCardifiedView(); + MaybeStartCardifiedView(); } void AppsGridView::UpdateDragFromReparentItem(Pointer pointer, @@ -1134,10 +1083,9 @@ } std::unique_ptr<AppListItemView> AppsGridView::CreateViewForItem( - AppListItem* item, - bool is_in_folder) { - std::unique_ptr<AppListItemView> view = std::make_unique<AppListItemView>( - this, item, app_list_view_delegate_, is_in_folder); + AppListItem* item) { + std::unique_ptr<AppListItemView> view = + std::make_unique<AppListItemView>(this, item, app_list_view_delegate_); view->SetCallback(base::BindRepeating(&AppsGridView::OnAppListItemViewPressed, base::Unretained(this), base::Unretained(view.get()))); @@ -1150,7 +1098,7 @@ // may have one more item than |item_list_|. DCHECK_LE(index, item_list_->item_count()); auto* item = item_list_->item_at(index); - return CreateViewForItem(item, item->IsInFolder()); + return CreateViewForItem(item); } void AppsGridView::EnsureViewVisible(const GridIndex& index) { @@ -1801,8 +1749,7 @@ SetViewHidden(drag_view_, false /* show */, true /* no animate */); } - if (cardified_state_) - EndAppsGridCardifiedView(); + MaybeEndCardifiedView(); SetAsFolderDroppingTarget(drop_target_, false); AppListItemView* released_drag_view = nullptr; @@ -1936,161 +1883,6 @@ return contents_view_->app_list_view()->GetAppListConfig(); } -void AppsGridView::StartAppsGridCardifiedView() { - if (!app_list_features::IsNewDragSpecInLauncherEnabled()) - return; - if (folder_delegate_) - return; - DCHECK(!cardified_state_); - StopObservingImplicitAnimations(); - RemoveAllBackgroundCards(); - // Calculate background bounds for a normal grid so it animates from the - // normal to the cardified bounds with the icons. - // Add an extra card for the peeking page in the last page. This hints users - // that apps can be dragged past the last existing page. - for (int i = 0; i < pagination_model_.total_pages() + 1; i++) - AppendBackgroundCard(); - cardified_state_ = true; - UpdateTilePadding(); - MaybeCreateGradientMask(); - AnimateCardifiedState(); -} - -void AppsGridView::EndAppsGridCardifiedView() { - if (!app_list_features::IsNewDragSpecInLauncherEnabled()) - return; - if (folder_delegate_) - return; - DCHECK(cardified_state_); - StopObservingImplicitAnimations(); - cardified_state_ = false; - // Update the padding between tiles, so we can animate back the apps grid - // elements to their original positions. - UpdateTilePadding(); - AnimateCardifiedState(); - layer()->SetClipRect(gfx::Rect()); -} - -void AppsGridView::AnimateCardifiedState() { - if (GetWidget()) { - // Normally Layout() cancels any animations. At this point there may be a - // pending Layout(), force it now so that one isn't triggered part way - // through the animation. Further, ignore this layout so that the position - // isn't reset. - DCHECK(!ignore_layout_); - base::AutoReset<bool> auto_reset(&ignore_layout_, true); - GetWidget()->LayoutRootViewIfNecessary(); - } - - CalculateIdealBounds(); - // Cache the current item container position, as RecenterItemsContainer() may - // change it. - gfx::Point start_position = items_container_->origin(); - RecenterItemsContainer(); - gfx::Vector2d translate_offset( - 0, start_position.y() - items_container_->origin().y()); - if (cardified_state_) { - // The drag view is translated when the items container is recentered. - // Reposition the drag view to compensate for the translation offset. - drag_view_start_ += translate_offset; - drag_view_->SetPosition(drag_view_start_); - } - // Drag view can be nullptr by EndDrag. - const int number_of_views_to_animate = - view_model_.view_size() - (drag_view_ ? 1 : 0); - - base::RepeatingClosure on_bounds_animator_callback; - if (number_of_views_to_animate > 0) { - on_bounds_animator_callback = base::BarrierClosure( - number_of_views_to_animate, - base::BindOnce(&AppsGridView::MaybeCallOnBoundsAnimatorDone, - weak_ptr_factory_.GetWeakPtr())); - bounds_animation_for_cardified_state_in_progress_++; - } - - for (int i = 0; i < view_model_.view_size(); ++i) { - AppListItemView* entry_view = view_model_.view_at(i); - // We don't animate bounds for the dragged view. - if (entry_view == drag_view_) - continue; - // Reposition view bounds to compensate for the translation offset. - gfx::Rect current_bounds = entry_view->bounds(); - current_bounds.Offset(translate_offset); - - entry_view->EnsureLayer(); - - if (cardified_state_) - entry_view->EnterCardifyState(); - else - entry_view->ExitCardifyState(); - - gfx::Rect target_bounds(view_model_.ideal_bounds(i)); - entry_view->SetBoundsRect(target_bounds); - - // View bounds are currently |target_bounds|. Transform the view so it - // appears in |current_bounds|. - gfx::Transform transform = gfx::TransformBetweenRects( - gfx::RectF(target_bounds), gfx::RectF(current_bounds)); - entry_view->layer()->SetTransform(transform); - - ui::ScopedLayerAnimationSettings animator( - entry_view->layer()->GetAnimator()); - animator.SetPreemptionStrategy( - ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); - animator.SetTweenType(kCardifiedStateTweenType); - if (!cardified_state_) { - animator.SetTransitionDuration( - base::TimeDelta::FromMilliseconds(kDefaultAnimationDuration)); - } - // When the animations are done, discard the layer and reset view to - // proper scale. - animator.AddObserver( - new CardifiedAnimationObserver(on_bounds_animator_callback)); - entry_view->layer()->SetTransform(gfx::Transform()); - } - - for (size_t i = 0; i < background_cards_.size(); i++) { - auto& background_card = background_cards_[i]; - // Reposition card bounds to compensate for the translation offset. - gfx::Rect background_bounds = background_card->bounds(); - background_bounds.Offset(translate_offset); - background_card->SetBounds(background_bounds); - ui::ScopedLayerAnimationSettings animator(background_card->GetAnimator()); - animator.SetTweenType(kCardifiedStateTweenType); - animator.SetPreemptionStrategy( - ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); - if (!cardified_state_) { - animator.SetTransitionDuration( - base::TimeDelta::FromMilliseconds(kDefaultAnimationDuration)); - } - animator.AddObserver(this); - ui::AnimationThroughputReporter reporter( - background_card->GetAnimator(), - metrics_util::ForSmoothness( - base::BindRepeating(&ReportCardifiedSmoothness, cardified_state_))); - if (cardified_state_) { - const bool is_active_page = - background_cards_[pagination_model_.selected_page()] == - background_card; - background_card->SetColor( - GetAppListConfig().GetCardifiedBackgroundColor(is_active_page)); - } else { - background_card->SetOpacity(kBackgroundCardOpacityHide); - } - background_card->SetBounds(BackgroundCardBounds(i)); - } - highlighted_page_ = pagination_model_.selected_page(); -} - -void AppsGridView::RecenterItemsContainer() { - const int pages = pagination_model_.total_pages(); - const int current_page = pagination_model_.selected_page(); - const int page_height = GetTileGridSize().height() + GetPaddingBetweenPages(); - items_container_->SetBoundsRect(gfx::Rect(0, -page_height * current_page, - GetContentsBounds().width(), - page_height * pages)); -} - bool AppsGridView::FirePageFlipTimerForTest() { if (!page_flip_timer_.IsRunning()) return false; @@ -2667,64 +2459,6 @@ Layout(); } -gfx::Rect AppsGridView::BackgroundCardBounds(int new_page_index) { - // The size of the grid excluding the outer padding. - const gfx::Size grid_size = GetTileGridSize(); - // The size for the background card that will be displayed. The outer padding - // of the grid need to be added. - const gfx::Size background_card_size = - grid_size + - gfx::Size(2 * horizontal_tile_padding_, 2 * vertical_tile_padding_); - const int padding_between_pages = GetPaddingBetweenPages(); - // The space that each page occupies in the items container. This is the size - // of the grid without outer padding plus the padding between pages. - const int grid_size_height = grid_size.height() + padding_between_pages; - // We position a new card in the last place in items container view. - const int vertical_page_start_offset = grid_size_height * new_page_index; - // Add a padding on the sides to make space for pagination preview. - const int horizontal_padding = - (GetContentsBounds().width() - background_card_size.width()) / 2 + - kCardifiedHorizontalPadding; - // The vertical padding should account for the fadeout mask. - const int vertical_padding = - (GetContentsBounds().height() - background_card_size.height()) / 2 + - GetAppListConfig().grid_fadeout_mask_height(); - return gfx::Rect( - horizontal_padding, vertical_padding + vertical_page_start_offset, - background_card_size.width() - 2 * kCardifiedHorizontalPadding, - background_card_size.height()); -} - -void AppsGridView::AppendBackgroundCard() { - background_cards_.push_back( - std::make_unique<ui::Layer>(ui::LAYER_SOLID_COLOR)); - ui::Layer* current_layer = background_cards_.back().get(); - current_layer->SetBounds(BackgroundCardBounds(background_cards_.size() - 1)); - current_layer->SetVisible(true); - current_layer->SetRoundedCornerRadius( - gfx::RoundedCornersF(kBackgroundCardCornerRadius)); - items_container_->layer()->Add(current_layer); -} - -void AppsGridView::RemoveBackgroundCard() { - items_container_->layer()->Remove(background_cards_.back().get()); - background_cards_.pop_back(); -} - -void AppsGridView::MaskContainerToBackgroundBounds() { - DCHECK(!background_cards_.empty()); - // Mask apps grid container layer to the background card width. - layer()->SetClipRect(gfx::Rect(background_cards_[0]->bounds().x(), 0, - background_cards_[0]->bounds().width(), - layer()->bounds().height())); -} - -void AppsGridView::RemoveAllBackgroundCards() { - for (auto& card : background_cards_) - items_container_->layer()->Remove(card.get()); - background_cards_.clear(); -} - void AppsGridView::OnAppListModelStatusChanged() { UpdatePulsingBlockViews(); Layout(); @@ -2748,6 +2482,8 @@ void AppsGridView::OnImplicitAnimationsCompleted() { if (layer()->opacity() == 0.0f) SetVisible(false); + // TODO(crbug.com/1211608): Refactor animation code so multiple animations + // don't share this method, then move code below to PagedAppsGridView. if (cardified_state_) { MaskContainerToBackgroundBounds(); return; @@ -2772,12 +2508,6 @@ entry.view->DestroyLayer(); } -void AppsGridView::MaybeCallOnBoundsAnimatorDone() { - --bounds_animation_for_cardified_state_in_progress_; - if (bounds_animation_for_cardified_state_in_progress_ == 0) - OnBoundsAnimatorDone(/*animator=*/nullptr); -} - GridIndex AppsGridView::GetNearestTileIndexForPoint( const gfx::Point& point) const { gfx::Rect bounds = GetContentsBounds(); @@ -3222,25 +2952,6 @@ kMaxAppListAppMovingType); } -// TODO(crbug.com/1211608): Move to PagedAppsGridView. -void AppsGridView::UpdateTilePadding() { - gfx::Size content_size = GetContentsBounds().size(); - const gfx::Size tile_size = GetTileViewSize(); - if (cardified_state_) - content_size = gfx::ScaleToRoundedSize(content_size, kCardifiedScale); - - // Item tiles should be evenly distributed in this view. - horizontal_tile_padding_ = - cols_ > 1 ? (content_size.width() - cols_ * tile_size.width()) / - ((cols_ - 1) * 2) - : 0; - vertical_tile_padding_ = - rows_per_page_ > 1 - ? (content_size.height() - rows_per_page_ * tile_size.height()) / - ((rows_per_page_ - 1) * 2) - : 0; -} - int AppsGridView::GetItemsNumOfPage(int page) const { if (page < 0 || page >= pagination_model_.total_pages()) return 0; @@ -3483,21 +3194,4 @@ return new_page_flip_target; } -void AppsGridView::SetHighlightedBackgroundCard(int new_highlighted_page) { - if (!IsValidPageFlipTarget(new_highlighted_page)) - return; - - if (new_highlighted_page != highlighted_page_) { - background_cards_[highlighted_page_]->SetColor( - GetAppListConfig().GetCardifiedBackgroundColor( - /*is_active=*/false)); - if (static_cast<int>(background_cards_.size()) == new_highlighted_page) - AppendBackgroundCard(); - background_cards_[new_highlighted_page]->SetColor( - GetAppListConfig().GetCardifiedBackgroundColor(/*is_active=*/true)); - - highlighted_page_ = new_highlighted_page; - } -} - } // namespace ash
diff --git a/ash/app_list/views/apps_grid_view.h b/ash/app_list/views/apps_grid_view.h index efe581d..405de59 100644 --- a/ash/app_list/views/apps_grid_view.h +++ b/ash/app_list/views/apps_grid_view.h
@@ -20,7 +20,6 @@ #include "ash/app_list/views/app_list_view.h" #include "ash/ash_export.h" #include "ash/public/cpp/pagination/pagination_model.h" -#include "base/memory/ref_counted.h" #include "base/time/time.h" #include "base/timer/timer.h" #include "ui/base/models/list_model_observer.h" @@ -118,9 +117,6 @@ // Returns the maximum size of the entire tile grid. gfx::Size GetMaximumTileGridSize(int cols, int rows_per_page) const; - // Returns the padding between each page of the apps grid. - int GetPaddingBetweenPages() const; - // This resets the grid view to a fresh state for showing the app list. void ResetForShowApps(); @@ -288,29 +284,6 @@ // view hierarchy. const AppListConfig& GetAppListConfig() const; - // Helper functions to start the Apps Grid Cardified state. - // The cardified state scales down apps and is shown when the user drags an - // app in the AppList. - void StartAppsGridCardifiedView(); - // Ends the Apps Grid Cardified state and sets it to normal. - void EndAppsGridCardifiedView(); - // Animates individual elements of the apps grid to and from cardified state. - void AnimateCardifiedState(); - // Translates the items container view to center the current page in the apps - // grid. - void RecenterItemsContainer(); - // Calculates the background bounds for the grid depending on the value of - // |cardified_state_| - gfx::Rect BackgroundCardBounds(int new_page_index); - // Appends a background card to the back of |background_cards_|. - void AppendBackgroundCard(); - // Removes the background card at the end of |background_cards_|. - void RemoveBackgroundCard(); - // Masks the apps grid container to background cards bounds. - void MaskContainerToBackgroundBounds(); - // Removes all background cards from |background_cards_|. - void RemoveAllBackgroundCards(); - // Return the view model. views::ViewModelT<AppListItemView>* view_model() { return &view_model_; } @@ -349,14 +322,13 @@ return bounds_animator_.get(); } - bool cardified_state_for_testing() const { return cardified_state_; } - - int BackgroundCardCountForTesting() const { return background_cards_.size(); } - protected: // The cardified apps grid should be scaled down by this factor. static constexpr float kCardifiedScale = 0.84f; + // The duration in ms for most of the apps grid view animations. + static constexpr int kDefaultAnimationDuration = 200; + // Returns the size of a tile view excluding its padding. virtual gfx::Size GetTileViewSize() const = 0; @@ -366,12 +338,22 @@ // Returns the size of the entire tile grid. virtual gfx::Size GetTileGridSize() const = 0; - // Creates a layer mask for gradient alpha when the feature is enabled. The - // gradient appears at the top and bottom of the apps grid to create a - // "fade out" effect when - // TODO(crbug.com/1211608): Move to PagedAppsGridView when cardified view - // methods move. - virtual void MaybeCreateGradientMask() = 0; + // Returns the padding between each page of the apps grid, or zero if the grid + // does not use pages. + virtual int GetPaddingBetweenPages() const = 0; + + // Starts the "cardified" state if the subclass supports it. + virtual void MaybeStartCardifiedView() {} + + // Ends the "cardified" state if the subclass supports it. + virtual void MaybeEndCardifiedView() {} + + // TODO(crbug.com/1211608): Remove these methods. They exist to allow this + // class to call into PagedAppsGridView from UpdateDrag() and + // OnImplicitAnimationsCompleted(). + virtual void SetHighlightedBackgroundCard(int new_highlighted_page) {} + virtual void MaskContainerToBackgroundBounds() {} + virtual void RemoveAllBackgroundCards() {} // Calculates the item views' bounds for non-folder. virtual void CalculateIdealBounds(); @@ -379,9 +361,6 @@ // Calculates the item views' bounds for folder. void CalculateIdealBoundsForFolder(); - // Update the padding of tile view based on the contents bounds. - void UpdateTilePadding(); - // Gets the bounds of the tile located at |index|, where |index| contains the // page/slot info. gfx::Rect GetExpectedTileBounds(const GridIndex& index) const; @@ -400,10 +379,17 @@ // Cancels any context menus showing for app items on the current page. void CancelContextMenusOnCurrentPage(); + // Returns true if the page is the right target to flip to. + bool IsValidPageFlipTarget(int page) const; + // Starts the page flip timer if |drag_point| is in left/right side page flip // zone or is over page switcher. void MaybeStartPageFlipTimer(const gfx::Point& drag_point); + // views::BoundsAnimatorObserver: + void OnBoundsAnimatorProgressed(views::BoundsAnimator* animator) override; + void OnBoundsAnimatorDone(views::BoundsAnimator* animator) override; + bool ignore_layout() const { return ignore_layout_; } views::BoundsAnimator* bounds_animator() { return bounds_animator_.get(); } views::View* items_container() { return items_container_; } @@ -411,8 +397,6 @@ return pulsing_blocks_model_; } int reorder_placeholder_slot() const { return reorder_placeholder_.slot; } - int vertical_tile_padding() const { return vertical_tile_padding_; } - int horizontal_tile_padding() const { return horizontal_tile_padding_; } const gfx::Point& last_drag_point() const { return last_drag_point_; } bool handling_keyboard_move() const { return handling_keyboard_move_; } @@ -436,13 +420,20 @@ // The location of |drag_view_| when the drag started. gfx::Point drag_view_start_; - // True if the AppList is in cardified state. + // If true, Layout() does nothing. See where set for details. + bool ignore_layout_ = false; + + // True if the AppList is in cardified state. "Cardified" means showing a + // rounded rectangle background "card" behind each page during a drag. The + // grid icons are reduced in size in this state. // TODO(crbug.com/1211608): Move cardified state members to PagedAppsGridView. bool cardified_state_ = false; - // Layer array for apps grid background cards. Used to display the background - // card during cardified state. - std::vector<std::unique_ptr<ui::Layer>> background_cards_; + int bounds_animation_for_cardified_state_in_progress_ = 0; + + // Tile spacing between the tile views. + int horizontal_tile_padding_ = 0; + int vertical_tile_padding_ = 0; private: friend class test::AppsGridViewTestApi; @@ -470,8 +461,7 @@ // number of apps. void UpdatePulsingBlockViews(); - std::unique_ptr<AppListItemView> CreateViewForItem(AppListItem* item, - bool is_in_folder = false); + std::unique_ptr<AppListItemView> CreateViewForItem(AppListItem* item); std::unique_ptr<AppListItemView> CreateViewForItemAtIndex(size_t index); @@ -598,13 +588,6 @@ // ui::ImplicitAnimationObserver overrides: void OnImplicitAnimationsCompleted() override; - // views::BoundsAnimatorObserver: - void OnBoundsAnimatorProgressed(views::BoundsAnimator* animator) override; - void OnBoundsAnimatorDone(views::BoundsAnimator* animator) override; - - // Call OnBoundsAnimatorDone when all layer animations finish. - void MaybeCallOnBoundsAnimatorDone(); - // Hide a given view temporarily without losing (mouse) events and / or // changing the size of it. If |immediate| is set the change will be // immediately applied - otherwise it will change gradually. @@ -712,9 +695,6 @@ // can be moved. bool IsValidReorderTargetIndex(const GridIndex& index) const; - // Returns true if the page is the right target to flip to. - bool IsValidPageFlipTarget(int page) const; - // Returns model index of the item view of the specified item. int GetModelIndexOfItem(const AppListItem* item) const; @@ -795,9 +775,6 @@ // Obtains the target page to flip for |drag_point|. int GetPageFlipTargetForDrag(const gfx::Point& drag_point); - // Updates the highlighted background card. Used only for cardified state. - void SetHighlightedBackgroundCard(int new_highlighted_page); - AppListModel* model_ = nullptr; // Owned by AppListView. AppListItemList* item_list_ = nullptr; // Not owned. @@ -908,10 +885,6 @@ // non-folder. bool extra_page_opened_ = false; - // Tile spacing between the tile views. - int horizontal_tile_padding_ = 0; - int vertical_tile_padding_ = 0; - // The drop location of the most recent reorder related accessibility event. GridIndex last_reorder_a11y_event_location_; @@ -923,16 +896,6 @@ GhostImageView* current_ghost_view_ = nullptr; GhostImageView* last_ghost_view_ = nullptr; - - // If true, Layout() does nothing. See where set for details. - bool ignore_layout_ = false; - - // The highlighted page during cardified state. - int highlighted_page_ = -1; - - int bounds_animation_for_cardified_state_in_progress_ = 0; - - base::WeakPtrFactory<AppsGridView> weak_ptr_factory_{this}; }; } // namespace ash
diff --git a/ash/app_list/views/apps_grid_view_unittest.cc b/ash/app_list/views/apps_grid_view_unittest.cc index 635a0ab..c1c0491 100644 --- a/ash/app_list/views/apps_grid_view_unittest.cc +++ b/ash/app_list/views/apps_grid_view_unittest.cc
@@ -175,7 +175,7 @@ set_display_type(ash::SearchResultDisplayType::kChip); set_is_recommendation(true); } - ~TestSuggestedSearchResult() override {} + ~TestSuggestedSearchResult() override = default; private: DISALLOW_COPY_AND_ASSIGN(TestSuggestedSearchResult); @@ -412,10 +412,10 @@ apps_grid_view_->MoveItemInModel(item_view, target); } - TestAppListColorProvider color_provider_; // Needed by AppListView. - AppListView* app_list_view_ = nullptr; // Owned by native widget. - AppsGridView* apps_grid_view_ = nullptr; // Owned by |app_list_view_|. - ContentsView* contents_view_ = nullptr; // Owned by |app_list_view_|. + TestAppListColorProvider color_provider_; // Needed by AppListView. + AppListView* app_list_view_ = nullptr; // Owned by native widget. + PagedAppsGridView* apps_grid_view_ = nullptr; // Owned by |app_list_view_|. + ContentsView* contents_view_ = nullptr; // Owned by |app_list_view_|. SearchResultContainerView* suggestions_container_ = nullptr; // Owned by |apps_grid_view_|. ExpandArrowView* expand_arrow_view_ = nullptr; // Owned by |apps_grid_view_|.
diff --git a/ash/app_list/views/paged_apps_grid_view.cc b/ash/app_list/views/paged_apps_grid_view.cc index 3ae00b6e..c4c944e 100644 --- a/ash/app_list/views/paged_apps_grid_view.cc +++ b/ash/app_list/views/paged_apps_grid_view.cc
@@ -5,20 +5,27 @@ #include "ash/app_list/views/paged_apps_grid_view.h" #include <algorithm> +#include <utility> #include "ash/app_list/views/app_list_item_view.h" #include "ash/app_list/views/app_list_main_view.h" #include "ash/app_list/views/contents_view.h" #include "ash/public/cpp/app_list/app_list_config.h" +#include "ash/public/cpp/app_list/app_list_features.h" #include "ash/public/cpp/ash_features.h" #include "ash/public/cpp/pagination/pagination_controller.h" #include "ash/public/cpp/pagination/pagination_model.h" +#include "base/barrier_closure.h" +#include "base/bind.h" +#include "base/callback.h" #include "base/check.h" #include "base/metrics/histogram_macros.h" #include "cc/paint/paint_flags.h" #include "third_party/skia/include/core/SkColor.h" +#include "ui/compositor/animation_throughput_reporter.h" #include "ui/compositor/layer.h" #include "ui/compositor/paint_recorder.h" +#include "ui/compositor/scoped_layer_animation_settings.h" #include "ui/events/event.h" #include "ui/events/types/event_type.h" #include "ui/gfx/canvas.h" @@ -30,6 +37,7 @@ #include "ui/gfx/geometry/vector2d_f.h" #include "ui/gfx/skia_paint_util.h" #include "ui/gfx/transform.h" +#include "ui/gfx/transform_util.h" #include "ui/views/paint_info.h" #include "ui/views/view.h" #include "ui/views/view_model_utils.h" @@ -49,6 +57,45 @@ "Apps.PaginationTransition.DragScroll.PresentationTime.MaxLatency." "TabletMode"; +// Vertical padding between the apps grid pages in cardified state. +constexpr int kCardifiedPaddingBetweenPages = 12; + +// Horizontal padding of the apps grid page in cardified state. +constexpr int kCardifiedHorizontalPadding = 16; + +// The radius of the corner of the background cards in the apps grid. +constexpr int kBackgroundCardCornerRadius = 12; + +// The opacity for the background cards when hidden. +constexpr float kBackgroundCardOpacityHide = 0.0f; + +// Animation curve used for entering and exiting cardified state. +constexpr gfx::Tween::Type kCardifiedStateTweenType = + gfx::Tween::LINEAR_OUT_SLOW_IN; + +// CardifiedAnimationObserver is used to observe the animation for toggling the +// cardified state of the apps grid view. We used this to ensure app icons are +// repainted with the correct bounds and scale. +class CardifiedAnimationObserver : public ui::ImplicitAnimationObserver { + public: + explicit CardifiedAnimationObserver(base::OnceClosure callback) + : callback_(std::move(callback)) {} + CardifiedAnimationObserver(const CardifiedAnimationObserver&) = delete; + CardifiedAnimationObserver& operator=(const CardifiedAnimationObserver&) = + delete; + ~CardifiedAnimationObserver() override = default; + + // ui::ImplicitAnimationObserver: + void OnImplicitAnimationsCompleted() override { + if (callback_) + std::move(callback_).Run(); + delete this; + } + + private: + base::OnceClosure callback_; +}; + } // namespace // A layer delegate used for PagedAppsGridView's mask layer, with top and bottom @@ -408,7 +455,7 @@ GetAppListConfig().grid_tile_spacing_in_folder() / 2; return gfx::Insets(-tile_padding_in_folder, -tile_padding_in_folder); } - return gfx::Insets(-vertical_tile_padding(), -horizontal_tile_padding()); + return gfx::Insets(-vertical_tile_padding_, -horizontal_tile_padding_); } gfx::Size PagedAppsGridView::GetTileGridSize() const { @@ -419,22 +466,22 @@ return rect.size(); } -void PagedAppsGridView::MaybeCreateGradientMask() { - if (!is_in_folder() && features::IsBackgroundBlurEnabled()) { - // TODO(newcomer): Improve implementation of the mask layer so we can - // enable it on all devices https://crbug.com/765292. - if (!layer()->layer_mask_layer()) { - // Always create a new layer. The layer may be recreated by animation, - // and using the mask layer used by the detached layer can lead to - // crash. b/118822974. - if (!fadeout_layer_delegate_) { - fadeout_layer_delegate_ = std::make_unique<FadeoutLayerDelegate>( - GetAppListConfig().grid_fadeout_mask_height()); - fadeout_layer_delegate_->layer()->SetBounds(layer()->bounds()); - } - layer()->SetMaskLayer(fadeout_layer_delegate_->layer()); - } - } +int PagedAppsGridView::GetPaddingBetweenPages() const { + // In cardified state, padding between pages should be fixed and it should + // include background card padding. + return cardified_state_ + ? kCardifiedPaddingBetweenPages + 2 * vertical_tile_padding_ + : GetAppListConfig().page_spacing(); +} + +void PagedAppsGridView::MaybeStartCardifiedView() { + if (!cardified_state_) + StartAppsGridCardifiedView(); +} + +void PagedAppsGridView::MaybeEndCardifiedView() { + if (cardified_state_) + EndAppsGridCardifiedView(); } //////////////////////////////////////////////////////////////////////////////// @@ -617,4 +664,276 @@ return true; } +void PagedAppsGridView::MaybeCreateGradientMask() { + if (!is_in_folder() && features::IsBackgroundBlurEnabled()) { + // TODO(newcomer): Improve implementation of the mask layer so we can + // enable it on all devices https://crbug.com/765292. + if (!layer()->layer_mask_layer()) { + // Always create a new layer. The layer may be recreated by animation, + // and using the mask layer used by the detached layer can lead to + // crash. b/118822974. + if (!fadeout_layer_delegate_) { + fadeout_layer_delegate_ = std::make_unique<FadeoutLayerDelegate>( + GetAppListConfig().grid_fadeout_mask_height()); + fadeout_layer_delegate_->layer()->SetBounds(layer()->bounds()); + } + layer()->SetMaskLayer(fadeout_layer_delegate_->layer()); + } + } +} + +void PagedAppsGridView::StartAppsGridCardifiedView() { + if (!app_list_features::IsNewDragSpecInLauncherEnabled()) + return; + if (is_in_folder()) + return; + DCHECK(!cardified_state_); + StopObservingImplicitAnimations(); + RemoveAllBackgroundCards(); + // Calculate background bounds for a normal grid so it animates from the + // normal to the cardified bounds with the icons. + // Add an extra card for the peeking page in the last page. This hints users + // that apps can be dragged past the last existing page. + for (int i = 0; i < pagination_model_.total_pages() + 1; i++) + AppendBackgroundCard(); + cardified_state_ = true; + UpdateTilePadding(); + MaybeCreateGradientMask(); + AnimateCardifiedState(); +} + +void PagedAppsGridView::EndAppsGridCardifiedView() { + if (!app_list_features::IsNewDragSpecInLauncherEnabled()) + return; + if (is_in_folder()) + return; + DCHECK(cardified_state_); + StopObservingImplicitAnimations(); + cardified_state_ = false; + // Update the padding between tiles, so we can animate back the apps grid + // elements to their original positions. + UpdateTilePadding(); + AnimateCardifiedState(); + layer()->SetClipRect(gfx::Rect()); +} + +void PagedAppsGridView::AnimateCardifiedState() { + if (GetWidget()) { + // Normally Layout() cancels any animations. At this point there may be a + // pending Layout(), force it now so that one isn't triggered part way + // through the animation. Further, ignore this layout so that the position + // isn't reset. + DCHECK(!ignore_layout_); + base::AutoReset<bool> auto_reset(&ignore_layout_, true); + GetWidget()->LayoutRootViewIfNecessary(); + } + + CalculateIdealBounds(); + // Cache the current item container position, as RecenterItemsContainer() may + // change it. + gfx::Point start_position = items_container()->origin(); + RecenterItemsContainer(); + gfx::Vector2d translate_offset( + 0, start_position.y() - items_container()->origin().y()); + if (cardified_state_) { + // The drag view is translated when the items container is recentered. + // Reposition the drag view to compensate for the translation offset. + drag_view_start_ += translate_offset; + drag_view_->SetPosition(drag_view_start_); + } + // Drag view can be nullptr by EndDrag. + const int number_of_views_to_animate = + view_model()->view_size() - (drag_view_ ? 1 : 0); + + base::RepeatingClosure on_bounds_animator_callback; + if (number_of_views_to_animate > 0) { + on_bounds_animator_callback = base::BarrierClosure( + number_of_views_to_animate, + base::BindOnce(&PagedAppsGridView::MaybeCallOnBoundsAnimatorDone, + weak_ptr_factory_.GetWeakPtr())); + bounds_animation_for_cardified_state_in_progress_++; + } + + for (int i = 0; i < view_model()->view_size(); ++i) { + AppListItemView* entry_view = view_model()->view_at(i); + // We don't animate bounds for the dragged view. + if (entry_view == drag_view_) + continue; + // Reposition view bounds to compensate for the translation offset. + gfx::Rect current_bounds = entry_view->bounds(); + current_bounds.Offset(translate_offset); + + entry_view->EnsureLayer(); + + if (cardified_state_) + entry_view->EnterCardifyState(); + else + entry_view->ExitCardifyState(); + + gfx::Rect target_bounds(view_model()->ideal_bounds(i)); + entry_view->SetBoundsRect(target_bounds); + + // View bounds are currently |target_bounds|. Transform the view so it + // appears in |current_bounds|. + gfx::Transform transform = gfx::TransformBetweenRects( + gfx::RectF(target_bounds), gfx::RectF(current_bounds)); + entry_view->layer()->SetTransform(transform); + + ui::ScopedLayerAnimationSettings animator( + entry_view->layer()->GetAnimator()); + animator.SetPreemptionStrategy( + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + animator.SetTweenType(kCardifiedStateTweenType); + if (!cardified_state_) { + animator.SetTransitionDuration( + base::TimeDelta::FromMilliseconds(kDefaultAnimationDuration)); + } + // When the animations are done, discard the layer and reset view to + // proper scale. + animator.AddObserver( + new CardifiedAnimationObserver(on_bounds_animator_callback)); + entry_view->layer()->SetTransform(gfx::Transform()); + } + + for (size_t i = 0; i < background_cards_.size(); i++) { + auto& background_card = background_cards_[i]; + // Reposition card bounds to compensate for the translation offset. + gfx::Rect background_bounds = background_card->bounds(); + background_bounds.Offset(translate_offset); + background_card->SetBounds(background_bounds); + ui::ScopedLayerAnimationSettings animator(background_card->GetAnimator()); + animator.SetTweenType(kCardifiedStateTweenType); + animator.SetPreemptionStrategy( + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + if (!cardified_state_) { + animator.SetTransitionDuration( + base::TimeDelta::FromMilliseconds(kDefaultAnimationDuration)); + } + animator.AddObserver(this); + ui::AnimationThroughputReporter reporter( + background_card->GetAnimator(), + metrics_util::ForSmoothness( + base::BindRepeating(&ReportCardifiedSmoothness, cardified_state_))); + if (cardified_state_) { + const bool is_active_page = + background_cards_[pagination_model_.selected_page()] == + background_card; + background_card->SetColor( + GetAppListConfig().GetCardifiedBackgroundColor(is_active_page)); + } else { + background_card->SetOpacity(kBackgroundCardOpacityHide); + } + background_card->SetBounds(BackgroundCardBounds(i)); + } + highlighted_page_ = pagination_model_.selected_page(); +} + +void PagedAppsGridView::MaybeCallOnBoundsAnimatorDone() { + --bounds_animation_for_cardified_state_in_progress_; + if (bounds_animation_for_cardified_state_in_progress_ == 0) + OnBoundsAnimatorDone(/*animator=*/nullptr); +} + +void PagedAppsGridView::RecenterItemsContainer() { + const int pages = pagination_model_.total_pages(); + const int current_page = pagination_model_.selected_page(); + const int page_height = GetTileGridSize().height() + GetPaddingBetweenPages(); + items_container()->SetBoundsRect(gfx::Rect(0, -page_height * current_page, + GetContentsBounds().width(), + page_height * pages)); +} + +gfx::Rect PagedAppsGridView::BackgroundCardBounds(int new_page_index) { + // The size of the grid excluding the outer padding. + const gfx::Size grid_size = GetTileGridSize(); + // The size for the background card that will be displayed. The outer padding + // of the grid need to be added. + const gfx::Size background_card_size = + grid_size + + gfx::Size(2 * horizontal_tile_padding_, 2 * vertical_tile_padding_); + const int padding_between_pages = GetPaddingBetweenPages(); + // The space that each page occupies in the items container. This is the size + // of the grid without outer padding plus the padding between pages. + const int grid_size_height = grid_size.height() + padding_between_pages; + // We position a new card in the last place in items container view. + const int vertical_page_start_offset = grid_size_height * new_page_index; + // Add a padding on the sides to make space for pagination preview. + const int horizontal_padding = + (GetContentsBounds().width() - background_card_size.width()) / 2 + + kCardifiedHorizontalPadding; + // The vertical padding should account for the fadeout mask. + const int vertical_padding = + (GetContentsBounds().height() - background_card_size.height()) / 2 + + GetAppListConfig().grid_fadeout_mask_height(); + return gfx::Rect( + horizontal_padding, vertical_padding + vertical_page_start_offset, + background_card_size.width() - 2 * kCardifiedHorizontalPadding, + background_card_size.height()); +} + +void PagedAppsGridView::AppendBackgroundCard() { + background_cards_.push_back( + std::make_unique<ui::Layer>(ui::LAYER_SOLID_COLOR)); + ui::Layer* current_layer = background_cards_.back().get(); + current_layer->SetBounds(BackgroundCardBounds(background_cards_.size() - 1)); + current_layer->SetVisible(true); + current_layer->SetRoundedCornerRadius( + gfx::RoundedCornersF(kBackgroundCardCornerRadius)); + items_container()->layer()->Add(current_layer); +} + +void PagedAppsGridView::RemoveBackgroundCard() { + items_container()->layer()->Remove(background_cards_.back().get()); + background_cards_.pop_back(); +} + +void PagedAppsGridView::MaskContainerToBackgroundBounds() { + DCHECK(!background_cards_.empty()); + // Mask apps grid container layer to the background card width. + layer()->SetClipRect(gfx::Rect(background_cards_[0]->bounds().x(), 0, + background_cards_[0]->bounds().width(), + layer()->bounds().height())); +} + +void PagedAppsGridView::RemoveAllBackgroundCards() { + for (auto& card : background_cards_) + items_container()->layer()->Remove(card.get()); + background_cards_.clear(); +} + +void PagedAppsGridView::SetHighlightedBackgroundCard(int new_highlighted_page) { + if (!IsValidPageFlipTarget(new_highlighted_page)) + return; + + if (new_highlighted_page != highlighted_page_) { + background_cards_[highlighted_page_]->SetColor( + GetAppListConfig().GetCardifiedBackgroundColor( + /*is_active=*/false)); + if (static_cast<int>(background_cards_.size()) == new_highlighted_page) + AppendBackgroundCard(); + background_cards_[new_highlighted_page]->SetColor( + GetAppListConfig().GetCardifiedBackgroundColor(/*is_active=*/true)); + + highlighted_page_ = new_highlighted_page; + } +} + +void PagedAppsGridView::UpdateTilePadding() { + gfx::Size content_size = GetContentsBounds().size(); + const gfx::Size tile_size = GetTileViewSize(); + if (cardified_state_) + content_size = gfx::ScaleToRoundedSize(content_size, kCardifiedScale); + + // Item tiles should be evenly distributed in this view. + horizontal_tile_padding_ = + cols() > 1 ? (content_size.width() - cols() * tile_size.width()) / + ((cols() - 1) * 2) + : 0; + vertical_tile_padding_ = + rows_per_page() > 1 + ? (content_size.height() - rows_per_page() * tile_size.height()) / + ((rows_per_page() - 1) * 2) + : 0; +} + } // namespace ash
diff --git a/ash/app_list/views/paged_apps_grid_view.h b/ash/app_list/views/paged_apps_grid_view.h index 3c52026..e4b98b3 100644 --- a/ash/app_list/views/paged_apps_grid_view.h +++ b/ash/app_list/views/paged_apps_grid_view.h
@@ -6,10 +6,12 @@ #define ASH_APP_LIST_VIEWS_PAGED_APPS_GRID_VIEW_H_ #include <memory> +#include <vector> #include "ash/app_list/views/apps_grid_view.h" #include "ash/ash_export.h" #include "ash/public/cpp/pagination/pagination_model_observer.h" +#include "base/memory/ref_counted.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/compositor/throughput_tracker.h" #include "ui/events/types/event_type.h" @@ -19,6 +21,10 @@ class Vector2d; } // namespace gfx +namespace ui { +class Layer; +} // namespace ui + namespace ash { class ContentsView; @@ -56,7 +62,9 @@ gfx::Size GetTileViewSize() const override; gfx::Insets GetTilePadding() const override; gfx::Size GetTileGridSize() const override; - void MaybeCreateGradientMask() override; + int GetPaddingBetweenPages() const override; + void MaybeStartCardifiedView() override; + void MaybeEndCardifiedView() override; // PaginationModelObserver: void TotalPagesChanged(int previous_page_count, int new_page_count) override; @@ -68,6 +76,9 @@ void ScrollStarted() override; void ScrollEnded() override; + bool cardified_state_for_testing() const { return cardified_state_; } + int BackgroundCardCountForTesting() const { return background_cards_.size(); } + private: class FadeoutLayerDelegate; @@ -75,6 +86,42 @@ // handled by PagedAppsGridView. bool ShouldHandleDragEvent(const ui::LocatedEvent& event); + // Creates a layer mask for gradient alpha when the feature is enabled. The + // gradient appears at the top and bottom of the apps grid to create a + // "fade out" effect when + void MaybeCreateGradientMask(); + + // Helper functions to start the Apps Grid Cardified state. + // The cardified state scales down apps and is shown when the user drags an + // app in the AppList. + void StartAppsGridCardifiedView(); + // Ends the Apps Grid Cardified state and sets it to normal. + void EndAppsGridCardifiedView(); + // Animates individual elements of the apps grid to and from cardified state. + void AnimateCardifiedState(); + // Call OnBoundsAnimatorDone when all layer animations finish. + void MaybeCallOnBoundsAnimatorDone(); + // Translates the items container view to center the current page in the apps + // grid. + void RecenterItemsContainer(); + // Calculates the background bounds for the grid depending on the value of + // |cardified_state_| + gfx::Rect BackgroundCardBounds(int new_page_index); + // Appends a background card to the back of |background_cards_|. + void AppendBackgroundCard(); + // Removes the background card at the end of |background_cards_|. + void RemoveBackgroundCard(); + // Masks the apps grid container to background cards bounds. + // TODO(crbug.com/1211608): Remove "override" from these methods. + void MaskContainerToBackgroundBounds() override; + // Removes all background cards from |background_cards_|. + void RemoveAllBackgroundCards() override; + // Updates the highlighted background card. Used only for cardified state. + void SetHighlightedBackgroundCard(int new_highlighted_page) override; + + // Update the padding of tile view based on the contents bounds. + void UpdateTilePadding(); + // Created by AppListMainView, owned by views hierarchy. ContentsView* const contents_view_; @@ -100,6 +147,15 @@ // Records the presentation time for apps grid dragging. std::unique_ptr<PresentationTimeRecorder> presentation_time_recorder_; + + // The highlighted page during cardified state. + int highlighted_page_ = -1; + + // Layer array for apps grid background cards. Used to display the background + // card during cardified state. + std::vector<std::unique_ptr<ui::Layer>> background_cards_; + + base::WeakPtrFactory<PagedAppsGridView> weak_ptr_factory_{this}; }; } // namespace ash
diff --git a/ash/clipboard/clipboard_history_controller_impl.cc b/ash/clipboard/clipboard_history_controller_impl.cc index d6782a5..b1122e9 100644 --- a/ash/clipboard/clipboard_history_controller_impl.cc +++ b/ash/clipboard/clipboard_history_controller_impl.cc
@@ -359,6 +359,8 @@ } } item_value.SetKey("id", base::Value(item.id().ToString())); + item_value.SetKey("timeCopied", + base::Value(item.time_copied().ToJsTimeIgnoringNull())); item_results.Append(std::move(item_value)); }
diff --git a/ash/clipboard/clipboard_history_item.cc b/ash/clipboard/clipboard_history_item.cc index 11fb9c0..2d72aa6 100644 --- a/ash/clipboard/clipboard_history_item.cc +++ b/ash/clipboard/clipboard_history_item.cc
@@ -7,7 +7,9 @@ namespace ash { ClipboardHistoryItem::ClipboardHistoryItem(ui::ClipboardData data) - : id_(base::UnguessableToken::Create()), data_(std::move(data)) {} + : id_(base::UnguessableToken::Create()), + data_(std::move(data)), + time_copied_(base::Time::Now()) {} ClipboardHistoryItem::ClipboardHistoryItem(const ClipboardHistoryItem&) = default;
diff --git a/ash/clipboard/clipboard_history_item.h b/ash/clipboard/clipboard_history_item.h index 704c787..7c949c7 100644 --- a/ash/clipboard/clipboard_history_item.h +++ b/ash/clipboard/clipboard_history_item.h
@@ -6,6 +6,9 @@ #define ASH_CLIPBOARD_CLIPBOARD_HISTORY_ITEM_H_ #include "ash/ash_export.h" +#include "base/i18n/time_formatting.h" +#include "base/strings/utf_string_conversions.h" +#include "base/time/time.h" #include "base/unguessable_token.h" #include "ui/base/clipboard/clipboard_data.h" @@ -27,11 +30,13 @@ const base::UnguessableToken& id() const { return id_; } const ui::ClipboardData& data() const { return data_; } + const base::Time time_copied() const { return time_copied_; } private: // Unique identifier. base::UnguessableToken id_; ui::ClipboardData data_; + base::Time time_copied_; }; } // namespace ash
diff --git a/ash/content/shimless_rma/resources/fake_data.js b/ash/content/shimless_rma/resources/fake_data.js index d603c1f..ac132e8 100644 --- a/ash/content/shimless_rma/resources/fake_data.js +++ b/ash/content/shimless_rma/resources/fake_data.js
@@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import {Component, ComponentRepairState, ComponentType, RmadErrorCode, RmaState, State} from './shimless_rma_types.js'; +import {Component, ComponentRepairState, ComponentType, RmadErrorCode, RmaState, StateResult} from './shimless_rma_types.js'; -/** @type {!Array<!State>} */ +/** @type {!Array<!StateResult>} */ export const fakeStates = [ {state: RmaState.kWelcomeScreen, error: RmadErrorCode.kOk}, {state: RmaState.kUpdateChrome, error: RmadErrorCode.kOk},
diff --git a/ash/content/shimless_rma/resources/fake_shimless_rma_service.js b/ash/content/shimless_rma/resources/fake_shimless_rma_service.js index 70748644..b32b11be 100644 --- a/ash/content/shimless_rma/resources/fake_shimless_rma_service.js +++ b/ash/content/shimless_rma/resources/fake_shimless_rma_service.js
@@ -6,7 +6,7 @@ import {FakeObservables} from 'chrome://resources/ash/common/fake_observables.js'; import {assert} from 'chrome://resources/js/assert.m.js'; -import {CalibrationComponent, CalibrationObserver, Component, ComponentRepairState, ComponentType, CurrentState, ErrorObserver, HardwareWriteProtectionStateObserver, NextState, PowerCableStateObserver, PrevState, ProvisioningObserver, ProvisioningStep, RmadErrorCode, RmaState, ShimlessRmaServiceInterface, State} from './shimless_rma_types.js'; +import {CalibrationComponent, CalibrationObserver, Component, ComponentRepairState, ComponentType, ErrorObserver, HardwareWriteProtectionStateObserver, PowerCableStateObserver, ProvisioningObserver, ProvisioningStep, RmadErrorCode, RmaState, ShimlessRmaServiceInterface, StateResult} from './shimless_rma_types.js'; /** @implements {ShimlessRmaServiceInterface} */ export class FakeShimlessRmaService { @@ -16,7 +16,7 @@ /** * The list of states for this RMA flow. - * @private {!Array<!State>} + * @private {!Array<!StateResult>} */ this.states_ = []; @@ -81,7 +81,7 @@ * list, and return kTransitionFailed if it would move off either end. * getCurrentState always return the state at the current index. * - * @param {!Array<!State>} states + * @param {!Array<!StateResult>} states */ setStates(states) { this.states_ = states; @@ -89,7 +89,7 @@ } /** - * @return {!Promise<!CurrentState>} + * @return {!Promise<!StateResult>} */ getCurrentState() { // As getNextState and getPrevState can modify the result of this function @@ -108,7 +108,7 @@ } /** - * @return {!Promise<!NextState>} + * @return {!Promise<!StateResult>} */ getNextState() { // As getNextState and getPrevState can modify the result of this function @@ -130,7 +130,7 @@ } /** - * @return {!Promise<!PrevState>} + * @return {!Promise<!StateResult>} */ getPrevState() { // As getNextState and getPrevState can modify the result of this function @@ -210,7 +210,7 @@ } /** - * @return {!Promise<!NextState>} + * @return {!Promise<!StateResult>} */ setSameOwner() { return this.getNextStateForMethod_( @@ -218,7 +218,7 @@ } /** - * @return {!Promise<!NextState>} + * @return {!Promise<!StateResult>} */ setDifferentOwner() { return this.getNextStateForMethod_( @@ -241,7 +241,7 @@ } /** - * @return {!Promise<!NextState>} + * @return {!Promise<!StateResult>} */ chooseManuallyDisableWriteProtect() { return this.getNextStateForMethod_( @@ -250,7 +250,7 @@ } /** - * @return {!Promise<!NextState>} + * @return {!Promise<!StateResult>} */ chooseRsuDisableWriteProtect() { return this.getNextStateForMethod_( @@ -260,7 +260,7 @@ /** * @param {string} code - * @return {!Promise<!NextState>} + * @return {!Promise<!StateResult>} */ setRsuDisableWriteProtectCode(code) { // TODO(gavindodd): Send the code over mojo. @@ -285,7 +285,7 @@ /** * @param {!Array<!Component>} components - * @return {!Promise<!NextState>} + * @return {!Promise<!StateResult>} */ setComponentsRepairState(components) { return this.getNextStateForMethod_( @@ -293,7 +293,7 @@ } /** - * @return {!Promise<!NextState>} + * @return {!Promise<!StateResult>} */ reworkMainboard() { return this.getNextStateForMethod_( @@ -315,7 +315,7 @@ } /** - * @return {!Promise<!NextState>} + * @return {!Promise<!StateResult>} */ reimageSkipped() { return this.getNextStateForMethod_( @@ -323,7 +323,7 @@ } /** - * @return {!Promise<!NextState>} + * @return {!Promise<!StateResult>} */ reimageFromDownload() { return this.getNextStateForMethod_( @@ -331,7 +331,7 @@ } /** - * @return {!Promise<!NextState>} + * @return {!Promise<!StateResult>} */ reimageFromUsb() { return this.getNextStateForMethod_( @@ -741,29 +741,29 @@ * @private * @param {string} method * @param {!RmaState} expectedState - * @returns {!Promise<!NextState>} + * @returns {!Promise<!StateResult>} */ getNextStateForMethod_(method, expectedState) { if (this.states_.length === 0) { - this.setFakeNextStateForMethod_( + this.setFakeStateForMethod_( method, RmaState.kUnknown, RmadErrorCode.kRmaNotRequired); } else if (this.stateIndex_ >= this.states_.length - 1) { // It should not be possible for stateIndex_ to be out of range unless // there is a bug in the fake. assert(this.stateIndex_ < this.states_.length); let state = this.states_[this.stateIndex_]; - this.setFakeNextStateForMethod_( + this.setFakeStateForMethod_( method, state.state, RmadErrorCode.kTransitionFailed); } else if (this.states_[this.stateIndex_].state !== expectedState) { // Error: Called in wrong state. let state = this.states_[this.stateIndex_]; - this.setFakeNextStateForMethod_( + this.setFakeStateForMethod_( method, state.state, RmadErrorCode.kRequestInvalid); } else { // Success. this.stateIndex_++; let state = this.states_[this.stateIndex_]; - this.setFakeNextStateForMethod_(method, state.state, state.error); + this.setFakeStateForMethod_(method, state.state, state.error); } return this.methods_.resolveMethod(method); } @@ -775,20 +775,7 @@ * @param {!RmadErrorCode} error */ setFakeCurrentState_(state, error) { - this.methods_.setResult( - 'getCurrentState', {currentState: state, error: error}); - } - - /** - * Sets the value that will be returned when calling state specific functions - * that progress state. e.g. setSameOwner() - * @private - * @param {string} method - * @param {!RmaState} state - * @param {!RmadErrorCode} error - */ - setFakeNextStateForMethod_(method, state, error) { - this.methods_.setResult(method, {nextState: state, error: error}); + this.setFakeStateForMethod_('getCurrentState', state, error); } /** @@ -798,7 +785,7 @@ * @param {!RmadErrorCode} error */ setFakeNextState_(state, error) { - this.methods_.setResult('getNextState', {nextState: state, error: error}); + this.setFakeStateForMethod_('getNextState', state, error); } /** @@ -808,6 +795,19 @@ * @param {!RmadErrorCode} error */ setFakePrevState_(state, error) { - this.methods_.setResult('getPrevState', {prevState: state, error: error}); + this.setFakeStateForMethod_('getPrevState', state, error); + } + + /** + * Sets the value that will be returned when calling state specific functions + * that update state. e.g. setSameOwner() + * @private + * @param {string} method + * @param {!RmaState} state + * @param {!RmadErrorCode} error + */ + setFakeStateForMethod_(method, state, error) { + this.methods_.setResult( + method, /** @type {!StateResult} */ ({state: state, error: error})); } }
diff --git a/ash/content/shimless_rma/resources/shimless_rma.js b/ash/content/shimless_rma/resources/shimless_rma.js index 5757b7fa..e9d244e 100644 --- a/ash/content/shimless_rma/resources/shimless_rma.js +++ b/ash/content/shimless_rma/resources/shimless_rma.js
@@ -16,7 +16,7 @@ import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {getShimlessRmaService} from './mojo_interface_provider.js'; -import {CurrentState, NextState, PrevState, RmadErrorCode, RmaState, ShimlessRmaServiceInterface} from './shimless_rma_types.js' +import {RmadErrorCode, RmaState, ShimlessRmaServiceInterface, StateResult} from './shimless_rma_types.js' /** * Enum for button states. @@ -150,9 +150,10 @@ this.shimlessRmaService_ = getShimlessRmaService(); // Get the initial state. - this.fetchState_().then((state) => { - this.initialState_ = state.currentState; - this.loadState_(state.currentState); + this.fetchState_().then((stateResult) => { + // TODO(gavindodd): Handle stateResult.error + this.initialState_ = stateResult.state; + this.loadState_(stateResult.state); }); } @@ -246,8 +247,8 @@ /** @protected */ onBackButtonClicked_() { - // TODO(joonbug): error handling based on state.error - this.fetchPrevState_().then((state) => this.loadState_(state.prevState)); + this.fetchPrevState_().then( + (stateResult) => this.loadState_(stateResult.state)); } /** @protected */ @@ -256,15 +257,17 @@ assert(page); // Acquire promise to check whether current page is ready for next page. - const prepPageAdvance = - page.onNextButtonClick || (() => Promise.resolve(RmaState.kUnknown)); + const prepPageAdvance = page.onNextButtonClick || + (() => Promise.resolve( + {state: RmaState.kUnknown, error: RmadErrorCode.kOk})); assert(typeof prepPageAdvance === 'function'); + // TODO(gavindodd): Handle stateResult.error prepPageAdvance() .then( - (rmaState) => !!rmaState ? Promise.resolve({nextState: rmaState}) : - this.fetchNextState_()) - .then((state) => this.loadState_(state.nextState)) + (stateResult) => !!stateResult ? Promise.resolve(stateResult) : + this.fetchNextState_()) + .then((stateResult) => this.loadState_(stateResult.state)) .catch((err) => void 0); }
diff --git a/ash/content/shimless_rma/resources/shimless_rma_types.js b/ash/content/shimless_rma/resources/shimless_rma_types.js index 493bb6fd..8f992b1 100644 --- a/ash/content/shimless_rma/resources/shimless_rma_types.js +++ b/ash/content/shimless_rma/resources/shimless_rma_types.js
@@ -10,6 +10,13 @@ * re-aliased to the corresponding mojo types, or replaced by them. */ +/** + * Return type from state progression methods. + * Convenience type as mojo-lite does not define types for method results and + * this is used frequently. + * @typedef {{state: !RmaState, error: !RmadErrorCode}} + */ +export let StateResult; /** * @enum {number} @@ -131,29 +138,6 @@ */ export let Component; -// TODO(gavindodd): Change the mojo interface to always use -// (RmaState state, RmadErrorCode error) -// as the method return signature so *State types are consolidated. -/** - * @typedef {{state: !RmaState, error: !RmadErrorCode}} - */ -export let State; - -/** - * @typedef {{currentState: !RmaState, error: !RmadErrorCode}} - */ -export let CurrentState; - -/** - * @typedef {{nextState: !RmaState, error: !RmadErrorCode}} - */ -export let NextState; - -/** - * @typedef {{prevState: !RmaState, error: !RmadErrorCode}} - */ -export let PrevState; - /** * Type alias for ErrorObserver. * @typedef {{onError: !function(!RmadErrorCode)}}
diff --git a/base/BUILD.gn b/base/BUILD.gn index fad1f1b0..06bc03e 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -2297,11 +2297,13 @@ "tracing/tracing_tls.h", ] - public_deps += [ "//third_party/perfetto:libperfetto" ] + public_deps += [ + "//base/tracing/protos:chrome_track_event_zero", + "//third_party/perfetto:libperfetto", + ] deps += [ "//base/tracing/protos:chrome_track_event", - "//base/tracing/protos:chrome_track_event_zero", "//third_party/perfetto/include/perfetto/protozero", ]
diff --git a/base/tracing/protos/chrome_track_event.proto b/base/tracing/protos/chrome_track_event.proto index 54e11ce..311ccd6 100644 --- a/base/tracing/protos/chrome_track_event.proto +++ b/base/tracing/protos/chrome_track_event.proto
@@ -34,7 +34,8 @@ } message ChromeBrowserContext { - optional fixed64 ptr = 1; + reserved 1; + optional string id = 2; } message ChromeProfileDestroyer { @@ -142,6 +143,50 @@ optional uint32 resource_id = 1; } +// Information about RenderProcessHost. +message RenderProcessHost { + // Unique Id to identify the RenderProcessHost. This is the browser-side, + // persistent id for this RenderProcessHost that stays constant even across OS + // layer processes managed by this RenderProcessHost. + optional uint32 id = 1; + // See ProcessLock::ToString(). + optional string process_lock = 2; + // The PID of the child process. + optional int32 child_process_id = 3; + + // Details about the associated browser context. + optional ChromeBrowserContext browser_context = 4; +} + +message RenderProcessHostListener { + // Routing ID of the listener to the RenderProcessHost, recorded when a new ID + // is added or when an ID is removed. + optional uint32 routing_id = 1; +} + +message RenderProcessHostCleanup { + // Number of IPC listeners registered to the host when Cleanup() was called. + optional uint32 listener_count = 1; + // Number of "keep alive" references active in the RenderProcessHost, recorded + // when Cleanup() was called. + optional uint32 keep_alive_ref_count = 2; +} + +message ChildProcessLauncherPriority { + // True if the new priority set to background. + optional bool is_backgrounded = 1; + // True if the renderer proecss has pending views. + optional bool has_pending_views = 2; + + // Importance of the child process in Android. + enum Importance { + IMPORTANCE_NORMAL = 1; + IMPORTANCE_MODERATE = 2; + IMPORTANCE_IMPORTANT = 3; + } + optional Importance importance = 3; +} + message ChromeTrackEvent { // Extension range for Chrome: 1000-1999 // Next ID: 1017 @@ -173,7 +218,12 @@ optional ChromeHashedPerformanceMark chrome_hashed_performance_mark = 1011; - // reserved 1012 to 1015. + optional RenderProcessHost render_process_host = 1012; + optional RenderProcessHostCleanup render_process_host_cleanup = 1013; + optional RenderProcessHostListener render_process_host_listener_changed = + 1014; + optional ChildProcessLauncherPriority child_process_launcher_priority = + 1015; optional ResourceBundle resource_bundle = 1016; }
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1 index e2ba3a48..3f50e2d 100644 --- a/build/fuchsia/linux.sdk.sha1 +++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@ -4.20210602.1.1 +4.20210602.3.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1 index e2ba3a48..3f50e2d 100644 --- a/build/fuchsia/mac.sdk.sha1 +++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@ -4.20210602.1.1 +4.20210602.3.1
diff --git a/build/lacros/test_runner.py b/build/lacros/test_runner.py index 982c045..7ec91cf 100755 --- a/build/lacros/test_runner.py +++ b/build/lacros/test_runner.py
@@ -102,7 +102,8 @@ # are allowed. For now we only enable crosapi in targets that run tests # serially. 'interactive_ui_tests', - 'lacros_chrome_browsertests' + 'lacros_chrome_browsertests', + 'lacros_chrome_browsertests_run_in_series' ]
diff --git a/build/toolchain/apple/toolchain.gni b/build/toolchain/apple/toolchain.gni index 80fa7b3..1ca6339 100644 --- a/build/toolchain/apple/toolchain.gni +++ b/build/toolchain/apple/toolchain.gni
@@ -17,12 +17,6 @@ assert((target_os == "ios" && host_os == "mac") || host_os != "win") declare_args() { - # This makes the linker set timestamps in Mach-O files to 0. This isn't - # enabled by default because this breaks Xcode's lldb. This has been fixed in - # https://reviews.llvm.org/rL368199 but that has not yet made it into a public - # lldb release. - mac_deterministic_build = false - # This controls whether whole module optimization is enabled when building # Swift modules. If enabled, the compiler will compile the module as one # unit, generating just one single object file. Otherwise, it will generate @@ -156,9 +150,8 @@ _strippath = invoker.bin_path + "strip" linker_driver += " -Wcrl,strippath," + _strippath - if (mac_deterministic_build) { - linker_driver += " --deterministic" - } + # This makes the linker set timestamps in Mach-O files to 0. + linker_driver += " --deterministic" # On iOS, the final applications are assembled using lipo (to support fat # builds). The correct flags are passed to the linker_driver.py script
diff --git a/cc/paint/oop_pixeltest.cc b/cc/paint/oop_pixeltest.cc index 811a994a..4a479a8 100644 --- a/cc/paint/oop_pixeltest.cc +++ b/cc/paint/oop_pixeltest.cc
@@ -1777,37 +1777,32 @@ const int sdk = base::android::BuildInfo::GetInstance()->sdk_int(); if (sdk <= base::android::SDK_VERSION_MARSHMALLOW) { error_pixels_percentage = 10.f; - max_abs_error = 16; + max_abs_error = 20; } else { // Newer OSes occasionally have smaller flakes when using the real GPU error_pixels_percentage = 1.5f; max_abs_error = 2; } -#elif defined(OS_MAC) || defined(OS_WIN) - // Mac and Windows need very small tolerances only under complex transforms - if (GetMatrixStrategy(GetParam()) == MatrixStrategy::kComplex) { - error_pixels_percentage = 0.2f; - max_abs_error = 2; - } #endif - // Regardless of OS, perspective triggers path rendering for each glyph, - // which produces its own set of pixel differences. - if (GetMatrixStrategy(GetParam()) == MatrixStrategy::kPerspective) { - error_pixels_percentage = 4.f; - max_abs_error = 36; - } + // Many platforms need very small tolerances under complex transforms, + // and higher tolerances for perspective, since it triggers path rendering + // for each glyph. Additionally, record filters require higher tolerance + // because oop-r converts raster-at-scale to fixed-scale. float avg_error = max_abs_error; - // And if the text is stored in a PaintFilter, allow for more differences - // since OOP-R converts to a fixed scale image before the transform. We - // could convert GPU-raster to fixed scale for direct comparison, but this - // ensures that both scaling modes produce approximately the same image. - if (GetTextBlobStrategy(GetParam()) == TextBlobStrategy::kRecordFilter && - (GetMatrixStrategy(GetParam()) == MatrixStrategy::kPerspective || - GetMatrixStrategy(GetParam()) == MatrixStrategy::kComplex)) { - error_pixels_percentage = 12.f; - max_abs_error = 220; - avg_error = 50.f; + const bool is_record_filter = + GetTextBlobStrategy(GetParam()) == TextBlobStrategy::kRecordFilter; + if (GetMatrixStrategy(GetParam()) == MatrixStrategy::kComplex) { + error_pixels_percentage = + std::max(is_record_filter ? 12.f : 0.2f, error_pixels_percentage); + max_abs_error = std::max(is_record_filter ? 220 : 2, max_abs_error); + avg_error = std::max(is_record_filter ? 50.f : 2.f, avg_error); + } else if (GetMatrixStrategy(GetParam()) == MatrixStrategy::kPerspective) { + error_pixels_percentage = + std::max(is_record_filter ? 12.f : 4.f, error_pixels_percentage); + max_abs_error = std::max(is_record_filter ? 255 : 36, max_abs_error); + avg_error = std::max(is_record_filter ? 60.f : 36.f, avg_error); } + FuzzyPixelComparator comparator( /*discard_alpha=*/false, /*error_pixels_percentage_limit=*/error_pixels_percentage, @@ -1995,12 +1990,7 @@ }; TEST_P(OopTextBlobPixelTest, Config) { -#if defined(OS_ANDROID) && defined(ARCH_CPU_X86_FAMILY) - // Broken on emulators: https://crbug.com/1189284 - GTEST_SKIP(); -#else RunTest(); -#endif } INSTANTIATE_TEST_SUITE_P(
diff --git a/cc/trees/draw_property_utils.cc b/cc/trees/draw_property_utils.cc index b6c84a81..5dd5670 100644 --- a/cc/trees/draw_property_utils.cc +++ b/cc/trees/draw_property_utils.cc
@@ -12,6 +12,7 @@ #include "base/containers/adapters.h" #include "base/containers/stack.h" #include "base/logging.h" +#include "build/build_config.h" #include "cc/base/math_util.h" #include "cc/layers/draw_properties.h" #include "cc/layers/layer.h" @@ -1121,18 +1122,57 @@ void UpdateElasticOverscroll( PropertyTrees* property_trees, TransformNode* overscroll_elasticity_transform_node, - const gfx::Vector2dF& elastic_overscroll) { + const gfx::Vector2dF& elastic_overscroll, + const ScrollNode* inner_viewport) { if (!overscroll_elasticity_transform_node) { DCHECK(elastic_overscroll.IsZero()); return; } +#if defined(OS_ANDROID) + + // On android, elastic overscroll is implemented by stretching the content + // from the overscrolled edge. + // TODO(https://crbug.com/1213217): Use a non-linear stretch rather than a + // simple scale transformation for the overscroll effect. + overscroll_elasticity_transform_node->local.MakeIdentity(); + overscroll_elasticity_transform_node->origin.SetPoint(0.f, 0.f, 0.f); + overscroll_elasticity_transform_node->to_screen_is_potentially_animated = + !elastic_overscroll.IsZero(); + + if (!elastic_overscroll.IsZero() && inner_viewport) { + overscroll_elasticity_transform_node->local.Scale( + 1.f + std::abs(elastic_overscroll.x()) / + inner_viewport->container_bounds.width(), + 1.f + std::abs(elastic_overscroll.y()) / + inner_viewport->container_bounds.height()); + + // If overscrolling to the right, stretch from right. + if (elastic_overscroll.x() > 0.f) { + overscroll_elasticity_transform_node->origin.set_x( + inner_viewport->container_bounds.width()); + } + + // If overscrolling off the bottom, stretch from bottom. + if (elastic_overscroll.y() > 0.f) { + overscroll_elasticity_transform_node->origin.set_y( + inner_viewport->container_bounds.height()); + } + } + +#else // defined(OS_ANDROID) + + // On other platforms, we modify the translation offset to match the + // overscroll amount. if (overscroll_elasticity_transform_node->scroll_offset == gfx::ScrollOffset(elastic_overscroll)) return; overscroll_elasticity_transform_node->scroll_offset = gfx::ScrollOffset(elastic_overscroll); + +#endif // defined(OS_ANDROID) + overscroll_elasticity_transform_node->needs_local_transform_update = true; property_trees->transform_tree.set_needs_update(true); } @@ -1448,7 +1488,8 @@ layer_tree_impl->current_page_scale_factor()); UpdateElasticOverscroll(property_trees, layer_tree_impl->OverscrollElasticityTransformNode(), - layer_tree_impl->current_elastic_overscroll()); + layer_tree_impl->current_elastic_overscroll(), + layer_tree_impl->InnerViewportScrollNode()); // Similarly, the device viewport and device transform are shared // by both trees. property_trees->clip_tree.SetViewportClip(
diff --git a/cc/trees/layer_tree_host_pixeltest_masks.cc b/cc/trees/layer_tree_host_pixeltest_masks.cc index 26d6d288..d858c5ba 100644 --- a/cc/trees/layer_tree_host_pixeltest_masks.cc +++ b/cc/trees/layer_tree_host_pixeltest_masks.cc
@@ -308,8 +308,7 @@ .InsertBeforeExtensionASCII(GetRendererSuffix())); } -TEST_P(LayerTreeHostMaskPixelTestWithLayerList, - DISABLED_MaskWithEffectDifferentSize) { +TEST_P(LayerTreeHostMaskPixelTestWithLayerList, MaskWithEffectDifferentSize) { mask_bounds_ = gfx::Size(25, 25); MaskContentLayerClient client(mask_bounds_); mask_layer_ = PictureLayer::Create(&client);
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc index 0cc5ae85f..f2011d4 100644 --- a/cc/trees/layer_tree_host_unittest.cc +++ b/cc/trees/layer_tree_host_unittest.cc
@@ -5720,34 +5720,57 @@ } } + void VerifyOverscroll(const gfx::Vector2dF& stretch_amount, + const gfx::Transform& transform) { +#if defined(OS_ANDROID) + gfx::Vector2dF scale = transform.Scale2d(); + // On android, overscroll stretches the content. We don't assert the amount + // of stretch but there should be some stretch for overscroll and no stretch + // without it. + if (stretch_amount.x() == 0.f) + EXPECT_EQ(1.f, scale.x()); + else + EXPECT_GT(scale.x(), 1.f); + if (stretch_amount.y() == 0.f) + EXPECT_EQ(1.f, scale.y()); + else + EXPECT_GT(scale.y(), 1.f); +#else // defined(OS_ANDROID) + gfx::Transform expected_draw_transform; + expected_draw_transform.Translate(-stretch_amount); + EXPECT_EQ(expected_draw_transform, transform); +#endif // defined(OS_ANDROID) + } + void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override { num_draws_++; LayerImpl* content_layer_impl = host_impl->active_tree()->LayerById(content_layer_id_); - gfx::Transform expected_draw_transform; switch (num_draws_) { case 1: // Initially, there's no overscroll. - EXPECT_EQ(expected_draw_transform, content_layer_impl->DrawTransform()); + VerifyOverscroll(gfx::Vector2dF(), content_layer_impl->DrawTransform()); // Begin overscrolling. This should be reflected in the draw transform // the next time we draw. scroll_elasticity_helper_->SetStretchAmount(gfx::Vector2dF(5.f, 6.f)); break; case 2: - expected_draw_transform.Translate(-5.0, -6.0); - EXPECT_EQ(expected_draw_transform, content_layer_impl->DrawTransform()); + // We should have some overscroll. + VerifyOverscroll(gfx::Vector2dF(5.f, 6.f), + content_layer_impl->DrawTransform()); scroll_elasticity_helper_->SetStretchAmount(gfx::Vector2dF(3.f, 2.f)); break; case 3: - expected_draw_transform.Translate(-3.0, -2.0); - EXPECT_EQ(expected_draw_transform, content_layer_impl->DrawTransform()); + VerifyOverscroll(gfx::Vector2dF(3.f, 2.f), + content_layer_impl->DrawTransform()); scroll_elasticity_helper_->SetStretchAmount(gfx::Vector2dF()); break; case 4: - EXPECT_EQ(expected_draw_transform, content_layer_impl->DrawTransform()); + // In the final frame there is no more overscroll. + VerifyOverscroll(gfx::Vector2dF(), content_layer_impl->DrawTransform()); EndTest(); break; default:
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni index 97a4f17f..488a510 100644 --- a/chrome/android/chrome_java_sources.gni +++ b/chrome/android/chrome_java_sources.gni
@@ -1156,6 +1156,7 @@ "java/src/org/chromium/chrome/browser/share/ShareDelegateImpl.java", "java/src/org/chromium/chrome/browser/share/ShareDelegateSupplier.java", "java/src/org/chromium/chrome/browser/share/ShareHelper.java", + "java/src/org/chromium/chrome/browser/share/ShareRegistrationCoordinator.java", "java/src/org/chromium/chrome/browser/share/ShareUtils.java", "java/src/org/chromium/chrome/browser/sharing/SharingAdapter.java", "java/src/org/chromium/chrome/browser/sharing/SharingJNIBridge.java",
diff --git a/chrome/android/chrome_junit_test_java_sources.gni b/chrome/android/chrome_junit_test_java_sources.gni index e5aa81c..cdd91a2 100644 --- a/chrome/android/chrome_junit_test_java_sources.gni +++ b/chrome/android/chrome_junit_test_java_sources.gni
@@ -200,6 +200,7 @@ "junit/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceNotificationTest.java", "junit/src/org/chromium/chrome/browser/search_engines/settings/SearchEngineAdapterTest.java", "junit/src/org/chromium/chrome/browser/send_tab_to_self/SendTabToSelfShareActivityTest.java", + "junit/src/org/chromium/chrome/browser/share/ShareRegistrationCoordinatorTest.java", "junit/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallMessageHandlerTest.java", "junit/src/org/chromium/chrome/browser/signin/SigninBridgeTest.java", "junit/src/org/chromium/chrome/browser/signin/SigninManagerImplTest.java",
diff --git a/chrome/android/expectations/monochrome_public_bundle.proguard_flags.expected b/chrome/android/expectations/monochrome_public_bundle.proguard_flags.expected index 55b8825..236f59a 100644 --- a/chrome/android/expectations/monochrome_public_bundle.proguard_flags.expected +++ b/chrome/android/expectations/monochrome_public_bundle.proguard_flags.expected
@@ -646,16 +646,6 @@ <init>(); } -# File: obj/third_party/androidx/androidx_startup_startup_runtime_java/proguard.txt -# This Proguard rule ensures that ComponentInitializers are are neither shrunk nor obfuscated. -# This is because they are discovered and instantiated during application initialization. --keep class * extends androidx.startup.Initializer { - # Keep the public no-argument constructor while allowing other methods to be optimized. - <init>(); -} - --assumenosideeffects class androidx.startup.StartupLogger - # File: obj/third_party/androidx/androidx_transition_transition_java/proguard.txt # Copyright (C) 2017 The Android Open Source Project #
diff --git a/chrome/android/features/cablev2_authenticator/java/src/org/chromium/chrome/browser/webauth/authenticator/CableAuthenticator.java b/chrome/android/features/cablev2_authenticator/java/src/org/chromium/chrome/browser/webauth/authenticator/CableAuthenticator.java index 292ef651..71021c2 100644 --- a/chrome/android/features/cablev2_authenticator/java/src/org/chromium/chrome/browser/webauth/authenticator/CableAuthenticator.java +++ b/chrome/android/features/cablev2_authenticator/java/src/org/chromium/chrome/browser/webauth/authenticator/CableAuthenticator.java
@@ -59,8 +59,10 @@ private static final int SIGN_REQUEST_CODE = 2; private static final int CTAP2_OK = 0; + private static final int CTAP2_ERR_CREDENTIAL_EXCLUDED = 0x19; private static final int CTAP2_ERR_OPERATION_DENIED = 0x27; private static final int CTAP2_ERR_UNSUPPORTED_OPTION = 0x2D; + private static final int CTAP2_ERR_NO_CREDENTIALS = 0x2E; private static final int CTAP2_ERR_OTHER = 0x7F; // sOwnBluetooth is true if this class owns the fact that Bluetooth is enabled and needs to @@ -316,7 +318,6 @@ Log.e(TAG, "OK."); if (data.hasExtra(Fido.FIDO2_KEY_ERROR_EXTRA)) { - Log.e(TAG, "error extra"); AuthenticatorErrorResponse error = AuthenticatorErrorResponse.deserializeFromBytes( data.getByteArrayExtra(Fido.FIDO2_KEY_ERROR_EXTRA)); Log.i(TAG, @@ -324,9 +325,14 @@ + String.valueOf(error.getErrorCodeAsInt())); // ErrorCode represents DOMErrors not CTAP status codes. - // TODO: figure out translation of the remaining codes int ctap_status; switch (error.getErrorCode()) { + case INVALID_STATE_ERR: + // Assumed to be caused by a matching excluded credential. + // (It's possible to match the error string to be sure, + // but that's fragile.) + ctap_status = CTAP2_ERR_CREDENTIAL_EXCLUDED; + break; case NOT_ALLOWED_ERR: ctap_status = CTAP2_ERR_OPERATION_DENIED; break; @@ -364,7 +370,6 @@ Log.e(TAG, "OK."); if (data.hasExtra(Fido.FIDO2_KEY_ERROR_EXTRA)) { - Log.e(TAG, "error extra"); AuthenticatorErrorResponse error = AuthenticatorErrorResponse.deserializeFromBytes( data.getByteArrayExtra(Fido.FIDO2_KEY_ERROR_EXTRA)); Log.i(TAG, @@ -372,9 +377,14 @@ + String.valueOf(error.getErrorCodeAsInt())); // ErrorCode represents DOMErrors not CTAP status codes. - // TODO: figure out translation of the remaining codes int ctap_status; switch (error.getErrorCode()) { + case INVALID_STATE_ERR: + // Assumed to be because none of the credentials were + // recognised. (It's possible to match the error string to + // be sure, but that's fragile.) + ctap_status = CTAP2_ERR_NO_CREDENTIALS; + break; case NOT_ALLOWED_ERR: ctap_status = CTAP2_ERR_OPERATION_DENIED; break;
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingComponentBridge.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingComponentBridge.java index 5d816ae..e9b14ad 100644 --- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingComponentBridge.java +++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingComponentBridge.java
@@ -1,3 +1,4 @@ + // 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. @@ -146,6 +147,13 @@ } @CalledByNative + private void showAccessorySheetTab(int tabType) { + if (getManualFillingComponent() != null) { + getManualFillingComponent().showAccessorySheetTab(tabType); + } + } + + @CalledByNative private void addOptionToggleToAccessorySheetData(Object objAccessorySheetData, String displayText, boolean enabled, @AccessoryAction int accessoryAction) { ((AccessorySheetData) objAccessorySheetData)
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingCoordinator.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingCoordinator.java index 769d7a9..62defef 100644 --- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingCoordinator.java +++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingCoordinator.java
@@ -127,6 +127,11 @@ } @Override + public void showAccessorySheetTab(@AccessoryTabType int tabType) { + mMediator.showAccessorySheetTab(tabType); + } + + @Override public void onResume() { mMediator.resume(); }
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingMediator.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingMediator.java index fdc18e7..23fa0a86 100644 --- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingMediator.java +++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingMediator.java
@@ -282,8 +282,7 @@ void dismiss() { if (!isInitialized()) return; pause(); - ViewGroup contentView = getContentView(); - if (contentView != null) mSoftKeyboardDelegate.hideSoftKeyboardOnly(contentView); + hideSoftKeyboard(); } void notifyPopupOpened(DropdownPopupWindow popup) { @@ -302,6 +301,13 @@ mModel.set(KEYBOARD_EXTENSION_STATE, HIDDEN); } + void showAccessorySheetTab(@AccessoryTabType int tabType) { + if (!isInitialized()) return; + mModel.set(SHOW_WHEN_VISIBLE, true); + if (is(HIDDEN)) mModel.set(KEYBOARD_EXTENSION_STATE, REPLACING_KEYBOARD); + mKeyboardAccessory.setActiveTab(tabType); + } + void pause() { if (!isInitialized()) return; mConfirmationHelper.dismiss(); @@ -588,7 +594,7 @@ int newSheetHeight = insetObserver != null ? insetObserver.getSystemWindowInsetsBottom() : mSoftKeyboardDelegate.calculateSoftKeyboardHeight(rootView); - newSheetHeight = Math.max(minimalSheetHeight, newSheetHeight); + newSheetHeight = Math.max(newSheetHeight, minimalSheetHeight); return newSheetHeight; }
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/README.md b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/README.md index fc60379..7d39111 100644 --- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/README.md +++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/README.md
@@ -72,7 +72,7 @@ | ID | State | Accessory Bar | Fallback Sheet | Floats | Transition into* |--------|--------------------|--------------------------|-----------------------------------------|---------|- -| 0x0100 | HIDDEN | Hidden | Hidden | N/A | FLOATING_BAR +| 0x0100 | HIDDEN | Hidden | Hidden | N/A | FLOATING_BAR, REPLACING_KEYBOARD | 0x0101 | EXTENDING_KEYBOARD | **Visible** | Hidden | No | WAITING_TO_REPLACE | 0x0001 | WAITING_TO_REPLACE | **Visible** | N/A — waits for keyboard to (dis)appear | No | REPLACING_KEYBOARD | 0x0011 | REPLACING_KEYBOARD | **Visible** as title bar | **Visible** | No | FLOATING_SHEET
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryCoordinator.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryCoordinator.java index 94d1f32f..6e37d68b 100644 --- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryCoordinator.java +++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryCoordinator.java
@@ -15,6 +15,7 @@ import androidx.viewpager.widget.ViewPager; import org.chromium.chrome.browser.flags.ChromeFeatureList; +import org.chromium.chrome.browser.keyboard_accessory.AccessoryTabType; import org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryProperties.BarItem; import org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryViewBinder.BarItemViewHolder; import org.chromium.chrome.browser.keyboard_accessory.data.KeyboardAccessoryData; @@ -92,6 +93,12 @@ void closeActiveTab(); /** + * Set the currently active tab to the given tabType. + * @param tabType The type of the tab that should be selected. + */ + void setActiveTab(@AccessoryTabType int tabType); + + /** * Returns whether active tab or null if no tab is currently active. The returned property * reflects the latest change while the view might still be in progress of being updated. * @return The active {@link KeyboardAccessoryData.Tab}, null otherwise. @@ -169,6 +176,10 @@ mTabLayout.getTabSwitchingDelegate().setTabs(tabs); } + public void setActiveTab(@AccessoryTabType int tabType) { + mTabLayout.getTabSwitchingDelegate().setActiveTab(tabType); + } + /** * Allows any {@link Provider} to communicate with the * {@link KeyboardAccessoryMediator} of this component.
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/tab_layout_component/KeyboardAccessoryTabLayoutMediator.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/tab_layout_component/KeyboardAccessoryTabLayoutMediator.java index 7153278..5f28def 100644 --- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/tab_layout_component/KeyboardAccessoryTabLayoutMediator.java +++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/tab_layout_component/KeyboardAccessoryTabLayoutMediator.java
@@ -14,9 +14,11 @@ import com.google.android.material.tabs.TabLayout; +import org.chromium.chrome.browser.keyboard_accessory.AccessoryTabType; import org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryCoordinator; import org.chromium.chrome.browser.keyboard_accessory.data.KeyboardAccessoryData; import org.chromium.chrome.browser.keyboard_accessory.tab_layout_component.KeyboardAccessoryTabLayoutCoordinator.AccessoryTabObserver; +import org.chromium.ui.modelutil.ListModel; import org.chromium.ui.modelutil.PropertyKey; import org.chromium.ui.modelutil.PropertyModel; import org.chromium.ui.modelutil.PropertyObservable; @@ -107,6 +109,20 @@ } @Override + public void setActiveTab(@AccessoryTabType int tabType) { + ListModel<KeyboardAccessoryData.Tab> tabs = mModel.get(TABS); + int tabPosition = 0; + while (tabPosition < tabs.size()) { + if (tabs.get(tabPosition).getRecordingType() == tabType) { + break; + } + tabPosition++; + } + assert tabPosition < tabs.size() : "No tab found for the given tabType: " + tabType; + mModel.set(ACTIVE_TAB, tabPosition); + } + + @Override public @Nullable KeyboardAccessoryData.Tab getActiveTab() { if (mModel.get(ACTIVE_TAB) == null) return null; return mModel.get(TABS).get(mModel.get(ACTIVE_TAB));
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingIntegrationTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingIntegrationTest.java index 3b502401..2a01cb10 100644 --- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingIntegrationTest.java +++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingIntegrationTest.java
@@ -143,6 +143,24 @@ @Test @SmallTest + @EnableFeatures({ChromeFeatureList.AUTOFILL_MANUAL_FALLBACK_ANDROID}) + public void testAccessorySheetShown() throws TimeoutException { + mHelper.loadTestPage(false); + // Register a sheet data provider so that sheet is available when needed. + mHelper.registerSheetDataProvider(AccessoryTabType.CREDIT_CARDS); + + // Show the passwords accessory sheet without focusing on any fields. + TestThreadUtils.runOnUiThreadBlocking( + () + -> mHelper.getManualFillingCoordinator().showAccessorySheetTab( + AccessoryTabType.CREDIT_CARDS)); + + // Verify that the accessory sheet is shown. + whenDisplayed(withChild(withId(R.id.keyboard_accessory_sheet))); + } + + @Test + @SmallTest @DisableIf. Build(sdk_is_greater_than = VERSION_CODES.LOLLIPOP_MR1, sdk_is_less_than = VERSION_CODES.N, message = "Flaky on Marshmallow https://crbug.com/1102302")
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingTestHelper.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingTestHelper.java index 0dc6e9a91..4eded381 100644 --- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingTestHelper.java +++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingTestHelper.java
@@ -50,6 +50,7 @@ import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.browser.keyboard_accessory.bar_component.KeyboardAccessoryCoordinator; import org.chromium.chrome.browser.keyboard_accessory.data.KeyboardAccessoryData; +import org.chromium.chrome.browser.keyboard_accessory.data.KeyboardAccessoryData.AccessorySheetData; import org.chromium.chrome.browser.keyboard_accessory.data.PropertyProvider; import org.chromium.chrome.browser.keyboard_accessory.sheet_tabs.AddressAccessorySheetCoordinator; import org.chromium.chrome.browser.keyboard_accessory.sheet_tabs.CreditCardAccessorySheetCoordinator; @@ -510,4 +511,10 @@ mActivityTestRule.getWebContents(), available); }); } + + public void registerSheetDataProvider(@AccessoryTabType int tabType) { + PropertyProvider<AccessorySheetData> sheetDataProvider = new PropertyProvider<>(); + getManualFillingCoordinator().registerSheetDataProvider( + mWebContentsRef.get(), tabType, sheetDataProvider); + } }
diff --git a/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingControllerTest.java b/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingControllerTest.java index 06dc719d..c651c66d 100644 --- a/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingControllerTest.java +++ b/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingControllerTest.java
@@ -1085,6 +1085,30 @@ .showConfirmation("Suggestion", "Delete it?", R.string.ok, testRunnable); } + @Test + public void testShowAccessorySheetTab() { + // Prepare a tab and register a new tab, so there is a reason to display the bar. + addBrowserTab(mMediator, 1111, null); + mController.registerSheetDataProvider( + mLastMockWebContents, AccessoryTabType.PASSWORDS, new PropertyProvider<>()); + assertThat(mModel.get(SHOW_WHEN_VISIBLE), is(false)); + assertThat(mModel.get(KEYBOARD_EXTENSION_STATE), is(HIDDEN)); + + mController.showAccessorySheetTab(AccessoryTabType.PASSWORDS); + + // Verify that the states are updated correctly and the active tab is set. + assertThat(mModel.get(SHOW_WHEN_VISIBLE), is(true)); + assertThat(mModel.get(KEYBOARD_EXTENSION_STATE), is(REPLACING_KEYBOARD)); + verify(mMockKeyboardAccessory, times(1)).setActiveTab(AccessoryTabType.PASSWORDS); + + // Simulate the callback once active tab is set. + mMediator.onChangeAccessorySheet(0); + + // Assert tha the keyboard extension state continues to be REPLACING_KEYBOARD as we're + // showing the sheet. + assertThat(mModel.get(KEYBOARD_EXTENSION_STATE), is(REPLACING_KEYBOARD)); + } + /** * Creates a tab and calls the observer events as if it was just created and switched to. * @param mediator The {@link ManualFillingMediator} whose observers should be triggered.
diff --git a/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/tab_layout_component/KeyboardAccessoryTabLayoutControllerTest.java b/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/tab_layout_component/KeyboardAccessoryTabLayoutControllerTest.java index 3c62218..23a5c78 100644 --- a/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/tab_layout_component/KeyboardAccessoryTabLayoutControllerTest.java +++ b/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/tab_layout_component/KeyboardAccessoryTabLayoutControllerTest.java
@@ -151,4 +151,27 @@ verifyNoMoreInteractions( mMockPropertyObserver, mMockTabListObserver, mMockAccessoryTabObserver); } + + @Test + public void testSetActiveTab() { + mModel.addObserver(mMockPropertyObserver); + assertThat(mModel.get(ACTIVE_TAB), is(nullValue())); + mCoordinator.getTabSwitchingDelegate().addTab(mTestTab); + + // Set the active tab type to 0 which is the recording_type of |mTestTab|. + mCoordinator.getTabSwitchingDelegate().setActiveTab(0); + + verify(mMockPropertyObserver).onPropertyChanged(mModel, ACTIVE_TAB); + assertThat(mModel.get(ACTIVE_TAB), is(0)); + } + + @Test(expected = AssertionError.class) + public void testSetActiveTab_tabTypeNotFound_throwsException() { + mModel.addObserver(mMockPropertyObserver); + assertThat(mModel.get(ACTIVE_TAB), is(nullValue())); + mCoordinator.getTabSwitchingDelegate().addTab(mTestTab); + + // Set the active tab type to 1 which is different from the recording_type of |mTestTab|. + mCoordinator.getTabSwitchingDelegate().setActiveTab(1); + } }
diff --git a/chrome/android/features/keyboard_accessory/public/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingComponent.java b/chrome/android/features/keyboard_accessory/public/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingComponent.java index 6171a01..434032c 100644 --- a/chrome/android/features/keyboard_accessory/public/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingComponent.java +++ b/chrome/android/features/keyboard_accessory/public/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingComponent.java
@@ -178,6 +178,12 @@ void hide(); /** + * Commands the accessory to show and set the currently active tab to the given |tabType|. + * @param tabType the tab that should be selected by default. + */ + void showAccessorySheetTab(@AccessoryTabType int tabType); + + /** * Notifies the component that the activity it's living in was resumed. */ void onResume();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ActivityUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/ActivityUtils.java index 555caf5..9ed56cb 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ActivityUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ActivityUtils.java
@@ -44,4 +44,15 @@ return (useLowEndTheme ? R.style.Theme_Chromium_WithWindowAnimation_LowEnd : R.style.Theme_Chromium_WithWindowAnimation); } + + /** + * Returns whether the activity is finishing or destroyed. + * @param activity The activity to check. + * @return Whether the activity is finishing or destroyed. Also returns true if the activity is + * null. + */ + public static boolean isActivityFinishingOrDestroyed(Activity activity) { + if (activity == null) return true; + return activity.isDestroyed() || activity.isFinishing(); + } } \ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeAccessorActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeAccessorActivity.java index e6bd329..3d9d65a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeAccessorActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeAccessorActivity.java
@@ -4,22 +4,21 @@ package org.chromium.chrome.browser; -import android.app.Activity; import android.content.Intent; import android.os.Bundle; import androidx.appcompat.app.AppCompatActivity; -import org.chromium.base.ApplicationStatus; import org.chromium.base.IntentUtils; -import org.chromium.chrome.browser.app.ChromeActivity; import org.chromium.chrome.browser.share.ShareHelper; -import org.chromium.components.browser_ui.widget.MenuOrKeyboardActionController; +import org.chromium.chrome.browser.share.ShareRegistrationCoordinator.ShareBroadcastReceiver; /** * {@code ChromeActivityAccessor} is the base class for share options, which * are activities that are shown in the share chooser. Activities subclassing - * ChromeAccessorActivity override handleAction. + * ChromeAccessorActivity need to: + * - Override #getBroadcastAction. + * - Register to receive that broadcast in ShareRegistrationCoordinator. */ public abstract class ChromeAccessorActivity extends AppCompatActivity { @Override @@ -32,39 +31,17 @@ if (!Intent.ACTION_SEND.equals(intent.getAction())) return; if (!IntentUtils.safeHasExtra(intent, ShareHelper.EXTRA_TASK_ID)) return; - ChromeActivity triggeringActivity = getTriggeringActivity(); - if (triggeringActivity == null) return; - - handleAction(/* triggeringActivity= */ triggeringActivity, - /* menuOrKeyboardActionController= */ triggeringActivity); + ShareBroadcastReceiver.sendShareBroadcastWithAction( + intent.getIntExtra(ShareHelper.EXTRA_TASK_ID, 0), getBroadcastAction()); } finally { finish(); } } /** - * Returns the ChromeActivity that called the share intent picker. + * Return a unique action string which is used to register to receive the broadcast in + * ShareRegistrationController. Usually, the best option is to use the stringified class name + * with the "BroadcastAction" postfix. */ - private ChromeActivity getTriggeringActivity() { - int triggeringTaskId = - IntentUtils.safeGetIntExtra(getIntent(), ShareHelper.EXTRA_TASK_ID, 0); - for (Activity activity : ApplicationStatus.getRunningActivities()) { - if (activity.getTaskId() == triggeringTaskId && activity instanceof ChromeActivity) { - return (ChromeActivity) activity; - } - } - return null; - } - - /** - * Completes the share action. - * - * Override this activity to implement desired share functionality. This activity - * will be destroyed immediately after this method is called. - * - * @param triggeringActivity The {@link Activity} that triggered the share. - * @param menuOrKeyboardActionController Handles menu or keyboard actions. - */ - protected abstract void handleAction(Activity triggeringActivity, - MenuOrKeyboardActionController menuOrKeyboardActionController); + protected abstract String getBroadcastAction(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java index b34a404..1825f9c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -1847,7 +1847,7 @@ LauncherShortcutActivity.updateIncognitoShortcut(ChromeTabbedActivity.this); - ChromeSurveyController.initialize(mTabModelSelectorImpl); + ChromeSurveyController.initialize(mTabModelSelectorImpl, getLifecycleDispatcher()); if (mStartSurfaceSupplier.get() != null && mOverviewShownOnStart) { mStartSurfaceSupplier.get().onOverviewShownAtLaunch(getOnCreateTimestampMs());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/DEPS b/chrome/android/java/src/org/chromium/chrome/browser/DEPS index b509cc63..2056347 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/DEPS +++ b/chrome/android/java/src/org/chromium/chrome/browser/DEPS
@@ -14,9 +14,6 @@ specific_include_rules = { # Exceptions to the ChromeActivity dependency restriction. These will all eventually be removed # new code should rely on acceptable dependency aquisition patterns. - "ChromeAccessorActivity\.java": [ - "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java", - ], "ChromeActivitySessionTracker\.java": [ "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java", ], @@ -65,9 +62,6 @@ "DownloadInfoBarController\.java": [ "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java", ], - "ExploreSitesIPH\.java": [ - "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java", - ], "ScreenshotTask\.java": [ "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java", ], @@ -98,9 +92,6 @@ "ChromePaymentRequestService\.java": [ "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java", ], - "SendTabToSelfShareActivity\.java": [ - "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java", - ], "InterceptNavigationDelegateClientImpl\.java": [ "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java", ],
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java index c84206d..cb392b7 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
@@ -288,7 +288,7 @@ int GOOGLE_APPS = 1; // This should not be used, it's a fallback for Chrome features that didn't identify // themselves. Please see {@link - // IncognitoCustomTabIntentDataProvider#addIncongitoExtrasForChromeFeatures} + // IncognitoCustomTabIntentDataProvider#addIncognitoExtrasForChromeFeatures} int OTHER_CHROME_FEATURES = 2; // Chrome Features
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java index 693bb66a4..467cd4c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
@@ -54,6 +54,7 @@ import org.chromium.base.supplier.ObservableSupplierImpl; import org.chromium.base.supplier.OneshotSupplier; import org.chromium.base.supplier.OneshotSupplierImpl; +import org.chromium.base.supplier.Supplier; import org.chromium.base.supplier.UnownedUserDataSupplier; import org.chromium.chrome.R; import org.chromium.chrome.browser.ActivityTabProvider; @@ -139,12 +140,14 @@ import org.chromium.chrome.browser.page_info.ChromePageInfo; import org.chromium.chrome.browser.partnercustomizations.PartnerBrowserCustomizations; import org.chromium.chrome.browser.preferences.Pref; +import org.chromium.chrome.browser.printing.PrintShareActivity; import org.chromium.chrome.browser.printing.TabPrinter; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.settings.SettingsLauncherImpl; import org.chromium.chrome.browser.share.ShareDelegate; import org.chromium.chrome.browser.share.ShareDelegateImpl; import org.chromium.chrome.browser.share.ShareDelegateSupplier; +import org.chromium.chrome.browser.share.ShareRegistrationCoordinator; import org.chromium.chrome.browser.sync.ProfileSyncService; import org.chromium.chrome.browser.tab.AccessibilityVisibilityHandler; import org.chromium.chrome.browser.tab.RequestDesktopUtils; @@ -368,6 +371,8 @@ private List<MenuOrKeyboardActionController.MenuOrKeyboardActionHandler> mMenuActionHandlers = new ArrayList<>(); + private ShareRegistrationCoordinator mShareRegistrationCoordinator; + protected ChromeActivity() { mIntentHandler = new IntentHandler(this, createIntentHandlerDelegate()); mManualFillingComponentSupplier.set(ManualFillingComponentFactory.createComponent()); @@ -567,6 +572,12 @@ mManualFillingComponentSupplier.get().getBottomInsetSupplier()); // Should be called after TabModels are initialized. + mShareRegistrationCoordinator = new ShareRegistrationCoordinator( + this, mActivityTabProvider, mRootUiCoordinator.getBottomSheetController()); + // Some share types are registered in the coorindator itself. + mShareRegistrationCoordinator.registerShareType(PrintShareActivity.BROADCAST_ACTION, + () -> doPrintShare(this, mActivityTabProvider)); + ShareDelegate shareDelegate = new ShareDelegateImpl(mRootUiCoordinator.getBottomSheetController(), getLifecycleDispatcher(), getActivityTabProvider(), @@ -1464,6 +1475,7 @@ mBookmarkBridgeSupplier = null; } + if (mShareRegistrationCoordinator != null) mShareRegistrationCoordinator.destroy(); if (mShareDelegateSupplier != null) { mShareDelegateSupplier.destroy(); } @@ -2364,18 +2376,8 @@ } if (id == R.id.print_id) { - // TODO(crbug.com/1155789): Move this logic to PrintShareActivity once the current tab - // is available as UnownedUserData. - PrintingController printingController = PrintingControllerImpl.getInstance(); - if (printingController != null && !printingController.isBusy() - && UserPrefs.get(Profile.getLastUsedRegularProfile()) - .getBoolean(Pref.PRINTING_ENABLED)) { - printingController.startPrint( - new TabPrinter(currentTab), new PrintManagerDelegateImpl(this)); - RecordUserAction.record("MobileMenuPrint"); - return true; - } - return false; + RecordUserAction.record("MobileMenuPrint"); + return doPrintShare(this, mActivityTabProvider); } if (id == R.id.add_to_homescreen_id) { @@ -2732,4 +2734,18 @@ public DisplayAndroidObserver getDisplayAndroidObserverForTesting() { return mDisplayAndroidObserver; } + + /** Returns whether the print action was successfully started. */ + private boolean doPrintShare(Activity activity, Supplier<Tab> currentTabSupplier) { + PrintingController printingController = PrintingControllerImpl.getInstance(); + + if (!currentTabSupplier.hasValue()) return false; + if (printingController == null || printingController.isBusy()) return false; + if (!UserPrefs.get(Profile.getLastUsedRegularProfile()).getBoolean(Pref.PRINTING_ENABLED)) { + return false; + } + printingController.startPrint( + new TabPrinter(currentTabSupplier.get()), new PrintManagerDelegateImpl(activity)); + return true; + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillPopupBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillPopupBridge.java index ed52a10..d6732a46 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillPopupBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillPopupBridge.java
@@ -183,8 +183,17 @@ String label, String sublabel, String itemTag, int iconId, boolean isIconAtStart, int suggestionId, boolean isDeletable, boolean isLabelMultiline, boolean isLabelBold) { int drawableId = iconId == 0 ? DropdownItem.NO_ICON : iconId; - array[index] = new AutofillSuggestion(label, sublabel, itemTag, drawableId, isIconAtStart, - suggestionId, isDeletable, isLabelMultiline, isLabelBold, /* featureForIPH= */ ""); + array[index] = new AutofillSuggestion.Builder() + .setLabel(label) + .setSubLabel(sublabel) + .setItemTag(itemTag) + .setIconId(drawableId) + .setIsIconAtStart(isIconAtStart) + .setSuggestionId(suggestionId) + .setIsDeletable(isDeletable) + .setIsMultiLineLabel(isLabelMultiline) + .setIsBoldLabel(isLabelBold) + .build(); } @NativeMethods
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/prefeditor/EditorDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/prefeditor/EditorDialog.java index e72c5bc..eb9851b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/prefeditor/EditorDialog.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/prefeditor/EditorDialog.java
@@ -621,6 +621,11 @@ // Note that keyboard will not be shown for dropdown field since it's not necessary. if (getCurrentFocus() != null) { KeyboardVisibilityDelegate.getInstance().showKeyboard(getCurrentFocus()); + // Put the cursor to the end of the text. + if (getCurrentFocus() instanceof EditText) { + EditText focusedEditText = (EditText) getCurrentFocus(); + focusedEditText.setSelection(focusedEditText.getText().length()); + } } if (sObserverForTest != null) sObserverForTest.onEditorReadyToEdit(); });
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkUtils.java index 13cdeda..b6901b2 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkUtils.java
@@ -481,7 +481,7 @@ // Extras for incognito CCT. if (isOffTheRecord) { - IncognitoCustomTabIntentDataProvider.addIncongitoExtrasForChromeFeatures( + IncognitoCustomTabIntentDataProvider.addIncognitoExtrasForChromeFeatures( intent, IncognitoCCTCallerId.READ_LATER); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/IncognitoCustomTabIntentDataProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/IncognitoCustomTabIntentDataProvider.java index 40439ce0..936147d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/IncognitoCustomTabIntentDataProvider.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/IncognitoCustomTabIntentDataProvider.java
@@ -159,7 +159,7 @@ return CustomTabsConnection.getInstance().getClientPackageNameForSession(sessionToken); } - public static void addIncongitoExtrasForChromeFeatures( + public static void addIncognitoExtrasForChromeFeatures( Intent intent, @IntentHandler.IncognitoCCTCallerId int chromeCallerId) { intent.putExtra(IntentHandler.EXTRA_OPEN_NEW_INCOGNITO_TAB, true); intent.putExtra(IntentHandler.EXTRA_INCOGNITO_CCT_CALLER_ID, chromeCallerId);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java index 4bd363029..4d126fc 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java
@@ -503,7 +503,7 @@ // Use Incognito CCT if the source page is in Incognito mode. This is gated by // flag ChromeFeatureList.CCT_INCOGNITO. if (mTab.isIncognito()) { - IncognitoCustomTabIntentDataProvider.addIncongitoExtrasForChromeFeatures( + IncognitoCustomTabIntentDataProvider.addIncognitoExtrasForChromeFeatures( customTabsIntent.intent, IntentHandler.IncognitoCCTCallerId.READER_MODE); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesIPH.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesIPH.java index 0cd42e9..8b1ee88d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesIPH.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesIPH.java
@@ -4,11 +4,13 @@ package org.chromium.chrome.browser.explore_sites; +import android.app.Activity; import android.content.Context; import android.graphics.Rect; import android.view.View; -import org.chromium.chrome.browser.app.ChromeActivity; +import org.chromium.base.ContextUtils; +import org.chromium.chrome.browser.ActivityUtils; import org.chromium.chrome.browser.feature_engagement.TrackerFactory; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.util.ChromeAccessibilityUtil; @@ -28,11 +30,10 @@ public class ExploreSitesIPH { public static void configureIPH(TileView tileView, Profile profile) { Context context = tileView.getContext(); - if (!(context instanceof ChromeActivity)) { - return; - } + if (context == null) return; + Activity activity = ContextUtils.activityFromContext(context); + if (activity == null) return; - ChromeActivity activity = (ChromeActivity) context; if (tileView.isAttachedToWindow()) { maybeShowIPH(tileView, profile, activity); } else { @@ -48,8 +49,8 @@ } } - private static void maybeShowIPH(TileView tileView, Profile profile, ChromeActivity activity) { - if (activity.isActivityFinishingOrDestroyed()) return; + private static void maybeShowIPH(TileView tileView, Profile profile, Activity activity) { + if (ActivityUtils.isActivityFinishingOrDestroyed(activity)) return; final String contentString = tileView.getContext().getString(org.chromium.chrome.R.string.explore_sites_iph);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/SurveyInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/SurveyInfoBar.java index 2eac2c6..77c5ee21 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/SurveyInfoBar.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/SurveyInfoBar.java
@@ -181,8 +181,9 @@ mClicked = true; mDelegate.onSurveyTriggered(); - SurveyController.getInstance().showSurveyIfAvailable( - TabUtils.getActivity(tab), mSiteId, mShowAsBottomSheet, mDisplayLogoResId); + // TODO(https://crbug.com/1212754): Move to ChromeSurveyController. + SurveyController.getInstance().showSurveyIfAvailable(TabUtils.getActivity(tab), mSiteId, + mShowAsBottomSheet, mDisplayLogoResId, mDelegate.getLifecycleDispatcher()); super.onCloseButtonClicked(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/SurveyInfoBarDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/SurveyInfoBarDelegate.java index e42276f..cb123a4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/SurveyInfoBarDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/SurveyInfoBarDelegate.java
@@ -4,6 +4,8 @@ package org.chromium.chrome.browser.infobar; +import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; + /** * Delegate for survey info bar actions. */ @@ -36,4 +38,10 @@ * @return The string that will be displayed on the info bar. */ String getSurveyPromptString(); + + /** + * Called to supply the survey info bar with lifecycle dispatcher used to show survey. + * @return The lifecycle dispatcher used to dispatch signals from the activity. + * */ + ActivityLifecycleDispatcher getLifecycleDispatcher(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeActivityNativeDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeActivityNativeDelegate.java index b90e8ee..d472be3 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeActivityNativeDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeActivityNativeDelegate.java
@@ -43,7 +43,8 @@ void onStopWithNative(); /** - * @return Whether the activity linked to the delegate has been destroyed or is finishing. + * @return Whether the activity linked to the delegate has been destroyed or is finishing. The + * majority of clients should prefer the method in {@link ActivityUtils}. */ boolean isActivityFinishingOrDestroyed();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/printing/PrintShareActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/printing/PrintShareActivity.java index d55a014..2d57252 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/printing/PrintShareActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/printing/PrintShareActivity.java
@@ -4,14 +4,10 @@ package org.chromium.chrome.browser.printing; -import android.app.Activity; - -import org.chromium.chrome.R; import org.chromium.chrome.browser.ChromeAccessorActivity; import org.chromium.chrome.browser.preferences.Pref; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.tab.Tab; -import org.chromium.components.browser_ui.widget.MenuOrKeyboardActionController; import org.chromium.components.user_prefs.UserPrefs; import org.chromium.printing.PrintingController; import org.chromium.printing.PrintingControllerImpl; @@ -20,10 +16,11 @@ * A simple activity that allows Chrome to expose print as an option in the share menu. */ public class PrintShareActivity extends ChromeAccessorActivity { + public static final String BROADCAST_ACTION = "PrintShareActivityBroadcastAction"; + @Override - protected void handleAction(Activity triggeringActivity, - MenuOrKeyboardActionController menuOrKeyboardActionController) { - menuOrKeyboardActionController.onMenuOrKeyboardAction(R.id.print_id, true); + protected String getBroadcastAction() { + return BROADCAST_ACTION; } public static boolean featureIsAvailable(Tab currentTab) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/send_tab_to_self/SendTabToSelfShareActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/send_tab_to_self/SendTabToSelfShareActivity.java index b5579f4..e3efdada 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/send_tab_to_self/SendTabToSelfShareActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/send_tab_to_self/SendTabToSelfShareActivity.java
@@ -4,68 +4,22 @@ package org.chromium.chrome.browser.send_tab_to_self; -import android.app.Activity; - -import androidx.annotation.VisibleForTesting; - import org.chromium.chrome.browser.ChromeAccessorActivity; -import org.chromium.chrome.browser.app.ChromeActivity; -import org.chromium.chrome.browser.settings.SettingsLauncherImpl; import org.chromium.chrome.browser.share.send_tab_to_self.SendTabToSelfAndroidBridge; -import org.chromium.chrome.browser.share.send_tab_to_self.SendTabToSelfCoordinator; -import org.chromium.chrome.browser.sync.ProfileSyncService; import org.chromium.chrome.browser.tab.Tab; -import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; -import org.chromium.components.browser_ui.bottomsheet.BottomSheetControllerProvider; -import org.chromium.components.browser_ui.widget.MenuOrKeyboardActionController; -import org.chromium.content_public.browser.NavigationEntry; -import org.chromium.ui.base.WindowAndroid; /** * A simple activity that allows Chrome to expose send tab to self as an option in the share menu. */ public class SendTabToSelfShareActivity extends ChromeAccessorActivity { - private static BottomSheetController sBottomSheetControllerForTesting; + public static final String BROADCAST_ACTION = "SendTabToSelfShareActivityBroadcastAction"; @Override - public void handleAction(Activity triggeringActivity, - MenuOrKeyboardActionController menuOrKeyboardActionController) { - // TODO(crbug.com/1175155): Remove ChromeActivity reference once the activity tab is - // available via UnownedUserData. - ChromeActivity chromeActivity = (ChromeActivity) triggeringActivity; - Tab tab = chromeActivity.getActivityTabProvider().get(); - if (tab == null) return; - NavigationEntry entry = tab.getWebContents().getNavigationController().getVisibleEntry(); - if (entry == null) return; - BottomSheetController controller = - getBottomSheetController(chromeActivity.getWindowAndroid()); - if (controller == null) { - return; - } - - boolean isSyncEnabled = - ProfileSyncService.get() != null && ProfileSyncService.get().isSyncRequested(); - controller.requestShowContent( - SendTabToSelfCoordinator.createBottomSheetContent(triggeringActivity, - entry.getUrl().getSpec(), entry.getTitle(), entry.getTimestamp(), - controller, new SettingsLauncherImpl(), isSyncEnabled), - true); - // TODO(crbug.com/968246): Remove the need to call this explicitly and instead have it - // automatically show since PeekStateEnabled is set to false. - controller.expandSheet(); + protected String getBroadcastAction() { + return BROADCAST_ACTION; } public static boolean featureIsAvailable(Tab currentTab) { return SendTabToSelfAndroidBridge.isFeatureAvailable(currentTab.getWebContents()); } - - private BottomSheetController getBottomSheetController(WindowAndroid window) { - if (sBottomSheetControllerForTesting != null) return sBottomSheetControllerForTesting; - return BottomSheetControllerProvider.from(window); - } - - @VisibleForTesting - public static void setBottomSheetControllerForTesting(BottomSheetController controller) { - sBottomSheetControllerForTesting = controller; - } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/share/ShareRegistrationCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/share/ShareRegistrationCoordinator.java new file mode 100644 index 0000000..ad97f053 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/share/ShareRegistrationCoordinator.java
@@ -0,0 +1,221 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.share; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; + +import org.chromium.base.ContextUtils; +import org.chromium.base.IntentUtils; +import org.chromium.base.Log; +import org.chromium.base.supplier.Supplier; +import org.chromium.chrome.browser.send_tab_to_self.SendTabToSelfShareActivity; +import org.chromium.chrome.browser.settings.SettingsLauncherImpl; +import org.chromium.chrome.browser.share.send_tab_to_self.SendTabToSelfCoordinator; +import org.chromium.chrome.browser.sync.ProfileSyncService; +import org.chromium.chrome.browser.tab.Tab; +import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; +import org.chromium.content_public.browser.NavigationEntry; + +import java.util.HashMap; +import java.util.Map; + +/** + * Glues the sub-class of ChromeAccessorActivity to the relevant share action. + * + * When adding a new share action to Chrome, + * 1. Add a new subclass of {@link ChromeAccessorActivity}. + * 2. Register that activity and the proper intent-filter in AndroidManifest.xml. + * 3. Register a {@link BroadcastReceiver} here to catch the action broadcasted from (1). + * 4. Implement the sharing logic in a function inside this class and call it from (3). + **/ +public class ShareRegistrationCoordinator { + private static final String TAG = "ShareRegCoord"; + + /** Handles receiving share-specific internal broadcasts. */ + public static class ShareBroadcastReceiver extends BroadcastReceiver { + /** A token used to verify that the broadcast is a Chrome-internal one. */ + private static final String EXTRA_TOKEN = "receiver_token"; + + /** The type to pass along to the receiver, used to route the request. */ + @VisibleForTesting + static final String EXTRA_TYPE = "share_type"; + + /** Top-level intent action that allows the share actions to be grouped in one intent. */ + private static final String RECEIVER_ACTION = "ShareBroadcastReceiverBroadcastAction"; + + private static final Map<Integer, ShareBroadcastReceiver> sReceiverMap = new HashMap<>(); + + /** + * Send a share broadcast with the given action. + * @param taskId The Activity task id for the broadcast destination,. + * @param action The share action to be broadcast. + */ + public static void sendShareBroadcastWithAction(int taskId, String action) { + sendShareBroadcastWithAction(taskId, action, ContextUtils.getApplicationContext()); + } + + @VisibleForTesting + static void sendShareBroadcastWithAction(int taskId, String action, Context context) { + ShareBroadcastReceiver receiver = sReceiverMap.get(taskId); + if (receiver == null) { + Log.e(TAG, + "Attempt to send share broadcast before reciever was registered: \"" + + action + "\""); + return; + } + + Intent intent = new Intent(RECEIVER_ACTION); + // Attach the parent ShareRegistrationCoordinator's hashcode to verify the intent. + intent.putExtra(EXTRA_TOKEN, receiver.getHashCodeToken()); + intent.putExtra(EXTRA_TYPE, action); + intent.putExtra(ShareHelper.EXTRA_TASK_ID, taskId); + + context.sendBroadcast(intent); + } + + private final Map<String, Runnable> mShareMap = new HashMap<>(); + private final int mTaskId; + private final int mHashCodeToken; + private Context mContext; + private boolean mIsDestroyed; + + /** + * @param activity The activity to associate with this receiver. + */ + public ShareBroadcastReceiver(Activity activity) { + this(activity.getTaskId(), ContextUtils.getApplicationContext()); + } + + @VisibleForTesting + ShareBroadcastReceiver(int taskId, Context context) { + mTaskId = taskId; + mContext = context; + // We do this so the token is durable over the lifetime of the app. + mHashCodeToken = hashCode(); + + sReceiverMap.put(mTaskId, this); + mContext.registerReceiver(this, new IntentFilter(RECEIVER_ACTION)); + } + + /** Destroy the receiver. */ + public void destroy() { + mIsDestroyed = true; + sReceiverMap.remove(mTaskId); + mContext.unregisterReceiver(this); + + mContext = null; + } + + /** + * Register this share type. + * @param type The share type to register. + * @param runnable The runnable to run when the share type is broadcasted. + */ + public void registerShareType(String type, Runnable runnable) { + if (mIsDestroyed) { + Log.e(TAG, "Attempted to register type after destruction: \"" + type + "\"."); + return; + } + + if (mShareMap.containsKey(type)) { + throw new IllegalStateException( + "Only one instance of a share type should be registered at a time."); + } + + mShareMap.put(type, runnable); + } + + @Override + public void onReceive(Context context, Intent intent) { + String type = IntentUtils.safeGetStringExtra(intent, EXTRA_TYPE); + if (mIsDestroyed) { + Log.e(TAG, "Broadcast received after destruction: \"" + type + "\"."); + return; + } + + boolean hasToken = intent.hasExtra(EXTRA_TOKEN) + && intent.getIntExtra(EXTRA_TOKEN, 0) == mHashCodeToken; + boolean hasTaskId = intent.hasExtra(ShareHelper.EXTRA_TASK_ID) + && intent.getIntExtra(ShareHelper.EXTRA_TASK_ID, 0) == mTaskId; + if (!hasToken || !hasTaskId) return; + + if (!mShareMap.containsKey(type)) { + Log.e(TAG, "Unidentified type receieved: \"" + type + "\"."); + return; + } + + mShareMap.get(type).run(); + } + + private int getHashCodeToken() { + return mHashCodeToken; + } + } + + private final ShareBroadcastReceiver mShareBroadcastReceiver; + + /** ShareRegistrationCoordinator constructor. */ + public ShareRegistrationCoordinator(Activity activity, Supplier<Tab> currentTabSupplier, + BottomSheetController bottomSheetController) { + mShareBroadcastReceiver = new ShareBroadcastReceiver(activity); + + mShareBroadcastReceiver.registerShareType( + SendTabToSelfShareActivity.BROADCAST_ACTION, () -> { + NavigationEntry entry = currentTabSupplier.hasValue() + ? currentTabSupplier.get() + .getWebContents() + .getNavigationController() + .getVisibleEntry() + : null; + doSendTabToSelfShare(activity, entry, bottomSheetController); + }); + } + + /** + * Register the type runnable pair. + * @param type The share type to register. + * @param runnable The runnable to invoke for the given share type. + */ + public void registerShareType(String type, Runnable runnable) { + mShareBroadcastReceiver.registerShareType(type, runnable); + } + + /** Destroys this component */ + public void destroy() { + mShareBroadcastReceiver.destroy(); + } + + /** + * Starts a send tab to self share action. + * + * @param context The current application context. + * @param entry The current {@link NavigationEntry}, null if the current tab isn't available or + * doesn't have a visible entry. + * @param bottomSheetController Controls what's shown in the bottom sheet. + */ + @VisibleForTesting + void doSendTabToSelfShare(@NonNull Context context, @Nullable NavigationEntry entry, + @NonNull BottomSheetController bottomSheetController) { + if (entry == null) return; + boolean isSyncEnabled = + ProfileSyncService.get() != null && ProfileSyncService.get().isSyncRequested(); + bottomSheetController.requestShowContent( + SendTabToSelfCoordinator.createBottomSheetContent(context, entry.getUrl().getSpec(), + entry.getTitle(), entry.getTimestamp(), bottomSheetController, + new SettingsLauncherImpl(), isSyncEnabled), + true); + // TODO(crbug.com/968246): Remove the need to call this explicitly and instead have it + // automatically show since PeekStateEnabled is set to false. + bottomSheetController.expandSheet(); + } +} \ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/survey/ChromeSurveyController.java b/chrome/android/java/src/org/chromium/chrome/browser/survey/ChromeSurveyController.java index a342139..d28c2af5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/survey/ChromeSurveyController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/survey/ChromeSurveyController.java
@@ -9,6 +9,7 @@ import android.text.TextUtils; import androidx.annotation.IntDef; +import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import org.chromium.base.CommandLine; @@ -25,6 +26,7 @@ import org.chromium.chrome.browser.infobar.InfoBarIdentifier; import org.chromium.chrome.browser.infobar.SurveyInfoBar; import org.chromium.chrome.browser.infobar.SurveyInfoBarDelegate; +import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; import org.chromium.chrome.browser.preferences.ChromePreferenceKeys; import org.chromium.chrome.browser.preferences.SharedPreferencesManager; import org.chromium.chrome.browser.privacy.settings.PrivacyPreferencesManagerImpl; @@ -51,15 +53,15 @@ */ public class ChromeSurveyController implements InfoBarAnimationListener { private static final String TAG = "ChromeSurveyCtrler"; - private static final long REQUIRED_VISIBILITY_DURATION_MS = 5000; @VisibleForTesting + static final long REQUIRED_VISIBILITY_DURATION_MS = 5000; + @VisibleForTesting public static final String COMMAND_LINE_PARAM_NAME = "survey_override_site_id"; @VisibleForTesting static final String MAX_NUMBER = "max-number"; @VisibleForTesting static final String SITE_ID_PARAM_NAME = "site-id"; - private static boolean sForceUmaEnabledForTesting; /** @@ -108,12 +110,15 @@ private final String mTriggerId; private final String mPrefKeyPromptDisplayed; + private final @Nullable ActivityLifecycleDispatcher mLifecycleDispatcher; @VisibleForTesting - ChromeSurveyController(String triggerId) { + ChromeSurveyController( + String triggerId, @Nullable ActivityLifecycleDispatcher lifecycleDispatcher) { mTriggerId = triggerId; mPrefKeyPromptDisplayed = ChromePreferenceKeys.CHROME_SURVEY_PROMPT_DISPLAYED_TIMESTAMP.createKey(mTriggerId); + mLifecycleDispatcher = lifecycleDispatcher; } /** @@ -121,11 +126,12 @@ * @param tabModelSelector The tab model selector to access the tab on which the survey will be * shown. */ - public static void initialize(TabModelSelector tabModelSelector) { + public static void initialize(TabModelSelector tabModelSelector, + @Nullable ActivityLifecycleDispatcher lifecycleDispatcher) { assert tabModelSelector != null; if (!isSurveyEnabled() || TextUtils.isEmpty(getTriggerId())) return; new StartDownloadIfEligibleTask( - new ChromeSurveyController(getTriggerId()), tabModelSelector) + new ChromeSurveyController(getTriggerId(), lifecycleDispatcher), tabModelSelector) .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } @@ -387,6 +393,11 @@ return ContextUtils.getApplicationContext().getString( R.string.chrome_survey_prompt); } + + @Override + public ActivityLifecycleDispatcher getLifecycleDispatcher() { + return mLifecycleDispatcher; + } }; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/survey/SurveyController.java b/chrome/android/java/src/org/chromium/chrome/browser/survey/SurveyController.java index 0c6698ee..2fe61ef 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/survey/SurveyController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/survey/SurveyController.java
@@ -7,9 +7,11 @@ import android.app.Activity; import android.content.Context; +import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import org.chromium.chrome.browser.AppHooks; +import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; /** * Class that controls retrieving and displaying surveys. Clients should call #downloadSurvey() and @@ -72,15 +74,26 @@ Runnable onFailureRunnable) {} /** + * @deprecated Use #showSurveyIfAvailable(Activity, String, boolean, int, + * ActivityLifecycleDispatcher). + */ + @Deprecated + public void showSurveyIfAvailable( + Activity activity, String siteId, boolean showAsBottomSheet, int displayLogoResId) { + this.showSurveyIfAvailable(activity, siteId, showAsBottomSheet, displayLogoResId, null); + } + + /** * Show the survey. * @param activity The client activity for the survey request. * @param siteId The id of the site from where the survey will be downloaded. * @param showAsBottomSheet Whether the survey should be presented as a bottom sheet or not. * @param displayLogoResId Optional resource id of the logo to be displayed on the survey. * Pass 0 for no logo. + * @param lifecycleDispatcher LifecycleDispatcher that will dispatch different activity signals. */ - public void showSurveyIfAvailable( - Activity activity, String siteId, boolean showAsBottomSheet, int displayLogoResId) {} + public void showSurveyIfAvailable(Activity activity, String siteId, boolean showAsBottomSheet, + int displayLogoResId, @Nullable ActivityLifecycleDispatcher lifecycleDispatcher) {} /** * Clears the survey cache containing responses and history.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityIncognitoMetricTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityIncognitoMetricTest.java index b1bae5e..549a670 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityIncognitoMetricTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityIncognitoMetricTest.java
@@ -85,7 +85,7 @@ assertEquals(0, RecordHistogram.getHistogramTotalCountForTesting(UMA_KEY)); Intent intent = createMinimalIncognitoCustomTabIntent(); CustomTabIntentDataProvider.addReaderModeUIExtras(intent); - IncognitoCustomTabIntentDataProvider.addIncongitoExtrasForChromeFeatures( + IncognitoCustomTabIntentDataProvider.addIncognitoExtrasForChromeFeatures( intent, IntentHandler.IncognitoCCTCallerId.READER_MODE); mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityIncognitoTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityIncognitoTest.java index 260ab27..179f9d6 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityIncognitoTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityIncognitoTest.java
@@ -373,7 +373,7 @@ public void ensureAddCustomMenuItemIsEnabledForReaderMode() throws Exception { Intent intent = createMinimalIncognitoCustomTabIntent(); CustomTabIntentDataProvider.addReaderModeUIExtras(intent); - IncognitoCustomTabIntentDataProvider.addIncongitoExtrasForChromeFeatures( + IncognitoCustomTabIntentDataProvider.addIncognitoExtrasForChromeFeatures( intent, IntentHandler.IncognitoCCTCallerId.READER_MODE); CustomTabActivity activity = launchIncognitoCustomTab(intent); CustomTabsTestUtils.openAppMenuAndAssertMenuShown(activity);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/survey/ChromeSurveyControllerIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/survey/ChromeSurveyControllerIntegrationTest.java index d9d616b..3664e86 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/survey/ChromeSurveyControllerIntegrationTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/survey/ChromeSurveyControllerIntegrationTest.java
@@ -26,6 +26,7 @@ import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.infobar.InfoBarIdentifier; import org.chromium.chrome.browser.infobar.SurveyInfoBar; +import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; import org.chromium.chrome.browser.preferences.ChromePreferenceKeys; import org.chromium.chrome.browser.preferences.SharedPreferencesManager; import org.chromium.chrome.browser.survey.ChromeSurveyController.InfoBarClosingState; @@ -182,8 +183,8 @@ } private static class AlwaysSuccessfulSurveyController extends SurveyController { - public CallbackHelper downloadCallbackHelper = new CallbackHelper(); - public CallbackHelper showSurveyCallbackHelper = new CallbackHelper(); + public final CallbackHelper downloadCallbackHelper = new CallbackHelper(); + public final CallbackHelper showSurveyCallbackHelper = new CallbackHelper(); @Override public void downloadSurvey(Context context, String triggerId, Runnable onSuccessRunnable, @@ -195,8 +196,9 @@ } @Override - public void showSurveyIfAvailable( - Activity activity, String siteId, boolean showAsBottomSheet, int displayLogoResId) { + public void showSurveyIfAvailable(Activity activity, String siteId, + boolean showAsBottomSheet, int displayLogoResId, + ActivityLifecycleDispatcher lifecycleDispatcher) { showSurveyCallbackHelper.notifyCalled(); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ui/system/StatusBarColorControllerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ui/system/StatusBarColorControllerTest.java index 0d70dbca..4a1374a 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/ui/system/StatusBarColorControllerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ui/system/StatusBarColorControllerTest.java
@@ -75,7 +75,7 @@ @Feature({"StatusBar"}) @MinAndroidSdkLevel(Build.VERSION_CODES.LOLLIPOP_MR1) @Restriction({UiRestriction.RESTRICTION_TYPE_PHONE}) // Status bar is always black on tablets - public void testColorToggleIncongitoInOverview() throws Exception { + public void testColorToggleIncognitoInOverview() throws Exception { ChromeTabbedActivity activity = mActivityTestRule.getActivity(); Resources resources = activity.getResources(); final int expectedOverviewStandardColor = defaultColorFallbackToBlack( @@ -87,13 +87,13 @@ "about:blank", true /* incognito */, TabLaunchType.FROM_CHROME_UI); TabModelSelector tabModelSelector = activity.getTabModelSelector(); TestThreadUtils.runOnUiThreadBlocking( - () -> { tabModelSelector.selectModel(true /* incongito */); }); + () -> { tabModelSelector.selectModel(true /* incognito */); }); TestThreadUtils.runOnUiThreadBlocking( () -> { activity.getLayoutManager().showOverview(false /* animate */); }); waitForStatusBarColor(activity, expectedOverviewIncognitoColor); TestThreadUtils.runOnUiThreadBlocking( - () -> { tabModelSelector.selectModel(false /* incongito */); }); + () -> { tabModelSelector.selectModel(false /* incognito */); }); ThemeTestUtils.assertStatusBarColor(activity, expectedOverviewStandardColor); }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/send_tab_to_self/SendTabToSelfShareActivityTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/send_tab_to_self/SendTabToSelfShareActivityTest.java index 441b09e9..0535f86 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/send_tab_to_self/SendTabToSelfShareActivityTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/send_tab_to_self/SendTabToSelfShareActivityTest.java
@@ -4,9 +4,7 @@ package org.chromium.chrome.browser.send_tab_to_self; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.eq; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.support.test.filters.SmallTest; @@ -17,66 +15,36 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.MockitoAnnotations; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; import org.robolectric.annotation.Config; import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.base.test.util.JniMocker; -import org.chromium.chrome.browser.ActivityTabProvider; -import org.chromium.chrome.browser.app.ChromeActivity; -import org.chromium.chrome.browser.profiles.Profile; -import org.chromium.chrome.browser.profiles.ProfileJni; import org.chromium.chrome.browser.share.send_tab_to_self.SendTabToSelfAndroidBridge; import org.chromium.chrome.browser.share.send_tab_to_self.SendTabToSelfAndroidBridgeJni; -import org.chromium.chrome.browser.share.send_tab_to_self.SendTabToSelfCoordinator; -import org.chromium.chrome.browser.sync.ProfileSyncService; import org.chromium.chrome.browser.tab.Tab; -import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent; -import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; -import org.chromium.content_public.browser.NavigationController; -import org.chromium.content_public.browser.NavigationEntry; import org.chromium.content_public.browser.WebContents; -import org.chromium.content_public.browser.test.util.TestThreadUtils; -import org.chromium.url.JUnitTestGURLs; -/** Tests for SendTabToSelfShareActivityTest */ +/** Tests for SendTabToSelfShareActivity */ @RunWith(BaseRobolectricTestRunner.class) @Config(manifest = Config.NONE) public class SendTabToSelfShareActivityTest { @Rule public JniMocker mocker = new JniMocker(); - @Mock - public Profile.Natives mMockProfileNatives; + @Rule + public MockitoRule mMockitoRule = MockitoJUnit.rule(); @Mock SendTabToSelfAndroidBridge.Natives mNativeMock; @Mock private Tab mTab; @Mock - private ChromeActivity mChromeActivity; - @Mock - private ActivityTabProvider mActivityTabProvider; - @Mock private WebContents mWebContents; - @Mock - private NavigationController mNavigationController; - @Mock - private NavigationEntry mNavigationEntry; - @Mock - private BottomSheetContent mBottomSheetContent; - @Mock - private BottomSheetController mBottomSheetController; - - @Mock - private ProfileSyncService mProfileSyncService; - - private Profile mProfile; @Before public void setUp() { - MockitoAnnotations.initMocks(this); mocker.mock(SendTabToSelfAndroidBridgeJni.TEST_HOOKS, mNativeMock); - mocker.mock(ProfileJni.TEST_HOOKS, mMockProfileNatives); } @Test @@ -89,33 +57,4 @@ boolean actual = SendTabToSelfShareActivity.featureIsAvailable(mTab); Assert.assertEquals(expected, actual); } - - @Test - @SmallTest - public void testHandleShareAction() { - // Setup the mocked object chain to get to the profile. - when(mChromeActivity.getActivityTabProvider()).thenReturn(mActivityTabProvider); - when(mActivityTabProvider.get()).thenReturn(mTab); - when(mMockProfileNatives.fromWebContents(eq(mWebContents))).thenReturn(mProfile); - - // Setup the mocked object chain to get to the url, title and timestamp. - when(mTab.getWebContents()).thenReturn(mWebContents); - when(mWebContents.getNavigationController()).thenReturn(mNavigationController); - when(mNavigationController.getVisibleEntry()).thenReturn(mNavigationEntry); - when(mNavigationEntry.getUrl()) - .thenReturn(JUnitTestGURLs.getGURL(JUnitTestGURLs.EXAMPLE_URL)); - - // Setup the mocked object for sync settings. - when(mProfileSyncService.isSyncRequested()).thenReturn(true); - TestThreadUtils.runOnUiThreadBlocking( - () -> ProfileSyncService.overrideForTests(mProfileSyncService)); - - // Setup the mocked object chain to get the bottom controller. - SendTabToSelfShareActivity shareActivity = new SendTabToSelfShareActivity(); - SendTabToSelfCoordinator.setBottomSheetContentForTesting(mBottomSheetContent); - SendTabToSelfShareActivity.setBottomSheetControllerForTesting(mBottomSheetController); - shareActivity.handleAction(/* triggeringActivity= */ mChromeActivity, - /* menuOrKeyboardActionController= */ mChromeActivity); - verify(mBottomSheetController).requestShowContent(any(BottomSheetContent.class), eq(true)); - } }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/share/OWNERS b/chrome/android/junit/src/org/chromium/chrome/browser/share/OWNERS new file mode 100644 index 0000000..f1b7df2 --- /dev/null +++ b/chrome/android/junit/src/org/chromium/chrome/browser/share/OWNERS
@@ -0,0 +1 @@ +file://chrome/android/java/src/org/chromium/chrome/browser/share/OWNERS
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/share/ShareRegistrationCoordinatorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/share/ShareRegistrationCoordinatorTest.java new file mode 100644 index 0000000..9d133d5 --- /dev/null +++ b/chrome/android/junit/src/org/chromium/chrome/browser/share/ShareRegistrationCoordinatorTest.java
@@ -0,0 +1,188 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.share; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.support.test.filters.SmallTest; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.Spy; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.robolectric.Robolectric; +import org.robolectric.annotation.Config; + +import org.chromium.base.supplier.Supplier; +import org.chromium.base.test.BaseRobolectricTestRunner; +import org.chromium.base.test.util.JniMocker; +import org.chromium.chrome.browser.profiles.Profile; +import org.chromium.chrome.browser.share.ShareRegistrationCoordinator.ShareBroadcastReceiver; +import org.chromium.chrome.browser.share.send_tab_to_self.SendTabToSelfAndroidBridge; +import org.chromium.chrome.browser.share.send_tab_to_self.SendTabToSelfAndroidBridgeJni; +import org.chromium.chrome.browser.sync.ProfileSyncService; +import org.chromium.chrome.browser.tab.Tab; +import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent; +import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; +import org.chromium.content_public.browser.NavigationEntry; +import org.chromium.content_public.browser.test.util.TestThreadUtils; +import org.chromium.url.JUnitTestGURLs; + +/** Tests for ShareRegistrationCoordinator. */ +@RunWith(BaseRobolectricTestRunner.class) +@Config(manifest = Config.NONE) +public class ShareRegistrationCoordinatorTest { + @Rule + public MockitoRule mMockitoRule = MockitoJUnit.rule(); + @Rule + public JniMocker mocker = new JniMocker(); + + @Mock + SendTabToSelfAndroidBridge.Natives mNativeMock; + + @Mock + private Profile mProfile; + @Mock + private Tab mTab; + @Mock + private NavigationEntry mNavigationEntry; + @Mock + private BottomSheetController mBottomSheetController; + @Mock + private ProfileSyncService mProfileSyncService; + @Mock + private Context mContext; + + @Captor + private ArgumentCaptor<Intent> mIntentCaptor; + + @Spy + private Activity mActivity; + + private Supplier<Tab> mCurrentTabSupplier; + private ShareRegistrationCoordinator mShareRegistrationCoordinator; + + @Before + public void setUp() { + mocker.mock(SendTabToSelfAndroidBridgeJni.TEST_HOOKS, mNativeMock); + Profile.setLastUsedProfileForTesting(mProfile); + mActivity = Mockito.spy(Robolectric.buildActivity(Activity.class).create().get()); + + mCurrentTabSupplier = () -> mTab; + mShareRegistrationCoordinator = new ShareRegistrationCoordinator( + mActivity, mCurrentTabSupplier, mBottomSheetController); + } + + @Test + @SmallTest + public void doSendTabToSelfShare() { + // Setup the mocked object chain to get to the url, title and timestamp. + when(mNavigationEntry.getUrl()) + .thenReturn(JUnitTestGURLs.getGURL(JUnitTestGURLs.EXAMPLE_URL)); + + // Setup the mocked object for sync settings. + when(mProfileSyncService.isSyncRequested()).thenReturn(true); + TestThreadUtils.runOnUiThreadBlocking( + () -> ProfileSyncService.overrideForTests(mProfileSyncService)); + + mShareRegistrationCoordinator.doSendTabToSelfShare( + mActivity, mNavigationEntry, mBottomSheetController); + verify(mBottomSheetController).requestShowContent(any(BottomSheetContent.class), eq(true)); + } + + @Test + @SmallTest + public void sendShareBroadcastWithAction() { + ShareBroadcastReceiver receiver = new ShareBroadcastReceiver(mActivity); + Runnable runnable = Mockito.mock(Runnable.class); + receiver.registerShareType("foobar", runnable); + + ShareBroadcastReceiver.sendShareBroadcastWithAction(mActivity.getTaskId(), "foobar"); + verify(runnable).run(); + + receiver.destroy(); + } + + @Test + @SmallTest + public void sendShareBroadcastWithAction_NoRegisteredReceiver() { + ShareBroadcastReceiver.sendShareBroadcastWithAction(mActivity.getTaskId(), "foobar"); + verify(mContext, times(0)).sendBroadcast(mIntentCaptor.capture()); + } + + @Test + @SmallTest + public void sendShareBroadcastWithAction_ReplaceShareTypeRunnable() { + ShareBroadcastReceiver receiver = new ShareBroadcastReceiver(mActivity); + Runnable runnable1 = Mockito.mock(Runnable.class); + Runnable runnable2 = Mockito.mock(Runnable.class); + receiver.registerShareType("foobar", runnable1); + try { + receiver.registerShareType("foobar", runnable2); + Assert.assertTrue("Expected exception to be thrown", false); + } catch (IllegalStateException e) { + } + } + + @Test + @SmallTest + public void sendShareBroadcastWithAction_RegisterShareTypeAfterDestruction() { + ShareBroadcastReceiver receiver = new ShareBroadcastReceiver(mActivity); + receiver.destroy(); + Runnable runnable = Mockito.mock(Runnable.class); + receiver.registerShareType("foobar", runnable); + + ShareBroadcastReceiver.sendShareBroadcastWithAction(mActivity.getTaskId(), "foobar"); + verify(runnable, times(0)).run(); + } + + @Test + @SmallTest + public void sendShareBroadcastWithAction_SendBroadcastAfterDestruction() { + ShareBroadcastReceiver receiver = new ShareBroadcastReceiver(mActivity); + Runnable runnable = Mockito.mock(Runnable.class); + receiver.registerShareType("foobar", runnable); + receiver.destroy(); + + ShareBroadcastReceiver.sendShareBroadcastWithAction(mActivity.getTaskId(), "foobar"); + verify(runnable, times(0)).run(); + } + + @Test + @SmallTest + public void sendShareBroadcastWithAction_DifferentActivity() { + ShareBroadcastReceiver receiver1 = new ShareBroadcastReceiver(mActivity); + Runnable runnable1 = Mockito.mock(Runnable.class); + receiver1.registerShareType("foobar", runnable1); + + doReturn(123).when(mActivity).getTaskId(); + ShareBroadcastReceiver receiver2 = new ShareBroadcastReceiver(mActivity); + Runnable runnable2 = Mockito.mock(Runnable.class); + receiver2.registerShareType("foobar", runnable2); + + ShareBroadcastReceiver.sendShareBroadcastWithAction(123, "foobar"); + verify(runnable1, times(0)).run(); + verify(runnable2).run(); + + receiver1.destroy(); + receiver2.destroy(); + } +} \ No newline at end of file
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/survey/ChromeSurveyControllerFlowTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/survey/ChromeSurveyControllerFlowTest.java index b628920..db64006 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/survey/ChromeSurveyControllerFlowTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/survey/ChromeSurveyControllerFlowTest.java
@@ -7,6 +7,7 @@ import static org.mockito.ArgumentMatchers.any; import android.content.Context; +import android.os.Looper; import androidx.annotation.Nullable; @@ -20,6 +21,7 @@ import org.mockito.Mockito; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; +import org.robolectric.Shadows; import org.robolectric.annotation.Config; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; @@ -28,18 +30,23 @@ import org.robolectric.shadows.ShadowLooper; import org.chromium.base.CommandLine; +import org.chromium.base.ContextUtils; import org.chromium.base.metrics.test.ShadowRecordHistogram; import org.chromium.base.task.test.BackgroundShadowAsyncTask; import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.base.test.util.CallbackHelper; import org.chromium.base.test.util.JniMocker; +import org.chromium.base.test.util.PayloadCallbackHelper; +import org.chromium.chrome.R; import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.infobar.InfoBarContainer; import org.chromium.chrome.browser.infobar.SurveyInfoBar; import org.chromium.chrome.browser.infobar.SurveyInfoBarDelegate; +import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; import org.chromium.chrome.browser.preferences.ChromePreferenceKeys; import org.chromium.chrome.browser.preferences.SharedPreferencesManager; +import org.chromium.chrome.browser.survey.ChromeSurveyController.InfoBarClosingState; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabObserver; import org.chromium.chrome.browser.tabmodel.TabModelSelector; @@ -48,6 +55,7 @@ import java.util.HashMap; import java.util.Map; +import java.util.concurrent.TimeUnit; /** * "Integration" style unit tests for {@link ChromeSurveyController} that mocks most of the @@ -96,14 +104,14 @@ @Implements(SurveyInfoBar.class) static class ShadowSurveyInfoBar { - static CallbackHelper sShowInfoBarCallback; + static PayloadCallbackHelper<SurveyInfoBarDelegate> sShowInfoBarCallback; @Implementation public static void showSurveyInfoBar(WebContents webContents, String siteId, boolean showAsBottomSheet, int displayLogoResId, SurveyInfoBarDelegate surveyInfoBarDelegate) { Assert.assertNotNull("sShowInfoBarCallback is null.", sShowInfoBarCallback); - sShowInfoBarCallback.notifyCalled(); + sShowInfoBarCallback.notifyCalled(surveyInfoBarDelegate); } } @@ -131,6 +139,8 @@ WebContents mMockWebContent; @Mock InfoBarContainer mMockInfoBarContainer; + @Mock + ActivityLifecycleDispatcher mMockLifecycleDispatcher; private final TestSurveyController mTestSurveyController = new TestSurveyController(); @@ -147,7 +157,7 @@ ChromeSurveyController.SITE_ID_PARAM_NAME, TEST_TRIGGER_ID); ShadowChromeFeatureList.sParamValues.put(ChromeSurveyController.MAX_NUMBER, "99"); ShadowInfoBarContainer.sInfoBarContainer = mMockInfoBarContainer; - ShadowSurveyInfoBar.sShowInfoBarCallback = new CallbackHelper(); + ShadowSurveyInfoBar.sShowInfoBarCallback = new PayloadCallbackHelper<>(); // Set user is selected and by pass the rate limit. The rate limiting logic is tested in // ChromeSurveyControllerTest. @@ -252,17 +262,8 @@ } @Test - public void testPresentSurvey_ValidTab() { - setupTabMocks(); - initializeChromeSurveyController(); - assertCallbackAssignedInSurveyController(); - - // Verify the survey should be attempted to present on a valid tab. - mockTabReady(); - mTestSurveyController.onDownloadSuccessRunnable.run(); - - Assert.assertEquals("presentSurvey should be triggered.", 1, - ShadowSurveyInfoBar.sShowInfoBarCallback.getCallCount()); + public void testPresentSurvey_ValidTab_SurveyInfobarDelegate() { + presentSurveyInfoBarInValidTab(); } @Test @@ -275,15 +276,13 @@ Mockito.doReturn(true).when(mMockTab).isLoading(); mTestSurveyController.onDownloadSuccessRunnable.run(); - Assert.assertEquals("presentSurvey should not be triggered.", 0, - ShadowSurveyInfoBar.sShowInfoBarCallback.getCallCount()); + assertSurveyInfoBarShown(false); Assert.assertNotNull("Tab observer should be registered.", mTabObserver); // Assume tab loading is complete. mockTabReady(); mTabObserver.onPageLoadFinished(mMockTab, null); - Assert.assertEquals("presentSurvey should be triggered.", 1, - ShadowSurveyInfoBar.sShowInfoBarCallback.getCallCount()); + assertSurveyInfoBarShown(true); } @Test @@ -296,15 +295,13 @@ Mockito.doReturn(false).when(mMockTab).isUserInteractable(); mTestSurveyController.onDownloadSuccessRunnable.run(); - Assert.assertEquals("presentSurvey should not be triggered.", 0, - ShadowSurveyInfoBar.sShowInfoBarCallback.getCallCount()); + assertSurveyInfoBarShown(false); Assert.assertNotNull("Tab observer should be registered.", mTabObserver); // Assume tab loading is complete. mockTabReady(); mTabObserver.onInteractabilityChanged(mMockTab, true); - Assert.assertEquals("presentSurvey should br triggered.", 1, - ShadowSurveyInfoBar.sShowInfoBarCallback.getCallCount()); + assertSurveyInfoBarShown(true); } @Test @@ -317,21 +314,120 @@ Mockito.when(mMockModelSelector.getCurrentTab()).thenReturn(null); mTestSurveyController.onDownloadSuccessRunnable.run(); - Assert.assertEquals("presentSurvey should not be triggered.", 0, - ShadowSurveyInfoBar.sShowInfoBarCallback.getCallCount()); + assertSurveyInfoBarShown(false); Assert.assertNotNull( "TabModelSelectorObserver should be registered.", mTabModelSelectorObserver); - // Assume tab selector can provide a tab (e.g. switch to a fully loaded tab) + // Assume tab selector can provide a tab (e.g. switch to a fully loaded tab). mockTabReady(); Mockito.when(mMockModelSelector.getCurrentTab()).thenReturn(mMockTab); mTabModelSelectorObserver.onChange(); - Assert.assertEquals("presentSurvey should triggered.", 1, - ShadowSurveyInfoBar.sShowInfoBarCallback.getCallCount()); + assertSurveyInfoBarShown(true); + } + + @Test + public void testSurveyInfoBarDelegate_getLifecycleDispatcher() { + presentSurveyInfoBarInValidTab(); + SurveyInfoBarDelegate surveyInfoBarDelegate = + ShadowSurveyInfoBar.sShowInfoBarCallback.getOnlyPayloadBlocking(); + Assert.assertEquals("#getLifecycleDispatcher is different.", mMockLifecycleDispatcher, + surveyInfoBarDelegate.getLifecycleDispatcher()); + } + + @Test + public void testSurveyInfoBarDelegate_getSurveyPromptString() { + presentSurveyInfoBarInValidTab(); + SurveyInfoBarDelegate surveyInfoBarDelegate = + ShadowSurveyInfoBar.sShowInfoBarCallback.getOnlyPayloadBlocking(); + + Assert.assertEquals("#getPromptString is different.", + ContextUtils.getApplicationContext().getString(R.string.chrome_survey_prompt), + surveyInfoBarDelegate.getSurveyPromptString()); + } + + @Test + public void testSurveyInfoBarDelegate_onSurveyTriggered() { + presentSurveyInfoBarInValidTab(); + SurveyInfoBarDelegate surveyInfoBarDelegate = + ShadowSurveyInfoBar.sShowInfoBarCallback.getOnlyPayloadBlocking(); + + surveyInfoBarDelegate.onSurveyTriggered(); + assertInfoBarClosingStateRecorded(InfoBarClosingState.ACCEPTED_SURVEY); + assertInfoBarDisplayedRecorded(); + } + + @Test + public void testSurveyInfoBarDelegate_onSurveyInfoBarClosed() { + presentSurveyInfoBarInValidTab(); + SurveyInfoBarDelegate surveyInfoBarDelegate = + ShadowSurveyInfoBar.sShowInfoBarCallback.getOnlyPayloadBlocking(); + + surveyInfoBarDelegate.onSurveyInfoBarClosed( + /*viaCloseButton=*/false, /*visibleWhenClosed=*/true); + assertInfoBarClosingStateRecorded(InfoBarClosingState.VISIBLE_INDIRECT); + assertInfoBarDisplayedNotRecorded("onSurveyInfoBarClosed with VISIBLE_INDIRECT " + + "should not result in info bar displayed being recorded."); + + surveyInfoBarDelegate.onSurveyInfoBarClosed( + /*viaCloseButton=*/false, /*visibleWhenClosed=*/false); + assertInfoBarClosingStateRecorded(InfoBarClosingState.HIDDEN_INDIRECT); + assertInfoBarDisplayedNotRecorded("onSurveyInfoBarClosed with HIDDEN_INDIRECT " + + "should not result in info bar displayed being recorded."); + + // #onSurveyInfoBarClosed(true, false) is not a valid case, so skipped in test. + surveyInfoBarDelegate.onSurveyInfoBarClosed( + /*viaCloseButton=*/true, /*visibleWhenClosed=*/true); + assertInfoBarClosingStateRecorded(InfoBarClosingState.CLOSE_BUTTON); + assertInfoBarDisplayedRecorded(); + } + + @Test + public void testSurveyInfoBarDelegate_onSurveyInfoBarTabBecomeInteractable() { + presentSurveyInfoBarInValidTab(); + SurveyInfoBarDelegate surveyInfoBarDelegate = + ShadowSurveyInfoBar.sShowInfoBarCallback.getOnlyPayloadBlocking(); + + surveyInfoBarDelegate.onSurveyInfoBarTabInteractabilityChanged(true); + Shadows.shadowOf(Looper.myLooper()) + .idleFor(ChromeSurveyController.REQUIRED_VISIBILITY_DURATION_MS, + TimeUnit.MILLISECONDS); + assertInfoBarDisplayedRecorded(); + } + + @Test + public void testSurveyInfoBarDelegate_onSurveyInfoBarTabBecomeNotInteractable() { + presentSurveyInfoBarInValidTab(); + SurveyInfoBarDelegate surveyInfoBarDelegate = + ShadowSurveyInfoBar.sShowInfoBarCallback.getOnlyPayloadBlocking(); + + surveyInfoBarDelegate.onSurveyInfoBarTabInteractabilityChanged(true); + Shadows.shadowOf(Looper.myLooper()) + .idleFor(ChromeSurveyController.REQUIRED_VISIBILITY_DURATION_MS - 1, + TimeUnit.MILLISECONDS); + surveyInfoBarDelegate.onSurveyInfoBarTabInteractabilityChanged(false); + Shadows.shadowOf(Looper.myLooper()).runToEndOfTasks(); + assertInfoBarDisplayedNotRecorded("Info bar should not be recorded as displayed " + + "if interactivity changed before minimum required visibility duration."); + } + + @Test + public void testSurveyInfoBarDelegate_onSurveyInfoBarTabHidden() { + presentSurveyInfoBarInValidTab(); + SurveyInfoBarDelegate surveyInfoBarDelegate = + ShadowSurveyInfoBar.sShowInfoBarCallback.getOnlyPayloadBlocking(); + + surveyInfoBarDelegate.onSurveyInfoBarTabInteractabilityChanged(true); + Shadows.shadowOf(Looper.myLooper()) + .idleFor(ChromeSurveyController.REQUIRED_VISIBILITY_DURATION_MS - 1, + TimeUnit.MILLISECONDS); + surveyInfoBarDelegate.onSurveyInfoBarTabHidden(); + Shadows.shadowOf(Looper.myLooper()).runToEndOfTasks(); + assertInfoBarDisplayedNotRecorded("Info bar should not be recorded as displayed " + + "if hidden before minimum required visibility duration."); } private void initializeChromeSurveyController() { - ChromeSurveyController.initialize(mMockModelSelector); + ChromeSurveyController.initialize(mMockModelSelector, mMockLifecycleDispatcher); try { BackgroundShadowAsyncTask.runBackgroundTasks(); } catch (Exception e) { @@ -340,6 +436,17 @@ ShadowLooper.runUiThreadTasks(); } + private void presentSurveyInfoBarInValidTab() { + setupTabMocks(); + initializeChromeSurveyController(); + assertCallbackAssignedInSurveyController(); + + // Verify the survey should be attempted to present on a valid tab. + mockTabReady(); + mTestSurveyController.onDownloadSuccessRunnable.run(); + assertSurveyInfoBarShown(true); + } + private void mockTabReady() { Mockito.doReturn(false).when(mMockTab).isLoading(); Mockito.doReturn(true).when(mMockTab).isUserInteractable(); @@ -373,6 +480,32 @@ mTestSurveyController.onDownloadFailureRunnable); } + private void assertSurveyInfoBarShown(boolean shown) { + Assert.assertEquals("presentSurvey should triggered.", shown ? 1 : 0, + ShadowSurveyInfoBar.sShowInfoBarCallback.getCallCount()); + if (shown) { + Assert.assertNotNull("SurveyInfoBarDelegate is null.", + ShadowSurveyInfoBar.sShowInfoBarCallback.getOnlyPayloadBlocking()); + } + } + + private void assertInfoBarClosingStateRecorded(@InfoBarClosingState int state) { + int count = ShadowRecordHistogram.getHistogramValueCountForTesting( + "Android.Survey.InfoBarClosingState", state); + Assert.assertEquals( + String.format("InfoBarClosingState for state <%d> is not recorded.", state), 1, + count); + } + + private void assertInfoBarDisplayedRecorded() { + Assert.assertTrue("SharedPreference for InfoBarShown is not recorded.", + mSharedPreferencesManager.contains(mPrefKey)); + } + + private void assertInfoBarDisplayedNotRecorded(String reason) { + Assert.assertFalse(reason, mSharedPreferencesManager.contains(mPrefKey)); + } + private static class TestSurveyController extends SurveyController { public final CallbackHelper downloadIfApplicableCallback = new CallbackHelper();
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/survey/ChromeSurveyControllerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/survey/ChromeSurveyControllerTest.java index 5fb93a2..49492ecc 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/survey/ChromeSurveyControllerTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/survey/ChromeSurveyControllerTest.java
@@ -249,7 +249,7 @@ private int mMaxNumber; RiggedSurveyController(int randomNumberToReturn, int dayOfYear, int maxNumber) { - super(TEST_SURVEY_TRIGGER_ID); + super(TEST_SURVEY_TRIGGER_ID, null); mRandomNumberToReturn = randomNumberToReturn; mDayOfYear = dayOfYear; mMaxNumber = maxNumber; @@ -271,11 +271,11 @@ } } - class TestChromeSurveyController extends ChromeSurveyController { + static class TestChromeSurveyController extends ChromeSurveyController { private Tab mTab; public TestChromeSurveyController(String triggerId) { - super(triggerId); + super(triggerId, null); } @Override
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index cd8dd25f..100eb78 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -5215,8 +5215,8 @@ </message> <!-- Experimental Lacros Infobar--> - <message name="IDS_EXPERIMENTAL_LACROS_WARNING_MESSAGE" desc="Message shown when user launches Lacros, an experimental feature, for the first time."> - Lacros is an experimental Browser. Please report issues with: Help > "Report an issue...". + <message name="IDS_EXPERIMENTAL_LACROS_WARNING_MESSAGE" desc="Message shown when user launches Lacros, an experimental feature."> + Experimental browser! May lose data or compromise privacy or security. Please report issues with: Help > "Report an issue...". </message> <message name="IDS_EXPERIMENTAL_LACROS_WARNING_MESSAGE_PRIMARY" desc="Addendum which is sometimes added to the initial warning message."> @@ -7639,8 +7639,8 @@ <message name="IDS_SHARING_REMOTE_COPY_NOTIFICATION_DESCRIPTION" desc="Second line of text displayed in a Remote Copy notification."> Press <ph name="MODIFIER_KEY_DESCRIPTION">$1<ex>Ctrl+V</ex></ph> to paste </message> - <message name="IDS_OMNIBOX_TOOLTIP_SMS_REMOTE_FETCHER" translateable="false" desc="The label of item for sms remote fetcher in the omnibox for showing device name when one device is available."> - Tap the notification on <ph name="DEVICE_NAME">$1<ex>Jimmy's Pixel</ex></ph> to verify your phone number + <message name="IDS_OMNIBOX_TOOLTIP_SMS_REMOTE_FETCHER" translateable="false" desc="The label of item for sms remote fetcher in the omnibox for showing confirmation of an interaction on the remote device."> + Chrome has sent the verification code to the website upon your approval on <ph name="DEVICE_NAME">$1<ex>Jimmy's Pixel</ex></ph> </message> <if expr="not use_titlecase"> <message name="IDS_CONTENT_CONTEXT_SHARING_CLICK_TO_CALL_MULTIPLE_DEVICES" desc="The label of item for click to call in context menu when multiple devices are available.">
diff --git a/chrome/app/generated_resources_grd/IDS_EXPERIMENTAL_LACROS_WARNING_MESSAGE.png.sha1 b/chrome/app/generated_resources_grd/IDS_EXPERIMENTAL_LACROS_WARNING_MESSAGE.png.sha1 index cfc5da4..e4cd29c 100644 --- a/chrome/app/generated_resources_grd/IDS_EXPERIMENTAL_LACROS_WARNING_MESSAGE.png.sha1 +++ b/chrome/app/generated_resources_grd/IDS_EXPERIMENTAL_LACROS_WARNING_MESSAGE.png.sha1
@@ -1 +1 @@ -8fb028bfd6f53770392671b73d3fc9ab4ace0bc0 \ No newline at end of file +851ecde2849c4846c62fdc1cb43379460bf57a35 \ No newline at end of file
diff --git a/chrome/app/resources/generated_resources_ar.xtb b/chrome/app/resources/generated_resources_ar.xtb index 4d6e53c..4344493 100644 --- a/chrome/app/resources/generated_resources_ar.xtb +++ b/chrome/app/resources/generated_resources_ar.xtb
@@ -3806,7 +3806,7 @@ <translation id="5125751979347152379">عنوان URL غير صالح.</translation> <translation id="5126611267288187364">عرض التغييرات</translation> <translation id="5127620150973591153">رمز إتمام الاتصال الآمن: <ph name="TOKEN" /></translation> -<translation id="5127805178023152808">المزامنة غير مفعّلة</translation> +<translation id="5127805178023152808">المزامنة متوقفة.</translation> <translation id="5127881134400491887">إدارة اتصالات الشبكة</translation> <translation id="512903556749061217">متصل</translation> <translation id="5130675701626084557">تعذَّر تنزيل الملف الشخصي. يُرجى إعادة المحاولة لاحقًا أو التواصل مع مشغّل شبكة الجوّال للحصول على المساعدة.</translation>
diff --git a/chrome/app/resources/generated_resources_hy.xtb b/chrome/app/resources/generated_resources_hy.xtb index e33a144d..f62567f 100644 --- a/chrome/app/resources/generated_resources_hy.xtb +++ b/chrome/app/resources/generated_resources_hy.xtb
@@ -383,7 +383,7 @@ <translation id="1415708812149920388">Սեղմատախտակի ընթերցումը մերժվեց</translation> <translation id="1415990189994829608">Այս տեսակի աշխատաշրջանում <ph name="EXTENSION_NAME" />-ը (ընդլայնման ID «<ph name="EXTENSION_ID" />») չի թույլատրվում:</translation> <translation id="1418954524306642206">Ընտրել տպիչի PPD ֆայլ</translation> -<translation id="1420834118113404499">Մեդիա արտոնագրեր</translation> +<translation id="1420834118113404499">Մեդիա լիցենզիաներ</translation> <translation id="1420920093772172268"><ph name="TURN_ON_BLUETOOTH_LINK" />՝ զուգակցումը թույլատրելու համար</translation> <translation id="1422159345171879700">Բեռնել վտանգավոր հրահանգաշարերը</translation> <translation id="1423716227250567100">Այս գործողության արդյունքում տեղի կունենա հետևյալը․ @@ -5659,7 +5659,7 @@ <translation id="7186303001964993981"><ph name="ORIGIN" /> կայքը չի կարող բացել այս պանակը, քանի որ այն պարունակում է համակարգի ֆայլեր</translation> <translation id="7187428571767585875">Գրանցամատյանի գրառումներ, որոնք ենթակա են հեռացման կամ փոփոխման՝</translation> <translation id="7189234443051076392">Համոզվեք, որ ձեր սարքում բավարար տարածք կա</translation> -<translation id="7189451821249468368">Ձեր արտոնագրերը բավարար չեն այս սարքը գրանցելու համար։ Լրացուցիչ արտոնագրեր գնելու համար դիմեք վաճառքների բաժին։ Եթե կարծում եք, որ այս հաղորդագրությունը սխալմամբ է ձեզ ուղարկվել, դիմեք աջակցման կենտրոն։</translation> +<translation id="7189451821249468368">Ձեր լիցենզիաները բավարար չեն այս սարքը գրանցելու համար։ Լրացուցիչ լիցենզիաներ գնելու համար դիմեք վաճառքների բաժին։ Եթե կարծում եք, որ այս հաղորդագրությունը սխալմամբ է ձեզ ուղարկվել, դիմեք աջակցման կենտրոն։</translation> <translation id="7189965711416741966">Մատնահետքն ավելացված է:</translation> <translation id="7191159667348037">Անհայտ տպիչ (USB)</translation> <translation id="7193051357671784796">Այս հավելվածն ավելացվել է ձեր կազմակերպության կողմից: Վերագործարկեք հավելվածը՝ տեղադրումն ավարտելու համար:</translation>
diff --git a/chrome/app/resources/generated_resources_ja.xtb b/chrome/app/resources/generated_resources_ja.xtb index 253e46ac..8d6af7f49 100644 --- a/chrome/app/resources/generated_resources_ja.xtb +++ b/chrome/app/resources/generated_resources_ja.xtb
@@ -4211,10 +4211,10 @@ <translation id="5583640892426849032">Backspace</translation> <translation id="5584088138253955452">ユーザー名を保存しますか?</translation> <translation id="5584091888252706332">起動時</translation> -<translation id="5584915726528712820"><ph name="BEGIN_PARAGRAPH1" />これは、お使いのデバイスとその使用状況(電池残量、システムとアプリのアクティビティ、エラーなど)に関する一般的な情報です。このデータは Android の改善に使用されます。また一部の集計情報は、Google のアプリのほか、Android デベロッパーなどのパートナーが開発するアプリやサービスの品質改善にも役立てられます。<ph name="END_PARAGRAPH1" /> +<translation id="5584915726528712820"><ph name="BEGIN_PARAGRAPH1" />送信されるのは、お使いのデバイスとその使用状況(電池残量、システムとアプリのアクティビティ、エラーなど)に関する一般的な情報です。この情報は Android の改善に使用されます。また一部の集計情報は、Google のアプリのほか、Android デベロッパーなどのパートナーが開発するアプリやサービスの品質改善にも役立てられます。<ph name="END_PARAGRAPH1" /> <ph name="BEGIN_PARAGRAPH2" />この機能をオフにした場合でも、システム アップデートやセキュリティなどの重要なサービスで必要となる情報は、デバイスからこれまでどおり送信されます。<ph name="END_PARAGRAPH2" /> <ph name="BEGIN_PARAGRAPH3" />デバイスの所有者は、[設定] > [詳細設定] > [診断と使用状況のデータを Google に自動送信する] でこの機能を管理できます。<ph name="END_PARAGRAPH3" /> - <ph name="BEGIN_PARAGRAPH4" />これに加えて [ウェブとアプリのアクティビティ] の設定もオンにしている場合、このデータは Google アカウントにも保存される可能性があります。account.google.com でアカウント設定を閲覧、削除、変更することができます。<ph name="END_PARAGRAPH4" /></translation> + <ph name="BEGIN_PARAGRAPH4" />[ウェブとアプリのアクティビティ] の設定もオンにしている場合、診断と使用状況のデータは Google アカウントにも保存される可能性があります。account.google.com でアカウント設定を閲覧、削除、変更することができます。<ph name="END_PARAGRAPH4" /></translation> <translation id="5585019845078534178">カード</translation> <translation id="5585118885427931890">ブックマーク フォルダを作成できませんでした。</translation> <translation id="558563010977877295">特定のページまたはページセットを開く</translation> @@ -6680,10 +6680,10 @@ <translation id="826511437356419340">ウィンドウ概観モードに切り替わりました。移動するにはスワイプするか、キーボードの場合は Tab キーを押してください。</translation> <translation id="8266947622852630193">すべての入力方法</translation> <translation id="8267539814046467575">プリンタの追加</translation> -<translation id="8267961145111171918"><ph name="BEGIN_PARAGRAPH1" />これは、お使いのデバイスとその使用状況(電池残量、システムとアプリのアクティビティ、エラーなど)に関する一般的な情報です。このデータは、Android の改善に使用されます。また一部の集計情報は、Google のアプリのほか、Android デベロッパーなどのパートナーが開発するアプリやサービスの品質改善にも役立てられます。<ph name="END_PARAGRAPH1" /> +<translation id="8267961145111171918"><ph name="BEGIN_PARAGRAPH1" />送信されるのは、お使いのデバイスとその使用状況(電池残量、システムとアプリのアクティビティ、エラーなど)に関する一般的な情報です。この情報は、Android の改善に使用されます。また一部の集計情報は、Google のアプリのほか、Android デベロッパーなどのパートナーが開発するアプリやサービスの品質改善にも役立てられます。<ph name="END_PARAGRAPH1" /> <ph name="BEGIN_PARAGRAPH2" />この機能をオフにした場合でも、システム アップデートやセキュリティなどの重要なサービスで必要となる情報は、デバイスからこれまでどおり送信されます。<ph name="END_PARAGRAPH2" /> <ph name="BEGIN_PARAGRAPH3" />デバイスの所有者は、[設定] > [詳細設定] > [診断と使用状況のデータを Google に自動送信する] でこの機能を管理できます。<ph name="END_PARAGRAPH3" /> - <ph name="BEGIN_PARAGRAPH4" />これに加えて、お子様のアカウントで [ウェブとアプリのアクティビティ] の設定もオンにしている場合、このデータはお子様の Google アカウントにも保存される可能性があります。これらの設定の詳細と設定を調整する方法については、families.google.com をご覧ください。<ph name="END_PARAGRAPH4" /></translation> + <ph name="BEGIN_PARAGRAPH4" />お子様のアカウントで [ウェブとアプリのアクティビティ] の設定もオンにしている場合、診断と使用状況のデータはお子様の Google アカウントにも保存される可能性があります。これらの設定の詳細と設定を調整する方法については、families.google.com をご覧ください。<ph name="END_PARAGRAPH4" /></translation> <translation id="826905130698769948">クライアント証明書が無効です</translation> <translation id="8270242299912238708">PDF ドキュメント</translation> <translation id="827097179112817503">ホームボタンを表示する</translation> @@ -7090,7 +7090,7 @@ <translation id="8737914367566358838">ページを翻訳する言語を選択してください</translation> <translation id="8740247629089392745">この Chromebook を <ph name="SUPERVISED_USER_NAME" /> に渡す準備ができました。設定はあと少しで完了です。</translation> <translation id="8741944563400125534">スイッチ アクセス設定ガイド</translation> -<translation id="8742998548129056176">これは、お使いのデバイスと使用状況に関する一般的な情報(電池残量、システムやアプリのアクティビティ、エラーなど)です。このデータは Android の改善に使用され、統計情報の一部は、Google アプリや、Android デベロッパーなどのパートナーが開発するアプリやサービスの品質改善にも役立てられます。</translation> +<translation id="8742998548129056176">送信されるのは、お使いのデバイスと使用状況に関する一般的な情報(電池残量、システムやアプリのアクティビティ、エラーなど)です。この情報は Android の改善に使用され、統計情報の一部は、Google アプリや、Android デベロッパーなどのパートナーが開発するアプリやサービスの品質改善にも役立てられます。</translation> <translation id="8743164338060742337"><ph name="NETWORK_INDEX" /> 番目のネットワーク(全 <ph name="NETWORK_COUNT" /> 件)、<ph name="NETWORK_NAME" />、<ph name="NETWORK_PROVIDER_NAME" />、信号強度 <ph name="SIGNAL_STRENGTH" />%、管理者によって管理、接続</translation> <translation id="8746654918629346731">「<ph name="EXTENSION_NAME" />」はリクエスト済みです</translation> <translation id="874689135111202667">{0,plural, =1{1 個のファイルをこのサイトにアップロードしますか?}other{# 個のファイルをこのサイトにアップロードしますか?}}</translation>
diff --git a/chrome/app/resources/generated_resources_mr.xtb b/chrome/app/resources/generated_resources_mr.xtb index e975349..2923779 100644 --- a/chrome/app/resources/generated_resources_mr.xtb +++ b/chrome/app/resources/generated_resources_mr.xtb
@@ -2541,7 +2541,7 @@ <translation id="370415077757856453">JavaScript ब्लॉक केले</translation> <translation id="3704331259350077894">ऑपरेशनची समाप्ती</translation> <translation id="3705722231355495246">-</translation> -<translation id="3706463572498736864">प्रति पत्रक पेज</translation> +<translation id="3706463572498736864">प्रति शीट पेज</translation> <translation id="370649949373421643">Wi-fi सक्षम करा</translation> <translation id="370665806235115550">लोड करीत आहे...</translation> <translation id="3707163604290651814">सध्या <ph name="NAME" /> म्हणून साइन इन केले</translation>
diff --git a/chrome/app/resources/generated_resources_sw.xtb b/chrome/app/resources/generated_resources_sw.xtb index 316636b..d1c2bdba 100644 --- a/chrome/app/resources/generated_resources_sw.xtb +++ b/chrome/app/resources/generated_resources_sw.xtb
@@ -4187,7 +4187,7 @@ <translation id="5543983818738093899">Inakagua hali...</translation> <translation id="554517701842997186">Kitekelezaji</translation> <translation id="5545335608717746497">{NUM_TABS,plural, =1{Weka kichupo kwenye kikundi}other{Weka vichupo kwenye kikundi}}</translation> -<translation id="5546865291508181392">Pata</translation> +<translation id="5546865291508181392">Tafuta</translation> <translation id="5548075230008247516">Umeacha kuchagua vipengee vyote, hali ya kuchagua imefungwa.</translation> <translation id="5548159762883465903">{NUM_OTHER_TABS,plural, =0{"<ph name="TAB_TITLE" />"}=1{"<ph name="TAB_TITLE" />" na Kichupo Kingine 1}other{"<ph name="TAB_TITLE" />" na Vichupo Vingine #}}</translation> <translation id="5548606607480005320">Angalizo la usalama</translation>
diff --git a/chrome/app/resources/generated_resources_th.xtb b/chrome/app/resources/generated_resources_th.xtb index eaaa2429..db9013be 100644 --- a/chrome/app/resources/generated_resources_th.xtb +++ b/chrome/app/resources/generated_resources_th.xtb
@@ -200,7 +200,7 @@ <translation id="1203942045716040624">ผู้ปฏิบัติงานที่แชร์: <ph name="SCRIPT_URL" /></translation> <translation id="1209796539517632982">เซิร์ฟเวอร์ชื่ออัตโนมัติ</translation> <translation id="1211769675100312947">ทางลัดที่คุณเป็นผู้คัดสรร</translation> -<translation id="1213254615020057352">ส่งข้อมูลการใช้งานและการวินิจฉัย ช่วยปรับปรุงประสบการณ์การใช้งาน Android ของบุตรหลานให้ดีขึ้นด้วยการส่งข้อมูลการวินิจฉัย อุปกรณ์ และการใช้งานแอปไปยัง Google โดยอัตโนมัติ โดยจะไม่มีการใช้ข้อมูลนี้ในการระบุชื่อบุตรหลานของคุณ และจะช่วยให้แอปและระบบมีความเสถียร พร้อมทั้งปรับปรุงด้านอื่นๆ ข้อมูลที่รวบรวมมาบางส่วนจะมีประโยชน์ต่อแอปและพาร์ทเนอร์ของ Google ด้วย เช่น นักพัฒนาซอฟต์แวร์ Android เจ้าของเป็นผู้บังคับใช้การตั้งค่านี้ เจ้าของอาจเลือกที่จะส่งข้อมูลการวินิจฉัยและการใช้งานสำหรับอุปกรณ์นี้ไปยัง Google หากเปิดการตั้งค่ากิจกรรมเพิ่มเติมบนเว็บและแอปสำหรับบุตรหลาน ระบบอาจบันทึกข้อมูลนี้ไว้ในบัญชี Google ของบุตรหลาน</translation> +<translation id="1213254615020057352">ส่งข้อมูลการใช้งานและการวินิจฉัย ช่วยปรับปรุงประสบการณ์การใช้งาน Android ของบุตรหลานให้ดีขึ้นด้วยการส่งข้อมูลการวินิจฉัย อุปกรณ์ และการใช้งานแอปไปยัง Google โดยอัตโนมัติ โดยจะไม่มีการใช้ข้อมูลนี้ในการระบุชื่อบุตรหลานของคุณ และจะช่วยให้แอปและระบบมีความเสถียร พร้อมทั้งปรับปรุงด้านอื่นๆ ข้อมูลที่รวบรวมมาบางส่วนจะมีประโยชน์ต่อแอปและพาร์ทเนอร์ของ Google ด้วย เช่น นักพัฒนาแอป Android เจ้าของเป็นผู้บังคับใช้การตั้งค่านี้ เจ้าของอาจเลือกที่จะส่งข้อมูลการวินิจฉัยและการใช้งานสำหรับอุปกรณ์นี้ไปยัง Google หากเปิดการตั้งค่ากิจกรรมเพิ่มเติมบนเว็บและแอปสำหรับบุตรหลาน ระบบอาจบันทึกข้อมูลนี้ไว้ในบัญชี Google ของบุตรหลาน</translation> <translation id="121384500095351701">ดาวน์โหลดไฟล์นี้อย่างปลอดภัยไม่ได้</translation> <translation id="1215411991991485844">มีการเพิ่มแอปพลิเคชันที่ทำงานอยู่เบื้องหลังตัวใหม่</translation> <translation id="1216542092748365687">นำลายนิ้วมือออก</translation> @@ -1838,7 +1838,7 @@ <translation id="2942279350258725020">Android Messages</translation> <translation id="2942560570858569904">กำลังรอ...</translation> <translation id="2942581856830209953">ปรับแต่งหน้านี้</translation> -<translation id="2944060181911631861">ส่งข้อมูลการใช้งานและการวินิจฉัย ช่วยปรับปรุงประสบการณ์การใช้งาน Android ของคุณให้ดีขึ้นด้วยการส่งข้อมูลการวินิจฉัย อุปกรณ์ และการใช้งานแอปไปยัง Google โดยอัตโนมัติ ซึ่งจะช่วยให้แอปและระบบมีความเสถียร พร้อมทั้งปรับปรุงด้านอื่นๆ ข้อมูลที่รวบรวมมาบางส่วนจะมีประโยชน์ต่อแอปและพาร์ทเนอร์ของ Google ด้วย เช่น นักพัฒนาซอฟต์แวร์ Android หากเปิดการตั้งค่ากิจกรรมเพิ่มเติมบนเว็บและแอปไว้ ระบบอาจบันทึกข้อมูลนี้ไว้ในบัญชี Google ของคุณ <ph name="BEGIN_LINK1" />ดูข้อมูลเพิ่มเติม<ph name="END_LINK1" /></translation> +<translation id="2944060181911631861">ส่งข้อมูลการใช้งานและการวินิจฉัย ช่วยปรับปรุงประสบการณ์การใช้งาน Android ของคุณให้ดีขึ้นด้วยการส่งข้อมูลการวินิจฉัย อุปกรณ์ และการใช้งานแอปไปยัง Google โดยอัตโนมัติ ซึ่งจะช่วยให้แอปและระบบมีความเสถียร พร้อมทั้งปรับปรุงด้านอื่นๆ ข้อมูลที่รวบรวมมาบางส่วนจะมีประโยชน์ต่อแอปและพาร์ทเนอร์ของ Google ด้วย เช่น นักพัฒนาแอป Android หากเปิดการตั้งค่ากิจกรรมเพิ่มเติมบนเว็บและแอปไว้ ระบบอาจบันทึกข้อมูลนี้ไว้ในบัญชี Google ของคุณ <ph name="BEGIN_LINK1" />ดูข้อมูลเพิ่มเติม<ph name="END_LINK1" /></translation> <translation id="2946119680249604491">เพิ่มการเชื่อมต่อ</translation> <translation id="2946640296642327832">เปิดใช้งานบลูทูธ</translation> <translation id="2947605845283690091">การท่องเว็บควรจะเร็ว โปรดใช้เวลาสักครู่เพื่อ<ph name="BEGIN_LINK" />ตรวจสอบส่วนขยาย<ph name="END_LINK" />ตอนนี้เลย</translation> @@ -2313,7 +2313,7 @@ <translation id="3473479545200714844">แว่นขยายหน้าจอ</translation> <translation id="3474218480460386727">ใช้ตัวอักษรไม่เกิน 99 ตัวสำหรับคำใหม่</translation> <translation id="3475843873335999118">ขออภัย ระบบยังคงไม่รู้จักลายนิ้วมือของคุณ โปรดป้อนรหัสผ่าน</translation> -<translation id="3476303763173086583">ส่งข้อมูลการใช้งานและการวินิจฉัย ช่วยปรับปรุงประสบการณ์การใช้งาน Android ของบุตรหลานให้ดีขึ้นด้วยการส่งข้อมูลการวินิจฉัย อุปกรณ์ และการใช้งานแอปไปยัง Google โดยอัตโนมัติ โดยจะไม่มีการใช้ข้อมูลนี้ในการระบุชื่อบุตรหลานของคุณ และจะช่วยให้แอปและระบบมีความเสถียร พร้อมทั้งปรับปรุงด้านอื่นๆ ข้อมูลที่รวบรวมมาบางส่วนจะมีประโยชน์ต่อแอปและพาร์ทเนอร์ของ Google ด้วย เช่น นักพัฒนาซอฟต์แวร์ Android เจ้าของเป็นผู้บังคับใช้<ph name="BEGIN_LINK1" />การตั้งค่า<ph name="END_LINK1" />นี้ เจ้าของอาจเลือกที่จะส่งข้อมูลการวินิจฉัยและการใช้งานสำหรับอุปกรณ์นี้ไปยัง Google หากเปิดการตั้งค่ากิจกรรมเพิ่มเติมบนเว็บและแอปสำหรับบุตรหลาน ระบบอาจบันทึกข้อมูลนี้ไว้ในบัญชี Google ของบุตรหลาน <ph name="BEGIN_LINK2" />ดูข้อมูลเพิ่มเติม<ph name="END_LINK2" /></translation> +<translation id="3476303763173086583">ส่งข้อมูลการใช้งานและการวินิจฉัย ช่วยปรับปรุงประสบการณ์การใช้งาน Android ของบุตรหลานให้ดีขึ้นด้วยการส่งข้อมูลการวินิจฉัย อุปกรณ์ และการใช้งานแอปไปยัง Google โดยอัตโนมัติ โดยจะไม่มีการใช้ข้อมูลนี้ในการระบุชื่อบุตรหลานของคุณ และจะช่วยให้แอปและระบบมีความเสถียร พร้อมทั้งปรับปรุงด้านอื่นๆ ข้อมูลที่รวบรวมมาบางส่วนจะมีประโยชน์ต่อแอปและพาร์ทเนอร์ของ Google ด้วย เช่น นักพัฒนาแอป Android เจ้าของเป็นผู้บังคับใช้<ph name="BEGIN_LINK1" />การตั้งค่า<ph name="END_LINK1" />นี้ เจ้าของอาจเลือกที่จะส่งข้อมูลการวินิจฉัยและการใช้งานสำหรับอุปกรณ์นี้ไปยัง Google หากเปิดการตั้งค่ากิจกรรมเพิ่มเติมบนเว็บและแอปสำหรับบุตรหลาน ระบบอาจบันทึกข้อมูลนี้ไว้ในบัญชี Google ของบุตรหลาน <ph name="BEGIN_LINK2" />ดูข้อมูลเพิ่มเติม<ph name="END_LINK2" /></translation> <translation id="347670947055184738">อ๊ะ! ระบบไม่สามารถดึงข้อมูลนโยบายจากอุปกรณ์</translation> <translation id="347785443197175480">อนุญาตให้ <ph name="HOST" /> เข้าถึงกล้องถ่ายรูปและไมโครโฟนของคุณต่อไป</translation> <translation id="3479552764303398839">ไม่ใช่ตอนนี้</translation> @@ -2662,7 +2662,7 @@ <translation id="3834775135533257713">ไม่สามารถเพิ่มแอปพลิเคชัน "<ph name="TO_INSTALL_APP_NAME" />" เนื่องจากขัดแย้งกับ "<ph name="INSTALLED_APP_NAME" />"</translation> <translation id="3835233591525155343">การใช้งานอุปกรณ์ของคุณ</translation> <translation id="3835522725882634757">แย่แล้ว! เซิร์ฟเวอร์นี้กำลังส่งข้อมูลที่ <ph name="PRODUCT_NAME" /> ไม่เข้าใจ โปรด<ph name="BEGIN_LINK" />รายงานข้อบกพร่อง<ph name="END_LINK" /> และรวม<ph name="BEGIN2_LINK" />รายการที่ยังไม่ผ่านกระบวนการ<ph name="END2_LINK" />ไว้ด้วย</translation> -<translation id="383669374481694771">นี่คือข้อมูลทั่วไปเกี่ยวกับอุปกรณ์และการใช้งานอุปกรณ์ (เช่น ระดับแบตเตอรี่ กิจกรรมในระบบและแอป ตลอดจนข้อผิดพลาด) ระบบจะใช้ข้อมูลเพื่อปรับปรุง Android และข้อมูลที่รวบรวมมาบางส่วนก็ยังจะช่วยให้แอปและพาร์ทเนอร์ของ Google เช่น นักพัฒนาซอฟต์แวร์ Android พัฒนาแอปและผลิตภัณฑ์ของตนให้ดีขึ้นด้วย</translation> +<translation id="383669374481694771">นี่คือข้อมูลทั่วไปเกี่ยวกับอุปกรณ์และการใช้งานอุปกรณ์ (เช่น ระดับแบตเตอรี่ กิจกรรมในระบบและแอป ตลอดจนข้อผิดพลาด) ระบบจะใช้ข้อมูลเพื่อปรับปรุง Android และข้อมูลที่รวบรวมมาบางส่วนก็ยังจะช่วยให้แอปและพาร์ทเนอร์ของ Google เช่น นักพัฒนาแอป Android พัฒนาแอปและผลิตภัณฑ์ของตนให้ดีขึ้นด้วย</translation> <translation id="3838085852053358637">ไม่สามารถโหลดส่วนขยาย</translation> <translation id="3838486795898716504"><ph name="PAGE_TITLE" /> เพิ่มเติม</translation> <translation id="383891835335927981">ไม่มีการซูมเข้าหรือซูมออกเว็บไซต์ใดๆ</translation> @@ -2998,7 +2998,7 @@ <translation id="4209464433672152343">เอกสารจะ<ph name="BEGIN_LINK_HELP" />ส่งไปยัง Google<ph name="END_LINK_HELP" /> เพื่อเตรียมพิมพ์ ดู แก้ไข และจัดการเครื่องพิมพ์และประวัติการพิมพ์ได้ใน<ph name="BEGIN_LINK_DASHBOARD" />แดชบอร์ด Google Cloud Print<ph name="END_LINK_DASHBOARD" /></translation> <translation id="4210048056321123003">กำลังดาวน์โหลดเครื่องเสมือน</translation> <translation id="421182450098841253">&แสดงแถบบุ๊กมาร์ก</translation> -<translation id="4211851069413100178">ส่งข้อมูลการใช้งานและการวินิจฉัย ช่วยปรับปรุงประสบการณ์การใช้งาน Android ของคุณให้ดีขึ้นด้วยการส่งข้อมูลการวินิจฉัย อุปกรณ์ และการใช้งานแอปไปยัง Google โดยอัตโนมัติ ซึ่งจะช่วยให้แอปและระบบมีความเสถียร พร้อมทั้งปรับปรุงด้านอื่นๆ ข้อมูลที่รวบรวมมาบางส่วนจะมีประโยชน์ต่อแอปและพาร์ทเนอร์ของ Google ด้วย เช่น นักพัฒนาซอฟต์แวร์ Android เจ้าของเป็นผู้บังคับใช้<ph name="BEGIN_LINK1" />การตั้งค่า<ph name="END_LINK1" />นี้ เจ้าของอาจเลือกที่จะส่งข้อมูลการวินิจฉัยและการใช้งานสำหรับอุปกรณ์นี้ไปยัง Google หากเปิดการตั้งค่ากิจกรรมเพิ่มเติมบนเว็บและแอปไว้ ระบบอาจบันทึกข้อมูลนี้ไว้ในบัญชี Google ของคุณ <ph name="BEGIN_LINK2" />ดูข้อมูลเพิ่มเติม<ph name="END_LINK2" /></translation> +<translation id="4211851069413100178">ส่งข้อมูลการใช้งานและการวินิจฉัย ช่วยปรับปรุงประสบการณ์การใช้งาน Android ของคุณให้ดีขึ้นด้วยการส่งข้อมูลการวินิจฉัย อุปกรณ์ และการใช้งานแอปไปยัง Google โดยอัตโนมัติ ซึ่งจะช่วยให้แอปและระบบมีความเสถียร พร้อมทั้งปรับปรุงด้านอื่นๆ ข้อมูลที่รวบรวมมาบางส่วนจะมีประโยชน์ต่อแอปและพาร์ทเนอร์ของ Google ด้วย เช่น นักพัฒนาแอป Android เจ้าของเป็นผู้บังคับใช้<ph name="BEGIN_LINK1" />การตั้งค่า<ph name="END_LINK1" />นี้ เจ้าของอาจเลือกที่จะส่งข้อมูลการวินิจฉัยและการใช้งานสำหรับอุปกรณ์นี้ไปยัง Google หากเปิดการตั้งค่ากิจกรรมเพิ่มเติมบนเว็บและแอปไว้ ระบบอาจบันทึกข้อมูลนี้ไว้ในบัญชี Google ของคุณ <ph name="BEGIN_LINK2" />ดูข้อมูลเพิ่มเติม<ph name="END_LINK2" /></translation> <translation id="42126664696688958">ส่งออก</translation> <translation id="42137655013211669">เซิร์ฟเวอร์ได้ห้ามการเข้าถึงทรัพยากรนี้</translation> <translation id="4217571870635786043">การพิมพ์ตามคำบอก</translation> @@ -3713,7 +3713,7 @@ <translation id="5017643436812738274">คุณไปยังส่วนต่างๆ ของหน้าได้ด้วยเคอร์เซอร์ข้อความ กด Ctrl+Search+7 เพื่อปิด</translation> <translation id="5017828934289857214">เตือนฉันภายหลัง</translation> <translation id="5018207570537526145">เปิดเว็บไซต์ส่วนขยาย</translation> -<translation id="5018526990965779848">ส่งข้อมูลการใช้งานและการวินิจฉัย ช่วยปรับปรุงประสบการณ์การใช้งาน Android ของคุณให้ดีขึ้นด้วยการส่งข้อมูลการวินิจฉัย อุปกรณ์ และการใช้งานแอปไปยัง Google โดยอัตโนมัติ ซึ่งจะช่วยให้แอปและระบบมีความเสถียร พร้อมทั้งปรับปรุงด้านอื่นๆ ข้อมูลที่รวบรวมมาบางส่วนจะมีประโยชน์ต่อแอปและพาร์ทเนอร์ของ Google ด้วย เช่น นักพัฒนาซอฟต์แวร์ Android หากเปิดการตั้งค่ากิจกรรมเพิ่มเติมบนเว็บและแอปไว้ ระบบอาจบันทึกข้อมูลนี้ไว้ในบัญชี Google ของคุณ</translation> +<translation id="5018526990965779848">ส่งข้อมูลการใช้งานและการวินิจฉัย ช่วยปรับปรุงประสบการณ์การใช้งาน Android ของคุณให้ดีขึ้นด้วยการส่งข้อมูลการวินิจฉัย อุปกรณ์ และการใช้งานแอปไปยัง Google โดยอัตโนมัติ ซึ่งจะช่วยให้แอปและระบบมีความเสถียร พร้อมทั้งปรับปรุงด้านอื่นๆ ข้อมูลที่รวบรวมมาบางส่วนจะมีประโยชน์ต่อแอปและพาร์ทเนอร์ของ Google ด้วย เช่น นักพัฒนาแอป Android หากเปิดการตั้งค่ากิจกรรมเพิ่มเติมบนเว็บและแอปไว้ ระบบอาจบันทึกข้อมูลนี้ไว้ในบัญชี Google ของคุณ</translation> <translation id="5021750053540820849">ยังไม่ได้อัปเดต</translation> <translation id="5026492829171796515">ลงชื่อเข้าใช้เพื่อเพิ่มบัญชี Google</translation> <translation id="5026806129670917316">เปิด Wi-Fi</translation> @@ -3866,7 +3866,7 @@ <translation id="5192062846343383368">เปิดแอป Family Link เพื่อดูการตั้งค่าการควบคุมดูแล</translation> <translation id="5193988420012215838">คัดลอกไปยังคลิปบอร์ดแล้ว</translation> <translation id="5197255632782567636">อินเทอร์เน็ต</translation> -<translation id="5198430103906431024">ส่งข้อมูลการใช้งานและการวินิจฉัย ปัจจุบันอุปกรณ์นี้ส่งข้อมูลการวินิจฉัย อุปกรณ์ และการใช้งานแอปไปยัง Google โดยอัตโนมัติ ซึ่งจะช่วยให้แอปและระบบมีความเสถียร พร้อมทั้งปรับปรุงด้านอื่นๆ ข้อมูลที่รวบรวมมาบางส่วนจะมีประโยชน์ต่อแอปและพาร์ทเนอร์ของ Google ด้วย เช่น นักพัฒนาซอฟต์แวร์ Android หากเปิดการตั้งค่ากิจกรรมเพิ่มเติมบนเว็บและแอปไว้ ระบบอาจบันทึกข้อมูลนี้ไว้ในบัญชี Google ของคุณ</translation> +<translation id="5198430103906431024">ส่งข้อมูลการใช้งานและการวินิจฉัย ปัจจุบันอุปกรณ์นี้ส่งข้อมูลการวินิจฉัย อุปกรณ์ และการใช้งานแอปไปยัง Google โดยอัตโนมัติ ซึ่งจะช่วยให้แอปและระบบมีความเสถียร พร้อมทั้งปรับปรุงด้านอื่นๆ ข้อมูลที่รวบรวมมาบางส่วนจะมีประโยชน์ต่อแอปและพาร์ทเนอร์ของ Google ด้วย เช่น นักพัฒนาแอป Android หากเปิดการตั้งค่ากิจกรรมเพิ่มเติมบนเว็บและแอปไว้ ระบบอาจบันทึกข้อมูลนี้ไว้ในบัญชี Google ของคุณ</translation> <translation id="5199729219167945352">การทดลอง</translation> <translation id="5203920255089865054">{NUM_EXTENSIONS,plural, =1{คลิกเพื่อดูส่วนขยาย}other{คลิกเพื่อดูส่วนขยายเหล่านี้}}</translation> <translation id="5204673965307125349">โปรดทำ Powerwash อุปกรณ์และลองอีกครั้ง</translation> @@ -4211,7 +4211,7 @@ <translation id="5583640892426849032">Backspace</translation> <translation id="5584088138253955452">บันทึกชื่อผู้ใช้ไหม</translation> <translation id="5584091888252706332">เริ่มต้น</translation> -<translation id="5584915726528712820"><ph name="BEGIN_PARAGRAPH1" />นี่เป็นข้อมูลทั่วไปเกี่ยวกับอุปกรณ์ของคุณและวิธีที่คุณใช้อุปกรณ์ (เช่น ระดับแบตเตอรี่ กิจกรรมในระบบและแอป และข้อผิดพลาด) ระบบจะใช้ข้อมูลดังกล่าวเพื่อปรับปรุง Android และข้อมูลแบบสรุปรวมบางอย่างจะช่วยให้แอป Google และพาร์ทเนอร์ต่างๆ เช่น นักพัฒนาซอฟต์แวร์ Android ปรับปรุงแอปและผลิตภัณฑ์ของตนให้ดีขึ้นได้อีกด้วย<ph name="END_PARAGRAPH1" /> +<translation id="5584915726528712820"><ph name="BEGIN_PARAGRAPH1" />นี่เป็นข้อมูลทั่วไปเกี่ยวกับอุปกรณ์ของคุณและวิธีที่คุณใช้อุปกรณ์ (เช่น ระดับแบตเตอรี่ กิจกรรมในระบบและแอป และข้อผิดพลาด) ระบบจะใช้ข้อมูลดังกล่าวเพื่อปรับปรุง Android และข้อมูลแบบสรุปรวมบางอย่างจะช่วยให้แอป Google และพาร์ทเนอร์ต่างๆ เช่น นักพัฒนาแอป Android ปรับปรุงแอปและผลิตภัณฑ์ของตนให้ดีขึ้นได้อีกด้วย<ph name="END_PARAGRAPH1" /> <ph name="BEGIN_PARAGRAPH2" />การปิดฟีเจอร์นี้จะไม่ส่งผลต่อความสามารถของอุปกรณ์ในการส่งข้อมูลที่จำเป็นต้องใช้ในบริการสำคัญอย่างเช่น การอัปเดตระบบ และความปลอดภัย<ph name="END_PARAGRAPH2" /> <ph name="BEGIN_PARAGRAPH3" />เจ้าของจะควบคุมฟีเจอร์นี้ได้จากการตั้งค่า > ขั้นสูง > ส่งข้อมูลการวินิจฉัยและการใช้งานไปยัง Google โดยอัตโนมัติ<ph name="END_PARAGRAPH3" /> <ph name="BEGIN_PARAGRAPH4" />หากการตั้งค่ากิจกรรมเพิ่มเติมบนเว็บและแอปเปิดอยู่ ระบบอาจบันทึกข้อมูลนี้ไว้ในบัญชี Google คุณจะดูหรือลบข้อมูล และเปลี่ยนแปลงการตั้งค่าบัญชีได้ที่ account.google.com<ph name="END_PARAGRAPH4" /></translation> @@ -5239,7 +5239,7 @@ <translation id="6725073593266469338">บริการ UI</translation> <translation id="6725206449694821596">โปรโตคอลการพิมพ์ผ่านอินเทอร์เน็ต (IPP)</translation> <translation id="672609503628871915">ดูว่ามีอะไรใหม่</translation> -<translation id="67269783048918309">ส่งข้อมูลการใช้งานและการวินิจฉัย ปัจจุบันอุปกรณ์นี้ส่งข้อมูลการวินิจฉัย อุปกรณ์ และการใช้งานแอปไปยัง Google โดยอัตโนมัติ โดยจะไม่มีการใช้ข้อมูลนี้ในการระบุชื่อบุตรหลานของคุณ และจะช่วยให้แอปและระบบมีความเสถียร พร้อมทั้งปรับปรุงด้านอื่นๆ ข้อมูลที่รวบรวมมาบางส่วนจะมีประโยชน์ต่อแอปและพาร์ทเนอร์ของ Google ด้วย เช่น นักพัฒนาซอฟต์แวร์ Android เจ้าของเป็นผู้บังคับใช้<ph name="BEGIN_LINK1" />การตั้งค่า<ph name="END_LINK1" />นี้ หากเปิดการตั้งค่ากิจกรรมเพิ่มเติมบนเว็บและแอปสำหรับบุตรหลาน ระบบอาจบันทึกข้อมูลนี้ไว้ในบัญชี Google ของบุตรหลาน <ph name="BEGIN_LINK2" />ดูข้อมูลเพิ่มเติม<ph name="END_LINK2" /></translation> +<translation id="67269783048918309">ส่งข้อมูลการใช้งานและการวินิจฉัย ปัจจุบันอุปกรณ์นี้ส่งข้อมูลการวินิจฉัย อุปกรณ์ และการใช้งานแอปไปยัง Google โดยอัตโนมัติ โดยจะไม่มีการใช้ข้อมูลนี้ในการระบุชื่อบุตรหลานของคุณ และจะช่วยให้แอปและระบบมีความเสถียร พร้อมทั้งปรับปรุงด้านอื่นๆ ข้อมูลที่รวบรวมมาบางส่วนจะมีประโยชน์ต่อแอปและพาร์ทเนอร์ของ Google ด้วย เช่น นักพัฒนาแอป Android เจ้าของเป็นผู้บังคับใช้<ph name="BEGIN_LINK1" />การตั้งค่า<ph name="END_LINK1" />นี้ หากเปิดการตั้งค่ากิจกรรมเพิ่มเติมบนเว็บและแอปสำหรับบุตรหลาน ระบบอาจบันทึกข้อมูลนี้ไว้ในบัญชี Google ของบุตรหลาน <ph name="BEGIN_LINK2" />ดูข้อมูลเพิ่มเติม<ph name="END_LINK2" /></translation> <translation id="6727969043791803658">เชื่อมต่อแล้ว แบตเตอรี่ <ph name="BATTERY_PERCENTAGE" />%</translation> <translation id="6732087373923685049">กล้อง</translation> <translation id="6732801395666424405">ยังไม่ได้โหลดใบรับรอง</translation> @@ -5352,7 +5352,7 @@ <translation id="6847125920277401289">เพิ่มพื้นที่ว่างเพื่อดำเนินการต่อ</translation> <translation id="6848388270925200958">ขณะนี้คุณมีบัตรบางใบที่ใช้ได้ในอุปกรณ์นี้เท่านั้น</translation> <translation id="6850286078059909152">สีข้อความ</translation> -<translation id="6851181413209322061">ส่งข้อมูลการใช้งานและการวินิจฉัย ปัจจุบันอุปกรณ์นี้ส่งข้อมูลการวินิจฉัย อุปกรณ์ และการใช้งานแอปไปยัง Google โดยอัตโนมัติ โดยจะไม่มีการใช้ข้อมูลนี้ในการระบุชื่อบุตรหลานของคุณ และจะช่วยให้แอปและระบบมีความเสถียร พร้อมทั้งปรับปรุงด้านอื่นๆ ข้อมูลที่รวบรวมมาบางส่วนจะมีประโยชน์ต่อแอปและพาร์ทเนอร์ของ Google ด้วย เช่น นักพัฒนาซอฟต์แวร์ Android เจ้าของเป็นผู้บังคับใช้การตั้งค่านี้ หากเปิดการตั้งค่ากิจกรรมเพิ่มเติมบนเว็บและแอปสำหรับบุตรหลาน ระบบอาจบันทึกข้อมูลนี้ไว้ในบัญชี Google ของบุตรหลาน</translation> +<translation id="6851181413209322061">ส่งข้อมูลการใช้งานและการวินิจฉัย ปัจจุบันอุปกรณ์นี้ส่งข้อมูลการวินิจฉัย อุปกรณ์ และการใช้งานแอปไปยัง Google โดยอัตโนมัติ โดยจะไม่มีการใช้ข้อมูลนี้ในการระบุชื่อบุตรหลานของคุณ และจะช่วยให้แอปและระบบมีความเสถียร พร้อมทั้งปรับปรุงด้านอื่นๆ ข้อมูลที่รวบรวมมาบางส่วนจะมีประโยชน์ต่อแอปและพาร์ทเนอร์ของ Google ด้วย เช่น นักพัฒนาแอป Android เจ้าของเป็นผู้บังคับใช้การตั้งค่านี้ หากเปิดการตั้งค่ากิจกรรมเพิ่มเติมบนเว็บและแอปสำหรับบุตรหลาน ระบบอาจบันทึกข้อมูลนี้ไว้ในบัญชี Google ของบุตรหลาน</translation> <translation id="6851497530878285708">เปิดใช้แอปแล้ว</translation> <translation id="6853142139292753691">คืนค่าแอปและหน้าเว็บโดยค่าเริ่มต้นไหม</translation> <translation id="6853388645642883916">โปรแกรมอัปเดตอยู่ในโหมดสลีป</translation> @@ -5673,7 +5673,7 @@ <translation id="7203150201908454328">ขยาย</translation> <translation id="7206693748120342859">กำลังดาวน์โหลด <ph name="PLUGIN_NAME" />...</translation> <translation id="720715819012336933">{NUM_PAGES,plural, =1{หน้าที่ออกไป}other{หน้าที่ออกไป}}</translation> -<translation id="7207457272187520234">ส่งข้อมูลการใช้งานและการวินิจฉัย ปัจจุบันอุปกรณ์นี้ส่งข้อมูลการวินิจฉัย อุปกรณ์ และการใช้งานแอปไปยัง Google โดยอัตโนมัติ ซึ่งจะช่วยให้แอปและระบบมีความเสถียร พร้อมทั้งปรับปรุงด้านอื่นๆ ข้อมูลที่รวบรวมมาบางส่วนจะมีประโยชน์ต่อแอปและพาร์ทเนอร์ของ Google ด้วย เช่น นักพัฒนาซอฟต์แวร์ Android เจ้าของเป็นผู้บังคับใช้การตั้งค่านี้ หากเปิดการตั้งค่ากิจกรรมเพิ่มเติมบนเว็บและแอปไว้ ระบบอาจบันทึกข้อมูลนี้ไว้ในบัญชี Google ของคุณ</translation> +<translation id="7207457272187520234">ส่งข้อมูลการใช้งานและการวินิจฉัย ปัจจุบันอุปกรณ์นี้ส่งข้อมูลการวินิจฉัย อุปกรณ์ และการใช้งานแอปไปยัง Google โดยอัตโนมัติ ซึ่งจะช่วยให้แอปและระบบมีความเสถียร พร้อมทั้งปรับปรุงด้านอื่นๆ ข้อมูลที่รวบรวมมาบางส่วนจะมีประโยชน์ต่อแอปและพาร์ทเนอร์ของ Google ด้วย เช่น นักพัฒนาแอป Android เจ้าของเป็นผู้บังคับใช้การตั้งค่านี้ หากเปิดการตั้งค่ากิจกรรมเพิ่มเติมบนเว็บและแอปไว้ ระบบอาจบันทึกข้อมูลนี้ไว้ในบัญชี Google ของคุณ</translation> <translation id="7207631048330366454">ค้นหาแอป</translation> <translation id="7210499381659830293">เครื่องพิมพ์ที่สั่งการผ่านส่วนขยาย</translation> <translation id="7211769023302873228">กด “<ph name="CURRENTKEY" />” อีกครั้งเพื่อยืนยันการกำหนดและออก</translation> @@ -6680,7 +6680,7 @@ <translation id="826511437356419340">เข้าสู่โหมดภาพรวมหน้าต่างแล้ว เลื่อนเพื่อไปยังส่วนต่างๆ หรือกด Tab หากใช้แป้นพิมพ์</translation> <translation id="8266947622852630193">วิธีการป้อนข้อมูลทั้งหมด</translation> <translation id="8267539814046467575">เพิ่มเครื่องพิมพ์</translation> -<translation id="8267961145111171918"><ph name="BEGIN_PARAGRAPH1" />นี่คือข้อมูลทั่วไปเกี่ยวกับอุปกรณ์นี้และวิธีใช้อุปกรณ์ (เช่น ระดับแบตเตอรี่ กิจกรรมในระบบและแอป และข้อผิดพลาด) ระบบจะใช้ข้อมูลดังกล่าวเพื่อปรับปรุง Android และข้อมูลแบบสรุปรวมบางอย่างจะช่วยให้แอป Google และพาร์ทเนอร์ต่างๆ เช่น นักพัฒนาซอฟต์แวร์ Android ปรับปรุงแอปและผลิตภัณฑ์ของตนให้ดีขึ้นได้อีกด้วย<ph name="END_PARAGRAPH1" /> +<translation id="8267961145111171918"><ph name="BEGIN_PARAGRAPH1" />นี่คือข้อมูลทั่วไปเกี่ยวกับอุปกรณ์นี้และวิธีใช้อุปกรณ์ (เช่น ระดับแบตเตอรี่ กิจกรรมในระบบและแอป และข้อผิดพลาด) ระบบจะใช้ข้อมูลดังกล่าวเพื่อปรับปรุง Android และข้อมูลแบบสรุปรวมบางอย่างจะช่วยให้แอป Google และพาร์ทเนอร์ต่างๆ เช่น นักพัฒนาแอป Android ปรับปรุงแอปและผลิตภัณฑ์ของตนให้ดีขึ้นได้อีกด้วย<ph name="END_PARAGRAPH1" /> <ph name="BEGIN_PARAGRAPH2" />การปิดฟีเจอร์นี้จะไม่ส่งผลต่อความสามารถของอุปกรณ์ในการส่งข้อมูลที่จำเป็นต้องใช้ในบริการสำคัญอย่างเช่น การอัปเดตระบบ และความปลอดภัย<ph name="END_PARAGRAPH2" /> <ph name="BEGIN_PARAGRAPH3" />เจ้าของจะควบคุมฟีเจอร์นี้ได้จากการตั้งค่า > ขั้นสูง > ส่งข้อมูลการวินิจฉัยและการใช้งานไปยัง Google โดยอัตโนมัติ<ph name="END_PARAGRAPH3" /> <ph name="BEGIN_PARAGRAPH4" />หากการตั้งค่ากิจกรรมเพิ่มเติมบนเว็บและแอปเปิดอยู่สำหรับบุตรหลาน ระบบอาจบันทึกข้อมูลนี้ไว้ในบัญชี Google ของบุตรหลาน ดูข้อมูลเพิ่มเติมเกี่ยวกับการตั้งค่าเหล่านี้และวิธีปรับการตั้งค่าได้ที่ families.google.com<ph name="END_PARAGRAPH4" /></translation> @@ -6941,7 +6941,7 @@ <translation id="8591783563402255548">1 วินาที</translation> <translation id="8592141010104017453">ไม่ต้องแสดงการแจ้งเตือนใดๆ</translation> <translation id="859246725979739260">เว็บไซต์นี้ถูกบล็อกไม่ให้เข้าถึงตำแหน่งของคุณ</translation> -<translation id="8593121833493516339">ส่งข้อมูลการใช้งานและการวินิจฉัย ช่วยปรับปรุงประสบการณ์การใช้งาน Android ของบุตรหลานให้ดีขึ้นด้วยการส่งข้อมูลการวินิจฉัย อุปกรณ์ และการใช้งานแอปไปยัง Google โดยอัตโนมัติ โดยจะไม่มีการใช้ข้อมูลนี้ในการระบุชื่อบุตรหลานของคุณ และจะช่วยให้แอปและระบบมีความเสถียร พร้อมทั้งปรับปรุงด้านอื่นๆ ข้อมูลที่รวบรวมมาบางส่วนจะมีประโยชน์ต่อแอปและพาร์ทเนอร์ของ Google ด้วย เช่น นักพัฒนาซอฟต์แวร์ Android หากเปิดการตั้งค่ากิจกรรมเพิ่มเติมบนเว็บและแอปสำหรับบุตรหลาน ระบบอาจบันทึกข้อมูลนี้ไว้ในบัญชี Google ของบุตรหลาน <ph name="BEGIN_LINK1" />ดูข้อมูลเพิ่มเติม<ph name="END_LINK1" /></translation> +<translation id="8593121833493516339">ส่งข้อมูลการใช้งานและการวินิจฉัย ช่วยปรับปรุงประสบการณ์การใช้งาน Android ของบุตรหลานให้ดีขึ้นด้วยการส่งข้อมูลการวินิจฉัย อุปกรณ์ และการใช้งานแอปไปยัง Google โดยอัตโนมัติ โดยจะไม่มีการใช้ข้อมูลนี้ในการระบุชื่อบุตรหลานของคุณ และจะช่วยให้แอปและระบบมีความเสถียร พร้อมทั้งปรับปรุงด้านอื่นๆ ข้อมูลที่รวบรวมมาบางส่วนจะมีประโยชน์ต่อแอปและพาร์ทเนอร์ของ Google ด้วย เช่น นักพัฒนาแอป Android หากเปิดการตั้งค่ากิจกรรมเพิ่มเติมบนเว็บและแอปสำหรับบุตรหลาน ระบบอาจบันทึกข้อมูลนี้ไว้ในบัญชี Google ของบุตรหลาน <ph name="BEGIN_LINK1" />ดูข้อมูลเพิ่มเติม<ph name="END_LINK1" /></translation> <translation id="8594908476761052472">จับภาพวิดีโอ</translation> <translation id="8596540852772265699">ไฟล์ที่กำหนดเอง</translation> <translation id="8597845839771543242">รูปแบบของคุณสมบัติ:</translation> @@ -6983,7 +6983,7 @@ <translation id="863903787380594467">PIN ไม่ถูกต้อง คุณลองได้อีก <ph name="RETRIES" /> ครั้ง</translation> <translation id="8639047128869322042">กำลังตรวจหาซอฟต์แวร์ที่เป็นอันตราย...</translation> <translation id="8639391553632924850"><ph name="INPUT_LABEL" /> - พอร์ต</translation> -<translation id="8639635302972078117">ส่งข้อมูลการใช้งานและการวินิจฉัย ปัจจุบันอุปกรณ์นี้ส่งข้อมูลการวินิจฉัย อุปกรณ์ และการใช้งานแอปไปยัง Google โดยอัตโนมัติ โดยจะไม่มีการใช้ข้อมูลนี้ในการระบุชื่อบุตรหลานของคุณ และจะช่วยให้แอปและระบบมีความเสถียร พร้อมทั้งปรับปรุงด้านอื่นๆ ข้อมูลที่รวบรวมมาบางส่วนจะมีประโยชน์ต่อแอปและพาร์ทเนอร์ของ Google ด้วย เช่น นักพัฒนาซอฟต์แวร์ Android หากเปิดการตั้งค่ากิจกรรมเพิ่มเติมบนเว็บและแอปสำหรับบุตรหลาน ระบบอาจบันทึกข้อมูลนี้ไว้ในบัญชี Google ของบุตรหลาน</translation> +<translation id="8639635302972078117">ส่งข้อมูลการใช้งานและการวินิจฉัย ปัจจุบันอุปกรณ์นี้ส่งข้อมูลการวินิจฉัย อุปกรณ์ และการใช้งานแอปไปยัง Google โดยอัตโนมัติ โดยจะไม่มีการใช้ข้อมูลนี้ในการระบุชื่อบุตรหลานของคุณ และจะช่วยให้แอปและระบบมีความเสถียร พร้อมทั้งปรับปรุงด้านอื่นๆ ข้อมูลที่รวบรวมมาบางส่วนจะมีประโยชน์ต่อแอปและพาร์ทเนอร์ของ Google ด้วย เช่น นักพัฒนาแอป Android หากเปิดการตั้งค่ากิจกรรมเพิ่มเติมบนเว็บและแอปสำหรับบุตรหลาน ระบบอาจบันทึกข้อมูลนี้ไว้ในบัญชี Google ของบุตรหลาน</translation> <translation id="8642900771896232685">2 วินาที</translation> <translation id="8642947597466641025">ทำให้ข้อความใหญ่ขึ้น</translation> <translation id="8643443571868262066"><ph name="FILE_NAME" /> อาจเป็นอันตราย ส่งไปให้การปกป้องขั้นสูงของ Google สแกนไหม</translation> @@ -7066,7 +7066,7 @@ <translation id="8719653885894320876">การดาวน์โหลด <ph name="PLUGIN_NAME" /> ล้มเหลว</translation> <translation id="8720200012906404956">กำลังมองหาเครือข่ายมือถือ <ph name="BEGIN_LINK" />ดูข้อมูลเพิ่มเติม<ph name="END_LINK" /></translation> <translation id="8720816553731218127">การเริ่มต้นแอตทริบิวต์เวลาการติดตั้งหมดเวลาแล้ว</translation> -<translation id="8722912030556880711">ส่งข้อมูลการใช้งานและการวินิจฉัย ปัจจุบันอุปกรณ์นี้ส่งข้อมูลการวินิจฉัย อุปกรณ์ และการใช้งานแอปไปยัง Google โดยอัตโนมัติ ซึ่งจะช่วยให้แอปและระบบมีความเสถียร พร้อมทั้งปรับปรุงด้านอื่นๆ ข้อมูลที่รวบรวมมาบางส่วนจะมีประโยชน์ต่อแอปและพาร์ทเนอร์ของ Google ด้วย เช่น นักพัฒนาซอฟต์แวร์ Android หากเปิดการตั้งค่ากิจกรรมเพิ่มเติมบนเว็บและแอปไว้ ระบบอาจบันทึกข้อมูลนี้ไว้ในบัญชี Google ของคุณ <ph name="BEGIN_LINK2" />ดูข้อมูลเพิ่มเติม<ph name="END_LINK2" /></translation> +<translation id="8722912030556880711">ส่งข้อมูลการใช้งานและการวินิจฉัย ปัจจุบันอุปกรณ์นี้ส่งข้อมูลการวินิจฉัย อุปกรณ์ และการใช้งานแอปไปยัง Google โดยอัตโนมัติ ซึ่งจะช่วยให้แอปและระบบมีความเสถียร พร้อมทั้งปรับปรุงด้านอื่นๆ ข้อมูลที่รวบรวมมาบางส่วนจะมีประโยชน์ต่อแอปและพาร์ทเนอร์ของ Google ด้วย เช่น นักพัฒนาแอป Android หากเปิดการตั้งค่ากิจกรรมเพิ่มเติมบนเว็บและแอปไว้ ระบบอาจบันทึกข้อมูลนี้ไว้ในบัญชี Google ของคุณ <ph name="BEGIN_LINK2" />ดูข้อมูลเพิ่มเติม<ph name="END_LINK2" /></translation> <translation id="8724405322205516354">เมื่อเห็นไอคอนนี้ ให้ใช้ลายนิ้วมือเพื่อระบุตัวตนหรือเพื่ออนุมัติการซื้อ</translation> <translation id="8724409975248965964">เพิ่มลายนิ้วมือแล้ว</translation> <translation id="8724859055372736596">&แสดงในโฟลเดอร์</translation> @@ -7090,7 +7090,7 @@ <translation id="8737914367566358838">เลือกภาษาปลายทางของหน้าเว็บ</translation> <translation id="8740247629089392745">คุณส่งมอบ Chromebook เครื่องนี้ให้ <ph name="SUPERVISED_USER_NAME" /> ได้ การตั้งค่าใกล้เสร็จแล้ว จากนั้นก็ได้เวลาแห่งการสำรวจ</translation> <translation id="8741944563400125534">คู่มือการตั้งค่าการเข้าถึงด้วยสวิตช์</translation> -<translation id="8742998548129056176">นี่คือข้อมูลทั่วไปเกี่ยวกับอุปกรณ์และวิธีที่คุณใช้งานอุปกรณ์ (เช่น ระดับแบตเตอรี่ กิจกรรมในระบบและแอป ตลอดจนข้อผิดพลาด) ระบบจะใช้ข้อมูลเพื่อปรับปรุง Android และข้อมูลที่รวบรวมมาบางส่วนจะช่วยให้แอปและพาร์ทเนอร์ของ Google เช่น นักพัฒนาซอฟต์แวร์ Android พัฒนาแอปและผลิตภัณฑ์ของตนให้ดีขึ้น</translation> +<translation id="8742998548129056176">นี่คือข้อมูลทั่วไปเกี่ยวกับอุปกรณ์และวิธีที่คุณใช้งานอุปกรณ์ (เช่น ระดับแบตเตอรี่ กิจกรรมในระบบและแอป ตลอดจนข้อผิดพลาด) ระบบจะใช้ข้อมูลเพื่อปรับปรุง Android และข้อมูลที่รวบรวมมาบางส่วนจะช่วยให้แอปและพาร์ทเนอร์ของ Google เช่น นักพัฒนาแอป Android พัฒนาแอปและผลิตภัณฑ์ของตนให้ดีขึ้น</translation> <translation id="8743164338060742337">เครือข่ายที่ <ph name="NETWORK_INDEX" /> จาก <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, <ph name="NETWORK_PROVIDER_NAME" /> ความแรงสัญญาณ <ph name="SIGNAL_STRENGTH" />%, จัดการโดยผู้ดูแลระบบ, เชื่อมต่อ</translation> <translation id="8746654918629346731">คุณขอ "<ph name="EXTENSION_NAME" />" แล้ว</translation> <translation id="874689135111202667">{0,plural, =1{อัปโหลด 1 ไฟล์ไปยังเว็บไซต์นี้ใช่ไหม}other{อัปโหลด # ไฟล์ไปยังเว็บไซต์นี้ใช่ไหม}}</translation> @@ -7276,7 +7276,7 @@ <translation id="8929696694736010839">เซสชันไม่ระบุตัวตนปัจจุบันเท่านั้น</translation> <translation id="8930351635855238750">การตั้งค่าคุกกี้ใหม่จะมีผลหลังจากการโหลดหน้านี้ซ้ำ</translation> <translation id="8930622219860340959">ไร้สาย</translation> -<translation id="8931076093143205651">ส่งข้อมูลการใช้งานและการวินิจฉัย ช่วยปรับปรุงประสบการณ์การใช้งาน Android ของคุณให้ดีขึ้นด้วยการส่งข้อมูลการวินิจฉัย อุปกรณ์ และการใช้งานแอปไปยัง Google โดยอัตโนมัติ ซึ่งจะช่วยให้แอปและระบบมีความเสถียร พร้อมทั้งปรับปรุงด้านอื่นๆ ข้อมูลที่รวบรวมมาบางส่วนจะมีประโยชน์ต่อแอปและพาร์ทเนอร์ของ Google ด้วย เช่น นักพัฒนาซอฟต์แวร์ Android เจ้าของเป็นผู้บังคับใช้การตั้งค่านี้ เจ้าของอาจเลือกที่จะส่งข้อมูลการวินิจฉัยและการใช้งานสำหรับอุปกรณ์นี้ไปยัง Google หากเปิดการตั้งค่ากิจกรรมเพิ่มเติมบนเว็บและแอปไว้ ระบบอาจบันทึกข้อมูลนี้ไว้ในบัญชี Google ของคุณ</translation> +<translation id="8931076093143205651">ส่งข้อมูลการใช้งานและการวินิจฉัย ช่วยปรับปรุงประสบการณ์การใช้งาน Android ของคุณให้ดีขึ้นด้วยการส่งข้อมูลการวินิจฉัย อุปกรณ์ และการใช้งานแอปไปยัง Google โดยอัตโนมัติ ซึ่งจะช่วยให้แอปและระบบมีความเสถียร พร้อมทั้งปรับปรุงด้านอื่นๆ ข้อมูลที่รวบรวมมาบางส่วนจะมีประโยชน์ต่อแอปและพาร์ทเนอร์ของ Google ด้วย เช่น นักพัฒนาแอป Android เจ้าของเป็นผู้บังคับใช้การตั้งค่านี้ เจ้าของอาจเลือกที่จะส่งข้อมูลการวินิจฉัยและการใช้งานสำหรับอุปกรณ์นี้ไปยัง Google หากเปิดการตั้งค่ากิจกรรมเพิ่มเติมบนเว็บและแอปไว้ ระบบอาจบันทึกข้อมูลนี้ไว้ในบัญชี Google ของคุณ</translation> <translation id="8931475688782629595">จัดการข้อมูลที่คุณซิงค์</translation> <translation id="8932654652795262306">รายละเอียดการเชื่อมต่อ Wi-Fi ฮอตสปอตจากมือถือโดยอัตโนมัติ</translation> <translation id="8932894639908691771">ตัวเลือกการเข้าถึงด้วยสวิตช์</translation> @@ -7510,9 +7510,9 @@ <translation id="9170848237812810038">เ&ลิกทำ</translation> <translation id="9170884462774788842">โปรแกรมอื่นในคอมพิวเตอร์ของคุณเพิ่มธีมที่อาจเปลี่ยนวิธีการทำงานของ Chrome</translation> <translation id="917350715406657904">คุณใช้งาน <ph name="APP_NAME" /> ถึงขีดจำกัดเวลาที่ผู้ปกครองตั้งไว้แล้ว พรุ่งนี้คุณจะใช้แอปได้ <ph name="TIME_LIMIT" /></translation> -<translation id="9174401638287877180">ส่งข้อมูลการใช้งานและการวินิจฉัย ช่วยปรับปรุงประสบการณ์การใช้งาน Android ของบุตรหลานให้ดีขึ้นด้วยการส่งข้อมูลการวินิจฉัย อุปกรณ์ และการใช้งานแอปไปยัง Google โดยอัตโนมัติ โดยจะไม่มีการใช้ข้อมูลนี้ในการระบุชื่อบุตรหลานของคุณ และจะช่วยให้แอปและระบบมีความเสถียร พร้อมทั้งปรับปรุงด้านอื่นๆ ข้อมูลที่รวบรวมมาบางส่วนจะมีประโยชน์ต่อแอปและพาร์ทเนอร์ของ Google ด้วย เช่น นักพัฒนาซอฟต์แวร์ Android หากเปิดการตั้งค่ากิจกรรมเพิ่มเติมบนเว็บและแอปสำหรับบุตรหลาน ระบบอาจบันทึกข้อมูลนี้ไว้ในบัญชี Google ของบุตรหลาน</translation> +<translation id="9174401638287877180">ส่งข้อมูลการใช้งานและการวินิจฉัย ช่วยปรับปรุงประสบการณ์การใช้งาน Android ของบุตรหลานให้ดีขึ้นด้วยการส่งข้อมูลการวินิจฉัย อุปกรณ์ และการใช้งานแอปไปยัง Google โดยอัตโนมัติ โดยจะไม่มีการใช้ข้อมูลนี้ในการระบุชื่อบุตรหลานของคุณ และจะช่วยให้แอปและระบบมีความเสถียร พร้อมทั้งปรับปรุงด้านอื่นๆ ข้อมูลที่รวบรวมมาบางส่วนจะมีประโยชน์ต่อแอปและพาร์ทเนอร์ของ Google ด้วย เช่น นักพัฒนาแอป Android หากเปิดการตั้งค่ากิจกรรมเพิ่มเติมบนเว็บและแอปสำหรับบุตรหลาน ระบบอาจบันทึกข้อมูลนี้ไว้ในบัญชี Google ของบุตรหลาน</translation> <translation id="917510707618656279">ถามเมื่อเว็บไซต์ต้องการเข้าถึงอุปกรณ์บลูทูธ</translation> -<translation id="9176476835295860688">ส่งข้อมูลการใช้งานและการวินิจฉัย ปัจจุบันอุปกรณ์นี้ส่งข้อมูลการวินิจฉัย อุปกรณ์ และการใช้งานแอปไปยัง Google โดยอัตโนมัติ ซึ่งจะช่วยให้แอปและระบบมีความเสถียร พร้อมทั้งปรับปรุงด้านอื่นๆ ข้อมูลที่รวบรวมมาบางส่วนจะมีประโยชน์ต่อแอปและพาร์ทเนอร์ของ Google ด้วย เช่น นักพัฒนาซอฟต์แวร์ Android เจ้าของเป็นผู้บังคับใช้<ph name="BEGIN_LINK1" />การตั้งค่า<ph name="END_LINK1" />นี้ หากเปิดการตั้งค่ากิจกรรมเพิ่มเติมบนเว็บและแอปไว้ ระบบอาจบันทึกข้อมูลนี้ไว้ในบัญชี Google ของคุณ <ph name="BEGIN_LINK2" />ดูข้อมูลเพิ่มเติม<ph name="END_LINK2" /></translation> +<translation id="9176476835295860688">ส่งข้อมูลการใช้งานและการวินิจฉัย ปัจจุบันอุปกรณ์นี้ส่งข้อมูลการวินิจฉัย อุปกรณ์ และการใช้งานแอปไปยัง Google โดยอัตโนมัติ ซึ่งจะช่วยให้แอปและระบบมีความเสถียร พร้อมทั้งปรับปรุงด้านอื่นๆ ข้อมูลที่รวบรวมมาบางส่วนจะมีประโยชน์ต่อแอปและพาร์ทเนอร์ของ Google ด้วย เช่น นักพัฒนาแอป Android เจ้าของเป็นผู้บังคับใช้<ph name="BEGIN_LINK1" />การตั้งค่า<ph name="END_LINK1" />นี้ หากเปิดการตั้งค่ากิจกรรมเพิ่มเติมบนเว็บและแอปไว้ ระบบอาจบันทึกข้อมูลนี้ไว้ในบัญชี Google ของคุณ <ph name="BEGIN_LINK2" />ดูข้อมูลเพิ่มเติม<ph name="END_LINK2" /></translation> <translation id="9176611096776448349"><ph name="WINDOW_TITLE" /> - เชื่อมต่ออุปกรณ์บลูทูธแล้ว</translation> <translation id="9179524979050048593">ชื่อผู้ใช้บนหน้าจอลงชื่อเข้าใช้</translation> <translation id="9180281769944411366">ขั้นตอนนี้อาจใช้เวลาสักครู่ กำลังเริ่มคอนเทนเนอร์ Linux</translation> @@ -7520,7 +7520,7 @@ <translation id="9182556968660520230">ไม่อนุญาตให้เว็บไซต์เล่นเนื้อหาที่มีการคุมครอง</translation> <translation id="918352324374649435">{COUNT,plural, =1{แอป}other{# แอป}}</translation> <translation id="9186963452600581158">ลงชื่อเข้าใช้ด้วยบัญชี Google ของบุตรหลาน</translation> -<translation id="9188732951356337132">ส่งข้อมูลการใช้งานและการวินิจฉัย ปัจจุบันอุปกรณ์นี้ส่งข้อมูลการวินิจฉัย อุปกรณ์ และการใช้งานแอปไปยัง Google โดยอัตโนมัติ โดยจะไม่มีการใช้ข้อมูลนี้ในการระบุชื่อบุตรหลานของคุณ และจะช่วยให้แอปและระบบมีความเสถียร พร้อมทั้งปรับปรุงด้านอื่นๆ ข้อมูลที่รวบรวมมาบางส่วนจะมีประโยชน์ต่อแอปและพาร์ทเนอร์ของ Google ด้วย เช่น นักพัฒนาซอฟต์แวร์ Android หากเปิดการตั้งค่ากิจกรรมเพิ่มเติมบนเว็บและแอปสำหรับบุตรหลาน ระบบอาจบันทึกข้อมูลนี้ไว้ในบัญชี Google ของบุตรหลาน <ph name="BEGIN_LINK2" />ดูข้อมูลเพิ่มเติม<ph name="END_LINK2" /></translation> +<translation id="9188732951356337132">ส่งข้อมูลการใช้งานและการวินิจฉัย ปัจจุบันอุปกรณ์นี้ส่งข้อมูลการวินิจฉัย อุปกรณ์ และการใช้งานแอปไปยัง Google โดยอัตโนมัติ โดยจะไม่มีการใช้ข้อมูลนี้ในการระบุชื่อบุตรหลานของคุณ และจะช่วยให้แอปและระบบมีความเสถียร พร้อมทั้งปรับปรุงด้านอื่นๆ ข้อมูลที่รวบรวมมาบางส่วนจะมีประโยชน์ต่อแอปและพาร์ทเนอร์ของ Google ด้วย เช่น นักพัฒนาแอป Android หากเปิดการตั้งค่ากิจกรรมเพิ่มเติมบนเว็บและแอปสำหรับบุตรหลาน ระบบอาจบันทึกข้อมูลนี้ไว้ในบัญชี Google ของบุตรหลาน <ph name="BEGIN_LINK2" />ดูข้อมูลเพิ่มเติม<ph name="END_LINK2" /></translation> <translation id="9198090666959937775">ใช้โทรศัพท์ Android เป็นคีย์ความปลอดภัย</translation> <translation id="920045321358709304">ค้นหา <ph name="SEARCH_ENGINE" /></translation> <translation id="9201023452444595544">ระบบจะล้างข้อมูลออฟไลน์ทั้งหมด</translation>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 8d9c15e1..bfd9846 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -5243,6 +5243,12 @@ if (use_x11) { deps += [ "//ui/gfx/x" ] } + + # device_info_fetcher uses a "defined(USE_GIO)" macro, so if it's refactored + # away from this file make sure gio_config is still added to configs. + if (use_gio) { + configs += [ "//build/linux:gio_config" ] + } } if (is_linux || is_chromeos_lacros) {
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 798259c..e2eb9acdc 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -922,13 +922,23 @@ heap_profiling::kMemlogSamplingRate5MB}, }; -const FeatureEntry::FeatureVariation kMemoriesVariations[] = {{ - "Persist Context", - (FeatureEntry::FeatureParam[]){ - {"MemoriesPersistContextAnnotationsInHistoryDb", "true"}}, - 1, - nullptr, -}}; +const FeatureEntry::FeatureVariation kMemoriesVariations[] = { + { + "Persist Context + Limit 1k", + (FeatureEntry::FeatureParam[]){ + {"MemoriesPersistContextAnnotationsInHistoryDb", "true"}}, + 1, + nullptr, + }, + { + "Persist Context + Limit 10k", + (FeatureEntry::FeatureParam[]){ + {"MemoriesPersistContextAnnotationsInHistoryDb", "true"}, + {"MemoriesMaxVisitsToCluster", "10000"}}, + 2, + nullptr, + }, +}; #if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_MAC) || \ defined(OS_WIN) @@ -4582,12 +4592,6 @@ #if defined(OS_WIN) || defined(OS_MAC) || defined(OS_LINUX) || \ defined(OS_CHROMEOS) - {"direct-manipulation-stylus", - flag_descriptions::kDirectManipulationStylusName, - flag_descriptions::kDirectManipulationStylusDescription, - kOsWin | kOsMac | kOsLinux, - FEATURE_VALUE_TYPE(features::kDirectManipulationStylus)}, - {"webui-feedback", flag_descriptions::kWebuiFeedbackName, flag_descriptions::kWebuiFeedbackDescription, kOsDesktop, FEATURE_VALUE_TYPE(features::kWebUIFeedback)}, @@ -5971,10 +5975,10 @@ flag_descriptions::kScrollUnificationDescription, kOsAll, FEATURE_VALUE_TYPE(features::kScrollUnification)}, -#if defined(OS_WIN) - {"elastic-overscroll-win", flag_descriptions::kElasticOverscrollWinName, - flag_descriptions::kElasticOverscrollWinDescription, kOsWin, - FEATURE_VALUE_TYPE(features::kElasticOverscrollWin)}, +#if defined(OS_WIN) || defined(OS_ANDROID) + {"elastic-overscroll", flag_descriptions::kElasticOverscrollName, + flag_descriptions::kElasticOverscrollDescription, kOsWin | kOsAndroid, + FEATURE_VALUE_TYPE(features::kElasticOverscroll)}, #endif #if BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm index fb4b2adc..6622f6d 100644 --- a/chrome/browser/app_controller_mac.mm +++ b/chrome/browser/app_controller_mac.mm
@@ -1767,8 +1767,12 @@ } _lastProfile = profile; - _lastProfileKeepAlive = std::make_unique<ScopedProfileKeepAlive>( - _lastProfile, ProfileKeepAliveOrigin::kAppControllerMac); + if (profile->IsOffTheRecord()) { + _lastProfileKeepAlive.reset(); + } else { + _lastProfileKeepAlive = std::make_unique<ScopedProfileKeepAlive>( + _lastProfile, ProfileKeepAliveOrigin::kAppControllerMac); + } } - (void)windowChangedToProfile:(Profile*)profile {
diff --git a/chrome/browser/ash/borealis/testing/callback_factory.h b/chrome/browser/ash/borealis/testing/callback_factory.h index ab9de213..f34ee7c 100644 --- a/chrome/browser/ash/borealis/testing/callback_factory.h +++ b/chrome/browser/ash/borealis/testing/callback_factory.h
@@ -17,6 +17,9 @@ // // The callbacks created by this factory are 'naggy' in the sense that // uninteresting calls on it will cause a warning to be printed. +// +// Prefer to use the NiceCallbackFactory where possible (see +// go/gmock-cookbook#NiceStrictNaggy) template <typename F> class NaggyCallbackFactory : public ::testing::MockFunction<F> { public: @@ -39,10 +42,16 @@ }; // As above, but uninteresting calls will be errors. +// +// Prefer to use the NiceCallbackFactory where possible (see +// go/gmock-cookbook#NiceStrictNaggy) template <typename F> using StrictCallbackFactory = ::testing::StrictMock<NaggyCallbackFactory<F>>; // As above, but uninteresting calls will be ignored. +// +// We recommend using this factory in preference to the others, see +// go/gmock-cookbook#NiceStrictNaggy for more information. template <typename F> using NiceCallbackFactory = ::testing::NiceMock<NaggyCallbackFactory<F>>;
diff --git a/chrome/browser/ash/login/ui/login_screen_extension_ui/web_dialog_view.cc b/chrome/browser/ash/login/ui/login_screen_extension_ui/web_dialog_view.cc index 90a44a6..347f6ed 100644 --- a/chrome/browser/ash/login/ui/login_screen_extension_ui/web_dialog_view.cc +++ b/chrome/browser/ash/login/ui/login_screen_extension_ui/web_dialog_view.cc
@@ -16,7 +16,7 @@ WebDialogView::WebDialogView( content::BrowserContext* context, - DialogDelegate* delegate, + chromeos::login_screen_extension_ui::DialogDelegate* delegate, std::unique_ptr<ui::WebDialogWebContentsDelegate::WebContentsHandler> handler) : views::WebDialogView(context, delegate, std::move(handler)),
diff --git a/chrome/browser/ash/login/ui/login_screen_extension_ui/web_dialog_view.h b/chrome/browser/ash/login/ui/login_screen_extension_ui/web_dialog_view.h index 2cb66ae..ff1490d 100644 --- a/chrome/browser/ash/login/ui/login_screen_extension_ui/web_dialog_view.h +++ b/chrome/browser/ash/login/ui/login_screen_extension_ui/web_dialog_view.h
@@ -32,7 +32,7 @@ METADATA_HEADER(WebDialogView); explicit WebDialogView( content::BrowserContext* context, - DialogDelegate* delegate, + chromeos::login_screen_extension_ui::DialogDelegate* delegate, std::unique_ptr<ui::WebDialogWebContentsDelegate::WebContentsHandler> handler); WebDialogView(const WebDialogView&) = delete; @@ -46,7 +46,9 @@ void OnFocusLeavingSystemTray(bool reverse) override; private: - DialogDelegate* delegate_ = nullptr; + // views::WebDialogView extends views::DialogDelegate, so fully qualified name + // is needed. + chromeos::login_screen_extension_ui::DialogDelegate* delegate_ = nullptr; }; } // namespace login_screen_extension_ui
diff --git a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc index 1bb487f..aa20c56 100644 --- a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc +++ b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc
@@ -384,6 +384,10 @@ return profile_->GetPrefs()->GetBoolean(prefs::kSearchSuggestEnabled); } +bool ChromeAutocompleteProviderClient::AllowDeletingBrowserHistory() const { + return profile_->GetPrefs()->GetBoolean(prefs::kAllowDeletingBrowserHistory); +} + bool ChromeAutocompleteProviderClient::IsPersonalizedUrlDataCollectionActive() const { return url_consent_helper_->IsEnabled();
diff --git a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.h b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.h index 2f4e86a..bcac51a 100644 --- a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.h +++ b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.h
@@ -71,6 +71,7 @@ signin::IdentityManager* GetIdentityManager() const override; bool IsOffTheRecord() const override; bool SearchSuggestEnabled() const override; + bool AllowDeletingBrowserHistory() const override; bool IsPersonalizedUrlDataCollectionActive() const override; bool IsAuthenticated() const override; bool IsSyncActive() const override;
diff --git a/chrome/browser/autofill/manual_filling_controller.h b/chrome/browser/autofill/manual_filling_controller.h index 03a0f70e..91b912e 100644 --- a/chrome/browser/autofill/manual_filling_controller.h +++ b/chrome/browser/autofill/manual_filling_controller.h
@@ -98,6 +98,11 @@ // action (given by an enum param) is available. virtual void OnAutomaticGenerationStatusChanged(bool available) = 0; + // Instructs the view to show the manual filling sheet for the given + // |tab_type|. + virtual void ShowAccessorySheetTab( + const autofill::AccessoryTabType& tab_type) = 0; + // -------------------------- // Methods called by UI code: // --------------------------
diff --git a/chrome/browser/autofill/manual_filling_controller_impl.cc b/chrome/browser/autofill/manual_filling_controller_impl.cc index b80bda10..7e0a7f3 100644 --- a/chrome/browser/autofill/manual_filling_controller_impl.cc +++ b/chrome/browser/autofill/manual_filling_controller_impl.cc
@@ -157,6 +157,18 @@ UpdateVisibility(); } +void ManualFillingControllerImpl::ShowAccessorySheetTab( + const autofill::AccessoryTabType& tab_type) { + if (tab_type == autofill::AccessoryTabType::CREDIT_CARDS) { + cc_controller_->RefreshSuggestions(); + } else { + NOTIMPLEMENTED() + << "ShowAccessorySheetTab does not support the given TabType yet " + << tab_type; + } + view_->ShowAccessorySheetTab(tab_type); +} + void ManualFillingControllerImpl::UpdateSourceAvailability( FillingSource source, bool has_suggestions) {
diff --git a/chrome/browser/autofill/manual_filling_controller_impl.h b/chrome/browser/autofill/manual_filling_controller_impl.h index 650ddee1..70723d3 100644 --- a/chrome/browser/autofill/manual_filling_controller_impl.h +++ b/chrome/browser/autofill/manual_filling_controller_impl.h
@@ -44,6 +44,8 @@ bool has_suggestions) override; void Hide() override; void OnAutomaticGenerationStatusChanged(bool available) override; + void ShowAccessorySheetTab( + const autofill::AccessoryTabType& tab_type) override; void OnFillingTriggered(autofill::AccessoryTabType type, const autofill::UserInfo::Field& selection) override; void OnOptionSelected(
diff --git a/chrome/browser/autofill/manual_filling_view_interface.h b/chrome/browser/autofill/manual_filling_view_interface.h index 7eef076..bb933947 100644 --- a/chrome/browser/autofill/manual_filling_view_interface.h +++ b/chrome/browser/autofill/manual_filling_view_interface.h
@@ -9,6 +9,7 @@ #include <vector> #include "build/build_config.h" +#include "components/autofill/core/browser/ui/accessory_sheet_enums.h" #include "url/gurl.h" class ManualFillingController; @@ -75,6 +76,10 @@ // Hides the accessory bar and the accessory sheet (if open). virtual void Hide() = 0; + // Shows the accessory sheet for the given |tab_type|. + virtual void ShowAccessorySheetTab( + const autofill::AccessoryTabType& tab_type) = 0; + private: friend class ManualFillingControllerImpl; // Factory function used to create a concrete instance of this view.
diff --git a/chrome/browser/autofill/mock_manual_filling_controller.h b/chrome/browser/autofill/mock_manual_filling_controller.h index 35d101e..cedce3a 100644 --- a/chrome/browser/autofill/mock_manual_filling_controller.h +++ b/chrome/browser/autofill/mock_manual_filling_controller.h
@@ -24,6 +24,7 @@ void(ManualFillingController::FillingSource, bool)); MOCK_METHOD0(Hide, void()); MOCK_METHOD1(OnAutomaticGenerationStatusChanged, void(bool)); + MOCK_METHOD1(ShowAccessorySheetTab, void(const autofill::AccessoryTabType&)); MOCK_METHOD2(OnFillingTriggered, void(autofill::AccessoryTabType type, const autofill::UserInfo::Field&));
diff --git a/chrome/browser/autofill/mock_manual_filling_view.h b/chrome/browser/autofill/mock_manual_filling_view.h index 4f220cd..fa463b9 100644 --- a/chrome/browser/autofill/mock_manual_filling_view.h +++ b/chrome/browser/autofill/mock_manual_filling_view.h
@@ -7,6 +7,7 @@ #include "chrome/browser/autofill/manual_filling_view_interface.h" #include "components/autofill/core/browser/ui/accessory_sheet_data.h" +#include "components/autofill/core/browser/ui/accessory_sheet_enums.h" #include "testing/gmock/include/gmock/gmock.h" class MockManualFillingView : public ManualFillingViewInterface { @@ -20,6 +21,7 @@ MOCK_METHOD0(SwapSheetWithKeyboard, void()); MOCK_METHOD0(ShowWhenKeyboardIsVisible, void()); MOCK_METHOD0(Hide, void()); + MOCK_METHOD1(ShowAccessorySheetTab, void(const autofill::AccessoryTabType&)); private: DISALLOW_COPY_AND_ASSIGN(MockManualFillingView);
diff --git a/chrome/browser/browser_process.h b/chrome/browser/browser_process.h index 3d634db..a7657cb 100644 --- a/chrome/browser/browser_process.h +++ b/chrome/browser/browser_process.h
@@ -35,11 +35,12 @@ class NotificationUIManager; class PrefService; class ProfileManager; +class SerialPolicyAllowedPorts; +class StartupData; class StatusTray; class SystemNetworkContextManager; class WatchDogThread; class WebRtcLogUploader; -class StartupData; #if !defined(OS_ANDROID) class IntranetRedirectDetector; @@ -260,6 +261,12 @@ virtual resource_coordinator::ResourceCoordinatorParts* resource_coordinator_parts() = 0; +#if !defined(OS_ANDROID) + // Returns the object which keeps track of serial port permissions configured + // through the policy engine. + virtual SerialPolicyAllowedPorts* serial_policy_allowed_ports() = 0; +#endif + virtual BuildState* GetBuildState() = 0; private:
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc index 5e43450..54e8cca 100644 --- a/chrome/browser/browser_process_impl.cc +++ b/chrome/browser/browser_process_impl.cc
@@ -157,6 +157,7 @@ #include "chrome/browser/gcm/gcm_product_util.h" #include "chrome/browser/intranet_redirect_detector.h" #include "chrome/browser/resource_coordinator/tab_manager.h" +#include "chrome/browser/serial/serial_policy_allowed_ports.h" #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_list.h" #include "components/gcm_driver/gcm_client_factory.h" @@ -895,6 +896,17 @@ return resource_coordinator_parts_.get(); } +#if !defined(OS_ANDROID) +SerialPolicyAllowedPorts* BrowserProcessImpl::serial_policy_allowed_ports() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (!serial_policy_allowed_ports_) { + serial_policy_allowed_ports_ = + std::make_unique<SerialPolicyAllowedPorts>(local_state()); + } + return serial_policy_allowed_ports_.get(); +} +#endif + BuildState* BrowserProcessImpl::GetBuildState() { #if !defined(OS_ANDROID) DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
diff --git a/chrome/browser/browser_process_impl.h b/chrome/browser/browser_process_impl.h index 0ee317e..e9c1273 100644 --- a/chrome/browser/browser_process_impl.h +++ b/chrome/browser/browser_process_impl.h
@@ -200,6 +200,10 @@ resource_coordinator::ResourceCoordinatorParts* resource_coordinator_parts() override; +#if !defined(OS_ANDROID) + SerialPolicyAllowedPorts* serial_policy_allowed_ports() override; +#endif + BuildState* GetBuildState() override; static void RegisterPrefs(PrefRegistrySimple* registry); @@ -403,6 +407,8 @@ // Called to signal the process' main message loop to exit. base::OnceClosure quit_closure_; + std::unique_ptr<SerialPolicyAllowedPorts> serial_policy_allowed_ports_; + BuildState build_state_; #endif
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc index 54ff3062..65524fb9 100644 --- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc +++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
@@ -13,7 +13,6 @@ #include "base/bind.h" #include "base/containers/contains.h" -#include "base/containers/flat_set.h" #include "base/files/file_util.h" #include "base/guid.h" #include "base/memory/ptr_util.h" @@ -137,6 +136,8 @@ #include "services/network/public/mojom/network_context.mojom.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/gfx/favicon_size.h" +#include "url/gurl.h" +#include "url/origin.h" #if defined(OS_ANDROID) #include "chrome/browser/android/customtabs/origin_verifier.h" @@ -170,6 +171,7 @@ #endif // BUILDFLAG(ENABLE_PLUGINS) #if BUILDFLAG(ENABLE_REPORTING) +#include "base/containers/flat_map.h" #include "net/network_error_logging/network_error_logging_service.h" #include "net/reporting/reporting_browsing_data_remover.h" #include "net/reporting/reporting_policy.h" @@ -833,6 +835,13 @@ ~MockReportingService() override = default; + void SetDocumentReportingEndpoints( + const url::Origin& origin, + const net::NetworkIsolationKey& network_isolation_key, + const base::flat_map<std::string, std::string>& endpoints) override { + NOTREACHED(); + } + void QueueReport(const GURL& url, const net::NetworkIsolationKey& network_isolation_key, const std::string& user_agent, @@ -850,13 +859,6 @@ NOTREACHED(); } - void ProcessReportingEndpointsHeader( - const url::Origin& origin, - const net::NetworkIsolationKey& network_isolation_key, - const std::string& header_value) override { - NOTREACHED(); - } - void RemoveBrowsingData(uint64_t data_type_mask, const base::RepeatingCallback<bool(const GURL&)>& origin_filter) override {
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index 2ffe9581..1834781 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -41,6 +41,7 @@ "//chromeos/dbus:runtime_probe_proto", "//chromeos/dbus:seneschal_proto", "//chromeos/dbus:vm_applications_apps_proto", + "//chromeos/dbus:vm_disk_management_proto", "//chromeos/dbus:vm_permission_service_proto", "//chromeos/dbus:vm_sk_forwarding_proto", "//chromeos/dbus/power:power_manager_proto", @@ -2169,6 +2170,8 @@ "dbus/smb_fs_service_provider.h", "dbus/virtual_file_request_service_provider.cc", "dbus/virtual_file_request_service_provider.h", + "dbus/vm/vm_disk_management_service_provider.cc", + "dbus/vm/vm_disk_management_service_provider.h", "dbus/vm/vm_permission_service_provider.cc", "dbus/vm/vm_permission_service_provider.h", "dbus/vm/vm_sk_forwarding_service_provider.cc", @@ -3318,6 +3321,7 @@ "dbus/org.chromium.SmbFsService.conf", "dbus/org.chromium.VirtualFileRequestService.conf", "dbus/org.chromium.VmApplicationsService.conf", + "dbus/vm/org.chromium.VmDiskManagementService.conf", "dbus/vm/org.chromium.VmPermissionService.conf", "dbus/vm/org.chromium.VmSKForwardingService.conf", ]
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc index 10a6ba5..5142012a 100644 --- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc +++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -112,6 +112,7 @@ #include "chrome/browser/chromeos/dbus/screen_lock_service_provider.h" #include "chrome/browser/chromeos/dbus/smb_fs_service_provider.h" #include "chrome/browser/chromeos/dbus/virtual_file_request_service_provider.h" +#include "chrome/browser/chromeos/dbus/vm/vm_disk_management_service_provider.h" #include "chrome/browser/chromeos/dbus/vm/vm_permission_service_provider.h" #include "chrome/browser/chromeos/dbus/vm/vm_sk_forwarding_service_provider.h" #include "chrome/browser/chromeos/dbus/vm_applications_service_provider.h" @@ -354,6 +355,13 @@ CrosDBusService::CreateServiceProviderList( std::make_unique<VmApplicationsServiceProvider>())); + vm_disk_management_service_ = CrosDBusService::Create( + system_bus, vm_tools::disk_management::kVmDiskManagementServiceName, + dbus::ObjectPath( + vm_tools::disk_management::kVmDiskManagementServicePath), + CrosDBusService::CreateServiceProviderList( + std::make_unique<VmDiskManagementServiceProvider>())); + vm_sk_forwarding_service_ = CrosDBusService::Create( system_bus, vm_tools::sk_forwarding::kVmSKForwardingServiceName, dbus::ObjectPath(vm_tools::sk_forwarding::kVmSKForwardingServicePath), @@ -465,6 +473,7 @@ component_updater_service_.reset(); chrome_features_service_.reset(); vm_applications_service_.reset(); + vm_disk_management_service_.reset(); vm_sk_forwarding_service_.reset(); vm_permission_service_.reset(); drive_file_stream_service_.reset(); @@ -494,6 +503,7 @@ std::unique_ptr<CrosDBusService> component_updater_service_; std::unique_ptr<CrosDBusService> chrome_features_service_; std::unique_ptr<CrosDBusService> vm_applications_service_; + std::unique_ptr<CrosDBusService> vm_disk_management_service_; std::unique_ptr<CrosDBusService> vm_sk_forwarding_service_; std::unique_ptr<CrosDBusService> vm_permission_service_; std::unique_ptr<CrosDBusService> drive_file_stream_service_;
diff --git a/chrome/browser/chromeos/dbus/vm/org.chromium.VmDiskManagementService.conf b/chrome/browser/chromeos/dbus/vm/org.chromium.VmDiskManagementService.conf new file mode 100644 index 0000000..a98fae0 --- /dev/null +++ b/chrome/browser/chromeos/dbus/vm/org.chromium.VmDiskManagementService.conf
@@ -0,0 +1,18 @@ +<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" + "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> +<!-- + Copyright 2021 The Chromium Authors. All rights reserved. + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. +--> + +<busconfig> + <policy user="chronos"> + <allow own="org.chromium.VmDiskManagementService"/> + </policy> + + <policy user="vm_cicerone"> + <allow send_destination="org.chromium.VmDiskManagementService" + send_interface="org.chromium.VmDiskManagementService"/> + </policy> +</busconfig> \ No newline at end of file
diff --git a/chrome/browser/chromeos/dbus/vm/vm_disk_management_service_provider.cc b/chrome/browser/chromeos/dbus/vm/vm_disk_management_service_provider.cc new file mode 100644 index 0000000..c05fc77 --- /dev/null +++ b/chrome/browser/chromeos/dbus/vm/vm_disk_management_service_provider.cc
@@ -0,0 +1,231 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/dbus/vm/vm_disk_management_service_provider.h" + +#include <string> + +#include "base/bind.h" +#include "base/logging.h" +#include "chrome/browser/ash/borealis/borealis_disk_manager_dispatcher.h" +#include "chrome/browser/ash/borealis/borealis_service.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "chromeos/dbus/vm_disk_management/disk_management.pb.h" +#include "dbus/bus.h" +#include "dbus/message.h" +#include "third_party/cros_system_api/dbus/service_constants.h" + +namespace chromeos { + +VmDiskManagementServiceProvider::VmDiskManagementServiceProvider() = default; + +VmDiskManagementServiceProvider::~VmDiskManagementServiceProvider() = default; + +void VmDiskManagementServiceProvider::Start( + scoped_refptr<dbus::ExportedObject> exported_object) { + exported_object->ExportMethod( + vm_tools::disk_management::kVmDiskManagementServiceInterface, + vm_tools::disk_management::kVmDiskManagementServiceGetDiskInfoMethod, + base::BindRepeating(&VmDiskManagementServiceProvider::GetDiskInfo, + weak_ptr_factory_.GetWeakPtr()), + base::BindOnce(&VmDiskManagementServiceProvider::OnExported, + weak_ptr_factory_.GetWeakPtr())); + exported_object->ExportMethod( + vm_tools::disk_management::kVmDiskManagementServiceInterface, + vm_tools::disk_management::kVmDiskManagementServiceRequestSpaceMethod, + base::BindRepeating(&VmDiskManagementServiceProvider::RequestSpace, + weak_ptr_factory_.GetWeakPtr()), + base::BindOnce(&VmDiskManagementServiceProvider::OnExported, + weak_ptr_factory_.GetWeakPtr())); + exported_object->ExportMethod( + vm_tools::disk_management::kVmDiskManagementServiceInterface, + vm_tools::disk_management::kVmDiskManagementServiceReleaseSpaceMethod, + base::BindRepeating(&VmDiskManagementServiceProvider::ReleaseSpace, + weak_ptr_factory_.GetWeakPtr()), + base::BindOnce(&VmDiskManagementServiceProvider::OnExported, + weak_ptr_factory_.GetWeakPtr())); +} + +void VmDiskManagementServiceProvider::OnExported( + const std::string& interface_name, + const std::string& method_name, + bool success) { + LOG_IF(ERROR, !success) << "Failed to export " << interface_name << "." + << method_name; +} + +void VmDiskManagementServiceProvider::GetDiskInfo( + dbus::MethodCall* method_call, + dbus::ExportedObject::ResponseSender response_sender) { + dbus::MessageReader reader(method_call); + + vm_tools::disk_management::GetDiskInfoRequest request; + if (!reader.PopArrayOfBytesAsProto(&request)) { + constexpr char error_message[] = + "Unable to parse GetDiskInfoRequest from message"; + LOG(ERROR) << error_message; + std::move(response_sender) + .Run(dbus::ErrorResponse::FromMethodCall( + method_call, DBUS_ERROR_INVALID_ARGS, error_message)); + return; + } + + std::unique_ptr<dbus::Response> response = + dbus::Response::FromMethodCall(method_call); + + if (request.origin().vm_name().empty() || + request.origin().container_name().empty() || + request.origin().owner_id().empty()) { + std::string error = + "GetDiskInfoRequest failed: request has missing or incomplete origin"; + OnGetDiskInfo( + std::move(response), std::move(response_sender), + borealis::Expected<borealis::BorealisDiskManager::GetDiskInfoResponse, + std::string>::Unexpected(std::move(error))); + } + + borealis::BorealisService::GetForProfile( + ProfileManager::GetPrimaryUserProfile()) + ->DiskManagerDispatcher() + .GetDiskInfo( + request.origin().vm_name(), request.origin().container_name(), + base::BindOnce(&VmDiskManagementServiceProvider::OnGetDiskInfo, + weak_ptr_factory_.GetWeakPtr(), std::move(response), + std::move(response_sender))); +} + +void VmDiskManagementServiceProvider::RequestSpace( + dbus::MethodCall* method_call, + dbus::ExportedObject::ResponseSender response_sender) { + dbus::MessageReader reader(method_call); + + vm_tools::disk_management::RequestSpaceRequest request; + if (!reader.PopArrayOfBytesAsProto(&request)) { + constexpr char error_message[] = + "Unable to parse RequestSpaceRequest from message"; + LOG(ERROR) << error_message; + std::move(response_sender) + .Run(dbus::ErrorResponse::FromMethodCall( + method_call, DBUS_ERROR_INVALID_ARGS, error_message)); + return; + } + + std::unique_ptr<dbus::Response> response = + dbus::Response::FromMethodCall(method_call); + + if (request.origin().vm_name().empty() || + request.origin().container_name().empty() || + request.origin().owner_id().empty()) { + std::string error = + "RequestSpaceRequest failed: request has missing or incomplete origin"; + OnRequestSpace(std::move(response), std::move(response_sender), + borealis::Expected<uint64_t, std::string>::Unexpected( + std::move(error))); + } + + borealis::BorealisService::GetForProfile( + ProfileManager::GetPrimaryUserProfile()) + ->DiskManagerDispatcher() + .RequestSpace( + request.origin().vm_name(), request.origin().container_name(), + request.space_requested(), + base::BindOnce(&VmDiskManagementServiceProvider::OnRequestSpace, + weak_ptr_factory_.GetWeakPtr(), std::move(response), + std::move(response_sender))); +} + +void VmDiskManagementServiceProvider::ReleaseSpace( + dbus::MethodCall* method_call, + dbus::ExportedObject::ResponseSender response_sender) { + dbus::MessageReader reader(method_call); + + vm_tools::disk_management::ReleaseSpaceRequest request; + if (!reader.PopArrayOfBytesAsProto(&request)) { + constexpr char error_message[] = + "Unable to parse ReleaseSpaceRequest from message"; + LOG(ERROR) << error_message; + std::move(response_sender) + .Run(dbus::ErrorResponse::FromMethodCall( + method_call, DBUS_ERROR_INVALID_ARGS, error_message)); + return; + } + + std::unique_ptr<dbus::Response> response = + dbus::Response::FromMethodCall(method_call); + + if (request.origin().vm_name().empty() || + request.origin().container_name().empty() || + request.origin().owner_id().empty()) { + std::string error = + "ReleaseSpaceRequest failed: request has missing or incomplete origin"; + OnReleaseSpace(std::move(response), std::move(response_sender), + borealis::Expected<uint64_t, std::string>::Unexpected( + std::move(error))); + } + + borealis::BorealisService::GetForProfile( + ProfileManager::GetPrimaryUserProfile()) + ->DiskManagerDispatcher() + .RequestSpace( + request.origin().vm_name(), request.origin().container_name(), + request.space_to_release(), + base::BindOnce(&VmDiskManagementServiceProvider::OnReleaseSpace, + weak_ptr_factory_.GetWeakPtr(), std::move(response), + std::move(response_sender))); +} + +void VmDiskManagementServiceProvider::OnGetDiskInfo( + std::unique_ptr<dbus::Response> response, + dbus::ExportedObject::ResponseSender response_sender, + borealis::Expected<borealis::BorealisDiskManager::GetDiskInfoResponse, + std::string> response_or_error) { + vm_tools::disk_management::GetDiskInfoResponse payload; + if (!response_or_error) { + LOG(ERROR) << "GetDiskInfoRequest failed: " << response_or_error.Error(); + payload.set_error(1); + } else { + payload.set_available_space(response_or_error.Value().available_bytes); + payload.set_expandable_space(response_or_error.Value().expandable_bytes); + } + // Reply to the original D-Bus method call. + dbus::MessageWriter writer(response.get()); + writer.AppendProtoAsArrayOfBytes(payload); + std::move(response_sender).Run(std::move(response)); +} + +void VmDiskManagementServiceProvider::OnRequestSpace( + std::unique_ptr<dbus::Response> response, + dbus::ExportedObject::ResponseSender response_sender, + borealis::Expected<uint64_t, std::string> response_or_error) { + vm_tools::disk_management::RequestSpaceResponse payload; + if (!response_or_error) { + LOG(ERROR) << "RequestSpaceRequest failed: " << response_or_error.Error(); + payload.set_error(1); + } else { + payload.set_space_granted(response_or_error.Value()); + } + // Reply to the original D-Bus method call. + dbus::MessageWriter writer(response.get()); + writer.AppendProtoAsArrayOfBytes(payload); + std::move(response_sender).Run(std::move(response)); +} + +void VmDiskManagementServiceProvider::OnReleaseSpace( + std::unique_ptr<dbus::Response> response, + dbus::ExportedObject::ResponseSender response_sender, + borealis::Expected<uint64_t, std::string> response_or_error) { + vm_tools::disk_management::ReleaseSpaceResponse payload; + if (!response_or_error) { + LOG(ERROR) << "ReleaseSpaceRequest failed: " << response_or_error.Error(); + payload.set_error(1); + } else { + payload.set_space_released(response_or_error.Value()); + } + // Reply to the original D-Bus method call. + dbus::MessageWriter writer(response.get()); + writer.AppendProtoAsArrayOfBytes(payload); + std::move(response_sender).Run(std::move(response)); +} + +} // namespace chromeos
diff --git a/chrome/browser/chromeos/dbus/vm/vm_disk_management_service_provider.h b/chrome/browser/chromeos/dbus/vm/vm_disk_management_service_provider.h new file mode 100644 index 0000000..46d3b43c --- /dev/null +++ b/chrome/browser/chromeos/dbus/vm/vm_disk_management_service_provider.h
@@ -0,0 +1,71 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_CHROMEOS_DBUS_VM_VM_DISK_MANAGEMENT_SERVICE_PROVIDER_H_ +#define CHROME_BROWSER_CHROMEOS_DBUS_VM_VM_DISK_MANAGEMENT_SERVICE_PROVIDER_H_ + +#include "base/compiler_specific.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "chrome/browser/ash/borealis/borealis_disk_manager.h" +#include "chromeos/dbus/services/cros_dbus_service.h" +#include "dbus/exported_object.h" + +namespace dbus { +class MethodCall; +} // namespace dbus + +namespace chromeos { + +// This class exports D-Bus methods used by Crostini VMs (currently only +// Borealis) for resizing their disks. +class VmDiskManagementServiceProvider + : public CrosDBusService::ServiceProviderInterface { + public: + VmDiskManagementServiceProvider(); + VmDiskManagementServiceProvider(const VmDiskManagementServiceProvider&) = + delete; + VmDiskManagementServiceProvider& operator=( + const VmDiskManagementServiceProvider&) = delete; + ~VmDiskManagementServiceProvider() override; + + // CrosDBusService::ServiceProviderInterface overrides: + void Start(scoped_refptr<dbus::ExportedObject> exported_object) override; + + private: + // Called from ExportedObject when UpdateApplicationList() is exported as a + // D-Bus method or failed to be exported. + void OnExported(const std::string& interface_name, + const std::string& method_name, + bool success); + + // Called on UI thread in response to a D-Bus request. + void GetDiskInfo(dbus::MethodCall* method_call, + dbus::ExportedObject::ResponseSender response_sender); + void RequestSpace(dbus::MethodCall* method_call, + dbus::ExportedObject::ResponseSender response_sender); + void ReleaseSpace(dbus::MethodCall* method_call, + dbus::ExportedObject::ResponseSender response_sender); + + // Callbacks for responding to certain D-Bus requests. + void OnGetDiskInfo( + std::unique_ptr<dbus::Response> response, + dbus::ExportedObject::ResponseSender response_sender, + borealis::Expected<borealis::BorealisDiskManager::GetDiskInfoResponse, + std::string> response_or_error); + void OnRequestSpace( + std::unique_ptr<dbus::Response> response, + dbus::ExportedObject::ResponseSender response_sender, + borealis::Expected<uint64_t, std::string> response_or_error); + void OnReleaseSpace( + std::unique_ptr<dbus::Response> response, + dbus::ExportedObject::ResponseSender response_sender, + borealis::Expected<uint64_t, std::string> response_or_error); + + base::WeakPtrFactory<VmDiskManagementServiceProvider> weak_ptr_factory_{this}; +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_DBUS_VM_VM_DISK_MANAGEMENT_SERVICE_PROVIDER_H_
diff --git a/chrome/browser/chromeos/nearby/nearby_process_manager_impl.cc b/chrome/browser/chromeos/nearby/nearby_process_manager_impl.cc index 3fba385..6af7b02 100644 --- a/chrome/browser/chromeos/nearby/nearby_process_manager_impl.cc +++ b/chrome/browser/chromeos/nearby/nearby_process_manager_impl.cc
@@ -166,8 +166,10 @@ connections_receiver = connections.InitWithNewPipeAndPassReceiver(); connections_.Bind(std::move(connections), /*bind_task_runner=*/nullptr); connections_.set_disconnect_handler( - base::BindOnce(&NearbyProcessManagerImpl::OnMojoPipeDisconnect, - weak_ptr_factory_.GetWeakPtr()), + base::BindOnce( + &NearbyProcessManagerImpl::OnMojoPipeDisconnect, + weak_ptr_factory_.GetWeakPtr(), + NearbyProcessShutdownReason::kConnectionsMojoPipeDisconnection), base::SequencedTaskRunnerHandle::Get()); mojo::PendingRemote<sharing::mojom::NearbySharingDecoder> decoder; @@ -175,8 +177,10 @@ decoder.InitWithNewPipeAndPassReceiver(); decoder_.Bind(std::move(decoder), /*bind_task_runner=*/nullptr); decoder_.set_disconnect_handler( - base::BindOnce(&NearbyProcessManagerImpl::OnMojoPipeDisconnect, - weak_ptr_factory_.GetWeakPtr()), + base::BindOnce( + &NearbyProcessManagerImpl::OnMojoPipeDisconnect, + weak_ptr_factory_.GetWeakPtr(), + NearbyProcessShutdownReason::kDecoderMojoPipeDisconnection), base::SequencedTaskRunnerHandle::Get()); // Pass these references to Connect() to start up the process. @@ -196,11 +200,11 @@ NotifyProcessStopped(shutdown_reason); } -void NearbyProcessManagerImpl::OnMojoPipeDisconnect() { - NS_LOG(ERROR) << "A utility process Mojo pipe has disconnected."; - - NearbyProcessShutdownReason shutdown_reason = - NearbyProcessShutdownReason::kMojoPipeDisconnection; +void NearbyProcessManagerImpl::OnMojoPipeDisconnect( + NearbyProcessShutdownReason shutdown_reason) { + NS_LOG(ERROR) << "The browser process has detected that the utility process " + "disconnected from a mojo pipe. [" + << shutdown_reason << "]"; ShutDownProcess(shutdown_reason); NotifyProcessStopped(shutdown_reason);
diff --git a/chrome/browser/chromeos/nearby/nearby_process_manager_impl.h b/chrome/browser/chromeos/nearby/nearby_process_manager_impl.h index 2179661..2461fc7 100644 --- a/chrome/browser/chromeos/nearby/nearby_process_manager_impl.h +++ b/chrome/browser/chromeos/nearby/nearby_process_manager_impl.h
@@ -96,7 +96,7 @@ bool AttemptToBindToUtilityProcess(); void OnSharingProcessCrash(); - void OnMojoPipeDisconnect(); + void OnMojoPipeDisconnect(NearbyProcessShutdownReason shutdown_reason); void OnReferenceDeleted(const base::UnguessableToken& reference_id); void ShutDownProcess(NearbyProcessShutdownReason shutdown_reason); void NotifyProcessStopped(NearbyProcessShutdownReason shutdown_reason);
diff --git a/chrome/browser/chromeos/secure_channel/nearby_connector_impl.cc b/chrome/browser/chromeos/secure_channel/nearby_connector_impl.cc index 29562d45..52fdb9b3 100644 --- a/chrome/browser/chromeos/secure_channel/nearby_connector_impl.cc +++ b/chrome/browser/chromeos/secure_channel/nearby_connector_impl.cc
@@ -155,7 +155,8 @@ util::NearbyDisconnectionReason::kNearbyProcessCrash; break; - case NearbyProcessShutdownReason::kMojoPipeDisconnection: + case NearbyProcessShutdownReason::kConnectionsMojoPipeDisconnection: + case NearbyProcessShutdownReason::kDecoderMojoPipeDisconnection: disconnection_reason = util::NearbyDisconnectionReason::kNearbyProcessMojoDisconnection; break;
diff --git a/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc b/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc index f2719e6..c176431 100644 --- a/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc +++ b/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc
@@ -139,6 +139,8 @@ // Canvas tests rely on the harness producing pixel output in order to read back // pixels from a canvas element. So we have to override the setup function. +// TODO(https://crbug.com/1093066): Investigate to see if these tests can be +// enabled for Service Worker-based extensions. class BrowserActionApiCanvasTest : public BrowserActionApiTest { public: void SetUp() override { @@ -149,7 +151,7 @@ using ContextType = ExtensionBrowserTest::ContextType; -class BrowserActionApiLazyTest +class BrowserActionApiTestWithContextType : public BrowserActionApiTest, public testing::WithParamInterface<ContextType> { protected: @@ -225,11 +227,17 @@ action->GetIsVisible(ExtensionAction::kDefaultTabId)); } + bool RunTest(const char* name) WARN_UNUSED_RESULT { + return RunExtensionTest( + name, {}, + {.load_as_service_worker = GetParam() == ContextType::kServiceWorker}); + } + private: base::test::ScopedFeatureList feature_list_; }; -IN_PROC_BROWSER_TEST_P(BrowserActionApiLazyTest, Basic) { +IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType, Basic) { ExtensionTestMessageListener ready_listener("ready", false); ASSERT_TRUE(embedded_test_server()->Start()); const Extension* extension = LoadExtensionWithParamOptions( @@ -253,19 +261,19 @@ EXPECT_TRUE(catcher.GetNextResult()); } -IN_PROC_BROWSER_TEST_P(BrowserActionApiLazyTest, Disable) { +IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType, Disable) { ASSERT_NO_FATAL_FAILURE(RunEnableTest("browser_action/enable", true)); } -IN_PROC_BROWSER_TEST_P(BrowserActionApiLazyTest, Enable) { +IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType, Enable) { ASSERT_NO_FATAL_FAILURE(RunEnableTest("browser_action/enable", false)); } -IN_PROC_BROWSER_TEST_P(BrowserActionApiLazyTest, Update) { +IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType, Update) { ASSERT_NO_FATAL_FAILURE(RunUpdateTest("browser_action/update", false)); } -IN_PROC_BROWSER_TEST_P(BrowserActionApiLazyTest, UpdateSvg) { +IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType, UpdateSvg) { // TODO(crbug.com/1064671): Service Workers currently don't support loading // SVG images. const bool expect_failure = GetParam() == ContextType::kServiceWorker; @@ -273,11 +281,11 @@ RunUpdateTest("browser_action/update_svg", expect_failure)); } -INSTANTIATE_TEST_SUITE_P(EventPage, - BrowserActionApiLazyTest, - ::testing::Values(ContextType::kEventPage)); +INSTANTIATE_TEST_SUITE_P(PersistentBackground, + BrowserActionApiTestWithContextType, + ::testing::Values(ContextType::kPersistentBackground)); INSTANTIATE_TEST_SUITE_P(ServiceWorker, - BrowserActionApiLazyTest, + BrowserActionApiTestWithContextType, ::testing::Values(ContextType::kServiceWorker)); IN_PROC_BROWSER_TEST_F(BrowserActionApiCanvasTest, DynamicBrowserAction) { @@ -523,10 +531,9 @@ } } -IN_PROC_BROWSER_TEST_P(BrowserActionApiLazyTest, +IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType, TabSpecificBrowserActionState) { - ASSERT_TRUE(RunExtensionTest("browser_action/tab_specific_state")) << - message_; + ASSERT_TRUE(RunTest("browser_action/tab_specific_state")) << message_; const Extension* extension = GetSingleLoadedExtension(); ASSERT_TRUE(extension) << message_; @@ -558,8 +565,8 @@ // Test that calling chrome.browserAction.setIcon() can set the icon for // extension. -IN_PROC_BROWSER_TEST_P(BrowserActionApiLazyTest, BrowserActionSetIcon) { - ASSERT_TRUE(RunExtensionTest("browser_action/set_icon")) << message_; +IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType, SetIcon) { + ASSERT_TRUE(RunTest("browser_action/set_icon")) << message_; const Extension* extension = GetSingleLoadedExtension(); ASSERT_TRUE(extension) << message_; @@ -592,8 +599,8 @@ // Test that calling chrome.browserAction.setPopup() can enable and change // a popup. -IN_PROC_BROWSER_TEST_P(BrowserActionApiLazyTest, BrowserActionAddPopup) { - ASSERT_TRUE(RunExtensionTest("browser_action/add_popup")) << message_; +IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType, AddPopup) { + ASSERT_TRUE(RunTest("browser_action/add_popup")) << message_; const Extension* extension = GetSingleLoadedExtension(); ASSERT_TRUE(extension) << message_; @@ -647,9 +654,9 @@ } // Test that calling chrome.browserAction.setPopup() can remove a popup. -IN_PROC_BROWSER_TEST_P(BrowserActionApiLazyTest, BrowserActionRemovePopup) { +IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType, RemovePopup) { // Load the extension, which has a browser action with a default popup. - ASSERT_TRUE(RunExtensionTest("browser_action/remove_popup")) << message_; + ASSERT_TRUE(RunTest("browser_action/remove_popup")) << message_; const Extension* extension = GetSingleLoadedExtension(); ASSERT_TRUE(extension) << message_; @@ -681,7 +688,7 @@ << "a specific tab id."; } -IN_PROC_BROWSER_TEST_P(BrowserActionApiLazyTest, IncognitoBasic) { +IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType, IncognitoBasic) { ExtensionTestMessageListener ready_listener("ready", false); ASSERT_TRUE(embedded_test_server()->Start()); scoped_refptr<const Extension> extension = LoadExtensionWithParamOptions( @@ -729,7 +736,7 @@ EXPECT_TRUE(catcher.GetNextResult()); } -IN_PROC_BROWSER_TEST_P(BrowserActionApiLazyTest, IncognitoUpdate) { +IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType, IncognitoUpdate) { ASSERT_TRUE(embedded_test_server()->Start()); ExtensionTestMessageListener incognito_not_allowed_listener( "incognito not allowed", false); @@ -792,7 +799,10 @@ // Tests that events are dispatched to the correct profile for split mode // extensions. -IN_PROC_BROWSER_TEST_P(BrowserActionApiLazyTest, IncognitoSplit) { +// TODO(https://crbug.com/1212866): Crashes or times out when running as a +// Service Worker-based extension. When fixed, make this a +// BrowserActionApiTestWithContextType test. +IN_PROC_BROWSER_TEST_F(BrowserActionApiTest, IncognitoSplit) { ResultCatcher catcher; const Extension* extension = LoadExtension(test_data_dir_.AppendASCII("browser_action/split_mode"), @@ -873,9 +883,10 @@ action->GetExplicitlySetBadgeText(ExtensionAction::kDefaultTabId)); } -IN_PROC_BROWSER_TEST_P(BrowserActionApiLazyTest, BadgeBackgroundColor) { +IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType, + BadgeBackgroundColor) { ASSERT_TRUE(embedded_test_server()->Start()); - ASSERT_TRUE(RunExtensionTest("browser_action/color")) << message_; + ASSERT_TRUE(RunTest("browser_action/color")) << message_; const Extension* extension = GetSingleLoadedExtension(); ASSERT_TRUE(extension) << message_; @@ -922,8 +933,8 @@ action->GetBadgeBackgroundColor(ExtensionAction::kDefaultTabId)); } -IN_PROC_BROWSER_TEST_P(BrowserActionApiLazyTest, Getters) { - ASSERT_TRUE(RunExtensionTest("browser_action/getters")) << message_; +IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType, Getters) { + ASSERT_TRUE(RunTest("browser_action/getters")) << message_; const Extension* extension = GetSingleLoadedExtension(); ASSERT_TRUE(extension) << message_; @@ -943,10 +954,11 @@ } // Verify triggering browser action. -IN_PROC_BROWSER_TEST_P(BrowserActionApiLazyTest, TestTriggerBrowserAction) { +IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType, + TestTriggerBrowserAction) { ASSERT_TRUE(embedded_test_server()->Start()); - ASSERT_TRUE(RunExtensionTest("trigger_actions/browser_action")) << message_; + ASSERT_TRUE(RunTest("trigger_actions/browser_action")) << message_; const Extension* extension = GetSingleLoadedExtension(); ASSERT_TRUE(extension) << message_; @@ -979,11 +991,11 @@ EXPECT_EQ(result, "red"); } -IN_PROC_BROWSER_TEST_P(BrowserActionApiLazyTest, - BrowserActionWithRectangularIcon) { +IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType, + WithRectangularIcon) { ExtensionTestMessageListener ready_listener("ready", true); - const Extension* extension = LoadExtension( + const Extension* extension = LoadExtensionWithParamOptions( test_data_dir_.AppendASCII("browser_action").AppendASCII("rect_icon")); ASSERT_TRUE(extension); EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
diff --git a/chrome/browser/extensions/api/module/module_apitest.cc b/chrome/browser/extensions/api/module/module_apitest.cc index 9330ebfe1..73bdee84 100644 --- a/chrome/browser/extensions/api/module/module_apitest.cc +++ b/chrome/browser/extensions/api/module/module_apitest.cc
@@ -5,27 +5,58 @@ #include "chrome/browser/extensions/extension_apitest.h" #include "content/public/test/browser_test.h" -using ExtensionModuleApiTest = extensions::ExtensionApiTest; +namespace extensions { -IN_PROC_BROWSER_TEST_F(ExtensionModuleApiTest, CognitoFile) { - ASSERT_TRUE(RunExtensionTest("extension_module/cognito_file", {}, - {.allow_file_access = true})) - << message_; -} +namespace { -IN_PROC_BROWSER_TEST_F(ExtensionModuleApiTest, IncognitoFile) { +using ContextType = ExtensionBrowserTest::ContextType; + +class ExtensionModuleApiTest : public ExtensionApiTest, + public testing::WithParamInterface<ContextType> { + public: + ExtensionModuleApiTest() = default; + ~ExtensionModuleApiTest() override = default; + ExtensionModuleApiTest(const ExtensionModuleApiTest&) = delete; + ExtensionModuleApiTest& operator=(const ExtensionModuleApiTest&) = delete; + + protected: + bool RunTest(const char* name, + LoadOptions load_options = {}) WARN_UNUSED_RESULT { + load_options.load_as_service_worker = + GetParam() == ContextType::kServiceWorker; + return RunExtensionTest(name, {}, load_options); + } +}; + +INSTANTIATE_TEST_SUITE_P(PersistentBackground, + ExtensionModuleApiTest, + ::testing::Values(ContextType::kPersistentBackground)); +INSTANTIATE_TEST_SUITE_P(ServiceWorker, + ExtensionModuleApiTest, + ::testing::Values(ContextType::kServiceWorker)); + +} // namespace + +IN_PROC_BROWSER_TEST_P(ExtensionModuleApiTest, CognitoFile) { ASSERT_TRUE( - RunExtensionTest("extension_module/incognito_file", {}, - {.allow_in_incognito = true, .allow_file_access = true})) + RunTest("extension_module/cognito_file", {.allow_file_access = true})) << message_; } -IN_PROC_BROWSER_TEST_F(ExtensionModuleApiTest, CognitoNoFile) { - ASSERT_TRUE(RunExtensionTest("extension_module/cognito_nofile")) << message_; -} - -IN_PROC_BROWSER_TEST_F(ExtensionModuleApiTest, IncognitoNoFile) { - ASSERT_TRUE(RunExtensionTest("extension_module/incognito_nofile", {}, - {.allow_in_incognito = true})) +IN_PROC_BROWSER_TEST_P(ExtensionModuleApiTest, IncognitoFile) { + ASSERT_TRUE(RunTest("extension_module/incognito_file", + {.allow_in_incognito = true, .allow_file_access = true})) << message_; } + +IN_PROC_BROWSER_TEST_P(ExtensionModuleApiTest, CognitoNoFile) { + ASSERT_TRUE(RunTest("extension_module/cognito_nofile")) << message_; +} + +IN_PROC_BROWSER_TEST_P(ExtensionModuleApiTest, IncognitoNoFile) { + ASSERT_TRUE(RunTest("extension_module/incognito_nofile", + {.allow_in_incognito = true})) + << message_; +} + +} // namespace extensions
diff --git a/chrome/browser/extensions/back_forward_cache_browsertest.cc b/chrome/browser/extensions/back_forward_cache_browsertest.cc index e7b7ed2b..4fba49a 100644 --- a/chrome/browser/extensions/back_forward_cache_browsertest.cc +++ b/chrome/browser/extensions/back_forward_cache_browsertest.cc
@@ -12,6 +12,7 @@ #include "extensions/common/extension.h" #include "net/dns/mock_host_resolver.h" #include "third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h" +#include "third_party/blink/public/mojom/frame/back_forward_cache_controller.mojom-shared.h" namespace extensions { @@ -339,4 +340,177 @@ blink::scheduler::WebSchedulerTrackedFeature::kIsolatedWorldScript)); } +// Tests sending a message to all frames does not send it to back-forward +// cached frames. +IN_PROC_BROWSER_TEST_F(ExtensionBackForwardCacheBrowserTest, + MessageSentToAllFramesDoesNotSendToBackForwardCache) { + const Extension* extension = extension = + LoadExtension(test_data_dir_.AppendASCII("back_forward_cache") + .AppendASCII("background_page")); + ASSERT_TRUE(extension); + + ASSERT_TRUE(embedded_test_server()->Start()); + GURL url_a(embedded_test_server()->GetURL("a.com", "/title2.html")); + GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html")); + + // 1) Navigate to A. + content::RenderFrameHost* rfh_a = + ui_test_utils::NavigateToURL(browser(), url_a); + content::RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a); + + // 2) Navigate to B. + content::RenderFrameHost* rfh_b = + ui_test_utils::NavigateToURL(browser(), url_b); + content::RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b); + + // Ensure that `rfh_a` is in the cache. + EXPECT_FALSE(delete_observer_rfh_a.deleted()); + EXPECT_NE(rfh_a, rfh_b); + EXPECT_EQ(rfh_a->GetLifecycleState(), + content::RenderFrameHost::LifecycleState::kInBackForwardCache); + + std::u16string expected_title = u"foo"; + auto title_watcher = std::make_unique<content::TitleWatcher>( + browser()->tab_strip_model()->GetActiveWebContents(), expected_title); + + constexpr char kScript[] = + R"HTML( + chrome.tabs.executeScript({allFrames: true, code: "document.title='foo'"}) + )HTML"; + ASSERT_TRUE(ExecuteScriptInBackgroundPageNoWait(extension->id(), kScript)); + + EXPECT_EQ(expected_title, title_watcher->WaitAndGetTitle()); + + // `rfh_a` should still be in the cache. + EXPECT_FALSE(delete_observer_rfh_a.deleted()); + EXPECT_NE(rfh_a, rfh_b); + EXPECT_EQ(rfh_a->GetLifecycleState(), + content::RenderFrameHost::LifecycleState::kInBackForwardCache); + + // Expect the original title when going back to A. + expected_title = u"Title Of Awesomeness"; + title_watcher = std::make_unique<content::TitleWatcher>( + browser()->tab_strip_model()->GetActiveWebContents(), expected_title); + // Go back to A. + content::WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + web_contents->GetController().GoBack(); + EXPECT_TRUE(WaitForLoadStop(web_contents)); + + EXPECT_EQ(expected_title, title_watcher->WaitAndGetTitle()); + + // `rfh_b` should still be in the cache. + EXPECT_FALSE(delete_observer_rfh_b.deleted()); + EXPECT_NE(rfh_a, rfh_b); + EXPECT_EQ(rfh_b->GetLifecycleState(), + content::RenderFrameHost::LifecycleState::kInBackForwardCache); + + // Now go forward to B, and expect that it is what was set before it + // went into the back forward cache. + expected_title = u"foo"; + title_watcher = std::make_unique<content::TitleWatcher>( + browser()->tab_strip_model()->GetActiveWebContents(), expected_title); + web_contents->GetController().GoForward(); + EXPECT_TRUE(WaitForLoadStop(web_contents)); + + EXPECT_EQ(expected_title, title_watcher->WaitAndGetTitle()); +} + +// Tests sending a message to specific frame that is in the back forward cache +// fails. +IN_PROC_BROWSER_TEST_F(ExtensionBackForwardCacheBrowserTest, + MessageSentToCachedIdFails) { + const Extension* extension = extension = + LoadExtension(test_data_dir_.AppendASCII("back_forward_cache") + .AppendASCII("background_page")); + ASSERT_TRUE(extension); + + ASSERT_TRUE(embedded_test_server()->Start()); + GURL url_a(embedded_test_server()->GetURL("a.com", "/iframe_blank.html")); + GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html")); + + // 1) Navigate to A. + content::RenderFrameHost* rfh_a = + ui_test_utils::NavigateToURL(browser(), url_a); + content::RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a); + + ASSERT_EQ(2u, rfh_a->GetFramesInSubtree().size()); + + // Cache the iframe's frame tree node id to send it a message later. + int iframe_frame_tree_node_id = + rfh_a->GetFramesInSubtree()[1]->GetFrameTreeNodeId(); + + // 2) Navigate to B. + content::RenderFrameHost* rfh_b = + ui_test_utils::NavigateToURL(browser(), url_b); + + // Ensure that `rfh_a` is in the cache. + EXPECT_FALSE(delete_observer_rfh_a.deleted()); + EXPECT_NE(rfh_a, rfh_b); + EXPECT_EQ(rfh_a->GetLifecycleState(), + content::RenderFrameHost::LifecycleState::kInBackForwardCache); + + std::u16string expected_title = u"foo"; + auto title_watcher = std::make_unique<content::TitleWatcher>( + browser()->tab_strip_model()->GetActiveWebContents(), expected_title); + + constexpr char kScript[] = + R"HTML( + chrome.tabs.executeScript({frameId: %d, + code: "document.title='foo'", + matchAboutBlank: true + }, (e) => { + window.domAutomationController.send(chrome.runtime.lastError ? 'false' + : 'true')}); + )HTML"; + EXPECT_EQ("false", + ExecuteScriptInBackgroundPage( + extension->id(), + base::StringPrintf(kScript, iframe_frame_tree_node_id))); + // Go back to A. + content::WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + web_contents->GetController().GoBack(); + EXPECT_TRUE(WaitForLoadStop(web_contents)); + + // Re-execute the script. + EXPECT_EQ("true", + ExecuteScriptInBackgroundPage( + extension->id(), + base::StringPrintf(kScript, iframe_frame_tree_node_id))); +} + +// Test that running extensions message dispatching via a ScriptContext::ForEach +// for back forward cached pages causes eviction of that RenderFrameHost. +IN_PROC_BROWSER_TEST_F(ExtensionBackForwardCacheBrowserTest, + StorageCallbackEvicts) { + const Extension* extension = extension = + LoadExtension(test_data_dir_.AppendASCII("back_forward_cache") + .AppendASCII("content_script_storage")); + ASSERT_TRUE(extension); + + ASSERT_TRUE(embedded_test_server()->Start()); + GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html")); + GURL url_b(embedded_test_server()->GetURL("b.com", "/title2.html")); + + // 1) Navigate to A. + content::RenderFrameHost* rfh_a = + ui_test_utils::NavigateToURL(browser(), url_a); + content::RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a); + + // 2) Navigate to B. + ui_test_utils::NavigateToURL(browser(), url_b); + + // Expect that `rfh_a` is destroyed as loading page B will causes a storage + // event which is sent to all listeners. Since `rfh_a` is a listener but is in + // the back forward cache it gets evicted. + delete_observer_rfh_a.WaitUntilDeleted(); + + // Validate also that the eviction reason is `kJavascriptExecution` due + // to the extension processing a callback while in the back forward cache. + EXPECT_EQ(1, histogram_tester_.GetBucketCount( + "BackForwardCache.Eviction.Renderer", + blink::mojom::RendererEvictionReason::kJavaScriptExecution)); +} + } // namespace extensions
diff --git a/chrome/browser/extensions/extension_security_exploit_browsertest.cc b/chrome/browser/extensions/extension_security_exploit_browsertest.cc index 0860d8e7..09c08b8 100644 --- a/chrome/browser/extensions/extension_security_exploit_browsertest.cc +++ b/chrome/browser/extensions/extension_security_exploit_browsertest.cc
@@ -353,10 +353,15 @@ // Inject the malformed/mutated IPC and verify that the renderer is terminated // as expected. - // - // TODO(https://crbug.com/1212918: Once the bug is fixed, re-enable the test - // assertion that verifies that `kill_waiter.Wait()` returns - // EMF_INVALID_EXTENSION_ID_FOR_CONTENT_SCRIPT. + content::RenderProcessHost* main_frame_process = + web_contents->GetMainFrame()->GetProcess(); + RenderProcessHostBadIpcMessageWaiter kill_waiter(main_frame_process); + IPC::IpcSecurityTestUtil::PwnMessageReceived( + main_frame_process->GetChannel(), + ExtensionHostMsg_OpenChannelToExtension(source_context, info, + channel_name, port_id)); + EXPECT_EQ(bad_message::EMF_INVALID_EXTENSION_ID_FOR_CONTENT_SCRIPT, + kill_waiter.Wait()); } IN_PROC_BROWSER_TEST_F(OpenChannelToExtensionExploitTest,
diff --git a/chrome/browser/extensions/extension_service_test_with_install.cc b/chrome/browser/extensions/extension_service_test_with_install.cc index 06f2cb3..622db83 100644 --- a/chrome/browser/extensions/extension_service_test_with_install.cc +++ b/chrome/browser/extensions/extension_service_test_with_install.cc
@@ -14,9 +14,7 @@ #include "chrome/browser/profiles/profile.h" #include "content/public/browser/notification_service.h" #include "content/public/test/browser_task_environment.h" -#include "content/public/test/test_utils.h" #include "extensions/browser/extension_creator.h" -#include "extensions/browser/extension_util.h" #include "extensions/browser/notification_types.h" #include "extensions/common/verifier_formats.h" #include "testing/gtest/include/gtest/gtest.h" @@ -342,13 +340,6 @@ ExtensionPrefs* prefs = ExtensionPrefs::Get(profile()); EXPECT_TRUE(prefs->GetInstalledExtensionInfo(id)); - // Make sure RegisterClient calls for storage are finished to avoid flaky - // crashes in QuotaManagerImpl::RegisterClient due to its getting called - // after LazyInitialize. - // TODO(crbug.com/1182630) : Remove this when 1182630 is fixed. - util::GetStoragePartitionForExtensionId(id, profile()); - task_environment()->RunUntilIdle(); - // We make a copy of the extension's id since the extension can be deleted // once it's uninstalled. std::string extension_id = id; @@ -432,11 +423,6 @@ // did so a bunch of stuff fails. Migrate this over. extension_loader.set_ignore_manifest_warnings(true); extension_loader.LoadExtension(crx_path); - - // Make sure RegisterClient calls for storage are finished to avoid flaky - // crashes in QuotaManagerImpl::RegisterClient on test shutdown. - // TODO(crbug.com/1182630) : Remove this when 1182630 is fixed. - base::RunLoop().RunUntilIdle(); } } // namespace extensions
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 3454267..7c09172 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -959,11 +959,6 @@ "expiry_milestone": 92 }, { - "name": "direct-manipulation-stylus", - "owners": [ "lanwei", "input-dev" ], - "expiry_milestone": 76 - }, - { "name": "disable-accelerated-2d-canvas", "owners": [ "fserb" ], "expiry_milestone": -1 @@ -1186,9 +1181,9 @@ "expiry_milestone": 93 }, { - "name": "elastic-overscroll-win", - "owners": [ "arakeri@microsoft.com" ], - "expiry_milestone": 90 + "name": "elastic-overscroll", + "owners": [ "arakeri@microsoft.com", "flackr@chromium.org" ], + "expiry_milestone": 99 }, { "name": "enable-accelerated-video-decode",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 3c06517..82d780c6 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -3667,11 +3667,6 @@ const char kD3D11VideoDecoderDescription[] = "Enables D3D11VideoDecoder for hardware accelerated video decoding."; -const char kElasticOverscrollWinName[] = "Elastic Overscroll for Windows"; -const char kElasticOverscrollWinDescription[] = - "Enables Elastic Overscrolling for Windows on touchscreens and precision " - "touchpads."; - const char kEnableIncognitoShortcutOnDesktopName[] = "Enable Incognito Desktop Shortcut"; const char kEnableIncognitoShortcutOnDesktopDescription[] = @@ -4961,10 +4956,6 @@ "Enables printing interactions with the operating system to be performed " "out-of-process."; -const char kDirectManipulationStylusName[] = "Direct Manipulation Stylus"; -const char kDirectManipulationStylusDescription[] = - "If enabled, Chrome will scroll web pages on stylus drag."; - const char kWebuiFeedbackName[] = "WebUI Feedback"; const char kWebuiFeedbackDescription[] = "If enabled, Chrome will show the Feedback WebUI, as opposed to Chrome " @@ -5130,6 +5121,12 @@ "will be sent to Google."; #endif +#if defined(OS_WIN) || defined(OS_ANDROID) +const char kElasticOverscrollName[] = "Elastic Overscroll"; +const char kElasticOverscrollDescription[] = + "Enables Elastic Overscrolling on touchscreens and precision touchpads."; +#endif // defined(OS_WIN) || defined(OS_ANDROID) + #if defined(OS_WIN) || (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) || \ defined(OS_MAC) const char kUIDebugToolsName[] = "Debugging tools for UI";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 38d59e9f..1e30edbd 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -2106,9 +2106,6 @@ extern const char kD3D11VideoDecoderName[]; extern const char kD3D11VideoDecoderDescription[]; -extern const char kElasticOverscrollWinName[]; -extern const char kElasticOverscrollWinDescription[]; - extern const char kEnableIncognitoShortcutOnDesktopName[]; extern const char kEnableIncognitoShortcutOnDesktopDescription[]; @@ -2894,9 +2891,6 @@ extern const char kEnableOopPrintDriversName[]; extern const char kEnableOopPrintDriversDescription[]; -extern const char kDirectManipulationStylusName[]; -extern const char kDirectManipulationStylusDescription[]; - extern const char kWebuiFeedbackName[]; extern const char kWebuiFeedbackDescription[]; @@ -3011,6 +3005,11 @@ extern const char kSendWebUIJavaScriptErrorReportsDescription[]; #endif +#if defined(OS_WIN) || defined(OS_ANDROID) +extern const char kElasticOverscrollName[]; +extern const char kElasticOverscrollDescription[]; +#endif // defined(OS_WIN) || defined(OS_ANDROID) + #if defined(OS_WIN) || (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) || \ defined(OS_MAC) extern const char kUIDebugToolsName[];
diff --git a/chrome/browser/media/router/chrome_media_router_factory.h b/chrome/browser/media/router/chrome_media_router_factory.h index ee14c57..0bd9664 100644 --- a/chrome/browser/media/router/chrome_media_router_factory.h +++ b/chrome/browser/media/router/chrome_media_router_factory.h
@@ -15,7 +15,7 @@ namespace media_router { -// A version of MediaRouterFactory for Chrome, which refers incongito contexts +// A version of MediaRouterFactory for Chrome, which refers incognito contexts // to their parent Profile. It also adds support for desktop features. class ChromeMediaRouterFactory : public MediaRouterFactory { public:
diff --git a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc index 3fcf3ae..3967a12 100644 --- a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc +++ b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc
@@ -1036,7 +1036,8 @@ return false; break; case NearbyProcessShutdownReason::kCrash: - case NearbyProcessShutdownReason::kMojoPipeDisconnection: + case NearbyProcessShutdownReason::kConnectionsMojoPipeDisconnection: + case NearbyProcessShutdownReason::kDecoderMojoPipeDisconnection: break; }
diff --git a/chrome/browser/nearby_sharing/nearby_sharing_service_impl_unittest.cc b/chrome/browser/nearby_sharing/nearby_sharing_service_impl_unittest.cc index 2ea70bc..d80c66d 100644 --- a/chrome/browser/nearby_sharing/nearby_sharing_service_impl_unittest.cc +++ b/chrome/browser/nearby_sharing/nearby_sharing_service_impl_unittest.cc
@@ -4303,7 +4303,8 @@ break; case NearbyProcessShutdownReason::kCrash: - case NearbyProcessShutdownReason::kMojoPipeDisconnection: + case NearbyProcessShutdownReason::kConnectionsMojoPipeDisconnection: + case NearbyProcessShutdownReason::kDecoderMojoPipeDisconnection: expected_to_restart = is_enabled && recent_shutdown_count <= NearbySharingServiceImpl:: @@ -4326,9 +4327,11 @@ NearbySharingServiceRestartTest, testing::Combine( testing::Bool(), - testing::Values(NearbyProcessShutdownReason::kNormal, - NearbyProcessShutdownReason::kCrash, - NearbyProcessShutdownReason::kMojoPipeDisconnection), + testing::Values( + NearbyProcessShutdownReason::kNormal, + NearbyProcessShutdownReason::kCrash, + NearbyProcessShutdownReason::kConnectionsMojoPipeDisconnection, + NearbyProcessShutdownReason::kDecoderMojoPipeDisconnection), testing::Values(0, NearbySharingServiceImpl:: kMaxRecentNearbyProcessUnexpectedShutdownCount -
diff --git a/chrome/browser/policy/android/BUILD.gn b/chrome/browser/policy/android/BUILD.gn index ffef53d..f49d251 100644 --- a/chrome/browser/policy/android/BUILD.gn +++ b/chrome/browser/policy/android/BUILD.gn
@@ -4,25 +4,49 @@ import("//build/config/android/rules.gni") -_jni_sources = [ - "java/src/org/chromium/chrome/browser/policy/CloudManagementSharedPreferences.java", - "java/src/org/chromium/chrome/browser/policy/PolicyServiceFactory.java", -] +android_library("util_java") { + sources = [ "java/src/org/chromium/chrome/browser/policy/CloudManagementSharedPreferences.java" ] -android_library("java") { deps = [ "//base:base_java", "//chrome/browser/preferences:java", + "//components/policy/android:policy_java", + ] + + annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ] +} + +android_library("java") { + sources = [ + "java/src/org/chromium/chrome/browser/policy/CloudManagementAndroidConnection.java", + "java/src/org/chromium/chrome/browser/policy/PolicyServiceFactory.java", + ] + + deps = [ + "//base:base_java", "//chrome/browser/profiles/android:java", "//components/policy/android:policy_java", "//third_party/androidx:androidx_annotation_annotation_java", ] + + public_deps = [ + ":delegate_java", + ":util_java", + ] + annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ] - sources = _jni_sources +} + +android_library("delegate_java") { + sources = [ "java/src/org/chromium/chrome/browser/policy/CloudManagementAndroidConnectionDelegate.java" ] } generate_jni("jni_headers") { - sources = _jni_sources + sources = [ + "java/src/org/chromium/chrome/browser/policy/CloudManagementAndroidConnection.java", + "java/src/org/chromium/chrome/browser/policy/CloudManagementSharedPreferences.java", + "java/src/org/chromium/chrome/browser/policy/PolicyServiceFactory.java", + ] } android_library("junit") { @@ -30,10 +54,15 @@ bypass_platform_checks = true testonly = true - sources = [ "java/src/org/chromium/chrome/browser/policy/CloudManagementSharedPreferencesTest.java" ] + sources = [ + "java/src/org/chromium/chrome/browser/policy/CloudManagementAndroidConnectionTest.java", + "java/src/org/chromium/chrome/browser/policy/CloudManagementSharedPreferencesTest.java", + ] deps = [ + ":delegate_java", ":java", + ":util_java", "//base:base_junit_test_support", "//chrome/browser/preferences:java", "//third_party/android_deps:robolectric_all_java",
diff --git a/chrome/browser/policy/android/cloud_management_shared_preferences.h b/chrome/browser/policy/android/cloud_management_shared_preferences.h index 9a51436..0219941 100644 --- a/chrome/browser/policy/android/cloud_management_shared_preferences.h +++ b/chrome/browser/policy/android/cloud_management_shared_preferences.h
@@ -12,11 +12,11 @@ namespace policy { namespace android { -// Saves the device management token to Shared Preferences. Ignored if -// |dm_token| is empty. +// Saves the device management token to Shared Preferences. void SaveDmTokenInSharedPreferences(const std::string& dm_token); -// Returns the DM token available from Shared Preferences, or +// Returns the DM token available from Shared Preferences or empty if the +// preference is not set. std::string ReadDmTokenFromSharedPreferences(); } // namespace android
diff --git a/chrome/browser/policy/android/java/src/org/chromium/chrome/browser/policy/CloudManagementAndroidConnection.java b/chrome/browser/policy/android/java/src/org/chromium/chrome/browser/policy/CloudManagementAndroidConnection.java new file mode 100644 index 0000000..0cbe861 --- /dev/null +++ b/chrome/browser/policy/android/java/src/org/chromium/chrome/browser/policy/CloudManagementAndroidConnection.java
@@ -0,0 +1,61 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.policy; + +import androidx.annotation.VisibleForTesting; + +import org.chromium.base.annotations.CalledByNative; + +/** + * Allows access to cloud management functionalities implemented downstream. + */ +public class CloudManagementAndroidConnection { + private static class LazyHolder { + private static final CloudManagementAndroidConnection INSTANCE = + new CloudManagementAndroidConnection(); + } + + /** Returns an instance of this class. */ + @CalledByNative + public static CloudManagementAndroidConnection getInstance() { + return LazyHolder.INSTANCE; + } + + /** Provides access to downstream implementation. */ + private final CloudManagementAndroidConnectionDelegate mDelegate; + + private CloudManagementAndroidConnection() { + mDelegate = new CloudManagementAndroidConnectionDelegate(); + } + + /* Returns the client ID to be used in the DM token generation. Once generated, the ID is saved + * to Shared Preferences so it can be reused. */ + @CalledByNative + public String getClientId() { + // Return the ID saved in Shared Preferences, if available. + String clientId = CloudManagementSharedPreferences.readClientId(); + if (!clientId.isEmpty()) { + return clientId; + } + + // Generate a new ID and save it in Shared Preferences, so it can be reused. + String newClientId = getDelegate().generateClientId(); + CloudManagementSharedPreferences.saveClientId(newClientId); + + return newClientId; + } + + /** Overrides {@link mDelegate} if not null. */ + private static CloudManagementAndroidConnectionDelegate sDelegateForTesting; + + @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) + public static void setDelegateForTesting(CloudManagementAndroidConnectionDelegate delegate) { + sDelegateForTesting = delegate; + } + + private CloudManagementAndroidConnectionDelegate getDelegate() { + return sDelegateForTesting != null ? sDelegateForTesting : mDelegate; + } +}
diff --git a/chrome/browser/policy/android/java/src/org/chromium/chrome/browser/policy/CloudManagementAndroidConnectionDelegate.java b/chrome/browser/policy/android/java/src/org/chromium/chrome/browser/policy/CloudManagementAndroidConnectionDelegate.java new file mode 100644 index 0000000..026c87a --- /dev/null +++ b/chrome/browser/policy/android/java/src/org/chromium/chrome/browser/policy/CloudManagementAndroidConnectionDelegate.java
@@ -0,0 +1,19 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.policy; + +import java.util.UUID; + +/** + * Delegate for cloud management functions implemented downstream for Google Chrome. + */ +public class CloudManagementAndroidConnectionDelegate { + /* Returns the client ID to be used in the DM token generation. By default a random UUID is + * generated for development and testing purposes. Any device that uses randomly generated UUID + * as client id for CBCM might be wiped out from the server without notice. */ + public String generateClientId() { + return UUID.randomUUID().toString(); + } +}
diff --git a/chrome/browser/policy/android/java/src/org/chromium/chrome/browser/policy/CloudManagementAndroidConnectionTest.java b/chrome/browser/policy/android/java/src/org/chromium/chrome/browser/policy/CloudManagementAndroidConnectionTest.java new file mode 100644 index 0000000..3b8e877b --- /dev/null +++ b/chrome/browser/policy/android/java/src/org/chromium/chrome/browser/policy/CloudManagementAndroidConnectionTest.java
@@ -0,0 +1,62 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.policy; + +import androidx.test.filters.SmallTest; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; + +import org.chromium.base.test.BaseRobolectricTestRunner; + +/** + * Unit tests for CloudManagementAndroidConnection. + */ +@RunWith(BaseRobolectricTestRunner.class) +@Config(manifest = Config.NONE) +public final class CloudManagementAndroidConnectionTest { + private static final String CLIENT_ID = "client-id"; + private static final String SAVED_CLIENT_ID = "saved-client-id"; + + /* Simple implementation of {@link CloudManagementAndroidConnection} that overrides {@link + * generateClientIdInternal} for easier testing. */ + private static class FakeCloudManagementAndroidConnectionDelegate + extends CloudManagementAndroidConnectionDelegate { + @Override + public String generateClientId() { + return CLIENT_ID; + } + } + + @Before + public void setUp() { + CloudManagementAndroidConnection.setDelegateForTesting( + new FakeCloudManagementAndroidConnectionDelegate()); + } + + @Test + @SmallTest + public void testGetClientId_Generated() { + Assert.assertEquals(CloudManagementSharedPreferences.readClientId(), ""); + + CloudManagementAndroidConnection connection = + CloudManagementAndroidConnection.getInstance(); + Assert.assertEquals(connection.getClientId(), CLIENT_ID); + Assert.assertEquals(CloudManagementSharedPreferences.readClientId(), CLIENT_ID); + } + + @Test + @SmallTest + public void testGetClientId_ReadFromSharedPreferences() { + CloudManagementSharedPreferences.saveClientId(SAVED_CLIENT_ID); + + CloudManagementAndroidConnection connection = + CloudManagementAndroidConnection.getInstance(); + Assert.assertEquals(connection.getClientId(), SAVED_CLIENT_ID); + } +}
diff --git a/chrome/browser/policy/android/java/src/org/chromium/chrome/browser/policy/CloudManagementSharedPreferences.java b/chrome/browser/policy/android/java/src/org/chromium/chrome/browser/policy/CloudManagementSharedPreferences.java index fbc9067c..75f2a46 100644 --- a/chrome/browser/policy/android/java/src/org/chromium/chrome/browser/policy/CloudManagementSharedPreferences.java +++ b/chrome/browser/policy/android/java/src/org/chromium/chrome/browser/policy/CloudManagementSharedPreferences.java
@@ -34,4 +34,22 @@ return SharedPreferencesManager.getInstance().readString( ChromePreferenceKeys.CLOUD_MANAGEMENT_DM_TOKEN, ""); } + + /** + * Sets the "Cloud management client ID" preference. + * + * @param clientId The ID generated to represent the current browser installation. + */ + public static void saveClientId(String clientId) { + SharedPreferencesManager.getInstance().writeString( + ChromePreferenceKeys.CLOUD_MANAGEMENT_CLIENT_ID, clientId); + } + + /** + * Returns the value of the "Cloud management client ID" preference. + */ + public static String readClientId() { + return SharedPreferencesManager.getInstance().readString( + ChromePreferenceKeys.CLOUD_MANAGEMENT_CLIENT_ID, ""); + } }
diff --git a/chrome/browser/policy/android/java/src/org/chromium/chrome/browser/policy/CloudManagementSharedPreferencesTest.java b/chrome/browser/policy/android/java/src/org/chromium/chrome/browser/policy/CloudManagementSharedPreferencesTest.java index 2495838..571afc0a 100644 --- a/chrome/browser/policy/android/java/src/org/chromium/chrome/browser/policy/CloudManagementSharedPreferencesTest.java +++ b/chrome/browser/policy/android/java/src/org/chromium/chrome/browser/policy/CloudManagementSharedPreferencesTest.java
@@ -22,6 +22,7 @@ @Config(manifest = Config.NONE) public class CloudManagementSharedPreferencesTest { private static final String DM_TOKEN = "fake-dm-token"; + private static final String CLIENT_ID = "fake-client-id"; @Test @SmallTest @@ -41,4 +42,23 @@ ChromePreferenceKeys.CLOUD_MANAGEMENT_DM_TOKEN, DM_TOKEN); Assert.assertEquals(CloudManagementSharedPreferences.readDmToken(), DM_TOKEN); } + + @Test + @SmallTest + public void testSaveClientId() { + CloudManagementSharedPreferences.saveClientId(CLIENT_ID); + Assert.assertEquals(SharedPreferencesManager.getInstance().readString( + ChromePreferenceKeys.CLOUD_MANAGEMENT_CLIENT_ID, ""), + CLIENT_ID); + } + + @Test + @SmallTest + public void testReadClientId() { + Assert.assertEquals(CloudManagementSharedPreferences.readClientId(), ""); + + SharedPreferencesManager.getInstance().writeString( + ChromePreferenceKeys.CLOUD_MANAGEMENT_CLIENT_ID, CLIENT_ID); + Assert.assertEquals(CloudManagementSharedPreferences.readClientId(), CLIENT_ID); + } }
diff --git a/chrome/browser/policy/browser_dm_token_storage_android.cc b/chrome/browser/policy/browser_dm_token_storage_android.cc index 0c22e91..7261783 100644 --- a/chrome/browser/policy/browser_dm_token_storage_android.cc +++ b/chrome/browser/policy/browser_dm_token_storage_android.cc
@@ -6,9 +6,12 @@ #include <string> +#include "base/android/jni_android.h" +#include "base/android/jni_string.h" #include "base/task/task_traits.h" #include "base/task/thread_pool.h" #include "chrome/browser/policy/android/cloud_management_shared_preferences.h" +#include "chrome/browser/policy/android/jni_headers/CloudManagementAndroidConnection_jni.h" #include "components/policy/core/common/policy_pref_names.h" #include "components/prefs/pref_service.h" @@ -29,7 +32,10 @@ BrowserDMTokenStorageAndroid::~BrowserDMTokenStorageAndroid() {} std::string BrowserDMTokenStorageAndroid::InitClientId() { - return std::string(); + JNIEnv* env = base::android::AttachCurrentThread(); + return base::android::ConvertJavaStringToUTF8( + env, Java_CloudManagementAndroidConnection_getClientId( + env, Java_CloudManagementAndroidConnection_getInstance(env))); } std::string BrowserDMTokenStorageAndroid::InitEnrollmentToken() {
diff --git a/chrome/browser/policy/browser_dm_token_storage_android_unittest.cc b/chrome/browser/policy/browser_dm_token_storage_android_unittest.cc index b19dfc9..40cf3ea9 100644 --- a/chrome/browser/policy/browser_dm_token_storage_android_unittest.cc +++ b/chrome/browser/policy/browser_dm_token_storage_android_unittest.cc
@@ -8,6 +8,7 @@ #include "base/location.h" #include "base/run_loop.h" #include "base/task_runner_util.h" +#include "chrome/browser/policy/android/cloud_management_shared_preferences.h" #include "content/public/test/browser_task_environment.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -25,13 +26,18 @@ } // namespace class BrowserDMTokenStorageAndroidTest : public testing::Test { + public: + void TearDown() override { + android::SaveDmTokenInSharedPreferences(std::string()); + } + private: content::BrowserTaskEnvironment task_environment_; }; TEST_F(BrowserDMTokenStorageAndroidTest, InitClientId) { BrowserDMTokenStorageAndroid storage; - EXPECT_THAT(storage.InitClientId(), IsEmpty()); + EXPECT_FALSE(storage.InitClientId().empty()); } TEST_F(BrowserDMTokenStorageAndroidTest, InitEnrollmentToken) {
diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java index af570be..5d919e4 100644 --- a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java +++ b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
@@ -139,6 +139,12 @@ "Chrome.Clipboard.SharedUriTimestamp"; /** + * The ID generated to represent the current browser installation in the DM Server for Cloud + * Management. + */ + public static final String CLOUD_MANAGEMENT_CLIENT_ID = "Chrome.Policy.CloudManagementClientId"; + + /** * The server-side token generated by the Device Management server on browser enrollment for * Cloud Management. */ @@ -990,6 +996,7 @@ CHROME_SURVEY_PROMPT_DISPLAYED_TIMESTAMP.pattern(), CLIPBOARD_SHARED_URI, CLIPBOARD_SHARED_URI_TIMESTAMP, + CLOUD_MANAGEMENT_CLIENT_ID, CLOUD_MANAGEMENT_DM_TOKEN, COMMERCE_SUBSCRIPTIONS_CHROME_MANAGED_TIMESTAMP, CONDITIONAL_TAB_STRIP_CONTINUOUS_DISMISS_COUNTER,
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc index c66bf99..2c0f20c 100644 --- a/chrome/browser/prefs/browser_prefs.cc +++ b/chrome/browser/prefs/browser_prefs.cc
@@ -719,6 +719,13 @@ #endif // BUILDFLAG(IS_CHROMEOS_ASH) registry->RegisterListPref(kSpellCheckBlacklistedDictionaries); + +#if !defined(OS_ANDROID) + registry->RegisterListPref( + prefs::kManagedProfileSerialAllowAllPortsForUrlsDeprecated); + registry->RegisterListPref( + prefs::kManagedProfileSerialAllowUsbDevicesForUrlsDeprecated); +#endif } } // namespace @@ -759,6 +766,9 @@ RegisterScreenshotPrefs(registry); safe_browsing::RegisterLocalStatePrefs(registry); secure_origin_allowlist::RegisterPrefs(registry); +#if !defined(OS_ANDROID) + SerialPolicyAllowedPorts::RegisterPrefs(registry); +#endif sessions::SessionIdGenerator::RegisterPrefs(registry); SSLConfigServiceManager::RegisterPrefs(registry); subresource_filter::IndexedRulesetVersion::RegisterPrefs(registry); @@ -1007,9 +1017,6 @@ registry); security_interstitials::InsecureFormBlockingPage::RegisterProfilePrefs( registry); -#if !defined(OS_ANDROID) - SerialPolicyAllowedPorts::RegisterProfilePrefs(registry); -#endif SessionStartupPref::RegisterProfilePrefs(registry); SharingSyncPreference::RegisterProfilePrefs(registry); site_engagement::SiteEngagementService::RegisterProfilePrefs(registry); @@ -1446,6 +1453,14 @@ // Added 05/2021 profile_prefs->ClearPref(kSpellCheckBlacklistedDictionaries); +#if !defined(OS_ANDROID) + // Added 05/2021 + profile_prefs->ClearPref( + prefs::kManagedProfileSerialAllowAllPortsForUrlsDeprecated); + profile_prefs->ClearPref( + prefs::kManagedProfileSerialAllowUsbDevicesForUrlsDeprecated); +#endif + // Please don't delete the following line. It is used by PRESUBMIT.py. // END_MIGRATE_OBSOLETE_PROFILE_PREFS }
diff --git a/chrome/browser/profiles/profile_keep_alive_types.cc b/chrome/browser/profiles/profile_keep_alive_types.cc index bc6a765d..e9eddc9 100644 --- a/chrome/browser/profiles/profile_keep_alive_types.cc +++ b/chrome/browser/profiles/profile_keep_alive_types.cc
@@ -43,6 +43,8 @@ return out << "kWebAppPermissionDialogWindow"; case ProfileKeepAliveOrigin::kSessionDataDeleter: return out << "kSessionDataDeleter"; + case ProfileKeepAliveOrigin::kWebAppProtocolHandlerLaunch: + return out << "kWebAppProtocolHandlerLaunch"; } NOTREACHED(); return out << static_cast<int>(origin);
diff --git a/chrome/browser/profiles/profile_keep_alive_types.h b/chrome/browser/profiles/profile_keep_alive_types.h index 250071d..bb8b5e57 100644 --- a/chrome/browser/profiles/profile_keep_alive_types.h +++ b/chrome/browser/profiles/profile_keep_alive_types.h
@@ -77,7 +77,10 @@ // Data for Clear on Exit is being deleted. kSessionDataDeleter = 16, - kMaxValue = kSessionDataDeleter, + // Waiting for the provider to be ready in protocol handler web app launch. + kWebAppProtocolHandlerLaunch = 17, + + kMaxValue = kWebAppProtocolHandlerLaunch, }; std::ostream& operator<<(std::ostream& out,
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/item_scan_manager.js b/chrome/browser/resources/chromeos/accessibility/switch_access/item_scan_manager.js index 9b7df388..bc5934a 100644 --- a/chrome/browser/resources/chromeos/accessibility/switch_access/item_scan_manager.js +++ b/chrome/browser/resources/chromeos/accessibility/switch_access/item_scan_manager.js
@@ -117,7 +117,15 @@ this.exitGroup_(); } - this.moveToValidNode(); + chrome.automation.getFocus(focus => { + // First, try to move back to the focused node. + if (focus) { + this.moveTo_(focus); + } else { + // Otherwise, move to anything that's valid based on the above history. + this.moveToValidNode(); + } + }); } /** @override */
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/item_scan_manager_test.js b/chrome/browser/resources/chromeos/accessibility/switch_access/item_scan_manager_test.js index 7c68300a..1c1804b6 100644 --- a/chrome/browser/resources/chromeos/accessibility/switch_access/item_scan_manager_test.js +++ b/chrome/browser/resources/chromeos/accessibility/switch_access/item_scan_manager_test.js
@@ -15,7 +15,8 @@ await importModule( ['BasicNode', 'BasicRootNode'], '/switch_access/nodes/basic_node.js'); await importModule( - 'KeyboardNode', '/switch_access/nodes/keyboard_node.js'); + ['KeyboardNode', 'KeyboardRootNode'], + '/switch_access/nodes/keyboard_node.js'); await importModule('SACache', '/switch_access/cache.js'); await importModule( 'SwitchAccessMenuAction', @@ -357,38 +358,9 @@ function() { const website = `<input type="text" id="input"></input>`; this.runWithLoadedTree(website, async (root) => { - // Set a hook to watch for node changes. - // TODO(anastasi): this should probably be extracted to a helper class - // and after some time delay, print out the current state for debugging. - function untilFocusIs(expected) { - const doesMatch = (expected) => { - const newNode = Navigator.byItem.node_; - const automationNode = newNode.automationNode || {}; - return (!expected.instance || - newNode instanceof expected.instance) && - (!expected.role || expected.role === automationNode.role) && - (!expected.className || - expected.className === automationNode.className); - }; - return new Promise(resolve => { - if (doesMatch(expected)) { - resolve(Navigator.byItem.node_); - return; - } - const original = Navigator.byItem.setNode_.bind(Navigator.byItem); - Navigator.byItem.setNode_ = (node) => { - original(node); - if (doesMatch(expected)) { - Navigator.byItem.setNode_ = original; - resolve(Navigator.byItem.node_); - return; - } - }; - }); - } - // SA initially focuses this node; wait for it first. - await untilFocusIs({className: 'BrowserNonClientFrameViewChromeOS'}); + await this.untilFocusIs( + {className: 'BrowserNonClientFrameViewChromeOS'}); // Move to the text field. Navigator.byItem.moveTo_(this.findNodeById('input')); @@ -398,11 +370,11 @@ 'Current node is not input'); input.performAction(SwitchAccessMenuAction.KEYBOARD); - const keyboard = - await untilFocusIs({role: chrome.automation.RoleType.KEYBOARD}); + const keyboard = await this.untilFocusIs( + {role: chrome.automation.RoleType.KEYBOARD}); keyboard.performAction('select'); - const key = await untilFocusIs({instance: KeyboardNode}); + const key = await this.untilFocusIs({instance: KeyboardNode}); key.performAction('select'); @@ -419,3 +391,50 @@ } }); }); + +TEST_F('SwitchAccessItemScanManagerTest', 'DismissVirtualKeyboard', function() { + const website = `<input type="text" id="input"></input><button>ok</button>`; + this.runWithLoadedTree(website, async (root) => { + // SA initially focuses this node; wait for it first. + await this.untilFocusIs({className: 'BrowserNonClientFrameViewChromeOS'}); + + // Move to the text field. + Navigator.byItem.moveTo_(this.findNodeById('input')); + const input = Navigator.byItem.node_; + assertEquals( + 'input', input.automationNode.htmlAttributes.id, + 'Current node is not input'); + input.performAction(SwitchAccessMenuAction.KEYBOARD); + + const keyboard = + await this.untilFocusIs({role: chrome.automation.RoleType.KEYBOARD}); + keyboard.performAction('select'); + + // Grab the key. + const key = await this.untilFocusIs({instance: KeyboardNode}); + + // Simulate a page focusing the ok button. + const okButton = root.find({attributes: {name: 'ok'}}); + okButton.focus(); + + // Wait for the keyboard to become invisible and the ok button to be focused + // by automation. + await new Promise(resolve => { + okButton.addEventListener(chrome.automation.EventType.FOCUS, resolve); + }); + await new Promise(resolve => { + keyboard.automationNode.addEventListener( + chrome.automation.EventType.STATE_CHANGED, (event) => { + if (event.target.role === chrome.automation.RoleType.KEYBOARD && + event.target.state.invisible) { + resolve(); + } + }); + }); + + // We should end up back on the focused button in SA. + const button = + await this.untilFocusIs({role: chrome.automation.RoleType.BUTTON}); + assertEquals('ok', button.automationNode.name); + }); +});
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/switch_access_e2e_test_base.js b/chrome/browser/resources/chromeos/accessibility/switch_access/switch_access_e2e_test_base.js index 383c6f3f..66c5f5a 100644 --- a/chrome/browser/resources/chromeos/accessibility/switch_access/switch_access_e2e_test_base.js +++ b/chrome/browser/resources/chromeos/accessibility/switch_access/switch_access_e2e_test_base.js
@@ -65,4 +65,53 @@ this.listenUntil( predicate, Navigator.byItem.desktopNode, 'childrenChanged', callback); } + + /** + * @param {!Object} expected + * @return {!Promise} + */ + untilFocusIs(expected) { + const doesMatch = (expected) => { + const newNode = Navigator.byItem.node_; + const automationNode = newNode.automationNode || {}; + return (!expected.instance || newNode instanceof expected.instance) && + (!expected.role || expected.role === automationNode.role) && + (!expected.className || + expected.className === automationNode.className); + }; + + let didResolve = false; + let lastFocusChangeTime = new Date(); + const id = setInterval(() => { + if (didResolve) { + clearInterval(id); + return; + } + + if ((new Date() - lastFocusChangeTime) < 3000) { + return; + } + + console.error( + `\nStill waiting for expectation: ${JSON.stringify(expected)}\n` + + `Focus is: ${Navigator.byItem.node_.debugString()}`); + }, 1000); + return new Promise(resolve => { + if (doesMatch(expected)) { + didResolve = true; + resolve(Navigator.byItem.node_); + return; + } + const original = Navigator.byItem.setNode_.bind(Navigator.byItem); + Navigator.byItem.setNode_ = (node) => { + original(node); + lastFocusChangeTime = new Date(); + if (doesMatch(expected)) { + Navigator.byItem.setNode_ = original; + didResolve = true; + resolve(Navigator.byItem.node_); + } + }; + }); + } };
diff --git a/chrome/browser/resources/new_tab_page/customize_shortcuts.html b/chrome/browser/resources/new_tab_page/customize_shortcuts.html index 4e3c5131..ff881ea 100644 --- a/chrome/browser/resources/new_tab_page/customize_shortcuts.html +++ b/chrome/browser/resources/new_tab_page/customize_shortcuts.html
@@ -129,7 +129,8 @@ .option-title { font-weight: bold; - margin: 8px 0; + margin-bottom: 4px; + margin-top: 12px; } .option-description {
diff --git a/chrome/browser/resources/read_later/side_panel/app.html b/chrome/browser/resources/read_later/side_panel/app.html index 266f321..efcd940 100644 --- a/chrome/browser/resources/read_later/side_panel/app.html +++ b/chrome/browser/resources/read_later/side_panel/app.html
@@ -8,31 +8,56 @@ width: 100%; } - h1 { - font-size: 15px; - font-weight: 500; - line-height: 22px; - margin: 12px 16px 14px 12px; + header { + border-bottom: solid 1px var(--google-grey-refresh-300); + display: flex; + padding-block-start: 4px; + } + + @media (prefers-color-scheme: dark) { + header { + border-bottom: solid 1px var(--google-grey-refresh-700); + } } cr-tabs { --cr-tabs-height: 40px; --cr-tabs-font-size: 13px; + flex: 1; + } + + #closeButtonContainer { + align-items: center; + display: flex; + height: 40px; + justify-content: center; + width: 48px; + } + + #closeButton { + --cr-icon-button-size: 28px; + --cr-icon-button-icon-size: 16px; + margin: 0; } #content { flex: 1; overflow: auto; + padding: 8px 0; } </style> <header> - <h1>Lists</h1> <cr-tabs tab-names="[[getTabNames_(tabs_)]]" selected="{{selectedTab_}}" on-selected-changed="onSelectedTabChanged_"> </cr-tabs> + <div id="closeButtonContainer"> + <cr-icon-button + id="closeButton" iron-icon="cr:close" on-click="onCloseClick_"> + </cr-icon-button> + </div> </header> <div id="content">
diff --git a/chrome/browser/resources/read_later/side_panel/app.js b/chrome/browser/resources/read_later/side_panel/app.js index 2daff34..7a537f5 100644 --- a/chrome/browser/resources/read_later/side_panel/app.js +++ b/chrome/browser/resources/read_later/side_panel/app.js
@@ -15,6 +15,7 @@ import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js'; import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {ReadLaterApiProxy, ReadLaterApiProxyImpl} from '../read_later_api_proxy.js'; /** * Key for localStorage object that refers to the last active tab's ID. @@ -50,6 +51,16 @@ }; } + constructor() { + super(); + + /** + * The side panel is currently hosted within Read Later UI. + * @const @private {!ReadLaterApiProxy} + */ + this.apiProxy_ = ReadLaterApiProxyImpl.getInstance(); + } + connectedCallback() { super.connectedCallback(); const lastActiveTab = window.localStorage[LOCAL_STORAGE_TAB_ID_KEY]; @@ -66,6 +77,11 @@ return Object.values(this.tabs_); } + /** @private */ + onCloseClick_() { + this.apiProxy_.closeUI(); + } + /** * @param {!Event} event * @private
diff --git a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/fake_page_handler.js b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/fake_page_handler.js index 8ad4852..f339920 100644 --- a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/fake_page_handler.js +++ b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/fake_page_handler.js
@@ -105,6 +105,7 @@ hideMoreSettings: false, hidePinToShelf: false, isPreferredApp: false, + windowMode: apps.mojom.WindowMode.kWindow, }; if (optConfig) {
diff --git a/chrome/browser/resources/settings/site_settings/all_sites.js b/chrome/browser/resources/settings/site_settings/all_sites.js index d6aa6c9..98b9cf6 100644 --- a/chrome/browser/resources/settings/site_settings/all_sites.js +++ b/chrome/browser/resources/settings/site_settings/all_sites.js
@@ -221,15 +221,7 @@ * @private */ populateList_() { - /** @type {!Array<ContentSettingsTypes>} */ - const contentTypes = this.getCategoryList(); - // Make sure to include cookies, because All Sites handles data storage + - // cookies as well as regular ContentSettingsTypes. - if (!contentTypes.includes(ContentSettingsTypes.COOKIES)) { - contentTypes.push(ContentSettingsTypes.COOKIES); - } - - this.browserProxy.getAllSites(contentTypes).then((response) => { + this.browserProxy.getAllSites().then((response) => { // Create a new map to make an observable change. const newMap = /** @type {!Map<string, !SiteGroup>} */ (new Map(this.siteGroupMap)); @@ -549,7 +541,7 @@ this.originRepresentation( this.actionMenuModel_.item.origins[0].origin); return loadTimeData.substituteString(this.i18n(messageId), displayName); - } + } }, /** @@ -613,14 +605,13 @@ }, /** - * Resets permission settings for a single origin. + * Resets all permission settings for a single origin. * @param {string} origin * @private */ resetPermissionsForOrigin_: function(origin) { - const contentSettingsTypes = this.getCategoryList(); this.browserProxy.setOriginPermissions( - origin, contentSettingsTypes, ContentSetting.DEFAULT); + origin, null, ContentSetting.DEFAULT); }, /**
diff --git a/chrome/browser/resources/settings/site_settings/site_details.js b/chrome/browser/resources/settings/site_settings/site_details.js index 7bd17b4..7874fba0 100644 --- a/chrome/browser/resources/settings/site_settings/site_details.js +++ b/chrome/browser/resources/settings/site_settings/site_details.js
@@ -150,7 +150,9 @@ this.fetchingForHost_ = this.toUrl(this.origin_).hostname; this.storedData_ = ''; this.websiteUsageProxy_.fetchUsageTotal(this.fetchingForHost_); - this.updatePermissions_(this.getCategoryList()); + this.browserProxy.getCategoryList(this.origin_).then((categoryList) => { + this.updatePermissions_(categoryList, /*hideOthers=*/ true); + }); } }); }, @@ -169,13 +171,12 @@ origin === undefined || origin === '') { return; } - if (!this.getCategoryList().includes(category)) { - return; - } - // Site details currently doesn't support embedded origins, so ignore it - // and just check whether the origins are the same. - this.updatePermissions_([category]); + this.browserProxy.getCategoryList(this.origin_).then((categoryList) => { + if (categoryList.includes(category)) { + this.updatePermissions_([category], /*hideOthers=*/ false); + } + }); }, /** @@ -199,9 +200,11 @@ * |this.origin_|. * @param {!Array<!ContentSettingsTypes>} categoryList The list * of categories to update permissions for. + * @param {boolean} hideOthers If true, permissions for categories not in + * |categoryList| will be hidden. * @private */ - updatePermissions_(categoryList) { + updatePermissions_(categoryList, hideOthers) { const permissionsMap = /** * @type {!Object<!ContentSettingsTypes, @@ -212,6 +215,9 @@ (map, element) => { if (categoryList.includes(element.category)) { map[element.category] = element; + } else if (hideOthers) { + // This will hide any permission not in the category list. + element.site = null; } return map; }, @@ -266,7 +272,7 @@ */ onResetSettings_(e) { this.browserProxy.setOriginPermissions( - this.origin_, this.getCategoryList(), ContentSetting.DEFAULT); + this.origin_, null, ContentSetting.DEFAULT); this.onCloseDialog_(e); },
diff --git a/chrome/browser/resources/settings/site_settings/site_details_permission.html b/chrome/browser/resources/settings/site_settings/site_details_permission.html index 3567e054..26f2632 100644 --- a/chrome/browser/resources/settings/site_settings/site_details_permission.html +++ b/chrome/browser/resources/settings/site_settings/site_details_permission.html
@@ -1,5 +1,5 @@ <style include="settings-shared md-select"></style> - <div id="details" hidden$="[[shouldHideCategory_(category)]]"> + <div id="details" hidden$="[[shouldHideCategory_(site)]]"> <div id="permissionItem" class$="list-item [[permissionInfoStringClass_(site.source, category,
diff --git a/chrome/browser/resources/settings/site_settings/site_details_permission.js b/chrome/browser/resources/settings/site_settings/site_details_permission.js index c29094a..b81cf93 100644 --- a/chrome/browser/resources/settings/site_settings/site_details_permission.js +++ b/chrome/browser/resources/settings/site_settings/site_details_permission.js
@@ -41,7 +41,8 @@ useAutomaticLabel: {type: Boolean, value: false}, /** - * The site that this widget is showing details for. + * The site that this widget is showing details for, or null if this widget + * should be hidden. * @type {RawSiteException} */ site: Object, @@ -67,16 +68,17 @@ this.onDefaultSettingChanged_.bind(this)); }, - shouldHideCategory_(category) { - return !this.getCategoryList().includes(category); - }, - /** - * Updates the drop-down value after |site| has changed. - * @param {!RawSiteException} site The site to display. + * Updates the drop-down value after |site| has changed. If |site| is null, + * this element will hide. + * @param {?RawSiteException} site The site to display. * @private */ siteChanged_(site) { + if (!site) { + return; + } + if (site.source === SiteSettingSource.DEFAULT) { this.defaultSetting_ = site.setting; this.$.permission.value = ContentSetting.DEFAULT; @@ -123,7 +125,7 @@ */ onPermissionSelectionChange_() { this.browserProxy.setOriginPermissions( - this.site.origin, [this.category], this.$.permission.value); + this.site.origin, this.category, this.$.permission.value); }, /** @@ -186,6 +188,14 @@ }, /** + * Returns true if |this| should be hidden. + * @private + */ + shouldHideCategory_() { + return !this.site; + }, + + /** * Returns true if there's a string to display that provides more information * about this permission's setting. Currently, this only gets called when * |this.site| is updated.
diff --git a/chrome/browser/resources/settings/site_settings/site_settings_behavior.js b/chrome/browser/resources/settings/site_settings/site_settings_behavior.js index bfc14bf..6b787bb1 100644 --- a/chrome/browser/resources/settings/site_settings/site_settings_behavior.js +++ b/chrome/browser/resources/settings/site_settings/site_settings_behavior.js
@@ -178,59 +178,6 @@ }; }, - /** - * Returns list of categories for each setting.ContentSettingsTypes that are - * currently enabled. - * @return {!Array<!ContentSettingsTypes>} - */ - getCategoryList() { - if (this.contentTypes_.length === 0) { - for (const typeName in ContentSettingsTypes) { - const contentType = ContentSettingsTypes[typeName]; - // <if expr="not chromeos and not is_win"> - if (contentType === ContentSettingsTypes.PROTECTED_CONTENT) { - continue; - } - // </if> - // Some categories store their data in a custom way. - if (contentType === ContentSettingsTypes.COOKIES || - contentType === ContentSettingsTypes.PROTOCOL_HANDLERS || - contentType === ContentSettingsTypes.ZOOM_LEVELS) { - continue; - } - this.contentTypes_.push(contentType); - } - } - - const addOrRemoveSettingWithFlag = (type, flag) => { - if (loadTimeData.getBoolean(flag)) { - if (!this.contentTypes_.includes(type)) { - this.contentTypes_.push(type); - } - } else { - if (this.contentTypes_.includes(type)) { - this.contentTypes_.splice(this.contentTypes_.indexOf(type), 1); - } - } - }; - // These categories are gated behind flags. - addOrRemoveSettingWithFlag( - ContentSettingsTypes.BLUETOOTH_SCANNING, - 'enableExperimentalWebPlatformFeatures'); - addOrRemoveSettingWithFlag( - ContentSettingsTypes.ADS, 'enableSafeBrowsingSubresourceFilter'); - addOrRemoveSettingWithFlag( - ContentSettingsTypes.PAYMENT_HANDLER, - 'enablePaymentHandlerContentSetting'); - addOrRemoveSettingWithFlag( - ContentSettingsTypes.BLUETOOTH_DEVICES, - 'enableWebBluetoothNewPermissionsBackend'); - addOrRemoveSettingWithFlag( - ContentSettingsTypes.WINDOW_PLACEMENT, - 'enableExperimentalWebPlatformFeatures'); - return this.contentTypes_.slice(0); - }, - }; /** @polymerBehavior */
diff --git a/chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.js b/chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.js index 0d1354e..afbcf6b9 100644 --- a/chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.js +++ b/chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.js
@@ -170,13 +170,20 @@ getDefaultValueForContentType(contentType) {} /** - * Gets a list of sites, grouped by eTLD+1, affected by any of the content - * settings specified by |contentTypes|. - * @param {!Array<!ContentSettingsTypes>} contentTypes A list of - * the content types to retrieve sites for. + * Gets a list of sites, grouped by eTLD+1, affected by any content settings + * that should be visible to the user. * @return {!Promise<!Array<!SiteGroup>>} */ - getAllSites(contentTypes) {} + getAllSites() {} + + /** + * Returns a list of content settings types that are controlled via a standard + * permissions UI and should be made visible to the user. + * @param {!string} origin The associated origin for which categories should + * be shown or hidden. + * @return {!Promise<!Array<string>>} + */ + getCategoryList(origin) {} /** * Get the string which describes the current effective cookie setting. @@ -189,12 +196,10 @@ * numSources different origin/profile (inconigto/regular) pairings. * This includes permissions adjusted by embargo, but excludes any set * via policy. - * @param {!Array<!ContentSettingsTypes>} contentTypes A list of - * the content types to retrieve sites with recently changed settings. * @param {!number} numSources Maximum number of different sources to return * @return {!Promise<!Array<!RecentSitePermissions>>} */ - getRecentSitePermissions(contentTypes, numSources) {} + getRecentSitePermissions(numSources) {} /** * Gets the chooser exceptions for a particular chooser type. @@ -235,14 +240,13 @@ * Resets the permissions for a list of categories for a given origin. This * does not support incognito settings or patterns. * @param {string} origin The origin to reset permissions for. - * @param {!Array<!ContentSettingsTypes>} contentTypes A list of - * categories to set the permission for. Typically this would be a - * single category, but sometimes it is useful to clear any permissions - * set for all categories. + * @param {?ContentSettingsTypes} category The category to set the permission + * for. If null, this applies to all categories. (Sometimes it is useful + * to clear any permissions set for all categories.) * @param {!ContentSetting} blanketSetting The setting to set all * permissions listed in |contentTypes| to. */ - setOriginPermissions(origin, contentTypes, blanketSetting) {} + setOriginPermissions(origin, category, blanketSetting) {} /** * Resets the category permission for a given origin (expressed as primary @@ -413,8 +417,13 @@ } /** @override */ - getAllSites(contentTypes) { - return sendWithPromise('getAllSites', contentTypes); + getAllSites() { + return sendWithPromise('getAllSites'); + } + + /** @override */ + getCategoryList(origin) { + return sendWithPromise('getCategoryList', origin); } /** @override */ @@ -423,9 +432,8 @@ } /** @override */ - getRecentSitePermissions(contentTypes, numSources) { - return sendWithPromise( - 'getRecentSitePermissions', contentTypes, numSources); + getRecentSitePermissions(numSources) { + return sendWithPromise('getRecentSitePermissions', numSources); } /** @override */
diff --git a/chrome/browser/resources/settings/site_settings_page/recent_site_permissions.js b/chrome/browser/resources/settings/site_settings_page/recent_site_permissions.js index 52db429..dc52ba48 100644 --- a/chrome/browser/resources/settings/site_settings_page/recent_site_permissions.js +++ b/chrome/browser/resources/settings/site_settings_page/recent_site_permissions.js
@@ -396,8 +396,7 @@ */ async populateList_() { this.recentSitePermissionsList_ = - await this.browserProxy.getRecentSitePermissions( - this.getCategoryList(), 3); + await this.browserProxy.getRecentSitePermissions(3); }, /**
diff --git a/chrome/browser/resources/welcome/BUILD.gn b/chrome/browser/resources/welcome/BUILD.gn index 7a04bed..6b365d4 100644 --- a/chrome/browser/resources/welcome/BUILD.gn +++ b/chrome/browser/resources/welcome/BUILD.gn
@@ -176,6 +176,7 @@ ] definitions = [ "//tools/typescript/definitions/bookmarks.d.ts", + "//tools/typescript/definitions/chrome_event.d.ts", "//tools/typescript/definitions/chrome_send.d.ts", "//tools/typescript/definitions/metrics_private.d.ts", ]
diff --git a/chrome/browser/safe_browsing/BUILD.gn b/chrome/browser/safe_browsing/BUILD.gn index ddf304b..b6b3584 100644 --- a/chrome/browser/safe_browsing/BUILD.gn +++ b/chrome/browser/safe_browsing/BUILD.gn
@@ -81,6 +81,7 @@ } deps += [ "//chrome/browser/profiles:profile", + "//components/paint_preview/buildflags", "//extensions/browser", ] }
diff --git a/chrome/browser/search/instant_service.cc b/chrome/browser/search/instant_service.cc index 57145ff..3523053 100644 --- a/chrome/browser/search/instant_service.cc +++ b/chrome/browser/search/instant_service.cc
@@ -217,11 +217,10 @@ most_visited_sites_->SetMostVisitedURLsObserver( this, ntp_tiles::kMaxNumMostVisited); most_visited_sites_->EnableCustomLinks(IsCustomLinksEnabled()); - } - most_visited_info_->use_most_visited = !IsCustomLinksEnabled(); - most_visited_info_->is_visible = - pref_service_->GetBoolean(prefs::kNtpShortcutsVisible); + most_visited_info_->use_most_visited = !IsCustomLinksEnabled(); + most_visited_info_->is_visible = most_visited_sites_->IsShortcutsVisible(); + } background_service_ = NtpBackgroundServiceFactory::GetForProfile(profile_); @@ -354,9 +353,7 @@ !search_provider_observer_->is_google()) { return false; } - bool use_most_visited = - !pref_service_->GetBoolean(prefs::kNtpUseMostVisitedTiles); - pref_service_->SetBoolean(prefs::kNtpUseMostVisitedTiles, use_most_visited); + bool use_most_visited = most_visited_sites_->IsCustomLinksEnabled(); most_visited_info_->use_most_visited = use_most_visited; bool was_initialized = most_visited_sites_->IsCustomLinksInitialized(); @@ -393,8 +390,8 @@ !search_provider_observer_->is_google()) { return false; } - bool is_visible = !pref_service_->GetBoolean(prefs::kNtpShortcutsVisible); - pref_service_->SetBoolean(prefs::kNtpShortcutsVisible, is_visible); + bool is_visible = !most_visited_sites_->IsShortcutsVisible(); + most_visited_sites_->SetShortcutsVisible(is_visible); most_visited_info_->is_visible = is_visible; if (do_notify) { @@ -623,7 +620,7 @@ bool InstantService::IsCustomLinksEnabled() { return search_provider_observer_ && search_provider_observer_->is_google() && - !pref_service_->GetBoolean(prefs::kNtpUseMostVisitedTiles); + most_visited_sites_->IsCustomLinksEnabled(); } void InstantService::BuildNtpTheme() { @@ -872,17 +869,15 @@ } std::pair<bool, bool> InstantService::GetCurrentShortcutSettings() { - bool using_most_visited = - pref_service_->GetBoolean(prefs::kNtpUseMostVisitedTiles); - bool is_visible = pref_service_->GetBoolean(prefs::kNtpShortcutsVisible); + bool using_most_visited = !most_visited_sites_->IsCustomLinksEnabled(); + bool is_visible = most_visited_sites_->IsShortcutsVisible(); return std::make_pair(using_most_visited, is_visible); } void InstantService::ResetToDefault() { ResetCustomLinks(); ResetCustomBackgroundNtpTheme(); - pref_service_->SetBoolean(prefs::kNtpUseMostVisitedTiles, false); - pref_service_->SetBoolean(prefs::kNtpShortcutsVisible, true); + ntp_tiles::MostVisitedSites::ResetProfilePrefs(pref_service_); } void InstantService::UpdateCustomBackgroundColorAsync( @@ -978,8 +973,6 @@ user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); registry->RegisterBooleanPref(prefs::kNtpCustomBackgroundLocalToDevice, false); - registry->RegisterBooleanPref(prefs::kNtpUseMostVisitedTiles, false); - registry->RegisterBooleanPref(prefs::kNtpShortcutsVisible, true); } // static
diff --git a/chrome/browser/search/instant_service_unittest.cc b/chrome/browser/search/instant_service_unittest.cc index 452b959..8d2c8b9 100644 --- a/chrome/browser/search/instant_service_unittest.cc +++ b/chrome/browser/search/instant_service_unittest.cc
@@ -112,26 +112,27 @@ } TEST_F(InstantServiceTest, DoesToggleMostVisitedOrCustomLinks) { - sync_preferences::TestingPrefServiceSyncable* pref_service = - profile()->GetTestingPrefService(); SetUserSelectedDefaultSearchProvider("{google:baseURL}"); - ASSERT_FALSE(pref_service->GetBoolean(prefs::kNtpUseMostVisitedTiles)); + ASSERT_FALSE(!most_visited_sites()->IsCustomLinksEnabled()); ASSERT_FALSE(instant_service_->most_visited_info_->use_most_visited); // Enable most visited tiles. EXPECT_TRUE(instant_service_->ToggleMostVisitedOrCustomLinks()); - EXPECT_TRUE(pref_service->GetBoolean(prefs::kNtpUseMostVisitedTiles)); + EXPECT_TRUE(!most_visited_sites()->IsCustomLinksEnabled()); EXPECT_TRUE(instant_service_->most_visited_info_->use_most_visited); // Disable most visited tiles. EXPECT_TRUE(instant_service_->ToggleMostVisitedOrCustomLinks()); - EXPECT_FALSE(pref_service->GetBoolean(prefs::kNtpUseMostVisitedTiles)); + EXPECT_FALSE(!most_visited_sites()->IsCustomLinksEnabled()); EXPECT_FALSE(instant_service_->most_visited_info_->use_most_visited); - // Should do nothing if this is a non-Google NTP. SetUserSelectedDefaultSearchProvider("https://www.search.com"); + EXPECT_FALSE(most_visited_sites()->IsCustomLinksEnabled()); + ASSERT_FALSE(instant_service_->most_visited_info_->use_most_visited); + + // Should do nothing if this is a non-Google NTP. EXPECT_FALSE(instant_service_->ToggleMostVisitedOrCustomLinks()); - EXPECT_FALSE(pref_service->GetBoolean(prefs::kNtpUseMostVisitedTiles)); + EXPECT_FALSE(most_visited_sites()->IsCustomLinksEnabled()); EXPECT_FALSE(instant_service_->most_visited_info_->use_most_visited); } @@ -139,30 +140,28 @@ testing::StrictMock<MockInstantServiceObserver> mock_observer; instant_service_->AddObserver(&mock_observer); - sync_preferences::TestingPrefServiceSyncable* pref_service = - profile()->GetTestingPrefService(); SetUserSelectedDefaultSearchProvider("{google:baseURL}"); - ASSERT_TRUE(pref_service->GetBoolean(prefs::kNtpShortcutsVisible)); + ASSERT_TRUE(most_visited_sites()->IsShortcutsVisible()); ASSERT_TRUE(instant_service_->most_visited_info_->is_visible); // Hide shortcuts. EXPECT_CALL(mock_observer, MostVisitedInfoChanged(testing::_)).Times(0); EXPECT_TRUE(instant_service_->ToggleShortcutsVisibility(false)); - EXPECT_FALSE(pref_service->GetBoolean(prefs::kNtpShortcutsVisible)); + EXPECT_FALSE(most_visited_sites()->IsShortcutsVisible()); EXPECT_FALSE(instant_service_->most_visited_info_->is_visible); task_environment()->RunUntilIdle(); // Show shortcuts, and check that a notification was sent. EXPECT_CALL(mock_observer, MostVisitedInfoChanged(testing::_)).Times(1); EXPECT_TRUE(instant_service_->ToggleShortcutsVisibility(true)); - EXPECT_TRUE(pref_service->GetBoolean(prefs::kNtpShortcutsVisible)); + EXPECT_TRUE(most_visited_sites()->IsShortcutsVisible()); EXPECT_TRUE(instant_service_->most_visited_info_->is_visible); // Should do nothing if this is a non-Google NTP. EXPECT_CALL(mock_observer, MostVisitedInfoChanged(testing::_)).Times(0); SetUserSelectedDefaultSearchProvider("https://www.search.com"); EXPECT_FALSE(instant_service_->ToggleShortcutsVisibility(false)); - EXPECT_TRUE(pref_service->GetBoolean(prefs::kNtpShortcutsVisible)); + EXPECT_TRUE(most_visited_sites()->IsShortcutsVisible()); EXPECT_TRUE(instant_service_->most_visited_info_->is_visible); } @@ -184,19 +183,16 @@ } TEST_F(InstantServiceTest, IsCustomLinksEnabled) { - sync_preferences::TestingPrefServiceSyncable* pref_service = - profile()->GetTestingPrefService(); - // Test that custom links are only enabled when Most Visited is toggled off // and this is a Google NTP. - pref_service->SetBoolean(prefs::kNtpUseMostVisitedTiles, false); + most_visited_sites()->EnableCustomLinks(true); SetUserSelectedDefaultSearchProvider("{google:baseURL}"); EXPECT_TRUE(instant_service_->IsCustomLinksEnabled()); // All other cases should return false. SetUserSelectedDefaultSearchProvider("https://www.search.com"); EXPECT_FALSE(instant_service_->IsCustomLinksEnabled()); - pref_service->SetBoolean(prefs::kNtpUseMostVisitedTiles, true); + most_visited_sites()->EnableCustomLinks(false); EXPECT_FALSE(instant_service_->IsCustomLinksEnabled()); SetUserSelectedDefaultSearchProvider("{google:baseURL}"); EXPECT_FALSE(instant_service_->IsCustomLinksEnabled());
diff --git a/chrome/browser/search/instant_unittest_base.cc b/chrome/browser/search/instant_unittest_base.cc index 18685d2..327ec82 100644 --- a/chrome/browser/search/instant_unittest_base.cc +++ b/chrome/browser/search/instant_unittest_base.cc
@@ -51,6 +51,10 @@ BrowserWithTestWindowTest::TearDown(); } +ntp_tiles::MostVisitedSites* InstantUnitTestBase::most_visited_sites() { + return instant_service_->most_visited_sites_.get(); +} + void InstantUnitTestBase::SetUserSelectedDefaultSearchProvider( const std::string& base_url) { TemplateURLData data;
diff --git a/chrome/browser/search/instant_unittest_base.h b/chrome/browser/search/instant_unittest_base.h index b1644fe..048da34c 100644 --- a/chrome/browser/search/instant_unittest_base.h +++ b/chrome/browser/search/instant_unittest_base.h
@@ -11,6 +11,7 @@ #include "build/build_config.h" #include "chrome/browser/search/instant_service.h" #include "chrome/test/base/browser_with_test_window_test.h" +#include "components/ntp_tiles/most_visited_sites.h" #include "components/search_engines/template_url_service.h" // This class provides an extension on top of BrowserWithTestWindowTest, and @@ -24,6 +25,8 @@ void SetUp() override; void TearDown() override; + ntp_tiles::MostVisitedSites* most_visited_sites(); + // Adds and sets the default search provider using the base_url. // The base_url should have the http[s]:// prefix and a trailing / after the // TLD.
diff --git a/chrome/browser/serial/serial_chooser_context.cc b/chrome/browser/serial/serial_chooser_context.cc index 2f7c5f5..a3109c3 100644 --- a/chrome/browser/serial/serial_chooser_context.cc +++ b/chrome/browser/serial/serial_chooser_context.cc
@@ -13,10 +13,12 @@ #include "base/strings/utf_string_conversions.h" #include "base/values.h" #include "build/build_config.h" +#include "chrome/browser/browser_process.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/serial/serial_blocklist.h" #include "chrome/browser/serial/serial_chooser_histograms.h" +#include "chrome/browser/serial/serial_policy_allowed_ports.h" #include "chrome/grit/generated_resources.h" #include "content/public/browser/device_service.h" #include "mojo/public/cpp/bindings/pending_remote.h" @@ -148,8 +150,7 @@ ContentSettingsType::SERIAL_GUARD, ContentSettingsType::SERIAL_CHOOSER_DATA, HostContentSettingsMapFactory::GetForProfile(profile)), - is_incognito_(profile->IsOffTheRecord()), - policy_(profile->GetPrefs()) {} + is_incognito_(profile->IsOffTheRecord()) {} SerialChooserContext::~SerialChooserContext() = default; @@ -206,7 +207,8 @@ } } - for (const auto& entry : policy_.usb_device_policy()) { + auto* policy = g_browser_process->serial_policy_allowed_ports(); + for (const auto& entry : policy->usb_device_policy()) { if (!base::Contains(entry.second, origin)) { continue; } @@ -218,7 +220,7 @@ is_incognito_)); } - for (const auto& entry : policy_.usb_vendor_policy()) { + for (const auto& entry : policy->usb_vendor_policy()) { if (!base::Contains(entry.second, origin)) { continue; } @@ -229,7 +231,7 @@ is_incognito_)); } - if (base::Contains(policy_.all_ports_policy(), origin)) { + if (base::Contains(policy->all_ports_policy(), origin)) { base::Value object(base::Value::Type::DICTIONARY); object.SetStringKey( kPortNameKey, @@ -263,7 +265,8 @@ } } - for (const auto& entry : policy_.usb_device_policy()) { + auto* policy = g_browser_process->serial_policy_allowed_ports(); + for (const auto& entry : policy->usb_device_policy()) { base::Value object = VendorAndProductIdsToValue(entry.first.first, entry.first.second); @@ -274,7 +277,7 @@ } } - for (const auto& entry : policy_.usb_vendor_policy()) { + for (const auto& entry : policy->usb_vendor_policy()) { base::Value object = VendorIdToValue(entry.first); for (const auto& origin : entry.second) { @@ -288,7 +291,7 @@ object.SetStringKey( kPortNameKey, l10n_util::GetStringUTF16(IDS_SERIAL_POLICY_DESCRIPTION_FOR_ANY_PORT)); - for (const auto& origin : policy_.all_ports_policy()) { + for (const auto& origin : policy->all_ports_policy()) { objects.push_back(std::make_unique<ObjectPermissionContextBase::Object>( origin, object.Clone(), content_settings::SETTING_SOURCE_POLICY, is_incognito_)); @@ -339,7 +342,8 @@ return false; } - if (policy_.HasPortPermission(origin, port)) { + if (g_browser_process->serial_policy_allowed_ports()->HasPortPermission( + origin, port)) { return true; }
diff --git a/chrome/browser/serial/serial_chooser_context.h b/chrome/browser/serial/serial_chooser_context.h index 4db8839..93d1b50f 100644 --- a/chrome/browser/serial/serial_chooser_context.h +++ b/chrome/browser/serial/serial_chooser_context.h
@@ -14,7 +14,6 @@ #include "base/memory/weak_ptr.h" #include "base/unguessable_token.h" -#include "chrome/browser/serial/serial_policy_allowed_ports.h" #include "components/permissions/object_permission_context_base.h" #include "content/public/browser/serial_delegate.h" #include "mojo/public/cpp/bindings/pending_remote.h" @@ -83,8 +82,6 @@ const bool is_incognito_; - SerialPolicyAllowedPorts policy_; - // Tracks the set of ports to which an origin has access to. std::map<url::Origin, std::set<base::UnguessableToken>> ephemeral_ports_;
diff --git a/chrome/browser/serial/serial_chooser_context_unittest.cc b/chrome/browser/serial/serial_chooser_context_unittest.cc index 18a8bd9..419b24e 100644 --- a/chrome/browser/serial/serial_chooser_context_unittest.cc +++ b/chrome/browser/serial/serial_chooser_context_unittest.cc
@@ -15,6 +15,8 @@ #include "chrome/browser/serial/serial_chooser_context_factory.h" #include "chrome/browser/serial/serial_chooser_histograms.h" #include "chrome/common/pref_names.h" +#include "chrome/test/base/scoped_testing_local_state.h" +#include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile.h" #include "components/content_settings/core/browser/host_content_settings_map.h" #include "components/content_settings/core/common/pref_names.h" @@ -71,7 +73,15 @@ class SerialChooserContextTest : public testing::Test { public: - SerialChooserContextTest() { + SerialChooserContextTest() + : testing_local_state_(TestingBrowserProcess::GetGlobal()) {} + ~SerialChooserContextTest() override = default; + + // Disallow copy and assignment. + SerialChooserContextTest(SerialChooserContextTest&) = delete; + SerialChooserContextTest& operator=(SerialChooserContextTest&) = delete; + + void SetUp() override { mojo::PendingRemote<device::mojom::SerialPortManager> port_manager; port_manager_.AddReceiver(port_manager.InitWithNewPipeAndPassReceiver()); @@ -84,12 +94,6 @@ context_->FlushPortManagerConnectionForTesting(); } - ~SerialChooserContextTest() override = default; - - // Disallow copy and assignment. - SerialChooserContextTest(SerialChooserContextTest&) = delete; - SerialChooserContextTest& operator=(SerialChooserContextTest&) = delete; - void TearDown() override { // Because SerialBlocklist is a singleton it must be cleared after tests run // to prevent leakage between tests. @@ -110,6 +114,7 @@ device::FakeSerialPortManager& port_manager() { return port_manager_; } TestingProfile* profile() { return &profile_; } + TestingPrefServiceSimple* local_state() { return testing_local_state_.Get(); } SerialChooserContext* context() { return context_; } permissions::MockPermissionObserver& permission_observer() { return permission_observer_; @@ -120,6 +125,7 @@ content::BrowserTaskEnvironment task_environment_; base::test::ScopedFeatureList feature_list_; device::FakeSerialPortManager port_manager_; + ScopedTestingLocalState testing_local_state_; TestingProfile profile_; SerialChooserContext* context_; permissions::MockPermissionObserver permission_observer_; @@ -388,9 +394,10 @@ port->token = base::UnguessableToken::Create(); context()->GrantPortPermission(origin, *port); - auto* prefs = profile()->GetTestingPrefService(); - prefs->SetManagedPref(prefs::kManagedDefaultSerialGuardSetting, - std::make_unique<base::Value>(CONTENT_SETTING_BLOCK)); + auto* profile_prefs = profile()->GetTestingPrefService(); + profile_prefs->SetManagedPref( + prefs::kManagedDefaultSerialGuardSetting, + std::make_unique<base::Value>(CONTENT_SETTING_BLOCK)); EXPECT_FALSE(context()->CanRequestObjectPermission(origin)); EXPECT_FALSE(context()->HasPortPermission(origin, *port)); @@ -413,11 +420,12 @@ context()->GrantPortPermission(kBarOrigin, *port); // Set the default to "ask" so that the policy being tested overrides it. - auto* prefs = profile()->GetTestingPrefService(); - prefs->SetManagedPref(prefs::kManagedDefaultSerialGuardSetting, - std::make_unique<base::Value>(CONTENT_SETTING_BLOCK)); - prefs->SetManagedPref(prefs::kManagedSerialAskForUrls, - ReadJson(R"([ "https://foo.origin" ])")); + auto* profile_prefs = profile()->GetTestingPrefService(); + profile_prefs->SetManagedPref( + prefs::kManagedDefaultSerialGuardSetting, + std::make_unique<base::Value>(CONTENT_SETTING_BLOCK)); + profile_prefs->SetManagedPref(prefs::kManagedSerialAskForUrls, + ReadJson(R"([ "https://foo.origin" ])")); EXPECT_TRUE(context()->CanRequestObjectPermission(kFooOrigin)); EXPECT_TRUE(context()->HasPortPermission(kFooOrigin, *port)); @@ -444,9 +452,9 @@ context()->GrantPortPermission(kFooOrigin, *port); context()->GrantPortPermission(kBarOrigin, *port); - auto* prefs = profile()->GetTestingPrefService(); - prefs->SetManagedPref(prefs::kManagedSerialBlockedForUrls, - ReadJson(R"([ "https://foo.origin" ])")); + auto* profile_prefs = profile()->GetTestingPrefService(); + profile_prefs->SetManagedPref(prefs::kManagedSerialBlockedForUrls, + ReadJson(R"([ "https://foo.origin" ])")); EXPECT_FALSE(context()->CanRequestObjectPermission(kFooOrigin)); EXPECT_FALSE(context()->HasPortPermission(kFooOrigin, *port)); @@ -468,11 +476,10 @@ const auto kFooOrigin = url::Origin::Create(GURL("https://foo.origin")); const auto kBarOrigin = url::Origin::Create(GURL("https://bar.origin")); - auto* prefs = profile()->GetTestingPrefService(); - prefs->SetManagedPref(prefs::kManagedSerialAllowAllPortsForUrls, - ReadJson(R"([ "https://foo.origin" ])")); - prefs->SetManagedPref(prefs::kManagedSerialAllowUsbDevicesForUrls, - ReadJson(R"([ + local_state()->SetManagedPref(prefs::kManagedSerialAllowAllPortsForUrls, + ReadJson(R"([ "https://foo.origin" ])")); + local_state()->SetManagedPref(prefs::kManagedSerialAllowUsbDevicesForUrls, + ReadJson(R"([ { "devices": [{ "vendor_id": 6353, "product_id": 19985 }], "urls": [ "https://bar.origin" ] @@ -507,7 +514,7 @@ EXPECT_FALSE(context()->HasPortPermission(kBarOrigin, *usb_port2)); auto foo_objects = context()->GetGrantedObjects(kFooOrigin); - EXPECT_EQ(1u, foo_objects.size()); + ASSERT_EQ(1u, foo_objects.size()); const auto& foo_object = foo_objects.front(); EXPECT_EQ(kFooOrigin.GetURL(), foo_object->origin); EXPECT_EQ(u"Any serial port", @@ -516,7 +523,7 @@ EXPECT_FALSE(foo_object->incognito); auto bar_objects = context()->GetGrantedObjects(kBarOrigin); - EXPECT_EQ(1u, bar_objects.size()); + ASSERT_EQ(1u, bar_objects.size()); const auto& bar_object = bar_objects.front(); EXPECT_EQ(kBarOrigin.GetURL(), bar_object->origin); EXPECT_EQ(u"Nexus One", context()->GetObjectDisplayName(bar_object->value)); @@ -548,9 +555,8 @@ const auto kFooOrigin = url::Origin::Create(GURL("https://foo.origin")); const auto kBarOrigin = url::Origin::Create(GURL("https://bar.origin")); - auto* prefs = profile()->GetTestingPrefService(); - prefs->SetManagedPref(prefs::kManagedSerialAllowUsbDevicesForUrls, - ReadJson(R"([ + local_state()->SetManagedPref(prefs::kManagedSerialAllowUsbDevicesForUrls, + ReadJson(R"([ { "devices": [{ "vendor_id": 6353 }], "urls": [ "https://google.com" ] @@ -599,11 +605,12 @@ const auto kFooOrigin = url::Origin::Create(GURL("https://foo.origin")); const auto kBarOrigin = url::Origin::Create(GURL("https://bar.origin")); - auto* prefs = profile()->GetTestingPrefService(); - prefs->SetManagedPref(prefs::kManagedDefaultSerialGuardSetting, - std::make_unique<base::Value>(CONTENT_SETTING_BLOCK)); - prefs->SetManagedPref(prefs::kManagedSerialAllowAllPortsForUrls, - ReadJson(R"([ "https://foo.origin" ])")); + auto* profile_prefs = profile()->GetTestingPrefService(); + profile_prefs->SetManagedPref( + prefs::kManagedDefaultSerialGuardSetting, + std::make_unique<base::Value>(CONTENT_SETTING_BLOCK)); + local_state()->SetManagedPref(prefs::kManagedSerialAllowAllPortsForUrls, + ReadJson(R"([ "https://foo.origin" ])")); auto port = device::mojom::SerialPortInfo::New(); port->token = base::UnguessableToken::Create(); @@ -618,12 +625,12 @@ const auto kFooOrigin = url::Origin::Create(GURL("https://foo.origin")); const auto kBarOrigin = url::Origin::Create(GURL("https://bar.origin")); - auto* prefs = profile()->GetTestingPrefService(); - prefs->SetManagedPref( + auto* profile_prefs = profile()->GetTestingPrefService(); + profile_prefs->SetManagedPref( prefs::kManagedSerialBlockedForUrls, ReadJson(R"([ "https://foo.origin", "https://bar.origin" ])")); - prefs->SetManagedPref(prefs::kManagedSerialAllowAllPortsForUrls, - ReadJson(R"([ "https://foo.origin" ])")); + local_state()->SetManagedPref(prefs::kManagedSerialAllowAllPortsForUrls, + ReadJson(R"([ "https://foo.origin" ])")); auto port = device::mojom::SerialPortInfo::New(); port->token = base::UnguessableToken::Create(); @@ -667,9 +674,8 @@ TEST_F(SerialChooserContextTest, BlocklistOverridesPolicy) { const auto origin = url::Origin::Create(GURL("https://google.com")); - auto* prefs = profile()->GetTestingPrefService(); - prefs->SetManagedPref(prefs::kManagedSerialAllowUsbDevicesForUrls, - ReadJson(R"([ + local_state()->SetManagedPref(prefs::kManagedSerialAllowUsbDevicesForUrls, + ReadJson(R"([ { "devices": [{ "vendor_id": 6353, "product_id": 22768 }], "urls": [ "https://google.com" ]
diff --git a/chrome/browser/serial/serial_policy_allowed_ports.cc b/chrome/browser/serial/serial_policy_allowed_ports.cc index f2677ac0..f5c1213 100644 --- a/chrome/browser/serial/serial_policy_allowed_ports.cc +++ b/chrome/browser/serial/serial_policy_allowed_ports.cc
@@ -47,8 +47,7 @@ SerialPolicyAllowedPorts::~SerialPolicyAllowedPorts() = default; // static -void SerialPolicyAllowedPorts::RegisterProfilePrefs( - user_prefs::PrefRegistrySyncable* registry) { +void SerialPolicyAllowedPorts::RegisterPrefs(PrefRegistrySimple* registry) { registry->RegisterListPref(prefs::kManagedSerialAllowAllPortsForUrls); registry->RegisterListPref(prefs::kManagedSerialAllowUsbDevicesForUrls); }
diff --git a/chrome/browser/serial/serial_policy_allowed_ports.h b/chrome/browser/serial/serial_policy_allowed_ports.h index 46bbe8b..f7caea5 100644 --- a/chrome/browser/serial/serial_policy_allowed_ports.h +++ b/chrome/browser/serial/serial_policy_allowed_ports.h
@@ -17,10 +17,7 @@ } // namespace mojom } // namespace device -namespace user_prefs { -class PrefRegistrySyncable; -} - +class PrefRegistrySimple; class PrefService; // This class is used to maintain and interpret the SerialAllowForUrls and @@ -35,7 +32,7 @@ SerialPolicyAllowedPorts& operator=(SerialPolicyAllowedPorts& other) = delete; ~SerialPolicyAllowedPorts(); - static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); + static void RegisterPrefs(PrefRegistrySimple* registry); // Checks if |origin| is allowed to use the port with |port_info|. bool HasPortPermission(const url::Origin& origin,
diff --git a/chrome/browser/serial/serial_policy_allowed_ports_unittest.cc b/chrome/browser/serial/serial_policy_allowed_ports_unittest.cc index 966bd0c..c47266a 100644 --- a/chrome/browser/serial/serial_policy_allowed_ports_unittest.cc +++ b/chrome/browser/serial/serial_policy_allowed_ports_unittest.cc
@@ -6,9 +6,9 @@ #include "base/containers/contains.h" #include "base/json/json_reader.h" +#include "chrome/browser/prefs/browser_prefs.h" #include "chrome/common/pref_names.h" -#include "chrome/test/base/testing_profile.h" -#include "components/prefs/pref_service.h" +#include "components/prefs/testing_pref_service.h" #include "content/public/test/browser_task_environment.h" #include "services/device/public/mojom/serial.mojom.h" #include "testing/gmock/include/gmock/gmock.h" @@ -48,21 +48,23 @@ class SerialPolicyAllowedPortsTest : public testing::Test { public: - SerialPolicyAllowedPortsTest() = default; + SerialPolicyAllowedPortsTest() { + RegisterLocalState(local_state_.registry()); + } + ~SerialPolicyAllowedPortsTest() override = default; void SetAllowAllPortsForUrlsPrefValue(const base::Value& value) { - profile_.GetPrefs()->Set(prefs::kManagedSerialAllowAllPortsForUrls, value); + local_state_.Set(prefs::kManagedSerialAllowAllPortsForUrls, value); } void SetAllowUsbDevicesForUrlsPrefValue(const base::Value& value) { - profile_.GetPrefs()->Set(prefs::kManagedSerialAllowUsbDevicesForUrls, - value); + local_state_.Set(prefs::kManagedSerialAllowUsbDevicesForUrls, value); } void InitializePolicy() { EXPECT_FALSE(policy_); - policy_ = std::make_unique<SerialPolicyAllowedPorts>(profile_.GetPrefs()); + policy_ = std::make_unique<SerialPolicyAllowedPorts>(&local_state_); } protected: @@ -70,7 +72,7 @@ private: content::BrowserTaskEnvironment task_environment_; - TestingProfile profile_; + TestingPrefServiceSimple local_state_; std::unique_ptr<SerialPolicyAllowedPorts> policy_; };
diff --git a/chrome/browser/sessions/session_restore.cc b/chrome/browser/sessions/session_restore.cc index 524417b8..e5fcb05 100644 --- a/chrome/browser/sessions/session_restore.cc +++ b/chrome/browser/sessions/session_restore.cc
@@ -17,6 +17,7 @@ #include "base/callback.h" #include "base/callback_helpers.h" #include "base/command_line.h" +#include "base/containers/flat_map.h" #include "base/debug/alias.h" #include "base/feature_list.h" #include "base/location.h" @@ -222,10 +223,15 @@ (*i)->user_title, (*i)->window_id.id()); browsers.push_back(browser); + // A foreign session window will not contain tab groups, however an + // instance is still required for RestoreTabsToBrowser. + base::flat_map<tab_groups::TabGroupId, tab_groups::TabGroupId> + new_group_ids; + // Restore and show the browser. const int initial_tab_count = 0; - RestoreTabsToBrowser(*(*i), browser, initial_tab_count, - &created_contents); + RestoreTabsToBrowser(*(*i), browser, initial_tab_count, &created_contents, + &new_group_ids); NotifySessionServiceOfRestoredTabs(browser, initial_tab_count); } @@ -573,7 +579,10 @@ // For the cases that users have more than one desk, a window is restored // to its parent desk, which can be non-active desk, and left invisible // but unminimized. - RestoreTabsToBrowser(*(*i), browser, initial_tab_count, created_contents); + base::flat_map<tab_groups::TabGroupId, tab_groups::TabGroupId> + new_group_ids; + RestoreTabsToBrowser(*(*i), browser, initial_tab_count, created_contents, + &new_group_ids); (*tab_count) += (static_cast<int>(browser->tab_strip_model()->count()) - initial_tab_count); #if !BUILDFLAG(IS_CHROMEOS_ASH) @@ -586,7 +595,7 @@ TabGroupModel* group_model = browser->tab_strip_model()->group_model(); for (auto& session_tab_group : (*i)->tab_groups) { TabGroup* model_tab_group = - group_model->GetTabGroup(session_tab_group->id); + group_model->GetTabGroup(new_group_ids.at(session_tab_group->id)); DCHECK(model_tab_group); model_tab_group->SetVisualData(session_tab_group->visual_data); } @@ -661,10 +670,13 @@ // tabs but pinned tabs will be pushed in front. // If there are no existing tabs, the tab at |window.selected_tab_index| will // be selected. Otherwise, the tab selection will remain untouched. - void RestoreTabsToBrowser(const sessions::SessionWindow& window, - Browser* browser, - int initial_tab_count, - std::vector<RestoredTab>* created_contents) { + void RestoreTabsToBrowser( + const sessions::SessionWindow& window, + Browser* browser, + int initial_tab_count, + std::vector<RestoredTab>* created_contents, + base::flat_map<tab_groups::TabGroupId, tab_groups::TabGroupId>* + new_group_ids) { DVLOG(1) << "RestoreTabsToBrowser " << window.tabs.size(); // TODO(https://crbug.com/1032348): Change to DCHECK once we understand // why some browsers don't have an active tab on startup. @@ -710,8 +722,8 @@ // the existing ones. E.g. this happens in Win8 Metro where we merge // windows or when launching a hosted app from the app launcher. int tab_index = i + initial_tab_count; - RestoreTab(tab, browser, created_contents, tab_index, is_selected_tab, - last_active_time); + RestoreTab(tab, browser, created_contents, new_group_ids, tab_index, + is_selected_tab, last_active_time); } } @@ -723,6 +735,8 @@ void RestoreTab(const sessions::SessionTab& tab, Browser* browser, std::vector<RestoredTab>* created_contents, + base::flat_map<tab_groups::TabGroupId, + tab_groups::TabGroupId>* new_group_ids, const int tab_index, bool is_selected_tab, base::TimeTicks last_active_time) { @@ -746,17 +760,29 @@ ->RecreateSessionStorage(tab.session_storage_persistent_id); } + // Relabel group IDs to prevent duplicating groups. See crbug.com/1202102. + absl::optional<tab_groups::TabGroupId> new_group; + if (tab.group) { + auto it = new_group_ids->find(*tab.group); + if (it == new_group_ids->end()) { + it = new_group_ids + ->emplace(*tab.group, tab_groups::TabGroupId::GenerateNew()) + .first; + } + new_group = it->second; + } + // Apply the stored group. WebContents* web_contents = chrome::AddRestoredTab( browser, tab.navigations, tab_index, selected_index, - tab.extension_app_id, tab.group, is_selected_tab, tab.pinned, + tab.extension_app_id, new_group, is_selected_tab, tab.pinned, last_active_time, session_storage_namespace.get(), tab.user_agent_override, true /* from_session_restore */); DCHECK(web_contents); RestoredTab restored_tab(web_contents, is_selected_tab, tab.extension_app_id.empty(), tab.pinned, - tab.group); + new_group); created_contents->push_back(restored_tab); // If this isn't the selected tab, there's nothing else to do.
diff --git a/chrome/browser/sessions/session_restore_browsertest.cc b/chrome/browser/sessions/session_restore_browsertest.cc index ae500328..ca910ec 100644 --- a/chrome/browser/sessions/session_restore_browsertest.cc +++ b/chrome/browser/sessions/session_restore_browsertest.cc
@@ -1039,7 +1039,8 @@ Browser* new_browser = QuitBrowserAndRestore(browser(), kNumTabs); ASSERT_EQ(kNumTabs, new_browser->tab_strip_model()->count()); - EXPECT_EQ(groups, GetTabGroups(new_browser->tab_strip_model())); + ASSERT_NO_FATAL_FAILURE( + CheckTabGrouping(new_browser->tab_strip_model(), group_spec)); } IN_PROC_BROWSER_TEST_P(SessionRestoreTabGroupsTest, GroupMetadataRestored) { @@ -1070,11 +1071,19 @@ TabStripModel* const new_tsm = new_browser->tab_strip_model(); ASSERT_EQ(5, new_tsm->count()); + const absl::optional<tab_groups::TabGroupId> new_group1 = + new_tsm->GetTabGroupForTab(0); + const absl::optional<tab_groups::TabGroupId> new_group2 = + new_tsm->GetTabGroupForTab(2); + + ASSERT_TRUE(new_group1); + ASSERT_TRUE(new_group2); + // Check that the restored visual data is the same. const tab_groups::TabGroupVisualData* const group1_restored_data = - new_tsm->group_model()->GetTabGroup(group1)->visual_data(); + new_tsm->group_model()->GetTabGroup(*new_group1)->visual_data(); const tab_groups::TabGroupVisualData* const group2_restored_data = - new_tsm->group_model()->GetTabGroup(group2)->visual_data(); + new_tsm->group_model()->GetTabGroup(*new_group2)->visual_data(); EXPECT_EQ(group1_data.title(), group1_restored_data->title()); EXPECT_EQ(group1_data.color(), group1_restored_data->color()); @@ -1084,6 +1093,37 @@ EXPECT_EQ(group2_data.is_collapsed(), group2_restored_data->is_collapsed()); } +IN_PROC_BROWSER_TEST_P(SessionRestoreTabGroupsTest, + TabGroupIDsRelabeledOnRestore) { + constexpr int kNumTabs = 3; + const std::array<absl::optional<int>, kNumTabs> group_spec = {0, 0, 1}; + + // Open |kNumTabs| tabs. + ui_test_utils::NavigateToURL(browser(), GetUrl1()); + for (int i = 1; i < kNumTabs; ++i) { + ui_test_utils::NavigateToURLWithDisposition( + browser(), GetUrl1(), WindowOpenDisposition::NEW_FOREGROUND_TAB, + ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP); + } + ASSERT_EQ(kNumTabs, browser()->tab_strip_model()->count()); + + CreateTabGroups(browser()->tab_strip_model(), group_spec); + ASSERT_NO_FATAL_FAILURE( + CheckTabGrouping(browser()->tab_strip_model(), group_spec)); + const auto orig_groups = GetTabGroups(browser()->tab_strip_model()); + + Browser* const new_browser = QuitBrowserAndRestore(browser(), 5); + TabStripModel* const new_tsm = new_browser->tab_strip_model(); + ASSERT_EQ(kNumTabs, new_tsm->count()); + ASSERT_NO_FATAL_FAILURE(CheckTabGrouping(new_tsm, group_spec)); + const auto new_groups = GetTabGroups(new_tsm); + + for (int i = 0; i < kNumTabs; ++i) { + SCOPED_TRACE(i); + EXPECT_NE(orig_groups[i], new_groups[i]); + } +} + INSTANTIATE_TEST_SUITE_P(WithAndWithoutReset, SessionRestoreTabGroupsTest, testing::Values(false, true));
diff --git a/chrome/browser/sessions/tab_restore_browsertest.cc b/chrome/browser/sessions/tab_restore_browsertest.cc index afb4fa5a..79612b4c 100644 --- a/chrome/browser/sessions/tab_restore_browsertest.cc +++ b/chrome/browser/sessions/tab_restore_browsertest.cc
@@ -1418,20 +1418,23 @@ TabGroupModel* restored_group_model = restored_window->tab_strip_model()->group_model(); ASSERT_EQ(tab_count, restored_window->tab_strip_model()->count()); + auto restored_group1 = + restored_window->tab_strip_model()->GetTabGroupForTab(tab_count - 3); + ASSERT_TRUE(restored_group1); EXPECT_EQ( - absl::make_optional(group1), - restored_window->tab_strip_model()->GetTabGroupForTab(tab_count - 3)); - EXPECT_EQ( - absl::make_optional(group1), + restored_window->tab_strip_model()->GetTabGroupForTab(tab_count - 3), restored_window->tab_strip_model()->GetTabGroupForTab(tab_count - 2)); - EXPECT_EQ( - absl::make_optional(group2), - restored_window->tab_strip_model()->GetTabGroupForTab(tab_count - 1)); + auto restored_group2 = + restored_window->tab_strip_model()->GetTabGroupForTab(tab_count - 1); + ASSERT_TRUE(restored_group2); + EXPECT_NE(restored_group2, restored_group1); - EXPECT_EQ(group1_data, - *restored_group_model->GetTabGroup(group1)->visual_data()); - EXPECT_EQ(group2_data, - *restored_group_model->GetTabGroup(group2)->visual_data()); + EXPECT_EQ( + group1_data, + *restored_group_model->GetTabGroup(*restored_group1)->visual_data()); + EXPECT_EQ( + group2_data, + *restored_group_model->GetTabGroup(*restored_group2)->visual_data()); } // Ensure a tab is not restored between tabs of another group. @@ -1781,3 +1784,47 @@ EXPECT_EQ(initial_origin, new_popup->GetMainFrame()->GetLastCommittedOrigin()); } + +// Ensures group IDs are regenerated for restored windows so that we don't split +// the same group between multiple windows. See https://crbug.com/1202102. This +// test is temporary until a more comprehensive fix is implemented. +IN_PROC_BROWSER_TEST_F(TabRestoreTest, RestoredWindowHasNewGroupIds) { + sessions::TabRestoreService* service = + TabRestoreServiceFactory::GetForProfile(browser()->profile()); + + AddSomeTabs(browser(), 2); + ASSERT_EQ(3, browser()->tab_strip_model()->count()); + + // Create a new browser from which to restore the first. + ui_test_utils::NavigateToURLWithDisposition( + browser(), GURL(chrome::kChromeUINewTabURL), + WindowOpenDisposition::NEW_WINDOW, + ui_test_utils::BROWSER_TEST_WAIT_FOR_BROWSER); + ASSERT_EQ(2u, active_browser_list_->size()); + Browser* second_browser = GetBrowser(1); + ASSERT_NE(browser(), second_browser); + + auto original_group = browser()->tab_strip_model()->AddToNewGroup({1, 2}); + CloseBrowserSynchronously(browser()); + ASSERT_EQ(1u, active_browser_list_->size()); + + // We should have a restore entry for the window. + const sessions::TabRestoreService::Entries& entries = service->entries(); + ASSERT_GE(entries.size(), 1u); + ASSERT_EQ(entries.front()->type, sessions::TabRestoreService::WINDOW); + + // Restore the window. + std::vector<sessions::LiveTab*> restored_window_tabs = + service->RestoreEntryById(second_browser->live_tab_context(), + entries.front()->id, + WindowOpenDisposition::NEW_FOREGROUND_TAB); + ASSERT_EQ(2u, active_browser_list_->size()); + ASSERT_EQ(3u, restored_window_tabs.size()); + Browser* third_browser = GetBrowser(1); + ASSERT_NE(second_browser, third_browser); + ASSERT_EQ(3, third_browser->tab_strip_model()->count()); + + // The group ID should be new. + EXPECT_NE(original_group, + third_browser->tab_strip_model()->GetTabGroupForTab(1)); +}
diff --git a/chrome/browser/sharing/sharing_ui_controller.cc b/chrome/browser/sharing/sharing_ui_controller.cc index 95513ee..e9561eb 100644 --- a/chrome/browser/sharing/sharing_ui_controller.cc +++ b/chrome/browser/sharing/sharing_ui_controller.cc
@@ -23,6 +23,13 @@ namespace { +// In some cases (e.g. SmsRemoteFetcher), we show a success icon after the +// message is received instead of after sending it out. The icon will be removed +// be removed after |kShowSuccessIconDuration| seconds. +// Note that the success icon should be able to persist across navigations. +static constexpr base::TimeDelta kShowSuccessIconDuration = + base::TimeDelta::FromSeconds(8); + BrowserWindow* GetWindowFromWebContents(content::WebContents* web_contents) { Browser* browser = chrome::FindBrowserWithWebContents(web_contents); return browser ? browser->window() : nullptr; @@ -168,16 +175,39 @@ return data; } +bool SharingUiController::ShouldShowLoadingIcon() const { + return true; +} + +int SharingUiController::GetIconLabelId() const { + return ShouldShowLoadingIcon() ? IDS_BROWSER_SHARING_OMNIBOX_SENDING_LABEL + : IDS_BROWSER_SHARING_OMNIBOX_SENT_LABEL; +} + +void SharingUiController::ShowSuccessIcon() { + last_dialog_id_++; + is_loading_ = true; + UpdateIcon(); + // For newly added dialog in |OnResponse|, we remove it with a post task. + base::SequencedTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, + base::BindOnce(&SharingUiController::HideSuccessIcon, + weak_ptr_factory_.GetWeakPtr(), last_dialog_id_), + kShowSuccessIconDuration); +} + base::OnceClosure SharingUiController::SendMessageToDevice( const syncer::DeviceInfo& device, absl::optional<base::TimeDelta> response_timeout, chrome_browser_sharing::SharingMessage sharing_message, absl::optional<SharingMessageSender::ResponseCallback> custom_callback) { - last_dialog_id_++; - is_loading_ = true; send_result_ = SharingSendMessageResult::kSuccessful; target_device_name_ = device.client_name(); - UpdateIcon(); + if (ShouldShowLoadingIcon()) { + last_dialog_id_++; + is_loading_ = true; + UpdateIcon(); + } SharingMessageSender::ResponseCallback response_callback = base::BindOnce( &SharingUiController::OnResponse, weak_ptr_factory_.GetWeakPtr(), @@ -238,8 +268,18 @@ if (dialog_id != last_dialog_id_) return; - is_loading_ = false; send_result_ = result; + if (ShouldShowLoadingIcon()) { + is_loading_ = false; + UpdateIcon(); + } +} + +void SharingUiController::HideSuccessIcon(int dialog_id) { + if (dialog_id != last_dialog_id_) + return; + + is_loading_ = false; UpdateIcon(); }
diff --git a/chrome/browser/sharing/sharing_ui_controller.h b/chrome/browser/sharing/sharing_ui_controller.h index eef3a67..4c9eb0d 100644 --- a/chrome/browser/sharing/sharing_ui_controller.h +++ b/chrome/browser/sharing/sharing_ui_controller.h
@@ -54,6 +54,9 @@ virtual sync_pb::SharingSpecificFields::EnabledFeatures GetRequiredFeature() const = 0; virtual const gfx::VectorIcon& GetVectorIcon() const = 0; + // If true, shows a loading icon on omnibox when sending out the message. + virtual bool ShouldShowLoadingIcon() const; + int GetIconLabelId() const; virtual std::u16string GetTextForTooltipAndAccessibleName() const = 0; // Get the name of the feature to be used as a prefix for the metric name. virtual SharingFeatureName GetFeatureMetricsPrefix() const = 0; @@ -100,6 +103,8 @@ virtual void DoUpdateApps(UpdateAppsCallback callback) = 0; // Prepares a new dialog data. virtual SharingDialogData CreateDialogData(SharingDialogType dialog_type); + // Shows a successful icon upon |AckReceived|. + void ShowSuccessIcon(); // Shows an icon in the omnibox which will be removed when receiving a // response or when cancelling the request by calling the returned callback. @@ -132,6 +137,8 @@ const absl::optional<url::Origin>& initiating_origin, std::vector<SharingApp> apps); + void HideSuccessIcon(int dialog_id); + SharingDialog* dialog_ = nullptr; content::WebContents* web_contents_ = nullptr; SharingService* sharing_service_ = nullptr;
diff --git a/chrome/browser/sharing/sms/sms_remote_fetcher_ui_controller.cc b/chrome/browser/sharing/sms/sms_remote_fetcher_ui_controller.cc index ee95456..0ac13e4 100644 --- a/chrome/browser/sharing/sms/sms_remote_fetcher_ui_controller.cc +++ b/chrome/browser/sharing/sms/sms_remote_fetcher_ui_controller.cc
@@ -65,6 +65,10 @@ return kSmartphoneIcon; } +bool SmsRemoteFetcherUiController::ShouldShowLoadingIcon() const { + return false; +} + std::u16string SmsRemoteFetcherUiController::GetTextForTooltipAndAccessibleName() const { return l10n_util::GetStringFUTF16(IDS_OMNIBOX_TOOLTIP_SMS_REMOTE_FETCHER, @@ -86,6 +90,7 @@ std::move(callback).Run(absl::nullopt, absl::nullopt, absl::nullopt); return; } + ShowSuccessIcon(); DCHECK(response); DCHECK(response->has_sms_fetch_response());
diff --git a/chrome/browser/sharing/sms/sms_remote_fetcher_ui_controller.h b/chrome/browser/sharing/sms/sms_remote_fetcher_ui_controller.h index 4572a0f..974eea2 100644 --- a/chrome/browser/sharing/sms/sms_remote_fetcher_ui_controller.h +++ b/chrome/browser/sharing/sms/sms_remote_fetcher_ui_controller.h
@@ -52,6 +52,7 @@ void OnAppChosen(const SharingApp& app) override; std::u16string GetContentType() const override; const gfx::VectorIcon& GetVectorIcon() const override; + bool ShouldShowLoadingIcon() const override; std::u16string GetTextForTooltipAndAccessibleName() const override; SharingFeatureName GetFeatureMetricsPrefix() const override;
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index e6a92900..8683625 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -3510,6 +3510,13 @@ } } + if (is_win || is_mac || is_linux) { + sources += [ + "startup/web_app_protocol_handling_startup_utils.cc", + "startup/web_app_protocol_handling_startup_utils.h", + ] + } + if (is_win || is_mac || (is_linux && !is_chromeos_lacros)) { sources += [ "startup/web_app_url_handling_startup_utils.cc",
diff --git a/chrome/browser/ui/android/passwords/manual_filling_view_android.cc b/chrome/browser/ui/android/passwords/manual_filling_view_android.cc index b5316b44..95483ad0 100644 --- a/chrome/browser/ui/android/passwords/manual_filling_view_android.cc +++ b/chrome/browser/ui/android/passwords/manual_filling_view_android.cc
@@ -94,6 +94,14 @@ } } +void ManualFillingViewAndroid::ShowAccessorySheetTab( + const autofill::AccessoryTabType& tab_type) { + if (auto obj = GetOrCreateJavaObject()) { + Java_ManualFillingComponentBridge_showAccessorySheetTab( + base::android::AttachCurrentThread(), obj, static_cast<int>(tab_type)); + } +} + void ManualFillingViewAndroid::OnAutomaticGenerationStatusChanged( bool available) { if (!available && java_object_internal_.is_null())
diff --git a/chrome/browser/ui/android/passwords/manual_filling_view_android.h b/chrome/browser/ui/android/passwords/manual_filling_view_android.h index 2f7ed0cc..f475659 100644 --- a/chrome/browser/ui/android/passwords/manual_filling_view_android.h +++ b/chrome/browser/ui/android/passwords/manual_filling_view_android.h
@@ -39,6 +39,8 @@ void SwapSheetWithKeyboard() override; void ShowWhenKeyboardIsVisible() override; void Hide() override; + void ShowAccessorySheetTab( + const autofill::AccessoryTabType& tab_type) override; // Called from Java via JNI: void OnFaviconRequested(
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_ar.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_ar.xtb index 09d0c2f..af27ec3 100644 --- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_ar.xtb +++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_ar.xtb
@@ -631,7 +631,7 @@ <translation id="510275257476243843">يتبقى ساعة واحدة</translation> <translation id="5118713593561876160">الاهتمامات</translation> <translation id="5123685120097942451">علامة تبويب "التصفُّح المتخفي"</translation> -<translation id="5127805178023152808">المزامنة غير مفعّلة</translation> +<translation id="5127805178023152808">المزامنة متوقفة.</translation> <translation id="5132942445612118989">مزامنة كلمات المرور والسجلّ والمزيد على جميع الأجهزة</translation> <translation id="5136035049889637840">تسوُّق منتجات مشابهة <ph name="BEGIN_NEW" />جديد<ph name="END_NEW" /></translation> <translation id="5139940364318403933">التعرّف على كيفية استخدام Google Drive</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_en-GB.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_en-GB.xtb index e37c7e8..53973ebe 100644 --- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_en-GB.xtb +++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_en-GB.xtb
@@ -138,7 +138,7 @@ <translation id="1960290143419248813">Chrome updates are no longer supported for this version of Android</translation> <translation id="1963976881984600709">Standard protection</translation> <translation id="1966710179511230534">Please update your sign-in details.</translation> -<translation id="1973912524893600642">Keep data</translation> +<translation id="1973912524893600642">Keep Data</translation> <translation id="1974060860693918893">Advanced</translation> <translation id="1984417487208496350">No protection (not recommended)</translation> <translation id="1984705450038014246">Sync your Chrome data</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_gu.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_gu.xtb index 87de01a..f09d9f4 100644 --- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_gu.xtb +++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_gu.xtb
@@ -684,6 +684,7 @@ <translation id="545042621069398927">તમારા ડાઉનલોડની ગતિ વધારી રહ્યાં છીએ.</translation> <translation id="5454166040603940656"><ph name="PROVIDER" /> સાથે</translation> <translation id="5456381639095306749">પૃષ્ઠ ડાઉનલોડ કરો</translation> +<translation id="5458366071038729214">તમે જે સાઇટ ફૉલો કરશો, તે અહીં દેખાશે</translation> <translation id="548278423535722844">નકશા અૅપ્લિકેશનમાં ખોલો</translation> <translation id="5483197086164197190">Chrome પર નૅવિગેટ કરો</translation> <translation id="5487521232677179737">ડેટા સાફ કરો</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_hy.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_hy.xtb index 023b38f..bb787fb 100644 --- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_hy.xtb +++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_hy.xtb
@@ -494,7 +494,7 @@ <translation id="4242533952199664413">Բացել կարգավորումները</translation> <translation id="4248098802131000011">Պաշտպանեք ձեր գաղտնաբառերը տվյալների արտահոսքից և անվտանգության հետ կապված այլ խնդիրներից</translation> <translation id="4250229828105606438">Սքրինշոթ</translation> -<translation id="4256782883801055595">Բաց կոդով ծրագրերի արտոնագրեր</translation> +<translation id="4256782883801055595">Բաց կոդով ծրագրերի լիցենզիաներ</translation> <translation id="4263656433980196874">Օգնականի միջոցով ձայնային որոնման միջերեսը բացվում է ամբողջ բարձրությամբ</translation> <translation id="4269820728363426813">Պատճենել հղման հասցեն</translation> <translation id="4290281343757112331">Ներբեռնե՞լ ավելի ուշ</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_ne.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_ne.xtb index 06d722b..d3e2571 100644 --- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_ne.xtb +++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_ne.xtb
@@ -682,6 +682,7 @@ <translation id="545042621069398927">तपाईंको डाउनलोडको गति बढाउँदै।</translation> <translation id="5454166040603940656"><ph name="PROVIDER" /> सँग</translation> <translation id="5456381639095306749">पृष्ठ डाउनलोड गर्नुहोस्</translation> +<translation id="5458366071038729214">तपाईं आफूले फलो गरेका साइटहरू यहाँ भेट्टाउनु हुने छ</translation> <translation id="548278423535722844">नक्सा एपमा खोल्नुहोस्</translation> <translation id="5483197086164197190">Chrome नेभिगेट गर्ने तरिका</translation> <translation id="5487521232677179737">डेटा मेटाउनुहोस्</translation>
diff --git a/chrome/browser/ui/ash/shelf/app_service/exo_app_type_resolver.cc b/chrome/browser/ui/ash/shelf/app_service/exo_app_type_resolver.cc index c56cf01..89de627c 100644 --- a/chrome/browser/ui/ash/shelf/app_service/exo_app_type_resolver.cc +++ b/chrome/browser/ui/ash/shelf/app_service/exo_app_type_resolver.cc
@@ -47,13 +47,26 @@ } auto task_id = arc::GetTaskIdFromWindowAppId(params.app_id); - if (!task_id.has_value()) + auto session_id = arc::GetSessionIdFromWindowAppId(params.app_id); + + // If neither |task_id| nor |session_id| are valid, this is not an ARC window. + if (!task_id.has_value() && !session_id.has_value()) return; out_properties_container.SetProperty(aura::client::kAppType, static_cast<int>(ash::AppType::ARC_APP)); - out_properties_container.SetProperty(full_restore::kWindowIdKey, *task_id); - int32_t restore_window_id = full_restore::GetArcRestoreWindowId(*task_id); + + if (task_id.has_value()) + out_properties_container.SetProperty(full_restore::kWindowIdKey, *task_id); + + int32_t restore_window_id = 0; + if (task_id.has_value()) { + restore_window_id = full_restore::GetArcRestoreWindowIdForTaskId(*task_id); + } else { + restore_window_id = + full_restore::GetArcRestoreWindowIdForSessionId(*session_id); + } + out_properties_container.SetProperty(full_restore::kRestoreWindowIdKey, restore_window_id);
diff --git a/chrome/browser/ui/autofill/payments/autofill_snackbar_controller_impl.cc b/chrome/browser/ui/autofill/payments/autofill_snackbar_controller_impl.cc index 031ff27..07c7c97 100644 --- a/chrome/browser/ui/autofill/payments/autofill_snackbar_controller_impl.cc +++ b/chrome/browser/ui/autofill/payments/autofill_snackbar_controller_impl.cc
@@ -6,6 +6,8 @@ #include <string> #include "base/macros.h" #include "build/build_config.h" +#include "chrome/browser/autofill/manual_filling_controller.h" +#include "chrome/browser/autofill/manual_filling_controller_impl.h" #include "chrome/browser/ui/android/autofill/snackbar/autofill_snackbar_view_android.h" #include "components/strings/grit/components_strings.h" #include "ui/base/l10n/l10n_util.h" @@ -40,7 +42,9 @@ } void AutofillSnackbarControllerImpl::OnActionClicked() { - // TODO(crbug.com/1196021): Trigger manual fallback and log the action. + ManualFillingControllerImpl::GetOrCreate(web_contents_) + ->ShowAccessorySheetTab(autofill::AccessoryTabType::CREDIT_CARDS); + // TODO(crbug.com/1196021): Log the action. } void AutofillSnackbarControllerImpl::OnDismissed() {
diff --git a/chrome/browser/ui/cookie_controls/cookie_controls_service.cc b/chrome/browser/ui/cookie_controls/cookie_controls_service.cc index 58d97240..35e4b2c 100644 --- a/chrome/browser/ui/cookie_controls/cookie_controls_service.cc +++ b/chrome/browser/ui/cookie_controls/cookie_controls_service.cc
@@ -32,8 +32,8 @@ CookieControlsService::~CookieControlsService() = default; void CookieControlsService::Init() { - incongito_cookie_settings_ = CookieSettingsFactory::GetForProfile(profile_); - cookie_observations_.AddObservation(incongito_cookie_settings_.get()); + incognito_cookie_settings_ = CookieSettingsFactory::GetForProfile(profile_); + cookie_observations_.AddObservation(incognito_cookie_settings_.get()); regular_cookie_settings_ = CookieSettingsFactory::GetForProfile(profile_->GetOriginalProfile()); cookie_observations_.AddObservation(regular_cookie_settings_.get()); @@ -84,7 +84,7 @@ } bool CookieControlsService::GetToggleCheckedValue() { - return incongito_cookie_settings_->ShouldBlockThirdPartyCookies(); + return incognito_cookie_settings_->ShouldBlockThirdPartyCookies(); } void CookieControlsService::OnThirdPartyCookieBlockingChanged(
diff --git a/chrome/browser/ui/cookie_controls/cookie_controls_service.h b/chrome/browser/ui/cookie_controls/cookie_controls_service.h index e4d1b4c..119b6c7a 100644 --- a/chrome/browser/ui/cookie_controls/cookie_controls_service.h +++ b/chrome/browser/ui/cookie_controls/cookie_controls_service.h
@@ -64,7 +64,7 @@ Profile* profile_; std::unique_ptr<policy::PolicyChangeRegistrar> policy_registrar_; - scoped_refptr<content_settings::CookieSettings> incongito_cookie_settings_; + scoped_refptr<content_settings::CookieSettings> incognito_cookie_settings_; scoped_refptr<content_settings::CookieSettings> regular_cookie_settings_; base::ScopedMultiSourceObservation<content_settings::CookieSettings, content_settings::CookieSettings::Observer>
diff --git a/chrome/browser/ui/global_media_controls/media_notification_service_unittest.cc b/chrome/browser/ui/global_media_controls/media_notification_service_unittest.cc index d3bea20a..38d97ee 100644 --- a/chrome/browser/ui/global_media_controls/media_notification_service_unittest.cc +++ b/chrome/browser/ui/global_media_controls/media_notification_service_unittest.cc
@@ -288,9 +288,7 @@ // Now, close the tab. The session may have been destroyed with // |SimulateFocusLost()| above. - auto item_itr = sessions().find(id.ToString()); - if (item_itr != sessions().end()) - item_itr->second.WebContentsDestroyed(); + service_->media_session_notification_producer_->OnRequestIdReleased(id); } void SimulatePlaybackStateChanged(const base::UnguessableToken& id,
diff --git a/chrome/browser/ui/global_media_controls/media_session_notification_producer.cc b/chrome/browser/ui/global_media_controls/media_session_notification_producer.cc index b85e3ce..8a797a2 100644 --- a/chrome/browser/ui/global_media_controls/media_session_notification_producer.cc +++ b/chrome/browser/ui/global_media_controls/media_session_notification_producer.cc
@@ -91,10 +91,10 @@ std::unique_ptr<media_message_center::MediaSessionNotificationItem> item, content::WebContents* web_contents, mojo::Remote<media_session::mojom::MediaController> controller) - : content::WebContentsObserver(web_contents), - owner_(owner), + : owner_(owner), id_(id), item_(std::move(item)), + web_contents_(web_contents), presentation_manager_(GetPresentationManager(web_contents)) { DCHECK(owner_); DCHECK(item_); @@ -124,13 +124,6 @@ GlobalMediaControlsDismissReason::kMediaSessionStopped)); } -void MediaSessionNotificationProducer::Session::WebContentsDestroyed() { - // If the WebContents is destroyed, then we should just remove the item - // instead of freezing it. - set_dismiss_reason(GlobalMediaControlsDismissReason::kTabClosed); - owner_->RemoveItem(id_); -} - void MediaSessionNotificationProducer::Session::MediaSessionInfoChanged( media_session::mojom::MediaSessionInfoPtr session_info) { is_playing_ = @@ -191,6 +184,11 @@ } } +void MediaSessionNotificationProducer::Session::OnRequestIdReleased() { + // The request ID is released when the tab is closed. + set_dismiss_reason(GlobalMediaControlsDismissReason::kTabClosed); +} + void MediaSessionNotificationProducer::Session::SetController( mojo::Remote<media_session::mojom::MediaController> controller) { if (controller.is_bound()) { @@ -429,6 +427,18 @@ service_->OnNotificationChanged(); } +void MediaSessionNotificationProducer::OnRequestIdReleased( + const base::UnguessableToken& request_id) { + const std::string id = request_id.ToString(); + auto it = sessions_.find(id); + if (it == sessions_.end()) + return; + + // When the tab is closed, just remove the item instead of freezing it. + it->second.OnRequestIdReleased(); + RemoveItem(id); +} + void MediaSessionNotificationProducer::OnContainerClicked( const std::string& id) { auto it = sessions_.find(id);
diff --git a/chrome/browser/ui/global_media_controls/media_session_notification_producer.h b/chrome/browser/ui/global_media_controls/media_session_notification_producer.h index 99d374a3..12185ca2 100644 --- a/chrome/browser/ui/global_media_controls/media_session_notification_producer.h +++ b/chrome/browser/ui/global_media_controls/media_session_notification_producer.h
@@ -54,6 +54,7 @@ media_session::mojom::AudioFocusRequestStatePtr session) override; void OnFocusLost( media_session::mojom::AudioFocusRequestStatePtr session) override; + void OnRequestIdReleased(const base::UnguessableToken& request_id) override; // MediaNotificationContainerObserver implementation. void OnContainerClicked(const std::string& id) override; @@ -106,8 +107,7 @@ friend class MediaToolbarButtonControllerTest; class Session - : public content::WebContentsObserver, - public media_session::mojom::MediaControllerObserver, + : public media_session::mojom::MediaControllerObserver, public media_router::WebContentsPresentationManager::Observer { public: Session(MediaSessionNotificationProducer* owner, @@ -120,9 +120,6 @@ Session& operator=(const Session&) = delete; ~Session() override; - // content::WebContentsObserver: - void WebContentsDestroyed() override; - // media_session::mojom::MediaControllerObserver: void MediaSessionInfoChanged( media_session::mojom::MediaSessionInfoPtr session_info) override; @@ -141,6 +138,10 @@ void OnMediaRoutesChanged( const std::vector<media_router::MediaRoute>& routes) override; + // Called when the request ID associated with this session is released (i.e. + // when the tab is closed). + void OnRequestIdReleased(); + media_message_center::MediaSessionNotificationItem* item() { return item_.get(); } @@ -169,6 +170,8 @@ RegisterIsAudioDeviceSwitchingSupportedCallback( base::RepeatingCallback<void(bool)> callback); + content::WebContents* web_contents() const { return web_contents_; } + void SetPresentationManagerForTesting( base::WeakPtr<media_router::WebContentsPresentationManager> presentation_manager); @@ -219,6 +222,8 @@ // Used to request audio output be routed to a different device. mojo::Remote<media_session::mojom::MediaController> controller_; + content::WebContents* const web_contents_; + base::WeakPtr<media_router::WebContentsPresentationManager> presentation_manager_; };
diff --git a/chrome/browser/ui/page_info/page_info_unittest.cc b/chrome/browser/ui/page_info/page_info_unittest.cc index f3fba4c..bd57a15 100644 --- a/chrome/browser/ui/page_info/page_info_unittest.cc +++ b/chrome/browser/ui/page_info/page_info_unittest.cc
@@ -28,6 +28,8 @@ #include "chrome/browser/usb/usb_chooser_context_factory.h" #include "chrome/common/chrome_features.h" #include "chrome/test/base/chrome_render_view_host_test_harness.h" +#include "chrome/test/base/scoped_testing_local_state.h" +#include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile.h" #include "components/content_settings/core/browser/host_content_settings_map.h" #include "components/content_settings/core/common/content_settings.h" @@ -124,7 +126,9 @@ class PageInfoTest : public ChromeRenderViewHostTestHarness { public: - PageInfoTest() { SetURL("http://www.example.com"); } + PageInfoTest() : testing_local_state_(TestingBrowserProcess::GetGlobal()) { + SetURL("http://www.example.com"); + } ~PageInfoTest() override {} @@ -265,6 +269,7 @@ security_state::VisibleSecurityState visible_security_state_; private: + ScopedTestingLocalState testing_local_state_; std::unique_ptr<PageInfo> page_info_; std::unique_ptr<MockPageInfoUI> mock_ui_;
diff --git a/chrome/browser/ui/startup/startup_browser_creator.cc b/chrome/browser/ui/startup/startup_browser_creator.cc index 1b49179..0d4fc22 100644 --- a/chrome/browser/ui/startup/startup_browser_creator.cc +++ b/chrome/browser/ui/startup/startup_browser_creator.cc
@@ -63,8 +63,6 @@ #include "chrome/browser/ui/startup/startup_browser_creator_impl.h" #include "chrome/browser/ui/ui_features.h" #include "chrome/browser/ui/web_applications/web_app_ui_manager_impl.h" -#include "chrome/browser/web_applications/components/os_integration_manager.h" -#include "chrome/browser/web_applications/components/web_app_provider_base.h" #include "chrome/common/buildflags.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_features.h" @@ -129,9 +127,7 @@ #endif #if defined(OS_WIN) || defined(OS_MAC) || defined(OS_LINUX) -#include "chrome/browser/ui/browser_dialogs.h" -#include "chrome/browser/web_applications/components/web_app_id.h" -#include "third_party/blink/public/common/custom_handlers/protocol_handler_utils.h" +#include "chrome/browser/ui/startup/web_app_protocol_handling_startup_utils.h" #endif #if defined(OS_WIN) || defined(OS_MAC) || \ @@ -401,86 +397,6 @@ StartupBrowserCreatorImpl::MaybeToggleFullscreen(browser); } -#if defined(OS_WIN) || defined(OS_MAC) || defined(OS_LINUX) -// Tries to launch the web app from a protocol handler url. Checks if the passed -// in url is a potential protocol url, if it is, check the protocol handler -// registry for an entry. If there is an entry, then check if we need approval -// from the user to launch this web app. If we didn't have approval from a -// previous session, launch the permission dialog to ask for approval. If we did -// get permission in the past, directly launch the web app with the translated -// url. Returns true if the command line references a valid app and also -// contains a protocol url that is specifically registered by the app. -// `launch_mode_recorder` is used if and only if this function returns true. -bool MaybeLaunchProtocolHandlerWebApp( - const base::CommandLine& command_line, - const base::FilePath& cur_dir, - Profile* profile, - std::unique_ptr<LaunchModeRecorder> launch_mode_recorder) { - std::string app_id = command_line.GetSwitchValueASCII(switches::kAppId); - // We must have a kAppId switch arg in the command line to launch. - if (app_id.empty()) - return false; - - GURL protocol_url; - base::CommandLine::StringVector args = command_line.GetArgs(); - for (const auto& arg : args) { -#if defined(OS_WIN) - GURL potential_protocol(base::AsStringPiece16(arg)); -#else - GURL potential_protocol(arg); -#endif // defined(OS_WIN) - // protocol_url is checked for validity later on with GetHandlersFor() where - // we consult the ProtocolHandlerRegistry and find entries that match this - // protocol. - if (potential_protocol.is_valid()) { - protocol_url = std::move(potential_protocol); - break; - } - } - if (protocol_url.is_empty()) - return false; - - web_app::WebAppProviderBase* provider = - web_app::WebAppProviderBase::GetProviderBase(profile); - web_app::OsIntegrationManager& os_integration_manager = - provider->os_integration_manager(); - const std::vector<ProtocolHandler> handlers = - os_integration_manager.GetHandlersForProtocol(protocol_url.scheme()); - - // Nothing to do if there are no handlers with a web_app_id. - if (!base::Contains(handlers, true, [](const auto& handler) { - return handler.web_app_id().has_value(); - })) { - return false; - } - - auto launch_callback = base::BindOnce( - [](const base::CommandLine& command_line, const base::FilePath& cur_dir, - Profile* profile, const GURL& protocol_url, - const web_app::AppId& app_id, - std::unique_ptr<LaunchModeRecorder> launch_mode_recorder, - bool accepted) { - if (accepted) { - apps::AppServiceProxyFactory::GetForProfile(profile) - ->BrowserAppLauncher() - ->LaunchAppWithCallback( - app_id, command_line, cur_dir, - /*url_handler_launch_url=*/absl::nullopt, protocol_url, - base::BindOnce(&FinalizeWebAppLaunch, - std::move(launch_mode_recorder))); - } // else allow the process to exit without opening a browser. - }, - command_line, cur_dir, profile, protocol_url, app_id, - std::move(launch_mode_recorder)); - // ShowWebAppProtocolHandlerIntentPicker keeps the `profile` alive through - // running of `launch_callback`. - chrome::ShowWebAppProtocolHandlerIntentPicker(std::move(protocol_url), - profile, std::move(app_id), - std::move(launch_callback)); - return true; -} -#endif // defined(OS_WIN) || defined(OS_MAC) || defined(OS_LINUX) - // If the process was launched with the web application command line flags, // e.g. --app=http://www.google.com/ or --app_id=... return true. // In this case |app_url| or |app_id| are populated if they're non-null. @@ -554,7 +470,6 @@ } return false; } - } // namespace StartupBrowserCreator::StartupBrowserCreator() = default; @@ -1058,13 +973,44 @@ #if defined(OS_WIN) || defined(OS_MAC) || defined(OS_LINUX) // Web app Protocol handling. - if (MaybeLaunchProtocolHandlerWebApp( - command_line, cur_dir, privacy_safe_profile, - std::make_unique<LaunchModeRecorder>())) { + auto startup_callback = base::BindOnce( + [](bool process_startup, const base::CommandLine& command_line, + const base::FilePath& cur_dir, Profile* profile, + Profile* last_used_profile, + const std::vector<Profile*>& last_opened_profiles) { + // TODO(crbug.com/1208199): Refactor StartupBrowserCreator and use the + // state struct here. + StartupBrowserCreator browser_creator; + browser_creator.StartupLaunchAfterProtocolHandler( + command_line, cur_dir, profile, process_startup, last_used_profile, + last_opened_profiles); + }, + process_startup); + + // web_app::startup::MaybeLaunchProtocolHandlerWebApp keeps the `profile` + // alive through running of `startup_callback`. + if (web_app::startup::MaybeLaunchProtocolHandlerWebApp( + command_line, cur_dir, privacy_safe_profile, last_used_profile, + last_opened_profiles, + base::BindOnce(&FinalizeWebAppLaunch, + std::make_unique<LaunchModeRecorder>()), + std::move(startup_callback))) { return true; } #endif + return StartupLaunchAfterProtocolHandler( + command_line, cur_dir, privacy_safe_profile, process_startup, + last_used_profile, last_opened_profiles); +} + +bool StartupBrowserCreator::StartupLaunchAfterProtocolHandler( + const base::CommandLine& command_line, + const base::FilePath& cur_dir, + Profile* privacy_safe_profile, + bool process_startup, + Profile* last_used_profile, + const std::vector<Profile*>& last_opened_profiles) { // If we're being run as an application window or application tab, don't // restore tabs or open initial URLs as the user has directly launched an app // shortcut. In the first case, the user should see a standlone app window. In
diff --git a/chrome/browser/ui/startup/startup_browser_creator.h b/chrome/browser/ui/startup/startup_browser_creator.h index 60f651e..a288b33 100644 --- a/chrome/browser/ui/startup/startup_browser_creator.h +++ b/chrome/browser/ui/startup/startup_browser_creator.h
@@ -191,6 +191,16 @@ Profile* profile, Profile::CreateStatus status); + // TODO(crbug/1213171): Move web-app functionality to its own file. + // The startup launch logic that is shared between ProcessCmdLineImpl() + // and web_app::MaybeLaunchProtocolHandlerWebApp(). + bool StartupLaunchAfterProtocolHandler(const base::CommandLine& command_line, + const base::FilePath& cur_dir, + Profile* privacy_safe_profile, + bool process_startup, + Profile* last_used_profile, + const Profiles& last_opened_profiles); + // Returns true once a profile was activated. Used by the // StartupBrowserCreatorTest.LastUsedProfileActivated test. static bool ActivatedProfile();
diff --git a/chrome/browser/ui/startup/startup_browser_creator_impl.cc b/chrome/browser/ui/startup/startup_browser_creator_impl.cc index d813c2a..eb05e1b 100644 --- a/chrome/browser/ui/startup/startup_browser_creator_impl.cc +++ b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
@@ -637,13 +637,21 @@ #if BUILDFLAG(IS_CHROMEOS_LACROS) PrefService* local_state = g_browser_process->local_state(); - if (local_state && - !local_state->GetBoolean(lacros_prefs::kShowedExperimentalBannerPref)) { - LacrosStartupInfoBarDelegate::Create(infobar_manager); + if (local_state) { + // We show the banner if it's never shown before. + bool should_show_banner = + !local_state->GetBoolean(lacros_prefs::kShowedExperimentalBannerPref); + // If Lacros is not the primary browser, we always show the banner. + should_show_banner |= !chromeos::LacrosService::Get() + ->init_params() + ->standalone_browser_is_primary; - // Mark the pref as shown, so that we don't show the banner again. - local_state->SetBoolean(lacros_prefs::kShowedExperimentalBannerPref, - true); + if (should_show_banner) { + LacrosStartupInfoBarDelegate::Create(infobar_manager); + + local_state->SetBoolean(lacros_prefs::kShowedExperimentalBannerPref, + true); + } } #endif
diff --git a/chrome/browser/ui/startup/web_app_protocol_handling_startup_utils.cc b/chrome/browser/ui/startup/web_app_protocol_handling_startup_utils.cc new file mode 100644 index 0000000..e7c541e --- /dev/null +++ b/chrome/browser/ui/startup/web_app_protocol_handling_startup_utils.cc
@@ -0,0 +1,173 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/startup/web_app_protocol_handling_startup_utils.h" + +#include <memory> +#include <utility> +#include <vector> + +#include "base/bind.h" +#include "base/callback.h" +#include "base/check.h" +#include "base/command_line.h" +#include "base/containers/contains.h" +#include "base/files/file_path.h" +#include "base/location.h" +#include "base/strings/string_util.h" +#include "build/build_config.h" +#include "chrome/browser/apps/app_service/app_service_proxy.h" +#include "chrome/browser/apps/app_service/app_service_proxy_factory.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/profiles/profile_keep_alive_types.h" +#include "chrome/browser/profiles/scoped_profile_keep_alive.h" +#include "chrome/browser/ui/browser_dialogs.h" +#include "chrome/browser/ui/startup/startup_browser_creator.h" +#include "chrome/browser/web_applications/components/os_integration_manager.h" +#include "chrome/browser/web_applications/components/web_app_id.h" +#include "chrome/browser/web_applications/web_app_provider.h" +#include "chrome/common/chrome_switches.h" +#include "components/keep_alive_registry/keep_alive_types.h" +#include "components/keep_alive_registry/scoped_keep_alive.h" +#include "third_party/blink/public/common/custom_handlers/protocol_handler_utils.h" +#include "url/gurl.h" + +namespace { + +// Tries to launch the web app when the `provider` is ready. `startup_callback` +// will run if there is no web app registered for `profile` that can handle +// `protocol_url`. If os_integration_manager finds a web app, then check if the +// web app has approval from the user to handle `protocol_url`. If the web app +// didn't have approval from a previous launch, show the permission dialog to +// ask for approval. The permission dialog will then launch the web app if the +// user accepts the dialog or close the dialog window if the user cancels it. +// If the web app did get permission in the past, the browser will directly +// launch the web app with the translated url. The passed in `keep_alive` and +// `profile_keep_alives` ensure the profiles and the browser are alive while +// `provider` is waiting for the signal for "on_registry_ready()". +void OnWebAppSystemReadyMaybeLaunchProtocolHandler( + web_app::WebAppProvider* provider, + const GURL& protocol_url, + const web_app::AppId& app_id, + const base::CommandLine& command_line, + const base::FilePath& cur_dir, + Profile* profile, + Profile* last_used_profile, + const std::vector<Profile*>& last_opened_profiles, + std::unique_ptr<ScopedKeepAlive> keep_alive, + const std::vector<std::unique_ptr<ScopedProfileKeepAlive>> + profile_keep_alives, + web_app::startup::FinalizeWebAppLaunchCallback finalize_callback, + web_app::startup::StartupLaunchAfterProtocolCallback startup_callback) { + web_app::OsIntegrationManager& os_integration_manager = + provider->os_integration_manager(); + const std::vector<ProtocolHandler> handlers = + os_integration_manager.GetHandlersForProtocol(protocol_url.scheme()); + + if (!base::Contains(handlers, true, [](const auto& handler) { + return handler.web_app_id().has_value(); + })) { + std::move(startup_callback) + .Run(command_line, cur_dir, profile, last_used_profile, + last_opened_profiles); + return; + } + + auto launch_callback = base::BindOnce( + [](const base::CommandLine& command_line, const base::FilePath& cur_dir, + Profile* profile, const GURL& protocol_url, + const web_app::AppId& app_id, + web_app::startup::FinalizeWebAppLaunchCallback callback, + bool accepted) { + if (accepted) { + apps::AppServiceProxyFactory::GetForProfile(profile) + ->BrowserAppLauncher() + ->LaunchAppWithCallback(app_id, command_line, cur_dir, + /*url_handler_launch_url=*/absl::nullopt, + protocol_url, std::move(callback)); + } // else allow the process to exit without opening a browser. + }, + command_line, cur_dir, profile, protocol_url, app_id, + std::move(finalize_callback)); + + // ShowWebAppProtocolHandlerIntentPicker keeps the `profile` alive through + // running of `launch_callback`. + chrome::ShowWebAppProtocolHandlerIntentPicker(protocol_url, profile, app_id, + std::move(launch_callback)); +} + +} // namespace + +namespace web_app { +namespace startup { + +bool MaybeLaunchProtocolHandlerWebApp( + const base::CommandLine& command_line, + const base::FilePath& cur_dir, + Profile* profile, + Profile* last_used_profile, + const std::vector<Profile*>& last_opened_profiles, + FinalizeWebAppLaunchCallback finalize_callback, + StartupLaunchAfterProtocolCallback startup_callback) { + std::string app_id = command_line.GetSwitchValueASCII(switches::kAppId); + // There must be a kAppId switch arg in the command line to launch. + if (app_id.empty()) + return false; + + GURL protocol_url; + base::CommandLine::StringVector args = command_line.GetArgs(); + for (const auto& arg : args) { +#if defined(OS_WIN) + GURL potential_protocol(base::AsStringPiece16(arg)); +#else + GURL potential_protocol(arg); +#endif // defined(OS_WIN) + // protocol_url is checked for validity later with getting the provider and + // consulting the os_integration_manager. However because that process has a + // wait for "on_registry_ready()", `potential_protocol` checks for + // blink::IsValidCustomHandlerScheme() here to avoid loading the + // web_app::WebAppProvider with a false positive. + bool unused_has_custom_scheme_prefix = false; + if (potential_protocol.is_valid() && + blink::IsValidCustomHandlerScheme(potential_protocol.scheme(), + /*allow_ext_prefix=*/false, + unused_has_custom_scheme_prefix)) { + protocol_url = std::move(potential_protocol); + break; + } + } + if (protocol_url.is_empty()) + return false; + + auto* provider = web_app::WebAppProvider::Get(profile); + DCHECK(provider); + // Create the keep_alives so the profiles and the browser stays alive as we + // wait for the provider() to be ready. + auto keep_alive = std::make_unique<ScopedKeepAlive>( + KeepAliveOrigin::WEB_APP_PROTOCOL_HANDLER_LAUNCH, + KeepAliveRestartOption::DISABLED); + std::vector<std::unique_ptr<ScopedProfileKeepAlive>> profile_keep_alives; + profile_keep_alives.push_back(std::make_unique<ScopedProfileKeepAlive>( + profile, ProfileKeepAliveOrigin::kWebAppProtocolHandlerLaunch)); + profile_keep_alives.push_back(std::make_unique<ScopedProfileKeepAlive>( + last_used_profile, ProfileKeepAliveOrigin::kWebAppProtocolHandlerLaunch)); + for (Profile* last_opened_profile : last_opened_profiles) { + profile_keep_alives.push_back(std::make_unique<ScopedProfileKeepAlive>( + last_opened_profile, + ProfileKeepAliveOrigin::kWebAppProtocolHandlerLaunch)); + } + + provider->on_registry_ready().Post( + FROM_HERE, + base::BindOnce(OnWebAppSystemReadyMaybeLaunchProtocolHandler, provider, + std::move(protocol_url), std::move(app_id), command_line, + cur_dir, profile, last_used_profile, last_opened_profiles, + std::move(keep_alive), std::move(profile_keep_alives), + std::move(finalize_callback), + std::move(startup_callback))); + return true; +} + +} // namespace startup +} // namespace web_app
diff --git a/chrome/browser/ui/startup/web_app_protocol_handling_startup_utils.h b/chrome/browser/ui/startup/web_app_protocol_handling_startup_utils.h new file mode 100644 index 0000000..b2d3ebcf --- /dev/null +++ b/chrome/browser/ui/startup/web_app_protocol_handling_startup_utils.h
@@ -0,0 +1,59 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_STARTUP_WEB_APP_PROTOCOL_HANDLING_STARTUP_UTILS_H_ +#define CHROME_BROWSER_UI_STARTUP_WEB_APP_PROTOCOL_HANDLING_STARTUP_UTILS_H_ + +#include <vector> + +#include "base/callback.h" +#include "chrome/browser/web_applications/components/web_app_id.h" +#include "components/services/app_service/public/mojom/types.mojom.h" + +class Browser; +class Profile; +namespace base { +class CommandLine; +class FilePath; +} // namespace base + +namespace web_app { +namespace startup { + +using FinalizeWebAppLaunchCallback = + base::OnceCallback<void(Browser* browser, + apps::mojom::LaunchContainer container)>; +using StartupLaunchAfterProtocolCallback = + base::OnceCallback<void(const base::CommandLine& command_line, + const base::FilePath& cur_dir, + Profile* profile, + Profile* last_used_profile, + const std::vector<Profile*>& last_opened_profiles)>; + +// Launches a web app to handle a URL if `command_line` contains +// --app-id=<app> and at least one URL for which the referenced app is +// is registered in `profile` to handle the URL's protocol. Returns true +// if the command_line contains --app-id=<app> and at least one valid URL +// by checking for blink::IsValidCustomHandlerScheme(). Only one valid URL +// is expected in `command_line` and all other URLs are ignored. +// The URL will be further validated by consulting the os_integration_manager +// and checked for a installed app that is registered in `profile` to handle +// the URL's protocol. `startup_callback` will run when the check fails and +// there is no installed web app registered for `profile` that can handle the +// protocol.`finalize_callback` is used if and only if this function +// returns true. +bool MaybeLaunchProtocolHandlerWebApp( + const base::CommandLine& command_line, + const base::FilePath& cur_dir, + Profile* profile, + Profile* last_used_profile, + const std::vector<Profile*>& last_opened_profiles, + FinalizeWebAppLaunchCallback finalize_callback, + StartupLaunchAfterProtocolCallback startup_callback); + +} // namespace startup + +} // namespace web_app + +#endif // CHROME_BROWSER_UI_STARTUP_WEB_APP_PROTOCOL_HANDLING_STARTUP_UTILS_H_
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc index cbfa041..ddebb0b 100644 --- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc +++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
@@ -490,9 +490,8 @@ if (browser_view) SetBackground(std::make_unique<TopContainerBackground>(browser_view)); - views::FocusRing::SetColorContextForSubtree( - this, ThemeProperties::COLOR_TOOLBAR, - ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON); + views::FocusRing::SetBackgroundColorIdForSubtree( + this, ThemeProperties::COLOR_TOOLBAR); } BookmarkBarView::~BookmarkBarView() {
diff --git a/chrome/browser/ui/views/chrome_web_dialog_view.cc b/chrome/browser/ui/views/chrome_web_dialog_view.cc index 61323fa..9a5ffca 100644 --- a/chrome/browser/ui/views/chrome_web_dialog_view.cc +++ b/chrome/browser/ui/views/chrome_web_dialog_view.cc
@@ -63,6 +63,10 @@ bool show) { views::WebDialogView* view = new views::WebDialogView( context, delegate, std::make_unique<ChromeWebContentsHandler>()); + // If the corner radius is specified, set it to |views::DialogDelegate|. + if (extra_params && extra_params->corner_radius) + view->set_corner_radius(*(extra_params->corner_radius)); + views::Widget::InitParams params; if (extra_params) params = std::move(*extra_params);
diff --git a/chrome/browser/ui/views/download/download_shelf_view.cc b/chrome/browser/ui/views/download/download_shelf_view.cc index 638cef9..d840bb6 100644 --- a/chrome/browser/ui/views/download/download_shelf_view.cc +++ b/chrome/browser/ui/views/download/download_shelf_view.cc
@@ -109,9 +109,8 @@ // and return to chrome with the download shelf still open. mouse_watcher_.set_notify_on_exit_time(base::TimeDelta::FromSeconds(5)); SetID(VIEW_ID_DOWNLOAD_SHELF); - views::FocusRing::SetColorContextForSubtree( - this, ThemeProperties::COLOR_TOOLBAR, - ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON); + views::FocusRing::SetBackgroundColorIdForSubtree( + this, ThemeProperties::COLOR_TOOLBAR); } DownloadShelfView::~DownloadShelfView() = default;
diff --git a/chrome/browser/ui/views/frame/tab_strip_region_view.cc b/chrome/browser/ui/views/frame/tab_strip_region_view.cc index 3d5a552f..8772a0ad 100644 --- a/chrome/browser/ui/views/frame/tab_strip_region_view.cc +++ b/chrome/browser/ui/views/frame/tab_strip_region_view.cc
@@ -155,10 +155,8 @@ } // namespace TabStripRegionView::TabStripRegionView(std::unique_ptr<TabStrip> tab_strip) { - // TOOD(pbos): Find a better update. See TabStrip::GetTabForegroundColor. - views::FocusRing::SetColorContextForSubtree( - this, ThemeProperties::COLOR_TAB_BACKGROUND_INACTIVE_FRAME_INACTIVE, - ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON); + views::FocusRing::SetBackgroundColorIdForSubtree( + this, ThemeProperties::COLOR_TAB_BACKGROUND_INACTIVE_FRAME_INACTIVE); layout_manager_ = SetLayoutManager(std::make_unique<views::FlexLayout>()); layout_manager_->SetOrientation(views::LayoutOrientation::kHorizontal);
diff --git a/chrome/browser/ui/views/infobars/infobar_container_view.cc b/chrome/browser/ui/views/infobars/infobar_container_view.cc index 1123c61..a9c5cd1 100644 --- a/chrome/browser/ui/views/infobars/infobar_container_view.cc +++ b/chrome/browser/ui/views/infobars/infobar_container_view.cc
@@ -66,9 +66,8 @@ content_shadow_(new ContentShadow()) { SetID(VIEW_ID_INFO_BAR_CONTAINER); AddChildView(content_shadow_); - views::FocusRing::SetColorContextForSubtree( - this, ThemeProperties::COLOR_TOOLBAR, - ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON); + views::FocusRing::SetBackgroundColorIdForSubtree( + this, ThemeProperties::COLOR_TOOLBAR); } InfoBarContainerView::~InfoBarContainerView() {
diff --git a/chrome/browser/ui/views/page_action/pwa_install_view_browsertest.cc b/chrome/browser/ui/views/page_action/pwa_install_view_browsertest.cc index ec50f0fc..97029c2a 100644 --- a/chrome/browser/ui/views/page_action/pwa_install_view_browsertest.cc +++ b/chrome/browser/ui/views/page_action/pwa_install_view_browsertest.cc
@@ -92,6 +92,8 @@ } // namespace +// Tests various cases that effect the visibility of the install icon in the +// omnibox. class PwaInstallViewBrowserTest : public extensions::ExtensionBrowserTest { public: PwaInstallViewBrowserTest()
diff --git a/chrome/browser/ui/views/page_info/page_info_bubble_view_unittest.cc b/chrome/browser/ui/views/page_info/page_info_bubble_view_unittest.cc index b049562..f519face3b 100644 --- a/chrome/browser/ui/views/page_info/page_info_bubble_view_unittest.cc +++ b/chrome/browser/ui/views/page_info/page_info_bubble_view_unittest.cc
@@ -20,6 +20,8 @@ #include "chrome/browser/usb/usb_chooser_context.h" #include "chrome/browser/usb/usb_chooser_context_factory.h" #include "chrome/common/pref_names.h" +#include "chrome/test/base/scoped_testing_local_state.h" +#include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile.h" #include "chrome/test/views/chrome_test_views_delegate.h" #include "components/content_settings/core/browser/host_content_settings_map.h" @@ -201,7 +203,8 @@ class PageInfoBubbleViewTest : public testing::Test { public: - PageInfoBubbleViewTest() {} + PageInfoBubbleViewTest() + : testing_local_state_(TestingBrowserProcess::GetGlobal()) {} // testing::Test: void SetUp() override { @@ -225,6 +228,7 @@ } protected: + ScopedTestingLocalState testing_local_state_; ScopedWebContentsTestHelper web_contents_helper_; views::ScopedViewsTestHelper views_helper_{ std::make_unique<ChromeTestViewsDelegate<>>()}; @@ -569,9 +573,8 @@ EXPECT_EQ(kExpectedChildren, api_->permissions_view()->children().size()); // Add the policy setting to prefs. - Profile* profile = web_contents_helper_.profile(); - profile->GetPrefs()->Set(prefs::kManagedSerialAllowUsbDevicesForUrls, - ReadJson(R"([ + testing_local_state_.Get()->Set(prefs::kManagedSerialAllowUsbDevicesForUrls, + ReadJson(R"([ { "devices": [{ "vendor_id": 6353, "product_id": 5678 }], "urls": [ "http://www.example.com" ]
diff --git a/chrome/browser/ui/views/sharing/sharing_icon_view.cc b/chrome/browser/ui/views/sharing/sharing_icon_view.cc index 5336660..7d710c08 100644 --- a/chrome/browser/ui/views/sharing/sharing_icon_view.cc +++ b/chrome/browser/ui/views/sharing/sharing_icon_view.cc
@@ -42,12 +42,12 @@ return web_contents ? get_controller_callback_.Run(web_contents) : nullptr; } -void SharingIconView::StartLoadingAnimation() { +void SharingIconView::StartLoadingAnimation(int icon_label_id) { if (loading_animation_) return; loading_animation_ = true; - AnimateIn(IDS_BROWSER_SHARING_OMNIBOX_SENDING_LABEL); + AnimateIn(icon_label_id); SchedulePaint(); } @@ -75,7 +75,7 @@ } if (controller->is_loading()) - StartLoadingAnimation(); + StartLoadingAnimation(controller->GetIconLabelId()); else StopLoadingAnimation();
diff --git a/chrome/browser/ui/views/sharing/sharing_icon_view.h b/chrome/browser/ui/views/sharing/sharing_icon_view.h index c3261ff..5a7c5d7 100644 --- a/chrome/browser/ui/views/sharing/sharing_icon_view.h +++ b/chrome/browser/ui/views/sharing/sharing_icon_view.h
@@ -34,7 +34,7 @@ SharingIconView& operator=(const SharingIconView&) = delete; ~SharingIconView() override; - void StartLoadingAnimation(); + void StartLoadingAnimation(int icon_label_id); void StopLoadingAnimation(); protected:
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc index 6f01d8c..b0fb911 100644 --- a/chrome/browser/ui/views/tabs/tab_strip.cc +++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -1114,9 +1114,11 @@ base::BindRepeating(&TabStrip::tabs_view_model, base::Unretained(this)))), drag_context_(std::make_unique<TabDragContextImpl>(this)) { - views::FocusRing::SetColorContextForSubtree( - this, ThemeProperties::COLOR_TOOLBAR, - ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON); + // TODO(pbos): This is probably incorrect, the background of individual tabs + // depend on their selected state. This should probably be pushed down into + // tabs. + views::FocusRing::SetBackgroundColorIdForSubtree( + this, ThemeProperties::COLOR_TOOLBAR); Init(); SetEventTargeter(std::make_unique<views::ViewTargeter>(this)); }
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.cc b/chrome/browser/ui/views/toolbar/toolbar_view.cc index b80a9dc170..eab5868 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_view.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_view.cc
@@ -176,9 +176,8 @@ for (const auto& view_and_command : GetViewCommandMap()) chrome::AddCommandObserver(browser_, view_and_command.second, this); } - views::FocusRing::SetColorContextForSubtree( - this, ThemeProperties::COLOR_TOOLBAR, - ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON); + views::FocusRing::SetBackgroundColorIdForSubtree( + this, ThemeProperties::COLOR_TOOLBAR); } ToolbarView::~ToolbarView() {
diff --git a/chrome/browser/ui/web_applications/pwa_mixed_content_browsertest.cc b/chrome/browser/ui/web_applications/pwa_mixed_content_browsertest.cc index b8692634..700f05b 100644 --- a/chrome/browser/ui/web_applications/pwa_mixed_content_browsertest.cc +++ b/chrome/browser/ui/web_applications/pwa_mixed_content_browsertest.cc
@@ -74,6 +74,8 @@ "/ssl/page_displays_insecure_content.html"); } + // This URL is on app.com, and the page contains a secure iframe that points + // to foo.com/simple.html. GURL GetSecureIFrameAppURL() { net::HostPortPair host_port_pair = net::HostPortPair::FromURL( https_server()->GetURL("foo.com", "/simple.html")); @@ -140,7 +142,7 @@ ->GetActiveWebContents() ->GetLastCommittedURL()); - // The WebContents is just reparented, so mixed content is still not loaded. + // The WebContents is just reparented, so mixed content is still loaded. CheckMixedContentLoaded(browser()); EXPECT_EQ(GetAppMenuCommandState(IDC_OPEN_IN_PWA_WINDOW, browser()), kEnabled); @@ -223,6 +225,7 @@ browser()->tab_strip_model()->GetActiveWebContents(), app_id); CheckMixedContentFailedToLoad(app_browser); + // Change the mixed content to be acceptable. content::RenderFrameHost* main_frame = app_browser->tab_strip_model()->GetActiveWebContents()->GetMainFrame(); content::RenderFrameHost* iframe = content::ChildFrameAt(main_frame, 0);
diff --git a/chrome/browser/ui/web_applications/web_app_browsertest.cc b/chrome/browser/ui/web_applications/web_app_browsertest.cc index e85f0f5..aa7fda5 100644 --- a/chrome/browser/ui/web_applications/web_app_browsertest.cc +++ b/chrome/browser/ui/web_applications/web_app_browsertest.cc
@@ -431,7 +431,7 @@ /*open_as_window=*/false)); } -// Tests that desktop PWAs open links in the browser. +// Tests that desktop PWAs open out-of-scope links with a custom toolbar. IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, DesktopPWAsOpenLinksInApp) { const GURL app_url = GetSecureAppURL(); const AppId app_id = InstallPWA(app_url);
diff --git a/chrome/browser/ui/web_applications/web_app_file_handling_browsertest.cc b/chrome/browser/ui/web_applications/web_app_file_handling_browsertest.cc index ed790af1..76ce7af 100644 --- a/chrome/browser/ui/web_applications/web_app_file_handling_browsertest.cc +++ b/chrome/browser/ui/web_applications/web_app_file_handling_browsertest.cc
@@ -20,6 +20,7 @@ #include "chrome/browser/apps/app_service/browser_app_launcher.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/ui/web_applications/web_app_controller_browsertest.h" +#include "chrome/browser/ui/webui/settings/site_settings_helper.h" #include "chrome/browser/web_applications/components/app_registrar.h" #include "chrome/browser/web_applications/components/file_handler_manager.h" #include "chrome/browser/web_applications/components/os_integration_manager.h" @@ -129,10 +130,6 @@ return https_server()->GetURL("app.com", "/ssl/page_with_frame.html"); } - GURL GetSecondAppUrl() { - return https_server()->GetURL("app.com", "/pwa/app2.html"); - } - void InstallFileHandlingPWA() { GURL url = GetSecureAppURL(); @@ -168,9 +165,7 @@ WebAppControllerBrowserTest::InstallWebApp(std::move(web_app_info)); } - void InstallSecondFileHandlingPWASameOrigin() { - GURL url = GetSecondAppUrl(); - + void InstallAnotherFileHandlingPwa(const GURL& url) { auto web_app_info = std::make_unique<WebApplicationInfo>(); web_app_info->start_url = url; web_app_info->scope = url.GetWithoutFilename(); @@ -214,6 +209,9 @@ return new_file_path; } +// // Launches the |app_id| web app with |files| handles, awaits for +// |expected_launch_url| to load and stashes any launch params on +// "window.launchParams" for further inspection. content::WebContents* LaunchApplication( Profile* profile, const std::string& app_id, @@ -409,6 +407,95 @@ } } +// Tests that when two apps are installed and share an origin (but not scope), +// `GetFileHandlersForAllWebAppsWithOrigin` will report all the file handlers +// across both apps. +IN_PROC_BROWSER_TEST_F(WebAppFileHandlingBrowserTest, + FileHandlerAggregationForUi) { + InstallFileHandlingPWA(); + EXPECT_EQ(3U, + GetFileHandlersForAllWebAppsWithOrigin(profile(), GetSecureAppURL()) + .size()); + + GURL second_app_url = https_server()->GetURL("app.com", "/pwa/app2.html"); + InstallAnotherFileHandlingPwa(second_app_url); + EXPECT_EQ(2U, registrar().GetAppIds().size()); + EXPECT_EQ(4U, + GetFileHandlersForAllWebAppsWithOrigin(profile(), GetSecureAppURL()) + .size()); + EXPECT_EQ( + 4U, + GetFileHandlersForAllWebAppsWithOrigin(profile(), second_app_url).size()); + + std::u16string display_string_app1 = + GetFileTypeAssociationsHandledByWebAppsForDisplay(profile(), + GetSecureAppURL()); + std::u16string display_string_app2 = + GetFileTypeAssociationsHandledByWebAppsForDisplay(profile(), + second_app_url); + EXPECT_EQ(display_string_app1, display_string_app2); +#if defined(OS_LINUX) + const std::u16string kHtmlDisplayString = u"text/html"; + const std::u16string kJpegDisplayString = u"image/jpeg"; +#else + const std::u16string kHtmlDisplayString = u"HTML"; + const std::u16string kJpegDisplayString = u"JPEG"; +#endif + EXPECT_NE(std::u16string::npos, display_string_app1.find(kHtmlDisplayString)); + EXPECT_NE(std::u16string::npos, display_string_app1.find(kJpegDisplayString)); +} + +IN_PROC_BROWSER_TEST_F(WebAppFileHandlingBrowserTest, + SometimesResetPermission) { + // Install the first app and simulate the user granting it the file handling + // permission. + InstallFileHandlingPWA(); + auto* map = HostContentSettingsMapFactory::GetForProfile(profile()); + const GURL origin = GetSecureAppURL().GetOrigin(); + EXPECT_EQ(CONTENT_SETTING_ASK, + map->GetContentSetting(origin, origin, + ContentSettingsType::FILE_HANDLING)); + map->SetContentSettingDefaultScope(origin, origin, + ContentSettingsType::FILE_HANDLING, + CONTENT_SETTING_ALLOW); + EXPECT_EQ(CONTENT_SETTING_ALLOW, + map->GetContentSetting(origin, origin, + ContentSettingsType::FILE_HANDLING)); + + // Install a second app, which is on the same origin and asks to handle more + // file types. The permission should have been set back to ASK. + GURL second_app_url = https_server()->GetURL("app.com", "/pwa/app2.html"); + InstallAnotherFileHandlingPwa(second_app_url); + EXPECT_EQ(CONTENT_SETTING_ASK, + map->GetContentSetting(origin, origin, + ContentSettingsType::FILE_HANDLING)); + + // Set to ALLOW again. + map->SetContentSettingDefaultScope(origin, origin, + ContentSettingsType::FILE_HANDLING, + CONTENT_SETTING_ALLOW); + + // Install a third app, which is on a different origin; this should have no + // effect on the permission. + GURL third_app_url = https_server()->GetURL("otherapp.com", "/pwa/app2.html"); + InstallAnotherFileHandlingPwa(third_app_url); + EXPECT_EQ(CONTENT_SETTING_ALLOW, + map->GetContentSetting(origin, origin, + ContentSettingsType::FILE_HANDLING)); + GURL third_app_origin = third_app_url.GetOrigin(); + EXPECT_EQ(CONTENT_SETTING_ASK, + map->GetContentSetting(third_app_origin, third_app_origin, + ContentSettingsType::FILE_HANDLING)); + // Install a fourth app, which is on the same origin but asks for a subset of + // the file types of the first two. This should have no effect on the + // permission. + GURL fourth_app_url = https_server()->GetURL("app.com", "/pwa2/app2.html"); + InstallAnotherFileHandlingPwa(fourth_app_url); + EXPECT_EQ(CONTENT_SETTING_ALLOW, + map->GetContentSetting(origin, origin, + ContentSettingsType::FILE_HANDLING)); +} + class WebAppFileHandlingOriginTrialBrowserTest : public WebAppFileHandlingTestBase { public: @@ -761,41 +848,33 @@ ->file_handler_permission_blocked()); } -// Tests that when two apps are installed and share an origin (but not scope), -// `GetFileHandlersForAllWebAppsWithOrigin` will report all the file handlers -// across both apps. -IN_PROC_BROWSER_TEST_F(WebAppFileHandlingPolicyBrowserTest, - FileHandlerAggregationForUi) { +IN_PROC_BROWSER_TEST_F(WebAppFileHandlingBrowserTest, + SettingsCategoryVisibility) { + // The file handling permission is visible in a general context. + const std::vector<ContentSettingsType>& all_categories = + site_settings::GetVisiblePermissionCategories(); + EXPECT_FALSE(std::find(all_categories.begin(), all_categories.end(), + ContentSettingsType::FILE_HANDLING) == + all_categories.end()); + + // The file handling permission is not visible in the context of an origin + // that doesn't correspond to a PWA. + std::vector<ContentSettingsType> categories_for_arbitrary_website = + site_settings::GetVisiblePermissionCategoriesForOrigin( + profile(), GURL("https://example.com")); + EXPECT_TRUE(std::find(categories_for_arbitrary_website.begin(), + categories_for_arbitrary_website.end(), + ContentSettingsType::FILE_HANDLING) == + categories_for_arbitrary_website.end()); + + // The file handling permission *is* visible for a PWA origin. InstallFileHandlingPWA(); - EXPECT_EQ(3U, - GetFileHandlersForAllWebAppsWithOrigin(profile(), GetSecureAppURL()) - .size()); - - InstallSecondFileHandlingPWASameOrigin(); - EXPECT_EQ(2U, registrar().GetAppIds().size()); - EXPECT_EQ(4U, - GetFileHandlersForAllWebAppsWithOrigin(profile(), GetSecureAppURL()) - .size()); - EXPECT_EQ(4U, - GetFileHandlersForAllWebAppsWithOrigin(profile(), GetSecondAppUrl()) - .size()); - - std::u16string display_string_app1 = - GetFileTypeAssociationsHandledByWebAppsForDisplay(profile(), - GetSecureAppURL()); - std::u16string display_string_app2 = - GetFileTypeAssociationsHandledByWebAppsForDisplay(profile(), - GetSecondAppUrl()); - EXPECT_EQ(display_string_app1, display_string_app2); -#if defined(OS_LINUX) - std::u16string html = u"text/html"; - std::u16string jpeg = u"image/jpeg"; -#else - std::u16string html = u"HTML"; - std::u16string jpeg = u"JPEG"; -#endif - EXPECT_NE(std::u16string::npos, display_string_app1.find(html)); - EXPECT_NE(std::u16string::npos, display_string_app1.find(jpeg)); + std::vector<ContentSettingsType> categories_for_pwa = + site_settings::GetVisiblePermissionCategoriesForOrigin( + profile(), GetSecureAppURL().GetOrigin()); + EXPECT_FALSE(std::find(categories_for_pwa.begin(), categories_for_pwa.end(), + ContentSettingsType::FILE_HANDLING) == + categories_for_pwa.end()); } #if BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/ui/web_applications/web_app_link_capturing_browsertest.cc b/chrome/browser/ui/web_applications/web_app_link_capturing_browsertest.cc index dd6fe10..2543ce6d 100644 --- a/chrome/browser/ui/web_applications/web_app_link_capturing_browsertest.cc +++ b/chrome/browser/ui/web_applications/web_app_link_capturing_browsertest.cc
@@ -68,6 +68,8 @@ namespace web_app { +// Tests that links are captured correctly into an installed WebApp using the +// 'tabbed' display mode, which allows the webapp window to have multiple tabs. class WebAppLinkCapturingBrowserTest : public WebAppNavigationBrowserTest { public: WebAppLinkCapturingBrowserTest() { @@ -206,6 +208,8 @@ base::test::ScopedFeatureList features_; }; +// First in scope navigation from about:blank gets captured and reparented into +// the app window. IN_PROC_BROWSER_TEST_F(WebAppTabStripLinkCapturingBrowserTest, InScopeNavigationsCaptured) { InstallTestApp();
diff --git a/chrome/browser/ui/webui/app_management/app_management.mojom b/chrome/browser/ui/webui/app_management/app_management.mojom index a39fcf3..d9612846 100644 --- a/chrome/browser/ui/webui/app_management/app_management.mojom +++ b/chrome/browser/ui/webui/app_management/app_management.mojom
@@ -25,6 +25,7 @@ bool hide_more_settings; bool hide_pin_to_shelf; bool is_preferred_app; + apps.mojom.WindowMode window_mode; }; // Extension-based apps primarily use install-time permissions that cannot be
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 9e1cc5a..3a72668 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
@@ -224,6 +224,7 @@ app->hide_pin_to_shelf = update.ShowInShelf() == apps::mojom::OptionalBool::kFalse || ShouldHidePinToShelf(app->id); + app->window_mode = update.WindowMode(); return app; }
diff --git a/chrome/browser/ui/webui/chromeos/multidevice_setup/multidevice_setup_dialog.cc b/chrome/browser/ui/webui/chromeos/multidevice_setup/multidevice_setup_dialog.cc index 8a072a2..f79625d 100644 --- a/chrome/browser/ui/webui/chromeos/multidevice_setup/multidevice_setup_dialog.cc +++ b/chrome/browser/ui/webui/chromeos/multidevice_setup/multidevice_setup_dialog.cc
@@ -62,9 +62,10 @@ } current_instance_ = new MultiDeviceSetupDialog(); - containing_window_ = chrome::ShowWebDialog( - nullptr /* parent */, ProfileManager::GetActiveUserProfile(), - current_instance_); + current_instance_->ShowSystemDialogForBrowserContext( + ProfileManager::GetActiveUserProfile(), nullptr); + + containing_window_ = current_instance_->dialog_window(); // Remove the black backdrop behind the dialog window which appears in tablet // and full-screen mode.
diff --git a/chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.cc b/chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.cc index f20c80f..391fc72 100644 --- a/chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.cc +++ b/chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.cc
@@ -29,12 +29,25 @@ namespace { +constexpr int kSystemDialogCornerRadiusDp = 12; + // Track all open system web dialog instances. This should be a small list. std::list<SystemWebDialogDelegate*>* GetInstances() { static base::NoDestructor<std::list<SystemWebDialogDelegate*>> instances; return instances.get(); } +// Creates default initial parameters. The system web dialog has 12 dip corner +// radius by default. If the window has a non-client frame view, we don't need +// to set shadow, since the bubble frame view will help draw the shadow. +views::Widget::InitParams CreateWidgetParams() { + views::Widget::InitParams params; + params.corner_radius = kSystemDialogCornerRadiusDp; + // Dialog frame view has its own shadow. + params.shadow_type = views::Widget::InitParams::ShadowType::kNone; + return params; +} + } // namespace // static @@ -166,6 +179,11 @@ size->SetSize(kDialogWidth, kDialogHeight); } +SystemWebDialogDelegate::FrameKind +SystemWebDialogDelegate::GetWebDialogFrameKind() const { + return FrameKind::kDialog; +} + std::string SystemWebDialogDelegate::GetDialogArgs() const { return std::string(); } @@ -200,7 +218,8 @@ void SystemWebDialogDelegate::ShowSystemDialogForBrowserContext( content::BrowserContext* browser_context, gfx::NativeWindow parent) { - views::Widget::InitParams extra_params; + views::Widget::InitParams extra_params = CreateWidgetParams(); + // If unparented and not modal, keep it on top (see header comment). if (!parent && GetDialogModalType() == ui::MODAL_TYPE_NONE) extra_params.z_order = ui::ZOrderLevel::kFloatingWindow;
diff --git a/chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.h b/chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.h index b0e28ac..719356c8 100644 --- a/chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.h +++ b/chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.h
@@ -72,6 +72,7 @@ void GetWebUIMessageHandlers( std::vector<content::WebUIMessageHandler*>* handlers) const override; void GetDialogSize(gfx::Size* size) const override; + FrameKind GetWebDialogFrameKind() const override; std::string GetDialogArgs() const override; void OnDialogShown(content::WebUI* webui) override; // Note: deletes |this|.
diff --git a/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc b/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc index 93ef644..c3c17be 100644 --- a/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc +++ b/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc
@@ -70,22 +70,6 @@ constexpr char kPrevNavigationTimePrefName[] = "NewTabPage.PrevNavigationTime"; -bool IsDriveModuleEnabled(Profile* profile) { - if (!base::FeatureList::IsEnabled(ntp_features::kNtpDriveModule)) { - return false; - } - if (base::GetFieldTrialParamValueByFeature( - ntp_features::kNtpDriveModule, - ntp_features::kNtpDriveModuleManagedUsersOnlyParam) != "true") { - return true; - } - auto* identity_manager = IdentityManagerFactory::GetForProfile(profile); - return identity_manager - ->FindExtendedAccountInfoByAccountId( - identity_manager->GetPrimaryAccountId(signin::ConsentLevel::kSync)) - .IsManaged(); -} - content::WebUIDataSource* CreateNewTabPageUiHtmlSource( Profile* profile, const base::Time& navigation_start_time) { @@ -276,7 +260,8 @@ source->AddBoolean( "chromeCartModuleEnabled", base::FeatureList::IsEnabled(ntp_features::kNtpChromeCartModule)); - source->AddBoolean("driveModuleEnabled", IsDriveModuleEnabled(profile)); + source->AddBoolean("driveModuleEnabled", + NewTabPageUI::IsDriveModuleEnabled(profile)); source->AddBoolean( "ruleBasedDiscountEnabled", base::GetFieldTrialParamValueByFeature( @@ -366,6 +351,24 @@ registry->RegisterTimePref(kPrevNavigationTimePrefName, base::Time()); } +// static +bool NewTabPageUI::IsDriveModuleEnabled(Profile* profile) { + if (!base::FeatureList::IsEnabled(ntp_features::kNtpDriveModule)) { + return false; + } + if (base::GetFieldTrialParamValueByFeature( + ntp_features::kNtpDriveModule, + ntp_features::kNtpDriveModuleManagedUsersOnlyParam) != "true") { + return true; + } + // TODO(https://crbug.com/1213351): Stop calling the private method + // FindExtendedPrimaryAccountInfo(). + auto* identity_manager = IdentityManagerFactory::GetForProfile(profile); + return identity_manager + ->FindExtendedPrimaryAccountInfo(signin::ConsentLevel::kSync) + .IsManaged(); +} + void NewTabPageUI::BindInterface( mojo::PendingReceiver<new_tab_page::mojom::PageHandlerFactory> pending_receiver) {
diff --git a/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.h b/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.h index 8d71068..04c66f5 100644 --- a/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.h +++ b/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.h
@@ -64,6 +64,7 @@ static bool IsNewTabPageOrigin(const GURL& url); static void RegisterProfilePrefs(PrefRegistrySimple* registry); + static bool IsDriveModuleEnabled(Profile* profile); // Instantiates the implementor of the mojom::PageHandlerFactory mojo // interface passing the pending receiver that will be internally bound.
diff --git a/chrome/browser/ui/webui/settings/site_settings_handler.cc b/chrome/browser/ui/webui/settings/site_settings_handler.cc index 918e662f..88ad648 100644 --- a/chrome/browser/ui/webui/settings/site_settings_handler.cc +++ b/chrome/browser/ui/webui/settings/site_settings_handler.cc
@@ -422,6 +422,10 @@ base::BindRepeating(&SiteSettingsHandler::HandleGetAllSites, base::Unretained(this))); web_ui()->RegisterMessageCallback( + "getCategoryList", + base::BindRepeating(&SiteSettingsHandler::HandleGetCategoryList, + base::Unretained(this))); + web_ui()->RegisterMessageCallback( "getCookieSettingDescription", base::BindRepeating( &SiteSettingsHandler::HandleGetCookieSettingDescription, @@ -730,15 +734,12 @@ void SiteSettingsHandler::HandleGetAllSites(const base::ListValue* args) { AllowJavascript(); - CHECK_EQ(2U, args->GetList().size()); + CHECK_EQ(1U, args->GetList().size()); std::string callback_id = args->GetList()[0].GetString(); - auto types = args->GetList()[1].GetList(); all_sites_map_.clear(); origin_permission_set_.clear(); - auto content_types = site_settings::ContentSettingsTypesFromGroupNames(types); - // Incognito contains incognito content settings plus non-incognito content // settings. Thus if it exists, just get exceptions for the incognito profile. Profile* profile = profile_; @@ -750,6 +751,12 @@ HostContentSettingsMap* map = HostContentSettingsMapFactory::GetForProfile(profile); + std::vector<ContentSettingsType> content_types = + site_settings::GetVisiblePermissionCategories(); + // Make sure to include cookies, because All Sites handles data storage + // cookies as well as regular ContentSettingsTypes. + content_types.push_back(ContentSettingsType::COOKIES); + // Retrieve a list of embargoed settings to check separately. This ensures // that only settings included in |content_types| will be listed in all sites. auto* autoblocker = @@ -792,6 +799,24 @@ ResolveJavascriptCallback(base::Value(callback_id), result); } +void SiteSettingsHandler::HandleGetCategoryList(const base::ListValue* args) { + AllowJavascript(); + + CHECK_EQ(2U, args->GetList().size()); + std::string callback_id = args->GetList()[0].GetString(); + GURL origin(args->GetList()[1].GetString()); + + std::vector<ContentSettingsType> content_types = + site_settings::GetVisiblePermissionCategoriesForOrigin(profile_, origin); + + base::Value result(base::Value::Type::LIST); + for (ContentSettingsType content_type : content_types) { + result.Append(site_settings::ContentSettingsTypeToGroupName(content_type)); + } + + ResolveJavascriptCallback(base::Value(callback_id), result); +} + void SiteSettingsHandler::HandleGetCookieSettingDescription( const base::ListValue* args) { AllowJavascript(); @@ -805,12 +830,12 @@ const base::ListValue* args) { AllowJavascript(); - CHECK_EQ(3U, args->GetList().size()); + CHECK_EQ(2U, args->GetList().size()); std::string callback_id = args->GetList()[0].GetString(); - auto types = args->GetList()[1].GetList(); - size_t max_sources = base::checked_cast<size_t>(args->GetList()[2].GetInt()); + size_t max_sources = base::checked_cast<size_t>(args->GetList()[1].GetInt()); - auto content_types = site_settings::ContentSettingsTypesFromGroupNames(types); + const std::vector<ContentSettingsType>& content_types = + site_settings::GetVisiblePermissionCategories(); auto recent_site_permissions = site_settings::GetRecentSitePermissions( profile_, content_types, max_sources); @@ -1019,28 +1044,28 @@ void SiteSettingsHandler::HandleSetOriginPermissions( const base::ListValue* args) { CHECK_EQ(3U, args->GetSize()); - std::string origin_string; - CHECK(args->GetString(0, &origin_string)); - const base::ListValue* types; - CHECK(args->GetList(1, &types)); - std::string value; - CHECK(args->GetString(2, &value)); + std::string origin_string = args->GetList()[0].GetString(); + const std::string* type_string = args->GetList()[1].GetIfString(); + std::string value = args->GetList()[2].GetString(); const GURL origin(origin_string); if (!origin.is_valid()) return; + std::vector<ContentSettingsType> types; + if (type_string) { + types.push_back( + site_settings::ContentSettingsTypeFromGroupName(*type_string)); + } else { + types = site_settings::GetVisiblePermissionCategoriesForOrigin(profile_, + origin); + } + ContentSetting setting; CHECK(content_settings::ContentSettingFromString(value, &setting)); - for (size_t i = 0; i < types->GetSize(); ++i) { - std::string type; - types->GetString(i, &type); - - ContentSettingsType content_type = - site_settings::ContentSettingsTypeFromGroupName(type); - HostContentSettingsMap* map = - HostContentSettingsMapFactory::GetForProfile(profile_); - + HostContentSettingsMap* map = + HostContentSettingsMapFactory::GetForProfile(profile_); + for (ContentSettingsType content_type : types) { permissions::PermissionUmaUtil::ScopedRevocationReporter scoped_revocation_reporter( profile_, origin, origin, content_type,
diff --git a/chrome/browser/ui/webui/settings/site_settings_handler.h b/chrome/browser/ui/webui/settings/site_settings_handler.h index 881025a..9dd5158 100644 --- a/chrome/browser/ui/webui/settings/site_settings_handler.h +++ b/chrome/browser/ui/webui/settings/site_settings_handler.h
@@ -169,14 +169,20 @@ // the front end when fetching finished. void HandleGetAllSites(const base::ListValue* args); + // Returns a list of content settings types that are controlled via a standard + // permissions UI and should be made visible to the user. There is a single + // nullable string argument, which represents an associated origin. See + // `SiteSettingsPrefsBrowserProxy#getCategoryList`. + void HandleGetCategoryList(const base::ListValue* args); + // Returns a string for display describing the current cookie settings. void HandleGetCookieSettingDescription(const base::ListValue* args); // Returns a list containing the most recent permission changes for the - // provided content types grouped by origin/profile (incognito, regular) - // combinations, limited to N origin/profile pairings. This includes - // permission changes made by embargo, but does not include permissions - // enforced via policy. + // content types that are visiblein settings, grouped by origin/profile + // (incognito, regular) combinations, limited to N origin/profile pairings. + // This includes permission changes made by embargo, but does not include + // permissions enforced via policy. void HandleGetRecentSitePermissions(const base::ListValue* args); // Called when the list of origins using storage has been fetched, and sends
diff --git a/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc b/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc index 98c96b29..c6775725 100644 --- a/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc +++ b/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc
@@ -543,9 +543,6 @@ TEST_F(SiteSettingsHandlerTest, GetAllSites) { base::ListValue get_all_sites_args; get_all_sites_args.AppendString(kCallbackId); - base::Value category_list(base::Value::Type::LIST); - category_list.Append(kNotifications); - get_all_sites_args.Append(std::move(category_list)); // Test all sites is empty when there are no preferences. handler()->HandleGetAllSites(&get_all_sites_args); @@ -744,9 +741,6 @@ base::ListValue get_recent_permissions_args; get_recent_permissions_args.AppendString(kCallbackId); - base::Value category_list(base::Value::Type::LIST); - category_list.Append(kNotifications); - get_recent_permissions_args.Append(std::move(category_list)); get_recent_permissions_args.Append(3); // Configure prefs and auto blocker with a controllable clock. @@ -783,15 +777,11 @@ url1, ContentSettingsType::NOTIFICATIONS, false); clock.Advance(base::TimeDelta::FromHours(2)); - map->SetContentSettingDefaultScope(url2, url2, ContentSettingsType::IMAGES, - CONTENT_SETTING_ALLOW); clock.Advance(base::TimeDelta::FromHours(1)); CreateIncognitoProfile(); HostContentSettingsMap* incognito_map = HostContentSettingsMapFactory::GetForProfile(incognito_profile()); incognito_map->SetClockForTesting(&clock); - incognito_map->SetContentSettingDefaultScope( - url1, url1, ContentSettingsType::IMAGES, CONTENT_SETTING_ALLOW); clock.Advance(base::TimeDelta::FromHours(1)); permissions::PermissionDecisionAutoBlocker* incognito_auto_blocker = @@ -1340,11 +1330,7 @@ // Block notifications. base::ListValue set_args; set_args.AppendString(origin_with_port); - { - auto category_list = std::make_unique<base::ListValue>(); - category_list->AppendString(kNotifications); - set_args.Append(std::move(category_list)); - } + set_args.AppendString(kNotifications); set_args.AppendString( content_settings::ContentSettingToString(CONTENT_SETTING_BLOCK)); handler()->HandleSetOriginPermissions(&set_args); @@ -1353,9 +1339,7 @@ // Reset things back to how they were. base::ListValue reset_args; reset_args.AppendString(origin_with_port); - auto category_list = std::make_unique<base::ListValue>(); - category_list->AppendString(kNotifications); - reset_args.Append(std::move(category_list)); + reset_args.AppendString(std::move(kNotifications)); reset_args.AppendString( content_settings::ContentSettingToString(CONTENT_SETTING_DEFAULT)); @@ -1677,11 +1661,7 @@ // Block notifications. base::ListValue set_args; set_args.AppendString(origin_anchor_string); - { - auto category_list = std::make_unique<base::ListValue>(); - category_list->AppendString(kNotifications); - set_args.Append(std::move(category_list)); - } + set_args.AppendString(kNotifications); set_args.AppendString( content_settings::ContentSettingToString(CONTENT_SETTING_BLOCK)); handler()->HandleSetOriginPermissions(&set_args); @@ -1873,9 +1853,6 @@ { base::ListValue get_all_sites_args; get_all_sites_args.AppendString(kCallbackId); - base::Value category_list(base::Value::Type::LIST); - category_list.Append(kNotifications); - get_all_sites_args.Append(std::move(category_list)); handler()->HandleGetAllSites(&get_all_sites_args); @@ -1911,9 +1888,6 @@ { base::ListValue get_recent_permissions_args; get_recent_permissions_args.AppendString(kCallbackId); - base::Value category_list(base::Value::Type::LIST); - category_list.Append(kNotifications); - get_recent_permissions_args.Append(std::move(category_list)); get_recent_permissions_args.Append(3); handler()->HandleGetRecentSitePermissions(&get_recent_permissions_args);
diff --git a/chrome/browser/ui/webui/settings/site_settings_helper.cc b/chrome/browser/ui/webui/settings/site_settings_helper.cc index b4dcf0a..7831684 100644 --- a/chrome/browser/ui/webui/settings/site_settings_helper.cc +++ b/chrome/browser/ui/webui/settings/site_settings_helper.cc
@@ -9,10 +9,13 @@ #include <set> #include <string> +#include "base/command_line.h" #include "base/containers/contains.h" #include "base/feature_list.h" +#include "base/no_destructor.h" #include "base/strings/utf_string_conversions.h" #include "base/values.h" +#include "build/build_config.h" #include "chrome/browser/bluetooth/bluetooth_chooser_context_factory.h" #include "chrome/browser/content_settings/chrome_content_settings_utils.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" @@ -25,6 +28,7 @@ #include "chrome/browser/subresource_filter/subresource_filter_profile_context_factory.h" #include "chrome/browser/usb/usb_chooser_context.h" #include "chrome/browser/usb/usb_chooser_context_factory.h" +#include "chrome/browser/web_applications/components/web_app_utils.h" #include "chrome/common/pref_names.h" #include "components/content_settings/core/browser/host_content_settings_map.h" #include "components/content_settings/core/common/content_settings.h" @@ -43,6 +47,7 @@ #include "components/subresource_filter/core/browser/subresource_filter_features.h" #include "components/url_formatter/url_formatter.h" #include "content/public/common/content_features.h" +#include "content/public/common/content_switches.h" #include "content/public/common/url_utils.h" #include "extensions/browser/extension_registry.h" #include "extensions/common/constants.h" @@ -401,16 +406,80 @@ return base::StringPiece(); } -std::vector<ContentSettingsType> ContentSettingsTypesFromGroupNames( - const base::Value::ConstListView types) { - std::vector<ContentSettingsType> content_types; - content_types.reserve(types.size()); - for (const auto& value : types) { - const auto& type = value.GetString(); - content_types.push_back( - site_settings::ContentSettingsTypeFromGroupName(type)); +const std::vector<ContentSettingsType>& GetVisiblePermissionCategories() { + // First build the list of permissions that will be shown regardless of + // `origin`. Some categories such as COOKIES store their data in a custom way, + // so are not included here. + static base::NoDestructor<std::vector<ContentSettingsType>> base_types({ + ContentSettingsType::AR, ContentSettingsType::AUTOMATIC_DOWNLOADS, + ContentSettingsType::BACKGROUND_SYNC, + ContentSettingsType::CLIPBOARD_READ_WRITE, + ContentSettingsType::FILE_HANDLING, + ContentSettingsType::FILE_SYSTEM_WRITE_GUARD, + ContentSettingsType::FONT_ACCESS, ContentSettingsType::GEOLOCATION, + ContentSettingsType::HID_GUARD, ContentSettingsType::IDLE_DETECTION, + ContentSettingsType::IMAGES, ContentSettingsType::JAVASCRIPT, + ContentSettingsType::MEDIASTREAM_CAMERA, + ContentSettingsType::MEDIASTREAM_MIC, ContentSettingsType::MIDI_SYSEX, + ContentSettingsType::MIXEDSCRIPT, ContentSettingsType::NOTIFICATIONS, + ContentSettingsType::POPUPS, +#if defined(IS_CHROMEOS_ASH) || defined(OS_WIN) + ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER, +#endif + ContentSettingsType::SENSORS, ContentSettingsType::SERIAL_GUARD, + ContentSettingsType::SOUND, ContentSettingsType::USB_GUARD, + ContentSettingsType::VR, + }); + static bool initialized = false; + if (!initialized) { + // The permission categories in this block are only shown when running with + // certain flags/switches. + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + ::switches::kEnableExperimentalWebPlatformFeatures)) { + base_types->push_back(ContentSettingsType::BLUETOOTH_SCANNING); + base_types->push_back(ContentSettingsType::WINDOW_PLACEMENT); + } + + if (base::FeatureList::IsEnabled(::features::kServiceWorkerPaymentApps)) + base_types->push_back(ContentSettingsType::PAYMENT_HANDLER); + + if (base::FeatureList::IsEnabled( + features::kWebBluetoothNewPermissionsBackend)) { + base_types->push_back(ContentSettingsType::BLUETOOTH_GUARD); + } + + if (base::FeatureList::IsEnabled( + subresource_filter::kSafeBrowsingSubresourceFilter)) { + base_types->push_back(ContentSettingsType::ADS); + } + + initialized = true; } - return content_types; + + return *base_types; +} + +std::vector<ContentSettingsType> GetVisiblePermissionCategoriesForOrigin( + Profile* profile, + const GURL& origin) { + const std::vector<ContentSettingsType>& base_types = + GetVisiblePermissionCategories(); + std::vector<ContentSettingsType> types_for_origin; + std::copy_if( + base_types.begin(), base_types.end(), + std::back_inserter(types_for_origin), + [&profile, &origin](ContentSettingsType type) { + // File Handling is only relevant for installed PWAs that ask for + // certain file types; if this is not the case, the control will do + // nothing and thus is hidden. + if (type == ContentSettingsType::FILE_HANDLING && + web_app::GetFileHandlersForAllWebAppsWithOrigin(profile, origin) + .empty()) { + return false; + } + return true; + }); + return types_for_origin; } std::string SiteSettingSourceToString(const SiteSettingSource source) {
diff --git a/chrome/browser/ui/webui/settings/site_settings_helper.h b/chrome/browser/ui/webui/settings/site_settings_helper.h index 817b2b0..685203f 100644 --- a/chrome/browser/ui/webui/settings/site_settings_helper.h +++ b/chrome/browser/ui/webui/settings/site_settings_helper.h
@@ -112,9 +112,17 @@ ContentSettingsType ContentSettingsTypeFromGroupName(base::StringPiece name); base::StringPiece ContentSettingsTypeToGroupName(ContentSettingsType type); -// Converts a ListValue of group names to a list of ContentSettingsTypes -std::vector<ContentSettingsType> ContentSettingsTypesFromGroupNames( - const base::Value::ConstListView types); +// Returns a list of all content settings types that correspond to permissions +// and which should be displayed in chrome://settings, for any situation not +// tied to particular a origin. +const std::vector<ContentSettingsType>& GetVisiblePermissionCategories(); + +// Returns a list of all content settings types that correspond to permissions +// and which should be displayed in chrome://settings for the given |origin|. +// This will not include categories that are not relevant for the given origin. +std::vector<ContentSettingsType> GetVisiblePermissionCategoriesForOrigin( + Profile* profile, + const GURL& origin); // Converts a SiteSettingSource to its string identifier. std::string SiteSettingSourceToString(const SiteSettingSource source);
diff --git a/chrome/browser/web_applications/README.md b/chrome/browser/web_applications/README.md index b0ba8f57b..1a865bd 100644 --- a/chrome/browser/web_applications/README.md +++ b/chrome/browser/web_applications/README.md
@@ -125,9 +125,20 @@ ## What makes up Chromium's implementation? -The task of turning web sites into "apps" in the user's OS environment has -surprisingly many parts to it. Here are some (but not all) of the key ones. +The task of turning web sites into "apps" in the user's OS environment has many parts to it. Before going into the parts, here is where they live: +[](https://docs.google.com/drawings/d/1TqUF2Pqh2S5qPGyA6njQWxOgSgKQBPePKPIH_srGeRk/edit?usp=sharing) + +* The `WebAppProvider` core system lives on the `Profile` object. +* The `WebAppUiManagerImpl` also lives on the `Profile` object (to avoid deps issues). +* The `AppBrowserController` (typically `WebAppBrowserController` for our interests) lives on the `Browser` object. +* The `WebAppTabHelperBase` lives on the `WebContents` object. + +While most on-disk storage is done in the [`WebAppSyncBridge`](#webappsyncbridge), the system also sometimes uses the `PrefService`. Most of these prefs live on the `Profile` (`profile->GetPrefs()`), but some prefs are in the global browser prefs (`g_browser_process->local_state()`). See the [storage](#storage) section below for more info. + +There is a presentation that also goes over the class structure and dependency diagram [here](https://docs.google.com/presentation/d/1bJfUFPMh7J_Avw3J4HBvAN2RWnV4T9LOXr0JSAgQAvg/pub), but it may be out of date. + +Here is more info for some (but not all) of the key parts: ### [`WebAppProvider`](web_app_provider.h) @@ -154,6 +165,20 @@ `Extension`s and in that mode there were no `WebApp`s; instead everything was stored on an `Extension`. +### [`WebAppSyncBridge`](web_app_sync_bridge.h) + +This is "bridge" between the WebAppProvider system's in-memory representation of web apps and the sync system's database representation (along with sync system functionality like add/remove/modify operations). This integration is a little complex and deserves it's own document, but it basically: +* Stores all WebApps into a database and updates the database if any fields change. +* Updates the system when there are changes from the sync system. + * Installs new apps, uninstalls apps the user uninstalled elsewhere, updates metadata like user display mode preference, etc. +* Tells the sync system if there are local changes (installs, uninstalls, etc). + +There is also a slide in a presentation [here](https://docs.google.com/presentation/d/e/2PACX-1vQxYZoCyhZ4xHS4pVuBC9YoE0O-QpW2Wj3scl6jtr3TEYheeod5Ch4b7OVEQEj_Hc6PM1RBGzovug3C/pub?start=false&loop=false&delayms=3000&slide=id.g59d9cb05b6_6_5) which illustrates how this system works, but it may be out of date. + +Note: This only stores per-web-app data, and that data will be deleted if the web app is uninstalled. To store data that persists after uninstall, or applies to a more general scope than a single web app, then the `PrefService` can be used, either on the `Profile` object (per-profile data, `profile->GetPrefs()`) or on the browser process (`g_browser_process->local_state()`). Example of needing prefs: +* Storing if an app was previously installed as a preinstalled app in the past. +* Information is needed during chrome startup before profiles are loaded. +* A feature needs to store global data - e.g. "When was the last time we showed the in-product-help banner for any webapp?" ### [`WebAppInstallManager`](web_app_install_manager.h) @@ -197,6 +222,10 @@ [`WebAppUiManager::Create()`](https://source.chromium.org/search?q=WebAppUiManager::Create)'s declaration and definition locations). +## Storage + +TODO + ## Deep Dives * [Installation Sources & Pipeline](docs/installation_pipeline.md)
diff --git a/chrome/browser/web_applications/components/url_handler_prefs.cc b/chrome/browser/web_applications/components/url_handler_prefs.cc index 7312551..eabbe8f 100644 --- a/chrome/browser/web_applications/components/url_handler_prefs.cc +++ b/chrome/browser/web_applications/components/url_handler_prefs.cc
@@ -8,6 +8,8 @@ #include "base/check.h" #include "base/files/file_path.h" +#include "base/ranges/algorithm.h" +#include "base/ranges/functional.h" #include "base/strings/strcat.h" #include "base/strings/string_piece.h" #include "base/strings/string_util.h" @@ -210,45 +212,35 @@ if (exclude_paths_exist && ExcludePathMatches(url_path, *exclude_paths)) continue; - // Do not include a match if it should open in a normal browser tab. - if (best_choice == UrlHandlerSavedChoice::kInBrowser) - continue; - matches.emplace_back(*profile_path, *app_id, url, best_choice, latest_timestamp); } } -// If one or more match should open in app, keep the most recent one and remove -// the others. Also remove matches with no saved choice. -// Otherwise, any remaining matches should all have no saved choice. -// Any match that should open in browser have already been removed and should -// not be found in |matches|. +// Find the most recent match. If it is saved as kInBrowser, preferred choice +// is the browser so no matches should be returned; If saved as kNone, all the +// matches should be returned so the user can make a new saved choice; If +// kInApp, only returned the app match as it is the saved choice. void FilterBySavedChoice(std::vector<UrlHandlerLaunchParams>& matches) { - for (const UrlHandlerLaunchParams& params : matches) - DCHECK(params.saved_choice != UrlHandlerSavedChoice::kInBrowser); + if (matches.empty()) + return; - // Are there matches that open in app? Which is the most recently saved? - bool has_in_app = false; - base::Time most_recent_time = base::Time::Min(); - size_t most_recent_pos = 0; - for (size_t i = 0; i < matches.size(); i++) { - const UrlHandlerLaunchParams& params = matches[i]; - if (params.saved_choice == UrlHandlerSavedChoice::kInApp) { - has_in_app = true; - if (params.saved_choice_timestamp > most_recent_time) { - most_recent_time = params.saved_choice_timestamp; - most_recent_pos = i; - } - } + // Record the most recent match. + auto most_recent_match_iterator = base::ranges::max_element( + matches, base::ranges::less(), + &UrlHandlerLaunchParams::saved_choice_timestamp); + + switch (most_recent_match_iterator->saved_choice) { + case UrlHandlerSavedChoice::kInApp: + matches = {std::move(*most_recent_match_iterator)}; + break; + case UrlHandlerSavedChoice::kInBrowser: + matches = {}; + break; + case UrlHandlerSavedChoice::kNone: + // `matches` already contain all matches. Do not modify. + break; } - - // Only keep the most recently saved match that opens in app. - if (has_in_app) - matches = {std::move(matches[most_recent_pos])}; - - // Since no matches opened in browser to begin with and now no matches open in - // app, any remaining matches must have no saved choice. } void FindMatchesImpl(const base::Value& pref_value, @@ -315,8 +307,8 @@ return matches; } -base::Value GetIncludePathsValue( - const std::vector<std::string>& include_paths) { +base::Value GetIncludePathsValue(const std::vector<std::string>& include_paths, + const base::Time& time) { base::Value value(base::Value::Type::LIST); // When no "paths" are specified in web-app-origin-association, all include // paths are allowed. @@ -327,7 +319,7 @@ path_dict.SetStringKey(kPath, include_path); path_dict.SetIntKey(kChoice, static_cast<int>(UrlHandlerSavedChoice::kNone)); - path_dict.SetKey(kTimestamp, util::TimeToValue(base::Time::Min())); + path_dict.SetKey(kTimestamp, util::TimeToValue(time)); value.Append(std::move(path_dict)); } return value; @@ -344,13 +336,14 @@ base::Value NewHandler(const AppId& app_id, const base::FilePath& profile_path, - const apps::UrlHandlerInfo& info) { + const apps::UrlHandlerInfo& info, + const base::Time& time) { base::Value value(base::Value::Type::DICTIONARY); value.SetStringKey(kAppId, app_id); value.SetKey(kProfilePath, util::FilePathToValue(profile_path)); value.SetBoolKey(kHasOriginWildcard, info.has_origin_wildcard); // Set include_paths and exclude paths from associated app. - value.SetKey(kIncludePaths, GetIncludePathsValue(info.paths)); + value.SetKey(kIncludePaths, GetIncludePathsValue(info.paths, time)); value.SetKey(kExcludePaths, GetExcludePathsValue(info.exclude_paths)); return value; } @@ -520,7 +513,8 @@ void AddWebApp(PrefService* local_state, const AppId& app_id, const base::FilePath& profile_path, - const apps::UrlHandlers& url_handlers) { + const apps::UrlHandlers& url_handlers, + const base::Time& time) { if (profile_path.empty() || url_handlers.empty()) return; @@ -534,7 +528,8 @@ if (origin.opaque()) continue; - base::Value new_handler(NewHandler(app_id, profile_path, handler_info)); + base::Value new_handler( + NewHandler(app_id, profile_path, handler_info, time)); base::Value* const handlers_mutable = pref_value->FindListKey(origin.Serialize()); // One or more apps are already associated with this origin.
diff --git a/chrome/browser/web_applications/components/url_handler_prefs.h b/chrome/browser/web_applications/components/url_handler_prefs.h index 156c4606..1512dc5 100644 --- a/chrome/browser/web_applications/components/url_handler_prefs.h +++ b/chrome/browser/web_applications/components/url_handler_prefs.h
@@ -78,7 +78,8 @@ void AddWebApp(PrefService* local_state, const AppId& app_id, const base::FilePath& profile_path, - const apps::UrlHandlers& url_handlers); + const apps::UrlHandlers& url_handlers, + const base::Time& time = base::Time::Now()); void UpdateWebApp(PrefService* local_state, const AppId& app_id, @@ -95,12 +96,12 @@ void Clear(PrefService* local_state); // Search for all (app, profile) combinations that have active URL handlers -// which matches |url|. -// If there are results with saved_choice == kInApp, only the one with the most -// recent timestamp is returned. Otherwise, if there results with saved_choice -// == kNone, all of those will be returned. No results with saved_choiced == -// kInBrowser will be returned in any case. -// |url| is a fully specified URL, eg. "https://contoso.com/abc/def". +// which matches `url`. +// `url` is a fully specified URL, eg. "https://contoso.com/abc/def". +// If the most recent match is saved as kInApp, only it will be returned; +// If saved as kNone, all the matches regardless of saved_choice value are +// returned; If saved as kInBrowser, the return value is empty as the preferred +// choice is the browser. std::vector<UrlHandlerLaunchParams> FindMatchingUrlHandlers( PrefService* local_state, const GURL& url);
diff --git a/chrome/browser/web_applications/components/url_handler_prefs_unittest.cc b/chrome/browser/web_applications/components/url_handler_prefs_unittest.cc index e7d87ef1..46d6cfbe 100644 --- a/chrome/browser/web_applications/components/url_handler_prefs_unittest.cc +++ b/chrome/browser/web_applications/components/url_handler_prefs_unittest.cc
@@ -705,14 +705,14 @@ const auto web_app = WebAppWithUrlHandlers( app_url_1_, {apps::UrlHandlerInfo(origin_1_, false, {}, {})}); url_handler_prefs::AddWebApp(LocalState(), web_app->app_id(), profile_1_, - web_app->url_handlers()); + web_app->url_handlers(), time_1_); { // Check default choice and timestamp. auto matches = url_handler_prefs::FindMatchingUrlHandlers(LocalState(), origin_url_1_); ASSERT_EQ(1u, matches.size()); EXPECT_EQ(matches[0].saved_choice, UrlHandlerSavedChoice::kNone); - EXPECT_EQ(matches[0].saved_choice_timestamp, base::Time::Min()); + EXPECT_EQ(matches[0].saved_choice_timestamp, time_1_); } // Save choice as UrlHandlerSavedChoice::kInApp. url_handler_prefs::SaveOpenInApp(LocalState(), web_app->app_id(), profile_1_, @@ -733,17 +733,17 @@ app_url_1_, {apps::UrlHandlerInfo(origin_1_, false, {"/abc", "/def"}, {})}); url_handler_prefs::AddWebApp(LocalState(), web_app->app_id(), profile_1_, - web_app->url_handlers()); + web_app->url_handlers(), time_1_); // Save choice as UrlHandlerSavedChoice::kInApp to "/abc" path. url_handler_prefs::SaveOpenInApp(LocalState(), web_app->app_id(), profile_1_, - origin_1_.GetURL().Resolve("abc"), time_1_); + origin_1_.GetURL().Resolve("abc"), time_2_); { // Check saved choice and timestamp. auto matches = url_handler_prefs::FindMatchingUrlHandlers( LocalState(), origin_1_.GetURL().Resolve("abc")); ASSERT_EQ(1u, matches.size()); EXPECT_EQ(matches[0].saved_choice, UrlHandlerSavedChoice::kInApp); - EXPECT_EQ(matches[0].saved_choice_timestamp, time_1_); + EXPECT_EQ(matches[0].saved_choice_timestamp, time_2_); } { // Check unaffected path. @@ -751,7 +751,7 @@ LocalState(), origin_1_.GetURL().Resolve("def")); ASSERT_EQ(1u, matches.size()); EXPECT_EQ(matches[0].saved_choice, UrlHandlerSavedChoice::kNone); - EXPECT_EQ(matches[0].saved_choice_timestamp, base::Time::Min()); + EXPECT_EQ(matches[0].saved_choice_timestamp, time_1_); } } @@ -783,21 +783,23 @@ app_url_1_, {apps::UrlHandlerInfo(origin_1_, false, {"/a", "/b"}, {"/x"})}); url_handler_prefs::AddWebApp(LocalState(), web_app->app_id(), profile_1_, - web_app->url_handlers()); + web_app->url_handlers(), time_1_); // Save choice as UrlHandlerSavedChoice::kInApp for "/a" path. url_handler_prefs::SaveOpenInApp(LocalState(), web_app->app_id(), profile_1_, - origin_1_.GetURL().Resolve("a"), time_1_); + origin_1_.GetURL().Resolve("a"), time_2_); { auto matches = url_handler_prefs::FindMatchingUrlHandlers( LocalState(), origin_1_.GetURL().Resolve("a")); ASSERT_EQ(1u, matches.size()); EXPECT_EQ(matches[0].saved_choice, UrlHandlerSavedChoice::kInApp); + EXPECT_EQ(matches[0].saved_choice_timestamp, time_2_); } { auto matches = url_handler_prefs::FindMatchingUrlHandlers( LocalState(), origin_1_.GetURL().Resolve("b")); ASSERT_EQ(1u, matches.size()); EXPECT_EQ(matches[0].saved_choice, UrlHandlerSavedChoice::kNone); + EXPECT_EQ(matches[0].saved_choice_timestamp, time_1_); } { auto matches = url_handler_prefs::FindMatchingUrlHandlers( @@ -842,9 +844,9 @@ app_url_2_, {apps::UrlHandlerInfo(origin_1_, false, {"/*"}, {})}); url_handler_prefs::AddWebApp(LocalState(), web_app_1->app_id(), profile_1_, - web_app_1->url_handlers()); + web_app_1->url_handlers(), time_1_); url_handler_prefs::AddWebApp(LocalState(), web_app_2->app_id(), profile_1_, - web_app_2->url_handlers()); + web_app_2->url_handlers(), time_1_); { // Both apps should match the input URL. auto matches = @@ -852,13 +854,13 @@ ASSERT_EQ(2u, matches.size()); EXPECT_EQ(matches[0].app_id, web_app_1->app_id()); EXPECT_EQ(matches[0].saved_choice, UrlHandlerSavedChoice::kNone); - EXPECT_EQ(matches[0].saved_choice_timestamp, base::Time::Min()); + EXPECT_EQ(matches[0].saved_choice_timestamp, time_1_); EXPECT_EQ(matches[1].app_id, web_app_2->app_id()); EXPECT_EQ(matches[1].saved_choice, UrlHandlerSavedChoice::kNone); - EXPECT_EQ(matches[1].saved_choice_timestamp, base::Time::Min()); + EXPECT_EQ(matches[1].saved_choice_timestamp, time_1_); } url_handler_prefs::SaveOpenInApp(LocalState(), web_app_1->app_id(), - profile_1_, origin_url_1_, time_1_); + profile_1_, origin_url_1_, time_2_); { // Only the app with a path saved as UrlHandlerSavedChoice::kInApp is // returned from matching. @@ -867,7 +869,7 @@ ASSERT_EQ(1u, matches.size()); EXPECT_EQ(matches[0].app_id, web_app_1->app_id()); EXPECT_EQ(matches[0].saved_choice, UrlHandlerSavedChoice::kInApp); - EXPECT_EQ(matches[0].saved_choice_timestamp, time_1_); + EXPECT_EQ(matches[0].saved_choice_timestamp, time_2_); } } @@ -878,11 +880,11 @@ app_url_2_, {apps::UrlHandlerInfo(origin_1_, false, {"/*"}, {})}); url_handler_prefs::AddWebApp(LocalState(), web_app_1->app_id(), profile_1_, - web_app_1->url_handlers()); + web_app_1->url_handlers(), time_1_); url_handler_prefs::AddWebApp(LocalState(), web_app_2->app_id(), profile_1_, - web_app_2->url_handlers()); + web_app_2->url_handlers(), time_1_); - url_handler_prefs::SaveOpenInBrowser(LocalState(), origin_url_1_, time_1_); + url_handler_prefs::SaveOpenInBrowser(LocalState(), origin_url_1_, time_2_); { auto matches = url_handler_prefs::FindMatchingUrlHandlers(LocalState(), origin_url_1_); @@ -924,4 +926,78 @@ } } +TEST_F(UrlHandlerPrefsTest, SaveUserChoiceInAppAndInstallNewApp) { + const auto web_app_1 = WebAppWithUrlHandlers( + app_url_1_, {apps::UrlHandlerInfo(origin_1_, false, {"/abc"}, {})}); + url_handler_prefs::AddWebApp(LocalState(), web_app_1->app_id(), profile_1_, + web_app_1->url_handlers(), time_1_); + // Save choice as UrlHandlerSavedChoice::kInApp to "/abc" path. + url_handler_prefs::SaveOpenInApp(LocalState(), web_app_1->app_id(), + profile_1_, + origin_1_.GetURL().Resolve("abc"), time_1_); + { + // Check saved choice. + auto matches = url_handler_prefs::FindMatchingUrlHandlers( + LocalState(), origin_1_.GetURL().Resolve("abc")); + ASSERT_EQ(1u, matches.size()); + EXPECT_EQ(matches.front().saved_choice, UrlHandlerSavedChoice::kInApp); + EXPECT_EQ(matches.front().app_id, web_app_1->app_id()); + EXPECT_EQ(matches.front().saved_choice_timestamp, time_1_); + } + + // Install another app. + const auto web_app_2 = WebAppWithUrlHandlers( + app_url_2_, {apps::UrlHandlerInfo(origin_1_, false, {"/abc"}, {})}); + url_handler_prefs::AddWebApp(LocalState(), web_app_2->app_id(), profile_1_, + web_app_2->url_handlers(), time_2_); + { + // Check now there should be two matches. + auto matches = url_handler_prefs::FindMatchingUrlHandlers( + LocalState(), origin_1_.GetURL().Resolve("abc")); + ASSERT_EQ(2u, matches.size()); + } + + // Save the new app as the default choice. + url_handler_prefs::SaveOpenInApp(LocalState(), web_app_2->app_id(), + profile_1_, + origin_1_.GetURL().Resolve("abc"), time_2_); + { + // Verify the new saved choice. + auto matches = url_handler_prefs::FindMatchingUrlHandlers( + LocalState(), origin_1_.GetURL().Resolve("abc")); + ASSERT_EQ(1u, matches.size()); + EXPECT_EQ(matches.front().saved_choice, UrlHandlerSavedChoice::kInApp); + EXPECT_EQ(matches.front().app_id, web_app_2->app_id()); + EXPECT_EQ(matches.front().saved_choice_timestamp, time_2_); + } +} + +TEST_F(UrlHandlerPrefsTest, SaveUserChoiceInBrowserAndInstallNewApp) { + const auto web_app_1 = WebAppWithUrlHandlers( + app_url_1_, {apps::UrlHandlerInfo(origin_1_, false, {"/abc"}, {})}); + url_handler_prefs::AddWebApp(LocalState(), web_app_1->app_id(), profile_1_, + web_app_1->url_handlers(), time_1_); + // Save choice to open in browser. + url_handler_prefs::SaveOpenInBrowser( + LocalState(), origin_1_.GetURL().Resolve("abc"), time_1_); + { + // Check saved choice. + auto matches = url_handler_prefs::FindMatchingUrlHandlers( + LocalState(), origin_1_.GetURL().Resolve("abc")); + ASSERT_EQ(0u, matches.size()); + } + + // Install another app. + const auto web_app_2 = WebAppWithUrlHandlers( + app_url_2_, {apps::UrlHandlerInfo(origin_1_, false, {"/abc"}, {})}); + url_handler_prefs::AddWebApp(LocalState(), web_app_2->app_id(), profile_1_, + web_app_2->url_handlers(), time_2_); + { + // Check there are now two matches. + auto matches = url_handler_prefs::FindMatchingUrlHandlers( + LocalState(), origin_1_.GetURL().Resolve("abc")); + ASSERT_EQ(2u, matches.size()); + } +} + } // namespace web_app
diff --git a/chrome/browser/web_applications/components/web_app_install_utils.cc b/chrome/browser/web_applications/components/web_app_install_utils.cc index 3b2c26f..2f97b699 100644 --- a/chrome/browser/web_applications/components/web_app_install_utils.cc +++ b/chrome/browser/web_applications/components/web_app_install_utils.cc
@@ -307,6 +307,8 @@ if (manifest_url.is_valid()) web_app_info->manifest_url = manifest_url; + + web_app_info->is_storage_isolated = manifest.isolated_storage; } std::vector<GURL> GetValidIconUrlsToDownload(
diff --git a/chrome/browser/web_applications/components/web_app_utils.cc b/chrome/browser/web_applications/components/web_app_utils.cc index 900b16a5..2d8b2ef 100644 --- a/chrome/browser/web_applications/components/web_app_utils.cc +++ b/chrome/browser/web_applications/components/web_app_utils.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/web_applications/components/web_app_utils.h" +#include "base/containers/contains.h" #include "base/files/file_path.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" @@ -152,6 +153,37 @@ #endif } +bool AreFileHandlersAlreadyRegistered( + Profile* profile, + const GURL& url, + const std::vector<blink::Manifest::FileHandler>& new_handlers) { + if (new_handlers.empty()) + return true; + + const apps::FileHandlers old_handlers = + GetFileHandlersForAllWebAppsWithOrigin(profile, url); + const std::set<std::string> mime_types_set = + apps::GetMimeTypesFromFileHandlers(old_handlers); + const std::set<std::string> extensions_set = + apps::GetFileExtensionsFromFileHandlers(old_handlers); + + for (const blink::Manifest::FileHandler& new_handler : new_handlers) { + for (const auto& new_handler_accept : new_handler.accept) { + if (!base::Contains(mime_types_set, + base::UTF16ToUTF8(new_handler_accept.first))) { + return false; + } + + for (const auto& new_extension : new_handler_accept.second) { + if (!base::Contains(extensions_set, base::UTF16ToUTF8(new_extension))) + return false; + } + } + } + + return true; +} + apps::FileHandlers GetFileHandlersForAllWebAppsWithOrigin(Profile* profile, const GURL& url) { auto* provider = WebAppProviderBase::GetProviderBase(profile);
diff --git a/chrome/browser/web_applications/components/web_app_utils.h b/chrome/browser/web_applications/components/web_app_utils.h index 3c59b0d..7d63b10 100644 --- a/chrome/browser/web_applications/components/web_app_utils.h +++ b/chrome/browser/web_applications/components/web_app_utils.h
@@ -10,6 +10,7 @@ #include "chrome/browser/web_applications/components/web_app_id.h" #include "components/services/app_service/public/cpp/file_handler.h" +#include "third_party/blink/public/common/manifest/manifest.h" class GURL; class Profile; @@ -75,6 +76,16 @@ // Returns true if sync should install web apps locally by default. bool AreAppsLocallyInstalledBySync(); +// Returns true if `new_handlers` are effectively the same or less broad than +// the file handlers for PWAs installed under the same origin as `url` in +// `profile`. In other words, if `new_handlers` would not change the text +// returned by `GetFileHandlersForAllWebAppsWithOrigin()`, then this will return +// true, otherwise false. +bool AreFileHandlersAlreadyRegistered( + Profile* profile, + const GURL& url, + const std::vector<blink::Manifest::FileHandler>& new_handlers); + // Returns all file handlers associated with any apps at the origin of `url`, in // the `profile`. This is not limited to a particular app's scope because it's // used for display in permissions contexts, and permissions are origin-bound.
diff --git a/chrome/browser/web_applications/components/web_application_info.h b/chrome/browser/web_applications/components/web_application_info.h index f32210f..0ac5b9f1 100644 --- a/chrome/browser/web_applications/components/web_application_info.h +++ b/chrome/browser/web_applications/components/web_application_info.h
@@ -277,6 +277,9 @@ // scope. blink::mojom::CaptureLinks capture_links = blink::mojom::CaptureLinks::kUndefined; + + // Whether the app should be loaded in a dedicated storage partition. + bool is_storage_isolated = false; }; std::ostream& operator<<(std::ostream& out,
diff --git a/chrome/browser/web_applications/docs/webappprovider_component_ownership.jpg b/chrome/browser/web_applications/docs/webappprovider_component_ownership.jpg new file mode 100644 index 0000000..9fbf633e --- /dev/null +++ b/chrome/browser/web_applications/docs/webappprovider_component_ownership.jpg Binary files differ
diff --git a/chrome/browser/web_applications/externally_managed_app_manager_impl_browsertest.cc b/chrome/browser/web_applications/externally_managed_app_manager_impl_browsertest.cc index dace874..d85b5ad 100644 --- a/chrome/browser/web_applications/externally_managed_app_manager_impl_browsertest.cc +++ b/chrome/browser/web_applications/externally_managed_app_manager_impl_browsertest.cc
@@ -218,6 +218,7 @@ IN_PROC_BROWSER_TEST_F(ExternallyManagedAppManagerImplBrowserTest, ForceReinstall) { ASSERT_TRUE(embedded_test_server()->Start()); + absl::optional<AppId> app_id; { GURL url(embedded_test_server()->GetURL( "/banners/" @@ -226,7 +227,7 @@ install_options.force_reinstall = true; InstallApp(std::move(install_options)); - absl::optional<AppId> app_id = registrar().FindAppWithUrlInScope(url); + app_id = registrar().FindAppWithUrlInScope(url); EXPECT_TRUE(app_id.has_value()); EXPECT_EQ("Manifest", registrar().GetAppShortName(app_id.value())); } @@ -237,9 +238,11 @@ install_options.force_reinstall = true; InstallApp(std::move(install_options)); - absl::optional<AppId> app_id = registrar().FindAppWithUrlInScope(url); - EXPECT_TRUE(app_id.has_value()); - EXPECT_EQ("Manifest test app", registrar().GetAppShortName(app_id.value())); + absl::optional<AppId> new_app_id = registrar().FindAppWithUrlInScope(url); + EXPECT_TRUE(new_app_id.has_value()); + EXPECT_EQ(new_app_id, app_id); + EXPECT_EQ("Manifest test app", + registrar().GetAppShortName(new_app_id.value())); } }
diff --git a/chrome/browser/web_applications/manifest_update_manager_browsertest.cc b/chrome/browser/web_applications/manifest_update_manager_browsertest.cc index 07349d7..c125a4a 100644 --- a/chrome/browser/web_applications/manifest_update_manager_browsertest.cc +++ b/chrome/browser/web_applications/manifest_update_manager_browsertest.cc
@@ -1577,7 +1577,7 @@ } IN_PROC_BROWSER_TEST_F(ManifestUpdateManagerBrowserTestWithFileHandling, - AllowedPermissionResetToAskOnUpdate) { + FileHandlingPermissionResetsOnUpdate) { constexpr char kFileHandlerManifestTemplate[] = R"( { "name": "Test app name", @@ -1593,12 +1593,18 @@ } } ], - "icons": $2 + "icons": [ + { + "src": "launcher-icon-4x.png", + "sizes": "192x192", + "type": "image/png" + } + ], + "theme_color": "$2" } )"; - OverrideManifest(kFileHandlerManifestTemplate, - {".txt", kInstallableIconList}); + OverrideManifest(kFileHandlerManifestTemplate, {".txt", "red"}); AppId app_id = InstallWebApp(); const WebApp* web_app = GetProvider().registrar().AsWebAppRegistrar()->GetAppById(app_id); @@ -1619,18 +1625,66 @@ EXPECT_EQ(CONTENT_SETTING_ALLOW, map->GetContentSetting(origin, origin, ContentSettingsType::FILE_HANDLING)); - // Update manifest. - OverrideManifest(kFileHandlerManifestTemplate, {".md", kInstallableIconList}); + // Update manifest, adding an extension to the file handler. Permission should + // be downgraded to ASK. The time override is necessary to make sure the + // manifest update isn't skipped due to throttling. + base::Time time_override = base::Time::Now(); + SetTimeOverride(time_override); + OverrideManifest(kFileHandlerManifestTemplate, {".md\", \".txt", "red"}); EXPECT_EQ(ManifestUpdateResult::kAppUpdated, GetResultAfterPageLoad(url, &app_id)); - const auto& new_file_handler = web_app->file_handlers()[0]; - auto new_extensions = new_file_handler.accept[0].file_extensions; + auto new_extensions = web_app->file_handlers()[0].accept[0].file_extensions; EXPECT_TRUE(base::Contains(new_extensions, ".md")); - - // Confirm permission is downgraded to ASK after manifest update. + EXPECT_TRUE(base::Contains(new_extensions, ".txt")); EXPECT_EQ(CONTENT_SETTING_ASK, map->GetContentSetting(origin, origin, ContentSettingsType::FILE_HANDLING)); + + // Set permission to ALLOW. + map->SetContentSettingDefaultScope(origin, origin, + ContentSettingsType::FILE_HANDLING, + CONTENT_SETTING_ALLOW); + + // Update manifest, but keep same file handlers. Permission should be left on + // ALLOW. + time_override += base::TimeDelta::FromDays(10); + SetTimeOverride(time_override); + OverrideManifest(kFileHandlerManifestTemplate, {".md\", \".txt", "blue"}); + EXPECT_EQ(ManifestUpdateResult::kAppUpdated, + GetResultAfterPageLoad(url, &app_id)); + new_extensions = web_app->file_handlers()[0].accept[0].file_extensions; + EXPECT_TRUE(base::Contains(new_extensions, ".md")); + EXPECT_TRUE(base::Contains(new_extensions, ".txt")); + EXPECT_EQ(CONTENT_SETTING_ALLOW, + map->GetContentSetting(origin, origin, + ContentSettingsType::FILE_HANDLING)); + + // Update manifest, asking for /fewer/ file types. Permission should be left + // on ALLOW. + time_override += base::TimeDelta::FromDays(10); + SetTimeOverride(time_override); + OverrideManifest(kFileHandlerManifestTemplate, {".txt", "blue"}); + EXPECT_EQ(ManifestUpdateResult::kAppUpdated, + GetResultAfterPageLoad(url, &app_id)); + new_extensions = web_app->file_handlers()[0].accept[0].file_extensions; + EXPECT_FALSE(base::Contains(new_extensions, ".md")); + EXPECT_TRUE(base::Contains(new_extensions, ".txt")); + EXPECT_EQ(CONTENT_SETTING_ALLOW, + map->GetContentSetting(origin, origin, + ContentSettingsType::FILE_HANDLING)); + + // Block the permission, update manifest, permission should still be block. + map->SetContentSettingDefaultScope(origin, origin, + ContentSettingsType::FILE_HANDLING, + CONTENT_SETTING_BLOCK); + OverrideManifest(kFileHandlerManifestTemplate, {".txt", "red"}); + time_override += base::TimeDelta::FromDays(10); + SetTimeOverride(time_override); + EXPECT_EQ(ManifestUpdateResult::kAppUpdated, + GetResultAfterPageLoad(url, &app_id)); + EXPECT_EQ(CONTENT_SETTING_BLOCK, + map->GetContentSetting(origin, origin, + ContentSettingsType::FILE_HANDLING)); } IN_PROC_BROWSER_TEST_F(ManifestUpdateManagerBrowserTestWithFileHandling,
diff --git a/chrome/browser/web_applications/manifest_update_task.cc b/chrome/browser/web_applications/manifest_update_task.cc index 632c477..078240d 100644 --- a/chrome/browser/web_applications/manifest_update_task.cc +++ b/chrome/browser/web_applications/manifest_update_task.cc
@@ -358,6 +358,8 @@ return true; } + // TODO(crbug.com/1212849): Handle changes to is_storage_isolated. + // TODO(crbug.com/926083): Check more manifest fields. return false; }
diff --git a/chrome/browser/web_applications/proto/web_app.proto b/chrome/browser/web_applications/proto/web_app.proto index 63d51363..828c2207 100644 --- a/chrome/browser/web_applications/proto/web_app.proto +++ b/chrome/browser/web_applications/proto/web_app.proto
@@ -211,4 +211,7 @@ // If present, the URL to use to create a new note in the app. optional string note_taking_new_note_url = 35; + + // Whether the app should be loaded in a dedicated storage partition. + optional bool is_storage_isolated = 36; }
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 6d7d566b..040f2a2 100644 --- a/chrome/browser/web_applications/test/web_app_test_utils.cc +++ b/chrome/browser/web_applications/test/web_app_test_utils.cc
@@ -369,6 +369,8 @@ sync_fallback_data.icon_infos = app->icon_infos(); app->SetSyncFallbackData(std::move(sync_fallback_data)); + app->SetStorageIsolated(random.next_bool()); + return app; }
diff --git a/chrome/browser/web_applications/web_app.cc b/chrome/browser/web_applications/web_app.cc index dbcb70f..dfc857e2 100644 --- a/chrome/browser/web_applications/web_app.cc +++ b/chrome/browser/web_applications/web_app.cc
@@ -305,6 +305,10 @@ window_controls_overlay_enabled_ = enabled; } +void WebApp::SetStorageIsolated(bool is_storage_isolated) { + is_storage_isolated_ = is_storage_isolated; +} + WebApp::ClientData::ClientData() = default; WebApp::ClientData::~ClientData() = default; @@ -497,6 +501,8 @@ out << "window_controls_overlay_enabled:" << std::endl << Indent(app.window_controls_overlay_enabled_) << std::endl; + out << "is_storage_isolated: " << app.is_storage_isolated_ << std::endl; + return out; } @@ -559,7 +565,8 @@ app.manifest_id_, app.client_data_.system_web_app_data, app.file_handler_permission_blocked_, - app.window_controls_overlay_enabled_ + app.window_controls_overlay_enabled_, + app.is_storage_isolated_ // clang-format on ); };
diff --git a/chrome/browser/web_applications/web_app.h b/chrome/browser/web_applications/web_app.h index 98b8efdc..c6de1b6 100644 --- a/chrome/browser/web_applications/web_app.h +++ b/chrome/browser/web_applications/web_app.h
@@ -198,6 +198,8 @@ return manifest_id_; } + bool IsStorageIsolated() const { return is_storage_isolated_; } + // A Web App can be installed from multiple sources simultaneously. Installs // add a source to the app. Uninstalls remove a source from the app. void AddSource(Source::Type source); @@ -257,6 +259,7 @@ void SetManifestId(const absl::optional<std::string>& manifest_id); void SetFileHandlerPermissionBlocked(bool permission_blocked); void SetWindowControlsOverlayEnabled(bool enabled); + void SetStorageIsolated(bool is_storage_isolated); // For logging and debug purposes. bool operator==(const WebApp&) const; @@ -319,6 +322,7 @@ absl::optional<std::string> manifest_id_; bool file_handler_permission_blocked_ = false; bool window_controls_overlay_enabled_ = false; + bool is_storage_isolated_ = false; // New fields must be added to: // - |operator==| // - |operator<<|
diff --git a/chrome/browser/web_applications/web_app_database.cc b/chrome/browser/web_applications/web_app_database.cc index 6572f68..56a5de4 100644 --- a/chrome/browser/web_applications/web_app_database.cc +++ b/chrome/browser/web_applications/web_app_database.cc
@@ -394,6 +394,8 @@ local_data->set_window_controls_overlay_enabled( web_app.window_controls_overlay_enabled()); + + local_data->set_is_storage_isolated(web_app.IsStorageIsolated()); return local_data; } @@ -806,6 +808,7 @@ web_app->SetWindowControlsOverlayEnabled( local_data.window_controls_overlay_enabled()); } + web_app->SetStorageIsolated(local_data.is_storage_isolated()); return web_app; }
diff --git a/chrome/browser/web_applications/web_app_database_unittest.cc b/chrome/browser/web_applications/web_app_database_unittest.cc index 61814020..081801d 100644 --- a/chrome/browser/web_applications/web_app_database_unittest.cc +++ b/chrome/browser/web_applications/web_app_database_unittest.cc
@@ -323,6 +323,7 @@ EXPECT_EQ(app->run_on_os_login_mode(), RunOnOsLoginMode::kNotRun); EXPECT_TRUE(app->manifest_url().is_empty()); EXPECT_FALSE(app->manifest_id().has_value()); + EXPECT_FALSE(app->IsStorageIsolated()); controller().RegisterApp(std::move(app)); Registry registry = database_factory().ReadRegistry(); @@ -383,6 +384,7 @@ EXPECT_EQ(app_copy->run_on_os_login_mode(), RunOnOsLoginMode::kNotRun); EXPECT_TRUE(app_copy->manifest_url().is_empty()); EXPECT_FALSE(app_copy->manifest_id().has_value()); + EXPECT_FALSE(app_copy->IsStorageIsolated()); } TEST_F(WebAppDatabaseTest, WebAppWithManyIcons) {
diff --git a/chrome/browser/web_applications/web_app_install_finalizer.cc b/chrome/browser/web_applications/web_app_install_finalizer.cc index da9efa8..0832123f 100644 --- a/chrome/browser/web_applications/web_app_install_finalizer.cc +++ b/chrome/browser/web_applications/web_app_install_finalizer.cc
@@ -29,6 +29,7 @@ #include "chrome/browser/web_applications/components/web_app_provider_base.h" #include "chrome/browser/web_applications/components/web_app_shortcuts_menu.h" #include "chrome/browser/web_applications/components/web_app_system_web_app_data.h" +#include "chrome/browser/web_applications/components/web_app_utils.h" #include "chrome/browser/web_applications/components/web_application_info.h" #include "chrome/browser/web_applications/manifest_update_task.h" #include "chrome/browser/web_applications/web_app.h" @@ -221,6 +222,7 @@ web_app->SetAdditionalSearchTerms(web_app_info.additional_search_terms); web_app->AddSource(source); web_app->SetIsInSyncInstall(false); + web_app->SetStorageIsolated(web_app_info.is_storage_isolated); UpdateIntWebAppPref(profile_->GetPrefs(), app_id, kLatestWebAppInstallSource, static_cast<int>(options.install_source)); @@ -231,6 +233,11 @@ app_id, web_app_info.enable_experimental_tabbed_window, /*is_user_action=*/false); + // This step is necessary in case this app shares an origin with another PWA + // which already asked for file handling permissions, and the new app asks to + // handle more file types. + MaybeResetFileHandlingPermission(web_app_info); + CommitCallback commit_callback = base::BindOnce( &WebAppInstallFinalizer::OnDatabaseCommitCompletedForInstall, weak_ptr_factory_.GetWeakPtr(), std::move(callback), app_id); @@ -644,14 +651,6 @@ if (!os_integration_manager().IsFileHandlingAPIAvailable(app_id)) return FileHandlerUpdateAction::kNoUpdate; - // TODO(https://crbug.com/1197013): Consider trying to re-use - // HaveFileHandlersChanged() results from the ManifestUpdateTask. - if (!HaveFileHandlersChanged( - /*old_handlers=*/registrar().GetAppFileHandlers(app_id), - /*new_handlers=*/web_app_info.file_handlers)) { - return FileHandlerUpdateAction::kNoUpdate; - } - const GURL& url = web_app_info.scope; // Keep in sync with chromeos::kChromeUIMediaAppURL. @@ -675,35 +674,55 @@ // It's possible we'll downgrade the permission and then fail to update OS // integrations (ex. if the disk or icon downloads fail), but this is ok // because these failures should rarely occur. - permissions::PermissionManager* permission_manager = - PermissionManagerFactory::GetForProfile( - Profile::FromBrowserContext(web_contents->GetBrowserContext())); - DCHECK(permission_manager); - // Note: Using GetPermissionStatus instead of GetPermissionStatusForFrame() - // because the relevant frame isn't available here. - permissions::PermissionResult status = - permission_manager->GetPermissionStatus( - ContentSettingsType::FILE_HANDLING, url, url); + ContentSetting content_setting = + MaybeResetFileHandlingPermission(web_app_info); - // If file handling permission is "ALLOW" during manifest update, downgrade - // to "ASK" via reset, as the user may not want to allow newly added file - // handlers, which may include more dangerous extensions. - // If the permission is "ASK" or "BLOCK", leave it as is. When permission is + // If the permission is "BLOCK", leave it as is. When permission is // "BLOCK", the `OnContentSettingChanged()` and // `DetectAndCorrectFileHandlingPermissionBlocks()` should capture the // permission change and make sure the OS and db state are in sync with the // PermissionManager permission setting. Therefore, manifest update task // should not update file handlers due to blocked permission state. - if (status.content_setting == CONTENT_SETTING_ALLOW) { - permission_manager->ResetPermission(content::PermissionType::FILE_HANDLING, - url, url); - } else if (status.content_setting == CONTENT_SETTING_BLOCK) { - DCHECK(registrar().IsAppFileHandlerPermissionBlocked(app_id)); + if (content_setting == CONTENT_SETTING_BLOCK) + return FileHandlerUpdateAction::kNoUpdate; + + // TODO(https://crbug.com/1197013): Consider trying to re-use + // HaveFileHandlersChanged() results from the ManifestUpdateTask. + if (!HaveFileHandlersChanged( + /*old_handlers=*/registrar().GetAppFileHandlers(app_id), + /*new_handlers=*/web_app_info.file_handlers)) { return FileHandlerUpdateAction::kNoUpdate; } + return FileHandlerUpdateAction::kUpdate; } +ContentSetting WebAppInstallFinalizer::MaybeResetFileHandlingPermission( + const WebApplicationInfo& web_app_info) { + permissions::PermissionManager* permission_manager = + PermissionManagerFactory::GetForProfile(profile_); + DCHECK(permission_manager); + const GURL& url = web_app_info.scope; + // Note: Since a frame is not available, using GetPermissionStatus() instead + // of GetPermissionStatusForFrame(). + permissions::PermissionResult status = + permission_manager->GetPermissionStatus( + ContentSettingsType::FILE_HANDLING, url, url); + + // If file handling permission is "ALLOW", downgrade to "ASK" via reset, as + // the user may not want to allow newly added file handlers, which may include + // more dangerous extensions. + if (status.content_setting == CONTENT_SETTING_ALLOW && + !AreFileHandlersAlreadyRegistered(profile_, url, + web_app_info.file_handlers)) { + permission_manager->ResetPermission(content::PermissionType::FILE_HANDLING, + url, url); + return CONTENT_SETTING_ASK; + } + + return status.content_setting; +} + void WebAppInstallFinalizer::OnDatabaseCommitCompletedForUpdate( InstallFinalizedCallback callback, AppId app_id,
diff --git a/chrome/browser/web_applications/web_app_install_finalizer.h b/chrome/browser/web_applications/web_app_install_finalizer.h index 5638596..88abcd7 100644 --- a/chrome/browser/web_applications/web_app_install_finalizer.h +++ b/chrome/browser/web_applications/web_app_install_finalizer.h
@@ -105,7 +105,9 @@ const AppId app_id, const WebApplicationInfo& web_app_info, std::unique_ptr<ShortcutInfo> old_shortcut); + bool ShouldUpdateOsHooks(const AppId& app_id); + // Checks whether OS registered file handlers need to update, taking into // account permission settings, as file handlers should be unregistered // when the permission has been denied. Also, downgrades granted file handling @@ -114,6 +116,15 @@ const AppId app_id, const WebApplicationInfo& web_app_info, content::WebContents* web_contents); + + // Resets the FILE_HANDLING content setting permission if `web_app_info` is + // asking for more file handling types than were previously granted to the + // app's origin. Returns the new content setting, which will be either + // unchanged, or will have switched from ALLOW to ASK. If the previous setting + // was BLOCK, no change is made. + ContentSetting MaybeResetFileHandlingPermission( + const WebApplicationInfo& web_app_info); + void OnDatabaseCommitCompletedForUpdate( InstallFinalizedCallback callback, AppId app_id, @@ -123,6 +134,7 @@ FileHandlerUpdateAction file_handlers_need_os_update, const WebApplicationInfo& web_app_info, bool success); + void OnUninstallOsHooks(const AppId& app_id, webapps::WebappUninstallSource uninstall_source, UninstallWebAppCallback callback,
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 2afb1e51..0f2b5cd5 100644 --- a/chrome/browser/web_applications/web_app_install_task_unittest.cc +++ b/chrome/browser/web_applications/web_app_install_task_unittest.cc
@@ -23,6 +23,7 @@ #include "chrome/browser/web_applications/components/web_app_constants.h" #include "chrome/browser/web_applications/components/web_app_helpers.h" #include "chrome/browser/web_applications/components/web_app_icon_generator.h" +#include "chrome/browser/web_applications/components/web_app_install_utils.h" #include "chrome/browser/web_applications/components/web_app_utils.h" #include "chrome/browser/web_applications/components/web_application_info.h" #include "chrome/browser/web_applications/test/test_data_retriever.h" @@ -1275,6 +1276,46 @@ } } +TEST_F(WebAppInstallTaskTest, StorageIsolationFlagSaved) { + const GURL manifest_start_url = GURL("https://example.com/start"); + const AppId app_id = GenerateAppIdFromURL(manifest_start_url); + + auto manifest = std::make_unique<blink::Manifest>(); + manifest->short_name = u"Short Name from Manifest"; + manifest->name = u"Name from Manifest"; + manifest->start_url = GURL("https://example.com/start"); + manifest->isolated_storage = true; + + auto web_app_info = std::make_unique<WebApplicationInfo>(); + UpdateWebAppInfoFromManifest(*manifest, manifest_start_url, + web_app_info.get()); + + data_retriever_->SetManifest(std::move(manifest), /*is_installable=*/true); + data_retriever_->SetRendererWebApplicationInfo(std::move(web_app_info)); + + base::RunLoop run_loop; + bool callback_called = false; + + install_task_->InstallWebAppFromManifestWithFallback( + web_contents(), /*force_shortcut_app=*/false, + webapps::WebappInstallSource::MENU_BROWSER_TAB, + base::BindOnce(test::TestAcceptDialogCallback), + base::BindLambdaForTesting( + [&](const AppId& installed_app_id, InstallResultCode code) { + EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code); + EXPECT_EQ(app_id, installed_app_id); + callback_called = true; + run_loop.Quit(); + })); + run_loop.Run(); + + EXPECT_TRUE(callback_called); + + const WebApp* web_app = registrar().GetAppById(app_id); + EXPECT_NE(nullptr, web_app); + EXPECT_TRUE(web_app->IsStorageIsolated()); +} + TEST_F(WebAppInstallTaskWithRunOnOsLoginTest, InstallFromWebContentsRunOnOsLogin) { EXPECT_TRUE(AreWebAppsUserInstallable(profile()));
diff --git a/chrome/browser/web_applications/web_app_unittest.cc b/chrome/browser/web_applications/web_app_unittest.cc index 92c85e8..b259d1c 100644 --- a/chrome/browser/web_applications/web_app_unittest.cc +++ b/chrome/browser/web_applications/web_app_unittest.cc
@@ -205,6 +205,7 @@ nullopt window_controls_overlay_enabled: 0 +is_storage_isolated: 0 )") << "Copypastable expectation: \n" << debug_string; } @@ -374,6 +375,7 @@ nullopt window_controls_overlay_enabled: 0 +is_storage_isolated: 0 )") << "Copypastable expectation: \n" << debug_string; }
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index 3bd9bbf..8c72c14 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-master-1622635148-895a7a9b984ca2b99a4b00b2a04fc8e55c529fad.profdata +chrome-win32-master-1622667452-ac768622a806a59c6280aa80b067d944195b9b61.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index 2da6b3a..f7088e7 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-master-1622635148-ba23959f0a77f895fe0cf2da1fc8384a42cf7236.profdata +chrome-win64-master-1622656662-3c6a534cfebd08404535bcdc0b3c72622ff4c893.profdata
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index 03f729f4..e9da05f 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc
@@ -112,12 +112,11 @@ const char kUserFeedbackAllowed[] = "feedback_allowed"; #if !defined(OS_ANDROID) -// Used to store the value of the SerialAllowAllPortsForUrls policy. -const char kManagedSerialAllowAllPortsForUrls[] = +// Replaced by kManagedSerialAllowAllPortsForUrls in M-93. +const char kManagedProfileSerialAllowAllPortsForUrlsDeprecated[] = "profile.managed.serial_allow_all_ports_for_urls"; - -// Used to store the value of the SerialAllowUsbDevicesForUrls policy. -const char kManagedSerialAllowUsbDevicesForUrls[] = +// Replaced by kManagedSerialAllowUsbDevicesForUrls in M-93. +const char kManagedProfileSerialAllowUsbDevicesForUrlsDeprecated[] = "profile.managed.serial_allow_usb_devices_for_urls"; #endif // !defined(OS_ANDROID) @@ -1610,6 +1609,16 @@ // *************** LOCAL STATE *************** // These are attached to the machine/installation +#if !defined(OS_ANDROID) +// Used to store the value of the SerialAllowAllPortsForUrls policy. +const char kManagedSerialAllowAllPortsForUrls[] = + "managed.serial_allow_all_ports_for_urls"; + +// Used to store the value of the SerialAllowUsbDevicesForUrls policy. +const char kManagedSerialAllowUsbDevicesForUrls[] = + "managed.serial_allow_usb_devices_for_urls"; +#endif // !defined(OS_ANDROID) + // Directory of the last profile used. const char kProfileLastUsed[] = "profile.last_used"; @@ -1853,11 +1862,6 @@ const char kNtpSearchSuggestionsImpressions[] = "ntp.search_suggestions_impressions"; const char kNtpSearchSuggestionsOptOut[] = "ntp.search_suggestions_opt_out"; -// Tracks whether the user has chosen to hide the shortcuts tiles on the NTP. -const char kNtpShortcutsVisible[] = "ntp.shortcust_visible"; -// Tracks whether the user has chosen to use custom links or most visited sites -// for the shortcut tiles on the NTP. -const char kNtpUseMostVisitedTiles[] = "ntp.use_most_visited_tiles"; #endif // defined(OS_ANDROID) // Which page should be visible on the new tab page v4
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index 99828b1..f57cd98e 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h
@@ -43,8 +43,8 @@ extern const char kRestoreOnStartup[]; extern const char kSessionExitType[]; #if !defined(OS_ANDROID) -extern const char kManagedSerialAllowAllPortsForUrls[]; -extern const char kManagedSerialAllowUsbDevicesForUrls[]; +extern const char kManagedProfileSerialAllowAllPortsForUrlsDeprecated[]; +extern const char kManagedProfileSerialAllowUsbDevicesForUrlsDeprecated[]; #endif // !defined(OS_ANDROID) #if BUILDFLAG(ENABLE_SUPERVISED_USERS) && BUILDFLAG(ENABLE_EXTENSIONS) extern const char kSupervisedUserApprovedExtensions[]; @@ -528,6 +528,11 @@ extern const char kPermissionActions[]; extern const char kHadThreeConsecutiveNotificationPermissionDenies[]; +#if !defined(OS_ANDROID) +extern const char kManagedSerialAllowAllPortsForUrls[]; +extern const char kManagedSerialAllowUsbDevicesForUrls[]; +#endif // !defined(OS_ANDROID) + extern const char kProfileLastUsed[]; extern const char kProfilesLastActive[]; extern const char kProfilesNumCreated[]; @@ -626,8 +631,6 @@ extern const char kNtpSearchSuggestionsBlocklist[]; extern const char kNtpSearchSuggestionsImpressions[]; extern const char kNtpSearchSuggestionsOptOut[]; -extern const char kNtpShortcutsVisible[]; -extern const char kNtpUseMostVisitedTiles[]; #endif // defined(OS_ANDROID) extern const char kNtpShownPage[];
diff --git a/chrome/services/sharing/nearby/nearby_connections.cc b/chrome/services/sharing/nearby/nearby_connections.cc index a0a1144..ae2e44d 100644 --- a/chrome/services/sharing/nearby/nearby_connections.cc +++ b/chrome/services/sharing/nearby/nearby_connections.cc
@@ -335,7 +335,8 @@ return; } - LOG(WARNING) << "Nearby dependency mojo disconnected: [" + LOG(WARNING) << "The utility process has detected that the browser process " + "has disconnected from a mojo pipe: [" << GetMojoDependencyName(dependency_name) << "]"; base::UmaHistogramEnumeration( "Nearby.Connections.UtilityProcessShutdownReason."
diff --git a/chrome/services/speech/cros_speech_recognition_recognizer_impl.cc b/chrome/services/speech/cros_speech_recognition_recognizer_impl.cc index 6596663..b8c2a57 100644 --- a/chrome/services/speech/cros_speech_recognition_recognizer_impl.cc +++ b/chrome/services/speech/cros_speech_recognition_recognizer_impl.cc
@@ -92,8 +92,12 @@ config->api_key = google_apis::GetSodaAPIKey(); config->language_dlc_path = languagepack_path_.value(); config->library_dlc_path = binary_path_.value(); - // TODO(crbug.com/1173135): Set options_->recognition_mode and - // options_->enable_formatting in the SodaConfig when available. + // TODO(crbug.com/1173135): Set options_->recognition_mode in the SodaConfig + // when available. + config->enable_formatting = + options_->enable_formatting + ? chromeos::machine_learning::mojom::OptionalBool::kTrue + : chromeos::machine_learning::mojom::OptionalBool::kFalse; cros_soda_client_->Reset(std::move(config), recognition_event_callback_); } cros_soda_client_->AddAudio(reinterpret_cast<char*>(buffer->data.data()),
diff --git a/chrome/services/speech/speech_recognition_recognizer_impl.cc b/chrome/services/speech/speech_recognition_recognizer_impl.cc index 3937722..6e5d7a7 100644 --- a/chrome/services/speech/speech_recognition_recognizer_impl.cc +++ b/chrome/services/speech/speech_recognition_recognizer_impl.cc
@@ -162,9 +162,9 @@ const base::FilePath& binary_path, const base::FilePath& config_path) : enable_soda_(base::FeatureList::IsEnabled(media::kUseSodaForLiveCaption)), + options_(std::move(options)), client_remote_(std::move(remote)), - config_path_(config_path), - options_(std::move(options)) { + config_path_(config_path) { recognition_event_callback_ = media::BindToCurrentLoop( base::BindRepeating(&SpeechRecognitionRecognizerImpl::OnRecognitionEvent, weak_factory_.GetWeakPtr()));
diff --git a/chrome/services/speech/speech_recognition_recognizer_impl.h b/chrome/services/speech/speech_recognition_recognizer_impl.h index 7e7c170..1c8c5d5 100644 --- a/chrome/services/speech/speech_recognition_recognizer_impl.h +++ b/chrome/services/speech/speech_recognition_recognizer_impl.h
@@ -84,6 +84,7 @@ const media::mojom::ConfidenceLevel confidence_level); const bool enable_soda_; + media::mojom::SpeechRecognitionOptionsPtr options_; private: void OnLanguageChanged(const std::string& language) final; @@ -120,7 +121,6 @@ int sample_rate_ = 0; int channel_count_ = 0; LanguageCode language_ = LanguageCode::kNone; - media::mojom::SpeechRecognitionOptionsPtr options_; base::TimeDelta caption_bubble_visible_duration_; base::TimeDelta caption_bubble_hidden_duration_;
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 321dfac..cc5d0b7 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -3794,8 +3794,6 @@ sources = [ "../browser/lacros/browser_test_util.cc", "../browser/lacros/browser_test_util.h", - "../browser/lacros/clipboard_lacros_browsertest.cc", - "../browser/lacros/crosapi_pref_observer_lacros_browsertest.cc", "../browser/lacros/device_attributes_lacros_browsertest.cc", "../browser/lacros/file_manager_lacros_browsertest.cc", "../browser/lacros/holding_space_service_lacros_browsertest.cc", @@ -3805,10 +3803,8 @@ "../browser/lacros/media_session_lacros_browsertest.cc", "../browser/lacros/message_center_lacros_browsertest.cc", "../browser/lacros/metrics_reporting_lacros_browsertest.cc", - "../browser/lacros/overview_lacros_browsertest.cc", "../browser/lacros/popup_lacros_browsertest.cc", "../browser/lacros/screen_manager_lacros_browsertest.cc", - "../browser/lacros/tablet_mode_lacros_browsertest.cc", "../browser/lacros/web_contents_can_go_back_observer_browsertest.cc", ] @@ -3827,6 +3823,41 @@ data_deps = [ "//chrome:packed_resources" ] } + + # This test target is intended for lacros chrome specific tests that depend + # on crosapi and must run in series, for those that can run in parallel, + # please use lacros_chrome_browsertests target instead. + test("lacros_chrome_browsertests_run_in_series") { + use_xvfb = use_xvfb_in_this_config + + configs += [ "//build/config:precompiled_headers" ] + defines = [ + "HAS_OUT_OF_PROC_TEST_RUNNER", + "CHROME_VERSION_MAJOR=" + chrome_version_major, + ] + + sources = [ + "../browser/lacros/browser_test_util.cc", + "../browser/lacros/browser_test_util.h", + "../browser/lacros/clipboard_lacros_browsertest.cc", + "../browser/lacros/crosapi_pref_observer_lacros_browsertest.cc", + "../browser/lacros/overview_lacros_browsertest.cc", + "../browser/lacros/tablet_mode_lacros_browsertest.cc", + ] + + deps = [ + ":browser_tests_runner", + ":test_support", + "//chromeos/crosapi/mojom", + "//chromeos/lacros", + "//chromeos/services/machine_learning/public/cpp", + "//chromeos/services/machine_learning/public/cpp:stub", + "//chromeos/services/machine_learning/public/mojom", + "//ui/platform_window", + ] + + data_deps = [ "//chrome:packed_resources" ] + } } if (is_linux || is_chromeos || is_mac || is_win || is_android) { @@ -4591,13 +4622,6 @@ ] } - if (is_android) { - sources += [ - "../browser/enterprise/util/android_enterprise_info_unittest.cc", - "../browser/policy/browser_dm_token_storage_android_unittest.cc", - ] - } - if (!is_android) { sources += [ "../browser/browsing_data/chrome_browsing_data_lifetime_manager_unittest.cc", @@ -4957,6 +4981,7 @@ "../browser/autofill/autofill_save_card_infobar_delegate_mobile_unittest.cc", "../browser/autofill/credit_card_accessory_controller_impl_unittest.cc", "../browser/autofill/manual_filling_controller_impl_unittest.cc", + "../browser/enterprise/util/android_enterprise_info_unittest.cc", "../browser/long_screenshots/long_screenshots_tab_service_unittest.cc", "../browser/media/android/cdm/media_drm_origin_id_manager_unittest.cc", "../browser/metrics/chrome_android_metrics_provider_unittest.cc", @@ -4975,6 +5000,7 @@ "../browser/password_manager/android/save_password_message_delegate_unittest.cc", "../browser/password_manager/android/update_password_infobar_delegate_android_unittest.cc", "../browser/permissions/permission_prompt_android_unittest.cc", + "../browser/policy/browser_dm_token_storage_android_unittest.cc", "../browser/profiles/android/profile_resolver_unittest.cc", "../browser/reputation/safety_tip_message_delegate_unittest.cc", "../browser/sharing/click_to_call/click_to_call_message_handler_android_unittest.cc", @@ -8566,7 +8592,7 @@ "//third_party/blink/web_tests/resources/testharness.js", ] - if (is_win) { + if (is_win && enable_vr) { deps += [ "//device/vr", "//device/vr:directx_helpers",
diff --git a/chrome/test/base/testing_browser_process.cc b/chrome/test/base/testing_browser_process.cc index a3f87044..f236495c 100644 --- a/chrome/test/base/testing_browser_process.cc +++ b/chrome/test/base/testing_browser_process.cc
@@ -64,6 +64,7 @@ #endif #if !defined(OS_ANDROID) +#include "chrome/browser/serial/serial_policy_allowed_ports.h" #include "components/keep_alive_registry/keep_alive_registry.h" #endif @@ -431,6 +432,16 @@ return resource_coordinator_parts_.get(); } +#if !defined(OS_ANDROID) +SerialPolicyAllowedPorts* TestingBrowserProcess::serial_policy_allowed_ports() { + if (!serial_policy_allowed_ports_) { + serial_policy_allowed_ports_ = + std::make_unique<SerialPolicyAllowedPorts>(local_state()); + } + return serial_policy_allowed_ports_.get(); +} +#endif + BuildState* TestingBrowserProcess::GetBuildState() { #if !defined(OS_ANDROID) return &build_state_; @@ -476,6 +487,9 @@ // are also freed. network_time_tracker_.reset(); notification_ui_manager_.reset(); +#if !defined(OS_ANDROID) + serial_policy_allowed_ports_.reset(); +#endif ShutdownBrowserPolicyConnector(); created_browser_policy_connector_ = false; }
diff --git a/chrome/test/base/testing_browser_process.h b/chrome/test/base/testing_browser_process.h index a60f9e6..eb859f99 100644 --- a/chrome/test/base/testing_browser_process.h +++ b/chrome/test/base/testing_browser_process.h
@@ -144,6 +144,9 @@ resource_coordinator::TabManager* GetTabManager() override; resource_coordinator::ResourceCoordinatorParts* resource_coordinator_parts() override; +#if !defined(OS_ANDROID) + SerialPolicyAllowedPorts* serial_policy_allowed_ports() override; +#endif BuildState* GetBuildState() override; // Set the local state for tests. Consumer is responsible for cleaning it up @@ -228,6 +231,7 @@ resource_coordinator_parts_; #if !defined(OS_ANDROID) + std::unique_ptr<SerialPolicyAllowedPorts> serial_policy_allowed_ports_; BuildState build_state_; #endif };
diff --git a/chrome/test/data/extensions/api_test/browser_action/add_popup/manifest.json b/chrome/test/data/extensions/api_test/browser_action/add_popup/manifest.json index 2e1b42d..2bd211b 100644 --- a/chrome/test/data/extensions/api_test/browser_action/add_popup/manifest.json +++ b/chrome/test/data/extensions/api_test/browser_action/add_popup/manifest.json
@@ -3,7 +3,8 @@ "version": "1.0", "manifest_version": 2, "background": { - "scripts": ["background.js"] + "scripts": ["background.js"], + "persistent": true }, "permissions": [ "tabs", "http://*/*"
diff --git a/chrome/test/data/extensions/api_test/browser_action/basics/manifest.json b/chrome/test/data/extensions/api_test/browser_action/basics/manifest.json index 27b1d54..321ff0dc 100644 --- a/chrome/test/data/extensions/api_test/browser_action/basics/manifest.json +++ b/chrome/test/data/extensions/api_test/browser_action/basics/manifest.json
@@ -3,7 +3,7 @@ "version": "1.0", "manifest_version": 2, "background": { - "persistent": false, + "persistent": true, "scripts": ["background.js"] }, "permissions": [
diff --git a/chrome/test/data/extensions/api_test/browser_action/color/manifest.json b/chrome/test/data/extensions/api_test/browser_action/color/manifest.json index 65b7668..3d084cc 100644 --- a/chrome/test/data/extensions/api_test/browser_action/color/manifest.json +++ b/chrome/test/data/extensions/api_test/browser_action/color/manifest.json
@@ -3,7 +3,8 @@ "version": "1.0", "manifest_version": 2, "background": { - "scripts": ["background.js"] + "scripts": ["background.js"], + "persistent": true }, "permissions": [ "tabs", "http://*/*"
diff --git a/chrome/test/data/extensions/api_test/browser_action/getters/manifest.json b/chrome/test/data/extensions/api_test/browser_action/getters/manifest.json index 08f9845..8aa1852 100644 --- a/chrome/test/data/extensions/api_test/browser_action/getters/manifest.json +++ b/chrome/test/data/extensions/api_test/browser_action/getters/manifest.json
@@ -3,7 +3,8 @@ "version": "1.0", "manifest_version": 2, "background": { - "scripts": ["background.js"] + "scripts": ["background.js"], + "persistent": true }, "permissions": [ "tabs", "http://*/*"
diff --git a/chrome/test/data/extensions/api_test/browser_action/rect_icon/background.js b/chrome/test/data/extensions/api_test/browser_action/rect_icon/background.js index 6a9b1ef..4c534d8 100644 --- a/chrome/test/data/extensions/api_test/browser_action/rect_icon/background.js +++ b/chrome/test/data/extensions/api_test/browser_action/rect_icon/background.js
@@ -5,6 +5,6 @@ chrome.test.sendMessage('ready', function() { chrome.browserAction.setIcon({path: 'rectangle.png'}, function() { chrome.test.assertNoLastError(); - chrome.test.succeed(); + chrome.test.notifyPass(); }); });
diff --git a/chrome/test/data/extensions/api_test/browser_action/rect_icon/manifest.json b/chrome/test/data/extensions/api_test/browser_action/rect_icon/manifest.json index fe353c5..d36e517 100644 --- a/chrome/test/data/extensions/api_test/browser_action/rect_icon/manifest.json +++ b/chrome/test/data/extensions/api_test/browser_action/rect_icon/manifest.json
@@ -2,7 +2,10 @@ "name": "Rectangle icons", "description": "A browser action with rectangular icons", "manifest_version": 2, - "background": {"scripts": ["background.js"]}, + "background": { + "scripts": ["background.js"], + "persistent": true + }, "browser_action": { "default_icon": "square.png" },
diff --git a/chrome/test/data/extensions/api_test/browser_action/remove_popup/manifest.json b/chrome/test/data/extensions/api_test/browser_action/remove_popup/manifest.json index 79e796b..0a4ef04 100644 --- a/chrome/test/data/extensions/api_test/browser_action/remove_popup/manifest.json +++ b/chrome/test/data/extensions/api_test/browser_action/remove_popup/manifest.json
@@ -3,7 +3,8 @@ "version": "1.0", "manifest_version": 2, "background": { - "scripts": ["background.js"] + "scripts": ["background.js"], + "persistent": true }, "permissions": [ "tabs", "http://*/*"
diff --git a/chrome/test/data/extensions/api_test/browser_action/set_icon/background.js b/chrome/test/data/extensions/api_test/browser_action/set_icon/background.js index b6e3953..3e01f2a 100644 --- a/chrome/test/data/extensions/api_test/browser_action/set_icon/background.js +++ b/chrome/test/data/extensions/api_test/browser_action/set_icon/background.js
@@ -3,7 +3,7 @@ // found in the LICENSE file. function getImageData() { - var canvas = document.createElement("canvas"); + var canvas = new OffscreenCanvas(10, 100); var ctx = canvas.getContext("2d"); ctx.fillStyle = "green";
diff --git a/chrome/test/data/extensions/api_test/browser_action/set_icon/manifest.json b/chrome/test/data/extensions/api_test/browser_action/set_icon/manifest.json index aa9f00c..9dcb00d 100644 --- a/chrome/test/data/extensions/api_test/browser_action/set_icon/manifest.json +++ b/chrome/test/data/extensions/api_test/browser_action/set_icon/manifest.json
@@ -3,7 +3,8 @@ "version": "1.0", "manifest_version": 2, "background": { - "scripts": ["background.js"] + "scripts": ["background.js"], + "persistent": true }, "permissions": [ "tabs", "http://*/*"
diff --git a/chrome/test/data/extensions/api_test/browser_action/tab_specific_state/manifest.json b/chrome/test/data/extensions/api_test/browser_action/tab_specific_state/manifest.json index 99612eb..db99512 100644 --- a/chrome/test/data/extensions/api_test/browser_action/tab_specific_state/manifest.json +++ b/chrome/test/data/extensions/api_test/browser_action/tab_specific_state/manifest.json
@@ -3,7 +3,8 @@ "version": "1.0", "manifest_version": 2, "background": { - "scripts": ["background.js"] + "scripts": ["background.js"], + "persistent": true }, "permissions": [ "tabs", "http://*/*" @@ -12,4 +13,4 @@ "default_icon": "icon1.png", "default_title": "hi!" } -} \ No newline at end of file +}
diff --git a/chrome/test/data/extensions/api_test/browser_action/update/manifest.json b/chrome/test/data/extensions/api_test/browser_action/update/manifest.json index ca88418..d7b382d 100644 --- a/chrome/test/data/extensions/api_test/browser_action/update/manifest.json +++ b/chrome/test/data/extensions/api_test/browser_action/update/manifest.json
@@ -3,7 +3,7 @@ "version": "1.0", "manifest_version": 2, "background": { - "persistent": false, + "persistent": true, "scripts": ["background.js"] }, "browser_action": {
diff --git a/chrome/test/data/extensions/api_test/extension_module/cognito_file/manifest.json b/chrome/test/data/extensions/api_test/extension_module/cognito_file/manifest.json index 6d2143f..176335f 100644 --- a/chrome/test/data/extensions/api_test/extension_module/cognito_file/manifest.json +++ b/chrome/test/data/extensions/api_test/extension_module/cognito_file/manifest.json
@@ -4,6 +4,7 @@ "manifest_version": 2, "description": "end-to-end browser test for some chrome.extension API: cognito mode.", "background": { - "page": "test.html" + "scripts": ["test.js"], + "persistent": true } }
diff --git a/chrome/test/data/extensions/api_test/extension_module/cognito_file/test.html b/chrome/test/data/extensions/api_test/extension_module/cognito_file/test.html deleted file mode 100644 index 3efb342..0000000 --- a/chrome/test/data/extensions/api_test/extension_module/cognito_file/test.html +++ /dev/null
@@ -1,6 +0,0 @@ -<!-- - * Copyright (c) 2011 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. ---> -<script src="test.js"></script>
diff --git a/chrome/test/data/extensions/api_test/extension_module/cognito_nofile/manifest.json b/chrome/test/data/extensions/api_test/extension_module/cognito_nofile/manifest.json index 6d2143f..176335f 100644 --- a/chrome/test/data/extensions/api_test/extension_module/cognito_nofile/manifest.json +++ b/chrome/test/data/extensions/api_test/extension_module/cognito_nofile/manifest.json
@@ -4,6 +4,7 @@ "manifest_version": 2, "description": "end-to-end browser test for some chrome.extension API: cognito mode.", "background": { - "page": "test.html" + "scripts": ["test.js"], + "persistent": true } }
diff --git a/chrome/test/data/extensions/api_test/extension_module/cognito_nofile/test.html b/chrome/test/data/extensions/api_test/extension_module/cognito_nofile/test.html deleted file mode 100644 index 3efb342..0000000 --- a/chrome/test/data/extensions/api_test/extension_module/cognito_nofile/test.html +++ /dev/null
@@ -1,6 +0,0 @@ -<!-- - * Copyright (c) 2011 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. ---> -<script src="test.js"></script>
diff --git a/chrome/test/data/extensions/api_test/extension_module/incognito_file/manifest.json b/chrome/test/data/extensions/api_test/extension_module/incognito_file/manifest.json index 7844475..0d304812 100644 --- a/chrome/test/data/extensions/api_test/extension_module/incognito_file/manifest.json +++ b/chrome/test/data/extensions/api_test/extension_module/incognito_file/manifest.json
@@ -4,6 +4,7 @@ "manifest_version": 2, "description": "end-to-end browser test for some chrome.extension API: incognito mode", "background": { - "page": "test.html" + "scripts": ["test.js"], + "persistent": true } }
diff --git a/chrome/test/data/extensions/api_test/extension_module/incognito_file/test.html b/chrome/test/data/extensions/api_test/extension_module/incognito_file/test.html deleted file mode 100644 index 3efb342..0000000 --- a/chrome/test/data/extensions/api_test/extension_module/incognito_file/test.html +++ /dev/null
@@ -1,6 +0,0 @@ -<!-- - * Copyright (c) 2011 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. ---> -<script src="test.js"></script>
diff --git a/chrome/test/data/extensions/api_test/extension_module/incognito_nofile/manifest.json b/chrome/test/data/extensions/api_test/extension_module/incognito_nofile/manifest.json index 7844475..0d304812 100644 --- a/chrome/test/data/extensions/api_test/extension_module/incognito_nofile/manifest.json +++ b/chrome/test/data/extensions/api_test/extension_module/incognito_nofile/manifest.json
@@ -4,6 +4,7 @@ "manifest_version": 2, "description": "end-to-end browser test for some chrome.extension API: incognito mode", "background": { - "page": "test.html" + "scripts": ["test.js"], + "persistent": true } }
diff --git a/chrome/test/data/extensions/api_test/extension_module/incognito_nofile/test.html b/chrome/test/data/extensions/api_test/extension_module/incognito_nofile/test.html deleted file mode 100644 index 3efb342..0000000 --- a/chrome/test/data/extensions/api_test/extension_module/incognito_nofile/test.html +++ /dev/null
@@ -1,6 +0,0 @@ -<!-- - * Copyright (c) 2011 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. ---> -<script src="test.js"></script>
diff --git a/chrome/test/data/extensions/api_test/trigger_actions/browser_action/manifest.json b/chrome/test/data/extensions/api_test/trigger_actions/browser_action/manifest.json index e4850aa..7e8ab8d 100644 --- a/chrome/test/data/extensions/api_test/trigger_actions/browser_action/manifest.json +++ b/chrome/test/data/extensions/api_test/trigger_actions/browser_action/manifest.json
@@ -3,7 +3,8 @@ "version": "1.0", "manifest_version": 2, "background": { - "scripts": ["background.js"] + "scripts": ["background.js"], + "persistent": true }, "permissions": [ "tabs", "http://*/*"
diff --git a/chrome/test/data/extensions/api_test/virtual_keyboard_private/test.js b/chrome/test/data/extensions/api_test/virtual_keyboard_private/test.js index 55488dd..350ebdf 100644 --- a/chrome/test/data/extensions/api_test/virtual_keyboard_private/test.js +++ b/chrome/test/data/extensions/api_test/virtual_keyboard_private/test.js
@@ -6,19 +6,42 @@ function callbackResult(result) { var result = result.map((item) => { - return {displayFormat: item.displayFormat, - textData: !!item.textData, - imageData: !!item.imageData}; + return { + displayFormat: item.displayFormat, + textData: !!item.textData, + imageData: !!item.imageData, + timeCopied: !!item.timeCopied + }; }); // Test that clipboard items are in the correct order with the correct data // types. - chrome.test.assertEq(result, - [{"displayFormat":"file","textData":true, "imageData":true}, - {"displayFormat":"png", "textData":false,"imageData":true}, - {"displayFormat":"text","textData":true, "imageData":false}, - {"displayFormat":"html","textData":false,"imageData":true}] - ); + chrome.test.assertEq(result, [ + { + 'displayFormat': 'file', + 'textData': true, + 'imageData': true, + 'timeCopied': true + }, + { + 'displayFormat': 'png', + 'textData': false, + 'imageData': true, + 'timeCopied': true + }, + { + 'displayFormat': 'text', + 'textData': true, + 'imageData': false, + 'timeCopied': true + }, + { + 'displayFormat': 'html', + 'textData': false, + 'imageData': true, + 'timeCopied': true + } + ]); } chrome.test.runTests([
diff --git a/chrome/test/data/extensions/back_forward_cache/background_page/background.js b/chrome/test/data/extensions/back_forward_cache/background_page/background.js new file mode 100644 index 0000000..96d4b44 --- /dev/null +++ b/chrome/test/data/extensions/back_forward_cache/background_page/background.js
@@ -0,0 +1,3 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file.
diff --git a/chrome/test/data/extensions/back_forward_cache/background_page/manifest.json b/chrome/test/data/extensions/back_forward_cache/background_page/manifest.json new file mode 100644 index 0000000..a3d6f99 --- /dev/null +++ b/chrome/test/data/extensions/back_forward_cache/background_page/manifest.json
@@ -0,0 +1,10 @@ +{ + "name": "Background Page Extension", + "version": "1.0", + "manifest_version": 2, + "description": "A minimal extension for testing purposes.", + "background": { + "scripts": ["background.js"] + }, + "permissions": ["*://a.com/*", "*://b.com/*"] +}
diff --git a/chrome/test/data/extensions/back_forward_cache/content_script_storage/manifest.json b/chrome/test/data/extensions/back_forward_cache/content_script_storage/manifest.json new file mode 100644 index 0000000..8ae32a8 --- /dev/null +++ b/chrome/test/data/extensions/back_forward_cache/content_script_storage/manifest.json
@@ -0,0 +1,14 @@ +{ + "name": "no caching", + "version": "0.1", + "manifest_version": 2, + "description": "Checks that content scripts receiving events evict from back forward cache.", + "permissions": ["storage"], + "content_scripts": [ + { + "matches": ["*://a.com/*", "*://b.com/*"], + "js": ["storage.js"], + "run_at": "document_end" + } + ] +}
diff --git a/chrome/test/data/extensions/back_forward_cache/content_script_storage/storage.js b/chrome/test/data/extensions/back_forward_cache/content_script_storage/storage.js new file mode 100644 index 0000000..9f134f7 --- /dev/null +++ b/chrome/test/data/extensions/back_forward_cache/content_script_storage/storage.js
@@ -0,0 +1,12 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +chrome.storage.onChanged.addListener((changes, area) => { + // do nothing +}); + +if (window.location.host.indexOf('b.com') != -1) { + var options = {test: true}; + chrome.storage.sync.set({options}); +}
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json index 151693a..2087cd8 100644 --- a/chrome/test/data/policy/policy_test_cases.json +++ b/chrome/test/data/policy/policy_test_cases.json
@@ -2609,7 +2609,7 @@ "policy_pref_mapping_tests": [ { "policies": {"SerialAllowAllPortsForUrls": ["https://www.google.com"]}, - "prefs": { "profile.managed.serial_allow_all_ports_for_urls": {} } + "prefs": { "managed.serial_allow_all_ports_for_urls": { "location": "local_state" } } } ] }, @@ -2628,7 +2628,7 @@ "urls": ["https://www.google.com"] } ]}, - "prefs": { "profile.managed.serial_allow_usb_devices_for_urls": {} } + "prefs": { "managed.serial_allow_usb_devices_for_urls": { "location": "local_state" } } } ] },
diff --git a/chrome/test/data/webui/chromeos/shimless_rma/fake_shimless_rma_service_test.js b/chrome/test/data/webui/chromeos/shimless_rma/fake_shimless_rma_service_test.js index 792a360..0d6b6ea 100644 --- a/chrome/test/data/webui/chromeos/shimless_rma/fake_shimless_rma_service_test.js +++ b/chrome/test/data/webui/chromeos/shimless_rma/fake_shimless_rma_service_test.js
@@ -22,7 +22,7 @@ test('GetCurrentStateDefaultRmaNotRequired', () => { return service.getCurrentState().then((state) => { - assertEquals(state.currentState, RmaState.kUnknown); + assertEquals(state.state, RmaState.kUnknown); assertEquals(state.error, RmadErrorCode.kRmaNotRequired); }); }); @@ -34,7 +34,7 @@ service.setStates(states); return service.getCurrentState().then((state) => { - assertEquals(state.currentState, RmaState.kWelcomeScreen); + assertEquals(state.state, RmaState.kWelcomeScreen); assertEquals(state.error, RmadErrorCode.kOk); }); }); @@ -46,14 +46,14 @@ service.setStates(states); return service.getCurrentState().then((state) => { - assertEquals(state.currentState, RmaState.kWelcomeScreen); + assertEquals(state.state, RmaState.kWelcomeScreen); assertEquals(state.error, RmadErrorCode.kMissingComponent); }); }); test('GetNextStateDefaultRmaNotRequired', () => { return service.getNextState().then((state) => { - assertEquals(state.nextState, RmaState.kUnknown); + assertEquals(state.state, RmaState.kUnknown); assertEquals(state.error, RmadErrorCode.kRmaNotRequired); }); }); @@ -66,7 +66,7 @@ service.setStates(states); return service.getNextState().then((state) => { - assertEquals(state.nextState, RmaState.kUpdateChrome); + assertEquals(state.state, RmaState.kUpdateChrome); assertEquals(state.error, RmadErrorCode.kOk); }); }); @@ -78,14 +78,14 @@ service.setStates(states); return service.getNextState().then((state) => { - assertEquals(state.nextState, RmaState.kWelcomeScreen); + assertEquals(state.state, RmaState.kWelcomeScreen); assertEquals(state.error, RmadErrorCode.kTransitionFailed); }); }); test('GetPrevStateDefaultRmaNotRequired', () => { return service.getPrevState().then((state) => { - assertEquals(state.prevState, RmaState.kUnknown); + assertEquals(state.state, RmaState.kUnknown); assertEquals(state.error, RmadErrorCode.kRmaNotRequired); }); }); @@ -98,11 +98,11 @@ service.setStates(states); service.getNextState().then((state) => { - assertEquals(state.nextState, RmaState.kUpdateChrome); + assertEquals(state.state, RmaState.kUpdateChrome); assertEquals(state.error, RmadErrorCode.kOk); }); return service.getPrevState().then((state) => { - assertEquals(state.prevState, RmaState.kWelcomeScreen); + assertEquals(state.state, RmaState.kWelcomeScreen); assertEquals(state.error, RmadErrorCode.kOk); }); }); @@ -114,7 +114,7 @@ service.setStates(states); return service.getPrevState().then((state) => { - assertEquals(state.prevState, RmaState.kWelcomeScreen); + assertEquals(state.state, RmaState.kWelcomeScreen); assertEquals(state.error, RmadErrorCode.kTransitionFailed); }); }); @@ -166,14 +166,14 @@ service.setStates(states); return service.setSameOwner().then((state) => { - assertEquals(state.nextState, RmaState.kUpdateChrome); + assertEquals(state.state, RmaState.kUpdateChrome); assertEquals(state.error, RmadErrorCode.kOk); }); }); test('SetSameOwnerWhenRmaNotRequired', () => { return service.setSameOwner().then((state) => { - assertEquals(state.nextState, RmaState.kUnknown); + assertEquals(state.state, RmaState.kUnknown); assertEquals(state.error, RmadErrorCode.kRmaNotRequired); }); }); @@ -186,7 +186,7 @@ service.setStates(states); return service.setSameOwner().then((state) => { - assertEquals(state.nextState, RmaState.kWelcomeScreen); + assertEquals(state.state, RmaState.kWelcomeScreen); assertEquals(state.error, RmadErrorCode.kRequestInvalid); }); }); @@ -199,7 +199,7 @@ service.setStates(states); return service.setDifferentOwner().then((state) => { - assertEquals(state.nextState, RmaState.kUpdateChrome); + assertEquals(state.state, RmaState.kUpdateChrome); assertEquals(state.error, RmadErrorCode.kOk); }); }); @@ -212,7 +212,7 @@ service.setStates(states); return service.setDifferentOwner().then((state) => { - assertEquals(state.nextState, RmaState.kWelcomeScreen); + assertEquals(state.state, RmaState.kWelcomeScreen); assertEquals(state.error, RmadErrorCode.kRequestInvalid); }); }); @@ -228,7 +228,7 @@ service.setStates(states); return service.chooseManuallyDisableWriteProtect().then((state) => { - assertEquals(state.nextState, RmaState.kUpdateChrome); + assertEquals(state.state, RmaState.kUpdateChrome); assertEquals(state.error, RmadErrorCode.kOk); }); }); @@ -241,7 +241,7 @@ service.setStates(states); return service.chooseManuallyDisableWriteProtect().then((state) => { - assertEquals(state.nextState, RmaState.kWelcomeScreen); + assertEquals(state.state, RmaState.kWelcomeScreen); assertEquals(state.error, RmadErrorCode.kRequestInvalid); }); }); @@ -257,7 +257,7 @@ service.setStates(states); return service.chooseRsuDisableWriteProtect().then((state) => { - assertEquals(state.nextState, RmaState.kUpdateChrome); + assertEquals(state.state, RmaState.kUpdateChrome); assertEquals(state.error, RmadErrorCode.kOk); }); }); @@ -270,7 +270,33 @@ service.setStates(states); return service.chooseRsuDisableWriteProtect().then((state) => { - assertEquals(state.nextState, RmaState.kWelcomeScreen); + assertEquals(state.state, RmaState.kWelcomeScreen); + assertEquals(state.error, RmadErrorCode.kRequestInvalid); + }); + }); + + test('SetRsuDisableWriteProtectCodeOk', () => { + let states = [ + {state: RmaState.kEnterRSUWPDisableCode, error: RmadErrorCode.kOk}, + {state: RmaState.kUpdateChrome, error: RmadErrorCode.kOk}, + ]; + service.setStates(states); + + return service.setRsuDisableWriteProtectCode('ignored').then((state) => { + assertEquals(state.state, RmaState.kUpdateChrome); + assertEquals(state.error, RmadErrorCode.kOk); + }); + }); + + test('SetRsuDisableWriteProtectCodeWrongStateFails', () => { + let states = [ + {state: RmaState.kWelcomeScreen, error: RmadErrorCode.kOk}, + {state: RmaState.kUpdateChrome, error: RmadErrorCode.kOk}, + ]; + service.setStates(states); + + return service.setRsuDisableWriteProtectCode('ignored').then((state) => { + assertEquals(state.state, RmaState.kWelcomeScreen); assertEquals(state.error, RmadErrorCode.kRequestInvalid); }); }); @@ -316,7 +342,7 @@ service.setStates(states); return service.setComponentsRepairState(components).then((state) => { - assertEquals(state.nextState, RmaState.kUpdateChrome); + assertEquals(state.state, RmaState.kUpdateChrome); assertEquals(state.error, RmadErrorCode.kOk); }); }); @@ -339,7 +365,7 @@ service.setStates(states); return service.setComponentsRepairState(components).then((state) => { - assertEquals(state.nextState, RmaState.kWelcomeScreen); + assertEquals(state.state, RmaState.kWelcomeScreen); assertEquals(state.error, RmadErrorCode.kRequestInvalid); }); }); @@ -352,7 +378,7 @@ service.setStates(states); return service.reworkMainboard().then((state) => { - assertEquals(state.nextState, RmaState.kUpdateChrome); + assertEquals(state.state, RmaState.kUpdateChrome); assertEquals(state.error, RmadErrorCode.kOk); }); }); @@ -365,7 +391,7 @@ service.setStates(states); return service.reworkMainboard().then((state) => { - assertEquals(state.nextState, RmaState.kWelcomeScreen); + assertEquals(state.state, RmaState.kWelcomeScreen); assertEquals(state.error, RmadErrorCode.kRequestInvalid); }); }); @@ -378,7 +404,7 @@ service.setStates(states); return service.reimageSkipped().then((state) => { - assertEquals(state.nextState, RmaState.kUpdateChrome); + assertEquals(state.state, RmaState.kUpdateChrome); assertEquals(state.error, RmadErrorCode.kOk); }); }); @@ -391,7 +417,7 @@ service.setStates(states); return service.reimageSkipped().then((state) => { - assertEquals(state.nextState, RmaState.kWelcomeScreen); + assertEquals(state.state, RmaState.kWelcomeScreen); assertEquals(state.error, RmadErrorCode.kRequestInvalid); }); }); @@ -404,7 +430,7 @@ service.setStates(states); return service.reimageFromDownload().then((state) => { - assertEquals(state.nextState, RmaState.kUpdateChrome); + assertEquals(state.state, RmaState.kUpdateChrome); assertEquals(state.error, RmadErrorCode.kOk); }); }); @@ -417,7 +443,7 @@ service.setStates(states); return service.reimageFromDownload().then((state) => { - assertEquals(state.nextState, RmaState.kWelcomeScreen); + assertEquals(state.state, RmaState.kWelcomeScreen); assertEquals(state.error, RmadErrorCode.kRequestInvalid); }); }); @@ -430,7 +456,7 @@ service.setStates(states); return service.reimageFromUsb().then((state) => { - assertEquals(state.nextState, RmaState.kUpdateChrome); + assertEquals(state.state, RmaState.kUpdateChrome); assertEquals(state.error, RmadErrorCode.kOk); }); }); @@ -443,7 +469,7 @@ service.setStates(states); return service.reimageFromUsb().then((state) => { - assertEquals(state.nextState, RmaState.kWelcomeScreen); + assertEquals(state.state, RmaState.kWelcomeScreen); assertEquals(state.error, RmadErrorCode.kRequestInvalid); }); });
diff --git a/chrome/test/data/webui/chromeos/shimless_rma/shimless_rma_app_test.js b/chrome/test/data/webui/chromeos/shimless_rma/shimless_rma_app_test.js index 8ee6018..96b0a02 100644 --- a/chrome/test/data/webui/chromeos/shimless_rma/shimless_rma_app_test.js +++ b/chrome/test/data/webui/chromeos/shimless_rma/shimless_rma_app_test.js
@@ -7,7 +7,7 @@ import {FakeShimlessRmaService} from 'chrome://shimless-rma/fake_shimless_rma_service.js'; import {setShimlessRmaServiceForTesting} from 'chrome://shimless-rma/mojo_interface_provider.js'; import {ButtonState, ShimlessRmaElement} from 'chrome://shimless-rma/shimless_rma.js'; -import {RmaState, State} from 'chrome://shimless-rma/shimless_rma_types.js'; +import {RmadErrorCode, RmaState, StateResult} from 'chrome://shimless-rma/shimless_rma_types.js'; import {assertFalse, assertTrue} from '../../chai_assert.js'; import {flushTasks, isVisible} from '../../test_util.m.js'; @@ -36,7 +36,7 @@ }); /** - * @param {!Array<!State>} states + * @param {!Array<!StateResult>} states * @param {string} chromeVersion */ function initializeShimlessRMAApp(states, chromeVersion) { @@ -138,7 +138,7 @@ await clickNext(); assertFalse(initialPage.hidden); - resolver.resolve(RmaState.kUpdateChrome); + resolver.resolve({state: RmaState.kUpdateChrome, error: RmadErrorCode.kOk}); await flushTasks(); const updatePage =
diff --git a/chrome/test/data/webui/js/cr/ui/BUILD.gn b/chrome/test/data/webui/js/cr/ui/BUILD.gn index c0b4a17..75e7570 100644 --- a/chrome/test/data/webui/js/cr/ui/BUILD.gn +++ b/chrome/test/data/webui/js/cr/ui/BUILD.gn
@@ -19,7 +19,6 @@ "menu_button_test.js", "menu_test.js", "position_util_test.js", - "splitter_test.js", ] namespace_rewrites = cr_namespace_rewrites @@ -144,16 +143,13 @@ extra_deps = [ ":modulize" ] } -js_library("splitter_test.m") { - sources = - [ "$root_gen_dir/chrome/test/data/webui/js/cr/ui/splitter_test.m.js" ] +js_library("splitter_test") { deps = [ "../../..:chai_assert", "//ui/webui/resources/js:util.m", "//ui/webui/resources/js/cr:ui.m", - "//ui/webui/resources/js/cr/ui:splitter.m", + "//ui/webui/resources/js/cr/ui:splitter", ] - extra_deps = [ ":modulize" ] } js_type_check("closure_compile") { @@ -169,6 +165,6 @@ ":menu_button_test.m", ":menu_test.m", ":position_util_test.m", - ":splitter_test.m", + ":splitter_test", ] }
diff --git a/chrome/test/data/webui/js/cr/ui/splitter_test.html b/chrome/test/data/webui/js/cr/ui/splitter_test.html deleted file mode 100644 index fa7eff4..0000000 --- a/chrome/test/data/webui/js/cr/ui/splitter_test.html +++ /dev/null
@@ -1,11 +0,0 @@ -<!doctype html> -<html> -<body> -<script src="chrome://resources/js/cr.js"></script> -<script src="chrome://resources/js/cr/ui.js"></script> -<script src="chrome://resources/js/cr/ui/splitter.js"></script> -<script src="chrome://resources/js/assert.js"></script> -<script src="chrome://resources/js/util.js"></script> -<script src="splitter_test.js"></script> -</body> -</html>
diff --git a/chrome/test/data/webui/js/cr/ui/splitter_test.js b/chrome/test/data/webui/js/cr/ui/splitter_test.js index 11a3bd2..b75c4e40 100644 --- a/chrome/test/data/webui/js/cr/ui/splitter_test.js +++ b/chrome/test/data/webui/js/cr/ui/splitter_test.js
@@ -3,10 +3,12 @@ // found in the LICENSE file. // clang-format off -// #import {assertEquals, assertTrue, assertFalse} from '../../../chai_assert.js'; -// #import {getRequiredElement} from 'chrome://resources/js/util.m.js'; -// #import {decorate} from 'chrome://resources/js/cr/ui.m.js'; -// #import {Splitter} from 'chrome://resources/js/cr/ui/splitter.m.js'; +import {decorate} from 'chrome://resources/js/cr/ui.m.js'; +import {Splitter} from 'chrome://resources/js/cr/ui/splitter.js'; +import {getRequiredElement} from 'chrome://resources/js/util.m.js'; + +import {assertEquals, assertFalse, assertTrue} from '../../../chai_assert.js'; + // clang-format on function setUp() { @@ -20,7 +22,7 @@ function testSplitter_IgnoresRightMouse() { const splitter = getRequiredElement('splitter'); - cr.ui.decorate(splitter, cr.ui.Splitter); + decorate(splitter, Splitter); const downRight = new MouseEvent('mousedown', {button: 1, cancelable: true}); assertTrue(splitter.dispatchEvent(downRight)); @@ -33,7 +35,7 @@ function testSplitter_ResizePreviousElement() { const splitter = getRequiredElement('splitter'); - cr.ui.decorate(splitter, cr.ui.Splitter); + decorate(splitter, Splitter); splitter.resizeNextElement = false; const previousElement = document.getElementById('previous'); @@ -62,7 +64,7 @@ function testSplitter_ResizeNextElement() { const splitter = getRequiredElement('splitter'); - cr.ui.decorate(splitter, cr.ui.Splitter); + decorate(splitter, Splitter); splitter.resizeNextElement = true; const nextElement = document.getElementById('next'); nextElement.style.width = '0px';
diff --git a/chrome/test/data/webui/settings/site_details_permission_tests.js b/chrome/test/data/webui/settings/site_details_permission_tests.js index 1934c20..cd18a0c5 100644 --- a/chrome/test/data/webui/settings/site_details_permission_tests.js +++ b/chrome/test/data/webui/settings/site_details_permission_tests.js
@@ -56,7 +56,7 @@ return browserProxy.whenCalled('setOriginPermissions').then((args) => { assertEquals(origin, args[0]); - assertDeepEquals([testElement.category], args[1]); + assertDeepEquals(testElement.category, args[1]); assertEquals(expectedContentSetting, args[2]); }); }
diff --git a/chrome/test/data/webui/settings/site_details_tests.js b/chrome/test/data/webui/settings/site_details_tests.js index b5008e4..1f2f06c8 100644 --- a/chrome/test/data/webui/settings/site_details_tests.js +++ b/chrome/test/data/webui/settings/site_details_tests.js
@@ -197,83 +197,6 @@ return siteDetailsElement; } - test('all site settings are shown', function() { - // Add ContentsSettingsTypes which are not supposed to be shown on the Site - // Details page here. - const nonSiteDetailsContentSettingsTypes = [ - ContentSettingsTypes.COOKIES, - ContentSettingsTypes.PROTOCOL_HANDLERS, - ContentSettingsTypes.ZOOM_LEVELS, - ]; - if (!isChromeOS && !isWindows) { - nonSiteDetailsContentSettingsTypes.push( - ContentSettingsTypes.PROTECTED_CONTENT); - } - - // A list of optionally shown content settings mapped to their loadTimeData - // flag string. - const optionalSiteDetailsContentSettingsTypes = - /** @type {!ContentSettingsType : string} */ ({}); - optionalSiteDetailsContentSettingsTypes[ContentSettingsTypes - .BLUETOOTH_SCANNING] = - 'enableExperimentalWebPlatformFeatures'; - optionalSiteDetailsContentSettingsTypes[ContentSettingsTypes - .WINDOW_PLACEMENT] = - 'enableExperimentalWebPlatformFeatures'; - optionalSiteDetailsContentSettingsTypes[ContentSettingsTypes - .PAYMENT_HANDLER] = - 'enablePaymentHandlerContentSetting'; - optionalSiteDetailsContentSettingsTypes[ContentSettingsTypes.ADS] = - 'enableSafeBrowsingSubresourceFilter'; - optionalSiteDetailsContentSettingsTypes[ContentSettingsTypes - .BLUETOOTH_DEVICES] = - 'enableWebBluetoothNewPermissionsBackend'; - - const controlledSettingsCount = /** @type{string : int } */ ({}); - - controlledSettingsCount['enableExperimentalWebPlatformFeatures'] = 2; - controlledSettingsCount['enablePaymentHandlerContentSetting'] = 1; - controlledSettingsCount['enableSafeBrowsingSubresourceFilter'] = 1; - controlledSettingsCount['enableWebBluetoothNewPermissionsBackend'] = 1; - - browserProxy.setPrefs(prefs); - - // First, explicitly set all the optional settings to false. - for (const contentSetting in optionalSiteDetailsContentSettingsTypes) { - const loadTimeDataOverride = {}; - loadTimeDataOverride[optionalSiteDetailsContentSettingsTypes - [contentSetting]] = false; - loadTimeData.overrideValues(loadTimeDataOverride); - } - - // Iterate over each flag in on / off state, assuming that the on state - // means the content setting will show, and off hides it. - for (const contentSetting in optionalSiteDetailsContentSettingsTypes) { - const numContentSettings = Object.keys(ContentSettingsTypes).length - - nonSiteDetailsContentSettingsTypes.length - - Object.keys(optionalSiteDetailsContentSettingsTypes).length; - - const loadTimeDataOverride = {}; - loadTimeDataOverride[optionalSiteDetailsContentSettingsTypes - [contentSetting]] = true; - loadTimeData.overrideValues(loadTimeDataOverride); - testElement = createSiteDetails('https://foo.com:443'); - assertEquals( - numContentSettings + - controlledSettingsCount[optionalSiteDetailsContentSettingsTypes[ - [contentSetting]]], - testElement.getCategoryList().length); - - // Check for setting = off at the end to ensure that the setting does - // not carry over for the next iteration. - loadTimeDataOverride[optionalSiteDetailsContentSettingsTypes - [contentSetting]] = false; - loadTimeData.overrideValues(loadTimeDataOverride); - testElement = createSiteDetails('https://foo.com:443'); - assertEquals(numContentSettings, testElement.getCategoryList().length); - } - }); - test('usage heading shows properly', function() { browserProxy.setPrefs(prefs); testElement = createSiteDetails('https://foo.com:443'); @@ -364,14 +287,6 @@ test('correct pref settings are shown', function() { browserProxy.setPrefs(prefs); - // Make sure all the possible content settings are shown for this test. - loadTimeData.overrideValues({ - enableExperimentalWebPlatformFeatures: true, - enableFileSystemWriteContentSetting: true, - enablePaymentHandlerContentSetting: true, - enableSafeBrowsingSubresourceFilter: true, - enableWebBluetoothNewPermissionsBackend: true, - }); testElement = createSiteDetails('https://foo.com:443'); return browserProxy.whenCalled('isOriginValid') @@ -425,6 +340,31 @@ }); }); + test('categories can be hidden', function() { + browserProxy.setPrefs(prefs); + // Only the categories in this list should be visible to the user. + browserProxy.setCategoryList( + [ContentSettingsTypes.NOTIFICATIONS, ContentSettingsTypes.GEOLOCATION]); + testElement = createSiteDetails('https://foo.com:443'); + + return browserProxy.whenCalled('isOriginValid') + .then(() => { + return browserProxy.whenCalled('getOriginPermissions'); + }) + .then(() => { + testElement.root.querySelectorAll('site-details-permission') + .forEach((siteDetailsPermission) => { + const shouldBeVisible = siteDetailsPermission.category === + ContentSettingsTypes.NOTIFICATIONS || + siteDetailsPermission.category === + ContentSettingsTypes.GEOLOCATION; + assertEquals( + !shouldBeVisible, siteDetailsPermission.$.details.hidden); + }); + }); + }); + + test('show confirmation dialog on reset settings', function() { browserProxy.setPrefs(prefs); testElement = createSiteDetails('https://foo.com:443'); @@ -444,7 +384,7 @@ // Accepting the dialog will make a call to setOriginPermissions. return browserProxy.whenCalled('setOriginPermissions').then((args) => { assertEquals(testElement.origin, args[0]); - assertDeepEquals(testElement.getCategoryList(), args[1]); + assertDeepEquals(null, args[1]); assertEquals(ContentSetting.DEFAULT, args[2]); }); });
diff --git a/chrome/test/data/webui/settings/test_site_settings_prefs_browser_proxy.js b/chrome/test/data/webui/settings/test_site_settings_prefs_browser_proxy.js index 2b3ee99e..ebf2d9532 100644 --- a/chrome/test/data/webui/settings/test_site_settings_prefs_browser_proxy.js +++ b/chrome/test/data/webui/settings/test_site_settings_prefs_browser_proxy.js
@@ -26,6 +26,7 @@ 'fetchBlockAutoplayStatus', 'fetchZoomLevels', 'getAllSites', + 'getCategoryList', 'getChooserExceptionList', 'getDefaultValueForContentType', 'getFormattedBytes', @@ -56,6 +57,38 @@ /** @private {boolean} */ this.hasIncognito_ = false; + this.categoryList_ = [ + ContentSettingsTypes.ADS, + ContentSettingsTypes.AR, + ContentSettingsTypes.AUTOMATIC_DOWNLOADS, + ContentSettingsTypes.BACKGROUND_SYNC, + ContentSettingsTypes.BLUETOOTH_DEVICES, + ContentSettingsTypes.BLUETOOTH_SCANNING, + ContentSettingsTypes.CAMERA, + ContentSettingsTypes.CLIPBOARD, + ContentSettingsTypes.FILE_HANDLING, + ContentSettingsTypes.FILE_SYSTEM_WRITE, + ContentSettingsTypes.FONT_ACCESS, + ContentSettingsTypes.GEOLOCATION, + ContentSettingsTypes.HID_DEVICES, + ContentSettingsTypes.IDLE_DETECTION, + ContentSettingsTypes.IMAGES, + ContentSettingsTypes.JAVASCRIPT, + ContentSettingsTypes.MIC, + ContentSettingsTypes.MIDI_DEVICES, + ContentSettingsTypes.MIXEDSCRIPT, + ContentSettingsTypes.NOTIFICATIONS, + ContentSettingsTypes.PAYMENT_HANDLER, + ContentSettingsTypes.POPUPS, + ContentSettingsTypes.PROTECTED_CONTENT, + ContentSettingsTypes.SENSORS, + ContentSettingsTypes.SERIAL_PORTS, + ContentSettingsTypes.SOUND, + ContentSettingsTypes.USB_DEVICES, + ContentSettingsTypes.VR, + ContentSettingsTypes.WINDOW_PLACEMENT, + ]; + /** @private {!SiteSettingsPref} */ this.prefs_ = createSiteSettingsPrefs([], [], []); @@ -82,6 +115,18 @@ } /** + * Test/fake implementation for {@link getCategoryList}. + * @param {!string} origin the origin for the list of visible permissions. + */ + getCategoryListForTest(origin) { + return this.categoryList_; + } + + setCategoryList(list) { + this.categoryList_ = list; + } + + /** * Pretends an incognito session started or ended. * @param {boolean} hasIncognito True for session started. */ @@ -172,7 +217,9 @@ } /** @override */ - setOriginPermissions(origin, contentTypes, blanketSetting) { + setOriginPermissions(origin, category, blanketSetting) { + const contentTypes = + category ? [category] : this.getCategoryListForTest(origin); for (let i = 0; i < contentTypes.length; ++i) { const type = contentTypes[i]; const exceptionList = this.prefs_.exceptions[type]; @@ -188,12 +235,13 @@ this.setPrefs(this.prefs_); this.methodCalled( - 'setOriginPermissions', [origin, contentTypes, blanketSetting]); + 'setOriginPermissions', [origin, category, blanketSetting]); } /** @override */ - getAllSites(contentTypes) { - this.methodCalled('getAllSites', contentTypes); + getAllSites() { + this.methodCalled('getAllSites'); + const contentTypes = this.getCategoryListForTest('https://example.com'); const origins_set = new Set(); contentTypes.forEach((contentType) => { @@ -236,6 +284,12 @@ } /** @override */ + getCategoryList(origin) { + this.methodCalled('getCategoryList', origin); + return Promise.resolve(this.getCategoryListForTest(origin)); + } + + /** @override */ getFormattedBytes(numBytes) { this.methodCalled('getFormattedBytes', numBytes); return Promise.resolve(`${numBytes} B`);
diff --git a/chrome/test/data/webui/webui_resource_browsertest.cc b/chrome/test/data/webui/webui_resource_browsertest.cc index e3b770b..84cd4b6e 100644 --- a/chrome/test/data/webui/webui_resource_browsertest.cc +++ b/chrome/test/data/webui/webui_resource_browsertest.cc
@@ -175,14 +175,8 @@ LoadTestUrl("?module=js/cr/ui/menu_button_test.m.js"); } -#if BUILDFLAG(IS_CHROMEOS_ASH) -IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, SplitterTest) { - LoadTestUrl("js/cr/ui/splitter_test.html"); -} -#endif - IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, SplitterModuleTest) { - LoadTestUrl("?module=js/cr/ui/splitter_test.m.js"); + LoadTestUrl("?module=js/cr/ui/splitter_test.js"); } IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, UtilTest) {
diff --git a/chrome/updater/BUILD.gn b/chrome/updater/BUILD.gn index 0c50854..398b20e 100644 --- a/chrome/updater/BUILD.gn +++ b/chrome/updater/BUILD.gn
@@ -435,6 +435,7 @@ if (is_win) { sources += [ + "activity_impl_win_unittest.cc", "policy/win/group_policy_manager_unittest.cc", "test/integration_tests_win.cc", "win/installer_api_unittest.cc",
diff --git a/chrome/updater/activity_impl_win.cc b/chrome/updater/activity_impl_win.cc index b8de570c..3ecc1780 100644 --- a/chrome/updater/activity_impl_win.cc +++ b/chrome/updater/activity_impl_win.cc
@@ -6,16 +6,23 @@ #include <string> +#include "base/bind.h" +#include "base/callback.h" #include "base/logging.h" #include "base/strings/strcat.h" #include "base/strings/utf_string_conversions.h" #include "base/win/registry.h" #include "base/win/windows_types.h" #include "chrome/updater/updater_scope.h" +#include "chrome/updater/win/user_info.h" #include "chrome/updater/win/win_constants.h" namespace updater { namespace { + +using ProcessActiveBitUnderKeyCallback = + base::RepeatingCallback<bool(HKEY, const std::wstring&)>; + constexpr wchar_t kDidRun[] = L"dr"; std::wstring GetAppClientStateKey(const std::string& id) { @@ -24,49 +31,107 @@ bool GetActiveBitUnderKey(HKEY rootkey, const std::wstring& key_name) { base::win::RegKey key; - if (key.Open(rootkey, key_name.c_str(), KEY_READ | KEY_WOW64_32KEY) == + if (key.Open(rootkey, key_name.c_str(), KEY_QUERY_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) { + // We support both string and DWORD formats for backward compatibility. std::wstring value; - if (key.ReadValue(kDidRun, &value) == ERROR_SUCCESS && value == L"1") + if ((key.ReadValue(kDidRun, &value) == ERROR_SUCCESS) && (value == L"1")) return true; + + DWORD value_dw = 0; + if ((key.ReadValueDW(kDidRun, &value_dw) == ERROR_SUCCESS) && + (value_dw == 1)) { + return true; + } } return false; } -bool GetMachineActiveBit(const std::string& id) { - // Read the active bit under each user in HKU\<sid>. - for (base::win::RegistryKeyIterator it(HKEY_USERS, L"", KEY_WOW64_32KEY); - it.Valid(); ++it) { - std::wstring user_state_key_name = - std::wstring(it.Name()).append(L"\\").append(GetAppClientStateKey(id)); - if (GetActiveBitUnderKey(HKEY_USERS, user_state_key_name)) - return true; - } - - return false; -} - -void ClearActiveBitUnderKey(HKEY rootkey, const std::wstring& key_name) { +bool ClearActiveBitUnderKey(HKEY rootkey, const std::wstring& key_name) { base::win::RegKey key; - if (key.Open(rootkey, key_name.c_str(), KEY_WRITE | KEY_WOW64_32KEY) != + if (key.Open(rootkey, key_name.c_str(), + KEY_QUERY_VALUE | KEY_SET_VALUE | KEY_WOW64_32KEY) != ERROR_SUCCESS) { VLOG(2) << "Failed to open activity key with write for " << key_name; - return; + return false; } + if (!key.HasValue(kDidRun)) + return true; + + // We always clear the value as a string "0". const LONG result = key.WriteValue(kDidRun, L"0"); VLOG_IF(2, result) << "Failed to clear activity key for " << key_name << ": " << result; + return !result; } -void ClearMachineActiveBit(const std::string& id) { +bool ProcessActiveBit(ProcessActiveBitUnderKeyCallback callback, + HKEY rootkey, + const std::wstring& sid, + const std::string& id) { + const std::wstring rootkey_suffix = + (rootkey == HKEY_USERS) ? base::StrCat({sid, L"\\"}) : L""; + const bool process_success = callback.Run( + rootkey, base::StrCat({rootkey_suffix, GetAppClientStateKey(id)})); + + // For Google Toolbar and similar apps that run at low integrity, we need to + // also look at the low integrity IE key. Note that we cannot use the + // IEGetWriteableHKCU function since this function assumes that we are + // running with the user's credentials. The path is as follows: + // USER_REG_VISTA_LOW_INTEGRITY_HKCU\\SID + // \\GOOPDATE_REG_RELATIVE_CLIENT_STATE\\app_guid + const std::wstring low_integrity_key_name = + base::StrCat({rootkey_suffix, USER_REG_VISTA_LOW_INTEGRITY_HKCU, L"\\", + sid, L"\\", GetAppClientStateKey(id)}); + + return callback.Run(rootkey, low_integrity_key_name) || process_success; +} + +bool ProcessUserActiveBit(ProcessActiveBitUnderKeyCallback callback, + const std::string& id) { + // Clear the active bit under HKCU. + std::wstring sid; + const HRESULT hr = GetProcessUser(nullptr, nullptr, &sid); + if (FAILED(hr)) { + VLOG(2) << "Failed to GetProcessUser " << hr; + return false; + } + + return ProcessActiveBit(callback, HKEY_CURRENT_USER, sid, id); +} + +bool ProcessSystemActiveBit(ProcessActiveBitUnderKeyCallback callback, + const std::string& id) { // Clear the active bit under each user in HKU\<sid>. for (base::win::RegistryKeyIterator it(HKEY_USERS, L"", KEY_WOW64_32KEY); it.Valid(); ++it) { - std::wstring user_state_key_name = - std::wstring(it.Name()).append(L"\\").append(GetAppClientStateKey(id)); - ClearActiveBitUnderKey(HKEY_USERS, user_state_key_name); + const std::wstring sid = it.Name(); + if (ProcessActiveBit(callback, HKEY_USERS, sid, id)) + return true; } + + return false; +} + +bool GetUserActiveBit(const std::string& id) { + // Read the active bit under HKCU. + return ProcessUserActiveBit(base::BindRepeating(&GetActiveBitUnderKey), id); +} + +void ClearUserActiveBit(const std::string& id) { + // Clear the active bit under HKCU. + ProcessUserActiveBit(base::BindRepeating(&ClearActiveBitUnderKey), id); +} + +bool GetSystemActiveBit(const std::string& id) { + // Read the active bit under each user in HKU\<sid>. + return ProcessSystemActiveBit(base::BindRepeating(&GetActiveBitUnderKey), id); +} + +void ClearSystemActiveBit(const std::string& id) { + // Clear the active bit under each user in HKU\<sid>. + ProcessSystemActiveBit(base::BindRepeating(&ClearActiveBitUnderKey), id); } } // namespace @@ -75,11 +140,10 @@ switch (scope) { case UpdaterScope::kUser: // TODO(crbug/1159498): Standardize registry access. - return GetActiveBitUnderKey(HKEY_CURRENT_USER, - GetAppClientStateKey(id).c_str()); + return GetUserActiveBit(id); case UpdaterScope::kSystem: - return GetMachineActiveBit(id); + return GetSystemActiveBit(id); } } @@ -87,12 +151,11 @@ switch (scope) { case UpdaterScope::kUser: // TODO(crbug/1159498): Standardize registry access. - ClearActiveBitUnderKey(HKEY_CURRENT_USER, - GetAppClientStateKey(id).c_str()); + ClearUserActiveBit(id); break; case UpdaterScope::kSystem: - ClearMachineActiveBit(id); + ClearSystemActiveBit(id); break; } }
diff --git a/chrome/updater/activity_impl_win_unittest.cc b/chrome/updater/activity_impl_win_unittest.cc new file mode 100644 index 0000000..7559cd1 --- /dev/null +++ b/chrome/updater/activity_impl_win_unittest.cc
@@ -0,0 +1,202 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/updater/activity_impl.h" + +#include <tchar.h> + +#include <string> +#include <tuple> + +#include "base/bind.h" +#include "base/callback.h" +#include "base/strings/strcat.h" +#include "base/win/registry.h" +#include "base/win/windows_types.h" +#include "chrome/updater/updater_scope.h" +#include "chrome/updater/win/user_info.h" +#include "chrome/updater/win/win_constants.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace updater { +namespace { + +struct ReadActiveBitRetval { + ReadActiveBitRetval() = default; + ReadActiveBitRetval(DWORD result, bool active_bit) + : read_result(result), active_bit_set(active_bit) {} + ReadActiveBitRetval(const ReadActiveBitRetval&) = default; + ReadActiveBitRetval& operator=(const ReadActiveBitRetval&) = default; + + DWORD read_result = ERROR_FILE_NOT_FOUND; + bool active_bit_set = false; +}; + +using ReadActiveBitCallback = + base::RepeatingCallback<ReadActiveBitRetval(base::win::RegKey&)>; +using WriteActiveBitCallback = + base::RepeatingCallback<DWORD(base::win::RegKey&, bool)>; + +struct ReadWriteCallbacks { + ReadWriteCallbacks() = default; + ReadWriteCallbacks(ReadActiveBitCallback read, WriteActiveBitCallback write) + : read_callback(read), write_callback(write) {} + ReadWriteCallbacks(const ReadWriteCallbacks&) = default; + ReadWriteCallbacks& operator=(const ReadWriteCallbacks&) = default; + + ReadActiveBitCallback read_callback; + WriteActiveBitCallback write_callback; +}; + +constexpr wchar_t kDidRun[] = L"dr"; +constexpr char kAppId[] = "{6ACB7D4D-E5BA-48b0-85FE-A4051500A1BD}"; +constexpr wchar_t kClientStateKeyPath[] = + _T(CLIENT_STATE_KEY) L"{6ACB7D4D-E5BA-48b0-85FE-A4051500A1BD}"; + +DWORD WriteActiveBitAsString(base::win::RegKey& key, bool value) { + return key.WriteValue(kDidRun, value ? L"1" : L"0"); +} + +DWORD WriteActiveBitAsDword(base::win::RegKey& key, bool value) { + return key.WriteValue(kDidRun, value); +} + +ReadActiveBitRetval ReadActiveBitAsString(base::win::RegKey& key) { + std::wstring did_run_str(L"0"); + const DWORD result = key.ReadValue(kDidRun, &did_run_str); + return ReadActiveBitRetval(result, did_run_str == L"1"); +} + +ReadActiveBitRetval ReadActiveBitAsDword(base::win::RegKey& key) { + DWORD did_run = 0; + const DWORD result = key.ReadValueDW(kDidRun, &did_run); + return ReadActiveBitRetval(result, !!did_run); +} + +} // namespace + +class ActivityWinTest + : public ::testing::TestWithParam< + std::tuple<UpdaterScope, bool, bool, ReadWriteCallbacks>> { + protected: + void SetUp() override { + std::wstring sid; + ASSERT_HRESULT_SUCCEEDED(GetProcessUser(nullptr, nullptr, &sid)); + low_integrity_key_path_ = + base::StrCat({USER_REG_VISTA_LOW_INTEGRITY_HKCU, L"\\", sid, L"\\", + kClientStateKeyPath}); + TearDown(); + + CreateUserActiveBit(SetUserValue(), WriteActiveBitFn()); + CreateLowIntegrityUserActiveBit(SetLowUserValue(), WriteActiveBitFn()); + } + + void TearDown() override { + base::win::RegKey(HKEY_CURRENT_USER, L"", DELETE) + .DeleteKey(kClientStateKeyPath); + base::win::RegKey(HKEY_CURRENT_USER, L"", DELETE) + .DeleteKey(low_integrity_key_path_.c_str()); + } + + UpdaterScope GetScope() const { return std::get<0>(GetParam()); } + + bool SetUserValue() const { return std::get<1>(GetParam()); } + + bool SetLowUserValue() const { return std::get<2>(GetParam()); } + + WriteActiveBitCallback WriteActiveBitFn() const { + return std::get<3>(GetParam()).write_callback; + } + + ReadActiveBitCallback ReadActiveBitFn() const { + return std::get<3>(GetParam()).read_callback; + } + + void CreateActiveBit(const std::wstring& key_name, + bool value, + WriteActiveBitCallback callback) const { + base::win::RegKey key; + ASSERT_EQ(ERROR_SUCCESS, + key.Create(HKEY_CURRENT_USER, key_name.c_str(), KEY_SET_VALUE)); + ASSERT_EQ(DWORD{ERROR_SUCCESS}, callback.Run(key, value)); + } + + void DeleteActiveBit(const std::wstring& key_name) const { + base::win::RegKey key; + ASSERT_EQ(ERROR_SUCCESS, + key.Open(HKEY_CURRENT_USER, key_name.c_str(), KEY_SET_VALUE)); + ASSERT_EQ(ERROR_SUCCESS, key.DeleteValue(kDidRun)); + } + + void CheckActiveBit(const std::wstring& key_name, + bool expected, + ReadActiveBitCallback callback) const { + base::win::RegKey key; + ASSERT_EQ(ERROR_SUCCESS, + key.Open(HKEY_CURRENT_USER, key_name.c_str(), KEY_QUERY_VALUE)); + + const ReadActiveBitRetval retval = callback.Run(key); + ASSERT_EQ(DWORD{ERROR_SUCCESS}, retval.read_result); + ASSERT_EQ(expected, retval.active_bit_set); + } + + void CreateUserActiveBit(bool value, WriteActiveBitCallback callback) const { + CreateActiveBit(kClientStateKeyPath, value, callback); + } + + void DeleteUserActiveBit() const { DeleteActiveBit(kClientStateKeyPath); } + + void CheckUserActiveBit(bool expected, ReadActiveBitCallback callback) const { + CheckActiveBit(kClientStateKeyPath, expected, callback); + } + + void CreateLowIntegrityUserActiveBit(bool value, + WriteActiveBitCallback callback) const { + CreateActiveBit(low_integrity_key_path_, value, callback); + } + + void DeleteLowIntegrityUserActiveBit() const { + DeleteActiveBit(low_integrity_key_path_); + } + + void CheckLowIntegrityUserActiveBit(bool expected, + ReadActiveBitCallback callback) const { + CheckActiveBit(low_integrity_key_path_, expected, callback); + } + + private: + std::wstring low_integrity_key_path_; +}; + +TEST_P(ActivityWinTest, GetActiveBit) { + ASSERT_EQ(SetUserValue() || SetLowUserValue(), + GetActiveBit(GetScope(), kAppId)); + + CheckUserActiveBit(SetUserValue(), ReadActiveBitFn()); + CheckLowIntegrityUserActiveBit(SetLowUserValue(), ReadActiveBitFn()); +} + +TEST_P(ActivityWinTest, ClearActiveBit) { + ClearActiveBit(GetScope(), kAppId); + + CheckUserActiveBit(false, base::BindRepeating(&ReadActiveBitAsString)); + CheckLowIntegrityUserActiveBit(false, + base::BindRepeating(&ReadActiveBitAsString)); + ASSERT_FALSE(GetActiveBit(GetScope(), kAppId)); +} + +INSTANTIATE_TEST_SUITE_P( + UpdaterScopeSetUserValueSetLowUserValueSetAsDword, + ActivityWinTest, + ::testing::Combine( + ::testing::Values(UpdaterScope::kUser, UpdaterScope::kSystem), + ::testing::Bool(), + ::testing::Bool(), + ::testing::Values( + ReadWriteCallbacks(base::BindRepeating(&ReadActiveBitAsString), + base::BindRepeating(&WriteActiveBitAsString)), + ReadWriteCallbacks(base::BindRepeating(&ReadActiveBitAsDword), + base::BindRepeating(&WriteActiveBitAsDword))))); + +} // namespace updater
diff --git a/chrome/updater/win/win_constants.h b/chrome/updater/win/win_constants.h index fbfad84..624cb515 100644 --- a/chrome/updater/win/win_constants.h +++ b/chrome/updater/win/win_constants.h
@@ -31,6 +31,10 @@ L"Software\\Policies\\" COMPANY_SHORTNAME_STRING L"\\" #define UPDATER_POLICIES_KEY COMPANY_POLICIES_KEY UPDATER_KEY L"\\" +#define USER_REG_VISTA_LOW_INTEGRITY_HKCU \ + L"Software\\Microsoft\\Internet Explorer\\" \ + L"InternetRegistry\\REGISTRY\\USER" + extern const wchar_t kRegValuePV[]; extern const wchar_t kRegValueName[];
diff --git a/chromecast/browser/cast_browser_main_parts.cc b/chromecast/browser/cast_browser_main_parts.cc index 744b0366..eb2472d 100644 --- a/chromecast/browser/cast_browser_main_parts.cc +++ b/chromecast/browser/cast_browser_main_parts.cc
@@ -770,7 +770,6 @@ #else #if defined(USE_AURA) - rounded_window_corners_manager_.reset(); // Reset display change observer here to ensure it is deleted before // display_configurator since display_configurator is deleted when // `cast_browser_process_` is reset below. @@ -781,6 +780,10 @@ cast_browser_process_->cast_browser_metrics()->Finalize(); cast_browser_process_.reset(); +#if defined(USE_AURA) + rounded_window_corners_manager_.reset(); +#endif + window_manager_.reset(); #if defined(USE_AURA) display::Screen::SetScreenInstance(nullptr);
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM index 77d8bdf2..5f9243f 100644 --- a/chromeos/CHROMEOS_LKGM +++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@ -14008.0.0 \ No newline at end of file +14009.0.0 \ No newline at end of file
diff --git a/chromeos/dbus/BUILD.gn b/chromeos/dbus/BUILD.gn index 8fc6eff..585ea332 100644 --- a/chromeos/dbus/BUILD.gn +++ b/chromeos/dbus/BUILD.gn
@@ -34,6 +34,7 @@ ":smbprovider_proto", ":update_engine_proto", ":vm_applications_apps_proto", + ":vm_disk_management_proto", ":vm_permission_service_proto", ":vm_plugin_dispatcher_proto", ":vm_sk_forwarding_proto", @@ -315,6 +316,12 @@ proto_out_dir = "chromeos/dbus/vm_applications" } +proto_library("vm_disk_management_proto") { + sources = [ "//third_party/cros_system_api/dbus/vm_disk_management/disk_management.proto" ] + + proto_out_dir = "chromeos/dbus/vm_disk_management" +} + proto_library("vm_sk_forwarding_proto") { sources = [ "//third_party/cros_system_api/dbus/vm_sk_forwarding/sk_forwarding.proto",
diff --git a/chromeos/dbus/shill/fake_shill_service_client.cc b/chromeos/dbus/shill/fake_shill_service_client.cc index e497e1c4..b1308c6 100644 --- a/chromeos/dbus/shill/fake_shill_service_client.cc +++ b/chromeos/dbus/shill/fake_shill_service_client.cc
@@ -361,6 +361,28 @@ std::move(callback).Run(passphrase ? *passphrase : std::string()); } +void FakeShillServiceClient::RequestTrafficCounters( + const dbus::ObjectPath& service_path, + ListValueCallback callback, + ErrorCallback error_callback) { + base::Value traffic_counters(base::Value::Type::LIST); + + base::Value chrome_dict(base::Value::Type::DICTIONARY); + chrome_dict.SetKey("source", base::Value(shill::kTrafficCounterSourceChrome)); + chrome_dict.SetKey("rx_bytes", base::Value(12)); + chrome_dict.SetKey("tx_bytes", base::Value(32)); + traffic_counters.Append(std::move(chrome_dict)); + + base::Value user_dict(base::Value::Type::DICTIONARY); + user_dict.SetKey("source", base::Value(shill::kTrafficCounterSourceUser)); + user_dict.SetKey("rx_bytes", base::Value(90)); + user_dict.SetKey("tx_bytes", base::Value(87)); + traffic_counters.Append(std::move(user_dict)); + + std::move(callback).Run( + base::Value::AsListValue(std::move(traffic_counters))); +} + ShillServiceClient::TestInterface* FakeShillServiceClient::GetTestInterface() { return this; }
diff --git a/chromeos/dbus/shill/fake_shill_service_client.h b/chromeos/dbus/shill/fake_shill_service_client.h index afc3729..b6fa731 100644 --- a/chromeos/dbus/shill/fake_shill_service_client.h +++ b/chromeos/dbus/shill/fake_shill_service_client.h
@@ -73,6 +73,9 @@ void GetWiFiPassphrase(const dbus::ObjectPath& service_path, StringCallback callback, ErrorCallback error_callback) override; + void RequestTrafficCounters(const dbus::ObjectPath& service_path, + ListValueCallback callback, + ErrorCallback error_callback) override; ShillServiceClient::TestInterface* GetTestInterface() override; // ShillServiceClient::TestInterface overrides.
diff --git a/chromeos/dbus/shill/shill_service_client.cc b/chromeos/dbus/shill/shill_service_client.cc index d1e70f7..b343ccc0 100644 --- a/chromeos/dbus/shill/shill_service_client.cc +++ b/chromeos/dbus/shill/shill_service_client.cc
@@ -213,6 +213,17 @@ std::move(error_callback)); } + void RequestTrafficCounters(const dbus::ObjectPath& service_path, + ListValueCallback callback, + ErrorCallback error_callback) override { + dbus::MethodCall method_call(shill::kFlimflamServiceInterface, + shill::kRequestTrafficCountersFunction); + + GetHelper(service_path) + ->CallListValueMethodWithErrorCallback( + &method_call, std::move(callback), std::move(error_callback)); + } + ShillServiceClient::TestInterface* GetTestInterface() override { return nullptr; }
diff --git a/chromeos/dbus/shill/shill_service_client.h b/chromeos/dbus/shill/shill_service_client.h index b5b1189..77caac1 100644 --- a/chromeos/dbus/shill/shill_service_client.h +++ b/chromeos/dbus/shill/shill_service_client.h
@@ -213,6 +213,12 @@ StringCallback callback, ErrorCallback error_callback) = 0; + // Calls the RequestTrafficCounters method. + // |callback| is called after the method call succeeds. + virtual void RequestTrafficCounters(const dbus::ObjectPath& service_path, + ListValueCallback callback, + ErrorCallback error_callback) = 0; + // Returns an interface for testing (stub only), or returns null. virtual TestInterface* GetTestInterface() = 0;
diff --git a/chromeos/dbus/shill/shill_service_client_unittest.cc b/chromeos/dbus/shill/shill_service_client_unittest.cc index 4e7196b..eb4211b 100644 --- a/chromeos/dbus/shill/shill_service_client_unittest.cc +++ b/chromeos/dbus/shill/shill_service_client_unittest.cc
@@ -291,4 +291,43 @@ base::RunLoop().RunUntilIdle(); } +TEST_F(ShillServiceClientTest, RequestTrafficCounters) { + // Set up value of response. + base::Value traffic_counters(base::Value::Type::LIST); + + base::Value chrome_dict(base::Value::Type::DICTIONARY); + chrome_dict.SetKey("source", base::Value(shill::kTrafficCounterSourceChrome)); + chrome_dict.SetKey("rx_bytes", base::Value(12)); + chrome_dict.SetKey("tx_bytes", base::Value(34)); + traffic_counters.Append(std::move(chrome_dict)); + + base::Value user_dict(base::Value::Type::DICTIONARY); + user_dict.SetKey("source", base::Value(shill::kTrafficCounterSourceUser)); + user_dict.SetKey("rx_bytes", base::Value(90)); + user_dict.SetKey("tx_bytes", base::Value(87)); + traffic_counters.Append(std::move(user_dict)); + + // Create response. + std::unique_ptr<dbus::Response> response(dbus::Response::CreateEmpty()); + dbus::MessageWriter writer(response.get()); + AppendValueDataAsVariant(&writer, traffic_counters); + + // Set expectations. + PrepareForMethodCall(shill::kRequestTrafficCountersFunction, + base::BindRepeating(&ExpectNoArgument), response.get()); + + // Call method. + base::MockCallback<ShillServiceClient::ListValueCallback> + mock_list_value_callback; + base::MockCallback<ShillServiceClient::ErrorCallback> mock_error_callback; + client_->RequestTrafficCounters(dbus::ObjectPath(kExampleServicePath), + mock_list_value_callback.Get(), + mock_error_callback.Get()); + EXPECT_CALL(mock_list_value_callback, Run(_)).Times(1); + EXPECT_CALL(mock_error_callback, Run(_, _)).Times(0); + + // Run the message loop. + base::RunLoop().RunUntilIdle(); +} + } // namespace chromeos
diff --git a/chromeos/profiles/atom.afdo.newest.txt b/chromeos/profiles/atom.afdo.newest.txt index b7365c9d..7024e9b 100644 --- a/chromeos/profiles/atom.afdo.newest.txt +++ b/chromeos/profiles/atom.afdo.newest.txt
@@ -1 +1 @@ -chromeos-chrome-amd64-atom-93-4515.9-1622454091-benchmark-93.0.4529.0-r1-redacted.afdo.xz +chromeos-chrome-amd64-atom-93-4515.9-1622454091-benchmark-93.0.4530.0-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/bigcore.afdo.newest.txt b/chromeos/profiles/bigcore.afdo.newest.txt index 0b3ce2ce..38d663c 100644 --- a/chromeos/profiles/bigcore.afdo.newest.txt +++ b/chromeos/profiles/bigcore.afdo.newest.txt
@@ -1 +1 @@ -chromeos-chrome-amd64-bigcore-93-4515.9-1622460530-benchmark-93.0.4529.0-r1-redacted.afdo.xz +chromeos-chrome-amd64-bigcore-93-4515.9-1622460530-benchmark-93.0.4530.0-r1-redacted.afdo.xz
diff --git a/chromeos/services/libassistant/device_settings_controller.cc b/chromeos/services/libassistant/device_settings_controller.cc index d72bfb1..a6757c7 100644 --- a/chromeos/services/libassistant/device_settings_controller.cc +++ b/chromeos/services/libassistant/device_settings_controller.cc
@@ -13,6 +13,7 @@ #include "chromeos/assistant/internal/internal_util.h" #include "chromeos/assistant/internal/proto/google3/assistant/api/client_op/device_args.pb.h" #include "chromeos/services/libassistant/public/mojom/device_settings_delegate.mojom.h" +#include "chromeos/services/libassistant/util.h" #include "libassistant/shared/internal_api/assistant_manager_internal.h" namespace client_op = ::assistant::api::client_op; @@ -317,7 +318,8 @@ voiceless_options.is_user_initiated = true; assistant_manager_internal_->SendVoicelessInteraction( - CreateGetDeviceSettingInteraction(interaction_id, result), + chromeos::libassistant::CreateGetDeviceSettingInteraction(interaction_id, + result), /*description=*/"get_settings_result", voiceless_options, [](auto) {}); }
diff --git a/chromeos/services/libassistant/display_controller.cc b/chromeos/services/libassistant/display_controller.cc index 453e791..6f8e9599 100644 --- a/chromeos/services/libassistant/display_controller.cc +++ b/chromeos/services/libassistant/display_controller.cc
@@ -11,6 +11,7 @@ #include "chromeos/services/assistant/public/cpp/features.h" #include "chromeos/services/libassistant/display_connection_impl.h" #include "chromeos/services/libassistant/public/mojom/speech_recognition_observer.mojom.h" +#include "chromeos/services/libassistant/util.h" #include "libassistant/shared/internal_api/assistant_manager_internal.h" namespace chromeos { @@ -121,8 +122,9 @@ result_apps_info.emplace_back(result_app_info); } - std::string interaction_proto = CreateVerifyProviderResponseInteraction( - interaction.interaction_id, result_apps_info); + std::string interaction_proto = + chromeos::libassistant::CreateVerifyProviderResponseInteraction( + interaction.interaction_id, result_apps_info); assistant_client::VoicelessOptions options; options.obfuscated_gaia_id = interaction.user_id;
diff --git a/chromeos/services/libassistant/util.cc b/chromeos/services/libassistant/util.cc index a92c3ee..766cac1 100644 --- a/chromeos/services/libassistant/util.cc +++ b/chromeos/services/libassistant/util.cc
@@ -14,10 +14,12 @@ #include "build/util/webkit_version.h" #include "chromeos/assistant/buildflags.h" #include "chromeos/assistant/internal/internal_constants.h" +#include "chromeos/assistant/internal/internal_util.h" #include "chromeos/assistant/internal/util_headers.h" #include "chromeos/dbus/util/version_loader.h" #include "chromeos/services/assistant/public/cpp/features.h" #include "chromeos/services/libassistant/constants.h" +#include "chromeos/services/libassistant/public/cpp/android_app_info.h" using chromeos::assistant::shared::ClientInteraction; using chromeos::assistant::shared::ClientOpResult; @@ -291,22 +293,22 @@ std::string CreateVerifyProviderResponseInteraction( const int interaction_id, - const std::vector<libassistant::mojom::AndroidAppInfoPtr>& apps_info) { + const std::vector<chromeos::assistant::AndroidAppInfo>& apps_info) { // Construct verify provider result proto. VerifyProviderClientOpResult result_proto; bool any_provider_available = false; for (const auto& android_app_info : apps_info) { auto* provider_status = result_proto.add_provider_status(); provider_status->set_status( - GetProviderVerificationStatus(android_app_info->status)); + GetProviderVerificationStatus(android_app_info.status)); auto* app_info = provider_status->mutable_provider_info()->mutable_android_app_info(); - app_info->set_package_name(android_app_info->package_name); - app_info->set_app_version(android_app_info->version); - app_info->set_localized_app_name(android_app_info->localized_app_name); - app_info->set_android_intent(android_app_info->intent); + app_info->set_package_name(android_app_info.package_name); + app_info->set_app_version(android_app_info.version); + app_info->set_localized_app_name(android_app_info.localized_app_name); + app_info->set_android_intent(android_app_info.intent); - if (android_app_info->status == AppStatus::kAvailable) + if (android_app_info.status == AppStatus::kAvailable) any_provider_available = true; } @@ -320,11 +322,11 @@ std::string CreateGetDeviceSettingInteraction( int interaction_id, - const std::vector<libassistant::mojom::DeviceSettingPtr>& device_settings) { + const std::vector<chromeos::assistant::DeviceSetting>& device_settings) { GetDeviceSettingsResult result_proto; for (const auto& setting : device_settings) { - (*result_proto.mutable_settings_info())[setting->setting_id] = - ToSettingInfo(setting->is_supported); + (*result_proto.mutable_settings_info())[setting.setting_id] = + ToSettingInfo(setting.is_supported); } // Construct response interaction.
diff --git a/chromeos/services/libassistant/util.h b/chromeos/services/libassistant/util.h index fa809f2..5b78f46 100644 --- a/chromeos/services/libassistant/util.h +++ b/chromeos/services/libassistant/util.h
@@ -7,8 +7,6 @@ #include <string> -#include "chromeos/services/libassistant/public/mojom/android_app_info.mojom.h" -#include "chromeos/services/libassistant/public/mojom/conversation_controller.mojom.h" #include "third_party/abseil-cpp/absl/types/optional.h" namespace base { @@ -16,6 +14,13 @@ } // namespace base namespace chromeos { +namespace assistant { +struct AndroidAppInfo; +struct DeviceSetting; +} // namespace assistant +} // namespace chromeos + +namespace chromeos { namespace libassistant { // Creates the configuration for libassistant. @@ -28,11 +33,11 @@ std::string CreateVerifyProviderResponseInteraction( const int interaction_id, - const std::vector<libassistant::mojom::AndroidAppInfoPtr>& apps_info); + const std::vector<chromeos::assistant::AndroidAppInfo>& apps_info); std::string CreateGetDeviceSettingInteraction( int interaction_id, - const std::vector<libassistant::mojom::DeviceSettingPtr>& device_settings); + const std::vector<chromeos::assistant::DeviceSetting>& device_settings); } // namespace libassistant } // namespace chromeos
diff --git a/chromeos/services/nearby/public/cpp/nearby_process_manager.cc b/chromeos/services/nearby/public/cpp/nearby_process_manager.cc index 6a9d631..79f40fc 100644 --- a/chromeos/services/nearby/public/cpp/nearby_process_manager.cc +++ b/chromeos/services/nearby/public/cpp/nearby_process_manager.cc
@@ -16,8 +16,11 @@ case NearbyProcessManager::NearbyProcessShutdownReason::kCrash: return os << "Crash"; case NearbyProcessManager::NearbyProcessShutdownReason:: - kMojoPipeDisconnection: - return os << "Mojo Pipe Disconnection"; + kConnectionsMojoPipeDisconnection: + return os << "Connections Mojo Pipe Disconnection"; + case NearbyProcessManager::NearbyProcessShutdownReason:: + kDecoderMojoPipeDisconnection: + return os << "Decoder Mojo Pipe Disconnection"; } }
diff --git a/chromeos/services/nearby/public/cpp/nearby_process_manager.h b/chromeos/services/nearby/public/cpp/nearby_process_manager.h index 684c09a..76c9b41 100644 --- a/chromeos/services/nearby/public/cpp/nearby_process_manager.h +++ b/chromeos/services/nearby/public/cpp/nearby_process_manager.h
@@ -34,8 +34,9 @@ enum class NearbyProcessShutdownReason { kNormal = 0, kCrash = 1, - kMojoPipeDisconnection = 2, - kMaxValue = kMojoPipeDisconnection + kDecoderMojoPipeDisconnection = 3, + kConnectionsMojoPipeDisconnection = 4, + kMaxValue = kConnectionsMojoPipeDisconnection }; using NearbyProcessStoppedCallback =
diff --git a/components/autofill/android/java/src/org/chromium/components/autofill/AutofillSuggestion.java b/components/autofill/android/java/src/org/chromium/components/autofill/AutofillSuggestion.java index 921032a..ed80ce14 100644 --- a/components/autofill/android/java/src/org/chromium/components/autofill/AutofillSuggestion.java +++ b/components/autofill/android/java/src/org/chromium/components/autofill/AutofillSuggestion.java
@@ -115,4 +115,76 @@ public String getFeatureForIPH() { return mFeatureForIPH; } + + /** + * Builder for the {@link AutofillSuggestion}. + */ + public static final class Builder { + private int mIconId; + private boolean mIsBoldLabel; + private boolean mIsIconAtStart; + private boolean mIsDeletable; + private boolean mIsMultiLineLabel; + private String mFeatureForIPH; + private String mItemTag; + private String mLabel; + private String mSubLabel; + private int mSuggestionId; + + public Builder setIconId(int iconId) { + this.mIconId = iconId; + return this; + } + + public Builder setIsBoldLabel(boolean isBoldLabel) { + this.mIsBoldLabel = isBoldLabel; + return this; + } + + public Builder setIsIconAtStart(boolean isIconAtStart) { + this.mIsIconAtStart = isIconAtStart; + return this; + } + + public Builder setIsDeletable(boolean isDeletable) { + this.mIsDeletable = isDeletable; + return this; + } + + public Builder setIsMultiLineLabel(boolean isMultiLineLabel) { + this.mIsMultiLineLabel = isMultiLineLabel; + return this; + } + + public Builder setFeatureForIPH(String featureForIPH) { + this.mFeatureForIPH = featureForIPH; + return this; + } + + public Builder setItemTag(String itemTag) { + this.mItemTag = itemTag; + return this; + } + + public Builder setLabel(String label) { + this.mLabel = label; + return this; + } + + public Builder setSubLabel(String subLabel) { + this.mSubLabel = subLabel; + return this; + } + + public Builder setSuggestionId(int suggestionId) { + this.mSuggestionId = suggestionId; + return this; + } + + public AutofillSuggestion build() { + assert !mLabel.isEmpty() : "AutofillSuggestion requires the label to be set."; + return new AutofillSuggestion(mLabel, mSubLabel, mItemTag, mIconId, mIsIconAtStart, + mSuggestionId, mIsDeletable, mIsMultiLineLabel, mIsBoldLabel, mFeatureForIPH); + } + } }
diff --git a/components/autofill/content/renderer/autofill_agent.h b/components/autofill/content/renderer/autofill_agent.h index 39f9944..7276726 100644 --- a/components/autofill/content/renderer/autofill_agent.h +++ b/components/autofill/content/renderer/autofill_agent.h
@@ -307,9 +307,6 @@ // The elements that currently are being previewed. std::vector<blink::WebFormControlElement> previewed_elements_; - // The form element currently requesting an interactive autocomplete. - blink::WebFormElement in_flight_request_form_; - // Last form which was interacted with by the user. blink::WebFormElement last_interacted_form_;
diff --git a/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.cc b/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.cc index 915fa45..c43af8e 100644 --- a/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.cc +++ b/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.cc
@@ -34,9 +34,12 @@ // If the user has navigated away without saving the modal, then the // |address_profile_save_prompt_callback_| is run here. if (!address_profile_save_prompt_callback_.is_null()) { - // TODO(crbug.com/1167062): Record last action on the infobar and send - // callback accordingly. - InfoBarDismissed(); + DCHECK( + user_decision_ != + AutofillClient::SaveAddressProfileOfferUserDecision::kAccepted && + user_decision_ != + AutofillClient::SaveAddressProfileOfferUserDecision::kEditAccepted); + RunSaveAddressProfilePromptCallback(); } } @@ -117,10 +120,25 @@ locale_); } -bool AutofillSaveUpdateAddressProfileDelegateIOS::EditAccepted() { - RunSaveAddressProfilePromptCallback( - AutofillClient::SaveAddressProfileOfferUserDecision::kEditAccepted); - return true; +void AutofillSaveUpdateAddressProfileDelegateIOS::EditAccepted() { + user_decision_ = + AutofillClient::SaveAddressProfileOfferUserDecision::kEditAccepted; + RunSaveAddressProfilePromptCallback(); +} + +void AutofillSaveUpdateAddressProfileDelegateIOS::EditDeclined() { + SetUserDecision( + AutofillClient::SaveAddressProfileOfferUserDecision::kEditDeclined); +} + +void AutofillSaveUpdateAddressProfileDelegateIOS::MessageTimeout() { + SetUserDecision( + AutofillClient::SaveAddressProfileOfferUserDecision::kMessageTimeout); +} + +void AutofillSaveUpdateAddressProfileDelegateIOS::MessageDeclined() { + SetUserDecision( + AutofillClient::SaveAddressProfileOfferUserDecision::kMessageDeclined); } void AutofillSaveUpdateAddressProfileDelegateIOS::SetProfileInfo( @@ -141,18 +159,14 @@ } bool AutofillSaveUpdateAddressProfileDelegateIOS::Accept() { - RunSaveAddressProfilePromptCallback( - AutofillClient::SaveAddressProfileOfferUserDecision::kAccepted); + user_decision_ = + AutofillClient::SaveAddressProfileOfferUserDecision::kAccepted; + RunSaveAddressProfilePromptCallback(); return true; } -void AutofillSaveUpdateAddressProfileDelegateIOS::InfoBarDismissed() { - RunSaveAddressProfilePromptCallback( - AutofillClient::SaveAddressProfileOfferUserDecision::kDeclined); -} - bool AutofillSaveUpdateAddressProfileDelegateIOS::Cancel() { - RunSaveAddressProfilePromptCallback( + SetUserDecision( AutofillClient::SaveAddressProfileOfferUserDecision::kDeclined); return true; } @@ -163,7 +177,7 @@ } int AutofillSaveUpdateAddressProfileDelegateIOS::GetIconId() const { - // TODO(crbug.com/1167062): Replace with proper icon. + NOTREACHED(); return IDR_INFOBAR_AUTOFILL_CC; } @@ -188,21 +202,32 @@ ConfirmInfoBarDelegate::ShouldExpire(details); } -int AutofillSaveUpdateAddressProfileDelegateIOS::GetButtons() const { - return BUTTON_OK | BUTTON_CANCEL; -} - -std::u16string AutofillSaveUpdateAddressProfileDelegateIOS::GetButtonLabel( - InfoBarButton button) const { - - NOTREACHED() << "Unsupported button label requested."; - return std::u16string(); -} - void AutofillSaveUpdateAddressProfileDelegateIOS:: - RunSaveAddressProfilePromptCallback( - AutofillClient::SaveAddressProfileOfferUserDecision decision) { - std::move(address_profile_save_prompt_callback_).Run(decision, profile_); + RunSaveAddressProfilePromptCallback() { + std::move(address_profile_save_prompt_callback_) + .Run(user_decision_, profile_); +} + +void AutofillSaveUpdateAddressProfileDelegateIOS::SetUserDecision( + AutofillClient::SaveAddressProfileOfferUserDecision user_decision) { + if (user_decision == AutofillClient::SaveAddressProfileOfferUserDecision:: + kMessageTimeout && + user_decision_ == AutofillClient::SaveAddressProfileOfferUserDecision:: + kMessageDeclined) { + // |SaveAddressProfileInfobarBannerInteractionHandler::InfobarVisibilityChanged| + // would be called even when the banner is explicitly dismissed by the + // user. In that case, do not change the |user_decision_|. + return; + } + if (user_decision_ == + AutofillClient::SaveAddressProfileOfferUserDecision::kEditAccepted || + user_decision_ == + AutofillClient::SaveAddressProfileOfferUserDecision::kAccepted) { + // The infobar has already been saved. So, cancel should not change the + // |user_decision_| now. + return; + } + user_decision_ = user_decision; } } // namespace autofill
diff --git a/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.h b/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.h index 0f83f94..710b07a 100644 --- a/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.h +++ b/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.h
@@ -61,9 +61,10 @@ // |original_profile_|. std::vector<ProfileValueDifference> GetProfileDiff() const; - // Calls |RunSaveAddressProfilePromptCallback| with the kEditAccepted| - // decision. - virtual bool EditAccepted(); + virtual void EditAccepted(); + void EditDeclined(); + void MessageTimeout(); + void MessageDeclined(); // Updates |profile_| |type| value to |value|. void SetProfileInfo(const ServerFieldType& type, const std::u16string& value); @@ -76,17 +77,25 @@ std::u16string GetMessageText() const override; infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override; bool ShouldExpire(const NavigationDetails& details) const override; - void InfoBarDismissed() override; - int GetButtons() const override; - std::u16string GetButtonLabel(InfoBarButton button) const override; bool Accept() override; bool Cancel() override; bool EqualsDelegate(infobars::InfoBarDelegate* delegate) const override; +#if defined(UNIT_TEST) + // Getter for |user_decision_|. Used for the testing purposes. + AutofillClient::SaveAddressProfileOfferUserDecision user_decision() const { + return user_decision_; + } +#endif + private: - // Fires the |address_profile_save_prompt_callback_| callback. - void RunSaveAddressProfilePromptCallback( - AutofillClient::SaveAddressProfileOfferUserDecision decision); + // Fires the |address_profile_save_prompt_callback_| callback with + // |user_decision_|. + void RunSaveAddressProfilePromptCallback(); + + // Sets |user_decision_| based on |user_decision|. + void SetUserDecision( + AutofillClient::SaveAddressProfileOfferUserDecision user_decision); // The application locale. std::string locale_; @@ -101,6 +110,11 @@ // The callback to run once the user makes a decision. AutofillClient::AddressProfileSavePromptCallback address_profile_save_prompt_callback_; + + // Records the last user decision based on the interactions with the + // banner/modal to be sent with |address_profile_save_prompt_callback_|. + AutofillClient::SaveAddressProfileOfferUserDecision user_decision_ = + AutofillClient::SaveAddressProfileOfferUserDecision::kIgnored; }; } // namespace autofill
diff --git a/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios_unittest.cc b/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios_unittest.cc index 780549c..3921741 100644 --- a/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios_unittest.cc +++ b/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios_unittest.cc
@@ -70,4 +70,49 @@ std::u16string(u"John Doe, 666 Erebus St.")); } +// Tests that the callback is run with kDeclined on destruction. +TEST(AutofillSaveUpdateAddressProfileDelegateIOSTest, + TestCallbackOnDestruction) { + AutofillProfile profile = test::GetFullProfile(); + base::MockCallback<AutofillClient::AddressProfileSavePromptCallback> callback; + auto delegate = std::make_unique<AutofillSaveUpdateAddressProfileDelegateIOS>( + profile, /*original_profile=*/nullptr, /*locale=*/"en-US", + callback.Get()); + + delegate->Cancel(); + EXPECT_CALL( + callback, + Run(AutofillClient::SaveAddressProfileOfferUserDecision::kDeclined, + testing::_)); + // The callback should run in the destructor. + delegate.reset(); +} + +// Tests that the callback is run with kAccepted on Accept. +TEST(AutofillSaveUpdateAddressProfileDelegateIOSTest, TestCallbackOnSave) { + AutofillProfile profile = test::GetFullProfile(); + base::MockCallback<AutofillClient::AddressProfileSavePromptCallback> callback; + EXPECT_CALL( + callback, + Run(AutofillClient::SaveAddressProfileOfferUserDecision::kAccepted, + testing::_)); + AutofillSaveUpdateAddressProfileDelegateIOS( + profile, /*original_profile=*/nullptr, /*locale=*/"en-US", callback.Get()) + .Accept(); +} + +// Tests that the callback is run with kEditAccepted on EditAccepted. +TEST(AutofillSaveUpdateAddressProfileDelegateIOSTest, + TestCallbackOnEditAccepted) { + AutofillProfile profile = test::GetFullProfile(); + base::MockCallback<AutofillClient::AddressProfileSavePromptCallback> callback; + EXPECT_CALL( + callback, + Run(AutofillClient::SaveAddressProfileOfferUserDecision::kEditAccepted, + testing::_)); + AutofillSaveUpdateAddressProfileDelegateIOS( + profile, /*original_profile=*/nullptr, /*locale=*/"en-US", callback.Get()) + .EditAccepted(); +} + } // namespace autofill
diff --git a/components/full_restore/arc_read_handler.cc b/components/full_restore/arc_read_handler.cc index 698f507..847b72c 100644 --- a/components/full_restore/arc_read_handler.cc +++ b/components/full_restore/arc_read_handler.cc
@@ -23,7 +23,12 @@ } void ArcReadHandler::AddArcWindowCandidate(aura::Window* window) { - arc_window_candidates_.insert(window); + // If the ARC task is not created yet, add |window| to + // |arc_window_candidates_| to wait for the task to be created. + if (!base::Contains(task_id_to_window_id_, + window->GetProperty(::full_restore::kWindowIdKey))) { + arc_window_candidates_.insert(window); + } } void ArcReadHandler::OnWindowDestroyed(aura::Window* window) { @@ -116,7 +121,7 @@ return window_info; } -int32_t ArcReadHandler::GetArcRestoreWindowId(int32_t task_id) { +int32_t ArcReadHandler::GetArcRestoreWindowIdForTaskId(int32_t task_id) { auto it = task_id_to_window_id_.find(task_id); if (it != task_id_to_window_id_.end()) return it->second; @@ -132,6 +137,12 @@ return kParentToHiddenContainer; } +int32_t ArcReadHandler::GetArcRestoreWindowIdForSessionId(int32_t session_id) { + // If `session_id` doesn't exist, that means there is no ARC app restored. + auto it = session_id_to_window_id_.find(session_id); + return it == session_id_to_window_id_.end() ? 0 : it->second; +} + int32_t ArcReadHandler::GetArcSessionId() { if (session_id_ < kArcSessionIdOffsetForRestoredLaunching) { LOG(WARNING) << "ARC session id is overflow: " << session_id_;
diff --git a/components/full_restore/arc_read_handler.h b/components/full_restore/arc_read_handler.h index 2761ac0..fed6664 100644 --- a/components/full_restore/arc_read_handler.h +++ b/components/full_restore/arc_read_handler.h
@@ -56,7 +56,10 @@ std::unique_ptr<WindowInfo> GetWindowInfo(int32_t restore_window_id); // Returns the restore window id for the ARC app's |task_id|. - int32_t GetArcRestoreWindowId(int32_t task_id); + int32_t GetArcRestoreWindowIdForTaskId(int32_t task_id); + + // Returns the restore window id for the ARC app's `session_id`. + int32_t GetArcRestoreWindowIdForSessionId(int32_t session_id); // Generates the ARC session id (1,000,000,001 - INT_MAX) for restored ARC // apps.
diff --git a/components/full_restore/full_restore_read_and_save_unittest.cc b/components/full_restore/full_restore_read_and_save_unittest.cc index 63b01589..9eab7de1 100644 --- a/components/full_restore/full_restore_read_and_save_unittest.cc +++ b/components/full_restore/full_restore_read_and_save_unittest.cc
@@ -491,10 +491,15 @@ read_handler->SetArcSessionIdForWindowId(kArcSessionId2, kArcTaskId1); EXPECT_EQ(1u, read_test_api.GetArcSessionIdMap().size()); + // Before OnTaskCreated is called, return |kArcTaskId1| for |kArcSessionId2| + // to simulate the ghost window property setting. + EXPECT_EQ(kArcTaskId1, + full_restore::GetArcRestoreWindowIdForSessionId(kArcSessionId2)); + // Before OnTaskCreated is called, return -1 to add the ARC app window to the // hidden container. EXPECT_EQ(kParentToHiddenContainer, - full_restore::GetArcRestoreWindowId(kArcTaskId2)); + full_restore::GetArcRestoreWindowIdForTaskId(kArcTaskId2)); // Call OnTaskCreated to simulate that the ARC app with |kAppId| has been // launched, and the new task id |kArcTaskId2| has been created with @@ -506,7 +511,8 @@ // map can be cleared. And verify that we can get the restore window id // |kArcTaskId1| with the new |kArcTaskId2|. EXPECT_TRUE(read_test_api.GetArcSessionIdMap().empty()); - EXPECT_EQ(kArcTaskId1, full_restore::GetArcRestoreWindowId(kArcTaskId2)); + EXPECT_EQ(kArcTaskId1, + full_restore::GetArcRestoreWindowIdForTaskId(kArcTaskId2)); // Verify |window_info| for |kArcTaskId1|. auto window_info = GetArcWindowInfo(kArcTaskId1); @@ -517,7 +523,7 @@ // for |kArcTaskId2|, and verify the task id map is now empty and a invalid // value is returned when trying to get the restore window id. read_handler->OnTaskDestroyed(kArcTaskId2); - EXPECT_EQ(0, full_restore::GetArcRestoreWindowId(kArcTaskId2)); + EXPECT_EQ(0, full_restore::GetArcRestoreWindowIdForTaskId(kArcTaskId2)); EXPECT_TRUE(read_test_api.GetArcTaskIdMap().empty()); EXPECT_TRUE(read_test_api.GetArcWindowIdMap().empty()); }
diff --git a/components/full_restore/full_restore_read_handler.cc b/components/full_restore/full_restore_read_handler.cc index 67dcfb2..2dd67e4 100644 --- a/components/full_restore/full_restore_read_handler.cc +++ b/components/full_restore/full_restore_read_handler.cc
@@ -47,13 +47,7 @@ if (window_id == kParentToHiddenContainer || arc_read_handler_->HasRestoreData(window_id)) { observed_windows_.AddObservation(window); - - // If |window| is added to a hidden container, that means the ARC task is - // not created yet, so add |window| to |arc_window_candidates_| to wait - // the task to be created. - if (window_id == kParentToHiddenContainer) - arc_read_handler_->AddArcWindowCandidate(window); - + arc_read_handler_->AddArcWindowCandidate(window); FullRestoreInfo::GetInstance()->OnWindowInitialized(window); } return; @@ -182,11 +176,20 @@ return it->second->FetchRestoreWindowId(app_id); } -int32_t FullRestoreReadHandler::GetArcRestoreWindowId(int32_t task_id) { +int32_t FullRestoreReadHandler::GetArcRestoreWindowIdForTaskId( + int32_t task_id) { if (!arc_read_handler_) return 0; - return arc_read_handler_->GetArcRestoreWindowId(task_id); + return arc_read_handler_->GetArcRestoreWindowIdForTaskId(task_id); +} + +int32_t FullRestoreReadHandler::GetArcRestoreWindowIdForSessionId( + int32_t session_id) { + if (!arc_read_handler_) + return 0; + + return arc_read_handler_->GetArcRestoreWindowIdForSessionId(session_id); } void FullRestoreReadHandler::ModifyWidgetParams(
diff --git a/components/full_restore/full_restore_read_handler.h b/components/full_restore/full_restore_read_handler.h index 2a529329..dd06e52 100644 --- a/components/full_restore/full_restore_read_handler.h +++ b/components/full_restore/full_restore_read_handler.h
@@ -102,10 +102,10 @@ int32_t FetchRestoreWindowId(const std::string& app_id); // Returns the restore window id for the ARC app's |task_id|. - // - // TODO(crbug.com/1146900): Handle the scenario that the window is created - // first, and OnTaskCreated is called later.. - int32_t GetArcRestoreWindowId(int32_t task_id); + int32_t GetArcRestoreWindowIdForTaskId(int32_t task_id); + + // Returns the restore window id for the ARC app's |session_id|. + int32_t GetArcRestoreWindowIdForSessionId(int32_t session_id); // Modifies `out_params` based on the window info associated with // `restore_window_id`.
diff --git a/components/full_restore/full_restore_utils.cc b/components/full_restore/full_restore_utils.cc index d776e2c..3ddde78 100644 --- a/components/full_restore/full_restore_utils.cc +++ b/components/full_restore/full_restore_utils.cc
@@ -54,11 +54,20 @@ return FullRestoreReadHandler::GetInstance()->FetchRestoreWindowId(app_id); } -int32_t GetArcRestoreWindowId(int32_t task_id) { +int32_t GetArcRestoreWindowIdForTaskId(int32_t task_id) { if (!ash::features::IsFullRestoreEnabled()) return 0; - return FullRestoreReadHandler::GetInstance()->GetArcRestoreWindowId(task_id); + return FullRestoreReadHandler::GetInstance()->GetArcRestoreWindowIdForTaskId( + task_id); +} + +int32_t GetArcRestoreWindowIdForSessionId(int32_t session_id) { + if (!ash::features::IsFullRestoreEnabled()) + return 0; + + return FullRestoreReadHandler::GetInstance() + ->GetArcRestoreWindowIdForSessionId(session_id); } bool ShouldRestore(const AccountId& account_id) {
diff --git a/components/full_restore/full_restore_utils.h b/components/full_restore/full_restore_utils.h index 747a46b2..14d2e376 100644 --- a/components/full_restore/full_restore_utils.h +++ b/components/full_restore/full_restore_utils.h
@@ -95,7 +95,11 @@ // Returns the restore window id for the ARC app's |task_id|. COMPONENT_EXPORT(FULL_RESTORE) -int32_t GetArcRestoreWindowId(int32_t task_id); +int32_t GetArcRestoreWindowIdForTaskId(int32_t task_id); + +// Returns the restore window id for the ARC app's |session_id|. +COMPONENT_EXPORT(FULL_RESTORE) +int32_t GetArcRestoreWindowIdForSessionId(int32_t session_id); // Returns true if we should restore apps and pages based on the restore setting // and the user's choice from the notification. Otherwise, returns false.
diff --git a/components/history/core/browser/visit_database.cc b/components/history/core/browser/visit_database.cc index e7c04dc0..ea6ef6b 100644 --- a/components/history/core/browser/visit_database.cc +++ b/components/history/core/browser/visit_database.cc
@@ -790,17 +790,13 @@ " visit_time >= ? AND " // Restrict to visits that are older than the specified end time. " visit_time < ? ")); - statement.BindInt64(0, - begin_time.ToDeltaSinceWindowsEpoch().InMicroseconds()); - statement.BindInt64(1, end_time.ToDeltaSinceWindowsEpoch().InMicroseconds()); + statement.BindTime(0, begin_time); + statement.BindTime(1, end_time); std::vector<DomainVisit> domain_visits; while (statement.Step()) { const GURL url(statement.ColumnString(1)); if (google_util::IsGoogleSearchUrl(url)) { - domain_visits.emplace_back( - url.host(), - base::Time::FromDeltaSinceWindowsEpoch( - base::TimeDelta::FromMicroseconds(statement.ColumnInt64(0)))); + domain_visits.emplace_back(url.host(), statement.ColumnTime(0)); } } return domain_visits;
diff --git a/components/history_clusters/core/memories_features.cc b/components/history_clusters/core/memories_features.cc index 8824f1a3..2cacde3a 100644 --- a/components/history_clusters/core/memories_features.cc +++ b/components/history_clusters/core/memories_features.cc
@@ -26,7 +26,7 @@ &kMemories, "MemoriesPersistContextAnnotationsInHistoryDb", false}; const base::FeatureParam<int> kMaxVisitsToCluster{ - &kMemories, "MemoriesMaxVisitsToCluster", 10}; + &kMemories, "MemoriesMaxVisitsToCluster", 1000}; const base::FeatureParam<int> kMaxDaysToCluster{&kMemories, "MemoriesMaxDaysToCluster", 9};
diff --git a/components/history_clusters/core/memories_remote_model_helper.cc b/components/history_clusters/core/memories_remote_model_helper.cc index 9232a9b..19fac31 100644 --- a/components/history_clusters/core/memories_remote_model_helper.cc +++ b/components/history_clusters/core/memories_remote_model_helper.cc
@@ -164,6 +164,10 @@ std::string request_body; base::JSONWriter::Write(container_value, &request_body); + // Also dump the encoded request, as it allows us to repro server-side errors. + if (debug_logger_) + debug_logger_->Run(request_body); + auto url_loader = CreateLoader(CreateRequest(endpoint), request_body); network::SimpleURLLoader* unowned_url_loader = url_loader.get(); unowned_url_loader->DownloadToString(
diff --git a/components/keep_alive_registry/keep_alive_types.cc b/components/keep_alive_registry/keep_alive_types.cc index bdb31eb..2138828 100644 --- a/components/keep_alive_registry/keep_alive_types.cc +++ b/components/keep_alive_registry/keep_alive_types.cc
@@ -68,6 +68,8 @@ return out << "NATIVE_MESSAGING_HOST_ERROR_REPORT"; case KeepAliveOrigin::WEB_APP_INTENT_PICKER: return out << "WEB_APP_INTENT_PICKER"; + case KeepAliveOrigin::WEB_APP_PROTOCOL_HANDLER_LAUNCH: + return out << "WEB_APP_PROTOCOL_HANDLER_LAUNCH"; case KeepAliveOrigin::SESSION_DATA_DELETER: return out << "SESSION_DATA_DELETER"; }
diff --git a/components/keep_alive_registry/keep_alive_types.h b/components/keep_alive_registry/keep_alive_types.h index 6a2ec7d..ab3fb23 100644 --- a/components/keep_alive_registry/keep_alive_types.h +++ b/components/keep_alive_registry/keep_alive_types.h
@@ -62,6 +62,7 @@ USER_MANAGER_VIEW, CREDENTIAL_PROVIDER_SIGNIN_DIALOG, WEB_APP_INTENT_PICKER, + WEB_APP_PROTOCOL_HANDLER_LAUNCH, // c/b/web_applications APP_START_URL_MIGRATION,
diff --git a/components/ntp_tiles/most_visited_sites.cc b/components/ntp_tiles/most_visited_sites.cc index ba0539d..8b1a9a42 100644 --- a/components/ntp_tiles/most_visited_sites.cc +++ b/components/ntp_tiles/most_visited_sites.cc
@@ -250,7 +250,7 @@ } void MostVisitedSites::InitializeCustomLinks() { - if (!custom_links_ || !current_tiles_.has_value() || !custom_links_enabled_) + if (!custom_links_ || !current_tiles_.has_value() || !IsCustomLinksEnabled()) return; if (custom_links_->Initialize(current_tiles_.value())) @@ -258,7 +258,7 @@ } void MostVisitedSites::UninitializeCustomLinks() { - if (!custom_links_ || !custom_links_enabled_) + if (!custom_links_ || !IsCustomLinksEnabled()) return; custom_links_action_count_ = -1; @@ -267,22 +267,46 @@ } bool MostVisitedSites::IsCustomLinksInitialized() { - if (!custom_links_ || !custom_links_enabled_) + if (!custom_links_ || !IsCustomLinksEnabled()) return false; return custom_links_->IsInitialized(); } void MostVisitedSites::EnableCustomLinks(bool enable) { - if (custom_links_enabled_ != enable) { - custom_links_enabled_ = enable; +#if !defined(OS_IOS) && !defined(OS_ANDROID) + if (IsCustomLinksEnabled() != enable) { + prefs_->SetBoolean(prefs::kNtpUseMostVisitedTiles, !enable); BuildCurrentTiles(); } +#endif // !defined(OS_IOS) && !defined(OS_ANDROID) +} + +bool MostVisitedSites::IsCustomLinksEnabled() const { +#if !defined(OS_IOS) && !defined(OS_ANDROID) + return !prefs_->GetBoolean(prefs::kNtpUseMostVisitedTiles); +#else + return false; +#endif // !defined(OS_IOS) && !defined(OS_ANDROID) +} + +void MostVisitedSites::SetShortcutsVisible(bool visible) { +#if !defined(OS_IOS) && !defined(OS_ANDROID) + prefs_->SetBoolean(prefs::kNtpShortcutsVisible, visible); +#endif // !defined(OS_IOS) && !defined(OS_ANDROID) +} + +bool MostVisitedSites::IsShortcutsVisible() const { +#if !defined(OS_IOS) && !defined(OS_ANDROID) + return prefs_->GetBoolean(prefs::kNtpShortcutsVisible); +#else + return true; +#endif // !defined(OS_IOS) && !defined(OS_ANDROID) } bool MostVisitedSites::AddCustomLink(const GURL& url, const std::u16string& title) { - if (!custom_links_ || !custom_links_enabled_) + if (!custom_links_ || !IsCustomLinksEnabled()) return false; bool is_first_action = !custom_links_->IsInitialized(); @@ -305,7 +329,7 @@ bool MostVisitedSites::UpdateCustomLink(const GURL& url, const GURL& new_url, const std::u16string& new_title) { - if (!custom_links_ || !custom_links_enabled_) + if (!custom_links_ || !IsCustomLinksEnabled()) return false; bool is_first_action = !custom_links_->IsInitialized(); @@ -326,7 +350,7 @@ } bool MostVisitedSites::ReorderCustomLink(const GURL& url, size_t new_pos) { - if (!custom_links_ || !custom_links_enabled_) + if (!custom_links_ || !IsCustomLinksEnabled()) return false; bool is_first_action = !custom_links_->IsInitialized(); @@ -347,7 +371,7 @@ } bool MostVisitedSites::DeleteCustomLink(const GURL& url) { - if (!custom_links_ || !custom_links_enabled_) + if (!custom_links_ || !IsCustomLinksEnabled()) return false; bool is_first_action = !custom_links_->IsInitialized(); @@ -368,7 +392,7 @@ } void MostVisitedSites::UndoCustomLinkAction() { - if (!custom_links_ || !custom_links_enabled_) + if (!custom_links_ || !IsCustomLinksEnabled()) return; // If this is undoing the first action after initialization, uninitialize @@ -424,10 +448,23 @@ void MostVisitedSites::RegisterProfilePrefs( user_prefs::PrefRegistrySyncable* registry) { registry->RegisterIntegerPref(prefs::kNumPersonalTiles, 0); +#if !defined(OS_IOS) && !defined(OS_ANDROID) + registry->RegisterBooleanPref(prefs::kNtpUseMostVisitedTiles, false); + registry->RegisterBooleanPref(prefs::kNtpShortcutsVisible, true); +#endif // !defined(OS_IOS) && !defined(OS_ANDROID) +} + +// static +void MostVisitedSites::ResetProfilePrefs(PrefService* prefs) { + prefs->SetInteger(prefs::kNumPersonalTiles, 0); +#if !defined(OS_IOS) && !defined(OS_ANDROID) + prefs->SetBoolean(prefs::kNtpUseMostVisitedTiles, false); + prefs->SetBoolean(prefs::kNtpShortcutsVisible, true); +#endif // !defined(OS_IOS) && !defined(OS_ANDROID) } size_t MostVisitedSites::GetMaxNumSites() const { - return max_num_sites_ + (custom_links_ && custom_links_enabled_ ? 1 : 0); + return max_num_sites_ + (custom_links_ && IsCustomLinksEnabled() ? 1 : 0); } void MostVisitedSites::InitiateTopSitesQuery() { @@ -736,7 +773,7 @@ void MostVisitedSites::OnCustomLinksChanged() { DCHECK(custom_links_); - if (!custom_links_enabled_) + if (!IsCustomLinksEnabled()) return; if (custom_links_->IsInitialized()) {
diff --git a/components/ntp_tiles/most_visited_sites.h b/components/ntp_tiles/most_visited_sites.h index 6720ee68..fc7d7a69 100644 --- a/components/ntp_tiles/most_visited_sites.h +++ b/components/ntp_tiles/most_visited_sites.h
@@ -182,6 +182,13 @@ // when a third-party NTP is being used, or when the user switches between // custom links and Most Visited sites. void EnableCustomLinks(bool enable); + // Returns true if custom links have been enabled and false if custom links + // are disabled and Most Visited sites should be returned instead. + bool IsCustomLinksEnabled() const; + // Sets the visibility of the NTP tiles. + void SetShortcutsVisible(bool visible); + // Returns whether NTP tiles should be shown. + bool IsShortcutsVisible() const; // Adds a custom link. If the number of current links is maxed, returns false // and does nothing. Will initialize custom links if they have not been // initialized yet, unless the action fails. Custom links must be enabled. @@ -219,6 +226,7 @@ void OnBlockedSitesChanged() override; static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); + static void ResetProfilePrefs(PrefService* prefs); // Workhorse for SaveNewTilesAndNotify. Implemented as a separate static and // public method for ease of testing. @@ -359,9 +367,6 @@ // Do not use directly. Use GetMaxNumSites() instead. size_t max_num_sites_; - // False if custom links is disabled and Most Visited sites should be returned - // instead. - bool custom_links_enabled_ = true; // Number of actions after custom link initialization. Set to -1 and not // incremented if custom links was not initialized during this session. int custom_links_action_count_ = -1;
diff --git a/components/ntp_tiles/pref_names.cc b/components/ntp_tiles/pref_names.cc index 8044493..39ef802 100644 --- a/components/ntp_tiles/pref_names.cc +++ b/components/ntp_tiles/pref_names.cc
@@ -35,5 +35,13 @@ const char kCustomLinksList[] = "custom_links.list"; const char kCustomLinksInitialized[] = "custom_links.initialized"; +#if !defined(OS_IOS) && !defined(OS_ANDROID) +// Tracks whether the user has chosen to hide the shortcuts tiles on the NTP. +const char kNtpShortcutsVisible[] = "ntp.shortcust_visible"; +// Tracks whether the user has chosen to use custom links or most visited sites +// for the shortcut tiles on the NTP. +const char kNtpUseMostVisitedTiles[] = "ntp.use_most_visited_tiles"; +#endif // !defined(OS_IOS) && !defined(OS_ANDROID) + } // namespace prefs } // namespace ntp_tiles
diff --git a/components/ntp_tiles/pref_names.h b/components/ntp_tiles/pref_names.h index 1b0959b..c412f27 100644 --- a/components/ntp_tiles/pref_names.h +++ b/components/ntp_tiles/pref_names.h
@@ -23,6 +23,11 @@ extern const char kCustomLinksList[]; extern const char kCustomLinksInitialized[]; +#if !defined(OS_IOS) && !defined(OS_ANDROID) +extern const char kNtpShortcutsVisible[]; +extern const char kNtpUseMostVisitedTiles[]; +#endif // !defined(OS_IOS) && !defined(OS_ANDROID) + } // namespace prefs } // namespace ntp_tiles
diff --git a/components/omnibox/browser/android/java/src/org/chromium/components/omnibox/AutocompleteResult.java b/components/omnibox/browser/android/java/src/org/chromium/components/omnibox/AutocompleteResult.java index e5cdd9f0..79029c2 100644 --- a/components/omnibox/browser/android/java/src/org/chromium/components/omnibox/AutocompleteResult.java +++ b/components/omnibox/browser/android/java/src/org/chromium/components/omnibox/AutocompleteResult.java
@@ -9,6 +9,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; import androidx.core.util.ObjectsCompat; import org.chromium.base.annotations.CalledByNative; @@ -70,7 +71,8 @@ * @param suggestions List of AutocompleteMatch objects. * @param groupsDetails Additional information about the AutocompleteMatch groups. */ - private AutocompleteResult(long nativeResult, @Nullable List<AutocompleteMatch> suggestions, + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + AutocompleteResult(long nativeResult, @Nullable List<AutocompleteMatch> suggestions, @Nullable SparseArray<GroupDetails> groupsDetails) { // Consider all locally constructed AutocompleteResult objects as coming from Cache. // These results do not have a native counterpart, meaning there's no corresponding C++ @@ -99,8 +101,25 @@ return new AutocompleteResult(0, suggestions, groupsDetails); } + /** + * Create AutocompleteResult object from native object. + * + * Newly created AutocompleteResult object is associated with its Native counterpart. + * + * @param nativeAutocompleteResult Corresponding Native object. + * @param suggestions Array of encompassed, associated AutocompleteMatch objects. + * These suggestions must be exact same and in same order as the ones held by + * Native AutocompleteResult content. + * @param groupIds An array of known group identifiers (used for matching group headers). + * @param groupNames An array of group names for each of the identifiers. The length and + * the content of this array must match the length and IDs of the |groupIds|. + * @param groupCollapsedStates An array of group default collapsed states. The length and + * the content of this array must match the length and IDs of the |groupIds|. + * @return AutocompleteResult object encompassing supplied information. + */ + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) @CalledByNative - private static AutocompleteResult build(long nativeAutocompleteResult, + static AutocompleteResult fromNative(long nativeAutocompleteResult, @NonNull AutocompleteMatch[] suggestions, @NonNull int[] groupIds, @NonNull String[] groupNames, @NonNull boolean[] groupCollapsedStates) { assert groupIds.length == groupNames.length; @@ -124,8 +143,9 @@ Collections.addAll(mSuggestions, suggestions); } + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) @CalledByNative - private void destroy() { + void notifyNativeDestroyed() { mNativeAutocompleteResult = 0; }
diff --git a/components/omnibox/browser/android/javatests/src/org/chromium/components/omnibox/AutocompleteResultUnitTest.java b/components/omnibox/browser/android/javatests/src/org/chromium/components/omnibox/AutocompleteResultUnitTest.java index 162f969d..81543bb 100644 --- a/components/omnibox/browser/android/javatests/src/org/chromium/components/omnibox/AutocompleteResultUnitTest.java +++ b/components/omnibox/browser/android/javatests/src/org/chromium/components/omnibox/AutocompleteResultUnitTest.java
@@ -279,4 +279,33 @@ Assert.assertNotEquals(res1, res2); Assert.assertNotEquals(res1.hashCode(), res2.hashCode()); } + + @Test + @SmallTest + public void resultCreatedFromCacheIsIdentifiedAsCached() { + AutocompleteResult res = new AutocompleteResult(0, null, null); + Assert.assertTrue(res.isFromCachedResult()); + res.notifyNativeDestroyed(); + Assert.assertTrue(res.isFromCachedResult()); + + res = AutocompleteResult.fromCache(new ArrayList<>(), new SparseArray<>()); + Assert.assertTrue(res.isFromCachedResult()); + res.notifyNativeDestroyed(); + Assert.assertTrue(res.isFromCachedResult()); + } + + @Test + @SmallTest + public void resultCreatedFromNativeAreNotIdentifiedAsCached() { + AutocompleteResult res = new AutocompleteResult(0x12345678, null, null); + Assert.assertFalse(res.isFromCachedResult()); + res.notifyNativeDestroyed(); + Assert.assertFalse(res.isFromCachedResult()); + + res = AutocompleteResult.fromNative( + 0xfedcba98, new AutocompleteMatch[0], new int[0], new String[0], new boolean[0]); + Assert.assertFalse(res.isFromCachedResult()); + res.notifyNativeDestroyed(); + Assert.assertFalse(res.isFromCachedResult()); + } }
diff --git a/components/omnibox/browser/autocomplete_provider_client.cc b/components/omnibox/browser/autocomplete_provider_client.cc index 418d3d8..d0805f83 100644 --- a/components/omnibox/browser/autocomplete_provider_client.cc +++ b/components/omnibox/browser/autocomplete_provider_client.cc
@@ -9,6 +9,10 @@ return nullptr; } +bool AutocompleteProviderClient::AllowDeletingBrowserHistory() const { + return true; +} + std::string AutocompleteProviderClient::ProfileUserName() const { return ""; }
diff --git a/components/omnibox/browser/autocomplete_provider_client.h b/components/omnibox/browser/autocomplete_provider_client.h index 05141fc6..0f30bd17 100644 --- a/components/omnibox/browser/autocomplete_provider_client.h +++ b/components/omnibox/browser/autocomplete_provider_client.h
@@ -125,6 +125,9 @@ virtual bool IsOffTheRecord() const = 0; virtual bool SearchSuggestEnabled() const = 0; + // True for almost all users except ones with a specific enterprise policy. + virtual bool AllowDeletingBrowserHistory() const; + // Returns whether personalized URL data collection is enabled. I.e., // the user has consented to have URLs recorded keyed by their Google account. // In this case, the user has agreed to share browsing data with Google and so
diff --git a/components/omnibox/browser/autocomplete_result_android.cc b/components/omnibox/browser/autocomplete_result_android.cc index 72687ca..4cc7bda 100644 --- a/components/omnibox/browser/autocomplete_result_android.cc +++ b/components/omnibox/browser/autocomplete_result_android.cc
@@ -62,7 +62,7 @@ ScopedJavaLocalRef<jobjectArray> j_group_names = ToJavaArrayOfStrings(env, group_names); - java_result_ = Java_AutocompleteResult_build( + java_result_ = Java_AutocompleteResult_fromNative( env, reinterpret_cast<intptr_t>(this), BuildJavaMatches(env), j_group_ids, j_group_names, j_group_collapsed_states); @@ -74,7 +74,7 @@ return; JNIEnv* env = base::android::AttachCurrentThread(); - Java_AutocompleteResult_destroy(env, java_result_); + Java_AutocompleteResult_notifyNativeDestroyed(env, java_result_); java_result_.Reset(); }
diff --git a/components/omnibox/browser/history_provider.h b/components/omnibox/browser/history_provider.h index 17534ec4..6179f4d1c 100644 --- a/components/omnibox/browser/history_provider.h +++ b/components/omnibox/browser/history_provider.h
@@ -41,7 +41,7 @@ // backing data. void DeleteMatchFromMatches(const AutocompleteMatch& match); - AutocompleteProviderClient* client() { return client_; } + AutocompleteProviderClient* client() const { return client_; } private: AutocompleteProviderClient* client_;
diff --git a/components/omnibox/browser/history_quick_provider.cc b/components/omnibox/browser/history_quick_provider.cc index 6cf2e63..d968eb3 100644 --- a/components/omnibox/browser/history_quick_provider.cc +++ b/components/omnibox/browser/history_quick_provider.cc
@@ -205,11 +205,12 @@ const ScoredHistoryMatch& history_match, int score) { const history::URLRow& info = history_match.url_info; - AutocompleteMatch match( - this, score, !!info.visit_count(), - history_match.url_matches.empty() ? - AutocompleteMatchType::HISTORY_TITLE : - AutocompleteMatchType::HISTORY_URL); + bool deletable = + !!info.visit_count() && client()->AllowDeletingBrowserHistory(); + AutocompleteMatch match(this, score, deletable, + history_match.url_matches.empty() + ? AutocompleteMatchType::HISTORY_TITLE + : AutocompleteMatchType::HISTORY_URL); match.typed_count = info.typed_count(); match.destination_url = info.url(); DCHECK(match.destination_url.is_valid());
diff --git a/components/omnibox/browser/history_url_provider.cc b/components/omnibox/browser/history_url_provider.cc index 00ace4b7..1654568e 100644 --- a/components/omnibox/browser/history_url_provider.cc +++ b/components/omnibox/browser/history_url_provider.cc
@@ -452,7 +452,8 @@ bool trim_http, const AutocompleteMatch& what_you_typed_match, const TemplateURL* default_search_provider, - const SearchTermsData* search_terms_data) + const SearchTermsData* search_terms_data, + bool allow_deleting_browser_history) : origin_task_runner(base::SequencedTaskRunnerHandle::Get()), input(input), input_before_fixup(input_before_fixup), @@ -465,7 +466,8 @@ default_search_provider ? new TemplateURL(default_search_provider->data()) : nullptr), - search_terms_data(new SearchTermsDataSnapshot(search_terms_data)) {} + search_terms_data(new SearchTermsDataSnapshot(search_terms_data)), + allow_deleting_browser_history(allow_deleting_browser_history) {} HistoryURLProviderParams::~HistoryURLProviderParams() { } @@ -574,7 +576,8 @@ // 2. std::unique_ptr<HistoryURLProviderParams> params(new HistoryURLProviderParams( fixed_up_input, input, trim_http, what_you_typed_match, - default_search_provider, search_terms_data)); + default_search_provider, search_terms_data, + client()->AllowDeletingBrowserHistory())); // Pass 1: Get the in-memory URL database, and use it to find and promote // the inline autocomplete match, if any. @@ -917,8 +920,9 @@ break; default: DCHECK_EQ(VisitClassifier::VISITED, classifier.type()); + params->what_you_typed_match.deletable = + params->allow_deleting_browser_history; // We have data for this match, use it. - params->what_you_typed_match.deletable = true; auto title = classifier.url_row().title(); params->what_you_typed_match.description = title; params->what_you_typed_match.destination_url = classifier.url_row().url(); @@ -1179,8 +1183,10 @@ const history::HistoryMatch& history_match = params.matches[match_number]; const history::URLRow& info = history_match.url_info; - AutocompleteMatch match(this, relevance, - !!info.visit_count(), AutocompleteMatchType::HISTORY_URL); + bool deletable = + !!info.visit_count() && client()->AllowDeletingBrowserHistory(); + AutocompleteMatch match(this, relevance, deletable, + AutocompleteMatchType::HISTORY_URL); match.typed_count = info.typed_count(); match.destination_url = info.url(); DCHECK(match.destination_url.is_valid());
diff --git a/components/omnibox/browser/history_url_provider.h b/components/omnibox/browser/history_url_provider.h index 980dda5..08fe9ea 100644 --- a/components/omnibox/browser/history_url_provider.h +++ b/components/omnibox/browser/history_url_provider.h
@@ -106,7 +106,8 @@ bool trim_http, const AutocompleteMatch& what_you_typed_match, const TemplateURL* default_search_provider, - const SearchTermsData* search_terms_data); + const SearchTermsData* search_terms_data, + bool allow_deleting_browser_history); ~HistoryURLProviderParams(); HistoryURLProviderParams(const HistoryURLProviderParams&) = delete; HistoryURLProviderParams& operator=(const HistoryURLProviderParams&) = delete; @@ -181,6 +182,10 @@ // Similarly, we use a std::unique_ptr<SearchTermsData> so that we can store a // snapshot of the SearchTermsData accessible from the history thread. std::unique_ptr<SearchTermsData> search_terms_data; + + // True if the user is allowed to delete browser history. Stored here because + // we aren't allowed to read user preferences from the History sequence. + const bool allow_deleting_browser_history; }; // This class is an autocomplete provider and is also a pseudo-internal
diff --git a/components/omnibox/browser/history_url_provider_unittest.cc b/components/omnibox/browser/history_url_provider_unittest.cc index 7e0c5bd..c055cb6 100644 --- a/components/omnibox/browser/history_url_provider_unittest.cc +++ b/components/omnibox/browser/history_url_provider_unittest.cc
@@ -1351,7 +1351,7 @@ history_match.url_info.set_url(GURL(url_text)); history_match.match_in_scheme = match_in_scheme; auto params = std::make_unique<HistoryURLProviderParams>( - input, input, true, AutocompleteMatch(), nullptr, nullptr); + input, input, true, AutocompleteMatch(), nullptr, nullptr, true); params->matches.push_back(history_match); return params;
diff --git a/components/omnibox/browser/local_history_zero_suggest_provider.cc b/components/omnibox/browser/local_history_zero_suggest_provider.cc index a6769df..35c8b1da 100644 --- a/components/omnibox/browser/local_history_zero_suggest_provider.cc +++ b/components/omnibox/browser/local_history_zero_suggest_provider.cc
@@ -227,7 +227,7 @@ template_url_service->search_terms_data(), TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, /*append_extra_query_params_from_command_line*/ true); - match.deletable = true; + match.deletable = client_->AllowDeletingBrowserHistory(); matches_.push_back(match); if (matches_.size() >= max_matches_)
diff --git a/components/permissions/permission_auditing_database.cc b/components/permissions/permission_auditing_database.cc index 7f70722..4f2e432 100644 --- a/components/permissions/permission_auditing_database.cc +++ b/components/permissions/permission_auditing_database.cc
@@ -24,15 +24,6 @@ namespace { -int64_t TimeToInt64(base::Time time) { - return time.ToDeltaSinceWindowsEpoch().InMicroseconds(); -} - -base::Time Int64ToTime(const int64_t& time) { - return base::Time::FromDeltaSinceWindowsEpoch( - base::TimeDelta::FromMicroseconds(time)); -} - // For this database, schema migration is supported for at least 1 year. // This means we can deprecate old versions that landed more than a year ago. // @@ -124,8 +115,8 @@ "VALUES (?, ?, ?, ?, ?, ?, ?)")); statement.BindString(0, session.origin.Serialize()); statement.BindInt(1, static_cast<int32_t>(session.type)); - statement.BindInt64(2, TimeToInt64(session.usage_start)); - statement.BindInt64(3, TimeToInt64(session.usage_end)); + statement.BindTime(2, session.usage_start); + statement.BindTime(3, session.usage_end); statement.BindBool(4, session.had_user_activation); statement.BindBool(5, session.was_foreground); statement.BindBool(6, session.had_focus); @@ -155,15 +146,13 @@ "AND usage_end_time >= ?")); statement.BindString(0, origin.Serialize()); statement.BindInt(1, static_cast<int32_t>(type)); - statement.BindInt64(2, start_time.is_null() - ? std::numeric_limits<int64_t>::min() - : TimeToInt64(start_time)); + statement.BindTime(2, start_time.is_null() ? base::Time::Min() : start_time); while (statement.Step()) { sessions.push_back({.origin = origin, .type = type, - .usage_start = Int64ToTime(statement.ColumnInt64(0)), - .usage_end = Int64ToTime(statement.ColumnInt64(1)), + .usage_start = statement.ColumnTime(0), + .usage_end = statement.ColumnTime(1), .had_user_activation = statement.ColumnBool(2), .was_foreground = statement.ColumnBool(3), .had_focus = statement.ColumnBool(4)}); @@ -187,7 +176,7 @@ statement.BindInt(1, static_cast<int32_t>(type)); absl::optional<base::Time> last_usage; if (statement.Step()) { - last_usage = Int64ToTime(statement.ColumnInt64(0)); + last_usage = statement.ColumnTime(0); } return last_usage; } @@ -206,10 +195,10 @@ "SET usage_end_time = ? " "WHERE origin = ? AND content_setting_type = ? " "AND usage_start_time = ?")); - statement.BindInt64(0, TimeToInt64(new_end_time)); + statement.BindTime(0, new_end_time); statement.BindString(1, origin.Serialize()); statement.BindInt(2, static_cast<int32_t>(type)); - statement.BindInt64(3, TimeToInt64(start_time)); + statement.BindTime(3, start_time); sql::Transaction transaction(&db_); if (!transaction.Begin()) { @@ -229,14 +218,11 @@ "DELETE FROM uses " "WHERE usage_start_time BETWEEN ? AND ? " "OR usage_end_time BETWEEN ? AND ?")); - auto start = start_time.is_null() ? std::numeric_limits<int64_t>::min() - : TimeToInt64(start_time); - auto end = end_time.is_null() ? std::numeric_limits<int64_t>::max() - : TimeToInt64(end_time); - statement.BindInt64(0, start); - statement.BindInt64(1, end); - statement.BindInt64(2, start); - statement.BindInt64(3, end); + statement.BindTime(0, start_time.is_null() ? base::Time::Min() : start_time); + statement.BindTime(1, end_time.is_null() ? base::Time::Max() : end_time); + statement.BindTime(2, start_time.is_null() ? base::Time::Min() : start_time); + statement.BindTime(3, end_time.is_null() ? base::Time::Max() : end_time); + sql::Transaction transaction(&db_); if (!transaction.Begin()) { return false;
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json index 8d68cc4..4a8b08a 100644 --- a/components/policy/resources/policy_templates.json +++ b/components/policy/resources/policy_templates.json
@@ -6392,7 +6392,7 @@ 'future_on': ['chrome_os', 'chrome.*'], 'features': { 'dynamic_refresh': True, - 'per_profile': True, + 'per_profile': False, }, 'example_value': ['https://www.example.com'], 'id': 837, @@ -6435,7 +6435,7 @@ 'future_on': ['chrome_os', 'chrome.*'], 'features': { 'dynamic_refresh': True, - 'per_profile': True, + 'per_profile': False, }, 'example_value': [ {
diff --git a/components/policy/resources/policy_templates_th.xtb b/components/policy/resources/policy_templates_th.xtb index c9199838..6712ca8 100644 --- a/components/policy/resources/policy_templates_th.xtb +++ b/components/policy/resources/policy_templates_th.xtb
@@ -79,7 +79,7 @@ <translation id="1076751984131277498">รายการที่อนุญาตของอุปกรณ์ USB ที่ถอดได้</translation> <translation id="1079801999187584280">ไม่อนุญาตการใช้เครื่องมือสำหรับนักพัฒนาซอฟต์แวร์</translation> <translation id="1082802595100075771">ให้ผู้ใช้เลือกที่จะใช้บริการของ Google แบบไม่ระบุตัวตนเพื่อให้คำอธิบายอัตโนมัติสำหรับรูปภาพที่ไม่มีป้ายกำกับ</translation> -<translation id="1087437665304381368">นโยบายนี้ควบคุมโหมดนักพัฒนาซอฟต์แวร์ของ <ph name="PRODUCT_OS_NAME" /> เท่านั้น หากคุณต้องการป้องกันการเข้าถึงตัวเลือกสำหรับนักพัฒนาซอฟต์แวร์ Android ก็จะต้องตั้งค่านโยบาย <ph name="DEVELOPER_TOOLS_DISABLED_POLICY_NAME" /></translation> +<translation id="1087437665304381368">นโยบายนี้ควบคุมโหมดนักพัฒนาซอฟต์แวร์ของ <ph name="PRODUCT_OS_NAME" /> เท่านั้น หากคุณต้องการป้องกันการเข้าถึงตัวเลือกสำหรับนักพัฒนาแอป Android ก็จะต้องตั้งค่านโยบาย <ph name="DEVELOPER_TOOLS_DISABLED_POLICY_NAME" /></translation> <translation id="1087707496788636333">เรากำลังย้ายรายการนโยบายของ Chrome Enterprise โปรดอัปเดตบุ๊กมาร์กเป็น <ph name="POLICY_DOCUMENTATION_URL" /></translation> <translation id="1095209545735032039">บล็อก Serial API ในเว็บไซต์เหล่านี้</translation> <translation id="1096105751829466145">ผู้ให้บริการการค้นหาเริ่มต้น</translation>
diff --git a/components/sessions/core/tab_restore_service_helper.cc b/components/sessions/core/tab_restore_service_helper.cc index 10f1d8d..40ace9274 100644 --- a/components/sessions/core/tab_restore_service_helper.cc +++ b/components/sessions/core/tab_restore_service_helper.cc
@@ -433,11 +433,36 @@ context = client_->CreateLiveTabContext( window.app_name, window.bounds, window.show_state, window.workspace, window.user_title); + + base::flat_map<tab_groups::TabGroupId, tab_groups::TabGroupId> + new_group_ids; + for (size_t tab_i = 0; tab_i < window.tabs.size(); ++tab_i) { const Tab& tab = *window.tabs[tab_i]; + + // Relabel group IDs to prevent duplicating groups, e.g. if the same + // window is restored twice or a tab of the same ID is restored + // elsewhere. See crbug.com/1202102. + absl::optional<tab_groups::TabGroupId> new_group; + if (tab.group) { + auto it = new_group_ids.find(*tab.group); + if (it == new_group_ids.end()) { + auto new_id = tab_groups::TabGroupId::GenerateNew(); + // Ensure the new ID does not collide with an existing group, + // failing silently if it does. This is extremely unlikely, + // given group IDs are 128 bit randomly generated numbers. + if (client_->FindLiveTabContextWithGroup(new_id)) { + return std::vector<LiveTab*>(); + } + it = new_group_ids.emplace(*tab.group, new_id).first; + } + + new_group = it->second; + } + LiveTab* restored_tab = context->AddRestoredTab( tab.navigations, context->GetTabCount(), - tab.current_navigation_index, tab.extension_app_id, tab.group, + tab.current_navigation_index, tab.extension_app_id, new_group, tab.group_visual_data.value_or(tab_groups::TabGroupVisualData()), static_cast<int>(tab_i) == window.selected_tab_index, tab.pinned, tab.platform_data.get(), tab.user_agent_override, nullptr); @@ -449,7 +474,8 @@ } for (const auto& tab_group : window.tab_groups) { - context->SetVisualDataForGroup(tab_group.first, tab_group.second); + context->SetVisualDataForGroup(new_group_ids.at(tab_group.first), + tab_group.second); } // All the window's tabs had the same former browser_id.
diff --git a/components/signin/public/identity_manager/identity_manager.cc b/components/signin/public/identity_manager/identity_manager.cc index b4ed826..be965f0 100644 --- a/components/signin/public/identity_manager/identity_manager.cc +++ b/components/signin/public/identity_manager/identity_manager.cc
@@ -305,17 +305,34 @@ AccountInfo IdentityManager::FindExtendedAccountInfoByAccountId( const CoreAccountId& account_id) const { + if (!HasAccountWithRefreshToken(account_id)) + return AccountInfo(); + + // AccountTrackerService returns an empty AccountInfo if the account is not + // found. return account_tracker_service_->GetAccountInfo(account_id); } AccountInfo IdentityManager::FindExtendedAccountInfoByEmailAddress( const std::string& email_address) const { - return account_tracker_service_->FindAccountInfoByEmail(email_address); + AccountInfo account_info = + account_tracker_service_->FindAccountInfoByEmail(email_address); + // AccountTrackerService always returns an AccountInfo, even on failure. In + // case of failure, the AccountInfo will be unpopulated, thus we should not + // be able to find a valid refresh token. + return HasAccountWithRefreshToken(account_info.account_id) ? account_info + : AccountInfo(); } AccountInfo IdentityManager::FindExtendedAccountInfoByGaiaId( const std::string& gaia_id) const { - return account_tracker_service_->FindAccountInfoByGaiaId(gaia_id); + AccountInfo account_info = + account_tracker_service_->FindAccountInfoByGaiaId(gaia_id); + // AccountTrackerService always returns an AccountInfo, even on failure. In + // case of failure, the AccountInfo will be unpopulated, thus we should not + // be able to find a valid refresh token. + return HasAccountWithRefreshToken(account_info.account_id) ? account_info + : AccountInfo(); } absl::optional<AccountInfo> @@ -538,6 +555,12 @@ } #endif +AccountInfo IdentityManager::FindExtendedPrimaryAccountInfo( + ConsentLevel consent_level) { + CoreAccountId account_id = GetPrimaryAccountId(consent_level); + return account_tracker_service_->GetAccountInfo(account_id); +} + PrimaryAccountManager* IdentityManager::GetPrimaryAccountManager() const { return primary_account_manager_.get(); }
diff --git a/components/signin/public/identity_manager/identity_manager.h b/components/signin/public/identity_manager/identity_manager.h index 09d9962..8e3a14a3 100644 --- a/components/signin/public/identity_manager/identity_manager.h +++ b/components/signin/public/identity_manager/identity_manager.h
@@ -53,6 +53,7 @@ class AccountFetcherService; class AccountTrackerService; class GaiaCookieManagerService; +class NewTabPageUI; namespace signin { @@ -253,9 +254,8 @@ // Returns extended information for account identified by |account_info|, or // an empty AccountInfo if the account is not found. - // Note: these functions may return a non-empty Accountinfo even if no refresh - // token is available for the account (in particular before tokens are - // loaded). + // Note: these functions return an empty AccountInfo if no refresh token is + // available for the account (in particular before tokens are loaded). AccountInfo FindExtendedAccountInfo( const CoreAccountInfo& account_info) const; // The same as `FindExtendedAccountInfo()` but finds an account by account ID. @@ -627,6 +627,19 @@ FRIEND_TEST_ALL_PREFIXES(IdentityManagerTest, OnNetworkInitialized); FRIEND_TEST_ALL_PREFIXES(IdentityManagerTest, ForceRefreshOfExtendedAccountInfo); + FRIEND_TEST_ALL_PREFIXES(IdentityManagerTest, FindExtendedPrimaryAccountInfo); + + // Only caller to FindExtendedPrimaryAccountInfo(). + // TODO(https://crbug.com/1213351): Delete once the private call has been + // removed. + friend class ::NewTabPageUI; + + // Returns the extended account info for the primary account. This function + // does not require tokens to be loaded. + // Do not add more external callers, as account info is generally not + // available until tokens are loaded. + // TODO(https://crbug.com/1213351): Remove existing external callers. + AccountInfo FindExtendedPrimaryAccountInfo(ConsentLevel consent_level); // Private getters used for testing only (i.e. see identity_test_utils.h). PrimaryAccountManager* GetPrimaryAccountManager() const;
diff --git a/components/signin/public/identity_manager/identity_manager_unittest.cc b/components/signin/public/identity_manager/identity_manager_unittest.cc index 0204898..0d4bbb1 100644 --- a/components/signin/public/identity_manager/identity_manager_unittest.cc +++ b/components/signin/public/identity_manager/identity_manager_unittest.cc
@@ -2177,11 +2177,16 @@ account_tracker()->SeedAccountInfo(account_info.gaia, account_info.email); ASSERT_EQ(account_info.account_id, account_id); - // FindExtendedAccountInfo() returns extended account information if - // the account is known. + // The refresh token is not available. + EXPECT_TRUE( + identity_manager()->FindExtendedAccountInfo(account_info).IsEmpty()); + + // FindExtendedAccountInfo() returns extended account information if the + // account is known and the token is available. + SetRefreshTokenForAccount(identity_manager(), account_info.account_id, + "token"); const AccountInfo extended_account_info = identity_manager()->FindExtendedAccountInfo(account_info); - EXPECT_TRUE(!extended_account_info.IsEmpty()); EXPECT_EQ(account_info.gaia, extended_account_info.gaia); EXPECT_EQ(account_info.email, extended_account_info.email); @@ -2191,63 +2196,130 @@ // Checks that FindExtendedAccountInfoByAccountId() returns information about // the account if the account is found, or an empty account info. TEST_F(IdentityManagerTest, FindExtendedAccountInfoByAccountId) { - // Add an account (note: cannot use kTestEmail as it is already inserted - // by the fixture common code, so use a different address). - const AccountInfo foo_account_info = - MakeAccountAvailable(identity_manager(), "foo@bar.com"); + CoreAccountInfo account_info; + account_info.email = kTestEmail2; + account_info.gaia = kTestGaiaId2; + account_info.account_id = identity_manager()->PickAccountIdForAccount( + account_info.gaia, account_info.email); + // Account is unknown. AccountInfo maybe_account_info = identity_manager()->FindExtendedAccountInfoByAccountId( - CoreAccountId("dummy_value")); + account_info.account_id); EXPECT_TRUE(maybe_account_info.IsEmpty()); + // Refresh token is not available. + const CoreAccountId account_id = + account_tracker()->SeedAccountInfo(account_info.gaia, account_info.email); maybe_account_info = identity_manager()->FindExtendedAccountInfoByAccountId( - foo_account_info.account_id); + account_info.account_id); + EXPECT_TRUE(maybe_account_info.IsEmpty()); + + // Account with refresh token. + SetRefreshTokenForAccount(identity_manager(), account_info.account_id, + "token"); + maybe_account_info = identity_manager()->FindExtendedAccountInfoByAccountId( + account_info.account_id); EXPECT_FALSE(maybe_account_info.IsEmpty()); - EXPECT_EQ(foo_account_info.account_id, maybe_account_info.account_id); - EXPECT_EQ(foo_account_info.email, maybe_account_info.email); - EXPECT_EQ(foo_account_info.gaia, maybe_account_info.gaia); + EXPECT_EQ(account_info.account_id, maybe_account_info.account_id); + EXPECT_EQ(account_info.email, maybe_account_info.email); + EXPECT_EQ(account_info.gaia, maybe_account_info.gaia); } // Checks that FindExtendedAccountInfoByEmailAddress() returns information about // the account if the account is found, or an empty account info. TEST_F(IdentityManagerTest, FindExtendedAccountInfoByEmailAddress) { - // Add an account (note: cannot use kTestEmail as it is already inserted - // by the fixture common code, so use a different address). - const AccountInfo foo_account_info = - MakeAccountAvailable(identity_manager(), "foo@bar.com"); + CoreAccountInfo account_info; + account_info.email = kTestEmail2; + account_info.gaia = kTestGaiaId2; + account_info.account_id = identity_manager()->PickAccountIdForAccount( + account_info.gaia, account_info.email); + // Account is unknown. AccountInfo maybe_account_info = - identity_manager()->FindExtendedAccountInfoByEmailAddress("dummy_value"); + identity_manager()->FindExtendedAccountInfoByEmailAddress( + account_info.email); EXPECT_TRUE(maybe_account_info.IsEmpty()); + // Refresh token is not available. + const CoreAccountId account_id = + account_tracker()->SeedAccountInfo(account_info.gaia, account_info.email); maybe_account_info = identity_manager()->FindExtendedAccountInfoByEmailAddress( - foo_account_info.email); + account_info.email); + EXPECT_TRUE(maybe_account_info.IsEmpty()); + + // Account with refresh token. + SetRefreshTokenForAccount(identity_manager(), account_info.account_id, + "token"); + maybe_account_info = + identity_manager()->FindExtendedAccountInfoByEmailAddress( + account_info.email); EXPECT_FALSE(maybe_account_info.IsEmpty()); - EXPECT_EQ(foo_account_info.account_id, maybe_account_info.account_id); - EXPECT_EQ(foo_account_info.email, maybe_account_info.email); - EXPECT_EQ(foo_account_info.gaia, maybe_account_info.gaia); + EXPECT_EQ(account_info.account_id, maybe_account_info.account_id); + EXPECT_EQ(account_info.email, maybe_account_info.email); + EXPECT_EQ(account_info.gaia, maybe_account_info.gaia); } // Checks that FindExtendedAccountInfoByGaiaId() returns information about the // account if the account is found, or an empty account info. TEST_F(IdentityManagerTest, FindExtendedAccountInfoByGaiaId) { - // Add an account (note: cannot use kTestEmail as it is already inserted - // by the fixture common code, so use a different address). - const AccountInfo foo_account_info = - MakeAccountAvailable(identity_manager(), "foo@bar.com"); + CoreAccountInfo account_info; + account_info.email = kTestEmail2; + account_info.gaia = kTestGaiaId2; + account_info.account_id = identity_manager()->PickAccountIdForAccount( + account_info.gaia, account_info.email); + // Account is unknown. AccountInfo maybe_account_info = - identity_manager()->FindExtendedAccountInfoByGaiaId("dummy_value"); + identity_manager()->FindExtendedAccountInfoByGaiaId(account_info.gaia); EXPECT_TRUE(maybe_account_info.IsEmpty()); - maybe_account_info = identity_manager()->FindExtendedAccountInfoByGaiaId( - foo_account_info.gaia); + // Refresh token is not available. + const CoreAccountId account_id = + account_tracker()->SeedAccountInfo(account_info.gaia, account_info.email); + maybe_account_info = + identity_manager()->FindExtendedAccountInfoByGaiaId(account_info.gaia); + EXPECT_TRUE(maybe_account_info.IsEmpty()); + + // Account with refresh token. + SetRefreshTokenForAccount(identity_manager(), account_info.account_id, + "token"); + maybe_account_info = + identity_manager()->FindExtendedAccountInfoByGaiaId(account_info.gaia); EXPECT_FALSE(maybe_account_info.IsEmpty()); - EXPECT_EQ(foo_account_info.account_id, maybe_account_info.account_id); - EXPECT_EQ(foo_account_info.email, maybe_account_info.email); - EXPECT_EQ(foo_account_info.gaia, maybe_account_info.gaia); + EXPECT_EQ(account_info.account_id, maybe_account_info.account_id); + EXPECT_EQ(account_info.email, maybe_account_info.email); + EXPECT_EQ(account_info.gaia, maybe_account_info.gaia); +} + +TEST_F(IdentityManagerTest, FindExtendedPrimaryAccountInfo) { + // AccountInfo found for primary account, even without token. + RemoveRefreshTokenForPrimaryAccount(identity_manager()); + ASSERT_TRUE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSignin)); + ASSERT_FALSE(identity_manager()->HasPrimaryAccountWithRefreshToken( + ConsentLevel::kSignin)); + AccountInfo extended_info = + identity_manager()->FindExtendedPrimaryAccountInfo(ConsentLevel::kSignin); + CoreAccountInfo core_info = + identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kSignin); + EXPECT_FALSE(extended_info.IsEmpty()); + EXPECT_EQ(core_info.account_id, extended_info.account_id); + EXPECT_EQ(core_info.email, extended_info.email); + EXPECT_EQ(core_info.gaia, extended_info.gaia); + +#if !BUILDFLAG(IS_CHROMEOS_ASH) + // It's not possible to sign out on Ash. + ClearPrimaryAccount(identity_manager()); + SetRefreshTokenForAccount(identity_manager(), core_info.account_id, "token"); + // No info found if there is no primary account. + ASSERT_FALSE(identity_manager()->HasPrimaryAccount(ConsentLevel::kSignin)); + ASSERT_TRUE( + identity_manager()->HasAccountWithRefreshToken(core_info.account_id)); + EXPECT_TRUE(identity_manager() + ->FindExtendedPrimaryAccountInfo(ConsentLevel::kSignin) + .IsEmpty()); +#endif } // Checks that FindExtendedAccountInfoForAccountWithRefreshTokenByAccountId()
diff --git a/components/strings/components_strings_am.xtb b/components/strings/components_strings_am.xtb index f2fe202..7610104 100644 --- a/components/strings/components_strings_am.xtb +++ b/components/strings/components_strings_am.xtb
@@ -1715,7 +1715,7 @@ <translation id="7378594059915113390">የሚዲያ መቆጣጠሪያዎች</translation> <translation id="7378627244592794276">አይ</translation> <translation id="7378810950367401542">/</translation> -<translation id="7386364858855961704">የለም</translation> +<translation id="7386364858855961704">አይመለከተውም</translation> <translation id="7390545607259442187">ካርድ ያረጋግጡ</translation> <translation id="7392089738299859607">አድራሻን ያዘምኑ</translation> <translation id="7399802613464275309">የደህንነት ፍተሻ</translation>
diff --git a/components/strings/components_strings_be.xtb b/components/strings/components_strings_be.xtb index d66e188..470fd36 100644 --- a/components/strings/components_strings_be.xtb +++ b/components/strings/components_strings_be.xtb
@@ -918,7 +918,7 @@ <translation id="4275830172053184480">Перазапусціце прыладу</translation> <translation id="4277028893293644418">Скінуць пароль</translation> <translation id="428639260510061158">{NUM_CARDS,plural, =1{Гэта картка захавана ў вашым Уліковым запісе Google}one{Гэтыя карткі захаваны ў вашым Уліковым запісе Google}few{Гэтыя карткі захаваны ў вашым Уліковым запісе Google}many{Гэтыя карткі захаваны ў вашым Уліковым запісе Google}other{Гэтыя карткі захаваны ў вашым Уліковым запісе Google}}</translation> -<translation id="4287885627794386150">Навучанне FLoC можа выкарыстоўвацца на працягу пробнага перыяду, але яшчэ не было актывавана</translation> +<translation id="4287885627794386150">Пробная версія функцыі можа выкарыстоўвацца, але яшчэ не актывавана</translation> <translation id="4297502707443874121">Мініяцюра старонкі <ph name="THUMBNAIL_PAGE" /></translation> <translation id="42981349822642051">Разгарнуць</translation> <translation id="4300675098767811073">Некалькі дзірак справа</translation> @@ -1724,7 +1724,7 @@ <translation id="7378594059915113390">Элементы кіравання мультымедыйным змесцівам</translation> <translation id="7378627244592794276">А вось i не!</translation> <translation id="7378810950367401542">/</translation> -<translation id="7386364858855961704">Непрымяніма</translation> +<translation id="7386364858855961704">Недастасоўна</translation> <translation id="7390545607259442187">Пацвердзіце картку</translation> <translation id="7392089738299859607">Абнавіць адрас</translation> <translation id="7399802613464275309">Праверка бяспекі</translation>
diff --git a/components/strings/components_strings_gu.xtb b/components/strings/components_strings_gu.xtb index 1e68b028..d6cb1c70 100644 --- a/components/strings/components_strings_gu.xtb +++ b/components/strings/components_strings_gu.xtb
@@ -734,6 +734,7 @@ <translation id="3631244953324577188">બાયોમેટ્રિક્સ</translation> <translation id="3633738897356909127">Chrome અપડેટ કરો બટન, તમારા Chrome સેટિંગમાંથી Chrome અપડેટ કરવા માટે Enter દબાવો</translation> <translation id="3634530185120165534">ટ્રે 5</translation> +<translation id="3637662659967048211">Google એકાઉન્ટમાં સાચવો</translation> <translation id="3640766068866876100">અનુક્રમણિકા-4x6-Ext</translation> <translation id="3642638418806704195">ઍપ્લિકેશન:</translation> <translation id="3650584904733503804">માન્યતા સફળ</translation> @@ -1411,6 +1412,7 @@ <translation id="6106989379647458772"><ph name="PAGE" /> પરનું વેબપેજ થોડી વાર માટે બંધ હોઈ શકે છે અથવા તે કાયમ માટે નવા વેબ ઍડ્રેસ પર ખસેડવામાં આવ્યું હોઈ શકે છે.</translation> <translation id="6107012941649240045">આને રજૂ કરેલું</translation> <translation id="610911394827799129">તમારા Google એકાઉન્ટમાં <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /> પર બ્રાઉઝિંગ ઇતિહાસના બીજા સ્વરૂપો હોય શકે છે</translation> +<translation id="6113594885686374546">યાત્રા બટન ફરી શરૂ કરો, તેમજ તમારી યાત્રા ફરી શરૂ કરવા અને તમારા Chrome ઇતિહાસમાં સંબંધિત પ્રવૃત્તિ જોવા માટે Enter કી દબાવો</translation> <translation id="6116338172782435947">ક્લિપબોર્ડ પર કૉપિ કરેલ ટેક્સ્ટ અને છબીઓને જુઓ</translation> <translation id="6120179357481664955">તમારું UPI ID યાદ રાખીએ?</translation> <translation id="6123290840358279103">વર્ચ્યુઅલ કાર્ડ જુઓ</translation> @@ -1486,6 +1488,7 @@ <translation id="6423385022588644828">હવેથી Touch IDનો ઉપયોગ કરીને તમારા કાર્ડ વધુ ઝડપથી કન્ફર્મ કરો</translation> <translation id="6425092077175753609">સામગ્રી</translation> <translation id="6427730057873428458">ગેટ ફોલ્ડ</translation> +<translation id="6428146287756735566">તમારા Chrome ઇતિહાસમાં સંબંધિત પ્રવૃત્તિ જોવા માટે, યાત્રા ફરી શરૂ કરો</translation> <translation id="6428450836711225518">તમારો ફોન નંબર ચકાસો</translation> <translation id="6433490469411711332">સંપર્ક માહિતીમાં ફેરફાર કરો</translation> <translation id="6433595998831338502"><ph name="HOST_NAME" /> એ કનેક્ટ કરવાનો ઇનકાર કર્યો.</translation> @@ -1537,6 +1540,7 @@ <translation id="6643016212128521049">સાફ કરો</translation> <translation id="6645291930348198241">કુકી અને સાઇટ ડેટાનો ઍક્સેસ કરો.</translation> <translation id="6646269444027925224">{COUNT,plural, =0{કોઈ નહિ}=1{From 1 site (you won't be signed out of your Google Account)}one{From # sites (you won't be signed out of your Google Account)}other{From # sites (you won't be signed out of your Google Account)}}</translation> +<translation id="6647197322759179819">યાત્રા ફરી શરૂ કરો</translation> <translation id="6648459603387803038">તમારા વ્યવસ્થાપક તમારા બ્રાઉઝર સેટઅપને રિમોટલી બદલી શકે છે. આ ડિવાઇસ પરની પ્રવૃત્તિ Chromeની બહારથી પણ મેનેજ કરી શકાય છે.</translation> <translation id="6648524591329069940">Serif ફૉન્ટ</translation> <translation id="6651270836885078973">આમના દ્વારા મેનેજ કરવામાં આવે છે:</translation> @@ -2188,6 +2192,7 @@ <translation id="9114524666733003316">કાર્ડ કન્ફર્મ કરી રહ્યાં છીએ...</translation> <translation id="9114581008513152754">આ બ્રાઉઝર કંપની દ્વારા અથવા અન્ય સંસ્થા દ્વારા મેનેજ કરવામાં આવતું નથી. આ ડિવાઇસ પરની પ્રવૃત્તિ Chromeની બહાર મેનેજ કરી શકાય છે. <ph name="BEGIN_LINK" />વધુ જાણો<ph name="END_LINK" /></translation> <translation id="9117930699067497412">નવીન</translation> +<translation id="9118692854637641831"><ph name="HISTORY_CLUSTERS_SEARCH_FOCUSED_FRIENDLY_MATCH_TEXT" />, Tab કી દબાવો તેમજ તમારી યાત્રા ફરી શરૂ કરવા અને તમારા Chrome ઇતિહાસમાં સંબંધિત પ્રવૃત્તિ જોવા માટે Enter કી દબાવો</translation> <translation id="9119042192571987207">અપલોડ કર્યો</translation> <translation id="9128016270925453879">પૉલિસી લોડ કરવામાં આવી છે</translation> <translation id="9128870381267983090">નેટવર્કથી કનેક્ટ કરો</translation>
diff --git a/components/strings/components_strings_mr.xtb b/components/strings/components_strings_mr.xtb index e02504f1..6b931b13 100644 --- a/components/strings/components_strings_mr.xtb +++ b/components/strings/components_strings_mr.xtb
@@ -260,7 +260,7 @@ <translation id="1800473098294731951">B9</translation> <translation id="1803264062614276815">कार्डधारकाचे नाव</translation> <translation id="1807246157184219062">फिकट</translation> -<translation id="1807528111851433570">पत्रक सुरू करा</translation> +<translation id="1807528111851433570">शीट सुरू करा</translation> <translation id="1812527064848182527">लॅंडस्केप</translation> <translation id="1814698615734239189">हे ॲप मोबाइल डिव्हाइससाठी डिझाइन केलेले आहे. ते कंपॅटिबिलिटी मोडमध्ये रन होत आहे. आकार बदलण्याला अनुमती दिल्यामुळे ॲप पुन्हा सुरू होण्याच्या समावेशासह समस्या येऊ शकतात.</translation> <translation id="1821930232296380041">अवैध विनंती किंवा विनंती मापदंड</translation> @@ -636,7 +636,7 @@ <translation id="3329013043687509092">संपृक्तता</translation> <translation id="3338095232262050444">सुरक्षित</translation> <translation id="3355823806454867987">प्रॉक्सी सेटिंग्ज बदला...</translation> -<translation id="3360103848165129075">पेमेंट हँडलर पत्रक</translation> +<translation id="3360103848165129075">पेमेंट हँडलर शीट</translation> <translation id="3361596688432910856">Chrome पुढील माहिती <ph name="BEGIN_EMPHASIS" />सेव्ह करणार नाही<ph name="END_EMPHASIS" />: <ph name="BEGIN_LIST" /> <ph name="LIST_ITEM" />तुमचा ब्राउझिंग इतिहास @@ -813,7 +813,7 @@ <translation id="3949601375789751990">तुमचा ब्राउझिंग इतिहास येथे दिसतो</translation> <translation id="3949870428812919180">सेव्ह केलेल्या पेमेंट पद्धती नाहीत</translation> <translation id="3950820424414687140">साइन इन करा</translation> -<translation id="3961148744525529027">पेमेंट हँडलर पत्रक अर्धे उघडलेले आहे</translation> +<translation id="3961148744525529027">पेमेंट हँडलर शीट अर्धे उघडलेले आहे</translation> <translation id="3962859241508114581">मागील ट्रॅक</translation> <translation id="3963721102035795474">वाचक मोड</translation> <translation id="3963837677003247395">मॅन्युअली सुरू ठेवायचे आहे का?</translation> @@ -1683,7 +1683,7 @@ <translation id="7220786058474068424">प्रक्रिया करत आहे</translation> <translation id="7221855153210829124">सूचना दर्शवा</translation> <translation id="7229659723041939809">तुम्ही आताच एका फसव्या साइटवर तुमचा पासवर्ड एंटर केला. तुम्ही हा पासवर्ड आता जेथे वापरता अशा <ph name="WEBSITE_1" />, <ph name="WEBSITE_2" />, <ph name="WEBSITE_3" /> आणि इतर साइटसाठी तुमचे सेव्ह केलेले पासवर्ड तपासण्याची Chrome शिफारस करते.</translation> -<translation id="7233592378249864828">खात्री केलेले पत्रक प्रिंट करा</translation> +<translation id="7233592378249864828">खात्री केलेले शीट प्रिंट करा</translation> <translation id="7238585580608191973">SHA-256 बोटाचा ठसा</translation> <translation id="7240120331469437312">सर्टिफिकेट विषय वैकल्पिक नाव</translation> <translation id="7243010569062352439"><ph name="PASSWORDS" />; <ph name="SIGNIN_DATA" /></translation> @@ -1798,7 +1798,7 @@ <translation id="7613889955535752492">कालबाह्य: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation> <translation id="7614494068621678628"><ph name="MANAGE_PASSWORDS_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome सेटिंग्जमध्ये तुमचे पासवर्ड पाहाण्यासाठी आणि व्यवस्थापित करण्यासाठी टॅब आणि त्यानंतर एंटर दाबा</translation> <translation id="7616645509853975347">तुमच्या अॅडमिनिस्ट्रेटरने तुमच्या ब्राउझरवर Chrome एंटरप्राइझ कनेक्टर्स सुरू केली आहेत. या कनेक्टरना तुमच्या काही डेटाचा अॅक्सेस आहे.</translation> -<translation id="7619838219691048931">शेवटचे पत्रक</translation> +<translation id="7619838219691048931">शेवटचे शीट</translation> <translation id="762844065391966283">एका वेळी एक</translation> <translation id="7633909222644580952">परफॉर्मंस डेटा आणि क्रॅश अहवाल</translation> <translation id="7637571805876720304">Chromium वरून क्रेडिट कार्ड काढून टाकायचे?</translation> @@ -1807,7 +1807,7 @@ <translation id="7639968568612851608">गडद राखाडी</translation> <translation id="7647206758853451655">प्रिंटची गुणवत्ता</translation> <translation id="7648992873808071793">या डिव्हाइसवर फाइल संचयित करा</translation> -<translation id="7653957176542370971">पेमेंट हँडलर पत्रक बंद केलेले आहे</translation> +<translation id="7653957176542370971">पेमेंट हँडलर शीट बंद केलेले आहे</translation> <translation id="7654909834015434372">तुम्ही भाष्ये संपादित करता तेव्हा हा दस्तऐवज त्याच्या मूळ रोटेशनवर परत येईल</translation> <translation id="765676359832457558">प्रगत सेटिंग्ज लपवा...</translation> <translation id="7658239707568436148">रद्द करा</translation> @@ -1977,7 +1977,7 @@ <translation id="8267698848189296333"><ph name="USERNAME" /> म्हणून साइन इन करीत आहे</translation> <translation id="8269242089528251720">वेगळे दस्तऐवज/संकलित केलेल्या प्रती</translation> <translation id="8275952078857499577">या साइटचे भाषांतर करणे ऑफर करू नका</translation> -<translation id="8277900682056760511">पेमेंट हँडलर पत्रक उघडलेले आहे</translation> +<translation id="8277900682056760511">पेमेंट हँडलर शीट उघडलेले आहे</translation> <translation id="8281084378435768645">Large-Photo</translation> <translation id="8282947398454257691">तुमचा अनन्य डिव्हाइस अभिज्ञापक जाणून घ्या</translation> <translation id="8284769179630993263">Chrome सेटिंग्जमध्ये तुमचे सुरक्षित ब्राउझिंग आणि आणखी बरेच काही व्यवस्थापित करा</translation> @@ -2211,7 +2211,7 @@ <translation id="9169931577761441333"><ph name="APP_NAME" /> ला होम स्क्रीनवर जोडा</translation> <translation id="9170848237812810038">&पूर्ववत करा</translation> <translation id="9171296965991013597">ॲप सोडायचे?</translation> -<translation id="9173282814238175921">एक दस्तऐवज/नवीन पत्रक</translation> +<translation id="9173282814238175921">एक दस्तऐवज/नवीन शीट</translation> <translation id="9173995187295789444">ब्लूटूथ डिव्हाइससाठी स्कॅन करत आहे...</translation> <translation id="917450738466192189">सर्व्हरचे सर्टिफिकेट चुकीचे आहे.</translation> <translation id="9174917557437862841">टॅब स्विच बटण, या टॅबवर जाण्यासाठी एंटर दाबा</translation>
diff --git a/components/strings/components_strings_ne.xtb b/components/strings/components_strings_ne.xtb index 9d6bc1f..73fbe1cd 100644 --- a/components/strings/components_strings_ne.xtb +++ b/components/strings/components_strings_ne.xtb
@@ -729,6 +729,7 @@ <translation id="3631244953324577188">बायोमेट्रिक्स</translation> <translation id="3633738897356909127">'Chrome अपडेट गर्नुहोस्' नामक बटन, आफ्नो Chrome का सेटिङमा गई Chrome अपडेट गर्न Enter थिच्नुहोस्</translation> <translation id="3634530185120165534">ट्रे ५</translation> +<translation id="3637662659967048211">Google खातामा सेभ गर्नुहोस्</translation> <translation id="3640766068866876100">Index-4x6-Ext</translation> <translation id="3642638418806704195">एप:</translation> <translation id="3650584904733503804">प्रमाणीकरण सफल भयो</translation> @@ -1403,6 +1404,7 @@ <translation id="6106989379647458772"><ph name="PAGE" /> को वेबपृष्ठ अस्थायी रूपमा बन्द भएको हुन सक्छ वा त्यो स्थायी रूपमा एउटा नयाँ वेब ठेगानामा सरेको हुन सक्छ।</translation> <translation id="6107012941649240045">लाई जारी गरिएको</translation> <translation id="610911394827799129">तपाईंको Google खाताको <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /> मा ब्राउजिङ इतिहासका अन्य ढाँचाहरू रहेका हुनसक्छन्।</translation> +<translation id="6113594885686374546">'खोज्ने क्रम सुचारु गर्नुहोस्' बटन, Chrome को ब्राउजिङ इतिहासमा सान्दर्भिक गतिविधि हेर्न खोज्ने क्रम सुचारु गर्न Enter थिच्नुहोस्</translation> <translation id="6116338172782435947">क्लिपबोर्डमा प्रतिलिपि गरिएका पाठ र छविहरू हेर्नुहोस्</translation> <translation id="6120179357481664955">आफ्नो UPI ID सम्झने हो?</translation> <translation id="6124432979022149706">Chrome Enterprise का कनेक्टरहरू</translation> @@ -1477,6 +1479,7 @@ <translation id="6423385022588644828">अब उप्रान्त Touch ID प्रयोग गरेर आफ्ना कार्डहरू अझ छिटो पुष्टि गर्नुहोस्</translation> <translation id="6425092077175753609">वस्तु</translation> <translation id="6427730057873428458">गेट फोल्ड</translation> +<translation id="6428146287756735566">Chrome को ब्राउजिङ इतिहासमा सान्दर्भिक गतिविधि हेर्न खोज्ने क्रम सुचारु गर्नुहोस्</translation> <translation id="6428450836711225518">आफ्नो फोन नम्बरको पुष्टि गर्नुहोस्</translation> <translation id="6433490469411711332">सम्पर्क सम्बन्धी जानकारीलाई सम्पादन गर्नुहोस्</translation> <translation id="6433595998831338502"><ph name="HOST_NAME" /> ले जडान गर्न अस्वीकार गर्यो।</translation> @@ -1528,6 +1531,7 @@ <translation id="6643016212128521049">खालि गर्नुहोस्</translation> <translation id="6645291930348198241">कुकीहरू र साइटको डेटा प्रयोग गर्न।</translation> <translation id="6646269444027925224">{COUNT,plural, =0{कुनै पनि होइन}=1{१ साइटबाट (तपाईं आफ्नो Google खाताबाट साइन आउट हुनु हुने छैन)}other{# साइटहरूबाट (तपाईं आफ्नो Google खाताबाट साइन आउट हुनु हुने छैन)}}</translation> +<translation id="6647197322759179819">खोज्ने क्रम सुचारु गर्नुहोस्</translation> <translation id="6648459603387803038">तपाईंका एड्मिन टाढैबाट तपाईंको ब्राउजरको सेटअप बदल्न सक्नुहुन्छ। यो डिभाइसका क्रियाकलाप Chrome बाहिरबाट पनि व्यवस्थापन गरिन सक्छ।</translation> <translation id="6648524591329069940">Serif फन्ट</translation> <translation id="6651270836885078973">व्यवस्थापक:</translation> @@ -2175,6 +2179,7 @@ <translation id="9114524666733003316">कार्डको पुष्टि गर्दै...</translation> <translation id="9114581008513152754">कुनै कम्पनी वा अन्य सङ्गठनले यो ब्राउजर व्यवस्थापन गर्दैन। यो डिभाइसका क्रियाकलाप Chrome बाहिरबाट व्यवस्थापन गर्न सकिन्छ। <ph name="BEGIN_LINK" />थप जान्नुहोस्<ph name="END_LINK" /></translation> <translation id="9117930699067497412">ताजा</translation> +<translation id="9118692854637641831"><ph name="HISTORY_CLUSTERS_SEARCH_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome को ब्राउजिङ इतिहासमा सान्दर्भिक गतिविधि हेर्न खोज्ने क्रम सुचारु गर्न Tab थिच्नुहोस् त्यसपछि Enter थिच्नुहोस्</translation> <translation id="9119042192571987207">अपलोड गरिएको</translation> <translation id="9128016270925453879">नीतिहरू लोड गरिएका छन्</translation> <translation id="9128870381267983090">नेटवर्कमा कनेक्ट गर्नुहोस्</translation>
diff --git a/components/sync/driver/resources/BUILD.gn b/components/sync/driver/resources/BUILD.gn index 8017305..c8e7dac5 100644 --- a/components/sync/driver/resources/BUILD.gn +++ b/components/sync/driver/resources/BUILD.gn
@@ -101,7 +101,7 @@ js_library("search") { deps = [ "//ui/webui/resources/js:util.m", - "//ui/webui/resources/js/cr/ui:splitter.m", + "//ui/webui/resources/js/cr/ui:splitter", ] }
diff --git a/components/sync/driver/resources/search.js b/components/sync/driver/resources/search.js index 9d6a76e..47f4127 100644 --- a/components/sync/driver/resources/search.js +++ b/components/sync/driver/resources/search.js
@@ -5,7 +5,7 @@ import {decorate} from 'chrome://resources/js/cr/ui.m.js'; import {ArrayDataModel} from 'chrome://resources/js/cr/ui/array_data_model.m.js'; import {List} from 'chrome://resources/js/cr/ui/list.m.js'; -import {Splitter} from 'chrome://resources/js/cr/ui/splitter.m.js'; +import {Splitter} from 'chrome://resources/js/cr/ui/splitter.js'; import {$, getRequiredElement} from 'chrome://resources/js/util.m.js'; import {decorateQuickQueryControls, decorateSearchControls} from './sync_search.js';
diff --git a/components/sync/driver/resources/sync_node_browser.js b/components/sync/driver/resources/sync_node_browser.js index b33d23da..6fd762d 100644 --- a/components/sync/driver/resources/sync_node_browser.js +++ b/components/sync/driver/resources/sync_node_browser.js
@@ -3,7 +3,7 @@ // found in the LICENSE file. import {decorate, define as crUiDefine} from 'chrome://resources/js/cr/ui.m.js'; -import {Splitter} from 'chrome://resources/js/cr/ui/splitter.m.js'; +import {Splitter} from 'chrome://resources/js/cr/ui/splitter.js'; import {Tree, TreeItem} from 'chrome://resources/js/cr/ui/tree.m.js'; import {$} from 'chrome://resources/js/util.m.js';
diff --git a/components/viz/service/display/surface_aggregator_perftest.cc b/components/viz/service/display/surface_aggregator_perftest.cc index 5322d27c..87882aa 100644 --- a/components/viz/service/display/surface_aggregator_perftest.cc +++ b/components/viz/service/display/surface_aggregator_perftest.cc
@@ -2,11 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <unordered_map> + #include "cc/test/fake_output_surface_client.h" #include "components/viz/common/frame_sinks/begin_frame_args.h" #include "components/viz/common/quads/compositor_frame.h" +#include "components/viz/common/quads/render_pass_io.h" #include "components/viz/common/quads/surface_draw_quad.h" #include "components/viz/common/quads/texture_draw_quad.h" +#include "components/viz/common/resources/transferable_resource.h" +#include "components/viz/common/surfaces/frame_sink_id.h" #include "components/viz/common/surfaces/local_surface_id.h" #include "components/viz/service/display/aggregated_frame.h" #include "components/viz/service/display/display_resource_provider_software.h" @@ -193,6 +198,7 @@ } void SetUpRenderPassListResources( + FrameSinkId frame_sink_id, CompositorRenderPassList* render_pass_list) { std::set<ResourceId> created_resources; for (auto& render_pass : *render_pass_list) { @@ -202,15 +208,36 @@ if (created_resources.find(resource_id) != created_resources.end()) { continue; } - resource_list_.push_back(TransferableResource::MakeSoftware( - SharedBitmap::GenerateId(), quad->rect.size(), RGBA_8888)); - resource_list_.back().id = resource_id; + resource_list_map_[frame_sink_id].push_back( + TransferableResource::MakeSoftware(SharedBitmap::GenerateId(), + quad->rect.size(), RGBA_8888)); + resource_list_map_[frame_sink_id].back().id = resource_id; created_resources.insert(resource_id); } } } } + void SubmitCompositorFrame(CompositorFrameSinkSupport* frame_sink, + SurfaceId surface_id, + const CompositorRenderPassList& render_pass_list, + std::vector<SurfaceRange> referenced_surfaces) { + CompositorRenderPassList local_list; + CompositorRenderPass::CopyAllForTest(render_pass_list, &local_list); + // Ensure damage encompasses the entire output_rect so everything is + // aggregated. + auto& last_render_pass = *local_list.back(); + last_render_pass.damage_rect = last_render_pass.output_rect; + + CompositorFrameBuilder frame_builder; + frame_builder.SetRenderPassList(std::move(local_list)) + .SetTransferableResources( + resource_list_map_[surface_id.frame_sink_id()]) + .SetReferencedSurfaces(std::move(referenced_surfaces)); + frame_sink->SubmitCompositorFrame(surface_id.local_surface_id(), + frame_builder.Build()); + } + void RunSingleSurfaceRenderPassListFromJson(const std::string& tag, const std::string& site, uint32_t year, @@ -219,13 +246,14 @@ ASSERT_TRUE(CompositorRenderPassListFromJSON(tag, site, year, index, &render_pass_list)); ASSERT_FALSE(render_pass_list.empty()); - this->SetUpRenderPassListResources(&render_pass_list); + + constexpr FrameSinkId root_frame_sink_id(1, 1); + TestSurfaceIdAllocator root_surface_id(root_frame_sink_id); + this->SetUpRenderPassListResources(root_frame_sink_id, &render_pass_list); aggregator_ = std::make_unique<SurfaceAggregator>( manager_.surface_manager(), resource_provider_.get(), true, true); - constexpr FrameSinkId root_frame_sink_id(1, 1); - TestSurfaceIdAllocator root_surface_id(root_frame_sink_id); auto root_support = std::make_unique<CompositorFrameSinkSupport>( nullptr, &manager_, root_frame_sink_id, /*is_root=*/true); @@ -234,19 +262,9 @@ timer_.Reset(); do { - CompositorRenderPassList local_list; - CompositorRenderPass::CopyAllForTest(render_pass_list, &local_list); - // Ensure damage encompasses the entire output_rect so everything is - // aggregated. - auto& last_render_pass = *local_list.back(); - last_render_pass.damage_rect = last_render_pass.output_rect; - - CompositorFrame frame = CompositorFrameBuilder() - .SetRenderPassList(std::move(local_list)) - .SetTransferableResources(resource_list_) - .Build(); - root_support->SubmitCompositorFrame(root_surface_id.local_surface_id(), - std::move(frame)); + SubmitCompositorFrame(root_support.get(), root_surface_id, + render_pass_list, + /*referenced_surfaces=*/{}); auto aggregated = aggregator_->Aggregate( root_surface_id, next_fake_display_time, gfx::OVERLAY_TRANSFORM_NONE); @@ -258,12 +276,77 @@ reporter.AddResult(kMetricSpeedRunsPerS, timer_.LapsPerSecond()); } + void RunMultiSurfacePerfTestFromJson(const std::string& name, size_t index) { + std::vector<FrameData> frame_data_list; + ASSERT_TRUE( + FrameDataFromJson("multi_surface_test", name, index, &frame_data_list)); + ASSERT_FALSE(frame_data_list.empty()); + + const int num_surfaces = frame_data_list.size(); + std::vector<std::unique_ptr<CompositorFrameSinkSupport>> frame_sinks( + num_surfaces); + for (int i = 0; i < num_surfaces; i++) { + auto frame_sink_id = frame_data_list[i].surface_id.frame_sink_id(); + // The first surface represents the root frame sink. + frame_sinks[i] = std::make_unique<CompositorFrameSinkSupport>( + nullptr, &manager_, frame_sink_id, + /*is_root=*/i == 0); + auto& render_pass_list = + frame_data_list[i].compositor_frame.render_pass_list; + this->SetUpRenderPassListResources(frame_sink_id, &render_pass_list); + } + // We only need to submit the non-root surfaces (i = [1, N-1]) once, but + // we'll submit the root surface every lap. + // Loop in reverse order so surfaces are always submitted before their + // parents are. + for (int i = frame_data_list.size() - 1; i >= 1; --i) { + auto surface_id = frame_data_list[i].surface_id; + auto& render_pass_list = + frame_data_list[i].compositor_frame.render_pass_list; + auto& referenced_surfaces = + frame_data_list[i].compositor_frame.metadata.referenced_surfaces; + SubmitCompositorFrame(frame_sinks[i].get(), surface_id, render_pass_list, + referenced_surfaces); + } + + aggregator_ = std::make_unique<SurfaceAggregator>( + manager_.surface_manager(), resource_provider_.get(), true, true); + + base::TimeTicks next_fake_display_time = + base::TimeTicks() + base::TimeDelta::FromSeconds(1); + timer_.Reset(); + do { + // For a single frame test we only need to submit a CompositorFrame for + // the root surface. + const auto& root_surface_data = frame_data_list[0]; + auto surface_id = root_surface_data.surface_id; + auto& render_pass_list = + root_surface_data.compositor_frame.render_pass_list; + auto& referenced_surfaces = + root_surface_data.compositor_frame.metadata.referenced_surfaces; + SubmitCompositorFrame(frame_sinks[0].get(), surface_id, render_pass_list, + referenced_surfaces); + + auto aggregated = aggregator_->Aggregate(root_surface_data.surface_id, + next_fake_display_time, + gfx::OVERLAY_TRANSFORM_NONE); + + next_fake_display_time += BeginFrameArgs::DefaultInterval(); + timer_.NextLap(); + } while (!timer_.HasTimeLimitExpired()); + + auto reporter = + SetUpSurfaceAggregatorReporter(name + "_multi_surface_json"); + reporter.AddResult(kMetricSpeedRunsPerS, timer_.LapsPerSecond()); + } + protected: ServerSharedBitmapManager shared_bitmap_manager_; FrameSinkManagerImpl manager_; std::unique_ptr<DisplayResourceProvider> resource_provider_; std::unique_ptr<SurfaceAggregator> aggregator_; - std::vector<TransferableResource> resource_list_; + // List of resources for each client_id. + std::map<FrameSinkId, std::vector<TransferableResource>> resource_list_map_; }; TEST_F(SurfaceAggregatorPerfTest, ManySurfacesOpaque) { @@ -348,6 +431,14 @@ TOP_REAL_WORLD_DESKTOP_RENDERER_PERF_TEST(yahoo_answers, 74) TOP_REAL_WORLD_DESKTOP_RENDERER_PERF_TEST(yahoo_sports, 269) +#define MULTI_SURFACE_PERF_TEST(NAME, FRAME) \ + TEST_F(SurfaceAggregatorPerfTest, NAME##_MultiSurfaceTest) { \ + this->RunMultiSurfacePerfTestFromJson(/*name=*/#NAME, \ + /*frame_index=*/FRAME); \ + } + +MULTI_SURFACE_PERF_TEST(youtube, 358) + #undef TOP_REAL_WORLD_DESKTOP_RENDERER_PERF_TEST } // namespace
diff --git a/components/viz/service/display/viz_perf_test.cc b/components/viz/service/display/viz_perf_test.cc index 0b863b5c..1e71a8b 100644 --- a/components/viz/service/display/viz_perf_test.cc +++ b/components/viz/service/display/viz_perf_test.cc
@@ -14,35 +14,68 @@ namespace viz { +namespace { + +// Creates a path to the JSON file where `group` and `name` are parent folder +// names, and `frame_index` padded to 4 digits will be the filename. e.g. +// .../render_pass_data/group/name/0001.json +absl::optional<base::FilePath> MakeJsonPath(const std::string& group, + const std::string& name, + size_t frame_index) { + base::FilePath json_path; + if (!base::PathService::Get(Paths::DIR_TEST_DATA, &json_path)) + return absl::nullopt; + std::string filename = base::NumberToString(frame_index); + while (filename.length() < 4) + filename = "0" + filename; + filename += ".json"; + return json_path.Append(FILE_PATH_LITERAL("render_pass_data")) + .AppendASCII(group) + .AppendASCII(name) + .AppendASCII(filename); +} + +absl::optional<base::Value> ReadValueFromJson(const std::string& group, + const std::string& name, + size_t frame_index) { + auto json_path = MakeJsonPath(group, name, frame_index); + if (!json_path) + return absl::nullopt; + if (!base::PathExists(*json_path)) + return absl::nullopt; + std::string json_text; + if (!base::ReadFileToString(*json_path, &json_text)) + return absl::nullopt; + return base::JSONReader::Read(json_text); +} + +} // namespace + bool CompositorRenderPassListFromJSON( const std::string& tag, const std::string& site, uint32_t year, size_t frame_index, CompositorRenderPassList* render_pass_list) { - base::FilePath json_path; - if (!base::PathService::Get(Paths::DIR_TEST_DATA, &json_path)) + std::string name = site + "_" + base::NumberToString(year); + auto dict = ReadValueFromJson(tag, name, frame_index); + if (!dict) { return false; - std::string site_year = site + "_" + base::NumberToString(year); - std::string filename = base::NumberToString(frame_index); - while (filename.length() < 4) - filename = "0" + filename; - filename += ".json"; - json_path = json_path.Append(FILE_PATH_LITERAL("render_pass_data")) - .AppendASCII(tag) - .AppendASCII(site_year) - .AppendASCII(filename); - if (!base::PathExists(json_path)) - return false; - std::string json_text; - if (!base::ReadFileToString(json_path, &json_text)) - return false; - absl::optional<base::Value> dict = base::JSONReader::Read(json_text); - if (!dict.has_value()) - return false; + } return CompositorRenderPassListFromDict(dict.value(), render_pass_list); } +bool FrameDataFromJson(const std::string& group, + const std::string& name, + size_t frame_index, + std::vector<FrameData>* frame_data_list) { + auto list = ReadValueFromJson(group, name, frame_index); + if (!list) { + return false; + } + return FrameDataFromList(list.value(), frame_data_list); +} + namespace { constexpr char kPerfTestTimeMillis[] = "perf-test-time-ms";
diff --git a/components/viz/service/display/viz_perf_test.h b/components/viz/service/display/viz_perf_test.h index 8ef6093e..a71bffb3 100644 --- a/components/viz/service/display/viz_perf_test.h +++ b/components/viz/service/display/viz_perf_test.h
@@ -6,6 +6,7 @@ #define COMPONENTS_VIZ_SERVICE_DISPLAY_VIZ_PERF_TEST_H_ #include <string> +#include <vector> #include "base/timer/lap_timer.h" #include "components/viz/common/quads/compositor_render_pass.h" @@ -13,6 +14,8 @@ namespace viz { +struct FrameData; + // Reads the specified JSON file and parses a CompositorRenderPassList from it, // storing the result in |render_pass_list|. bool CompositorRenderPassListFromJSON( @@ -22,7 +25,15 @@ size_t frame_index, CompositorRenderPassList* render_pass_list); -// Viz perf test base class that sets up a lap timer with a specified duration. +// Reads the specified JSON file and stores the compositor frame data in the +// output parameter `frame_data_list`. +bool FrameDataFromJson(const std::string& group, + const std::string& name, + size_t frame_index, + std::vector<FrameData>* frame_data_list); + +// Viz perf test base class that sets up a lap timer with a specified +// duration. class VizPerfTest : public testing::Test { public: VizPerfTest();
diff --git a/components/viz/test/data/mask_with_effect_different_size.png b/components/viz/test/data/mask_with_effect_different_size.png index 82917eb..2a8c50dd 100644 --- a/components/viz/test/data/mask_with_effect_different_size.png +++ b/components/viz/test/data/mask_with_effect_different_size.png Binary files differ
diff --git a/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.h b/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.h index e09a4178..de99672d 100644 --- a/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.h +++ b/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.h
@@ -192,9 +192,6 @@ // orientation. content::MouseWheelRailsFilterMac _mouseWheelFilter; - // Whether the direct manipulation feature is enabled. - bool _direct_manipulation_enabled; - // Whether the pen's tip is in contact with the stylus digital tablet. bool _has_pen_contact;
diff --git a/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.mm b/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.mm index e92152bd..3ff49bb 100644 --- a/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.mm +++ b/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.mm
@@ -228,8 +228,6 @@ _isStylusEnteringProximity = false; _keyboardLockActive = false; _textInputType = ui::TEXT_INPUT_TYPE_NONE; - _direct_manipulation_enabled = - base::FeatureList::IsEnabled(features::kDirectManipulationStylus); _has_pen_contact = false; } return self; @@ -763,77 +761,49 @@ if (type == NSMouseMoved) _cursorHidden = NO; - bool send_touch = - _direct_manipulation_enabled && - _pointerType == blink::WebPointerProperties::PointerType::kPen; + bool unaccelerated_movement = + _mouse_locked && _mouse_lock_unaccelerated_movement; + WebMouseEvent event = WebMouseEventBuilder::Build( + theEvent, self, _pointerType, unaccelerated_movement); - // Send touch events when the pen is in contact with the tablet. - if (send_touch) { - // Because the NSLeftMouseUp event's buttonMask is not - // NSEventButtonMaskPenTip, we read |has_pen_contact_| to ensure a - // TouchRelease is sent appropriately at the end when the stylus is - // no longer in contact with the digitizer. - send_touch = _has_pen_contact; - if (type == NSLeftMouseDown || type == NSLeftMouseUp || - type == NSLeftMouseDragged) { - NSEventButtonMask buttonMask = [theEvent buttonMask]; - if (buttonMask == NSEventButtonMaskPenTip) { - DCHECK(type != NSLeftMouseUp); - send_touch = _has_pen_contact = true; - } else { - _has_pen_contact = false; - } + if (_mouse_locked && + base::FeatureList::IsEnabled(features::kConsolidatedMovementXY)) { + // When mouse is locked, we keep increasing |last_mouse_screen_position| + // by movement_x/y so that we can still use PositionInScreen to calculate + // movements in blink. We need to keep |last_mouse_screen_position_| from + // getting too large because it will lose some precision. So whenever it + // exceed the |wrap_around_distance|, we start again from the current + // mouse position (locked position), and also send a synthesized event to + // update the blink-side status. + if (std::abs(_last_mouse_screen_position.x()) > wrap_around_distance || + std::abs(_last_mouse_screen_position.y()) > wrap_around_distance) { + NSWindow* window = [self window]; + NSPoint location = [window mouseLocationOutsideOfEventStream]; + int window_number = window ? [window windowNumber] : -1; + NSEvent* nsevent = [NSEvent mouseEventWithType:NSMouseMoved + location:location + modifierFlags:[theEvent modifierFlags] + timestamp:[theEvent timestamp] + windowNumber:window_number + context:nil + eventNumber:0 + clickCount:[theEvent clickCount] + pressure:0]; + WebMouseEvent wrap_around_event = + WebMouseEventBuilder::Build(nsevent, self, _pointerType); + _last_mouse_screen_position = wrap_around_event.PositionInScreen(); + wrap_around_event.SetModifiers( + event.GetModifiers() | + blink::WebInputEvent::Modifiers::kRelativeMotionEvent); + _hostHelper->RouteOrProcessMouseEvent(wrap_around_event); } + event.SetPositionInScreen( + _last_mouse_screen_position + + gfx::Vector2dF(event.movement_x, event.movement_y)); } - if (!send_touch) { - bool unaccelerated_movement = - _mouse_locked && _mouse_lock_unaccelerated_movement; - WebMouseEvent event = WebMouseEventBuilder::Build( - theEvent, self, _pointerType, unaccelerated_movement); - - if (_mouse_locked && - base::FeatureList::IsEnabled(features::kConsolidatedMovementXY)) { - // When mouse is locked, we keep increasing |last_mouse_screen_position| - // by movement_x/y so that we can still use PositionInScreen to calculate - // movements in blink. We need to keep |last_mouse_screen_position_| from - // getting too large because it will lose some precision. So whenever it - // exceed the |wrap_around_distance|, we start again from the current - // mouse position (locked position), and also send a synthesized event to - // update the blink-side status. - if (std::abs(_last_mouse_screen_position.x()) > wrap_around_distance || - std::abs(_last_mouse_screen_position.y()) > wrap_around_distance) { - NSWindow* window = [self window]; - NSPoint location = [window mouseLocationOutsideOfEventStream]; - int window_number = window ? [window windowNumber] : -1; - NSEvent* nsevent = [NSEvent mouseEventWithType:NSMouseMoved - location:location - modifierFlags:[theEvent modifierFlags] - timestamp:[theEvent timestamp] - windowNumber:window_number - context:nil - eventNumber:0 - clickCount:[theEvent clickCount] - pressure:0]; - WebMouseEvent wrap_around_event = - WebMouseEventBuilder::Build(nsevent, self, _pointerType); - _last_mouse_screen_position = wrap_around_event.PositionInScreen(); - wrap_around_event.SetModifiers( - event.GetModifiers() | - blink::WebInputEvent::Modifiers::kRelativeMotionEvent); - _hostHelper->RouteOrProcessMouseEvent(wrap_around_event); - } - event.SetPositionInScreen( - _last_mouse_screen_position + - gfx::Vector2dF(event.movement_x, event.movement_y)); - } - - _last_mouse_screen_position = event.PositionInScreen(); - _hostHelper->RouteOrProcessMouseEvent(event); - } else { - WebTouchEvent event = WebTouchEventBuilder::Build(theEvent, self); - _hostHelper->RouteOrProcessTouchEvent(event); - } + _last_mouse_screen_position = event.PositionInScreen(); + _hostHelper->RouteOrProcessMouseEvent(event); } - (void)tabletEvent:(NSEvent*)theEvent {
diff --git a/content/browser/accessibility/accessibility_event_recorder_uia_win.cc b/content/browser/accessibility/accessibility_event_recorder_uia_win.cc index 7be8433..2bd11a3 100644 --- a/content/browser/accessibility/accessibility_event_recorder_uia_win.cc +++ b/content/browser/accessibility/accessibility_event_recorder_uia_win.cc
@@ -8,6 +8,8 @@ #include <numeric> #include <utility> +#include <psapi.h> + #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" @@ -16,6 +18,7 @@ #include "base/win/scoped_safearray.h" #include "base/win/scoped_variant.h" #include "base/win/windows_version.h" +#include "build/build_config.h" #include "content/browser/accessibility/browser_accessibility_com_win.h" #include "content/browser/accessibility/browser_accessibility_manager.h" #include "content/browser/accessibility/browser_accessibility_manager_win.h" @@ -30,6 +33,25 @@ namespace { +#if defined(COMPILER_MSVC) +#define RETURN_ADDRESS() _ReturnAddress() +#elif defined(COMPILER_GCC) && !defined(OS_NACL) +#define RETURN_ADDRESS() \ + __builtin_extract_return_addr(__builtin_return_address(0)) +#else +#define RETURN_ADDRESS() nullptr +#endif + +static std::pair<uintptr_t, uintptr_t> GetModuleAddressRange( + const wchar_t* module_name) { + MODULEINFO info; + CHECK(GetModuleInformation(GetCurrentProcess(), GetModuleHandle(module_name), + &info, sizeof(info))); + + const uintptr_t start = reinterpret_cast<uintptr_t>(info.lpBaseOfDll); + return std::make_pair(start, start + info.SizeOfImage); +} + std::string UiaIdentifierToStringPretty(int32_t id) { auto str = base::WideToUTF8(UiaIdentifierToString(id)); // Remove UIA_ prefix, and EventId/PropertyId suffixes @@ -175,66 +197,10 @@ // Wait for shutdown signal shutdown_signal_.Wait(); - // Due to a bug in Windows (fixed in Windows 10 19H1), events are raised - // exactly twice for any in-proc off-thread event listeners. We filter out the - // duplicate events here, and forward the remaining events to our owner. { base::AutoLock lock{on_event_lock_}; - if (event_logs_.size() == 1) { - // Only received events on a single thread... perhaps the bug was fixed? - // Forward all events. - for (auto&& event : event_logs_.begin()->second) - owner_->OnEvent(event); - } else if (event_logs_.size() == 2) { - // Events were raised on two threads, as expected. Sort the lists and - // forward events, eliminating duplicates that occur in both threads. - auto&& events_thread1 = event_logs_.begin()->second; - auto&& events_thread2 = (++event_logs_.begin())->second; - - std::sort(events_thread1.begin(), events_thread1.end()); - std::sort(events_thread2.begin(), events_thread2.end()); - - auto it1 = events_thread1.begin(); - auto it2 = events_thread2.begin(); - while (it1 < events_thread1.end() && it2 < events_thread2.end()) { - if (*it1 == *it2) { - owner_->OnEvent(*it1); - it1++; - it2++; - } else if (*it1 < *it2) { - owner_->OnEvent(*it1); - it1++; - } else { - owner_->OnEvent(*it2); - it2++; - } - } - while (it1 < events_thread1.end()) - owner_->OnEvent(*it1++); - while (it2 < events_thread2.end()) - owner_->OnEvent(*it2++); - } else { - // Typically we'll get events on exactly two threads (one directly from - // UIA, the second from RPC), but sometimes RPC will split its events - // across different threads. - // - // Unfortunately, there is no robust method of eliminating duplicates in - // this case. Tests with intentional duplicates could run afoul of this - // logic in rare scenarios; it is recommended that intentionally - // duplicated events be avoided in tests, when possible. - std::vector<std::string> combined; - for (auto&& log : event_logs_) - combined.insert(combined.end(), log.second.begin(), log.second.end()); - std::sort(combined.begin(), combined.end()); - - std::string last_event; - for (auto&& event : combined) { - if (last_event != event) - owner_->OnEvent(last_event = event); - else - last_event = {}; - } - } + for (const std::string& event : event_logs_) + owner_->OnEvent(event); } // Cleanup @@ -251,24 +217,27 @@ } void AccessibilityEventRecorderUia::Thread::SendShutdownSignal() { - // We expect to see the shutdown sentinel exactly twice (due to the Windows - // bug detailed in |ThreadMain| and fixed in 19H1), so don't actually shut - // down the thread until the second call. - if (shutdown_sentinel_received_ || - base::win::GetVersion() >= base::win::Version::WIN10_19H1) - shutdown_signal_.Signal(); - else - shutdown_sentinel_received_ = true; + shutdown_signal_.Signal(); } void AccessibilityEventRecorderUia::Thread::OnEvent(const std::string& event) { // We need to synchronize event logging, since UIA event callbacks can be // coming from multiple threads. base::AutoLock lock{on_event_lock_}; - event_logs_[base::PlatformThread::CurrentId()].push_back(event); + event_logs_.push_back(event); } -AccessibilityEventRecorderUia::Thread::EventHandler::EventHandler() {} +AccessibilityEventRecorderUia::Thread::EventHandler::EventHandler() { + // Some events are duplicated between UIAutomationCore.dll and RPCRT4.dll. + // Before WIN10_19H1, events are mainly sent from RPCRT4.dll, with a few + // duplicates sent from UIAutomationCore.dll. + // After WIN10_19H1, events are mainly sent from UIAutomationCore.dll, with a + // few duplicates sent from RPCRT4.dll. + allowed_module_address_range_ = GetModuleAddressRange( + (base::win::GetVersion() >= base::win::Version::WIN10_19H1) + ? L"UIAutomationCore.dll" + : L"RPCRT4.dll"); +} AccessibilityEventRecorderUia::Thread::EventHandler::~EventHandler() {} @@ -287,11 +256,23 @@ STDMETHODIMP AccessibilityEventRecorderUia::Thread::EventHandler::HandleFocusChangedEvent( IUIAutomationElement* sender) { - if (!owner_) + if (!owner_ || !IsCallerFromAllowedModule(RETURN_ADDRESS())) return S_OK; base::win::ScopedSafearray id; sender->GetRuntimeId(id.Receive()); + + if (auto lock_scope = id.CreateLockScope<VT_I4>()) { + // Debounce focus events received from the same |sender|. + if (std::equal(lock_scope->begin(), lock_scope->end(), + last_focused_runtime_id_.begin(), + last_focused_runtime_id_.end())) { + return S_OK; + } + + last_focused_runtime_id_ = {lock_scope->begin(), lock_scope->end()}; + } + base::win::ScopedVariant id_variant(id.Release()); Microsoft::WRL::ComPtr<IUIAutomationElement> element_found; @@ -319,17 +300,18 @@ IUIAutomationElement* sender, PROPERTYID property_id, VARIANT new_value) { - if (owner_) { - std::string prop_str = UiaIdentifierToStringPretty(property_id); - if (prop_str.empty()) { - VLOG(1) << "Ignoring UIA property-changed event " << property_id; - return S_OK; - } + if (!owner_ || !IsCallerFromAllowedModule(RETURN_ADDRESS())) + return S_OK; - std::string log = base::StringPrintf("%s changed %s", prop_str.c_str(), - GetSenderInfo(sender).c_str()); - owner_->OnEvent(log); + std::string prop_str = UiaIdentifierToStringPretty(property_id); + if (prop_str.empty()) { + VLOG(1) << "Ignoring UIA property-changed event " << property_id; + return S_OK; } + + std::string log = base::StringPrintf("%s changed %s", prop_str.c_str(), + GetSenderInfo(sender).c_str()); + owner_->OnEvent(log); return S_OK; } @@ -338,34 +320,35 @@ HandleStructureChangedEvent(IUIAutomationElement* sender, StructureChangeType change_type, SAFEARRAY* runtime_id) { - if (owner_) { - std::string type_str; - switch (change_type) { - case StructureChangeType_ChildAdded: - type_str = "ChildAdded"; - break; - case StructureChangeType_ChildRemoved: - type_str = "ChildRemoved"; - break; - case StructureChangeType_ChildrenInvalidated: - type_str = "ChildrenInvalidated"; - break; - case StructureChangeType_ChildrenBulkAdded: - type_str = "ChildrenBulkAdded"; - break; - case StructureChangeType_ChildrenBulkRemoved: - type_str = "ChildrenBulkRemoved"; - break; - case StructureChangeType_ChildrenReordered: - type_str = "ChildrenReordered"; - break; - } + if (!owner_ || !IsCallerFromAllowedModule(RETURN_ADDRESS())) + return S_OK; - std::string log = - base::StringPrintf("StructureChanged/%s %s", type_str.c_str(), - GetSenderInfo(sender).c_str()); - owner_->OnEvent(log); + std::string type_str; + switch (change_type) { + case StructureChangeType_ChildAdded: + type_str = "ChildAdded"; + break; + case StructureChangeType_ChildRemoved: + type_str = "ChildRemoved"; + break; + case StructureChangeType_ChildrenInvalidated: + type_str = "ChildrenInvalidated"; + break; + case StructureChangeType_ChildrenBulkAdded: + type_str = "ChildrenBulkAdded"; + break; + case StructureChangeType_ChildrenBulkRemoved: + type_str = "ChildrenBulkRemoved"; + break; + case StructureChangeType_ChildrenReordered: + type_str = "ChildrenReordered"; + break; } + + std::string log = + base::StringPrintf("StructureChanged/%s %s", type_str.c_str(), + GetSenderInfo(sender).c_str()); + owner_->OnEvent(log); return S_OK; } @@ -373,33 +356,45 @@ AccessibilityEventRecorderUia::Thread::EventHandler::HandleAutomationEvent( IUIAutomationElement* sender, EVENTID event_id) { - if (owner_) { - if (event_id == owner_->shutdown_sentinel_) { - // This is a sentinel value that tells us the tests are finished. - owner_->SendShutdownSignal(); - } else { - std::string event_str = UiaIdentifierToStringPretty(event_id); - if (event_str.empty()) { - VLOG(1) << "Ignoring UIA automation event " << event_id; - return S_OK; - } + if (!owner_ || !IsCallerFromAllowedModule(RETURN_ADDRESS())) + return S_OK; - // Remove duplicate menuclosed events with no event data. - // The "duplicates" are benign. UIA currently duplicates *all* events for - // in-process listeners, and the event-recorder tries to eliminate the - // duplicates... but since the recorder sometimes isn't able to retrieve - // the role, the duplicate-elimination logic doesn't see them as - // duplicates in this case. - std::string sender_info = - event_id == UIA_MenuClosedEventId ? "" : GetSenderInfo(sender); - std::string log = - base::StringPrintf("%s %s", event_str.c_str(), sender_info.c_str()); - owner_->OnEvent(log); + if (event_id == owner_->shutdown_sentinel_) { + // This is a sentinel value that tells us the tests are finished. + owner_->SendShutdownSignal(); + } else { + std::string event_str = UiaIdentifierToStringPretty(event_id); + if (event_str.empty()) { + VLOG(1) << "Ignoring UIA automation event " << event_id; + return S_OK; } + + // Remove duplicate menuclosed events with no event data. + // The "duplicates" are benign. UIA currently duplicates *all* events for + // in-process listeners, and the event-recorder tries to eliminate the + // duplicates... but since the recorder sometimes isn't able to retrieve + // the role, the duplicate-elimination logic doesn't see them as + // duplicates in this case. + std::string sender_info = + event_id == UIA_MenuClosedEventId ? "" : GetSenderInfo(sender); + std::string log = + base::StringPrintf("%s %s", event_str.c_str(), sender_info.c_str()); + owner_->OnEvent(log); } return S_OK; } +// Due to a bug in Windows (fixed in Windows 10 19H1, but found broken in 20H2), +// events are raised exactly twice for any in-proc off-thread event listeners. +// To avoid this, in UIA API methods we can pass the RETURN_ADDRESS() to this +// method to determine whether the caller belongs to a specific platform module. +bool AccessibilityEventRecorderUia::Thread::EventHandler:: + IsCallerFromAllowedModule(void* return_address) { + const auto address = reinterpret_cast<uintptr_t>(return_address); + return address >= allowed_module_address_range_.first && + address < allowed_module_address_range_.second; +} + std::string AccessibilityEventRecorderUia::Thread::EventHandler::GetSenderInfo( IUIAutomationElement* sender) { std::string sender_info;
diff --git a/content/browser/accessibility/accessibility_event_recorder_uia_win.h b/content/browser/accessibility/accessibility_event_recorder_uia_win.h index 8809a4a..01d7c06 100644 --- a/content/browser/accessibility/accessibility_event_recorder_uia_win.h +++ b/content/browser/accessibility/accessibility_event_recorder_uia_win.h
@@ -9,8 +9,8 @@ #include <stdint.h> #include <uiautomation.h> #include <wrl/client.h> -#include <map> #include <string> +#include <utility> #include <vector> #include "base/atomicops.h" @@ -67,12 +67,11 @@ base::OnceClosure initialization_complete_; base::OnceClosure shutdown_complete_; base::WaitableEvent shutdown_signal_; - bool shutdown_sentinel_received_ = false; // Thread-specific wrapper for OnEvent to handle necessary locking void OnEvent(const std::string& event); base::Lock on_event_lock_; - std::map<base::PlatformThreadId, std::vector<std::string>> event_logs_; + std::vector<std::string> event_logs_; // An implementation of various UIA interfaces that forward event // notifications to the owning event recorder. @@ -119,10 +118,15 @@ AccessibilityEventRecorderUia::Thread* owner_ = nullptr; private: + std::pair<uintptr_t, uintptr_t> allowed_module_address_range_; + bool IsCallerFromAllowedModule(void* return_address); + std::string GetSenderInfo(IUIAutomationElement* sender); Microsoft::WRL::ComPtr<IUIAutomationElement> root_; + std::vector<int32_t> last_focused_runtime_id_; + DISALLOW_COPY_AND_ASSIGN(EventHandler); }; Microsoft::WRL::ComPtr<CComObject<EventHandler>> uia_event_handler_;
diff --git a/content/browser/accessibility/browser_accessibility_manager.cc b/content/browser/accessibility/browser_accessibility_manager.cc index a80ca3a..2fb5600 100644 --- a/content/browser/accessibility/browser_accessibility_manager.cc +++ b/content/browser/accessibility/browser_accessibility_manager.cc
@@ -786,13 +786,6 @@ BrowserAccessibilityStateImpl::GetInstance()->OnAccessibilityApiUsage(); } -void BrowserAccessibilityManager::SetFocusLocallyForTesting( - BrowserAccessibility* node) { - ui::AXTreeData data = GetTreeData(); - data.focus_id = node->GetId(); - ax_tree()->UpdateData(data); -} - // static void BrowserAccessibilityManager::SetFocusChangeCallbackForTesting( base::RepeatingClosure callback) { @@ -1372,6 +1365,33 @@ return result; } +void BrowserAccessibilityManager::OnTreeDataChanged( + ui::AXTree* tree, + const ui::AXTreeData& old_data, + const ui::AXTreeData& new_data) { + DCHECK_EQ(ax_tree(), tree); + if (new_data.tree_id == ui::AXTreeIDUnknown() || + new_data.tree_id == ax_tree_id_) { + return; // Tree ID hasn't changed. + } + + // Either the tree that is being managed by this manager has just been + // created, or it has been destroyed and re-created. + connected_to_parent_tree_node_ = false; + + // If the current focus is in the tree that has just been destroyed, then + // reset the focus to nullptr. It will be set to the current focus again the + // next time there is a focus event. + if (ax_tree_id_ != ui::AXTreeIDUnknown() && + ax_tree_id_ == last_focused_node_tree_id_) { + SetLastFocusedNode(nullptr); + } + + ui::AXTreeManagerMap::GetInstance().RemoveTreeManager(ax_tree_id_); + ax_tree_id_ = new_data.tree_id; + ui::AXTreeManagerMap::GetInstance().AddTreeManager(ax_tree_id_, this); +} + void BrowserAccessibilityManager::OnNodeWillBeDeleted(ui::AXTree* tree, ui::AXNode* node) { DCHECK(node); @@ -1443,26 +1463,10 @@ ui::AXTree* tree, bool root_changed, const std::vector<ui::AXTreeObserver::Change>& changes) { - const bool ax_tree_id_changed = - GetTreeData().tree_id != ui::AXTreeIDUnknown() && - GetTreeData().tree_id != ax_tree_id_; - // When the tree that contains the focus is destroyed and re-created, we - // should fire a new focus event. Also, whenever the tree ID or the root of - // this tree changes we may need to fire an event on our parent node in the - // parent tree to ensure that we're properly connected. - if (ax_tree_id_changed && last_focused_node_tree_id_ && - ax_tree_id_ == *last_focused_node_tree_id_) { - SetLastFocusedNode(nullptr); - } - if (ax_tree_id_changed || root_changed) + DCHECK_EQ(ax_tree(), tree); + if (root_changed) connected_to_parent_tree_node_ = false; - if (ax_tree_id_changed) { - ui::AXTreeManagerMap::GetInstance().RemoveTreeManager(ax_tree_id_); - ax_tree_id_ = GetTreeData().tree_id; - ui::AXTreeManagerMap::GetInstance().AddTreeManager(ax_tree_id_, this); - } - // Calls OnDataChanged on newly created, reparented or changed nodes. for (const auto& change : changes) { ui::AXNode* node = change.node;
diff --git a/content/browser/accessibility/browser_accessibility_manager.h b/content/browser/accessibility/browser_accessibility_manager.h index 0c29d23..08119a55 100644 --- a/content/browser/accessibility/browser_accessibility_manager.h +++ b/content/browser/accessibility/browser_accessibility_manager.h
@@ -236,10 +236,6 @@ return hidden_by_interstitial_page_; } - // Pretend that the given node has focus, for testing only. Doesn't - // communicate with the renderer and doesn't fire any events. - void SetFocusLocallyForTesting(BrowserAccessibility* node); - // For testing only, register a function to be called when focus changes // in any BrowserAccessibilityManager. static void SetFocusChangeCallbackForTesting(base::RepeatingClosure callback); @@ -440,6 +436,9 @@ ui::AXTree* ax_tree() const { return tree_.get(); } // AXTreeObserver implementation. + void OnTreeDataChanged(ui::AXTree* tree, + const ui::AXTreeData& old_data, + const ui::AXTreeData& new_data) override; void OnNodeWillBeDeleted(ui::AXTree* tree, ui::AXNode* node) override; void OnSubtreeWillBeDeleted(ui::AXTree* tree, ui::AXNode* node) override; void OnNodeCreated(ui::AXTree* tree, ui::AXNode* node) override;
diff --git a/content/browser/accessibility/browser_accessibility_win_unittest.cc b/content/browser/accessibility/browser_accessibility_win_unittest.cc index 7642483..05dccefa 100644 --- a/content/browser/accessibility/browser_accessibility_win_unittest.cc +++ b/content/browser/accessibility/browser_accessibility_win_unittest.cc
@@ -1227,7 +1227,9 @@ BrowserAccessibilityWin* combo_box_accessible = ToBrowserAccessibilityWin(root_accessible->PlatformGetChild(0)); ASSERT_NE(nullptr, combo_box_accessible); - manager->SetFocusLocallyForTesting(combo_box_accessible); + ui::AXTreeData data = manager->GetTreeData(); + data.focus_id = combo_box_accessible->GetId(); + manager->ax_tree()->UpdateDataForTesting(data); ASSERT_EQ(combo_box_accessible, ToBrowserAccessibilityWin(manager->GetFocus())); BrowserAccessibilityWin* search_box_accessible = @@ -1884,7 +1886,9 @@ BrowserAccessibilityWin* combo_box_accessible = ToBrowserAccessibilityWin(root_accessible->PlatformGetChild(0)); ASSERT_NE(nullptr, combo_box_accessible); - manager->SetFocusLocallyForTesting(combo_box_accessible); + ui::AXTreeData data = manager->GetTreeData(); + data.focus_id = combo_box_accessible->GetId(); + manager->ax_tree()->UpdateDataForTesting(data); ASSERT_EQ(combo_box_accessible, ToBrowserAccessibilityWin(manager->GetFocus())); BrowserAccessibilityWin* text_field_accessible = @@ -1907,7 +1911,9 @@ EXPECT_EQ(2, caret_offset); // Move the focus to the text field. - manager->SetFocusLocallyForTesting(text_field_accessible); + data = manager->GetTreeData(); + data.focus_id = text_field_accessible->GetId(); + manager->ax_tree()->UpdateDataForTesting(data); ASSERT_EQ(text_field_accessible, ToBrowserAccessibilityWin(manager->GetFocus())); @@ -2017,7 +2023,9 @@ EXPECT_EQ(6, caret_offset); // Move the focus to the content editable. - manager->SetFocusLocallyForTesting(div_editable_accessible); + ui::AXTreeData data = manager->GetTreeData(); + data.focus_id = div_editable_accessible->GetId(); + manager->ax_tree()->UpdateDataForTesting(data); ASSERT_EQ(div_editable_accessible, ToBrowserAccessibilityWin(manager->GetFocus())); @@ -2187,7 +2195,9 @@ EXPECT_EQ(7, caret_offset); // Move the focus to the content editable. - manager->SetFocusLocallyForTesting(div_editable_accessible); + ui::AXTreeData data = manager->GetTreeData(); + data.focus_id = div_editable_accessible->GetId(); + manager->ax_tree()->UpdateDataForTesting(data); ASSERT_EQ(div_editable_accessible, ToBrowserAccessibilityWin(manager->GetFocus()));
diff --git a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc index 54b653f..53477cb0 100644 --- a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc +++ b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -201,6 +201,11 @@ } IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, + AccessibilityCSSContentVisibilityAutoAriaHidden) { + RunCSSTest(FILE_PATH_LITERAL("content-visibility-auto-aria-hidden.html")); +} + +IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, AccessibilityCSSContentVisibilityHiddenCheckFailure) { RunCSSTest(FILE_PATH_LITERAL("content-visibility-hidden-check-failure.html")); }
diff --git a/content/browser/browser_context.cc b/content/browser/browser_context.cc index a7734981..cfc09d0 100644 --- a/content/browser/browser_context.cc +++ b/content/browser/browser_context.cc
@@ -64,6 +64,9 @@ namespace { +using perfetto::protos::pbzero::ChromeBrowserContext; +using perfetto::protos::pbzero::ChromeTrackEvent; + void SaveSessionStateOnIOThread(AppCacheServiceImpl* appcache_service) { appcache_service->set_force_keep_session_state(); } @@ -77,33 +80,23 @@ } // namespace BrowserContext::BrowserContext() { - TRACE_EVENT("shutdown", "BrowserContext::BrowserContext", - [&](perfetto::EventContext ctx) { - auto* event = - ctx.event<perfetto::protos::pbzero::ChromeTrackEvent>(); - event->set_chrome_browser_context()->set_ptr( - reinterpret_cast<uint64_t>(this)); - }); - TRACE_EVENT_NESTABLE_ASYNC_BEGIN1("shutdown", "Browser.BrowserContext", this, - "browser_context", - static_cast<void*>(this)); - impl_ = std::make_unique<Impl>(this); + TRACE_EVENT("shutdown", "BrowserContext::BrowserContext", + ChromeTrackEvent::kChromeBrowserContext, *this); + TRACE_EVENT_BEGIN("shutdown", "Browser.BrowserContext", + perfetto::Track::FromPointer(this), + ChromeTrackEvent::kChromeBrowserContext, *this); } BrowserContext::~BrowserContext() { TRACE_EVENT("shutdown", "BrowserContext::~BrowserContext", - [&](perfetto::EventContext ctx) { - auto* event = - ctx.event<perfetto::protos::pbzero::ChromeTrackEvent>(); - event->set_chrome_browser_context()->set_ptr( - reinterpret_cast<uint64_t>(this)); - }); + ChromeTrackEvent::kChromeBrowserContext, *this); + + // End for ASYNC event "Browser.BrowserContext". + TRACE_EVENT_END("shutdown", perfetto::Track::FromPointer(this), + ChromeTrackEvent::kChromeBrowserContext, *this); impl_.reset(); - - TRACE_EVENT_NESTABLE_ASYNC_END1("shutdown", "Browser.BrowserContext", this, - "browser_context", static_cast<void*>(this)); } DownloadManager* BrowserContext::GetDownloadManager() { @@ -347,6 +340,11 @@ dict.Add("id", impl()->UniqueId()); } +void BrowserContext::WriteIntoTrace( + perfetto::TracedProto<ChromeBrowserContext> proto) { + proto->set_id(impl()->UniqueId()); +} + ////////////////////////////////////////////////////////////////////////////// // The //content embedder can override the methods below to change or extend // how the //content layer interacts with a BrowserContext. The code below
diff --git a/content/browser/browser_main_runner_impl.cc b/content/browser/browser_main_runner_impl.cc index fde9208..4edb502 100644 --- a/content/browser/browser_main_runner_impl.cc +++ b/content/browser/browser_main_runner_impl.cc
@@ -169,7 +169,7 @@ main_loop_->PreShutdown(); // Finalize the startup tracing session if it is still active. - StartupTracingController::GetInstance().WaitUntilStopped(); + StartupTracingController::GetInstance().ShutdownAndWaitForStopIfNeeded(); { // The trace event has to stay between profiler creation and destruction.
diff --git a/content/browser/child_process_launcher.cc b/content/browser/child_process_launcher.cc index 65099d93..ecc8ee0e 100644 --- a/content/browser/child_process_launcher.cc +++ b/content/browser/child_process_launcher.cc
@@ -16,6 +16,7 @@ #include "base/process/launch.h" #include "base/process/process_metrics.h" #include "base/time/time.h" +#include "base/tracing/protos/chrome_track_event.pbzero.h" #include "build/build_config.h" #include "content/public/browser/child_process_launcher_utils.h" #include "content/public/common/content_features.h" @@ -29,6 +30,28 @@ using internal::ChildProcessLauncherHelper; +void ChildProcessLauncherPriority::WriteIntoTrace( + perfetto::TracedProto< + perfetto::protos::pbzero::ChildProcessLauncherPriority> proto) { + proto->set_is_backgrounded(is_background()); + proto->set_has_pending_views(boost_for_pending_views); + +#if defined(OS_ANDROID) + using PriorityProto = perfetto::protos::pbzero::ChildProcessLauncherPriority; + switch (importance) { + case ChildProcessImportance::IMPORTANT: + proto->set_importance(PriorityProto::IMPORTANCE_IMPORTANT); + break; + case ChildProcessImportance::NORMAL: + proto->set_importance(PriorityProto::IMPORTANCE_NORMAL); + break; + case ChildProcessImportance::MODERATE: + proto->set_importance(PriorityProto::IMPORTANCE_MODERATE); + break; + } +#endif +} + #if defined(OS_ANDROID) bool ChildProcessLauncher::Client::CanUseWarmUpConnection() { return true;
diff --git a/content/browser/child_process_launcher.h b/content/browser/child_process_launcher.h index 7b299d9..7517fb03 100644 --- a/content/browser/child_process_launcher.h +++ b/content/browser/child_process_launcher.h
@@ -23,6 +23,7 @@ #include "content/public/browser/child_process_termination_info.h" #include "content/public/common/result_codes.h" #include "mojo/public/cpp/system/invitation.h" +#include "third_party/perfetto/include/perfetto/tracing/traced_proto.h" #if defined(OS_ANDROID) #include "content/public/browser/android/child_process_importance.h" @@ -32,6 +33,14 @@ class CommandLine; } +namespace perfetto { +namespace protos { +namespace pbzero { +class ChildProcessLauncherPriority; +} +} // namespace protos +} // namespace perfetto + namespace content { class SandboxedProcessLauncherDelegate; @@ -88,6 +97,10 @@ return !(*this == other); } + void WriteIntoTrace( + perfetto::TracedProto< + perfetto::protos::pbzero::ChildProcessLauncherPriority> proto); + // Prefer |is_background()| to inspecting these fields individually (to ensure // all logic uses the same notion of "backgrounded").
diff --git a/content/browser/conversions/conversion_host.cc b/content/browser/conversions/conversion_host.cc index ce6c32d..e288bd75 100644 --- a/content/browser/conversions/conversion_host.cc +++ b/content/browser/conversions/conversion_host.cc
@@ -261,7 +261,10 @@ StorableConversion storable_conversion( conversion_manager->GetConversionPolicy().GetSanitizedConversionData( conversion->conversion_data), - conversion_destination, conversion->reporting_origin); + conversion_destination, conversion->reporting_origin, + conversion_manager->GetConversionPolicy() + .GetSanitizedEventSourceTriggerData( + conversion->event_source_trigger_data)); if (conversion_page_metrics_) conversion_page_metrics_->OnConversion(storable_conversion);
diff --git a/content/browser/conversions/conversion_host.h b/content/browser/conversions/conversion_host.h index 3be185c..96baab314 100644 --- a/content/browser/conversions/conversion_host.h +++ b/content/browser/conversions/conversion_host.h
@@ -57,6 +57,8 @@ FRIEND_TEST_ALL_PREFIXES(ConversionHostTest, ValidConversion_NoBadMessage); FRIEND_TEST_ALL_PREFIXES(ConversionHostTest, Conversion_AssociatedWithConversionSite); + FRIEND_TEST_ALL_PREFIXES(ConversionHostTest, + Conversion_EventSourceTriggerDataPropagated); FRIEND_TEST_ALL_PREFIXES(ConversionHostTest, PerPageConversionMetrics); FRIEND_TEST_ALL_PREFIXES(ConversionHostTest, NoManager_NoPerPageConversionMetrics);
diff --git a/content/browser/conversions/conversion_policy.cc b/content/browser/conversions/conversion_policy.cc index 145247f3..2264883 100644 --- a/content/browser/conversions/conversion_policy.cc +++ b/content/browser/conversions/conversion_policy.cc
@@ -17,6 +17,10 @@ // conversion metadata is stripped to these lower bits. const int kMaxAllowedConversionValues = 8; +// Maximum number of allowed event source trigger data values. Higher entropy +// event source trigger data is stripped to these lower bits. +const int kMaxAllowedEventSourceTriggerDataValues = 2; + } // namespace uint64_t ConversionPolicy::NoiseProvider::GetNoisedConversionData( @@ -32,6 +36,20 @@ return static_cast<uint64_t>(base::RandInt(0, kMaxAllowedConversionValues)); } +uint64_t ConversionPolicy::NoiseProvider::GetNoisedEventSourceTriggerData( + uint64_t event_source_trigger_data) const { + // Return |event_source_trigger_data| without any noise 95% of the time. + if (base::RandDouble() > .05) + return event_source_trigger_data; + + // 5% of the time return a random number in the allowed range. Note that the + // value is noised 5% of the time, but only wrong 5 * + // (kMaxAllowedEventSourceTriggerDataValues - 1) / + // kMaxAllowedEventSourceTriggerDataValues percent of the time. + return static_cast<uint64_t>( + base::RandInt(0, kMaxAllowedEventSourceTriggerDataValues)); +} + // static std::unique_ptr<ConversionPolicy> ConversionPolicy::CreateForTesting( std::unique_ptr<NoiseProvider> noise_provider) { @@ -62,6 +80,21 @@ return conversion_data % kMaxAllowedConversionValues; } +uint64_t ConversionPolicy::GetSanitizedEventSourceTriggerData( + uint64_t event_source_trigger_data) const { + // Add noise to the conversion when the value is first sanitized from a + // conversion registration event. This noised data will be used for all + // associated impressions that convert. + if (noise_provider_) { + event_source_trigger_data = + noise_provider_->GetNoisedEventSourceTriggerData( + event_source_trigger_data); + } + + // Allow at most 1 bit of entropy in event source trigger data. + return event_source_trigger_data % kMaxAllowedEventSourceTriggerDataValues; +} + uint64_t ConversionPolicy::GetSanitizedImpressionData( uint64_t impression_data) const { // Impression data is allowed the full 64 bits.
diff --git a/content/browser/conversions/conversion_policy.h b/content/browser/conversions/conversion_policy.h index ae84fdae..dfc9a0e 100644 --- a/content/browser/conversions/conversion_policy.h +++ b/content/browser/conversions/conversion_policy.h
@@ -27,10 +27,16 @@ NoiseProvider() = default; virtual ~NoiseProvider() = default; - // Returns a noise value of |conversion_data|. By default, this reports + // Returns a noised value of |conversion_data|. By default, this reports // completely random data for 5% of conversions, and sends the real data for // 95%. Virtual for testing. virtual uint64_t GetNoisedConversionData(uint64_t conversion_data) const; + + // Returns a noised value of |event_source_trigger_data|. By default, this + // reports completely random data for 5% of conversions, and sends the real + // data for 95%. Virtual for testing. + virtual uint64_t GetNoisedEventSourceTriggerData( + uint64_t event_source_trigger_data) const; }; static std::unique_ptr<ConversionPolicy> CreateForTesting( @@ -47,6 +53,10 @@ // from the provided to data to at most 3 bits of information. virtual uint64_t GetSanitizedConversionData(uint64_t conversion_data) const; + // Gets the sanitized event source trigger data for a conversion. + virtual uint64_t GetSanitizedEventSourceTriggerData( + uint64_t event_source_trigger_data) const; + // Gets the sanitized impression data for an impression. virtual uint64_t GetSanitizedImpressionData(uint64_t impression_data) const;
diff --git a/content/browser/conversions/conversion_policy_unittest.cc b/content/browser/conversions/conversion_policy_unittest.cc index c35984a..d320124c 100644 --- a/content/browser/conversions/conversion_policy_unittest.cc +++ b/content/browser/conversions/conversion_policy_unittest.cc
@@ -21,6 +21,11 @@ uint64_t GetNoisedConversionData(uint64_t conversion_data) const override { return conversion_data; } + + uint64_t GetNoisedEventSourceTriggerData( + uint64_t event_source_trigger_data) const override { + return event_source_trigger_data; + } }; // Mock ConversionNoiseProvider that always noises values by +1. @@ -29,6 +34,11 @@ uint64_t GetNoisedConversionData(uint64_t conversion_data) const override { return conversion_data + 1; } + + uint64_t GetNoisedEventSourceTriggerData( + uint64_t event_source_trigger_data) const override { + return event_source_trigger_data + 1; + } }; } // namespace @@ -65,7 +75,7 @@ } } -TEST_F(ConversionPolicyTest, SantizizeConversionData_OutputHasNoise) { +TEST_F(ConversionPolicyTest, SanitizeConversionData_OutputHasNoise) { // The policy should include noise when sanitizing data. EXPECT_EQ(5LU, ConversionPolicy::CreateForTesting( std::make_unique<IncrementingNoiseProvider>()) @@ -82,6 +92,46 @@ } } +TEST_F(ConversionPolicyTest, + HighEntropyEventSourceTriggerData_StrippedToLowerBits) { + uint64_t event_source_trigger_data = 4LU; + + // The policy should strip the data to the lower 1 bit. + EXPECT_EQ( + 0LU, + ConversionPolicy::CreateForTesting(std::make_unique<EmptyNoiseProvider>()) + ->GetSanitizedEventSourceTriggerData(event_source_trigger_data)); +} + +TEST_F(ConversionPolicyTest, OneBitEventSourceTriggerData_Unchanged) { + std::unique_ptr<ConversionPolicy> policy = ConversionPolicy::CreateForTesting( + std::make_unique<EmptyNoiseProvider>()); + for (uint64_t event_source_trigger_data = 0; event_source_trigger_data < 2; + event_source_trigger_data++) { + EXPECT_EQ( + event_source_trigger_data, + policy->GetSanitizedEventSourceTriggerData(event_source_trigger_data)); + } +} + +TEST_F(ConversionPolicyTest, SanitizeEventSourceTriggerData_OutputHasNoise) { + // The policy should include noise when sanitizing data. + EXPECT_EQ(0LU, ConversionPolicy::CreateForTesting( + std::make_unique<IncrementingNoiseProvider>()) + ->GetSanitizedEventSourceTriggerData(1UL)); +} + +// This test will fail flakily if noise is used. +TEST_F(ConversionPolicyTest, DebugMode_EventSourceTriggerDataNotNoised) { + uint64_t event_source_trigger_data = 0UL; + for (int i = 0; i < 100; i++) { + EXPECT_EQ( + event_source_trigger_data, + ConversionPolicy(/*debug_mode=*/true) + .GetSanitizedEventSourceTriggerData(event_source_trigger_data)); + } +} + TEST_F(ConversionPolicyTest, NoExpiryForImpression_DefaultUsed) { base::Time impression_time = base::Time::Now(); EXPECT_EQ(impression_time + base::TimeDelta::FromDays(30),
diff --git a/content/browser/conversions/conversion_report.h b/content/browser/conversions/conversion_report.h index e634fc1..2a50451 100644 --- a/content/browser/conversions/conversion_report.h +++ b/content/browser/conversions/conversion_report.h
@@ -32,7 +32,8 @@ // Impression associated with this conversion report. const StorableImpression impression; - // Data provided at reporting time by the reporting origin. + // Data provided at reporting time by the reporting origin. Depending on the + // source type, this contains the associated data in the trigger redirect. uint64_t conversion_data; // The time the conversion occurred. @@ -48,6 +49,9 @@ // Id assigned by storage to uniquely identify a completed conversion. If // null, an ID has not been assigned yet. const absl::optional<int64_t> conversion_id; + + // When adding new members, the `ReportsEqual()` testing utility in + // `conversion_test_utils.h` should also be updated. }; // Only used for logging.
diff --git a/content/browser/conversions/conversion_storage_sql.cc b/content/browser/conversions/conversion_storage_sql.cc index 618c73d..8f0d24a 100644 --- a/content/browser/conversions/conversion_storage_sql.cc +++ b/content/browser/conversions/conversion_storage_sql.cc
@@ -211,20 +211,16 @@ base::Time current_time = clock_->Now(); - // TODO(apaseltiner): Support kEvent as well as kNavigation. - const StorableImpression::SourceType kSourceType = - StorableImpression::SourceType::kNavigation; - // Get all impressions that match this <reporting_origin, // conversion_destination> pair. Only get impressions that are active and not // past their expiry time. const char kGetMatchingImpressionsSql[] = "SELECT impression_id, impression_data, impression_origin, " "conversion_origin, impression_time, expiry_time, priority, " - "attributed_truthfully " + "attributed_truthfully, source_type " "FROM impressions " "WHERE conversion_destination = ? AND reporting_origin = ? " - "AND active = 1 AND expiry_time > ? AND source_type = ?" + "AND active = 1 AND expiry_time > ? " "ORDER BY impression_time DESC"; sql::Statement statement( @@ -232,7 +228,6 @@ statement.BindString(0, serialized_conversion_destination); statement.BindString(1, SerializeOrigin(reporting_origin)); statement.BindTime(2, current_time); - statement.BindInt(3, static_cast<int>(kSourceType)); std::vector<StorableImpression> impressions; @@ -259,10 +254,12 @@ StorableImpression::AttributionLogic attribution_logic = static_cast<StorableImpression::AttributionLogic>( statement.ColumnInt(7)); + StorableImpression::SourceType source_type = + static_cast<StorableImpression::SourceType>(statement.ColumnInt(8)); StorableImpression impression(impression_data, impression_origin, conversion_origin, reporting_origin, - impression_time, expiry_time, kSourceType, + impression_time, expiry_time, source_type, attribution_source_priority, impression_id); impressions.push_back(std::move(impression)); attribution_logics.insert_or_assign(impression_id, attribution_logic); @@ -275,7 +272,13 @@ const StorableImpression& impression_to_attribute = delegate_->GetImpressionToAttribute(impressions); - ConversionReport report(impression_to_attribute, conversion.conversion_data(), + const uint64_t conversion_data = + impression_to_attribute.source_type() == + StorableImpression::SourceType::kEvent + ? conversion.event_source_trigger_data() + : conversion.conversion_data(); + + ConversionReport report(impression_to_attribute, conversion_data, /*conversion_time=*/current_time, /*report_time=*/current_time, /*conversion_id=*/absl::nullopt); @@ -332,7 +335,9 @@ // provide the max number of conversions prior to this new conversion being // logged. int max_prior_conversions_before_inactive = - delegate_->GetMaxConversionsPerImpression(kSourceType) - 1; + delegate_->GetMaxConversionsPerImpression( + report.impression.source_type()) - + 1; // Update the attributed impression. impression_update_statement.BindInt(0, max_prior_conversions_before_inactive);
diff --git a/content/browser/conversions/conversion_storage_sql_unittest.cc b/content/browser/conversions/conversion_storage_sql_unittest.cc index d60a7455..b2d0dea 100644 --- a/content/browser/conversions/conversion_storage_sql_unittest.cc +++ b/content/browser/conversions/conversion_storage_sql_unittest.cc
@@ -352,7 +352,8 @@ clock()->Advance(base::TimeDelta::FromDays(1)); StorableConversion conversion(1, net::SchemefulSite(conversion_origin), - reporting_origin); + reporting_origin, + /*event_source_trigger_data=*/0); EXPECT_TRUE(storage()->MaybeCreateAndStoreConversionReport(conversion)); clock()->Advance(base::TimeDelta::FromDays(1)); @@ -396,7 +397,8 @@ clock()->Advance(base::TimeDelta::FromDays(1)); StorableConversion conversion(1, net::SchemefulSite(conversion_origin), - reporting_origin); + reporting_origin, + /*event_source_trigger_data=*/0); EXPECT_TRUE(storage()->MaybeCreateAndStoreConversionReport(conversion)); clock()->Advance(base::TimeDelta::FromDays(1));
diff --git a/content/browser/conversions/conversion_storage_unittest.cc b/content/browser/conversions/conversion_storage_unittest.cc index df7a551..0655f3a7 100644 --- a/content/browser/conversions/conversion_storage_unittest.cc +++ b/content/browser/conversions/conversion_storage_unittest.cc
@@ -155,10 +155,27 @@ .Build(); storage()->StoreImpression(impression); StorableConversion conversion(1, net::SchemefulSite(GURL("https://a.test")), - impression.reporting_origin()); + impression.reporting_origin(), + /*event_source_trigger_data=*/0); EXPECT_TRUE(storage()->MaybeCreateAndStoreConversionReport(conversion)); } +TEST_F(ConversionStorageTest, EventSourceImpressionsForConversion_Converts) { + storage()->StoreImpression( + ImpressionBuilder(clock()->Now()) + .SetSourceType(StorableImpression::SourceType::kEvent) + .Build()); + EXPECT_TRUE(storage()->MaybeCreateAndStoreConversionReport( + DefaultConversion(/*event_source_trigger_data=*/456))); + + clock()->Advance(base::TimeDelta::FromMilliseconds(kReportTime)); + + std::vector<ConversionReport> actual_reports = + storage()->GetConversionsToReport(clock()->Now()); + EXPECT_EQ(1u, actual_reports.size()); + EXPECT_EQ(456u, actual_reports[0].conversion_data); +} + TEST_F(ConversionStorageTest, ImpressionExpired_NoConversionsStored) { storage()->StoreImpression( ImpressionBuilder(clock()->Now()) @@ -602,14 +619,16 @@ for (int i = 0; i < 5; i++) { auto origin = url::Origin::Create(GURL(base::StringPrintf("https://%d.com/", i))); - StorableConversion conversion(1, net::SchemefulSite(origin), origin); + StorableConversion conversion(1, net::SchemefulSite(origin), origin, + /*event_source_trigger_data=*/0); EXPECT_TRUE(storage()->MaybeCreateAndStoreConversionReport(conversion)); } clock()->Advance(base::TimeDelta::FromDays(1)); for (int i = 5; i < 10; i++) { auto origin = url::Origin::Create(GURL(base::StringPrintf("https://%d.com/", i))); - StorableConversion conversion(1, net::SchemefulSite(origin), origin); + StorableConversion conversion(1, net::SchemefulSite(origin), origin, + /*event_source_trigger_data=*/0); EXPECT_TRUE(storage()->MaybeCreateAndStoreConversionReport(conversion)); }
diff --git a/content/browser/conversions/conversion_test_utils.cc b/content/browser/conversions/conversion_test_utils.cc index 720f58f..88eb2f12 100644 --- a/content/browser/conversions/conversion_test_utils.cc +++ b/content/browser/conversions/conversion_test_utils.cc
@@ -271,12 +271,13 @@ source_type_, priority_, impression_id_); } -StorableConversion DefaultConversion() { +StorableConversion DefaultConversion(uint64_t event_source_trigger_data) { StorableConversion conversion( /*conversion_data=*/111, /*conversion_destination=*/ net::SchemefulSite(GURL(kDefaultConversionDestination)), - /*reporting_origin=*/url::Origin::Create(GURL(kDefaultReportOrigin))); + /*reporting_origin=*/url::Origin::Create(GURL(kDefaultReportOrigin)), + event_source_trigger_data); return conversion; } @@ -289,7 +290,7 @@ impression.impression_data(), impression.impression_origin(), impression.conversion_origin(), impression.reporting_origin(), impression.impression_time(), impression.expiry_time(), - impression.priority()); + impression.source_type(), impression.priority()); }; if (tie(expected) != tie(actual)) { @@ -311,8 +312,10 @@ conversion.impression.reporting_origin(), conversion.impression.impression_time(), conversion.impression.expiry_time(), + conversion.impression.source_type(), conversion.impression.priority(), - conversion.conversion_data, conversion.report_time); + conversion.conversion_data, conversion.report_time, + conversion.extra_delay); }; if (expected.size() != actual.size())
diff --git a/content/browser/conversions/conversion_test_utils.h b/content/browser/conversions/conversion_test_utils.h index 7f48bca..e7ebb986 100644 --- a/content/browser/conversions/conversion_test_utils.h +++ b/content/browser/conversions/conversion_test_utils.h
@@ -5,8 +5,9 @@ #ifndef CONTENT_BROWSER_CONVERSIONS_CONVERSION_TEST_UTILS_H_ #define CONTENT_BROWSER_CONVERSIONS_CONVERSION_TEST_UTILS_H_ +#include <stdint.h> + #include <list> -#include <string> #include <vector> #include "base/containers/circular_deque.h" @@ -250,7 +251,7 @@ // Returns a StorableConversion with default data which matches the default // impressions created by ImpressionBuilder. -StorableConversion DefaultConversion(); +StorableConversion DefaultConversion(uint64_t event_source_trigger_data = 0); testing::AssertionResult ImpressionsEqual(const StorableImpression& expected, const StorableImpression& actual);
diff --git a/content/browser/conversions/conversions_browsertest.cc b/content/browser/conversions/conversions_browsertest.cc index c673348..33d0530 100644 --- a/content/browser/conversions/conversions_browsertest.cc +++ b/content/browser/conversions/conversions_browsertest.cc
@@ -575,4 +575,101 @@ SetBrowserClientForTesting(old_browser_client); } +IN_PROC_BROWSER_TEST_F(ConversionsBrowserTest, + EventSourceImpressionConversion_ReportSent) { + // Expected reports must be registered before the server starts. + // 123 in the `registerConversionForOrigin` call below is sanitized to 1 in + // the report's `trigger_data`. + ExpectedReportWaiter expected_report( + GURL("https://a.test/.well-known/attribution-reporting/" + "report-attribution"), + /*body=*/R"({"source_event_id":"7","trigger_data":"1"})", https_server()); + ASSERT_TRUE(https_server()->Start()); + + GURL impression_url = https_server()->GetURL( + "a.test", "/conversions/page_with_impression_creator.html"); + EXPECT_TRUE(NavigateToURL(web_contents(), impression_url)); + + // Create an anchor tag with impression attributes. + GURL conversion_url = https_server()->GetURL( + "b.test", "/conversions/page_with_conversion_redirect.html"); + EXPECT_TRUE( + ExecJs(web_contents(), + JsReplace(R"( + createImpressionTagWithRegisterAttributionSource("link" /* id */, + $1 /* url */, + "7" /* impression data */, + $2 /* conversion_destination */);)", + conversion_url, url::Origin::Create(conversion_url)))); + + EXPECT_TRUE(NavigateToURL(web_contents(), conversion_url)); + + // Register a conversion with the original page as the reporting origin. + EXPECT_TRUE( + ExecJs(web_contents(), + JsReplace(R"(registerConversionForOrigin(0 /* conversion_data */, + $1, + 123 /* event_source_trigger_data */);)", + url::Origin::Create(impression_url)))); + + expected_report.WaitForReport(); +} + +IN_PROC_BROWSER_TEST_F(ConversionsBrowserTest, + EventSourceImpressionTwoConversions_OneReportSent) { + // Expected reports must be registered before the server starts. + // 123 in the `registerConversionForOrigin` call below is sanitized to 1 in + // the report's `trigger_data`. + ExpectedReportWaiter expected_report( + GURL("https://a.test/.well-known/attribution-reporting/" + "report-attribution"), + /*body=*/R"({"source_event_id":"7","trigger_data":"1"})", https_server()); + ExpectedReportWaiter expected_report_not_sent( + GURL("https://a.test/.well-known/attribution-reporting/" + "report-attribution"), + /*body=*/"", https_server()); + ASSERT_TRUE(https_server()->Start()); + + GURL impression_url = https_server()->GetURL( + "a.test", "/conversions/page_with_impression_creator.html"); + EXPECT_TRUE(NavigateToURL(web_contents(), impression_url)); + + // Create an anchor tag with impression attributes. + GURL conversion_url = https_server()->GetURL( + "b.test", "/conversions/page_with_conversion_redirect.html"); + EXPECT_TRUE( + ExecJs(web_contents(), + JsReplace(R"( + createImpressionTagWithRegisterAttributionSource("link" /* id */, + $1 /* url */, + "7" /* impression data */, + $2 /* conversion_destination */);)", + conversion_url, url::Origin::Create(conversion_url)))); + + EXPECT_TRUE(NavigateToURL(web_contents(), conversion_url)); + + // Register two conversions with the original page as the reporting origin. + for (int i = 0; i < 2; i++) { + EXPECT_TRUE( + ExecJs(web_contents(), + JsReplace(R"(registerConversionForOrigin(0 /* conversion_data */, + $1, + 123 /* event_source_trigger_data */);)", + url::Origin::Create(impression_url)))); + } + + expected_report.WaitForReport(); + + // Since we want to verify that a report _isn't_ sent, we can't really wait on + // any event here. The best thing we can do is just impose a short delay and + // verify the browser didn't send anything. Worst case, this should start + // flakily failing if the logic breaks. + base::RunLoop run_loop; + base::SequencedTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, run_loop.QuitClosure(), + base::TimeDelta::FromMilliseconds(100)); + run_loop.Run(); + EXPECT_FALSE(expected_report_not_sent.HasRequest()); +} + } // namespace content
diff --git a/content/browser/conversions/storable_conversion.cc b/content/browser/conversions/storable_conversion.cc index f8e9bd82..a1c67c2 100644 --- a/content/browser/conversions/storable_conversion.cc +++ b/content/browser/conversions/storable_conversion.cc
@@ -13,10 +13,12 @@ StorableConversion::StorableConversion( uint64_t conversion_data, net::SchemefulSite conversion_destination, - url::Origin reporting_origin) + url::Origin reporting_origin, + uint64_t event_source_trigger_data) : conversion_data_(conversion_data), conversion_destination_(std::move(conversion_destination)), - reporting_origin_(std::move(reporting_origin)) { + reporting_origin_(std::move(reporting_origin)), + event_source_trigger_data_(event_source_trigger_data) { DCHECK(!reporting_origin_.opaque()); DCHECK(!conversion_destination_.opaque()); }
diff --git a/content/browser/conversions/storable_conversion.h b/content/browser/conversions/storable_conversion.h index 082d3ad..b2e2314 100644 --- a/content/browser/conversions/storable_conversion.h +++ b/content/browser/conversions/storable_conversion.h
@@ -23,7 +23,8 @@ // navigation origin known by the browser process. StorableConversion(uint64_t conversion_data, net::SchemefulSite conversion_destination, - url::Origin reporting_origin); + url::Origin reporting_origin, + uint64_t event_source_trigger_data); StorableConversion(const StorableConversion& other); StorableConversion& operator=(const StorableConversion& other) = delete; ~StorableConversion(); @@ -36,6 +37,10 @@ const url::Origin& reporting_origin() const { return reporting_origin_; } + uint64_t event_source_trigger_data() const { + return event_source_trigger_data_; + } + private: // Conversion data associated with conversion registration event. uint64_t conversion_data_; @@ -46,6 +51,10 @@ // Origin of the conversion redirect url, and the origin that will receive any // reports. url::Origin reporting_origin_; + + // Event source trigger data specified in conversion redirect. Defaults to 0 + // if not provided. + uint64_t event_source_trigger_data_; }; } // namespace content
diff --git a/content/browser/conversions/storable_impression.h b/content/browser/conversions/storable_impression.h index e10881c8..19a4063 100644 --- a/content/browser/conversions/storable_impression.h +++ b/content/browser/conversions/storable_impression.h
@@ -93,8 +93,8 @@ // If null, an ID has not been assigned yet. absl::optional<int64_t> impression_id_; - // When adding new members, the ImpressionsEqual() testing utility in - // conversion_test_utils.h should also be updated. + // When adding new members, the `ImpressionsEqual()` testing utility in + // `conversion_test_utils.h` should also be updated. }; } // namespace content
diff --git a/content/browser/download/download_browsertest.cc b/content/browser/download/download_browsertest.cc index b54c252..2025b14 100644 --- a/content/browser/download/download_browsertest.cc +++ b/content/browser/download/download_browsertest.cc
@@ -67,6 +67,7 @@ #include "content/test/content_browser_test_utils_internal.h" #include "content/test/fake_network_url_loader_factory.h" #include "content/test/test_content_browser_client.h" +#include "net/base/features.h" #include "net/base/filename_util.h" #include "net/dns/mock_host_resolver.h" #include "net/test/embedded_test_server/controllable_http_response.h" @@ -3989,7 +3990,25 @@ download->GetTargetFilePath().BaseName().value().c_str()); } -IN_PROC_BROWSER_TEST_F(DownloadContentTest, DownloadAttributeSameSiteCookie) { +class DownloadContentSameSiteCookieTest + : public DownloadContentTest, + public ::testing::WithParamInterface<bool> { + public: + DownloadContentSameSiteCookieTest() { + if (DoesCookieSameSiteConsiderRedirectChain()) { + inner_feature_list_.InitAndEnableFeature( + net::features::kCookieSameSiteConsidersRedirectChain); + } + } + + bool DoesCookieSameSiteConsiderRedirectChain() { return GetParam(); } + + private: + base::test::ScopedFeatureList inner_feature_list_; +}; + +IN_PROC_BROWSER_TEST_P(DownloadContentSameSiteCookieTest, + DownloadAttributeSameSiteCookie) { base::ScopedAllowBlockingForTesting allow_blocking; net::EmbeddedTestServer test_server; ASSERT_TRUE(test_server.InitializeAndListen()); @@ -4048,7 +4067,8 @@ EXPECT_STREQ("B=C", file_contents.c_str()); // OriginOne redirects through OriginTwo. Because the redirect chain contains - // a cross-site redirect, SameSite=Strict cookies are not sent. + // a cross-site redirect, SameSite=Strict cookies are not sent (if redirect + // chains are considered). // // Initiator origin: kOriginOne // Redirect chain contains: kOriginTwo @@ -4063,9 +4083,17 @@ ASSERT_TRUE( base::ReadFileToString(download->GetTargetFilePath(), &file_contents)); - EXPECT_STREQ("B=C", file_contents.c_str()); + if (DoesCookieSameSiteConsiderRedirectChain()) { + EXPECT_STREQ("B=C", file_contents.c_str()); + } else { + EXPECT_STREQ("A=B; B=C", file_contents.c_str()); + } } +INSTANTIATE_TEST_SUITE_P(/* no label */, + DownloadContentSameSiteCookieTest, + ::testing::Bool()); + // The file empty.bin is served with a MIME type of application/octet-stream. // The content body is empty. Make sure this case is handled properly and we // don't regress on http://crbug.com/320394.
diff --git a/content/browser/media/media_internals_audio_focus_helper.h b/content/browser/media/media_internals_audio_focus_helper.h index 2863eda..c6dc9fd 100644 --- a/content/browser/media/media_internals_audio_focus_helper.h +++ b/content/browser/media/media_internals_audio_focus_helper.h
@@ -31,6 +31,7 @@ media_session::mojom::AudioFocusRequestStatePtr session) override; void OnFocusLost( media_session::mojom::AudioFocusRequestStatePtr session) override; + void OnRequestIdReleased(const base::UnguessableToken&) override {} // Sets whether we should listen to audio focus events. void SetEnabled(bool enabled);
diff --git a/content/browser/media/session/audio_focus_delegate.h b/content/browser/media/session/audio_focus_delegate.h index a4501db..6890c4d 100644 --- a/content/browser/media/session/audio_focus_delegate.h +++ b/content/browser/media/session/audio_focus_delegate.h
@@ -46,6 +46,9 @@ // Retrieves the current request ID for the associated |MediaSession|. virtual const base::UnguessableToken& request_id() const = 0; + + // Inform the AudioFocusManager that this request ID will no longer be used. + virtual void ReleaseRequestId() = 0; }; } // namespace content
diff --git a/content/browser/media/session/audio_focus_delegate_android.h b/content/browser/media/session/audio_focus_delegate_android.h index de3174b..8fe9f26 100644 --- a/content/browser/media/session/audio_focus_delegate_android.h +++ b/content/browser/media/session/audio_focus_delegate_android.h
@@ -33,6 +33,7 @@ absl::optional<media_session::mojom::AudioFocusType> GetCurrentFocusType() const override; const base::UnguessableToken& request_id() const override; + void ReleaseRequestId() override {} // Called when the Android system requests the MediaSession to be suspended. // Called by Java through JNI.
diff --git a/content/browser/media/session/audio_focus_delegate_default.cc b/content/browser/media/session/audio_focus_delegate_default.cc index b7dc5d2..4729b013 100644 --- a/content/browser/media/session/audio_focus_delegate_default.cc +++ b/content/browser/media/session/audio_focus_delegate_default.cc
@@ -54,6 +54,7 @@ const base::UnguessableToken& request_id() const override { return request_id_; } + void ReleaseRequestId() override; private: // Finishes an async audio focus request. @@ -158,6 +159,19 @@ session_info_ = session_info.Clone(); } +void AudioFocusDelegateDefault::ReleaseRequestId() { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + if (!base::FeatureList::IsEnabled( + media_session::features::kMediaSessionService)) { + return; + } + + EnsureServiceConnection(); + + audio_focus_->RequestIdReleased(request_id_); +} + void AudioFocusDelegateDefault::FinishAudioFocusRequest(AudioFocusType type, bool success) { DCHECK_CURRENTLY_ON(BrowserThread::UI);
diff --git a/content/browser/media/session/media_session_controller_unittest.cc b/content/browser/media/session/media_session_controller_unittest.cc index 76131e3..3c9185d0 100644 --- a/content/browser/media/session/media_session_controller_unittest.cc +++ b/content/browser/media/session/media_session_controller_unittest.cc
@@ -43,6 +43,7 @@ const base::UnguessableToken& request_id() const override { return base::UnguessableToken::Null(); } + void ReleaseRequestId() override {} private: absl::optional<media_session::mojom::AudioFocusType> audio_focus_type_;
diff --git a/content/browser/media/session/media_session_impl.cc b/content/browser/media/session/media_session_impl.cc index a7756939..f51d3b4 100644 --- a/content/browser/media/session/media_session_impl.cc +++ b/content/browser/media/session/media_session_impl.cc
@@ -264,6 +264,8 @@ #endif void MediaSessionImpl::WebContentsDestroyed() { + delegate_->ReleaseRequestId(); + // This should only work for tests. In production, all the players should have // already been removed before WebContents is destroyed.
diff --git a/content/browser/media/session/media_session_impl_browsertest.cc b/content/browser/media/session/media_session_impl_browsertest.cc index a8e154f..cab6248 100644 --- a/content/browser/media/session/media_session_impl_browsertest.cc +++ b/content/browser/media/session/media_session_impl_browsertest.cc
@@ -91,6 +91,8 @@ MOCK_CONST_METHOD0(request_id, const base::UnguessableToken&()); + MOCK_METHOD(void, ReleaseRequestId, (), (override)); + void ResolveRequest(bool result) { if (!async_mode_) return;
diff --git a/content/browser/media/session/media_session_impl_unittest.cc b/content/browser/media/session/media_session_impl_unittest.cc index a529333f..dd33955c 100644 --- a/content/browser/media/session/media_session_impl_unittest.cc +++ b/content/browser/media/session/media_session_impl_unittest.cc
@@ -62,6 +62,8 @@ MOCK_CONST_METHOD0(request_id, const base::UnguessableToken&()); + MOCK_METHOD(void, ReleaseRequestId, (), (override)); + MediaSessionInfo::SessionState GetState() const { DCHECK(!session_info_.is_null()); return session_info_->state;
diff --git a/content/browser/net/http_cookie_browsertest.cc b/content/browser/net/http_cookie_browsertest.cc index ee7dd8e..f2dc5a6 100644 --- a/content/browser/net/http_cookie_browsertest.cc +++ b/content/browser/net/http_cookie_browsertest.cc
@@ -5,6 +5,7 @@ #include "base/strings/strcat.h" #include "base/strings/string_split.h" #include "base/strings/stringprintf.h" +#include "base/test/scoped_feature_list.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/web_contents.h" @@ -34,10 +35,15 @@ // See also (tests for cookie access via JavaScript): // //content/browser/renderer_host/cookie_browsertest.cc -class HttpCookieBrowserTest : public ContentBrowserTest { +class HttpCookieBrowserTest : public ContentBrowserTest, + public ::testing::WithParamInterface<bool> { public: - HttpCookieBrowserTest() - : https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {} + HttpCookieBrowserTest() : https_server_(net::EmbeddedTestServer::TYPE_HTTPS) { + if (DoesSameSiteConsiderRedirectChain()) { + feature_list_.InitAndEnableFeature( + net::features::kCookieSameSiteConsidersRedirectChain); + } + } ~HttpCookieBrowserTest() override = default; @@ -57,6 +63,8 @@ kHostC)); } + bool DoesSameSiteConsiderRedirectChain() { return GetParam(); } + const char* kHostA = "a.test"; const char* kHostB = "b.test"; const char* kHostC = "c.test"; @@ -217,9 +225,10 @@ private: net::test_server::EmbeddedTestServer https_server_; + base::test::ScopedFeatureList feature_list_; }; -IN_PROC_BROWSER_TEST_F(HttpCookieBrowserTest, SendSameSiteCookies) { +IN_PROC_BROWSER_TEST_P(HttpCookieBrowserTest, SendSameSiteCookies) { SetSameSiteCookies(kHostA); SetSameSiteCookies(kHostB); @@ -267,7 +276,7 @@ net::CookieStringIs(UnorderedElementsAre(Key(kSameSiteNoneCookieName)))); } -IN_PROC_BROWSER_TEST_F(HttpCookieBrowserTest, SendSameSiteCookies_Redirect) { +IN_PROC_BROWSER_TEST_P(HttpCookieBrowserTest, SendSameSiteCookies_Redirect) { SetSameSiteCookies(kHostA); WebContentsImpl* web_contents = @@ -285,29 +294,56 @@ Key(kSameSiteStrictCookieName), Key(kSameSiteLaxCookieName), Key(kSameSiteNoneCookieName), Key(kSameSiteUnspecifiedCookieName)))); - // Main frame cross-site redirect (B->A) sends Lax but not Strict SameSite - // cookies... - ASSERT_TRUE(NavigateToURL( - web_contents, - RedirectUrl(https_server(), kHostB, - EchoCookiesUrl(https_server(), kHostA)), - /*expected_commit_url=*/EchoCookiesUrl(https_server(), kHostA))); - EXPECT_THAT(ExtractFrameContent(web_contents->GetMainFrame()), - net::CookieStringIs(UnorderedElementsAre( - Key(kSameSiteLaxCookieName), Key(kSameSiteNoneCookieName), - Key(kSameSiteUnspecifiedCookieName)))); + if (DoesSameSiteConsiderRedirectChain()) { + // Main frame cross-site redirect (B->A) sends Lax but not Strict SameSite + // cookies... + ASSERT_TRUE(NavigateToURL( + web_contents, + RedirectUrl(https_server(), kHostB, + EchoCookiesUrl(https_server(), kHostA)), + /*expected_commit_url=*/EchoCookiesUrl(https_server(), kHostA))); + EXPECT_THAT(ExtractFrameContent(web_contents->GetMainFrame()), + net::CookieStringIs(UnorderedElementsAre( + Key(kSameSiteLaxCookieName), Key(kSameSiteNoneCookieName), + Key(kSameSiteUnspecifiedCookieName)))); - // ... even if the first URL is same-site. (A->B->A) - ASSERT_TRUE(NavigateToURL( - web_contents, - RedirectUrl(https_server(), kHostA, - RedirectUrl(https_server(), kHostB, - EchoCookiesUrl(https_server(), kHostA))), - /*expected_commit_url=*/EchoCookiesUrl(https_server(), kHostA))); - EXPECT_THAT(ExtractFrameContent(web_contents->GetMainFrame()), - net::CookieStringIs(UnorderedElementsAre( - Key(kSameSiteLaxCookieName), Key(kSameSiteNoneCookieName), - Key(kSameSiteUnspecifiedCookieName)))); + // ... even if the first URL is same-site. (A->B->A) + ASSERT_TRUE(NavigateToURL( + web_contents, + RedirectUrl(https_server(), kHostA, + RedirectUrl(https_server(), kHostB, + EchoCookiesUrl(https_server(), kHostA))), + /*expected_commit_url=*/EchoCookiesUrl(https_server(), kHostA))); + EXPECT_THAT(ExtractFrameContent(web_contents->GetMainFrame()), + net::CookieStringIs(UnorderedElementsAre( + Key(kSameSiteLaxCookieName), Key(kSameSiteNoneCookieName), + Key(kSameSiteUnspecifiedCookieName)))); + } else { + // If redirect chains are not considered, then cross-site redirects do not + // make the request cross-site. + ASSERT_TRUE(NavigateToURL( + web_contents, + RedirectUrl(https_server(), kHostB, + EchoCookiesUrl(https_server(), kHostA)), + /*expected_commit_url=*/EchoCookiesUrl(https_server(), kHostA))); + EXPECT_THAT(ExtractFrameContent(web_contents->GetMainFrame()), + net::CookieStringIs(UnorderedElementsAre( + Key(kSameSiteStrictCookieName), Key(kSameSiteLaxCookieName), + Key(kSameSiteNoneCookieName), + Key(kSameSiteUnspecifiedCookieName)))); + + ASSERT_TRUE(NavigateToURL( + web_contents, + RedirectUrl(https_server(), kHostA, + RedirectUrl(https_server(), kHostB, + EchoCookiesUrl(https_server(), kHostA))), + /*expected_commit_url=*/EchoCookiesUrl(https_server(), kHostA))); + EXPECT_THAT(ExtractFrameContent(web_contents->GetMainFrame()), + net::CookieStringIs(UnorderedElementsAre( + Key(kSameSiteStrictCookieName), Key(kSameSiteLaxCookieName), + Key(kSameSiteNoneCookieName), + Key(kSameSiteUnspecifiedCookieName)))); + } // A same-site redirected iframe (A->A embedded in A) sends all SameSite // cookies. @@ -320,26 +356,51 @@ Key(kSameSiteStrictCookieName), Key(kSameSiteLaxCookieName), Key(kSameSiteNoneCookieName), Key(kSameSiteUnspecifiedCookieName)))); - // A cross-site redirected iframe in a same-site context (B->A embedded in A) - // does not send SameSite cookies... - EXPECT_THAT( - ArrangeFramesAndGetContentFromLeaf( - "a.test(%s)", {0}, - RedirectUrl(https_server(), kHostB, - EchoCookiesUrl(https_server(), kHostA))), - net::CookieStringIs(UnorderedElementsAre(Key(kSameSiteNoneCookieName)))); + if (DoesSameSiteConsiderRedirectChain()) { + // A cross-site redirected iframe in a same-site context (B->A embedded in + // A) does not send SameSite cookies... + EXPECT_THAT(ArrangeFramesAndGetContentFromLeaf( + "a.test(%s)", {0}, + RedirectUrl(https_server(), kHostB, + EchoCookiesUrl(https_server(), kHostA))), + net::CookieStringIs( + UnorderedElementsAre(Key(kSameSiteNoneCookieName)))); - // ... even if the first URL is same-site. (A->B->A embedded in A) - EXPECT_THAT( - ArrangeFramesAndGetContentFromLeaf( - "a.test(%s)", {0}, - RedirectUrl(https_server(), kHostA, - RedirectUrl(https_server(), kHostB, - EchoCookiesUrl(https_server(), kHostA)))), - net::CookieStringIs(UnorderedElementsAre(Key(kSameSiteNoneCookieName)))); + // ... even if the first URL is same-site. (A->B->A embedded in A) + EXPECT_THAT( + ArrangeFramesAndGetContentFromLeaf( + "a.test(%s)", {0}, + RedirectUrl(https_server(), kHostA, + RedirectUrl(https_server(), kHostB, + EchoCookiesUrl(https_server(), kHostA)))), + net::CookieStringIs( + UnorderedElementsAre(Key(kSameSiteNoneCookieName)))); + } else { + // If redirect chains are not considered, then cross-site redirects do not + // make the request cross-site. + EXPECT_THAT(ArrangeFramesAndGetContentFromLeaf( + "a.test(%s)", {0}, + RedirectUrl(https_server(), kHostB, + EchoCookiesUrl(https_server(), kHostA))), + net::CookieStringIs(UnorderedElementsAre( + Key(kSameSiteStrictCookieName), Key(kSameSiteLaxCookieName), + Key(kSameSiteNoneCookieName), + Key(kSameSiteUnspecifiedCookieName)))); + + EXPECT_THAT( + ArrangeFramesAndGetContentFromLeaf( + "a.test(%s)", {0}, + RedirectUrl(https_server(), kHostA, + RedirectUrl(https_server(), kHostB, + EchoCookiesUrl(https_server(), kHostA)))), + net::CookieStringIs(UnorderedElementsAre( + Key(kSameSiteStrictCookieName), Key(kSameSiteLaxCookieName), + Key(kSameSiteNoneCookieName), + Key(kSameSiteUnspecifiedCookieName)))); + } } -IN_PROC_BROWSER_TEST_F(HttpCookieBrowserTest, SetSameSiteCookies) { +IN_PROC_BROWSER_TEST_P(HttpCookieBrowserTest, SetSameSiteCookies) { WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(shell()->web_contents()); @@ -373,7 +434,7 @@ ASSERT_EQ(1U, ClearCookies()); } -IN_PROC_BROWSER_TEST_F(HttpCookieBrowserTest, SetSameSiteCookies_Redirect) { +IN_PROC_BROWSER_TEST_P(HttpCookieBrowserTest, SetSameSiteCookies_Redirect) { WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(shell()->web_contents()); @@ -420,18 +481,33 @@ net::MatchesCookieWithName(kSameSiteUnspecifiedCookieName))); ASSERT_EQ(4U, ClearCookies()); - // A cross-site redirected iframe only sets SameSite=None cookies. - EXPECT_THAT(ArrangeFramesAndGetCanonicalCookiesForLeaf( - "a.test(%s)", - RedirectUrl(https_server(), kHostB, - SetSameSiteCookiesUrl(https_server(), kHostA)), - https_server()->GetURL(kHostA, "/")), - UnorderedElementsAre( - net::MatchesCookieWithName(kSameSiteNoneCookieName))); - ASSERT_EQ(1U, ClearCookies()); + if (DoesSameSiteConsiderRedirectChain()) { + // A cross-site redirected iframe only sets SameSite=None cookies. + EXPECT_THAT(ArrangeFramesAndGetCanonicalCookiesForLeaf( + "a.test(%s)", + RedirectUrl(https_server(), kHostB, + SetSameSiteCookiesUrl(https_server(), kHostA)), + https_server()->GetURL(kHostA, "/")), + UnorderedElementsAre( + net::MatchesCookieWithName(kSameSiteNoneCookieName))); + ASSERT_EQ(1U, ClearCookies()); + } else { + EXPECT_THAT( + ArrangeFramesAndGetCanonicalCookiesForLeaf( + "a.test(%s)", + RedirectUrl(https_server(), kHostB, + SetSameSiteCookiesUrl(https_server(), kHostA)), + https_server()->GetURL(kHostA, "/")), + UnorderedElementsAre( + net::MatchesCookieWithName(kSameSiteStrictCookieName), + net::MatchesCookieWithName(kSameSiteLaxCookieName), + net::MatchesCookieWithName(kSameSiteNoneCookieName), + net::MatchesCookieWithName(kSameSiteUnspecifiedCookieName))); + ASSERT_EQ(4U, ClearCookies()); + } } -IN_PROC_BROWSER_TEST_F(HttpCookieBrowserTest, SendSamePartyCookies) { +IN_PROC_BROWSER_TEST_P(HttpCookieBrowserTest, SendSamePartyCookies) { SetSamePartyCookies(kHostA); SetSamePartyCookies(kHostD); @@ -515,7 +591,7 @@ Key(kSamePartyUnspecifiedCookieName)))); } -IN_PROC_BROWSER_TEST_F(HttpCookieBrowserTest, SetSamePartyCookies) { +IN_PROC_BROWSER_TEST_P(HttpCookieBrowserTest, SetSamePartyCookies) { WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(shell()->web_contents()); @@ -606,5 +682,9 @@ ASSERT_EQ(3U, ClearCookies()); } +INSTANTIATE_TEST_SUITE_P(/* no label */, + HttpCookieBrowserTest, + ::testing::Bool()); + } // namespace } // namespace content
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc index 96764279c..f90add2 100644 --- a/content/browser/renderer_host/render_frame_host_impl.cc +++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -3358,6 +3358,14 @@ if (did_create_new_document) DidCommitNewDocument(params, navigation_request); + // Set up reporting endpoints for this document. + DCHECK(frame_token_.value()); + if (!reporting_endpoints_.empty()) { + GetStoragePartition()->GetNetworkContext()->SetDocumentReportingEndpoints( + params.origin, isolation_info_.network_isolation_key(), + reporting_endpoints_); + } + // When the frame hosts a different document, its state must be replicated // via its proxies to the other processes where it appears as remote. // @@ -5246,7 +5254,7 @@ if (!in_back_forward_cache) { TRACE_EVENT0("navigation", "BackForwardCache_EvictAfterDocumentRestored"); // TODO(carlscab): We should no longer get into this branch thanks to - // https://crrev.com/c/2352815. Lets keep this old code for now just in case + // https://crrev.com/c/2563674. Lets keep this old code for now just in case // and replace with a CHECK once we are confident that is the case. base::debug::DumpWithoutCrashing(); BackForwardCacheMetrics::RecordEvictedAfterDocumentRestored( @@ -9791,6 +9799,16 @@ cross_origin_embedder_policy_ = navigation_request->cross_origin_embedder_policy(); + reporting_endpoints_.clear(); + DCHECK(navigation_request); + + if (navigation_request->response() && + navigation_request->response()->parsed_headers && + navigation_request->response()->parsed_headers->reporting_endpoints) { + reporting_endpoints_ = + *(navigation_request->response()->parsed_headers->reporting_endpoints); + } + // We move the PolicyContainerHost of |navigation_request| into the // RenderFrameHost unless this is the initial, "fake" navigation to // about:blank (because otherwise we would overwrite the PolicyContainerHost
diff --git a/content/browser/renderer_host/render_frame_host_impl.h b/content/browser/renderer_host/render_frame_host_impl.h index c00698b..59cd84d 100644 --- a/content/browser/renderer_host/render_frame_host_impl.h +++ b/content/browser/renderer_host/render_frame_host_impl.h
@@ -3718,6 +3718,14 @@ mojo::UniqueReceiverSet<blink::mojom::CodeCacheHost> code_cache_host_receivers_; + // Holds the mapping of names to URLs of reporting endpoints for the current + // document, as parsed from the Reporting-Endpoints response header. This data + // comes directly from the structured header parser, and does not necessarily + // represent a valid reporting configuration. This is passed to the network + // service to set up the actual endpoint configuration once the document load + // commits. + base::flat_map<std::string, std::string> reporting_endpoints_; + // NOTE: This must be the last member. base::WeakPtrFactory<RenderFrameHostImpl> weak_ptr_factory_{this};
diff --git a/content/browser/renderer_host/render_frame_metadata_provider_impl.h b/content/browser/renderer_host/render_frame_metadata_provider_impl.h index 3d68f96..bfcd03de 100644 --- a/content/browser/renderer_host/render_frame_metadata_provider_impl.h +++ b/content/browser/renderer_host/render_frame_metadata_provider_impl.h
@@ -60,7 +60,6 @@ private: friend class FakeRenderWidgetHostViewAura; - friend class DelegatedInkPointTest; // Paired with the mojom::RenderFrameMetadataObserverClient overrides, these // methods are enqueued in |frame_token_message_queue_|. They are invoked when
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index a107b155..67a4e821 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -68,6 +68,8 @@ #include "base/trace_event/memory_dump_manager.h" #include "base/trace_event/memory_dump_provider.h" #include "base/trace_event/trace_event.h" +#include "base/trace_event/typed_macros.h" +#include "base/tracing/protos/chrome_track_event.pbzero.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "cc/base/switches.h" @@ -292,6 +294,8 @@ namespace { +using perfetto::protos::pbzero::ChromeTrackEvent; + // Stores the maximum number of renderer processes the content module can // create. Only applies if it is set to a non-zero value. size_t g_max_renderer_count_override = 0; @@ -1712,11 +1716,12 @@ instance_weak_factory_(absl::in_place, this), shutdown_exit_code_(-1) { CHECK(!browser_context->ShutdownStarted()); - TRACE_EVENT2("shutdown", "RenderProcessHostImpl", "render_process_host", this, - "id", GetID()); - TRACE_EVENT_NESTABLE_ASYNC_BEGIN2("shutdown", "Browser.RenderProcessHostImpl", - this, "render_process_host", this, - "browser_context", browser_context_); + TRACE_EVENT("shutdown", "RenderProcessHostImpl", + ChromeTrackEvent::kRenderProcessHost, *this); + TRACE_EVENT_BEGIN("shutdown", "Browser.RenderProcessHostImpl", + perfetto::Track::FromPointer(this), + ChromeTrackEvent::kRenderProcessHost, *this); + widget_helper_ = new RenderWidgetHelper(); ChildProcessSecurityPolicyImpl::GetInstance()->Add(GetID(), browser_context); @@ -1826,8 +1831,8 @@ } RenderProcessHostImpl::~RenderProcessHostImpl() { - TRACE_EVENT2("shutdown", "~RenderProcessHostImpl", "render_process_host", - this, "id", GetID()); + TRACE_EVENT("shutdown", "~RenderProcessHostImpl", + ChromeTrackEvent::kRenderProcessHost, *this); DCHECK_CURRENTLY_ON(BrowserThread::UI); #ifndef NDEBUG DCHECK(is_self_deleted_) @@ -1858,16 +1863,19 @@ if (cleanup_network_service_plugin_exceptions_upon_destruction_) RemoveNetworkServicePluginExceptions(GetID()); - TRACE_EVENT_NESTABLE_ASYNC_END1("shutdown", "Cleanup in progress", this, - "render_process_host", this); - TRACE_EVENT_NESTABLE_ASYNC_END1("shutdown", "Browser.RenderProcessHostImpl", - this, "render_process_host", this); // Manually delete here in order to avoid DeleteOnIOThread trait when // kProcessHostOnUI is enabled. if (base::FeatureList::IsEnabled(features::kProcessHostOnUI) && gpu_client_) { delete gpu_client_.release(); } + + // "Cleanup in progress" + TRACE_EVENT_END("shutdown", perfetto::Track::FromPointer(this), + ChromeTrackEvent::kRenderProcessHost, *this); + // "Browser.RenderProcessHostImpl" + TRACE_EVENT_END("shutdown", perfetto::Track::FromPointer(this), + ChromeTrackEvent::kRenderProcessHost, *this); } bool RenderProcessHostImpl::Init() { @@ -2378,6 +2386,22 @@ .ToString()); } +void RenderProcessHostImpl::WriteIntoTrace( + perfetto::TracedProto<perfetto::protos::pbzero::RenderProcessHost> proto) { + int id = GetID(); + proto->set_id(id); + proto->set_process_lock(ChildProcessSecurityPolicyImpl::GetInstance() + ->GetProcessLock(id) + .ToString()); + browser_context_->WriteIntoTrace( + proto.WriteNestedMessage<perfetto::protos::pbzero::RenderProcessHost:: + FieldMetadata_BrowserContext>()); + + // TODO(ssid): Consider moving this to ChildProcessLauncher proto field. + if (child_process_launcher_) + proto->set_child_process_id(child_process_launcher_->GetProcess().Pid()); +} + void RenderProcessHostImpl::RegisterMojoInterfaces() { auto registry = std::make_unique<service_manager::BinderRegistry>(); @@ -2815,9 +2839,8 @@ } void RenderProcessHostImpl::DisableKeepAliveRefCount() { - TRACE_EVENT2("shutdown", "RenderProcessHostImpl::DisableKeepAliveRefCount", - "browser_context", browser_context_, "render_process_host", - this); + TRACE_EVENT("shutdown", "RenderProcessHostImpl::DisableKeepAliveRefCount", + ChromeTrackEvent::kRenderProcessHost, *this); DCHECK_CURRENTLY_ON(BrowserThread::UI); @@ -2885,16 +2908,26 @@ void RenderProcessHostImpl::AddRoute(int32_t routing_id, IPC::Listener* listener) { - TRACE_EVENT2("shutdown", "RenderProcessHostImpl::AddRoute", - "render_process_host", this, "routing_id", routing_id); + TRACE_EVENT("shutdown", "RenderProcessHostImpl::AddRoute", + ChromeTrackEvent::kRenderProcessHost, *this, + [&](perfetto::EventContext ctx) { + auto* proto = ctx.event<ChromeTrackEvent>() + ->set_render_process_host_listener_changed(); + proto->set_routing_id(routing_id); + }); CHECK(!listeners_.Lookup(routing_id)) << "Found Routing ID Conflict: " << routing_id; listeners_.AddWithID(listener, routing_id); } void RenderProcessHostImpl::RemoveRoute(int32_t routing_id) { - TRACE_EVENT2("shutdown", "RenderProcessHostImpl::RemoveRoute", - "render_process_host", this, "routing_id", routing_id); + TRACE_EVENT("shutdown", "RenderProcessHostImpl::RemoveRoute", + ChromeTrackEvent::kRenderProcessHost, *this, + [&](perfetto::EventContext ctx) { + auto* proto = ctx.event<ChromeTrackEvent>() + ->set_render_process_host_listener_changed(); + proto->set_routing_id(routing_id); + }); DCHECK(listeners_.Lookup(routing_id) != nullptr); listeners_.Remove(routing_id); Cleanup(); @@ -3770,8 +3803,8 @@ } void RenderProcessHostImpl::Cleanup() { - TRACE_EVENT1("shutdown", "RenderProcessHostImpl::Cleanup", - "render_process_host", this); + TRACE_EVENT("shutdown", "RenderProcessHostImpl::Cleanup", + ChromeTrackEvent::kRenderProcessHost, *this); DCHECK_CURRENTLY_ON(BrowserThread::UI); // Keep the one renderer thread around forever in single process mode. if (run_renderer_in_process()) @@ -3783,10 +3816,9 @@ // been made, and guarantee that the RenderProcessHostDestroyed observer // callback is always the last callback fired. if (within_process_died_observer_) { - TRACE_EVENT1( - "shutdown", - "RenderProcessHostImpl::Cleanup : within_process_died_observer", - "render_process_host", this); + TRACE_EVENT("shutdown", + "RenderProcessHostImpl::Cleanup : within_process_died_observer", + ChromeTrackEvent::kRenderProcessHost, *this); delayed_cleanup_needed_ = true; return; } @@ -3802,23 +3834,32 @@ // Until there are no other owners of this object, we can't delete // ourselves. if (!listeners_.IsEmpty()) { - TRACE_EVENT2("shutdown", "RenderProcessHostImpl::Cleanup : Has listeners.", - "render_process_host", this, "listener_count", - listeners_.size()); + TRACE_EVENT( + "shutdown", "RenderProcessHostImpl::Cleanup : Has listeners.", + ChromeTrackEvent::kRenderProcessHost, *this, + [&](perfetto::EventContext ctx) { + auto* proto = + ctx.event<ChromeTrackEvent>()->set_render_process_host_cleanup(); + proto->set_listener_count(listeners_.size()); + }); return; } else if (keep_alive_ref_count_ != 0) { - TRACE_EVENT2("shutdown", - "RenderProcessHostImpl::Cleanup : Have keep_alive_ref.", - "render_process_host", this, "keep_alive_ref_count_", - keep_alive_ref_count_); + TRACE_EVENT( + "shutdown", "RenderProcessHostImpl::Cleanup : Have keep_alive_ref.", + ChromeTrackEvent::kRenderProcessHost, *this, + [&](perfetto::EventContext ctx) { + auto* proto = + ctx.event<ChromeTrackEvent>()->set_render_process_host_cleanup(); + proto->set_keep_alive_ref_count(keep_alive_ref_count_); + }); return; } - TRACE_EVENT1("shutdown", "RenderProcessHostImpl::Cleanup : Starting cleanup.", - "render_process_host", this); - TRACE_EVENT_NESTABLE_ASYNC_BEGIN2("shutdown", "Cleanup in progress", this, - "render_process_host", this, - "browser_context", browser_context_); + TRACE_EVENT("shutdown", "RenderProcessHostImpl::Cleanup : Starting cleanup.", + ChromeTrackEvent::kRenderProcessHost, *this); + TRACE_EVENT_BEGIN("shutdown", "Cleanup in progress", + perfetto::Track::FromPointer(this), + ChromeTrackEvent::kRenderProcessHost, *this); if (is_initialized_) { GetIOThreadTaskRunner({})->PostTask( @@ -3993,19 +4034,26 @@ // static void RenderProcessHostImpl::RegisterHost(int host_id, RenderProcessHost* host) { - TRACE_EVENT2("shutdown", "RenderProcessHostImpl::RegisterHost", - "render_process_host", host, "host_id", host_id); + TRACE_EVENT( + "shutdown", "RenderProcessHostImpl::RegisterHost", + [&](perfetto::EventContext ctx) { + ctx.event<ChromeTrackEvent>()->set_render_process_host()->set_id( + host_id); + }); GetAllHosts().AddWithID(host, host_id); } // static void RenderProcessHostImpl::UnregisterHost(int host_id) { RenderProcessHost* host = GetAllHosts().Lookup(host_id); - TRACE_EVENT2("shutdown", "RenderProcessHostImpl::UnregisterHost", - "render_process_host", host, "host_id", host_id); - if (!host) return; + TRACE_EVENT( + "shutdown", "RenderProcessHostImpl::UnregisterHost", + [&](perfetto::EventContext ctx) { + ctx.event<ChromeTrackEvent>()->set_render_process_host()->set_id( + host_id); + }); GetAllHosts().Remove(host_id); @@ -4894,9 +4942,9 @@ priority_.is_background() != priority.is_background(); const bool visibility_state_changed = priority_.visible != priority.visible; - TRACE_EVENT2("renderer_host", "RenderProcessHostImpl::UpdateProcessPriority", - "should_background", priority.is_background(), - "has_pending_views", priority.boost_for_pending_views); + TRACE_EVENT("renderer_host", "RenderProcessHostImpl::UpdateProcessPriority", + ChromeTrackEvent::kRenderProcessHost, *this, + ChromeTrackEvent::kChildProcessLauncherPriority, priority); priority_ = priority; // Control the background state from the browser process, otherwise the task @@ -4907,13 +4955,6 @@ if (!run_renderer_in_process()) { DCHECK(child_process_launcher_.get()); DCHECK(!child_process_launcher_->IsStarting()); - // Make sure to keep the pid in the trace so we can tell which process is - // being modified. - TRACE_EVENT2( - "renderer_host", - "RenderProcessHostImpl::UpdateProcessPriority.SetProcessPriority", - "pid", child_process_launcher_->GetProcess().Pid(), - "priority_is_background", priority.is_background()); child_process_launcher_->SetProcessPriority(priority_); }
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h index 59ee682..c70224e 100644 --- a/content/browser/renderer_host/render_process_host_impl.h +++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -84,6 +84,7 @@ #include "third_party/blink/public/mojom/plugins/plugin_registry.mojom-forward.h" #include "third_party/blink/public/mojom/push_messaging/push_messaging.mojom-forward.h" #include "third_party/blink/public/mojom/webdatabase/web_database.mojom-forward.h" +#include "third_party/perfetto/include/perfetto/tracing/traced_proto.h" #include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h" #include "ui/gfx/gpu_memory_buffer.h" @@ -104,6 +105,14 @@ class SystemTracingService; } +namespace perfetto { +namespace protos { +namespace pbzero { +class RenderProcessHost; +} +} // namespace protos +} // namespace perfetto + namespace viz { class GpuClient; } @@ -296,6 +305,9 @@ child_process_activity_time_ = base::TimeTicks::Now(); } + void WriteIntoTrace( + perfetto::TracedProto<perfetto::protos::pbzero::RenderProcessHost> proto); + // Return the set of previously stored frame tokens for a |new_routing_id|. // The frame tokens were stored on the IO thread via the // RenderMessageFilter::GenerateFrameRoutingID mojo call. Returns false if
diff --git a/content/browser/renderer_host/render_view_host_delegate.cc b/content/browser/renderer_host/render_view_host_delegate.cc index 42de6d8..9874982a 100644 --- a/content/browser/renderer_host/render_view_host_delegate.cc +++ b/content/browser/renderer_host/render_view_host_delegate.cc
@@ -10,12 +10,6 @@ return nullptr; } -bool RenderViewHostDelegate::OnMessageReceived( - RenderViewHostImpl* render_view_host, - const IPC::Message& message) { - return false; -} - WebContents* RenderViewHostDelegate::GetAsWebContents() { return nullptr; }
diff --git a/content/browser/renderer_host/render_view_host_delegate.h b/content/browser/renderer_host/render_view_host_delegate.h index b877d0b7..ba6cb540 100644 --- a/content/browser/renderer_host/render_view_host_delegate.h +++ b/content/browser/renderer_host/render_view_host_delegate.h
@@ -14,10 +14,6 @@ #include "mojo/public/cpp/bindings/pending_remote.h" #include "net/base/load_states.h" -namespace IPC { -class Message; -} - namespace blink { namespace web_pref { struct WebPreferences; @@ -53,10 +49,6 @@ // there is no corresponding delegate. virtual RenderViewHostDelegateView* GetDelegateView(); - // This is used to give the delegate a chance to filter IPC messages. - virtual bool OnMessageReceived(RenderViewHostImpl* render_view_host, - const IPC::Message& message); - // Return this object cast to a WebContents, if it is one. If the object is // not a WebContents, returns NULL. DEPRECATED: Be sure to include brettw or // jam as reviewers before you use this method. http://crbug.com/82582
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc index 8748d842..2e43f4e 100644 --- a/content/browser/renderer_host/render_view_host_impl.cc +++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -771,11 +771,7 @@ // RenderViewHostImpl, IPC message handlers: bool RenderViewHostImpl::OnMessageReceived(const IPC::Message& msg) { - // Crash reports trigerred by the IPC messages below should be associated - // with URL of the main frame. - ScopedActiveURL scoped_active_url(this); - - return delegate_->OnMessageReceived(this, msg); + return false; } void RenderViewHostImpl::OnDidContentsPreferredSizeChange(
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 b2e08a8..893c804 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
@@ -14,7 +14,6 @@ #include "base/metrics/histogram_macros.h" #include "base/stl_util.h" #include "base/strings/stringprintf.h" -#include "base/trace_event/trace_event.h" #include "components/viz/common/features.h" #include "components/viz/common/hit_test/hit_test_region_list.h" #include "components/viz/common/quads/surface_draw_quad.h" @@ -28,7 +27,6 @@ #include "content/public/browser/render_widget_host_iterator.h" #include "third_party/blink/public/common/input/web_input_event.h" #include "ui/base/layout.h" -#include "ui/compositor/compositor.h" #include "ui/gfx/geometry/dip_util.h" namespace { @@ -643,14 +641,6 @@ mouse_capture_target_ = target; } - if (target) { - ui::EventType type = mouse_event.GetTypeAsUiEventType(); - bool hovering = - (type ^ ui::ET_MOUSE_DRAGGED) && (type ^ ui::ET_MOUSE_PRESSED); - ForwardDelegatedInkPoint(target, root_view, mouse_event, mouse_event, - hovering); - } - DCHECK(target_location.has_value()); blink::WebMouseEvent event = mouse_event; event.SetPositionInWidget(target_location->x(), target_location->y()); @@ -875,11 +865,6 @@ base::debug::DumpWithoutCrashing(); } - if (touch_target_) { - ForwardDelegatedInkPoint(touch_target_, root_view, touch_event, - touch_event.touches[0], touch_event.hovering); - } - TouchEventAckQueue::TouchEventSource event_source = is_emulated_touchevent ? TouchEventAckQueue::TouchEventSource::EmulatedTouchEvent @@ -2003,71 +1988,4 @@ event_targeter_->SetIsAutoScrollInProgress(is_autoscroll_in_progress); } -bool IsMoveEvent(ui::EventType type) { - return type == ui::ET_MOUSE_MOVED || type == ui::ET_MOUSE_DRAGGED || - type == ui::ET_TOUCH_MOVED; -} - -void RenderWidgetHostInputEventRouter::ForwardDelegatedInkPoint( - RenderWidgetHostViewBase* target_view, - RenderWidgetHostViewBase* root_view, - const blink::WebInputEvent& input_event, - const blink::WebPointerProperties& pointer_properties, - bool hovering) { - const absl::optional<cc::DelegatedInkBrowserMetadata>& metadata = - target_view->host() - ->render_frame_metadata_provider() - ->LastRenderFrameMetadata() - .delegated_ink_metadata; - - if (IsMoveEvent(input_event.GetTypeAsUiEventType()) && metadata && - hovering == metadata.value().delegated_ink_is_hovering) { - if (!delegated_ink_point_renderer_.is_bound()) { - ui::Compositor* compositor = target_view->GetCompositor(); - - // The remote can't be bound if the compositor is null, so bail if that - // is the case so we don't crash by trying to use an unbound remote. - if (!compositor) - return; - - TRACE_EVENT_INSTANT0("input", - "Binding mojo interface for delegated ink points.", - TRACE_EVENT_SCOPE_THREAD); - compositor->SetDelegatedInkPointRenderer( - delegated_ink_point_renderer_.BindNewPipeAndPassReceiver()); - delegated_ink_point_renderer_.reset_on_disconnect(); - } - - gfx::PointF position = pointer_properties.PositionInWidget(); - root_view->TransformPointToRootSurface(&position); - position.Scale(target_view->GetDeviceScaleFactor()); - - gfx::DelegatedInkPoint delegated_ink_point( - position, input_event.TimeStamp(), pointer_properties.id); - TRACE_EVENT_INSTANT1("input", - "Forwarding delegated ink point from browser.", - TRACE_EVENT_SCOPE_THREAD, "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 - // the IPC overhead will result in a minor increase in latency for getting - // this event to the renderer. However, by sending it here, the event is - // given the greatest possible chance to make it to viz before - // DrawAndSwap() is called, allowing more points to be drawn as part of - // the delegated ink trail, and thus reducing user perceived latency. - delegated_ink_point_renderer_->StoreDelegatedInkPoint(delegated_ink_point); - ended_delegated_ink_trail_ = false; - } else if (delegated_ink_point_renderer_.is_bound() && - !ended_delegated_ink_trail_) { - // Let viz know that the most recent point it received from us is probably - // the last point the user is inking, so it shouldn't predict anything - // beyond it. - TRACE_EVENT_INSTANT0("input", "Delegated ink trail ended", - TRACE_EVENT_SCOPE_THREAD); - delegated_ink_point_renderer_->ResetPrediction(); - ended_delegated_ink_trail_ = true; - } -} - } // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_input_event_router.h b/content/browser/renderer_host/render_widget_host_input_event_router.h index b850e9e..3550833 100644 --- a/content/browser/renderer_host/render_widget_host_input_event_router.h +++ b/content/browser/renderer_host/render_widget_host_input_event_router.h
@@ -23,10 +23,8 @@ #include "content/browser/renderer_host/render_widget_host_view_base_observer.h" #include "content/browser/renderer_host/render_widget_targeter.h" #include "content/common/content_export.h" -#include "mojo/public/cpp/bindings/remote.h" #include "third_party/blink/public/mojom/input/input_event_result.mojom-shared.h" #include "ui/gfx/geometry/vector2d_conversions.h" -#include "ui/gfx/mojom/delegated_ink_point_renderer.mojom.h" #include "ui/gfx/transform.h" namespace blink { @@ -34,7 +32,6 @@ class WebInputEvent; class WebMouseEvent; class WebMouseWheelEvent; -class WebPointerProperties; class WebTouchEvent; } @@ -335,18 +332,6 @@ void SetTouchscreenGestureTarget(RenderWidgetHostViewBase* target, bool moved_recently = false); - void ForwardDelegatedInkPoint( - RenderWidgetHostViewBase* target_view, - RenderWidgetHostViewBase* root_view, - const blink::WebInputEvent& input_event, - const blink::WebPointerProperties& pointer_properties, - bool hovering); - - void FlushForTest() { delegated_ink_point_renderer_.FlushForTesting(); } - bool IsDelegatedInkRendererBoundForTest() { - return delegated_ink_point_renderer_.is_bound(); - } - FrameSinkIdOwnerMap owner_map_; TargetMap touchscreen_gesture_target_map_; RenderWidgetHostViewBase* touch_target_ = nullptr; @@ -444,18 +429,6 @@ // Used to prevent multiple dumps. bool has_dumped_ = false; - // Remote end of the connection for sending delegated ink points to viz to - // support the delegated ink trails feature. - mojo::Remote<gfx::mojom::DelegatedInkPointRenderer> - delegated_ink_point_renderer_; - // Used to know if we have already told viz to reset prediction because the - // final point of the delegated ink trail has been sent. True when prediction - // has already been reset for the most recent trail, false otherwise. This - // flag helps make sure that we don't send more IPCs than necessary to viz to - // reset prediction. Sending extra IPCs wouldn't impact correctness, but can - // impact performance due to the IPC overhead. - bool ended_delegated_ink_trail_ = false; - base::WeakPtrFactory<RenderWidgetHostInputEventRouter> weak_ptr_factory_{ this}; @@ -477,8 +450,6 @@ InputEventRouterWheelTargetTest); FRIEND_TEST_ALL_PREFIXES(SitePerProcessMacBrowserTest, InputEventRouterTouchpadGestureTargetTest); - FRIEND_TEST_ALL_PREFIXES(SitePerProcessDelegatedInkBrowserTest, - MetadataAndPointGoThroughOOPIF); }; } // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_input_event_router_unittest.cc b/content/browser/renderer_host/render_widget_host_input_event_router_unittest.cc index 9db386e..fe41ab1 100644 --- a/content/browser/renderer_host/render_widget_host_input_event_router_unittest.cc +++ b/content/browser/renderer_host/render_widget_host_input_event_router_unittest.cc
@@ -31,13 +31,6 @@ #include "third_party/blink/public/common/input/synthetic_web_input_event_builders.h" #include "third_party/blink/public/mojom/input/touch_event.mojom.h" -#if defined(USE_AURA) -#include "ui/aura/test/aura_test_helper.h" -#include "ui/aura/test/test_screen.h" -#include "ui/aura/window_tree_host.h" -#include "ui/gfx/mojom/delegated_ink_point_renderer.mojom.h" -#endif // defined(USE_AURA) - namespace content { namespace { @@ -107,15 +100,10 @@ void Reset() { last_gesture_seen_ = blink::WebInputEvent::Type::kUndefined; } - void SetCompositor(ui::Compositor* compositor) { compositor_ = compositor; } - ui::Compositor* GetCompositor() override { return compositor_; } - private: blink::WebInputEvent::Type last_gesture_seen_ = blink::WebInputEvent::Type::kUndefined; uint32_t unique_id_for_last_touch_ack_ = 0; - - ui::Compositor* compositor_; }; class StubHitTestQuery : public viz::HitTestQuery { @@ -348,8 +336,6 @@ RenderWidgetHostViewBase* gesture_target, bool should_cancel); - void FlushInkRenderer() { rwhier()->FlushForTest(); } - BrowserTaskEnvironment task_environment_; MockRenderWidgetHostDelegate delegate_; @@ -1059,505 +1045,4 @@ base::RunLoop().RunUntilIdle(); } -#if defined(USE_AURA) -// Mock the DelegatedInkPointRenderer to grab the delegated ink points as they -// are shipped off to viz from the browser process. -class MockDelegatedInkPointRenderer - : public gfx::mojom::DelegatedInkPointRenderer { - public: - explicit MockDelegatedInkPointRenderer( - mojo::PendingReceiver<gfx::mojom::DelegatedInkPointRenderer> receiver) - : receiver_(this, std::move(receiver)) {} - - void StoreDelegatedInkPoint(const gfx::DelegatedInkPoint& point) override { - delegated_ink_point_ = point; - } - - bool HasDelegatedInkPoint() { return delegated_ink_point_.has_value(); } - - gfx::DelegatedInkPoint GetDelegatedInkPoint() { - gfx::DelegatedInkPoint point = delegated_ink_point_.value(); - delegated_ink_point_.reset(); - return point; - } - - void ClearDelegatedInkPoint() { delegated_ink_point_.reset(); } - - void ResetPrediction() override { prediction_reset_ = true; } - bool GetPredictionState() { - bool state = prediction_reset_; - prediction_reset_ = false; - return state; - } - - void FlushForTesting() { receiver_.FlushForTesting(); } - - void ResetReceiver() { receiver_.reset(); } - bool ReceiverIsBound() { return receiver_.is_bound(); } - - private: - mojo::Receiver<gfx::mojom::DelegatedInkPointRenderer> receiver_; - absl::optional<gfx::DelegatedInkPoint> delegated_ink_point_; - bool prediction_reset_ = false; -}; - -// MockCompositor class binds the mojo interfaces so that the ink points are -// shipped to the browser process. Uses values from the real compositor to be -// created, but a fake FrameSinkId must be used so that it hasn't already been -// registered. -class MockCompositor : public ui::Compositor { - public: - explicit MockCompositor(ui::Compositor* compositor) - : ui::Compositor(viz::FrameSinkId(5, 5), - compositor->context_factory(), - compositor->task_runner(), - compositor->is_pixel_canvas()) {} - - void SetDelegatedInkPointRenderer( - mojo::PendingReceiver<gfx::mojom::DelegatedInkPointRenderer> receiver) - override { - delegated_ink_point_renderer_ = - std::make_unique<MockDelegatedInkPointRenderer>(std::move(receiver)); - } - - MockDelegatedInkPointRenderer* delegated_ink_point_renderer() { - return delegated_ink_point_renderer_.get(); - } - - private: - std::unique_ptr<MockDelegatedInkPointRenderer> delegated_ink_point_renderer_; -}; - -enum TestEvent { kMouseEvent, kTouchEvent }; -enum HoveringState { kHovering, kNotHovering }; - -class DelegatedInkPointTest - : public RenderWidgetHostInputEventRouterTest, - public testing::WithParamInterface<std::tuple<TestEvent, HoveringState>> { - public: - DelegatedInkPointTest() = default; - - void SetUp() override { - RenderWidgetHostInputEventRouterTest::SetUp(); - - aura_test_helper_ = std::make_unique<aura::test::AuraTestHelper>( - ImageTransportFactory::GetInstance()->GetContextFactory()); - aura_test_helper_->SetUp(); - - compositor_ = std::make_unique<MockCompositor>( - aura_test_helper_->GetHost()->compositor()); - view_root_->SetCompositor(compositor_.get()); - } - - void TearDown() override { - aura_test_helper_->TearDown(); - compositor_.reset(); - RenderWidgetHostInputEventRouterTest::TearDown(); - } - - TestEvent GetEventParam() { return std::get<0>(GetParam()); } - HoveringState GetHoverParam() { return std::get<1>(GetParam()); } - - void SetInkMetadataFlagOnRenderFrameMetadata(bool delegated_ink) { - SetInkMetadataFlagOnSpecificHost(delegated_ink, widget_host_root_.get()); - } - - void SetInkMetadataFlagOnSpecificHost(bool delegated_ink, - RenderWidgetHostImpl* widget_host) { - cc::RenderFrameMetadata metadata; - if (delegated_ink) { - metadata.delegated_ink_metadata = cc::DelegatedInkBrowserMetadata( - GetHoverParam() == HoveringState::kHovering); - } - widget_host->render_frame_metadata_provider() - ->SetLastRenderFrameMetadataForTest(metadata); - } - - void SendEvent(bool match_test_hovering_state, - gfx::PointF point, - base::TimeTicks timestamp = base::TimeTicks::Now()) { - SendEvent(match_test_hovering_state, point, timestamp, - /*use_enter_event*/ false, /*use_exit_event*/ false); - } - - void SendEvent(bool match_test_hovering_state, - const gfx::PointF& point, - base::TimeTicks timestamp, - bool use_enter_event, - bool use_exit_event) { - DCHECK(!(use_enter_event && use_exit_event)); - - // Hovering creates and sends ui::MouseEvents with - // ET_MOUSE_{MOVED,ENTERED,EXITED} types, so do the same here in hovering - // scenarios. - if (GetEventParam() == TestEvent::kTouchEvent && - !Hovering(match_test_hovering_state)) { - blink::WebInputEvent::Type event_type = - blink::WebInputEvent::Type::kTouchMove; - blink::WebTouchPoint::State touch_state = - blink::WebTouchPoint::State::kStateMoved; - if (use_enter_event) { - event_type = blink::WebInputEvent::Type::kTouchStart; - touch_state = blink::WebTouchPoint::State::kStatePressed; - // Set this now so that if we are going to send a enter event anyway, - // we don't send two. - sent_touch_press_ = true; - } - if (use_exit_event) { - event_type = blink::WebInputEvent::Type::kTouchEnd; - touch_state = blink::WebTouchPoint::State::kStateReleased; - } - - // Touch needs a pressed event first to properly handle future move - // events. - SendTouchPress(point); - - blink::WebTouchEvent touch_event( - event_type, blink::WebInputEvent::kNoModifiers, timestamp); - touch_event.touches_length = 1; - touch_event.touches[0].id = kPointerId; - touch_event.touches[0].SetPositionInWidget(point); - touch_event.touches[0].state = touch_state; - touch_event.unique_touch_event_id = GetTouchId(); - - rwhier()->RouteTouchEvent(view_root_.get(), &touch_event, - ui::LatencyInfo(ui::SourceEventType::TOUCH)); - - // Need to send a new press event after ending the previous touch. - if (use_exit_event) - sent_touch_press_ = false; - } else { - blink::WebInputEvent::Type event_type = - blink::WebInputEvent::Type::kMouseMove; - if (use_enter_event) - event_type = blink::WebInputEvent::Type::kMouseEnter; - if (use_exit_event) - event_type = blink::WebInputEvent::Type::kMouseLeave; - - int modifiers = 0; - if (!Hovering(match_test_hovering_state)) - modifiers = blink::WebInputEvent::kLeftButtonDown; - - blink::WebMouseEvent mouse_event(event_type, modifiers, timestamp, - kPointerId); - mouse_event.SetPositionInWidget(point); - - rwhier()->RouteMouseEvent(view_root_.get(), &mouse_event, - ui::LatencyInfo(ui::SourceEventType::MOUSE)); - } - } - - void SetDeviceScaleFactor(float dsf) { - aura_test_helper_->GetTestScreen()->SetDeviceScaleFactor(dsf); - } - - MockCompositor* compositor() { return compositor_.get(); } - - int32_t GetExpectedPointerId() const { return kPointerId; } - - private: - void SendTouchPress(const gfx::PointF& requested_touch_location) { - DCHECK(GetEventParam() == TestEvent::kTouchEvent); - if (sent_touch_press_) - return; - - // Location of the press event doesn't matter, so long as it doesn't exactly - // match the location of the subsequent move event. If they match, then the - // move event is dropped. - gfx::PointF point(requested_touch_location.x() + 2.f, - requested_touch_location.y() + 2.f); - - // Send a TouchStart/End sequence. - blink::WebTouchEvent press( - blink::WebInputEvent::Type::kTouchStart, - blink::WebInputEvent::kNoModifiers, - blink::WebInputEvent::GetStaticTimeStampForTests()); - press.touches_length = 1; - press.touches[0].id = kPointerId; - press.touches[0].SetPositionInWidget(point); - press.touches[0].state = blink::WebTouchPoint::State::kStatePressed; - press.unique_touch_event_id = GetTouchId(); - - rwhier()->RouteTouchEvent(view_root_.get(), &press, - ui::LatencyInfo(ui::SourceEventType::TOUCH)); - sent_touch_press_ = true; - } - - bool Hovering(bool match_test_hovering_state) { - return (GetHoverParam() == HoveringState::kHovering && - match_test_hovering_state) || - (GetHoverParam() == HoveringState::kNotHovering && - !match_test_hovering_state); - } - - // Unique touch id is unique per event, so always increment before providing - // a new one. - int GetTouchId() { return ++unique_touch_id_; } - - // Pointer id to use in these tests. It must be consistent throughout a single - // test for some of the touch variations. - const int32_t kPointerId = 5; - - // Touch events are ignored if a press isn't sent first, so use this to track - // if we have already sent a touch press event yet or not. - bool sent_touch_press_ = false; - - // Most recently used unique touch id for blink::WebTouchEvents - int unique_touch_id_ = 0; - - // Helper for creating a compositor and setting the device scale factor. - std::unique_ptr<aura::test::AuraTestHelper> aura_test_helper_; - - // Mock compositor used for getting the delegated ink points that are - // forwarded. - std::unique_ptr<MockCompositor> compositor_; -}; - -struct DelegatedInkPointTestPassToString { - std::string operator()( - const testing::TestParamInfo<std::tuple<TestEvent, HoveringState>> type) - const { - std::string suffix; - - if (std::get<0>(type.param) == TestEvent::kMouseEvent) - suffix.append("Mouse"); - else - suffix.append("Touch"); - - if (std::get<1>(type.param) == HoveringState::kHovering) - suffix.append("Hovering"); - else - suffix.append("NotHovering"); - - return suffix; - } -}; - -INSTANTIATE_TEST_SUITE_P( - DelegatedInkTrails, - DelegatedInkPointTest, - testing::Combine( - testing::Values(TestEvent::kMouseEvent, TestEvent::kTouchEvent), - testing::Values(HoveringState::kHovering, HoveringState::kNotHovering)), - DelegatedInkPointTestPassToString()); - -// Tests to confirm that input events are correctly forwarded to the UI -// Compositor when DelegatedInkTrails should be drawn, and stops forwarding when -// they no longer should be drawn. -TEST_P(DelegatedInkPointTest, EventForwardedToCompositor) { - // First confirm that the flag is false by default and the point is not sent. - SendEvent(true, gfx::PointF(15, 15)); - MockDelegatedInkPointRenderer* delegated_ink_point_renderer = - compositor()->delegated_ink_point_renderer(); - - EXPECT_FALSE(delegated_ink_point_renderer); - - // Then set it to true and confirm that the DelegatedInkPointRenderer is - // initialized, the connection is made and the point makes it to the renderer. - SetInkMetadataFlagOnRenderFrameMetadata(true); - gfx::DelegatedInkPoint expected_point( - gfx::PointF(10, 10), base::TimeTicks::Now(), GetExpectedPointerId()); - SendEvent(true, expected_point.point(), expected_point.timestamp()); - - delegated_ink_point_renderer = compositor()->delegated_ink_point_renderer(); - EXPECT_TRUE(delegated_ink_point_renderer); - delegated_ink_point_renderer->FlushForTesting(); - - EXPECT_TRUE(delegated_ink_point_renderer->HasDelegatedInkPoint()); - gfx::DelegatedInkPoint actual_point = - delegated_ink_point_renderer->GetDelegatedInkPoint(); - EXPECT_EQ(expected_point.point(), actual_point.point()); - EXPECT_EQ(expected_point.timestamp(), actual_point.timestamp()); - EXPECT_EQ(GetExpectedPointerId(), actual_point.pointer_id()); - - // Then try changing the scale factor to confirm it affects the point - // correctly. - const float scale = 2.6f; - SetDeviceScaleFactor(scale); - gfx::PointF unscaled_point(15, 15); - base::TimeTicks unscaled_time = base::TimeTicks::Now(); - - SendEvent(true, unscaled_point, unscaled_time); - delegated_ink_point_renderer->FlushForTesting(); - - unscaled_point.Scale(scale); - expected_point = gfx::DelegatedInkPoint(unscaled_point, unscaled_time, - GetExpectedPointerId()); - - EXPECT_TRUE(delegated_ink_point_renderer->HasDelegatedInkPoint()); - actual_point = delegated_ink_point_renderer->GetDelegatedInkPoint(); - EXPECT_EQ(expected_point.point(), actual_point.point()); - EXPECT_EQ(expected_point.timestamp(), actual_point.timestamp()); - EXPECT_EQ(GetExpectedPointerId(), actual_point.pointer_id()); - - // Confirm that prediction is reset when the API is no longer being used and - // |delegated_ink_metadata| is not set. - SetInkMetadataFlagOnRenderFrameMetadata(false); - - SendEvent(true, gfx::PointF(25, 25)); - delegated_ink_point_renderer->FlushForTesting(); - - EXPECT_FALSE(delegated_ink_point_renderer->HasDelegatedInkPoint()); - EXPECT_TRUE(delegated_ink_point_renderer->GetPredictionState()); - - // Finally, confirm that nothing is sent after the prediction has been reset - // when the delegated ink flag on the render frame metadata is false. - SendEvent(true, gfx::PointF(46, 46)); - delegated_ink_point_renderer->FlushForTesting(); - - EXPECT_FALSE(delegated_ink_point_renderer->HasDelegatedInkPoint()); - EXPECT_FALSE(delegated_ink_point_renderer->GetPredictionState()); -} - -// Confirm that the interface is rebound if the receiver disconnects. -TEST_P(DelegatedInkPointTest, MojoInterfaceReboundOnDisconnect) { - // First make sure the connection exists. - SetInkMetadataFlagOnRenderFrameMetadata(true); - SendEvent(true, gfx::PointF(15, 15)); - - MockDelegatedInkPointRenderer* delegated_ink_point_renderer = - compositor()->delegated_ink_point_renderer(); - - EXPECT_TRUE(delegated_ink_point_renderer); - EXPECT_TRUE(delegated_ink_point_renderer->ReceiverIsBound()); - - // Reset the receiver and flush the remote to confirm it is no longer bound. - delegated_ink_point_renderer->ResetReceiver(); - FlushInkRenderer(); - - EXPECT_FALSE(delegated_ink_point_renderer->ReceiverIsBound()); - - // Confirm that it now gets reconnected correctly. - SendEvent(true, gfx::PointF(25, 25)); - - delegated_ink_point_renderer = compositor()->delegated_ink_point_renderer(); - - EXPECT_TRUE(delegated_ink_point_renderer); - EXPECT_TRUE(delegated_ink_point_renderer->ReceiverIsBound()); -} - -// Test to confirm that forwarding points to viz will stop and prediction is -// reset if the state of hovering differs between what is expected and the -// received points. -TEST_P(DelegatedInkPointTest, StopForwardingOnHoverStateChange) { - // First send a point and make sure it makes it to the renderer. - SetInkMetadataFlagOnRenderFrameMetadata(true); - SendEvent(true, gfx::PointF(15, 15)); - - MockDelegatedInkPointRenderer* delegated_ink_point_renderer = - compositor()->delegated_ink_point_renderer(); - EXPECT_TRUE(delegated_ink_point_renderer); - delegated_ink_point_renderer->FlushForTesting(); - - EXPECT_TRUE(delegated_ink_point_renderer->HasDelegatedInkPoint()); - delegated_ink_point_renderer->ClearDelegatedInkPoint(); - - // Now send a point that doesn't match the state of hovering on the metadata - // to confirm that it isn't sent and ResetPrediction is called. - SendEvent(false, gfx::PointF(20, 20)); - delegated_ink_point_renderer->FlushForTesting(); - - EXPECT_FALSE(delegated_ink_point_renderer->HasDelegatedInkPoint()); - EXPECT_TRUE(delegated_ink_point_renderer->GetPredictionState()); - - // Send another that doesn't match to confirm the end trail point is only sent - // once. - SendEvent(false, gfx::PointF(25, 25)); - delegated_ink_point_renderer->FlushForTesting(); - EXPECT_FALSE(delegated_ink_point_renderer->HasDelegatedInkPoint()); - - // Send one that does match again to confirm that points will start sending - // again if the hovering state starts matching again. - SendEvent(true, gfx::PointF(30, 30)); - delegated_ink_point_renderer->FlushForTesting(); - - EXPECT_TRUE(delegated_ink_point_renderer->HasDelegatedInkPoint()); - EXPECT_FALSE(delegated_ink_point_renderer->GetPredictionState()); -} - -// Confirm that only move events are forwarded, not enter/exit or equivalent -// events. -TEST_P(DelegatedInkPointTest, IgnoreEnterAndExitEvents) { - // First set everything up and try forwarding a point, confirming that it is - // sent as expected. - SetInkMetadataFlagOnRenderFrameMetadata(true); - gfx::DelegatedInkPoint expected_point( - gfx::PointF(10, 10), base::TimeTicks::Now(), GetExpectedPointerId()); - SendEvent(true, expected_point.point(), expected_point.timestamp()); - - MockDelegatedInkPointRenderer* delegated_ink_point_renderer = - compositor()->delegated_ink_point_renderer(); - EXPECT_TRUE(delegated_ink_point_renderer); - delegated_ink_point_renderer->FlushForTesting(); - - EXPECT_TRUE(delegated_ink_point_renderer->HasDelegatedInkPoint()); - gfx::DelegatedInkPoint actual_point = - delegated_ink_point_renderer->GetDelegatedInkPoint(); - EXPECT_EQ(expected_point.point(), actual_point.point()); - EXPECT_EQ(expected_point.timestamp(), actual_point.timestamp()); - EXPECT_EQ(GetExpectedPointerId(), actual_point.pointer_id()); - - // Now try with an exit event. - SendEvent(true, gfx::PointF(42, 19), base::TimeTicks::Now(), - /*use_enter_event=*/false, /*use_exit_event=*/true); - delegated_ink_point_renderer->FlushForTesting(); - EXPECT_FALSE(delegated_ink_point_renderer->HasDelegatedInkPoint()); - - // Try sending an enter event and confirm it is not forwarded. - SendEvent(true, gfx::PointF(12, 12), base::TimeTicks::Now(), - /*use_enter_event=*/true, /*use_exit_event=*/false); - delegated_ink_point_renderer->FlushForTesting(); - EXPECT_FALSE(delegated_ink_point_renderer->HasDelegatedInkPoint()); - - // Finally, confirm that sending move events will work again without issue. - expected_point = gfx::DelegatedInkPoint( - gfx::PointF(20, 21), base::TimeTicks::Now(), GetExpectedPointerId()); - SendEvent(true, expected_point.point(), expected_point.timestamp()); - - delegated_ink_point_renderer->FlushForTesting(); - - EXPECT_TRUE(delegated_ink_point_renderer->HasDelegatedInkPoint()); - actual_point = delegated_ink_point_renderer->GetDelegatedInkPoint(); - EXPECT_EQ(expected_point.point(), actual_point.point()); - EXPECT_EQ(expected_point.timestamp(), actual_point.timestamp()); - EXPECT_EQ(GetExpectedPointerId(), actual_point.pointer_id()); -} - -// This test confirms that points can be forwarded when using delegated ink in -// a child frame, such as an OOPIF. -TEST_P(DelegatedInkPointTest, ForwardPointsToChildFrame) { - // Make the child frame, set the delegated ink flag on it, give it a - // compositor, and set it as the hit test result so that the input router - // sends points to it. - ChildViewState child = MakeChildView(view_root_.get()); - SetInkMetadataFlagOnSpecificHost(true, child.widget_host.get()); - child.view->SetCompositor(compositor()); - view_root_->SetHittestResult(child.view.get(), false); - - // Send a point and confirm that it is forwarded, meaning that it correctly - // checked the metadata flag on the child frame's widget. - gfx::DelegatedInkPoint expected_point( - gfx::PointF(10, 10), base::TimeTicks::Now(), GetExpectedPointerId()); - SendEvent(true, expected_point.point(), expected_point.timestamp(), false, - false); - - MockDelegatedInkPointRenderer* delegated_ink_point_renderer = - compositor()->delegated_ink_point_renderer(); - EXPECT_TRUE(delegated_ink_point_renderer); - delegated_ink_point_renderer->FlushForTesting(); - - EXPECT_TRUE(delegated_ink_point_renderer->HasDelegatedInkPoint()); - gfx::DelegatedInkPoint actual_point = - delegated_ink_point_renderer->GetDelegatedInkPoint(); - EXPECT_EQ(expected_point.point(), actual_point.point()); - EXPECT_EQ(expected_point.timestamp(), actual_point.timestamp()); - EXPECT_EQ(GetExpectedPointerId(), actual_point.pointer_id()); - - // Reset's the hit test result on the root so that we don't crash on - // destruction. - rwhier()->OnRenderWidgetHostViewBaseDestroyed(child.view.get()); -} - -#endif // defined(USE_AURA) - } // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc index 053eaaf..d8365d0 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -1855,10 +1855,10 @@ } viz::FrameSinkId RenderWidgetHostViewAura::GetRootFrameSinkId() { - if (!GetCompositor()) + if (!window_ || !window_->GetHost() || !window_->GetHost()->compositor()) return viz::FrameSinkId(); - return GetCompositor()->frame_sink_id(); + return window_->GetHost()->compositor()->frame_sink_id(); } viz::SurfaceId RenderWidgetHostViewAura::GetCurrentSurfaceId() const { @@ -2377,7 +2377,7 @@ UpdateLegacyWin(); #endif - delegated_frame_host_->AttachToCompositor(GetCompositor()); + delegated_frame_host_->AttachToCompositor(window_->GetHost()->compositor()); } void RenderWidgetHostViewAura::RemovingFromRootWindow() { @@ -2730,11 +2730,4 @@ tooltip_observer_for_testing_->OnTooltipTextUpdated(tooltip_text); } -ui::Compositor* RenderWidgetHostViewAura::GetCompositor() { - if (!window_ || !window_->GetHost()) - return nullptr; - - return window_->GetHost()->compositor(); -} - } // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h index ea2aee1..b881bdc 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.h +++ b/content/browser/renderer_host/render_widget_host_view_aura.h
@@ -373,8 +373,6 @@ MouseWheelPhaseHandler* GetMouseWheelPhaseHandler() override; - ui::Compositor* GetCompositor() override; - protected: ~RenderWidgetHostViewAura() override;
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc index a90ac41..466e96ff 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -120,6 +120,7 @@ #include "ui/events/keycodes/keyboard_code_conversion.h" #include "ui/events/test/event_generator.h" #include "ui/gfx/geometry/rect.h" +#include "ui/gfx/mojom/delegated_ink_point_renderer.mojom.h" #include "ui/gfx/selection_bound.h" #include "ui/wm/core/window_util.h" @@ -285,6 +286,9 @@ return event_handler()->pointer_state(); } + // Flush the mojo remote on the event handler for testing purposes. + void FlushForTest() { event_handler()->FlushForTest(); } + void SetRenderFrameMetadata(cc::RenderFrameMetadata metadata) { host()->render_frame_metadata_provider()->SetLastRenderFrameMetadataForTest( metadata); @@ -6754,4 +6758,428 @@ #endif // defined(OS_WIN) +// Mock the DelegatedInkPointRenderer to grab the delegated ink points as they +// are shipped off to viz from the browser process. +class MockDelegatedInkPointRenderer + : public gfx::mojom::DelegatedInkPointRenderer { + public: + explicit MockDelegatedInkPointRenderer( + mojo::PendingReceiver<gfx::mojom::DelegatedInkPointRenderer> receiver) + : receiver_(this, std::move(receiver)) {} + + void StoreDelegatedInkPoint(const gfx::DelegatedInkPoint& point) override { + delegated_ink_point_ = point; + } + + bool HasDelegatedInkPoint() { return delegated_ink_point_.has_value(); } + + gfx::DelegatedInkPoint GetDelegatedInkPoint() { + gfx::DelegatedInkPoint point = delegated_ink_point_.value(); + delegated_ink_point_.reset(); + return point; + } + + void ClearDelegatedInkPoint() { delegated_ink_point_.reset(); } + + void ResetPrediction() override { prediction_reset_ = true; } + bool GetPredictionState() { + bool state = prediction_reset_; + prediction_reset_ = false; + return state; + } + + void FlushForTesting() { receiver_.FlushForTesting(); } + + void ResetReceiver() { receiver_.reset(); } + bool ReceiverIsBound() { return receiver_.is_bound(); } + + private: + mojo::Receiver<gfx::mojom::DelegatedInkPointRenderer> receiver_; + absl::optional<gfx::DelegatedInkPoint> delegated_ink_point_; + bool prediction_reset_ = false; +}; + +// MockCompositor class binds the mojo interfaces so that the ink points are +// shipped to the browser process. Uses values from the real compositor to be +// created, but a fake FrameSinkId must be used so that it hasn't already been +// registered. +class MockCompositor : public ui::Compositor { + public: + explicit MockCompositor(ui::Compositor* compositor) + : ui::Compositor(viz::FrameSinkId(5, 5), + compositor->context_factory(), + compositor->task_runner(), + compositor->is_pixel_canvas()) {} + + void SetDelegatedInkPointRenderer( + mojo::PendingReceiver<gfx::mojom::DelegatedInkPointRenderer> receiver) + override { + delegated_ink_point_renderer_ = + std::make_unique<MockDelegatedInkPointRenderer>(std::move(receiver)); + } + + MockDelegatedInkPointRenderer* delegated_ink_point_renderer() { + return delegated_ink_point_renderer_.get(); + } + + private: + std::unique_ptr<MockDelegatedInkPointRenderer> delegated_ink_point_renderer_; +}; + +enum TestEvent { kMouseEvent, kTouchEvent }; +enum HoveringState { kHovering, kNotHovering }; + +class DelegatedInkPointTest + : public RenderWidgetHostViewAuraTest, + public testing::WithParamInterface<std::tuple<TestEvent, HoveringState>> { + public: + DelegatedInkPointTest() = default; + + void SetUp() override { + RenderWidgetHostViewAuraTest::SetUp(); + + InitViewForFrame(nullptr); + aura_test_helper_->GetTestScreen()->SetDeviceScaleFactor(1.0f); + + real_compositor_ = view_->GetNativeView()->layer()->GetCompositor(); + compositor_ = std::make_unique<MockCompositor>( + aura_test_helper_->GetHost()->compositor()); + view_->GetNativeView()->layer()->SetCompositorForTesting(compositor_.get()); + } + + void TearDown() override { + // Restore the view's compositor to the old value so it no longer references + // the MockCompositor that is about to be destructed. This also ensures + // that the view can be properly destroyed by TearDown(). + view_->GetNativeView()->layer()->SetCompositorForTesting(real_compositor_); + compositor_.reset(); + RenderWidgetHostViewAuraTest::TearDown(); + } + + TestEvent GetEventParam() { return std::get<0>(GetParam()); } + HoveringState GetHoverParam() { return std::get<1>(GetParam()); } + + void SetInkMetadataFlagOnRenderFrameMetadata(bool delegated_ink) { + cc::RenderFrameMetadata metadata; + if (delegated_ink) { + metadata.delegated_ink_metadata = cc::DelegatedInkBrowserMetadata( + GetHoverParam() == HoveringState::kHovering); + } + view_->SetRenderFrameMetadata(metadata); + } + + void SendEvent(bool match_test_hovering_state, + gfx::PointF point, + base::TimeTicks timestamp = ui::EventTimeForNow()) { + SendEvent(match_test_hovering_state, point, timestamp, + /*use_enter_event*/ false, /*use_exit_event*/ false); + } + + void SendEvent(bool match_test_hovering_state, + const gfx::PointF& point, + base::TimeTicks timestamp, + bool use_enter_event, + bool use_exit_event) { + DCHECK(!(use_enter_event && use_exit_event)); + + // Hovering creates and sends ui::MouseEvents with + // ET_MOUSE_{MOVED,ENTERED,EXITED} types, so do the same here in hovering + // scenarios. + if (GetEventParam() == TestEvent::kTouchEvent && + !Hovering(match_test_hovering_state)) { + ui::EventType event_type = ui::ET_TOUCH_MOVED; + if (use_enter_event) + event_type = ui::ET_TOUCH_PRESSED; + if (use_exit_event) + event_type = ui::ET_TOUCH_RELEASED; + + // Touch needs a pressed event first to properly handle future move + // events. + SendTouchPress(point); + + ui::TouchEvent touch_event( + event_type, point, point, timestamp, + ui::PointerDetails(ui::EventPointerType::kTouch, kPointerId)); + view_->OnTouchEvent(&touch_event); + + // Need to send a new press event after ending the previous touch. + if (use_exit_event) + sent_touch_press_ = false; + } else { + ui::EventPointerType pointer_type = ui::EventPointerType::kMouse; + if (GetEventParam() == TestEvent::kTouchEvent) { + DCHECK(Hovering(match_test_hovering_state)); + pointer_type = ui::EventPointerType::kPen; + } + + ui::EventType event_type = ui::ET_MOUSE_MOVED; + if (use_enter_event) + event_type = ui::ET_MOUSE_ENTERED; + if (use_exit_event) + event_type = ui::ET_MOUSE_EXITED; + + int flags = + Hovering(match_test_hovering_state) ? 0 : ui::EF_LEFT_MOUSE_BUTTON; + ui::MouseEvent mouse_event(event_type, point, point, timestamp, flags, 0, + ui::PointerDetails(pointer_type, kPointerId)); + view_->OnMouseEvent(&mouse_event); + } + } + + MockCompositor* compositor() { return compositor_.get(); } + + int32_t GetExpectedPointerId() const { return kPointerId; } + + private: + void SendTouchPress(const gfx::PointF& requested_touch_location) { + DCHECK(GetEventParam() == TestEvent::kTouchEvent); + if (sent_touch_press_) + return; + + // Location of the press event doesn't matter, so long as it doesn't exactly + // match the location of the subsequent move event. If they match, then the + // move event is dropped. + gfx::PointF point(requested_touch_location.x() + 2.f, + requested_touch_location.y() + 2.f); + + ui::TouchEvent press( + ui::ET_TOUCH_PRESSED, point, point, ui::EventTimeForNow(), + ui::PointerDetails(ui::EventPointerType::kTouch, kPointerId)); + + view_->OnTouchEvent(&press); + sent_touch_press_ = true; + } + + bool Hovering(bool match_test_hovering_state) { + return (GetHoverParam() == HoveringState::kHovering && + match_test_hovering_state) || + (GetHoverParam() == HoveringState::kNotHovering && + !match_test_hovering_state); + } + + // Pointer id to use in these tests. It must be consistent throughout a single + // test for some of the touch variations. + const int32_t kPointerId = 5; + + // Touch events are ignored if a press isn't sent first, so use this to track + // if we have already sent a touch press event yet or not. + bool sent_touch_press_ = false; + + // The real compositor that was contained by the |view_| and must be replaced + // before tear down, and the mock compositor used for getting the delegated + // ink points. + ui::Compositor* real_compositor_; + std::unique_ptr<MockCompositor> compositor_; +}; + +struct DelegatedInkPointTestPassToString { + std::string operator()( + const testing::TestParamInfo<std::tuple<TestEvent, HoveringState>> type) + const { + std::string suffix; + + if (std::get<0>(type.param) == TestEvent::kMouseEvent) + suffix.append("Mouse"); + else + suffix.append("Touch"); + + if (std::get<1>(type.param) == HoveringState::kHovering) + suffix.append("Hovering"); + else + suffix.append("NotHovering"); + + return suffix; + } +}; + +INSTANTIATE_TEST_SUITE_P( + DelegatedInkTrails, + DelegatedInkPointTest, + testing::Combine( + testing::Values(TestEvent::kMouseEvent, TestEvent::kTouchEvent), + testing::Values(HoveringState::kHovering, HoveringState::kNotHovering)), + DelegatedInkPointTestPassToString()); + +// Tests to confirm that input events are correctly forwarded to the UI +// Compositor when DelegatedInkTrails should be drawn, and stops forwarding when +// they no longer should be drawn. +TEST_P(DelegatedInkPointTest, EventForwardedToCompositor) { + // First confirm that the flag is false by default and the point is not sent. + SendEvent(true, gfx::PointF(15, 15)); + MockDelegatedInkPointRenderer* delegated_ink_point_renderer = + compositor()->delegated_ink_point_renderer(); + + EXPECT_FALSE(delegated_ink_point_renderer); + + // Then set it to true and confirm that the DelegatedInkPointRenderer is + // initialized, the connection is made and the point makes it to the renderer. + SetInkMetadataFlagOnRenderFrameMetadata(true); + gfx::DelegatedInkPoint expected_point( + gfx::PointF(10, 10), base::TimeTicks::Now(), GetExpectedPointerId()); + SendEvent(true, expected_point.point(), expected_point.timestamp()); + + delegated_ink_point_renderer = compositor()->delegated_ink_point_renderer(); + EXPECT_TRUE(delegated_ink_point_renderer); + delegated_ink_point_renderer->FlushForTesting(); + + EXPECT_TRUE(delegated_ink_point_renderer->HasDelegatedInkPoint()); + gfx::DelegatedInkPoint actual_point = + delegated_ink_point_renderer->GetDelegatedInkPoint(); + EXPECT_EQ(expected_point.point(), actual_point.point()); + EXPECT_EQ(expected_point.timestamp(), actual_point.timestamp()); + EXPECT_EQ(GetExpectedPointerId(), actual_point.pointer_id()); + + // Then try changing the scale factor to confirm it affects the point + // correctly. + const float scale = 2.6f; + aura_test_helper_->GetTestScreen()->SetDeviceScaleFactor(scale); + gfx::PointF unscaled_point(15, 15); + base::TimeTicks unscaled_time = base::TimeTicks::Now(); + + SendEvent(true, unscaled_point, unscaled_time); + delegated_ink_point_renderer->FlushForTesting(); + + unscaled_point.Scale(scale); + expected_point = gfx::DelegatedInkPoint(unscaled_point, unscaled_time, + GetExpectedPointerId()); + + EXPECT_TRUE(delegated_ink_point_renderer->HasDelegatedInkPoint()); + actual_point = delegated_ink_point_renderer->GetDelegatedInkPoint(); + EXPECT_EQ(expected_point.point(), actual_point.point()); + EXPECT_EQ(expected_point.timestamp(), actual_point.timestamp()); + EXPECT_EQ(GetExpectedPointerId(), actual_point.pointer_id()); + + // Confirm that prediction is reset when the API is no longer being used and + // |delegated_ink_metadata| is not set. + SetInkMetadataFlagOnRenderFrameMetadata(false); + + SendEvent(true, gfx::PointF(25, 25)); + delegated_ink_point_renderer->FlushForTesting(); + + EXPECT_FALSE(delegated_ink_point_renderer->HasDelegatedInkPoint()); + EXPECT_TRUE(delegated_ink_point_renderer->GetPredictionState()); + + // Finally, confirm that nothing is sent after the prediction has been reset + // when the delegated ink flag on the render frame metadata is false. + SendEvent(true, gfx::PointF(46, 46)); + delegated_ink_point_renderer->FlushForTesting(); + + EXPECT_FALSE(delegated_ink_point_renderer->HasDelegatedInkPoint()); + EXPECT_FALSE(delegated_ink_point_renderer->GetPredictionState()); +} + +// Confirm that the interface is rebound if the receiver disconnects. +TEST_P(DelegatedInkPointTest, MojoInterfaceReboundOnDisconnect) { + // First make sure the connection exists. + SetInkMetadataFlagOnRenderFrameMetadata(true); + SendEvent(true, gfx::PointF(15, 15)); + + MockDelegatedInkPointRenderer* delegated_ink_point_renderer = + compositor()->delegated_ink_point_renderer(); + + EXPECT_TRUE(delegated_ink_point_renderer); + EXPECT_TRUE(delegated_ink_point_renderer->ReceiverIsBound()); + + // Reset the receiver and flush the remote to confirm it is no longer bound. + delegated_ink_point_renderer->ResetReceiver(); + view_->FlushForTest(); + + EXPECT_FALSE(delegated_ink_point_renderer->ReceiverIsBound()); + + // Confirm that it now gets reconnected correctly. + SendEvent(true, gfx::PointF(25, 25)); + + delegated_ink_point_renderer = compositor()->delegated_ink_point_renderer(); + + EXPECT_TRUE(delegated_ink_point_renderer); + EXPECT_TRUE(delegated_ink_point_renderer->ReceiverIsBound()); +} + +// Test to confirm that forwarding points to viz will stop and prediction is +// reset if the state of hovering differs between what is expected and the +// received points. +TEST_P(DelegatedInkPointTest, StopForwardingOnHoverStateChange) { + // First send a point and make sure it makes it to the renderer. + SetInkMetadataFlagOnRenderFrameMetadata(true); + SendEvent(true, gfx::PointF(15, 15)); + + MockDelegatedInkPointRenderer* delegated_ink_point_renderer = + compositor()->delegated_ink_point_renderer(); + EXPECT_TRUE(delegated_ink_point_renderer); + delegated_ink_point_renderer->FlushForTesting(); + + EXPECT_TRUE(delegated_ink_point_renderer->HasDelegatedInkPoint()); + delegated_ink_point_renderer->ClearDelegatedInkPoint(); + + // Now send a point that doesn't match the state of hovering on the metadata + // to confirm that it isn't sent and ResetPrediction is called. + SendEvent(false, gfx::PointF(20, 20)); + delegated_ink_point_renderer->FlushForTesting(); + + EXPECT_FALSE(delegated_ink_point_renderer->HasDelegatedInkPoint()); + EXPECT_TRUE(delegated_ink_point_renderer->GetPredictionState()); + + // Send another that doesn't match to confirm the end trail point is only sent + // once. + SendEvent(false, gfx::PointF(25, 25)); + delegated_ink_point_renderer->FlushForTesting(); + EXPECT_FALSE(delegated_ink_point_renderer->HasDelegatedInkPoint()); + + // Send one that does match again to confirm that points will start sending + // again if the hovering state starts matching again. + SendEvent(true, gfx::PointF(30, 30)); + delegated_ink_point_renderer->FlushForTesting(); + + EXPECT_TRUE(delegated_ink_point_renderer->HasDelegatedInkPoint()); + EXPECT_FALSE(delegated_ink_point_renderer->GetPredictionState()); +} + +// Confirm that only move events are forwarded, not enter/exit or equivalent +// events. +TEST_P(DelegatedInkPointTest, IgnoreEnterAndExitEvents) { + // First set everything up and try forwarding a point, confirming that it is + // sent as expected. + SetInkMetadataFlagOnRenderFrameMetadata(true); + gfx::DelegatedInkPoint expected_point( + gfx::PointF(10, 10), base::TimeTicks::Now(), GetExpectedPointerId()); + SendEvent(true, expected_point.point(), expected_point.timestamp()); + + MockDelegatedInkPointRenderer* delegated_ink_point_renderer = + compositor()->delegated_ink_point_renderer(); + EXPECT_TRUE(delegated_ink_point_renderer); + delegated_ink_point_renderer->FlushForTesting(); + + EXPECT_TRUE(delegated_ink_point_renderer->HasDelegatedInkPoint()); + gfx::DelegatedInkPoint actual_point = + delegated_ink_point_renderer->GetDelegatedInkPoint(); + EXPECT_EQ(expected_point.point(), actual_point.point()); + EXPECT_EQ(expected_point.timestamp(), actual_point.timestamp()); + EXPECT_EQ(GetExpectedPointerId(), actual_point.pointer_id()); + + // Try sending an enter event and confirm it is not forwarded. + SendEvent(true, gfx::PointF(12, 12), base::TimeTicks::Now(), + /*use_enter_event*/ true, /*use_exit_event*/ false); + delegated_ink_point_renderer->FlushForTesting(); + EXPECT_FALSE(delegated_ink_point_renderer->HasDelegatedInkPoint()); + + // Now try with an exit event. + SendEvent(true, gfx::PointF(42, 19), base::TimeTicks::Now(), + /*use_enter_event*/ false, /*use_exit_event*/ true); + delegated_ink_point_renderer->FlushForTesting(); + EXPECT_FALSE(delegated_ink_point_renderer->HasDelegatedInkPoint()); + + // Finally, confirm that sending move events will work again without issue. + expected_point = gfx::DelegatedInkPoint( + gfx::PointF(20, 21), base::TimeTicks::Now(), GetExpectedPointerId()); + SendEvent(true, expected_point.point(), expected_point.timestamp()); + + delegated_ink_point_renderer->FlushForTesting(); + + EXPECT_TRUE(delegated_ink_point_renderer->HasDelegatedInkPoint()); + actual_point = delegated_ink_point_renderer->GetDelegatedInkPoint(); + EXPECT_EQ(expected_point.point(), actual_point.point()); + EXPECT_EQ(expected_point.timestamp(), actual_point.timestamp()); + EXPECT_EQ(GetExpectedPointerId(), actual_point.pointer_id()); +} + } // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_view_base.cc b/content/browser/renderer_host/render_widget_host_view_base.cc index 3e66a34e..ec0d6b0 100644 --- a/content/browser/renderer_host/render_widget_host_view_base.cc +++ b/content/browser/renderer_host/render_widget_host_view_base.cc
@@ -988,8 +988,4 @@ transformed_point); } -ui::Compositor* RenderWidgetHostViewBase::GetCompositor() { - return nullptr; -} - } // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_view_base.h b/content/browser/renderer_host/render_widget_host_view_base.h index 6c9aa1e..9e207025 100644 --- a/content/browser/renderer_host/render_widget_host_view_base.h +++ b/content/browser/renderer_host/render_widget_host_view_base.h
@@ -54,7 +54,6 @@ } namespace ui { -class Compositor; enum class DomCode; class LatencyInfo; class TouchEvent; @@ -545,8 +544,6 @@ void SetTooltipObserverForTesting(TooltipObserver* observer); - virtual ui::Compositor* GetCompositor(); - protected: explicit RenderWidgetHostViewBase(RenderWidgetHost* host); ~RenderWidgetHostViewBase() override;
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame.cc b/content/browser/renderer_host/render_widget_host_view_child_frame.cc index 4e26cd2ff..14a83f94 100644 --- a/content/browser/renderer_host/render_widget_host_view_child_frame.cc +++ b/content/browser/renderer_host/render_widget_host_view_child_frame.cc
@@ -1003,10 +1003,4 @@ host()->SynchronizeVisualProperties(); } -ui::Compositor* RenderWidgetHostViewChildFrame::GetCompositor() { - if (!GetRootView()) - return nullptr; - return GetRootView()->GetCompositor(); -} - } // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame.h b/content/browser/renderer_host/render_widget_host_view_child_frame.h index fdcd303..a32e3e0 100644 --- a/content/browser/renderer_host/render_widget_host_view_child_frame.h +++ b/content/browser/renderer_host/render_widget_host_view_child_frame.h
@@ -256,8 +256,6 @@ return weak_factory_.GetWeakPtr(); } - ui::Compositor* GetCompositor() override; - protected: ~RenderWidgetHostViewChildFrame() override;
diff --git a/content/browser/renderer_host/render_widget_host_view_event_handler.cc b/content/browser/renderer_host/render_widget_host_view_event_handler.cc index 68ba083..f4dbe7b3e 100644 --- a/content/browser/renderer_host/render_widget_host_view_event_handler.cc +++ b/content/browser/renderer_host/render_widget_host_view_event_handler.cc
@@ -364,6 +364,69 @@ } } +bool IsMoveEvent(ui::EventType type) { + return type == ui::ET_MOUSE_MOVED || type == ui::ET_MOUSE_DRAGGED || + type == ui::ET_TOUCH_MOVED; +} + +void RenderWidgetHostViewEventHandler::ForwardDelegatedInkPoint( + ui::LocatedEvent* event, + bool hovering, + int32_t pointer_id) { + const cc::RenderFrameMetadata& last_metadata = + host_->render_frame_metadata_provider()->LastRenderFrameMetadata(); + if (IsMoveEvent(event->type()) && + last_metadata.delegated_ink_metadata.has_value() && + hovering == last_metadata.delegated_ink_metadata.value() + .delegated_ink_is_hovering) { + if (!delegated_ink_point_renderer_.is_bound()) { + ui::Compositor* compositor = window_ && window_->layer() + ? window_->layer()->GetCompositor() + : nullptr; + + // The remote can't be bound if the compositor is null, so bail if that + // is the case so we don't crash by trying to use an unbound remote. + if (!compositor) + return; + + TRACE_EVENT_INSTANT0("input", + "Binding mojo interface for delegated ink points.", + TRACE_EVENT_SCOPE_THREAD); + compositor->SetDelegatedInkPointRenderer( + delegated_ink_point_renderer_.BindNewPipeAndPassReceiver()); + delegated_ink_point_renderer_.reset_on_disconnect(); + } + + gfx::PointF point = event->root_location_f(); + point.Scale(host_view_->GetDeviceScaleFactor()); + gfx::DelegatedInkPoint delegated_ink_point(point, event->time_stamp(), + pointer_id); + TRACE_EVENT_INSTANT1("input", + "Forwarding delegated ink point from browser.", + TRACE_EVENT_SCOPE_THREAD, "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 + // the IPC overhead will result in a minor increase in latency for getting + // this event to the renderer. However, by sending it here, the event is + // given the greatest possible chance to make it to viz before + // DrawAndSwap() is called, allowing more points to be drawn as part of + // the delegated ink trail, and thus reducing user perceived latency. + delegated_ink_point_renderer_->StoreDelegatedInkPoint(delegated_ink_point); + ended_delegated_ink_trail_ = false; + } else if (delegated_ink_point_renderer_.is_bound() && + !ended_delegated_ink_trail_) { + // Let viz know that the most recent point it received from us is probably + // the last point the user is inking, so it shouldn't predict anything + // beyond it. + TRACE_EVENT_INSTANT0("input", "Delegated ink trail ended", + TRACE_EVENT_SCOPE_THREAD); + delegated_ink_point_renderer_->ResetPrediction(); + ended_delegated_ink_trail_ = true; + } +} + void RenderWidgetHostViewEventHandler::OnMouseEvent(ui::MouseEvent* event) { TRACE_EVENT0("input", "RenderWidgetHostViewBase::OnMouseEvent"); @@ -407,6 +470,9 @@ bool is_selection_popup = NeedsInputGrab(popup_child_host_view_); if (CanRendererHandleEvent(event, mouse_locked_, is_selection_popup) && !(event->flags() & ui::EF_FROM_TOUCH)) { + bool hovering = (event->type() ^ ui::ET_MOUSE_DRAGGED) && + (event->type() ^ ui::ET_MOUSE_PRESSED); + ForwardDelegatedInkPoint(event, hovering, event->pointer_details().id); // Confirm existing composition text on mouse press, to make sure // the input caret won't be moved with an ongoing composition text. @@ -531,6 +597,9 @@ if (handled) return; + ForwardDelegatedInkPoint(event, event->hovering(), + event->pointer_details().id); + if (had_no_pointer) delegate_->selection_controller_client()->OnTouchDown(); if (!pointer_state_.GetPointerCount())
diff --git a/content/browser/renderer_host/render_widget_host_view_event_handler.h b/content/browser/renderer_host/render_widget_host_view_event_handler.h index 6d41f4d..65dbc6313 100644 --- a/content/browser/renderer_host/render_widget_host_view_event_handler.h +++ b/content/browser/renderer_host/render_widget_host_view_event_handler.h
@@ -12,12 +12,14 @@ #include "content/browser/renderer_host/input/mouse_wheel_phase_handler.h" #include "content/common/content_export.h" #include "content/public/browser/native_web_keyboard_event.h" +#include "mojo/public/cpp/bindings/remote.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/public/mojom/input/pointer_lock_result.mojom.h" #include "ui/aura/scoped_enable_unadjusted_mouse_events.h" #include "ui/aura/scoped_keyboard_hook.h" #include "ui/events/event_handler.h" #include "ui/events/gestures/motion_event_aura.h" +#include "ui/gfx/mojom/delegated_ink_point_renderer.mojom.h" #include "ui/latency/latency_info.h" namespace aura { @@ -252,6 +254,15 @@ void HandleMouseWheelEvent(ui::MouseEvent* event); + // Forward the location and timestamp of the event to viz if a delegated ink + // trail is requested. + void ForwardDelegatedInkPoint(ui::LocatedEvent* event, + bool hovering, + int32_t pointer_id); + + // Flush the remote for testing purposes. + void FlushForTest() { delegated_ink_point_renderer_.FlushForTesting(); } + // Whether return characters should be passed on to the RenderWidgetHostImpl. bool accept_return_character_ = false; @@ -314,6 +325,18 @@ std::unique_ptr<HitTestDebugKeyEventObserver> debug_observer_; + // Remote end of the connection for sending delegated ink points to viz to + // support the delegated ink trails feature. + mojo::Remote<gfx::mojom::DelegatedInkPointRenderer> + delegated_ink_point_renderer_; + // Used to know if we have already told viz to reset prediction because the + // final point of the delegated ink trail has been sent. True when prediction + // has already been reset for the most recent trail, false otherwise. This + // flag helps make sure that we don't send more IPCs than necessary to viz to + // reset prediction. Sending extra IPCs wouldn't impact correctness, but can + // impact performance due to the IPC overhead. + bool ended_delegated_ink_trail_ = false; + DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewEventHandler); };
diff --git a/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm b/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm index ea91436..74b55dea 100644 --- a/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm +++ b/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm
@@ -482,8 +482,6 @@ mock_clock_.Advance(base::TimeDelta::FromMilliseconds(100)); ui::SetEventTickClockForTesting(&mock_clock_); RenderViewHostImplTestHarness::SetUp(); - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature(features::kDirectManipulationStylus); browser_context_ = std::make_unique<TestBrowserContext>(); process_host_ = @@ -1092,78 +1090,6 @@ GetPointerType(events)); } -TEST_F(RenderWidgetHostViewMacTest, PointerEventWithPenTypeSendAsTouch) { - // Send a NSEvent of NSTabletProximity type which has a device type of pen. - NSEvent* event = MockTabletEventWithParams(kCGEventTabletProximity, true, - NSPenPointingDevice); - [rwhv_mac_->GetInProcessNSView() tabletEvent:event]; - // Flush and clear other messages (e.g. begin frames) the RWHVMac also sends. - base::RunLoop().RunUntilIdle(); - static_cast<RenderWidgetHostImpl*>(rwhv_mac_->GetRenderWidgetHost()) - ->input_router() - ->ForceSetTouchActionAuto(); - - event = MockMouseEventWithParams( - kCGEventLeftMouseDown, {6, 9}, kCGMouseButtonLeft, - kCGEventMouseSubtypeTabletPoint, false, true); - [rwhv_mac_->GetInProcessNSView() mouseEvent:event]; - base::RunLoop().RunUntilIdle(); - MockWidgetInputHandler::MessageVector events = - host_->GetAndResetDispatchedMessages(); - ASSERT_EQ("TouchStart", GetMessageNames(events)); - EXPECT_EQ(blink::WebPointerProperties::PointerType::kPen, - GetPointerType(events)); - events.clear(); - base::RunLoop().RunUntilIdle(); - events = host_->GetAndResetDispatchedMessages(); - - event = MockMouseEventWithParams( - kCGEventLeftMouseDragged, {16, 29}, kCGMouseButtonLeft, - kCGEventMouseSubtypeTabletPoint, false, true); - [rwhv_mac_->GetInProcessNSView() mouseEvent:event]; - base::RunLoop().RunUntilIdle(); - events = host_->GetAndResetDispatchedMessages(); - ASSERT_EQ("TouchMove", GetMessageNames(events)); - EXPECT_EQ(blink::WebPointerProperties::PointerType::kPen, - GetPointerType(events)); - - events.clear(); - base::RunLoop().RunUntilIdle(); - events = host_->GetAndResetDispatchedMessages(); - - event = MockMouseEventWithParams(kCGEventLeftMouseUp, {16, 29}, - kCGMouseButtonLeft, - kCGEventMouseSubtypeTabletPoint, false); - [rwhv_mac_->GetInProcessNSView() mouseEvent:event]; - base::RunLoop().RunUntilIdle(); - events = host_->GetAndResetDispatchedMessages(); - ASSERT_EQ("TouchEnd", GetMessageNames(events)); - EXPECT_EQ(blink::WebPointerProperties::PointerType::kPen, - static_cast<const blink::WebTouchEvent&>( - events[0]->ToEvent()->Event()->Event()) - .touches[0] - .pointer_type); - - events.clear(); - base::RunLoop().RunUntilIdle(); - events = host_->GetAndResetDispatchedMessages(); - ASSERT_EQ("GestureScrollEnd", GetMessageNames(events)); - - event = - MockMouseEventWithParams(kCGEventLeftMouseDown, {6, 9}, - kCGMouseButtonLeft, kCGEventMouseSubtypeDefault); - [rwhv_mac_->GetInProcessNSView() mouseEvent:event]; - base::RunLoop().RunUntilIdle(); - events = host_->GetAndResetDispatchedMessages(); - ASSERT_EQ("MouseDown", GetMessageNames(events)); - EXPECT_EQ(blink::WebPointerProperties::PointerType::kMouse, - GetPointerType(events)); - - events.clear(); - base::RunLoop().RunUntilIdle(); - events = host_->GetAndResetDispatchedMessages(); -} - TEST_F(RenderWidgetHostViewMacTest, SendMouseMoveOnShowingContextMenu) { rwhv_mac_->SetShowingContextMenu(true); base::RunLoop().RunUntilIdle();
diff --git a/content/browser/site_per_process_hit_test_browsertest.cc b/content/browser/site_per_process_hit_test_browsertest.cc index 556a1838..05e9add2 100644 --- a/content/browser/site_per_process_hit_test_browsertest.cc +++ b/content/browser/site_per_process_hit_test_browsertest.cc
@@ -18,7 +18,6 @@ #include "base/test/scoped_feature_list.h" #include "base/test/test_timeouts.h" #include "build/build_config.h" -#include "components/viz/common/features.h" #include "components/viz/test/host_frame_sink_manager_test_api.h" #include "content/browser/compositor/surface_utils.h" #include "content/browser/renderer_host/cursor_manager.h" @@ -7329,130 +7328,4 @@ EXPECT_EQ(kSlowHitTestFlags, hit_test_data[2].flags); } -#if defined(USE_AURA) -class SitePerProcessDelegatedInkBrowserTest - : public SitePerProcessHitTestBrowserTest { - public: - SitePerProcessDelegatedInkBrowserTest() = default; - - void SetUpCommandLine(base::CommandLine* command_line) override { - SitePerProcessHitTestBrowserTest::SetUpCommandLine(command_line); - command_line->AppendSwitchASCII(switches::kEnableBlinkFeatures, - "DelegatedInkTrails"); - } -}; - -// Test confirms that a point hitting an OOPIF that is requesting delegated ink -// trails results in the metadata being correctly sent to the child's -// RenderWidgetHost and is usable for sending delegated ink points. -IN_PROC_BROWSER_TEST_F(SitePerProcessDelegatedInkBrowserTest, - MetadataAndPointGoThroughOOPIF) { - // Delegated ink is only supported on Skia Renderer for now. - if (!features::IsUsingSkiaRenderer()) - return; - - GURL main_url(embedded_test_server()->GetURL( - "/frame_tree/page_with_positioned_frame.html")); - EXPECT_TRUE(NavigateToURL(shell(), main_url)); - - FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) - ->GetFrameTree() - ->root(); - ASSERT_EQ(1U, root->child_count()); - - FrameTreeNode* child = root->child_at(0); - - GURL site_url(embedded_test_server()->GetURL("baz.com", "/title1.html")); - EXPECT_EQ(site_url, child->current_url()); - EXPECT_NE(shell()->web_contents()->GetSiteInstance(), - child->current_frame_host()->GetSiteInstance()); - - // Make sure the child frame is indeed a OOPIF - EXPECT_TRUE(child->current_frame_host()->IsCrossProcessSubframe()); - - EXPECT_TRUE(ExecJs(child->current_frame_host(), R"( - let presenter = null; - navigator.ink.requestPresenter('delegated-ink-trail').then(e => { - presenter = e; - }); - let style = { color: 'green', diameter: 21 }; - - window.addEventListener('pointermove' , evt => { - presenter.updateInkTrailStartPoint(evt, style); - document.write('Force a new frame so that an updated ' + - 'RenderFrameMetadata is sent to the browser process.'); - }); - )")); - - RenderWidgetHostImpl* root_rwh = - root->current_frame_host()->GetRenderWidgetHost(); - RenderWidgetHostImpl* child_rwh = - child->current_frame_host()->GetRenderWidgetHost(); - - // Create listeners for mouse events. - RenderWidgetHostMouseEventMonitor main_frame_monitor(root_rwh); - RenderWidgetHostMouseEventMonitor child_frame_monitor(child_rwh); - - WaitForHitTestData(child->current_frame_host()); - - RenderWidgetHostViewBase* root_view = - static_cast<RenderWidgetHostViewBase*>(root_rwh->GetView()); - RenderWidgetHostViewBase* rwhv_child = - static_cast<RenderWidgetHostViewBase*>(child_rwh->GetView()); - - RenderWidgetHostInputEventRouter* router = - web_contents()->GetInputEventRouter(); - - EXPECT_FALSE(router->IsDelegatedInkRendererBoundForTest()); - - // Target MouseMove to child frame. - blink::WebMouseEvent mouse_event( - blink::WebInputEvent::Type::kMouseMove, - blink::WebInputEvent::kNoModifiers, - blink::WebInputEvent::GetStaticTimeStampForTests()); - SetWebEventPositions(&mouse_event, gfx::Point(55, 55), root_view); - - RouteMouseEventAndWaitUntilDispatch(router, root_view, rwhv_child, - &mouse_event); - - // Dispatch twice because the router generates an extra MouseLeave for the - // main frame. - main_frame_monitor.ResetEventReceived(); - child_frame_monitor.ResetEventReceived(); - - RouteMouseEventAndWaitUntilDispatch(router, root_view, rwhv_child, - &mouse_event); - EXPECT_FALSE(main_frame_monitor.EventWasReceived()); - EXPECT_TRUE(child_frame_monitor.EventWasReceived()); - - // Wait for the child to receive and process input so that the new - // RenderFrameMetadata is sent to the browser process. - { - auto observer = std::make_unique<MainThreadFrameObserver>(child_rwh); - observer->Wait(); - } - - // Confirm that the metadata is what we expect and accessible from the child's - // RenderWidgetHost. - const cc::RenderFrameMetadata& last_metadata = - child_rwh->render_frame_metadata_provider()->LastRenderFrameMetadata(); - EXPECT_TRUE(last_metadata.delegated_ink_metadata.has_value()); - EXPECT_TRUE( - last_metadata.delegated_ink_metadata.value().delegated_ink_is_hovering); - - // Send one more mouse move event and confirm that it causes the forwarding - // to occur, which will result in the |delegated_ink_point_renderer_| mojom - // remote being bound. - main_frame_monitor.ResetEventReceived(); - child_frame_monitor.ResetEventReceived(); - SetWebEventPositions(&mouse_event, gfx::Point(57, 57), root_view); - RouteMouseEventAndWaitUntilDispatch(router, root_view, rwhv_child, - &mouse_event); - - EXPECT_FALSE(main_frame_monitor.EventWasReceived()); - EXPECT_TRUE(child_frame_monitor.EventWasReceived()); - EXPECT_TRUE(router->IsDelegatedInkRendererBoundForTest()); -} -#endif // USE_AURA - } // namespace content
diff --git a/content/browser/storage_partition_impl_unittest.cc b/content/browser/storage_partition_impl_unittest.cc index ab16fbf..4b76522 100644 --- a/content/browser/storage_partition_impl_unittest.cc +++ b/content/browser/storage_partition_impl_unittest.cc
@@ -1892,7 +1892,8 @@ .SetExpiry(base::TimeDelta::FromDays(2)) .Build()); conversion_manager->HandleConversion( - StorableConversion(123, net::SchemefulSite(conv), reporter)); + StorableConversion(123, net::SchemefulSite(conv), reporter, + /*event_source_trigger_data=*/0)); } EXPECT_EQ(5u, GetConversionsToReportForTesting(conversion_manager,
diff --git a/content/browser/tracing/startup_tracing_browsertest.cc b/content/browser/tracing/startup_tracing_browsertest.cc index 44c9db4..20a45fd 100644 --- a/content/browser/tracing/startup_tracing_browsertest.cc +++ b/content/browser/tracing/startup_tracing_browsertest.cc
@@ -326,6 +326,12 @@ CheckOutput(GetExpectedPath(), GetOutputType()); } +IN_PROC_BROWSER_TEST_P(StartupTracingTest, ContinueAtShutdown) { + EXPECT_TRUE(NavigateToURL(shell(), GetTestUrl("", "title1.html"))); + StartupTracingController::GetInstance() + .set_continue_on_shutdown_for_testing(); +} + class EmergencyStopTracingTest : public StartupTracingTest {}; INSTANTIATE_TEST_SUITE_P(
diff --git a/content/browser/tracing/startup_tracing_controller.cc b/content/browser/tracing/startup_tracing_controller.cc index 7cc95b6..5957d39 100644 --- a/content/browser/tracing/startup_tracing_controller.cc +++ b/content/browser/tracing/startup_tracing_controller.cc
@@ -511,6 +511,15 @@ run_loop.Run(); } +void StartupTracingController::ShutdownAndWaitForStopIfNeeded() { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + if (should_continue_on_shutdown_) + return; + + WaitUntilStopped(); +} + // static void StartupTracingController::EmergencyStop() { if (GetIOThreadTaskRunner({})->RunsTasksInCurrentSequence()) {
diff --git a/content/browser/tracing/startup_tracing_controller.h b/content/browser/tracing/startup_tracing_controller.h index fcbbc4d28..492a036c 100644 --- a/content/browser/tracing/startup_tracing_controller.h +++ b/content/browser/tracing/startup_tracing_controller.h
@@ -31,6 +31,7 @@ void StartIfNeeded(); void WaitUntilStopped(); + void ShutdownAndWaitForStopIfNeeded(); // By default, a trace is written into a temporary file which then is renamed, // however this can lead to data loss when the browser process crashes. @@ -68,6 +69,10 @@ bool is_finished_for_testing() const { return state_ == State::kStopped; } + void set_continue_on_shutdown_for_testing() { + should_continue_on_shutdown_ = true; + } + private: void Stop(base::OnceClosure on_finished_callback); @@ -92,6 +97,8 @@ std::string default_basename_; bool basename_for_test_set_ = false; + // Used for testing only + bool should_continue_on_shutdown_ = false; TempFilePolicy temp_file_policy_ = TempFilePolicy::kUseTemporaryFile; };
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index 5572f096..15621d2 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc
@@ -1179,21 +1179,6 @@ return GetRenderManager(); } -bool WebContentsImpl::OnMessageReceived(RenderViewHostImpl* render_view_host, - const IPC::Message& message) { - OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::OnMessageReceived", - "render_view_host", render_view_host); - for (auto& observer : observers_.observer_list()) { - // TODO(nick, creis): https://crbug.com/758026: Replace all uses of this - // variant of OnMessageReceived with the version that takes a - // RenderFrameHost, and then delete it. - if (observer.OnMessageReceived(message)) - return true; - } - - return false; -} - bool WebContentsImpl::OnMessageReceived(RenderFrameHostImpl* render_frame_host, const IPC::Message& message) { OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::OnMessageReceived", @@ -2616,8 +2601,7 @@ // TODO(dtapuska): Enable barrel button selection drag support on Android. // crbug.com/758042 #if defined(OS_WIN) - prefs.barrel_button_for_drag_enabled = - base::FeatureList::IsEnabled(features::kDirectManipulationStylus); + prefs.barrel_button_for_drag_enabled = true; #endif // defined(OS_WIN) prefs.enable_scroll_animator =
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h index f5318f70..9152a4d 100644 --- a/content/browser/web_contents/web_contents_impl.h +++ b/content/browser/web_contents/web_contents_impl.h
@@ -813,8 +813,6 @@ // RenderViewHostDelegate ---------------------------------------------------- RenderViewHostDelegateView* GetDelegateView() override; - bool OnMessageReceived(RenderViewHostImpl* render_view_host, - const IPC::Message& message) override; // RenderFrameHostDelegate has the same method, so list it there because this // interface is going away. // WebContents* GetAsWebContents() override;
diff --git a/content/public/browser/browser_context.h b/content/public/browser/browser_context.h index e42b740..2d9cc0c 100644 --- a/content/public/browser/browser_context.h +++ b/content/public/browser/browser_context.h
@@ -25,6 +25,7 @@ #include "third_party/blink/public/mojom/blob/blob.mojom-forward.h" #include "third_party/blink/public/mojom/push_messaging/push_messaging.mojom-forward.h" #include "third_party/blink/public/mojom/push_messaging/push_messaging_status.mojom-forward.h" +#include "third_party/perfetto/include/perfetto/tracing/traced_proto.h" #include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h" #if !defined(OS_ANDROID) @@ -61,6 +62,14 @@ class VariationsClient; } // namespace variations +namespace perfetto { +namespace protos { +namespace pbzero { +class ChromeBrowserContext; +} +} // namespace protos +} // namespace perfetto + namespace content { class BackgroundFetchDelegate; @@ -270,6 +279,11 @@ // Write a representation of this object into a trace. void WriteIntoTrace(perfetto::TracedValue context); + // Write a representation of this object into tracing proto. + void WriteIntoTrace( + perfetto::TracedProto<perfetto::protos::pbzero::ChromeBrowserContext> + context); + ////////////////////////////////////////////////////////////////////////////// // The //content embedder can override the methods below to change or extend // how the //content layer interacts with a BrowserContext.
diff --git a/content/public/browser/web_contents_observer.cc b/content/public/browser/web_contents_observer.cc index b6754c23..b068bd5 100644 --- a/content/public/browser/web_contents_observer.cc +++ b/content/public/browser/web_contents_observer.cc
@@ -43,10 +43,6 @@ return false; } -bool WebContentsObserver::OnMessageReceived(const IPC::Message& message) { - return false; -} - void WebContentsObserver::ResetWebContents() { static_cast<WebContentsImpl*>(web_contents_)->RemoveObserver(this); web_contents_ = nullptr;
diff --git a/content/public/browser/web_contents_observer.h b/content/public/browser/web_contents_observer.h index 6c2b6e4..3fc353f 100644 --- a/content/public/browser/web_contents_observer.h +++ b/content/public/browser/web_contents_observer.h
@@ -18,7 +18,6 @@ #include "content/public/browser/navigation_controller.h" #include "content/public/browser/reload_type.h" #include "content/public/browser/visibility.h" -#include "ipc/ipc_listener.h" #include "mojo/public/cpp/system/message_pipe.h" #include "services/network/public/mojom/fetch_api.mojom-forward.h" #include "services/service_manager/public/cpp/bind_source_info.h" @@ -77,7 +76,7 @@ // // TODO(creis, jochen): Hide the fact that there are several RenderViewHosts // from the WebContentsObserver API. http://crbug.com/173325 -class CONTENT_EXPORT WebContentsObserver : public IPC::Listener { +class CONTENT_EXPORT WebContentsObserver { public: // Frames and Views ---------------------------------------------------------- @@ -703,13 +702,6 @@ virtual void OnServiceWorkerAccessed(NavigationHandle* navigation_handle, const GURL& scope, AllowServiceWorkerResult allowed) {} - // IPC::Listener implementation. - // DEPRECATED: Use (i.e. override) the other overload instead: - // virtual bool OnMessageReceived(const IPC::Message& message, - // RenderFrameHost* render_frame_host); - // TODO(https://crbug.com/758026): Delete this overload when possible. - bool OnMessageReceived(const IPC::Message& message) override; - WebContents* web_contents() const; protected: @@ -722,7 +714,7 @@ // observing. WebContentsObserver(); - ~WebContentsObserver() override; + virtual ~WebContentsObserver(); // Start observing a different WebContents; used with the default constructor. void Observe(WebContents* web_contents);
diff --git a/content/public/common/content_switch_dependent_feature_overrides.cc b/content/public/common/content_switch_dependent_feature_overrides.cc index 763db06..47fb1cc8 100644 --- a/content/public/common/content_switch_dependent_feature_overrides.cc +++ b/content/public/common/content_switch_dependent_feature_overrides.cc
@@ -29,8 +29,12 @@ {switches::kAppCacheForceEnabled, std::cref(blink::features::kAppCacheRequireOriginTrial), base::FeatureList::OVERRIDE_DISABLE_FEATURE}, + // Overrides for --enable-experimental-web-platform-features. {switches::kEnableExperimentalWebPlatformFeatures, + std::cref(net::features::kCookieSameSiteConsidersRedirectChain), + base::FeatureList::OVERRIDE_ENABLE_FEATURE}, + {switches::kEnableExperimentalWebPlatformFeatures, std::cref(network::features::kCrossOriginEmbedderPolicyCredentialless), base::FeatureList::OVERRIDE_ENABLE_FEATURE}, {switches::kEnableExperimentalWebPlatformFeatures, @@ -84,6 +88,9 @@ // Overrides for --enable-experimental-cookie-features. {switches::kEnableExperimentalCookieFeatures, + std::cref(net::features::kCookieSameSiteConsidersRedirectChain), + base::FeatureList::OVERRIDE_ENABLE_FEATURE}, + {switches::kEnableExperimentalCookieFeatures, std::cref(net::features::kCookiesWithoutSameSiteMustBeSecure), base::FeatureList::OVERRIDE_ENABLE_FEATURE}, {switches::kEnableExperimentalCookieFeatures,
diff --git a/content/renderer/accessibility/render_accessibility_impl.cc b/content/renderer/accessibility/render_accessibility_impl.cc index 99f0ec20..7373213 100644 --- a/content/renderer/accessibility/render_accessibility_impl.cc +++ b/content/renderer/accessibility/render_accessibility_impl.cc
@@ -429,7 +429,6 @@ reset_token_ = reset_token; serializer_->Reset(); pending_events_.clear(); - dirty_objects_.clear(); const WebDocument& document = GetMainDocument(); if (!document.IsNull()) { @@ -451,13 +450,11 @@ void RenderAccessibilityImpl::MarkWebAXObjectDirty( const WebAXObject& obj, bool subtree, - ax::mojom::Action event_from_action, - std::vector<ui::AXEventIntent> event_intents) { + ax::mojom::Action event_from_action) { DirtyObject dirty_object; dirty_object.obj = obj; dirty_object.event_from = ax::mojom::EventFrom::kAction; dirty_object.event_from_action = event_from_action; - dirty_object.event_intents = event_intents; dirty_objects_.push_back(dirty_object); if (subtree) @@ -512,10 +509,6 @@ if (IsImmediateProcessingRequiredForEvent(event)) event_schedule_mode_ = EventScheduleMode::kProcessEventsImmediately; - if (ShouldSerializeNodeForEvent(obj, event)) - MarkWebAXObjectDirty(obj, false, event.event_from_action, - event.event_intents); - ScheduleSendPendingAccessibilityEvents(); } @@ -603,17 +596,6 @@ if (obj.IsDetached()) return false; - // If we were to return true for kLayoutComplete, that means calling - // MarkWebAXObjectDirty on the root node (since kLayoutComplete is fired - // on the root), and because the root is focusable, MarkWebAXObjectDirty - // sets the event schedule mode to kProcessEventsImmediately, which is - // inefficient. So it's best to not actually serialize a node in response - // to a kLayoutComplete event, but note that it will still ensure that a - // lower-priority update is scheduled, which will serialize any nodes whose - // bounding boxes have changed. - if (event.event_type == ax::mojom::Event::kLayoutComplete) - return false; - if (event.event_type == ax::mojom::Event::kTextSelectionChanged && !obj.IsAtomicTextField()) { // Selection changes on non-atomic text fields cause no change to the @@ -787,7 +769,6 @@ pending_events_.insert( pending_events_.begin(), ui::AXEvent(root_obj.AxID(), ax::mojom::Event::kLayoutComplete)); - MarkWebAXObjectDirty(root_obj, false); // If loaded and has some content, insert load complete at the top, so that // screen readers are informed a new document is ready. @@ -893,18 +874,88 @@ continue; } + auto obj = WebAXObject::FromWebDocumentByID(document, event.id); + + // Make sure the object still exists. + // TODO(accessibility) Change this to CheckValidity() if there aren't crash + // reports of illegal lifecycle changes from WebDisallowTransitionScope. + if (!obj.MaybeUpdateLayoutAndCheckValidity()) + continue; + + // Make sure it's a descendant of our root node - exceptions include the + // scroll area that's the parent of the main document (we ignore it), and + // possibly nodes attached to a different document. + // TODO(accessibility) Remove once it's clear this never triggers. +#if defined(AX_FAIL_FAST_BUILD) + SANITIZER_CHECK(tree_source_->IsInTree(obj)) + << "\n* Object not in tree: " << obj.ToString(true).Utf8(); +#endif + + // If it's ignored, find the first ancestor that's not ignored. + // + // Note that "IsDetached()" also calls "IsNull()". Additionally, + // "ParentObject()" always gets the first ancestor that is included in tree + // (ignored or unignored), so it will never return objects that are not + // included in the tree at all. + if (!obj.IsDetached() && !obj.AccessibilityIsIncludedInTree()) + obj = obj.ParentObject(); + for (; !obj.IsDetached() && obj.AccessibilityIsIgnored(); + obj = obj.ParentObject()) { + // There are 3 states of nodes that we care about here. + // (x) Unignored, included in tree + // [x] Ignored, included in tree + // <x> Ignored, excluded from tree + // + // Consider the following tree : + // ++(0) Role::kRootWebArea + // ++++<1> Role::kNone + // ++++++[2] Role::kGenericContainer <body> + // ++++++++[3] Role::kGenericContainer with 'visibility: hidden' + // + // If we modify [3] to be 'visibility: visible', we will receive + // Event::kChildrenChanged here for the Ignored parent [2]. + // We must re-serialize the Unignored parent node (0) due to this + // change, but we must also re-serialize [2] since its children + // have changed. <1> was never part of the ax tree, and therefore + // does not need to be serialized. + // Note that [3] will be serialized to (3) during : + // |AXTreeSerializer<>::SerializeChangedNodes| when node [2] is + // being serialized, since it will detect the Ignored state had + // changed. + // + // Similarly, during Event::kTextChanged, if any Ignored, + // but included in tree ancestor uses NameFrom::kContents, + // they must also be re-serialized in case the name changed. + if (ShouldSerializeNodeForEvent(obj, event)) { + DirtyObject dirty_object; + dirty_object.obj = obj; + dirty_object.event_from = event.event_from; + dirty_object.event_from_action = event.event_from_action; + dirty_object.event_intents = event.event_intents; + dirty_objects.push_back(dirty_object); + } + } + events.push_back(event); VLOG(1) << "Accessibility event: " << ui::ToString(event.event_type) << " on node id " << event.id; + + // Some events don't cause any changes to their associated objects. + if (ShouldSerializeNodeForEvent(obj, event)) { + DirtyObject dirty_object; + dirty_object.obj = obj; + dirty_object.event_from = event.event_from; + dirty_object.event_from_action = event.event_from_action; + dirty_object.event_intents = event.event_intents; + dirty_objects.push_back(dirty_object); + } } // Now serialize all dirty objects. Keep track of IDs serialized // so we don't have to serialize the same node twice. std::set<int32_t> already_serialized_ids; - for (size_t i = 0; i < dirty_objects.size(); ++i) { - DirtyObject current_dirty_object = dirty_objects[i]; - + for (const DirtyObject& current_dirty_object : dirty_objects) { auto obj = current_dirty_object.obj; // Dirty objects can be added using MarkWebAXObjectDirty(obj) from other // parts of the code as well, so we need to ensure the object still exists. @@ -926,52 +977,6 @@ if (already_serialized_ids.find(obj.AxID()) != already_serialized_ids.end()) continue; - // If it's ignored, find the first ancestor that's not ignored and - // mark all ancestors along the way as dirty. - if (obj.AccessibilityIsIgnored()) { - WebAXObject ancestor = obj; - for (; !ancestor.IsDetached() && ancestor.AccessibilityIsIgnored(); - ancestor = ancestor.ParentObject()) { - // There are 3 states of nodes that we care about here. - // (x) Unignored, included in tree - // [x] Ignored, included in tree - // <x> Ignored, excluded from tree - // - // Consider the following tree : - // ++(0) Role::kRootWebArea - // ++++<1> Role::kNone - // ++++++[2] Role::kGenericContainer <body> - // ++++++++[3] Role::kGenericContainer with 'visibility: hidden' - // - // If we modify [3] to be 'visibility: visible', we will receive - // Event::kChildrenChanged here for the Ignored parent [2]. - // We must re-serialize the Unignored parent node (0) due to this - // change, but we must also re-serialize [2] since its children - // have changed. <1> was never part of the ax tree, and therefore - // does not need to be serialized. - // Note that [3] will be serialized to (3) during : - // |AXTreeSerializer<>::SerializeChangedNodes| when node [2] is - // being serialized, since it will detect the Ignored state had - // changed. - // - // Similarly, during Event::kTextChanged, if any Ignored, - // but included in tree ancestor uses NameFrom::kContents, - // they must also be re-serialized in case the name changed. - DirtyObject dirty_object; - dirty_object.obj = ancestor; - dirty_object.event_from = current_dirty_object.event_from; - dirty_object.event_from_action = current_dirty_object.event_from_action; - dirty_object.event_intents = current_dirty_object.event_intents; - dirty_objects.push_back(dirty_object); - } - DirtyObject dirty_object; - dirty_object.obj = ancestor; - dirty_object.event_from = current_dirty_object.event_from; - dirty_object.event_from_action = current_dirty_object.event_from_action; - dirty_object.event_intents = current_dirty_object.event_intents; - dirty_objects.push_back(dirty_object); - } - ui::AXTreeUpdate update; update.event_from = current_dirty_object.event_from; update.event_from_action = current_dirty_object.event_from_action;
diff --git a/content/renderer/accessibility/render_accessibility_impl.h b/content/renderer/accessibility/render_accessibility_impl.h index f1004a5e..6365bdf 100644 --- a/content/renderer/accessibility/render_accessibility_impl.h +++ b/content/renderer/accessibility/render_accessibility_impl.h
@@ -113,8 +113,7 @@ void MarkWebAXObjectDirty( const blink::WebAXObject& obj, bool subtree, - ax::mojom::Action event_from_action = ax::mojom::Action::kNone, - std::vector<ui::AXEventIntent> event_intents = {}); + ax::mojom::Action event_from_action = ax::mojom::Action::kNone); void HandleAXEvent(const ui::AXEvent& event);
diff --git a/content/renderer/accessibility/render_accessibility_impl_browsertest.cc b/content/renderer/accessibility/render_accessibility_impl_browsertest.cc index 84323f4..0f55b53 100644 --- a/content/renderer/accessibility/render_accessibility_impl_browsertest.cc +++ b/content/renderer/accessibility/render_accessibility_impl_browsertest.cc
@@ -432,7 +432,7 @@ WebDocument document = GetMainFrame()->GetDocument(); WebAXObject root_obj = WebAXObject::FromWebDocument(document); GetRenderAccessibilityImpl()->HandleAXEvent( - ui::AXEvent(root_obj.AxID(), ax::mojom::Event::kChildrenChanged)); + ui::AXEvent(root_obj.AxID(), ax::mojom::Event::kLayoutComplete)); SendPendingAccessibilityEvents(); EXPECT_EQ(1, CountAccessibilityNodesSentToBrowser()); {
diff --git a/content/renderer/media/batching_media_log.cc b/content/renderer/media/batching_media_log.cc index 3023fb1..8d8c5cb2 100644 --- a/content/renderer/media/batching_media_log.cc +++ b/content/renderer/media/batching_media_log.cc
@@ -8,14 +8,11 @@ #include "base/bind.h" #include "base/json/json_writer.h" -#include "base/location.h" #include "base/logging.h" #include "base/single_thread_task_runner.h" -#include "base/threading/thread_task_runner_handle.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_util.h" #include "base/time/default_tick_clock.h" -#include "content/public/common/content_client.h" -#include "content/public/renderer/content_renderer_client.h" -#include "content/public/renderer/render_thread.h" #include "media/base/logging_override_if_enabled.h" namespace { @@ -60,8 +57,6 @@ last_ipc_send_time_(tick_clock_->NowTicks()), ipc_send_pending_(false), logged_rate_limit_warning_(false) { - DCHECK(RenderThread::Get()) - << "BatchingMediaLog must be constructed on the render thread"; // Pre-bind the WeakPtr on the right thread since we'll receive calls from // other threads and don't want races. weak_this_ = weak_factory_.GetWeakPtr();
diff --git a/content/renderer/media/render_media_event_handler.cc b/content/renderer/media/render_media_event_handler.cc index 220d293d..fef52e4 100644 --- a/content/renderer/media/render_media_event_handler.cc +++ b/content/renderer/media/render_media_event_handler.cc
@@ -12,7 +12,11 @@ GetMediaInternalRecordLogRemote().Log(events_to_send); } -RenderMediaEventHandler::RenderMediaEventHandler() = default; +RenderMediaEventHandler::RenderMediaEventHandler() { + DCHECK(RenderThread::Get()) + << "RenderMediaEventHandler must be constructed on the render thread"; +} + RenderMediaEventHandler::~RenderMediaEventHandler() = default; // This media log doesn't care, since the RenderThread outlives us for
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc index a61bf4db..19aba494 100644 --- a/content/renderer/render_thread_impl.cc +++ b/content/renderer/render_thread_impl.cc
@@ -631,9 +631,9 @@ // but the system default is true. #if defined(OS_MAC) is_elastic_overscroll_enabled_ = true; -#elif defined(OS_WIN) +#elif defined(OS_WIN) || defined(OS_ANDROID) is_elastic_overscroll_enabled_ = - base::FeatureList::IsEnabled(features::kElasticOverscrollWin); + base::FeatureList::IsEnabled(features::kElasticOverscroll); #else is_elastic_overscroll_enabled_ = false; #endif
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc index 074db7fb..2b4cf709 100644 --- a/content/renderer/renderer_blink_platform_impl.cc +++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -1034,11 +1034,15 @@ // sent back to the Browser via Mojo objects bound to |owner_task_runner|. std::unique_ptr<media::MediaLog> RendererBlinkPlatformImpl::GetMediaLog( blink::MediaInspectorContext* inspector_context, - scoped_refptr<base::SingleThreadTaskRunner> owner_task_runner) { + scoped_refptr<base::SingleThreadTaskRunner> owner_task_runner, + bool is_on_worker) { std::vector<std::unique_ptr<BatchingMediaLog::EventHandler>> handlers; // For chrome://media-internals. - handlers.push_back(std::make_unique<RenderMediaEventHandler>()); + // This should only be created in the main Window context, and not from + // a worker context. + if (!is_on_worker) + handlers.push_back(std::make_unique<RenderMediaEventHandler>()); // For devtools' media tab. handlers.push_back(
diff --git a/content/renderer/renderer_blink_platform_impl.h b/content/renderer/renderer_blink_platform_impl.h index 6ce06a9..8275928 100644 --- a/content/renderer/renderer_blink_platform_impl.h +++ b/content/renderer/renderer_blink_platform_impl.h
@@ -242,7 +242,8 @@ scoped_refptr<network::SharedURLLoaderFactory> factory) override; std::unique_ptr<media::MediaLog> GetMediaLog( blink::MediaInspectorContext* inspector_context, - scoped_refptr<base::SingleThreadTaskRunner> owner_task_runner) override; + scoped_refptr<base::SingleThreadTaskRunner> owner_task_runner, + bool is_on_worker) override; media::GpuVideoAcceleratorFactories* GetGpuFactories() override; scoped_refptr<base::SingleThreadTaskRunner> MediaThreadTaskRunner() override; media::DecoderFactory* GetMediaDecoderFactory() override;
diff --git a/content/test/data/accessibility/css/content-visibility-auto-aria-hidden-expected-blink.txt b/content/test/data/accessibility/css/content-visibility-auto-aria-hidden-expected-blink.txt new file mode 100644 index 0000000..42459b5 --- /dev/null +++ b/content/test/data/accessibility/css/content-visibility-auto-aria-hidden-expected-blink.txt
@@ -0,0 +1,6 @@ +rootWebArea name='Done' +++genericContainer ignored +++++genericContainer ignored +++++++genericContainer +++++++++genericContainer +++++++++++staticText name='Not hidden'
diff --git a/content/test/data/accessibility/css/content-visibility-auto-aria-hidden.html b/content/test/data/accessibility/css/content-visibility-auto-aria-hidden.html new file mode 100644 index 0000000..4c5bfefa6 --- /dev/null +++ b/content/test/data/accessibility/css/content-visibility-auto-aria-hidden.html
@@ -0,0 +1,25 @@ +<!-- +@WAIT-FOR:Done +--> +<html> +<head> +<style> +.auto { + content-visibility: auto; +} +.push-content-down { + height: 5000px; +} +</style> +</head> +<body> +<div class="push-content-down" role="none"></div> +<div class="auto"><div aria-hidden="true">aria-hidden</div><div>Not hidden</div></div> +<script> +function runTest() { + document.title = 'Done'; +} +window.onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest)); +</script> +</body> +</html>
diff --git a/content/test/data/accessibility/event/aria-combo-box-expand-expected-auralinux.txt b/content/test/data/accessibility/event/aria-combo-box-expand-expected-auralinux.txt index 7dbfe02..45182e87 100644 --- a/content/test/data/accessibility/event/aria-combo-box-expand-expected-auralinux.txt +++ b/content/test/data/accessibility/event/aria-combo-box-expand-expected-auralinux.txt
@@ -1,5 +1,12 @@ +FOCUS-EVENT:FALSE role=ROLE_DOCUMENT_WEB name='(null)' ENABLED,FOCUSABLE,SENSITIVE,SHOWING,VISIBLE +FOCUS-EVENT:TRUE role=ROLE_COMBO_BOX name='(null)' EDITABLE,ENABLED,EXPANDABLE,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,SINGLE-LINE,VISIBLE,SUPPORTS-AUTOCOMPLETION,SELECTABLE-TEXT +STATE-CHANGE:FOCUSED:FALSE role=ROLE_DOCUMENT_WEB name='(null)' ENABLED,FOCUSABLE,SENSITIVE,SHOWING,VISIBLE +STATE-CHANGE:FOCUSED:TRUE role=ROLE_COMBO_BOX name='(null)' EDITABLE,ENABLED,EXPANDABLE,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,SINGLE-LINE,VISIBLE,SUPPORTS-AUTOCOMPLETION,SELECTABLE-TEXT +TEXT-CARET-MOVED role=ROLE_COMBO_BOX name='(null)' EDITABLE,ENABLED,EXPANDABLE,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,SINGLE-LINE,VISIBLE,SUPPORTS-AUTOCOMPLETION,SELECTABLE-TEXT +=== Start Continuation === +STATE-CHANGE:EXPANDED:TRUE role=ROLE_COMBO_BOX name='(null)' EDITABLE,ENABLED,EXPANDABLE,EXPANDED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,SINGLE-LINE,VISIBLE,SUPPORTS-AUTOCOMPLETION,SELECTABLE-TEXT +=== Start Continuation === FOCUS-EVENT:TRUE role=ROLE_LIST_ITEM name='Apple' ENABLED,FOCUSABLE,FOCUSED,SELECTABLE,SELECTED,SENSITIVE,SHOWING,VISIBLE SELECTION-CHANGED role=ROLE_LIST_BOX name='(null)' ENABLED,SENSITIVE,SHOWING,VERTICAL,VISIBLE -STATE-CHANGE:EXPANDED:TRUE role=ROLE_COMBO_BOX name='(null)' EDITABLE,ENABLED,EXPANDABLE,EXPANDED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,SINGLE-LINE,VISIBLE,SUPPORTS-AUTOCOMPLETION,SELECTABLE-TEXT STATE-CHANGE:FOCUSED:TRUE role=ROLE_LIST_ITEM name='Apple' ENABLED,FOCUSABLE,FOCUSED,SELECTABLE,SELECTED,SENSITIVE,SHOWING,VISIBLE STATE-CHANGE:SELECTED:TRUE role=ROLE_LIST_ITEM name='Apple' ENABLED,FOCUSABLE,FOCUSED,SELECTABLE,SELECTED,SENSITIVE,SHOWING,VISIBLE
diff --git a/content/test/data/accessibility/event/aria-combo-box-expand-expected-mac.txt b/content/test/data/accessibility/event/aria-combo-box-expand-expected-mac.txt index 343feae3..fee02ce 100644 --- a/content/test/data/accessibility/event/aria-combo-box-expand-expected-mac.txt +++ b/content/test/data/accessibility/event/aria-combo-box-expand-expected-mac.txt
@@ -1,4 +1,9 @@ +AXFocusedUIElementChanged on AXComboBox +AXSelectedTextChanged on AXComboBox AXTextSelectionDirection=AXTextSelectionDirectionUnknown AXTextSelectionGranularity=AXTextSelectionGranularityUnknown AXTextStateChangeType=AXTextStateChangeTypeSelectionMove +AXSelectedTextChanged on AXWebArea AXTextSelectionDirection=AXTextSelectionDirectionUnknown AXTextSelectionGranularity=AXTextSelectionGranularityUnknown AXTextStateChangeType=AXTextStateChangeTypeSelectionMove +=== Start Continuation === AXExpandedChanged on AXComboBox +=== Start Continuation === AXFocusedUIElementChanged on AXStaticText AXValue="Apple" AXSelectedChildrenChanged on AXComboBox -AXSelectedChildrenChanged on AXList \ No newline at end of file +AXSelectedChildrenChanged on AXList
diff --git a/content/test/data/accessibility/event/aria-combo-box-expand-expected-uia-win.txt b/content/test/data/accessibility/event/aria-combo-box-expand-expected-uia-win.txt index aadb6d6..72b6a31 100644 --- a/content/test/data/accessibility/event/aria-combo-box-expand-expected-uia-win.txt +++ b/content/test/data/accessibility/event/aria-combo-box-expand-expected-uia-win.txt
@@ -1,7 +1,10 @@ +AutomationFocusChanged on role=combobox +Text_TextSelectionChanged on role=combobox +=== Start Continuation === AriaProperties changed on role=combobox +ExpandCollapseExpandCollapseState changed on role=combobox +=== Start Continuation === AriaProperties changed on role=option, name=Apple AutomationFocusChanged on role=option, name=Apple -AutomationFocusChanged on role=option, name=Apple -ExpandCollapseExpandCollapseState changed on role=combobox SelectionItemIsSelected changed on role=option, name=Apple SelectionItem_ElementSelected on role=option, name=Apple
diff --git a/content/test/data/accessibility/event/aria-combo-box-expand-expected-uia-win7.txt b/content/test/data/accessibility/event/aria-combo-box-expand-expected-uia-win7.txt deleted file mode 100644 index 2cbca25..0000000 --- a/content/test/data/accessibility/event/aria-combo-box-expand-expected-uia-win7.txt +++ /dev/null
@@ -1,8 +0,0 @@ -AriaProperties changed on role=combobox -AriaProperties changed on role=option, name=Apple -AutomationFocusChanged on role=combobox -AutomationFocusChanged on role=option, name=Apple -AutomationFocusChanged on role=option, name=Apple -ExpandCollapseExpandCollapseState changed on role=combobox -SelectionItemIsSelected changed on role=option, name=Apple -SelectionItem_ElementSelected on role=option, name=Apple
diff --git a/content/test/data/accessibility/event/aria-combo-box-expand-expected-win.txt b/content/test/data/accessibility/event/aria-combo-box-expand-expected-win.txt index 99969e2..5db16f2 100644 --- a/content/test/data/accessibility/event/aria-combo-box-expand-expected-win.txt +++ b/content/test/data/accessibility/event/aria-combo-box-expand-expected-win.txt
@@ -1,6 +1,12 @@ +EVENT_OBJECT_FOCUS on <input> role=ROLE_SYSTEM_COMBOBOX FOCUSED,COLLAPSED,FOCUSABLE,HASPOPUP IA2_STATE_EDITABLE,IA2_STATE_SELECTABLE_TEXT,IA2_STATE_SINGLE_LINE,IA2_STATE_SUPPORTS_AUTOCOMPLETION +EVENT_OBJECT_LOCATIONCHANGE role=ROLE_SYSTEM_CARET window_class=Chrome_WidgetWin_0 +EVENT_OBJECT_SHOW role=ROLE_SYSTEM_CARET window_class=Chrome_WidgetWin_0 +IA2_EVENT_TEXT_CARET_MOVED on <input> role=ROLE_SYSTEM_COMBOBOX FOCUSED,COLLAPSED,FOCUSABLE,HASPOPUP IA2_STATE_EDITABLE,IA2_STATE_SELECTABLE_TEXT,IA2_STATE_SINGLE_LINE,IA2_STATE_SUPPORTS_AUTOCOMPLETION +=== Start Continuation === +EVENT_OBJECT_STATECHANGE on <input> role=ROLE_SYSTEM_COMBOBOX FOCUSED,EXPANDED,FOCUSABLE,HASPOPUP IA2_STATE_EDITABLE,IA2_STATE_SELECTABLE_TEXT,IA2_STATE_SINGLE_LINE,IA2_STATE_SUPPORTS_AUTOCOMPLETION +=== Start Continuation === EVENT_OBJECT_FOCUS on <li#option1> role=ROLE_SYSTEM_LISTITEM name="Apple" SELECTED,FOCUSED,FOCUSABLE,SELECTABLE PosInSet=1 SetSize=3 EVENT_OBJECT_SELECTION on <li#option1> role=ROLE_SYSTEM_LISTITEM name="Apple" SELECTED,FOCUSED,FOCUSABLE,SELECTABLE PosInSet=1 SetSize=3 EVENT_OBJECT_SELECTIONWITHIN on <ul#list> role=ROLE_SYSTEM_LIST IA2_STATE_VERTICAL SetSize=3 -EVENT_OBJECT_STATECHANGE on <input> role=ROLE_SYSTEM_COMBOBOX EXPANDED,FOCUSABLE,HASPOPUP IA2_STATE_EDITABLE,IA2_STATE_SELECTABLE_TEXT,IA2_STATE_SINGLE_LINE,IA2_STATE_SUPPORTS_AUTOCOMPLETION EVENT_OBJECT_STATECHANGE on <li#option1> role=ROLE_SYSTEM_LISTITEM name="Apple" SELECTED,FOCUSED,FOCUSABLE,SELECTABLE PosInSet=1 SetSize=3 -IA2_EVENT_ACTIVE_DESCENDANT_CHANGED on <input> role=ROLE_SYSTEM_COMBOBOX EXPANDED,FOCUSABLE,HASPOPUP IA2_STATE_EDITABLE,IA2_STATE_SELECTABLE_TEXT,IA2_STATE_SINGLE_LINE,IA2_STATE_SUPPORTS_AUTOCOMPLETION \ No newline at end of file +IA2_EVENT_ACTIVE_DESCENDANT_CHANGED on <input> role=ROLE_SYSTEM_COMBOBOX EXPANDED,FOCUSABLE,HASPOPUP IA2_STATE_EDITABLE,IA2_STATE_SELECTABLE_TEXT,IA2_STATE_SINGLE_LINE,IA2_STATE_SUPPORTS_AUTOCOMPLETION
diff --git a/content/test/data/accessibility/event/aria-combo-box-expand.html b/content/test/data/accessibility/event/aria-combo-box-expand.html index 7e88c0d..9623859 100644 --- a/content/test/data/accessibility/event/aria-combo-box-expand.html +++ b/content/test/data/accessibility/event/aria-combo-box-expand.html
@@ -1,7 +1,3 @@ -<!-- -@MAC-RUN-UNTIL-EVENT:AXSelectedChildrenChanged -@MAC-RUN-UNTIL-EVENT:AXExpandedChanged ---> <!DOCTYPE html> <html> <body> @@ -13,11 +9,16 @@ <li id="option3" role="option">Banana</li> </ul> <script> - document.querySelector('input').focus(); + var go_passes = [ + () => document.querySelector('input').focus(), + () => document.querySelector('input').setAttribute('aria-expanded', 'true'), + () => document.querySelector('input').setAttribute('aria-activedescendant', 'option1'), + ]; + + let current_pass = 0; function go() { - var combo_box = document.querySelector('input'); - combo_box.setAttribute('aria-expanded', 'true'); - combo_box.setAttribute('aria-activedescendant', 'option1'); + go_passes[current_pass++].call(); + return current_pass < go_passes.length; } </script> </body>
diff --git a/content/test/data/accessibility/event/aria-combo-box-next-expected-uia-win.txt b/content/test/data/accessibility/event/aria-combo-box-next-expected-uia-win.txt index e065920..c4b6a6069 100644 --- a/content/test/data/accessibility/event/aria-combo-box-next-expected-uia-win.txt +++ b/content/test/data/accessibility/event/aria-combo-box-next-expected-uia-win.txt
@@ -1,7 +1,6 @@ AriaProperties changed on role=option, name=Apple AriaProperties changed on role=option, name=Orange AutomationFocusChanged on role=option, name=Orange -AutomationFocusChanged on role=option, name=Orange SelectionItemIsSelected changed on role=option, name=Apple SelectionItemIsSelected changed on role=option, name=Orange SelectionItem_ElementSelected on role=option, name=Orange @@ -9,7 +8,6 @@ AriaProperties changed on role=option, name=Banana AriaProperties changed on role=option, name=Orange AutomationFocusChanged on role=option, name=Banana -AutomationFocusChanged on role=option, name=Banana SelectionItemIsSelected changed on role=option, name=Banana SelectionItemIsSelected changed on role=option, name=Orange SelectionItem_ElementSelected on role=option, name=Banana
diff --git a/content/test/data/accessibility/event/aria-combo-box-next-expected-uia-win7.txt b/content/test/data/accessibility/event/aria-combo-box-next-expected-uia-win7.txt deleted file mode 100644 index 5813e2a..0000000 --- a/content/test/data/accessibility/event/aria-combo-box-next-expected-uia-win7.txt +++ /dev/null
@@ -1,17 +0,0 @@ -AriaProperties changed on role=option, name=Apple -AriaProperties changed on role=option, name=Orange -AutomationFocusChanged on role=option, name=Apple -AutomationFocusChanged on role=option, name=Orange -AutomationFocusChanged on role=option, name=Orange -SelectionItemIsSelected changed on role=option, name=Apple -SelectionItemIsSelected changed on role=option, name=Orange -SelectionItem_ElementSelected on role=option, name=Orange -=== Start Continuation === -AriaProperties changed on role=option, name=Banana -AriaProperties changed on role=option, name=Orange -AutomationFocusChanged on role=option, name=Banana -AutomationFocusChanged on role=option, name=Banana -AutomationFocusChanged on role=option, name=Orange -SelectionItemIsSelected changed on role=option, name=Banana -SelectionItemIsSelected changed on role=option, name=Orange -SelectionItem_ElementSelected on role=option, name=Banana
diff --git a/content/test/data/accessibility/event/expanded-changed-expected-mac.txt b/content/test/data/accessibility/event/expanded-changed-expected-mac.txt index 3724521..5312fbbc 100644 --- a/content/test/data/accessibility/event/expanded-changed-expected-mac.txt +++ b/content/test/data/accessibility/event/expanded-changed-expected-mac.txt
@@ -1 +1,2 @@ -AXExpandedChanged on AXLink AXDescription="Toggle" \ No newline at end of file +=== Start Continuation === +AXExpandedChanged on AXLink AXDescription="Toggle"
diff --git a/content/test/data/accessibility/event/expanded-changed-expected-uia-win.txt b/content/test/data/accessibility/event/expanded-changed-expected-uia-win.txt index 53e0dc7..0b2f7da0 100644 --- a/content/test/data/accessibility/event/expanded-changed-expected-uia-win.txt +++ b/content/test/data/accessibility/event/expanded-changed-expected-uia-win.txt
@@ -1,6 +1,7 @@ -AriaProperties changed on role=link, name=Toggle AriaProperties changed on role=list, name=list AriaProperties changed on role=listitem, name=list item 1 AriaProperties changed on role=listitem, name=list item 2 AriaProperties changed on role=listitem, name=list item 3 -ExpandCollapseExpandCollapseState changed on role=link, name=Toggle \ No newline at end of file +=== Start Continuation === +AriaProperties changed on role=link, name=Toggle +ExpandCollapseExpandCollapseState changed on role=link, name=Toggle
diff --git a/content/test/data/accessibility/event/expanded-changed.html b/content/test/data/accessibility/event/expanded-changed.html index d39c742..97d8870 100644 --- a/content/test/data/accessibility/event/expanded-changed.html +++ b/content/test/data/accessibility/event/expanded-changed.html
@@ -13,9 +13,15 @@ <li aria-label="list item 3">ListItem 3</li> </ul> <script> + var go_passes = [ + () => document.getElementById('list').style.visibility = 'visible', + () => document.getElementById('title').setAttribute('aria-expanded', 'true'), + ]; + + let current_pass = 0; function go() { - document.getElementById('list').style.visibility = 'visible'; - document.getElementById('title').setAttribute('aria-expanded', 'true'); + go_passes[current_pass++].call(); + return current_pass < go_passes.length; } </script> </body>
diff --git a/content/test/data/accessibility/event/focus-listbox-multiselect-expected-uia-win.txt b/content/test/data/accessibility/event/focus-listbox-multiselect-expected-uia-win.txt index fef719d..3e39e79 100644 --- a/content/test/data/accessibility/event/focus-listbox-multiselect-expected-uia-win.txt +++ b/content/test/data/accessibility/event/focus-listbox-multiselect-expected-uia-win.txt
@@ -1,7 +1,6 @@ AriaProperties changed on role=option, name=b AriaProperties changed on role=option, name=c AutomationFocusChanged on role=option, name=c -AutomationFocusChanged on role=option, name=c SelectionItemIsSelected changed on role=option, name=b SelectionItemIsSelected changed on role=option, name=c SelectionItem_ElementSelected on role=option, name=c
diff --git a/content/test/data/accessibility/event/listbox-next-expected-uia-win.txt b/content/test/data/accessibility/event/listbox-next-expected-uia-win.txt index 957e79b..7065466 100644 --- a/content/test/data/accessibility/event/listbox-next-expected-uia-win.txt +++ b/content/test/data/accessibility/event/listbox-next-expected-uia-win.txt
@@ -1,7 +1,6 @@ AriaProperties changed on role=option, name=Apple AriaProperties changed on role=option, name=Orange AutomationFocusChanged on role=option, name=Orange -AutomationFocusChanged on role=option, name=Orange SelectionItemIsSelected changed on role=option, name=Apple SelectionItemIsSelected changed on role=option, name=Orange SelectionItem_ElementSelected on role=option, name=Orange
diff --git a/content/test/data/accessibility/event/listbox-next-expected-uia-win7.txt b/content/test/data/accessibility/event/listbox-next-expected-uia-win7.txt deleted file mode 100644 index d5397e6..0000000 --- a/content/test/data/accessibility/event/listbox-next-expected-uia-win7.txt +++ /dev/null
@@ -1,8 +0,0 @@ -AriaProperties changed on role=option, name=Apple -AriaProperties changed on role=option, name=Orange -AutomationFocusChanged on role=option, name=Apple -AutomationFocusChanged on role=option, name=Orange -AutomationFocusChanged on role=option, name=Orange -SelectionItemIsSelected changed on role=option, name=Apple -SelectionItemIsSelected changed on role=option, name=Orange -SelectionItem_ElementSelected on role=option, name=Orange
diff --git a/content/test/data/accessibility/event/menulist-collapse-expected-uia-win.txt b/content/test/data/accessibility/event/menulist-collapse-expected-uia-win.txt index 0b3357b..d8ebbce6 100644 --- a/content/test/data/accessibility/event/menulist-collapse-expected-uia-win.txt +++ b/content/test/data/accessibility/event/menulist-collapse-expected-uia-win.txt
@@ -1,5 +1,4 @@ AutomationFocusChanged on role=combobox -AutomationFocusChanged on role=combobox === Start Continuation === AriaProperties changed on role=combobox SelectionItemIsSelected changed on role=combobox
diff --git a/content/test/data/accessibility/event/menulist-collapse-next-expected-uia-win.txt b/content/test/data/accessibility/event/menulist-collapse-next-expected-uia-win.txt index fa79854..9da1adf 100644 --- a/content/test/data/accessibility/event/menulist-collapse-next-expected-uia-win.txt +++ b/content/test/data/accessibility/event/menulist-collapse-next-expected-uia-win.txt
@@ -1,5 +1,4 @@ AutomationFocusChanged on role=combobox -AutomationFocusChanged on role=combobox === Start Continuation === AriaProperties changed on role=combobox AriaProperties changed on role=listitem, name=Orange
diff --git a/content/test/data/accessibility/event/menulist-focus-expected-uia-win.txt b/content/test/data/accessibility/event/menulist-focus-expected-uia-win.txt index 3cd5d17..50c9f72 100644 --- a/content/test/data/accessibility/event/menulist-focus-expected-uia-win.txt +++ b/content/test/data/accessibility/event/menulist-focus-expected-uia-win.txt
@@ -1,2 +1 @@ AutomationFocusChanged on role=combobox -AutomationFocusChanged on role=combobox
diff --git a/content/test/data/accessibility/event/subtree-reparented-via-aria-owns-expected-auralinux.txt b/content/test/data/accessibility/event/subtree-reparented-via-aria-owns-expected-auralinux.txt index 5325c31d..a542fbe 100644 --- a/content/test/data/accessibility/event/subtree-reparented-via-aria-owns-expected-auralinux.txt +++ b/content/test/data/accessibility/event/subtree-reparented-via-aria-owns-expected-auralinux.txt
@@ -1 +1,4 @@ -PARENT-CHANGED PARENT:(role=ROLE_PANEL name='(null)') role=ROLE_LANDMARK name='(null)' ENABLED,SENSITIVE,SHOWING,VISIBLE +CHILDREN-CHANGED:ADD index:0 CHILD:(role=ROLE_LANDMARK) role=ROLE_PANEL ENABLED,SENSITIVE,SHOWING,VISIBLE +CHILDREN-CHANGED:REMOVE index:1 CHILD:(role=ROLE_LANDMARK) role=ROLE_DOCUMENT_WEB ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VISIBLE +STATE-CHANGE:DEFUNCT:TRUE role=ROLE_INVALID name='(null)' DEFUNCT +STATE-CHANGE:DEFUNCT:TRUE role=ROLE_INVALID name='(null)' DEFUNCT
diff --git a/content/test/data/accessibility/event/subtree-reparented-via-aria-owns-expected-win.txt b/content/test/data/accessibility/event/subtree-reparented-via-aria-owns-expected-win.txt index 9632e1cb..5a902d09 100644 --- a/content/test/data/accessibility/event/subtree-reparented-via-aria-owns-expected-win.txt +++ b/content/test/data/accessibility/event/subtree-reparented-via-aria-owns-expected-win.txt
@@ -1,4 +1,6 @@ +EVENT_OBJECT_HIDE on <div#search> role=ROLE_SYSTEM_GROUPING EVENT_OBJECT_REORDER on <#document> role=ROLE_SYSTEM_DOCUMENT value~=[doc-url] FOCUSED,FOCUSABLE EVENT_OBJECT_REORDER on <div#group> role=ROLE_SYSTEM_GROUPING +EVENT_OBJECT_SHOW on <div#search> role=ROLE_SYSTEM_GROUPING IA2_EVENT_TEXT_INSERTED on <div#group> role=ROLE_SYSTEM_GROUPING new_text={'<obj>' start=0 end=1} -IA2_EVENT_TEXT_REMOVED on <#document> role=ROLE_SYSTEM_DOCUMENT value~=[doc-url] FOCUSED,FOCUSABLE old_text={'<obj>' start=1 end=2} +IA2_EVENT_TEXT_REMOVED on <#document> role=ROLE_SYSTEM_DOCUMENT value~=[doc-url] FOCUSED,FOCUSABLE old_text={'<obj>' start=1 end=2} \ No newline at end of file
diff --git a/content/test/data/accessibility/event/tbody-focus-expected-uia-win.txt b/content/test/data/accessibility/event/tbody-focus-expected-uia-win.txt index 44f41197..eaa209f 100644 --- a/content/test/data/accessibility/event/tbody-focus-expected-uia-win.txt +++ b/content/test/data/accessibility/event/tbody-focus-expected-uia-win.txt
@@ -1,2 +1 @@ AutomationFocusChanged on role=rowgroup, name=tbody -AutomationFocusChanged on role=rowgroup, name=tbody
diff --git a/content/test/data/accessibility/event/tfoot-focus-expected-uia-win.txt b/content/test/data/accessibility/event/tfoot-focus-expected-uia-win.txt index 437da270..8d3b7fb 100644 --- a/content/test/data/accessibility/event/tfoot-focus-expected-uia-win.txt +++ b/content/test/data/accessibility/event/tfoot-focus-expected-uia-win.txt
@@ -1,2 +1 @@ AutomationFocusChanged on role=rowgroup, name=tfoot -AutomationFocusChanged on role=rowgroup, name=tfoot
diff --git a/content/test/data/accessibility/event/thead-focus-expected-uia-win.txt b/content/test/data/accessibility/event/thead-focus-expected-uia-win.txt index 45470dda..40aef32 100644 --- a/content/test/data/accessibility/event/thead-focus-expected-uia-win.txt +++ b/content/test/data/accessibility/event/thead-focus-expected-uia-win.txt
@@ -1,2 +1 @@ AutomationFocusChanged on role=rowgroup, name=thead -AutomationFocusChanged on role=rowgroup, name=thead
diff --git a/content/test/fuzzer/code_cache_host_mojolpm_fuzzer.cc b/content/test/fuzzer/code_cache_host_mojolpm_fuzzer.cc index 54216e7..95f957d9 100644 --- a/content/test/fuzzer/code_cache_host_mojolpm_fuzzer.cc +++ b/content/test/fuzzer/code_cache_host_mojolpm_fuzzer.cc
@@ -24,6 +24,7 @@ #include "content/public/test/test_content_client_initializer.h" #include "content/test/fuzzer/code_cache_host_mojolpm_fuzzer.pb.h" #include "mojo/core/embedder/embedder.h" +#include "storage/browser/quota/quota_manager.h" #include "storage/browser/quota/special_storage_policy.h" #include "storage/browser/test/mock_special_storage_policy.h" #include "third_party/blink/public/mojom/loader/code_cache.mojom-mojolpm.h" @@ -213,7 +214,9 @@ std::make_unique<content::CacheStorageControlWrapper>( content::GetIOThreadTaskRunner({}), browser_context_->GetPath(), browser_context_->GetSpecialStoragePolicy(), - /*quota_manager_proxy=*/nullptr, + browser_context_->GetDefaultStoragePartition() + ->GetQuotaManager() + ->proxy(), /*blob_storage_context=*/mojo::NullRemote()); generated_code_cache_context_ =
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt index 2ff25483..f0fc28e 100644 --- a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
@@ -279,9 +279,9 @@ # Flaky on AMD Win7 crbug.com/989050 [ angle-d3d11 win7 amd ] conformance2/textures/misc/tex-unpack-params-imagedata.html [ RetryOnFailure ] -# Passthrough command decoder / Linux / OpenGL / NVIDIA -crbug.com/766918 [ angle-opengl linux passthrough nvidia ] conformance2/textures/image_bitmap_from_video/* [ RetryOnFailure ] -crbug.com/965648 [ angle-opengl linux passthrough nvidia ] deqp/functional/gles3/shaderstruct.html [ RetryOnFailure ] +# Win / Intel +crbug.com/1215624 [ win intel angle-d3d11 ] conformance2/textures/video/* [ RetryOnFailure ] +crbug.com/1215624 [ win intel angle-d3d11 ] conformance2/textures/webgl_canvas/tex-2d-rgba8-rgba-unsigned_byte.html [ RetryOnFailure ] #################### # Mac failures # @@ -604,6 +604,8 @@ # Linux / OpenGL / NVIDIA failures crbug.com/angleproject/4555 [ linux angle-opengl passthrough nvidia ] conformance/misc/type-conversion-test.html [ Skip ] +crbug.com/766918 [ angle-opengl linux passthrough nvidia ] conformance2/textures/image_bitmap_from_video/* [ RetryOnFailure ] +crbug.com/965648 [ angle-opengl linux passthrough nvidia ] deqp/functional/gles3/shaderstruct.html [ RetryOnFailure ] # Linux GTX 1660 crbug.com/1115314 [ linux nvidia-0x2184 angle-opengl passthrough ] deqp/functional/gles3/fbocompleteness.html [ Failure ] @@ -716,9 +718,6 @@ crbug.com/angleproject/3686 [ android angle-opengles ] deqp/functional/gles3/multisample/fbo_8_samples.html [ Failure ] crbug.com/angleproject/3686 [ android angle-opengles ] deqp/functional/gles3/multisample/fbo_max_samples.html [ Failure ] -# Flakily hitting a fatal V8 compiler issue. -crbug.com/1213266 [ android android-pixel-4 ] deqp/functional/gles3/* [ RetryOnFailure ] - crbug.com/1037958 [ mac amd-0x679e ] conformance2/transform_feedback/switching-objects.html [ RetryOnFailure ] # Conflicting expectations to test that the
diff --git a/content/test/test_render_view_host.cc b/content/test/test_render_view_host.cc index cea0a32..88bd15d 100644 --- a/content/test/test_render_view_host.cc +++ b/content/test/test_render_view_host.cc
@@ -234,10 +234,6 @@ return display_feature_; } -ui::Compositor* TestRenderWidgetHostView::GetCompositor() { - return compositor_; -} - TestRenderViewHost::TestRenderViewHost( FrameTree* frame_tree, SiteInstance* instance,
diff --git a/content/test/test_render_view_host.h b/content/test/test_render_view_host.h index 0529c4ec..5482020 100644 --- a/content/test/test_render_view_host.h +++ b/content/test/test_render_view_host.h
@@ -118,7 +118,6 @@ viz::SurfaceId GetCurrentSurfaceId() const override; std::unique_ptr<SyntheticGestureTarget> CreateSyntheticGestureTarget() override; - ui::Compositor* GetCompositor() override; bool is_showing() const { return is_showing_; } bool is_occluded() const { return is_occluded_; } @@ -130,8 +129,6 @@ const WebCursor& last_cursor() const { return last_cursor_; } - void SetCompositor(ui::Compositor* compositor) { compositor_ = compositor; } - protected: // RenderWidgetHostViewBase: void UpdateBackgroundColor() override; @@ -157,8 +154,6 @@ #endif absl::optional<DisplayFeature> display_feature_; - - ui::Compositor* compositor_ = nullptr; }; // TestRenderViewHost ----------------------------------------------------------
diff --git a/docs/security/faq.md b/docs/security/faq.md index 428acc5..912df6a1 100644 --- a/docs/security/faq.md +++ b/docs/security/faq.md
@@ -677,6 +677,11 @@ See our dedicated [Service Worker Security FAQ](https://chromium.googlesource.com/chromium/src/+/main/docs/security/service-worker-security-faq.md). +<a name="TOC-What-is-the-security-story-for-Extensions-"></a> +## What is the security story for Extensions? + +See our dedicated [Extensions Security FAQ](https://chromium.googlesource.com/chromium/src/+/main/extensions/docs/security_faq.md). + <a name="TOC-What-about-URL-spoofs-using-Internationalized-Domain-Names-IDN-"></a> ## What about URL spoofs using Internationalized Domain Names (IDN)? @@ -692,30 +697,7 @@ <a name="TOC-Chrome-silently-syncs-extensions-across-devices.-Is-this-a-security-vulnerability-"></a> ## Chrome silently syncs extensions across devices. Is this a security vulnerability? -If an attacker has access to one of a victim's devices, the attacker can install -an extension which will be synced to the victim's other sync-enabled -devices. Similarly, an attacker who phishes a victim's Google credentials can -sign in to Chrome as the victim and install an extension, which will be synced -to the victim's other sync-enabled devices. Sync thereby enables an attacker to -elevate phished credentials or physical access to persistent access on all of a -victim's sync-enabled devices. - -To mitigate this issue, Chrome only syncs extensions that have been installed -from the Chrome Web Store. Extensions in the Chrome Web Store are monitored for -abusive behavior. - -In the future, we may pursue further mitigations. However, because an attacker -must already have the victim's Google credentials and/or [physical access to a -device](#TOC-Why-aren-t-physically-local-attacks-in-Chrome-s-threat-model-), we -don't consider this attack a security vulnerability. - -We **do** consider it a vulnerability if an attacker can get an extension to -sync to a victim's device without either of the above preconditions. For -example, we consider it a vulnerability if an attacker could craft a request to -Google's sync servers that causes an extension to be installed to a user's -device, or if an attacker could entice a victim to visit a webpage that causes -an extension to be installed on their device(s). Please report such bugs via -https://bugs.chromium.org/p/chromium/issues/entry?template=Security+Bug. +This topic has been moved to the [Extensions Security FAQ](https://chromium.googlesource.com/chromium/src/+/main/extensions/docs/security_faq.md). <a name="TOC-Are-PDF-files-static-content-in-Chromium-"></a> ## Are PDF files static content in Chromium?
diff --git a/docs/standards/DIR_METADATA b/docs/standards/DIR_METADATA new file mode 100644 index 0000000..d09af66 --- /dev/null +++ b/docs/standards/DIR_METADATA
@@ -0,0 +1,9 @@ +# Metadata information for this directory. +# +# For more information on DIR_METADATA files, see: +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md +# +# For the schema of this file, see Metadata message: +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto + +team_email: "spec-mentors@chromium.org"
diff --git a/docs/standards/README.md b/docs/standards/README.md new file mode 100644 index 0000000..ad05972 --- /dev/null +++ b/docs/standards/README.md
@@ -0,0 +1,13 @@ +# Developing web standards within Chromium + +The [Chromium process for launching +features](https://www.chromium.org/blink/launching-features) requires that +web-exposed features go through (though not always complete) a public +standardization process. + +We provide a [specification mentorship +program](https://www.chromium.org/blink/spec-mentors) to help you go through +this process. + +If you notice misbehavior in a standardization venue, see their [codes of +conduct](conduct.md).
diff --git a/docs/standards/conduct.md b/docs/standards/conduct.md new file mode 100644 index 0000000..004ade9 --- /dev/null +++ b/docs/standards/conduct.md
@@ -0,0 +1,74 @@ +# Codes of Conduct + +Chromium contributors participate in many organizations that standardize Web +APIs. These organizations have rules that govern participants' behavior. We need +to follow these rules, and we can expect that others in these bodies will also +follow the rules. + +This document links to each organization's code of conduct and any contact +information that organization provides for navigating difficulties. For +organizations without a code of conduct, we're happy to help them develop one. + +If you notice someone breaking a venue's code of conduct, you have several options for handling the situation: + +1. If you feel comfortable, call out the behavior in the discussion and give an + opportunity for it to be addressed. For example: + + > "This comment is not constructive/does not help move us to consensus/makes + an incorrect assumption/is not actionable. Could you please re-state or + rephrase your comments accordingly?" +1. If you do not feel comfortable raising the concern directly, or the behavior + is not fixed or acknowledged, disengage with the discussion and escalate the + issue: + 1. To your [spec mentor](https://www.chromium.org/blink/spec-mentors) if you have one. + 1. To a relevant group chair. + 1. To the SDO's ombuds group as identified below and/or in their code of conduct. + + +[TOC] + + +## W3C + +See the [Code of Ethics and Professional +Conduct](https://www.w3.org/Consortium/cepc/) and the +[procedures](https://www.w3.org/Consortium/pwe/#Procedures) used to enforce it. +The ombuds may be contacted +[individually](https://www.w3.org/Consortium/pwe/#ombuds) or collectively at +<ombuds@w3.org>. + +## WHATWG + +See the [Code of Conduct](https://whatwg.org/code-of-conduct). Escalate via +<sg@whatwg.org>. + +## IETF + +See the [Guidelines for Conduct](https://www.rfc-editor.org/rfc/rfc7154.html) +and the [Anti-Harassment +Procedures](https://www.rfc-editor.org/rfc/rfc7776.html). + +Escalate via [individual ombudspeople](https://www.ietf.org/contact/ombudsteam/) +or <ombudsteam@ietf.org>. + +## ECMA TC39 + +See the [Code of Conduct](https://tc39.es/code-of-conduct/). Report violations via <tc39-conduct-reports@googlegroups.com>. + +## Khronos + +See the +[https://www.khronos.org/events/code-of-conduct](https://www.khronos.org/events/code-of-conduct). +Their escalation path is more tailored to events than standardization activity, +but you can [file an anonymous +report](https://docs.google.com/forms/d/1nr1B_TOMIhSXh1yG8VsvGpEO9p6GWY-3kxJu-rnA5dU/viewform). + +## FIDO + +The [FIDO Alliance](https://fidoalliance.org/) does not currently have a code of conduct. + +## AO Media + +The [Alliance for Open Media](https://aomedia.org/) does not currently have a code of conduct. + +
diff --git a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc index 68d2372..613c704 100644 --- a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc +++ b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc
@@ -667,7 +667,7 @@ } // From here the lifecycle of this request is driven by subsequent events on - // either |proxy_loader_binding_|, |proxy_client_binding_|, or + // either |proxied_loader_receiver_|, |proxied_client_receiver_|, or // |header_client_receiver_|. }
diff --git a/extensions/browser/content_script_tracker.cc b/extensions/browser/content_script_tracker.cc index cd719013..ba90b446 100644 --- a/extensions/browser/content_script_tracker.cc +++ b/extensions/browser/content_script_tracker.cc
@@ -248,6 +248,7 @@ const content::RenderProcessHost& process, const ExtensionId& extension_id) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + DCHECK(!extension_id.empty()); // Check if we've been notified about the content script injection via // ReadyToCommitNavigation or WillExecuteCode methods.
diff --git a/extensions/browser/extension_message_filter.cc b/extensions/browser/extension_message_filter.cc index 9ee2211..b225535 100644 --- a/extensions/browser/extension_message_filter.cc +++ b/extensions/browser/extension_message_filter.cc
@@ -100,9 +100,13 @@ return true; case MessagingEndpoint::Type::kTab: - // TODO(https://crbug.com/1212918: Re-enable the enforcement after - // investigating and fixing the root cause of bad message reports coming - // from the end users. + if (source_endpoint.extension_id.has_value() && + !ContentScriptTracker::DidProcessRunContentScriptFromExtension( + process, source_endpoint.extension_id.value())) { + bad_message::ReceivedBadMessage( + &process, bad_message::EMF_INVALID_EXTENSION_ID_FOR_CONTENT_SCRIPT); + return false; + } return true; } }
diff --git a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_browsertest.cc b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_browsertest.cc index 0cdb37a0..99f6fa9 100644 --- a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_browsertest.cc +++ b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_browsertest.cc
@@ -205,13 +205,9 @@ // potential race between the cross-origin renderer initiated navigation and // the navigation to "about:blank" started from the browser. // -// Disabled on Linux and Mac due to flakiness: https://crbug.com/1182355. -#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) || defined(OS_MAC) -#define MAYBE_NavigationRaceFromEmbedder DISABLED_NavigationRaceFromEmbedder -#else -#define MAYBE_NavigationRaceFromEmbedder NavigationRaceFromEmbedder -#endif -IN_PROC_BROWSER_TEST_F(MimeHandlerViewTest, MAYBE_NavigationRaceFromEmbedder) { +// Disabled on all platforms due to flakiness: https://crbug.com/1182355. +IN_PROC_BROWSER_TEST_F(MimeHandlerViewTest, + DISABLED_NavigationRaceFromEmbedder) { const std::string kTestName = "test_navigation_race_embedder"; auto cross_origin_url = embedded_test_server()->GetURL("b.com", "/test_page.html").spec();
diff --git a/extensions/common/api/virtual_keyboard_private.json b/extensions/common/api/virtual_keyboard_private.json index adcd418..70bc634 100644 --- a/extensions/common/api/virtual_keyboard_private.json +++ b/extensions/common/api/virtual_keyboard_private.json
@@ -117,6 +117,10 @@ "$ref": "DisplayFormat", "name": "displayFormat", "description": "The display format associated with this item." + }, + "timeCopied": { + "type": "number", + "description": "The time that this item was added to the clipboard, in milliseconds since the epoch." } } }
diff --git a/extensions/docs/security_faq.md b/extensions/docs/security_faq.md new file mode 100644 index 0000000..6662d4a0 --- /dev/null +++ b/extensions/docs/security_faq.md
@@ -0,0 +1,387 @@ +# Extensions Security FAQ + +[TOC] + +## Purpose + +This document outlines many common questions we've received about extensions +security and what we do or do not consider to be security bugs. This is +primarily written for an audience of Chromium developers and security +researchers. + +It is analogous to the general +[Chrome Security FAQ](https://chromium.googlesource.com/chromium/src/+/main/docs/security/faq.md). + +## Future Additions + +Add canonical examples of bugs for each of these (particularly WontFix bugs for +examples of what is not considered a security bug). + +## FAQ + +### I've found / written an extension that can access sensitive user data, like passwords and emails. Is this a security bug in Chromium? + +In most cases, this is _not_ a security bug. Extensions are designed to have +access to user data if and only if they have the appropriate +[permissions](https://developer.chrome.com/docs/extensions/mv3/declare_permissions/). +For instance, an extension may be able to access a user's data on a set of sites +(or all sites) if the extension requests the appropriate permissions in its +manifest file. Before an extension can use these capabilities, they must be +granted by the user - as an example, the install prompt may say that the +extension can "Read and change your data on google.com". + +If the extension is only able to access user data through permissions the +extension has requested (for instance, it is able to access data on google.com +because it specified host or content script permissions that match google.com), +then this access is working as intended. If an extension is able to access data +_without_ appropriate permission, then this would be a security bug. Please +report any such bugs [here][new-security-bug]. + +### Why do you allow extensions to access sensitive user data? Surely there's no reason to allow it to read my passwords! + +It may seem alarming that certain extensions can access certain types of +sensitive data, such as passwords. However, this access can be critical to +extensions' functionality. Consider, for instance, password managers (which +store and retrieve your passwords) - these extensions, fundamentally, must +access this type of sensitive data. There is very little data that we can +deterministically say should never be available to extensions. + +When installing extensions, users should be sure to look both at the permissions +requested by the extension (displayed in the installation prompt) and also at +the extension's privacy policy and other disclosures (which may be linked from +the extension's listing on the +[Chrome Web Store](https://chrome.google.com/webstore)). + +### If extensions can read sensitive user data, what prevents an extension from stealing my sensitive data? + +First, extensions should only be allowed to access data that they have +permission to (and these permissions must be approved by the user before they +can be used, either at installation or at runtime). Users should only install +extensions and grant permissions to extensions they trust. + +In addition to these platform mitigations, developers distributing through the +Chrome Web Store are required to adhere to a number of different policies, which +describe which types of behaviors are allowed. For instance, the +[user data](https://developer.chrome.com/docs/webstore/user_data/) FAQ here +describes the types of data and permissions that extensions are allowed to +gather and use. + +Google also subjects extensions to a combination of automated and manual review +systems. + +### I've found / written an extension that can access site data without any host patterns specified in the "permissions" or "host\_permissions" manifest keys. Is this a security bug? + +In most cases, this is _not_ a security bug. Extensions can also access certain +sites with content scripts (specified in the `content\_scripts` key) or with the +`activeTab` permission. Hosts specified in `content\_scripts` (under the +`matches` key) are displayed to the user in permission requests in the same way +as host permissions requested under `permissions` or `host\_permissions` - that +is, it indicates the extension can "Read and change your data on <site>". +ActiveTab requires a user to explicitly invoke the extension on a page before +the extension can access data on the page, which is a form of runtime permission +grant (similar to how "sharing" a page with an app on Android grants the app +access to the content of the page). + +If an extension is able to access site data without any API or permission that +allows this access, then it may be a security bug. Please report any such bugs +[here][new-security-bug]. + +### Are extensions able to keep running after they have been uninstalled? + +An extension is not able to directly keep running after it has been uninstalled +(or disabled) by the user or the browser. However, any changes made by an +extension to a currently loaded site (e.g. script injection or data +modification) will remain in place after the extension is uninstalled until the +user leaves the site (e.g. by navigating away or refreshing), and potentially +beyond. This has a few implications: + +* Exfiltrated data is still exfiltrated. If an extension sent data from the + local device to a remote server, Chromium cannot delete the data on that + remote server. +* Content scripts (and other injected scripts) will continue running on pages + they have already been injected in after the extension is disabled. Since + Chromium cannot "un-inject" these scripts, they may continue running until + the user leaves the site. +* Data modified by the extension remains modified. This includes data like + cookies, which may influence how a site operates. Additionally, extensions + may have mutated the cache, installed service workers on sites, or similar + modifications. These will persist. + +Other extension behavior, such as running background scripts, network handlers, +URL overrides, proxy settings, and preference modifications should be reverted +upon uninstallation. + +### I've found an extension that violates Chrome Web Store policy. Is this considered a bug in Chromium? + +Individual extensions are generally not considered a part of Chromium, so +extensions violating Chrome Web Store policies (including distribution policies) +are not considered security bugs in Chromium itself. + +You can report the extension with the "Report abuse" link in the extension's +entry on the Chrome Web Store. +<!-- TODO(devlin): Link to + https://support.google.com/chrome_webstore/answer/7508032?hl=en when we + have a p-link for this. Otherwise, it violates + https://crbug.com/679462. --> + +### Is adding a malicious extension to a user's profile considered a security bug? + +Chromium +[does not consider physically-local attacks to be security bugs][physically-local-attacks]. +This includes attacks like loading extensions on a user's machine. As such, +attacks like loading extensions physically through loading an unpacked +extension in the chrome://extensions page, via malicious software that executes +outside of the Chromium browser, or updating enterprise policies to load +extensions are all not within Chromium's threat model. + +Adding a malicious extension to the user's profile is only a security bug if you +find a way to add the extension without direct access to the user's profile and +bypassing the normal extension installation flow. For instance, if an extension +could be installed (without user consent) when the user visits a malicious site, +this would be considered a security bug. Please report any such bugs +[here][new-security-bug]. + +### Chrome silently syncs extensions across devices. Is this a security vulnerability? + +If an attacker has access to one of a victim‘s devices, the attacker can install +an extension which will be synced to the victim’s other sync-enabled devices. +Similarly, an attacker who phishes a victim‘s Google credentials can sign in to +Chrome as the victim and install an extension, which will be synced to the +victim’s other sync-enabled devices. Sync thereby enables an attacker to elevate +phished credentials or physical access to persistent access on all of a victim's +sync-enabled devices. + +To mitigate this issue, Chrome only syncs extensions that have been installed +from the Chrome Web Store. Extensions in the Chrome Web Store are monitored for +abusive behavior. + +In the future, we may pursue further mitigations. However, because an attacker +must already have the victim‘s Google credentials and/or +[physical access to a device][physically-local-attacks], we don’t consider this +attack a security vulnerability. + +We **do** consider it a vulnerability if an attacker can get an extension to +sync to a victim‘s device without either of the above preconditions. For +example, we consider it a vulnerability if an attacker could craft a request to +Google’s sync servers without proper credentials that causes an extension to be +installed to a user's device, or if an attacker could entice a victim to visit a +webpage that causes an extension to be installed on their device(s). Please +report any such bugs [here][new-security-bug]. + +### Why do some permissions (and APIs) requested by developers not display a permission warning? + +Permissions and APIs may not have an associated warning for a number of reasons. +There is not a 1-to-1 mapping of permissions listed in the manifest and warnings +shown to the user. + +Some permissions may grant innocuous capabilities to extensions. For instance, +the `storage` permission allows an extension to store _its own data_. This does +not grant the extension access to any additional data; further, this type of +behavior is already possible using open web APIs like `localStorage` and Indexed +DB. Since this does not provide the extension any access to any new data or +dangerous capabilities, the API does not have an associated warning. + +Other permissions, like `webRequest`, may only apply to sites the extension has +access to. The webRequest API allows extensions to monitor (and potentially +modify) network requests made by web pages. However, an extension can _only_ +intercept these requests for sites it has access to. Requesting access to a site +already displays a permission warning ("Read and change your data on <site>"); +the webRequest API does not provide any additional access. This is also the case +for the `scripting` permission and others. + +Some APIs may also have runtime permission prompts, such as dialogs or choosers, +that are shown to the user in context. Since these APIs do not immediately grant +any data access to extensions, no permission warning is shown. + +Finally, some permissions may be subsumed by other, more powerful, permissions. +For instance, if an extension has access to the history API (which allows +extensions to read and change a user's browsing history), we do not also show a +warning for the `topSites` API (which allows extensions to see the top sites a +user has visited). Since the history API is strictly more powerful, it subsumes +the `topSites` API. You can read more +[here](https://chromium.googlesource.com/chromium/src/+/main/extensions/docs/permissions.md#Determining-Permission-Warnings). + +### Why do optional permissions not display a permission warning at install time? + +Permissions listed in the `optional\_permissions` key in the manifest are not +granted to the extension at install-time. Instead, they are granted through the +use of the +[Permissions API](https://developer.chrome.com/docs/extensions/reference/permissions/). +When the extension requests new capabilities (i.e., permissions that have not +been previously granted and are not superseded by other granted permissions), a +dialog is shown to the user, allowing them to grant or refuse the permissions. + +### If an extension is updated to include new permissions, are users notified? + +If an extension updates and includes new permissions that are not already +contained within its current granted capabilities, the extension is disabled on +users' machines and the user is notified (and asked if they'd like to grant the +new permissions and enable the extension). You can read more +[here](https://chromium.googlesource.com/chromium/src/+/main/extensions/docs/permissions.md#Permission-Increases). + +This does not apply to newly-requested optional permissions, which are not +granted by default. + +### I've found / written an extension that can execute code from a remote server. Is this a security bug? + +This is not considered a security bug in Chromium +([example](https://crbug.com/1025017)). Prior to Manifest Version 3, extensions +were allowed to execute code that was not contained in the extension package +(also called remotely-hosted code); this is a pattern that is extremely common +in web development. Beginning in Manifest Version 3, all logic must be contained +within the extension package for developers distributing through the Chrome Web +store; however, this is a _policy_ requirement (described +[here](https://developer.chrome.com/docs/webstore/program_policies/)), and is +not enforced by the Chromium browser. + +While the platform includes some restrictions through the inclusion of a default +content security policy for extensions, this is not meant to be a guaranteed +deterrent, and does not prevent all types of remote code execution. For +instance, it is impossible for the Chromium browser to guard against an +extension that includes an interpreter that processes remotely-fetched JSON +commands, even though this type of behavior is prohibited by policy in Manifest +V3. + +### Why do we allow extensions to open or close chrome:-scheme pages? + +Web pages with the chrome:-scheme (such as chrome://settings) are generally +protected from extensions - extensions are not allowed to read or change data +on these pages (without the use of the `--extensions-on-chrome-urls` command +line flag). However, extensions _are_ allowed to open and close these pages +through APIs like the tabs and windows APIs. This is critical for certain types +of extensions, such as tab and session managers, bookmark managers, and history +managers. + +### Why are extensions allowed to bypass a web page's Content Security Policy? + +Extensions are considered more privileged than the web pages they are allowed to +run on. As such, they are allowed to circumvent restrictions put in place by +those web pages. This can be critical for extension functionality. + +### Is executing in the main world of a document a security bug? + +No ([example](https://bugs.chromium.org/p/chromium/issues/detail?id=760419)). By +default, extension scripts (like content scripts and those injected with +[tabs.executeScript()](https://developer.chrome.com/docs/extensions/reference/tabs/#method-executeScript) +or +[scripting.executeScript()](https://developer.chrome.com/docs/extensions/reference/scripting/#method-executeScript) +execute in an isolated world. However, this is _not_ intended as a security +boundary to protect the main page from the extension (rather, it is a soft +boundary in the other direction, _slightly_ protecting the extension from the +webpage and other extensions active on the page). More than anything else, this +is designed to prevent collision of JavaScript variables, so that `foo` in the +content script does not reference `foo` from the main world. + +Extensions can trivially execute in the main world of a document if they so +desire - for instance, by appending a `<script>` element. Assuming the extension +has access to the site, it can already read and change the data on that site. As +such, injecting in the main world does not represent any increased capability or +access, and is not a security bug. + +### Is a web page accessing content script data in an isolated world considered a security bug? + +Isolated worlds are separate JavaScript execution contexts in V8. By default, +script in one world cannot access the data in another. Circumventing this _may_ +be a security bug, depending on the attack. + +**Process-based attacks:** Since isolated worlds are necessarily in the same +process as the main world, any attack that allows the attacker to read +process-level data (such as a Spectre or Meltdown attack, or other renderer +compromise) could potentially access content script data or access APIs exposed +to content scripts. + +**Shared variable attacks:** Certain content is shared between the isolated +world and the main world. For instance, references to an undeclared variable can +result in accessing a frame with the same name from the window object. +Similarly, the content of the DOM is shared between different JS worlds (though +the JS objects are distinct to each). Attackers may be able to "trick" a content +script into using these variables as a flavor of XSS - an example of this is +[this Project Zero bug](https://bugs.chromium.org/p/project-zero/issues/detail?id=1225). +These are bugs in the particular extension, rather than in Chromium. Please +report them to the extension developer. + +Other attacks that cross from the main world into an extension's isolated world +may be considered security bugs; please report any such bugs +[here][new-security-bug]. + +### Extensions can modify, relax, or remove site security by removing security-sensitive headers like Content-Security-Policy, HTTP Strict-Transport-Security, Access-Control-Allow-Origin, and others. Is this a security bug? + +Assuming the extension has access to the site, this is not considered a security +bug. If the extension has access to a site, it can read and change all data +associated with that site, including affecting how it can be shared with other +parties. + +However, modifying security-sensitive headers is generally discouraged, unless +absolutely necessary (such as for developer tools). + +### An extension is able to open a native application. Is this a security bug? + +_Maybe_. Extensions are allowed to open (and potentially communicate with) +native applications in a variety of ways. One of the main ways is the +[nativeMessaging API](https://developer.chrome.com/docs/extensions/nativeMessaging/), +which allows for communication with installed native applications that have +registered a manifest on the user's machine. Extensions are also able to open +native applications with the +[downloads.open()](https://developer.chrome.com/docs/extensions/reference/downloads/#method-open) +method. Finally, extensions are allowed to navigate to file:-scheme URLs, which +could, depending on the user's system configuration, result in execution. Using +these methods to open a native application is not considered a security bug. + +If an extension is able to open a native application or execute native code in +another way, it may be a security bug; please report any such bugs +[here][new-security-bug]. + +### An extension is able to read file contents from the local machine. Is this a security bug? + +Extensions can read file contents if they are granted file permission by the +user. This is toggled in the chrome://extensions page for the given extension +(under "Allow access to file URLs"; note that this is the default for unpacked +extensions). If this setting is enabled, extensions can read all files on disk. +Additionally, extensions are allowed to read any files that were explicitly +shared with them, such as through the HTML5 Filesystem API. Additionally, +extensions (with appropriate API permissions) can read the URLs of tabs and +history entries, including file:-scheme URLs; however, this should not allow +access to the _contents _of the file. + +If an extension is able to read file contents from the local machine in another +way, this may be a security bug; please report any such bugs +[here][new-security-bug]. + +### An extension is able to read and store data from incognito browsing. Is this a security bug? + +Extensions are allowed to run in an incognito profile if the "Allow in +incognito" setting is enabled for the given extension in the +chrome://extensions page. In this scenario, the extension has access to all the +types of data it does in normal browsing - such as URLs and the contents of +websites. Chrome does not limit what an extension does with this data. + +If an extension is able to access incognito contexts without this setting +enabled, this may be a security bug; please report any such bugs +[here][new-security-bug]. + +### I've found a security bug in an extension. Is this a security bug in Chromium? + +This depends on the extension. + +**Component Extensions:** Some extensions (called "component extensions") are +bundled by the Chromium browser and implement core browser functionality. An +example of this is the CryptoToken extension (used in security key +authentication). If you find a security bug in a component extension, this _is_ +considered a security bug in Chromium. Please report any such bugs +[here][new-security-bug]. + +**Google Extensions:** A security bug in an extension developed by Google, but +not distributed directly with the Chrome browser, would likely not be considered +a bug in Chromium. However, they may be covered by the +[Google Vulnerability Reward Program](https://www.google.com/about/appsecurity/reward-program/). + +**Other Extensions:** A security bug in a third-party extension would not be +considered a security bug in Chromium. Some third-party extensions may have +their own vulnerability reward programs; please check with the extension +developer. It may also be eligible for a reward through the Developer Data +Protection Reward Program; visit +[this site](https://www.google.com/about/appsecurity/ddprp/) for more +information. + +[new-security-bug]: https://bugs.chromium.org/p/chromium/issues/entry?template=Security+Bug +[physically-local-attacks]: https://chromium.googlesource.com/chromium/src/+/main/docs/security/faq.md#why-arent-physically_local-attacks-in-chromes-threat-model
diff --git a/fuchsia/cipd/README.md b/fuchsia/cipd/README.md index 9a7a851..92d1908 100644 --- a/fuchsia/cipd/README.md +++ b/fuchsia/cipd/README.md
@@ -6,15 +6,6 @@ ## Example usage -To create a CIPD package, run the following command from the build output -directory. In this example, "http.yaml" is being built for arm64: +The most recent package can be discovered by searching for the "canary" ref: -``` -$ cipd create --pkg-def gen/fuchsia/cipd/http/http.yaml - -ref latest - -tag version:$(cat gen/fuchsia/cipd/build_id.txt) -``` - -The most recent package can be discovered by searching for the "latest" ref: - -`$ cipd describe chromium/fuchsia/$PACKAGE_NAME-$TARGET_ARCH -version latest` +`$ cipd describe chromium/fuchsia/$PACKAGE_NAME-$TARGET_ARCH -version canary`
diff --git a/fuchsia/engine/web_instance_host/web_instance_host.cc b/fuchsia/engine/web_instance_host/web_instance_host.cc index d59eeef8..df91c66 100644 --- a/fuchsia/engine/web_instance_host/web_instance_host.cc +++ b/fuchsia/engine/web_instance_host/web_instance_host.cc
@@ -120,20 +120,22 @@ return directory.Unbind().TakeChannel(); } -void AppendFeature(base::StringPiece features_flag, - base::StringPiece feature_string, - base::CommandLine* command_line) { - if (!command_line->HasSwitch(features_flag)) { - command_line->AppendSwitchNative(std::string(features_flag), - feature_string); +// Appends |value| to the value of |switch_name| in the |command_line|. +// The switch is assumed to consist of comma-separated values. If |switch_name| +// is already set in |command_line| then a comma will be appended, followed by +// |value|, otherwise the switch will be set to |value|. +void AppendToSwitch(base::StringPiece switch_name, + base::StringPiece value, + base::CommandLine* command_line) { + if (!command_line->HasSwitch(switch_name)) { + command_line->AppendSwitchNative(switch_name, value); return; } - std::string new_feature_string = base::StrCat( - {command_line->GetSwitchValueASCII(features_flag), ",", feature_string}); - command_line->RemoveSwitch(features_flag); - command_line->AppendSwitchNative(std::string(features_flag), - new_feature_string); + std::string new_value = base::StrCat( + {command_line->GetSwitchValueASCII(switch_name), ",", value}); + command_line->RemoveSwitch(switch_name); + command_line->AppendSwitchNative(switch_name, new_value); } // File names must not contain directory separators, nor match the special @@ -247,12 +249,12 @@ if (origin == switches::kAllowRunningInsecureContent) { launch_args->AppendSwitch(switches::kAllowRunningInsecureContent); } else if (origin == kDisableMixedContentAutoupgradeOrigin) { - AppendFeature(switches::kDisableFeatures, - kMixedContentAutoupgradeFeatureName, launch_args); + AppendToSwitch(switches::kDisableFeatures, + kMixedContentAutoupgradeFeatureName, launch_args); } else { // Pass the rest of the list to the Context process. - AppendFeature(network::switches::kUnsafelyTreatInsecureOriginAsSecure, - origin, launch_args); + AppendToSwitch(network::switches::kUnsafelyTreatInsecureOriginAsSecure, + origin, launch_args); } } } @@ -543,10 +545,11 @@ if (use_overlays_for_video) { // Overlays are only available if OutputPresenterFuchsia is in use. - AppendFeature(switches::kEnableFeatures, - features::kUseSkiaOutputDeviceBufferQueue.name, &launch_args); - AppendFeature(switches::kEnableFeatures, - features::kUseRealBuffersForPageFlipTest.name, &launch_args); + AppendToSwitch(switches::kEnableFeatures, + features::kUseSkiaOutputDeviceBufferQueue.name, + &launch_args); + AppendToSwitch(switches::kEnableFeatures, + features::kUseRealBuffersForPageFlipTest.name, &launch_args); launch_args.AppendSwitchASCII(switches::kEnableHardwareOverlays, "underlay"); launch_args.AppendSwitch(switches::kUseOverlaysForVideo); @@ -563,8 +566,8 @@ launch_args.AppendSwitch(switches::kUseVulkan); const std::vector<base::StringPiece> enabled_features = { features::kUseSkiaRenderer.name, features::kVulkan.name}; - AppendFeature(switches::kEnableFeatures, - base::JoinString(enabled_features, ","), &launch_args); + AppendToSwitch(switches::kEnableFeatures, + base::JoinString(enabled_features, ","), &launch_args); // SkiaRenderer requires out-of-process rasterization be enabled. launch_args.AppendSwitch(switches::kEnableOopRasterization); @@ -625,8 +628,8 @@ return ZX_ERR_INVALID_ARGS; } - AppendFeature(switches::kDisableFeatures, - features::kEnableSoftwareOnlyVideoCodecs.name, &launch_args); + AppendToSwitch(switches::kDisableFeatures, + features::kEnableSoftwareOnlyVideoCodecs.name, &launch_args); } if (!HandleCdmDataDirectoryParam(¶ms, &launch_args, &launch_info)) {
diff --git a/fuchsia/runners/common/web_component.cc b/fuchsia/runners/common/web_component.cc index fe1ffad..1bed5bfc 100644 --- a/fuchsia/runners/common/web_component.cc +++ b/fuchsia/runners/common/web_component.cc
@@ -4,14 +4,10 @@ #include "fuchsia/runners/common/web_component.h" -#include <fuchsia/logger/cpp/fidl.h> -#include <fuchsia/sys/cpp/fidl.h> #include <fuchsia/ui/views/cpp/fidl.h> -#include <lib/fidl/cpp/binding_set.h> #include <lib/fit/function.h> #include <lib/sys/cpp/component_context.h> #include <lib/ui/scenic/cpp/view_ref_pair.h> -#include <utility> #include "base/bind.h" #include "base/fuchsia/fuchsia_logging.h"
diff --git a/fuchsia/runners/common/web_component.h b/fuchsia/runners/common/web_component.h index 62471b3..98b7119 100644 --- a/fuchsia/runners/common/web_component.h +++ b/fuchsia/runners/common/web_component.h
@@ -10,7 +10,6 @@ #include <fuchsia/ui/app/cpp/fidl.h> #include <fuchsia/web/cpp/fidl.h> #include <lib/fidl/cpp/binding.h> -#include <lib/fidl/cpp/binding_set.h> #include <memory> #include <string> #include <utility>
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc index 90e5de37..e3a6455 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
@@ -23,12 +23,47 @@ #include "ui/gfx/geometry/rect_conversions.h" #include "ui/gl/ca_renderer_layer_params.h" #include "ui/gl/dc_renderer_layer_params.h" -#include "ui/gl/gl_utils.h" #include "ui/gl/gl_version_info.h" namespace gpu { namespace gles2 { +// Temporarily allows compilation of shaders that use the +// ARB_texture_rectangle/ANGLE_texture_rectangle extension. We don't want to +// expose the extension to WebGL user shaders but we still need to use it for +// parts of the implementation on macOS. Note that the extension is always +// enabled on macOS and this only controls shader compilation. +class GLES2DecoderPassthroughImpl:: + ScopedEnableTextureRectangleInShaderCompiler { + public: + ScopedEnableTextureRectangleInShaderCompiler( + const ScopedEnableTextureRectangleInShaderCompiler&) = delete; + ScopedEnableTextureRectangleInShaderCompiler& operator=( + const ScopedEnableTextureRectangleInShaderCompiler&) = delete; + + // This class is a no-op except on macOS. +#if !defined(OS_MAC) + explicit ScopedEnableTextureRectangleInShaderCompiler( + GLES2DecoderPassthroughImpl* decoder) {} + + private: +#else + explicit ScopedEnableTextureRectangleInShaderCompiler( + GLES2DecoderPassthroughImpl* decoder) + : decoder_(decoder) { + if (decoder_->feature_info_->IsWebGLContext()) + decoder_->api_->glEnableFn(GL_TEXTURE_RECTANGLE_ANGLE); + } + ~ScopedEnableTextureRectangleInShaderCompiler() { + if (decoder_->feature_info_->IsWebGLContext()) + decoder_->api_->glDisableFn(GL_TEXTURE_RECTANGLE_ANGLE); + } + + private: + GLES2DecoderPassthroughImpl* decoder_; +#endif +}; + namespace { template <typename ClientType, typename ServiceType, typename GenFunction> @@ -4470,8 +4505,7 @@ GLboolean unpack_flip_y, GLboolean unpack_premultiply_alpha, GLboolean unpack_unmultiply_alpha) { - gl::ScopedEnableTextureRectangleInShaderCompiler enable( - feature_info_->IsWebGLContext() ? api() : nullptr); + ScopedEnableTextureRectangleInShaderCompiler enable(this); BindPendingImageForClientIDIfNeeded(source_id); api()->glCopyTextureCHROMIUMFn( GetTextureServiceID(api(), source_id, resources_, false), source_level, @@ -4499,8 +4533,7 @@ GLboolean unpack_flip_y, GLboolean unpack_premultiply_alpha, GLboolean unpack_unmultiply_alpha) { - gl::ScopedEnableTextureRectangleInShaderCompiler enable( - feature_info_->IsWebGLContext() ? api() : nullptr); + ScopedEnableTextureRectangleInShaderCompiler enable(this); BindPendingImageForClientIDIfNeeded(source_id); api()->glCopySubTextureCHROMIUMFn( GetTextureServiceID(api(), source_id, resources_, false), source_level,
diff --git a/infra/config/generated/cr-buildbucket.cfg b/infra/config/generated/cr-buildbucket.cfg index 5ec629fd..471fe03 100644 --- a/infra/config/generated/cr-buildbucket.cfg +++ b/infra/config/generated/cr-buildbucket.cfg
@@ -18120,6 +18120,76 @@ } } builders { + name: "Win x64 Builder (reclient)(cross)" + swarming_host: "chromium-swarm.appspot.com" + swarming_tags: "vpython:native-python-wrapper" + dimensions: "builderless:1" + dimensions: "cores:8" + dimensions: "cpu:x86-64" + dimensions: "os:Windows-10" + dimensions: "pool:luci.chromium.ci" + dimensions: "ssd:0" + recipe { + name: "chromium" + cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" + cipd_version: "refs/heads/master" + properties_j: "$build/reclient:{\"instance\":\"rbe-chromium-trusted\",\"metrics_project\":\"chromium-reclient-metrics\"}" + properties_j: "$kitchen:{\"devshell\":true,\"emulate_gce\":true,\"git_auth\":true}" + properties_j: "$recipe_engine/isolated:{\"server\":\"https://isolateserver.appspot.com\"}" + properties_j: "$recipe_engine/resultdb/test_presentation:{\"column_keys\":[],\"grouping_keys\":[\"status\",\"v.test_suite\"]}" + properties_j: "builder_group:\"chromium.fyi\"" + } + execution_timeout_secs: 36000 + build_numbers: YES + service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com" + experiments { + key: "chromium.chromium_tests.use_rbe_cas" + value: 100 + } + experiments { + key: "chromium.resultdb.result_sink" + value: 100 + } + experiments { + key: "chromium.resultdb.result_sink.gtests_local" + value: 100 + } + experiments { + key: "chromium.resultdb.result_sink.junit_tests" + value: 100 + } + experiments { + key: "luci.buildbucket.use_bbagent" + value: 100 + } + experiments { + key: "luci.use_realms" + value: 100 + } + resultdb { + enable: true + bq_exports { + project: "luci-resultdb" + dataset: "chromium" + table: "ci_test_results" + test_results {} + } + bq_exports { + project: "luci-resultdb" + dataset: "chromium" + table: "gpu_ci_test_results" + test_results { + predicate { + test_id_regexp: "ninja://(chrome/test:|content/test:fuchsia_)telemetry_gpu_integration_test/.+" + } + } + } + history_options { + use_invocation_timestamp: true + } + } + } + builders { name: "Win10 FYI x64 DX12 Vulkan Debug (NVIDIA)" swarming_host: "chromium-swarm.appspot.com" swarming_tags: "vpython:native-python-wrapper" @@ -41448,7 +41518,7 @@ name: "chromium_trybot" cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" cipd_version: "refs/heads/master" - properties_j: "$build/goma:{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\",\"use_luci_auth\":true}" + properties_j: "$build/goma:{\"enable_ats\":true,\"jobs\":150,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\",\"use_luci_auth\":true}" properties_j: "$kitchen:{\"devshell\":true,\"git_auth\":true}" properties_j: "$recipe_engine/isolated:{\"server\":\"https://isolateserver.appspot.com\"}" properties_j: "$recipe_engine/resultdb/test_presentation:{\"column_keys\":[],\"grouping_keys\":[\"status\",\"v.test_suite\"]}"
diff --git a/infra/config/generated/luci-milo.cfg b/infra/config/generated/luci-milo.cfg index c4054b1..64480e6f 100644 --- a/infra/config/generated/luci-milo.cfg +++ b/infra/config/generated/luci-milo.cfg
@@ -6478,6 +6478,11 @@ category: "win" short_name: "re" } + builders { + name: "buildbucket/luci.chromium.ci/Win x64 Builder (reclient)(cross)" + category: "win" + short_name: "re x" + } header { oncalls { name: "Chromium"
diff --git a/infra/config/generated/luci-scheduler.cfg b/infra/config/generated/luci-scheduler.cfg index deeec9f..01585dde 100644 --- a/infra/config/generated/luci-scheduler.cfg +++ b/infra/config/generated/luci-scheduler.cfg
@@ -3868,6 +3868,16 @@ } } job { + id: "Win x64 Builder (reclient)(cross)" + realm: "ci" + acl_sets: "ci" + buildbucket { + server: "cr-buildbucket.appspot.com" + bucket: "luci.chromium.ci" + builder: "Win x64 Builder (reclient)(cross)" + } +} +job { id: "Win10 FYI x64 DX12 Vulkan Debug (NVIDIA)" realm: "ci" acls { @@ -7055,6 +7065,7 @@ triggers: "Win x64 Builder" triggers: "Win x64 Builder (dbg)" triggers: "Win x64 Builder (reclient)" + triggers: "Win x64 Builder (reclient)(cross)" triggers: "Win10 FYI x64 SkiaRenderer Dawn Release (NVIDIA)" triggers: "Windows deterministic" triggers: "android-10-arm64-rel"
diff --git a/infra/config/subprojects/chromium/ci.star b/infra/config/subprojects/chromium/ci.star index 93658b5c1..834e6faf 100644 --- a/infra/config/subprojects/chromium/ci.star +++ b/infra/config/subprojects/chromium/ci.star
@@ -3979,6 +3979,20 @@ os = os.WINDOWS_DEFAULT, ) +ci.fyi_windows_builder( + name = "Win x64 Builder (reclient)(cross)", + builderless = True, + console_view_entry = consoles.console_view_entry( + category = "win", + short_name = "re x", + ), + goma_backend = None, + reclient_instance = "rbe-chromium-trusted", + configure_kitchen = True, + kitchen_emulate_gce = True, + os = os.WINDOWS_DEFAULT, +) + ci.fyi_celab_builder( name = "win-celab-builder-rel", console_view_entry = consoles.console_view_entry(
diff --git a/infra/config/subprojects/chromium/try.star b/infra/config/subprojects/chromium/try.star index 18ac6c9da..cb780f6 100644 --- a/infra/config/subprojects/chromium/try.star +++ b/infra/config/subprojects/chromium/try.star
@@ -1917,6 +1917,7 @@ try_.gpu_chromium_android_builder( name = "android_optional_gpu_tests_rel", branch_selector = branches.STANDARD_MILESTONE, + goma_jobs = goma.jobs.J150, main_list_view = "try", tryjob = try_.job( location_regexp = [
diff --git a/ios/chrome/app/strings/resources/ios_strings_ar.xtb b/ios/chrome/app/strings/resources/ios_strings_ar.xtb index 517790aa..c86e32c 100644 --- a/ios/chrome/app/strings/resources/ios_strings_ar.xtb +++ b/ios/chrome/app/strings/resources/ios_strings_ar.xtb
@@ -397,7 +397,7 @@ <translation id="5090832849094901128">لن يؤدي حذف كلمة المرور هذه إلى حذف حسابك على <ph name="WEBSITE" />.</translation> <translation id="5094827893301452931">اكتملت مشاركة Tweet.</translation> <translation id="5118764316110575523">غير مفعَّل</translation> -<translation id="5127805178023152808">المزامنة غير مفعّلة</translation> +<translation id="5127805178023152808">المزامنة متوقفة.</translation> <translation id="5132942445612118989">مزامنة كلمات المرور والسجلّ والمزيد على جميع الأجهزة</translation> <translation id="5140288047769711648">سيتذكّر Chrome كلمة المرور هذه بالنيابة عنك. وبالتالي لن تضطرّ لتذكُّرها كلّ مرّة.</translation> <translation id="5150492518600715772">الإرسال إلى جهازك</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_en-GB.xtb b/ios/chrome/app/strings/resources/ios_strings_en-GB.xtb index 8e116d0..c032cb26 100644 --- a/ios/chrome/app/strings/resources/ios_strings_en-GB.xtb +++ b/ios/chrome/app/strings/resources/ios_strings_en-GB.xtb
@@ -103,7 +103,7 @@ <translation id="1952172573699511566">Websites will show text in your preferred language, when possible.</translation> <translation id="1952728750904661634">Sign in with managed account</translation> <translation id="1965935827552890526">Finish what you were doing in your other open Chrome window.</translation> -<translation id="1973912524893600642">Keep data</translation> +<translation id="1973912524893600642">Keep Data</translation> <translation id="1974060860693918893">Advanced</translation> <translation id="1989112275319619282">Browse</translation> <translation id="2015722694326466240">To see passwords, you must first set a passcode on your device.</translation> @@ -198,7 +198,7 @@ <translation id="2964349545761222050">Block third-party cookies</translation> <translation id="2969979262385602596">Failed to sign in. Please try again later.</translation> <translation id="2975121486251958312">Only Incognito mode is available</translation> -<translation id="2982481275546140226">Clear data</translation> +<translation id="2982481275546140226">Clear Data</translation> <translation id="298306318844797842">Add Payment Method...</translation> <translation id="2989805286512600854">Open in New Tab</translation> <translation id="3037605927509011580">Aw, Snap!</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_gu.xtb b/ios/chrome/app/strings/resources/ios_strings_gu.xtb index a98d9d9..e008c8a4 100644 --- a/ios/chrome/app/strings/resources/ios_strings_gu.xtb +++ b/ios/chrome/app/strings/resources/ios_strings_gu.xtb
@@ -492,6 +492,7 @@ <translation id="6059830886158432458">તમારી સ્ટોરી અને પ્રવૃત્તિને અહીં નિયંત્રિત કરો</translation> <translation id="6066301408025741299">રદ કરવા માટે ટેપ કરો.</translation> <translation id="60829778314739003">સ્વીકારો અને આગળ વધો</translation> +<translation id="6084848228346514841">કોઈ ટૅબ પસંદ કરો</translation> <translation id="6108923351542677676">સેટઅપની પ્રક્રિયા ચાલુ છે...</translation> <translation id="6119050551270742952">વર્તમાન વેબપેજ છૂપા મોડમાં છે</translation> <translation id="6122191549521593678">ઓનલાઇન</translation> @@ -782,6 +783,7 @@ <ph name="BEGIN_LINK" />વધુ જાણો<ph name="END_LINK" /></translation> <translation id="8820817407110198400">બુકમાર્ક</translation> <translation id="8840513115188359703">તમે તમારા Google એકાઉન્ટમાંથી સાઇન આઉટ થશો નહિ.</translation> +<translation id="8868471676553493380">{count,plural, =1{{count} ટૅબ}one{{count} ટૅબ}other{{count} ટૅબ}}</translation> <translation id="8870413625673593573">તાજેતરમાં બંધ કરેલા</translation> <translation id="8876882697946675716">તમારા ડિવાઇસને સિંક કરેલું રાખો</translation> <translation id="8881801611828450202"><ph name="SEARCH_ENGINE" /> પર આ છબી શોધો</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_hy.xtb b/ios/chrome/app/strings/resources/ios_strings_hy.xtb index 2681fece..7567bd3 100644 --- a/ios/chrome/app/strings/resources/ios_strings_hy.xtb +++ b/ios/chrome/app/strings/resources/ios_strings_hy.xtb
@@ -750,7 +750,7 @@ <translation id="8503813439785031346">Օգտանուն</translation> <translation id="850600235656508448">Բացել ինկոգնիտո ռեժիմում</translation> <translation id="8510057420705599706">Դուք դուրս կգրվեք հաշվից, և համաժամացումը կանջատվի, սակայն ձեր էջանիշները, պատմությունը, գաղտնաբառերը և Chrome-ի այլ տվյալներ կպահպանվեն այս սարքում։</translation> -<translation id="8517375800490286174">Բաց կոդով հավելվածների արտոնագրեր</translation> +<translation id="8517375800490286174">Բաց կոդով հավելվածների լիցենզիաներ</translation> <translation id="8524799873541103884"><ph name="INCOGNITO" /> Ներդիրներ <ph name="FIRST_VISIBLE_TAB" /> – <ph name="LAST_VISIBLE_TAB" />՝ <ph name="NUMBER_OF_OPEN_TABS" />-ից</translation> <translation id="8529767659511976195">Նոր</translation> <translation id="8532105204136943229">Ժամկետի սպառման տարեթիվը</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_ne.xtb b/ios/chrome/app/strings/resources/ios_strings_ne.xtb index 205f7f1..74e600fa 100644 --- a/ios/chrome/app/strings/resources/ios_strings_ne.xtb +++ b/ios/chrome/app/strings/resources/ios_strings_ne.xtb
@@ -492,6 +492,7 @@ <translation id="6059830886158432458">यहाँ आफ्नो समाचार फिडमा देखिने सामग्री तथा क्रियाकलाप नियन्त्रण गर्नुहोस्</translation> <translation id="6066301408025741299">रद्द गर्न ट्याप गर्नुहोस्।</translation> <translation id="60829778314739003">स्वीकार गर्नुहोस् र जारी राख्नुहोस्</translation> +<translation id="6084848228346514841">ट्याबहरू चयन गर्नुहोस्</translation> <translation id="6108923351542677676">सेटअप प्रगतिमा छ...</translation> <translation id="6119050551270742952">हालको वेबपृष्ठ इन्कोग्निटो मोडमा छ</translation> <translation id="6122191549521593678">अनलाइन</translation> @@ -782,6 +783,7 @@ <ph name="BEGIN_LINK" />थप जान्नुहोस्<ph name="END_LINK" /></translation> <translation id="8820817407110198400">बुकमार्कहरू</translation> <translation id="8840513115188359703">तपाईं आफ्नो Google खाताबाट साइन आउट हुनु हुने छैन।</translation> +<translation id="8868471676553493380">{count,plural, =1{{count} ट्याब}other{{count} वटा ट्याब}}</translation> <translation id="8870413625673593573">हालै बन्द गरिएको</translation> <translation id="8876882697946675716">आफ्ना डिभाइसहरू सिंक गरिराख्नुहोस्</translation> <translation id="8881801611828450202"><ph name="SEARCH_ENGINE" /> मा यो छवि खोज्नुहोस्</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_pa.xtb b/ios/chrome/app/strings/resources/ios_strings_pa.xtb index 0c86f6ac..759ab0e4 100644 --- a/ios/chrome/app/strings/resources/ios_strings_pa.xtb +++ b/ios/chrome/app/strings/resources/ios_strings_pa.xtb
@@ -781,7 +781,7 @@ <ph name="BEGIN_LINK" />ਹੋਰ ਜਾਣੋ<ph name="END_LINK" /></translation> <translation id="8820817407110198400">Bookmarks</translation> <translation id="8840513115188359703">ਤੁਸੀਂ ਆਪਣੇ 'Google ਖਾਤੇ' ਤੋਂ ਸਾਈਨ-ਆਊਟ ਨਹੀਂ ਹੋਵੋਗੇ।</translation> -<translation id="8868471676553493380">{count,plural, =1{{count} Tab}one{{count} Tab}other{{count} Tabs}}</translation> +<translation id="8868471676553493380">{count,plural, =1{{count} ਟੈਬ}one{{count} ਟੈਬ}other{{count} ਟੈਬਾਂ}}</translation> <translation id="8870413625673593573">ਹੁਣੇ ਜਿਹੇ ਬੰਦ ਕੀਤੀਆਂ</translation> <translation id="8876882697946675716">ਆਪਣੇ ਡੀਵਾਈਸਾਂ ਦਾ ਆਪਸ ਵਿੱਚ ਸਮਕਾਲੀਕਰਨ ਕਰਕੇ ਰੱਖੋ</translation> <translation id="8881801611828450202">ਇਸ ਚਿੱਤਰ ਲਈ <ph name="SEARCH_ENGINE" /> ਖੋਜੋ</translation>
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/BUILD.gn b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/BUILD.gn index 05019059..97721d3 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/BUILD.gn +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/BUILD.gn
@@ -36,6 +36,7 @@ configs += [ "//build/config/compiler:enable_arc" ] testonly = true sources = [ + "save_address_profile_infobar_banner_interaction_handler_unittest.mm", "save_address_profile_infobar_modal_interaction_handler_unittest.mm", "save_address_profile_infobar_modal_overlay_request_callback_installer_unittest.mm", ]
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_banner_interaction_handler.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_banner_interaction_handler.h index b6b8fbf..5db5bc40 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_banner_interaction_handler.h +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_banner_interaction_handler.h
@@ -9,6 +9,10 @@ #import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common/infobar_banner_interaction_handler.h" +namespace autofill { +class AutofillSaveUpdateAddressProfileDelegateIOS; +} + // Helper object that updates the model layer for interaction events with the // SaveAddressProfile infobar banner UI. class SaveAddressProfileInfobarBannerInteractionHandler @@ -18,8 +22,13 @@ ~SaveAddressProfileInfobarBannerInteractionHandler() override; // InfobarBannerInteractionHandler: - void BannerVisibilityChanged(InfoBarIOS* infobar, bool visible) override {} - void BannerDismissedByUser(InfoBarIOS* infobar) override {} + void BannerVisibilityChanged(InfoBarIOS* infobar, bool visible) override; + void BannerDismissedByUser(InfoBarIOS* infobar) override; + + private: + // Returns the SaveAddressProfile delegate from |infobar|. + autofill::AutofillSaveUpdateAddressProfileDelegateIOS* GetInfobarDelegate( + InfoBarIOS* infobar); }; #endif // IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_AUTOFILL_ADDRESS_PROFILE_SAVE_ADDRESS_PROFILE_INFOBAR_BANNER_INTERACTION_HANDLER_H_
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_banner_interaction_handler.mm b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_banner_interaction_handler.mm index 2c41a3a..c981c67 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_banner_interaction_handler.mm +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_banner_interaction_handler.mm
@@ -4,6 +4,7 @@ #import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_banner_interaction_handler.h" +#include "components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.h" #include "ios/chrome/browser/infobars/infobar_ios.h" #import "ios/chrome/browser/overlays/public/infobar_banner/save_address_profile_infobar_banner_overlay_request_config.h" @@ -23,3 +24,20 @@ SaveAddressProfileInfobarBannerInteractionHandler:: ~SaveAddressProfileInfobarBannerInteractionHandler() = default; + +void SaveAddressProfileInfobarBannerInteractionHandler::BannerVisibilityChanged( + InfoBarIOS* infobar, + bool visible) { + if (!visible) { + autofill::AutofillSaveUpdateAddressProfileDelegateIOS::FromInfobarDelegate( + infobar->delegate()) + ->MessageTimeout(); + } +} + +void SaveAddressProfileInfobarBannerInteractionHandler::BannerDismissedByUser( + InfoBarIOS* infobar) { + autofill::AutofillSaveUpdateAddressProfileDelegateIOS::FromInfobarDelegate( + infobar->delegate()) + ->MessageDeclined(); +}
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_banner_interaction_handler_unittest.mm b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_banner_interaction_handler_unittest.mm new file mode 100644 index 0000000..4d4a7716 --- /dev/null +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_banner_interaction_handler_unittest.mm
@@ -0,0 +1,70 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_banner_interaction_handler.h" + +#include "base/guid.h" +#include "ios/chrome/browser/infobars/infobar_manager_impl.h" +#include "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_autofill_save_update_address_profile_delegate_ios.h" +#import "ios/chrome/browser/infobars/overlays/infobar_overlay_request_inserter.h" +#import "ios/chrome/browser/infobars/test/fake_infobar_ios.h" +#include "ios/chrome/browser/infobars/test/mock_infobar_delegate.h" +#import "ios/chrome/browser/overlays/public/overlay_request_queue.h" +#include "testing/platform_test.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +// Test fixture for SaveAddressProfileInfobarBannerInteractionHandler. +class SaveAddressProfileInfobarBannerInteractionHandlerTest + : public PlatformTest { + public: + SaveAddressProfileInfobarBannerInteractionHandlerTest() + : delegate_factory_(), + profile_(base::GenerateGUID(), "https://www.example.com/") { + infobar_ = std::make_unique<InfoBarIOS>( + InfobarType::kInfobarTypeSaveAutofillAddressProfile, + MockAutofillSaveUpdateAddressProfileDelegateIOSFactory:: + CreateMockAutofillSaveUpdateAddressProfileDelegateIOSFactory( + profile_)); + } + + MockAutofillSaveUpdateAddressProfileDelegateIOS& mock_delegate() { + return *static_cast<MockAutofillSaveUpdateAddressProfileDelegateIOS*>( + infobar_->delegate()); + } + + protected: + SaveAddressProfileInfobarBannerInteractionHandler handler_; + MockAutofillSaveUpdateAddressProfileDelegateIOSFactory delegate_factory_; + autofill::AutofillProfile profile_; + std::unique_ptr<InfoBarIOS> infobar_; +}; + +// Tests that user_decision is set to message timeout on BannerVisibilityChanged +// with parameter value as false. +TEST_F(SaveAddressProfileInfobarBannerInteractionHandlerTest, + BannerVisibilityFalse) { + handler_.BannerVisibilityChanged(infobar_.get(), false); + EXPECT_EQ(mock_delegate().user_decision(), + autofill::AutofillClient::SaveAddressProfileOfferUserDecision:: + kMessageTimeout); +} + +// Tests that user_decision is set to message declined on BannerDismissedByUser. +TEST_F(SaveAddressProfileInfobarBannerInteractionHandlerTest, + BannerDismissedByUser) { + handler_.BannerDismissedByUser(infobar_.get()); + EXPECT_EQ(mock_delegate().user_decision(), + autofill::AutofillClient::SaveAddressProfileOfferUserDecision:: + kMessageDeclined); + + handler_.BannerVisibilityChanged(infobar_.get(), false); + // Expect the user decision to be message declined even when + // BannerVisibilityChanged is called. + EXPECT_EQ(mock_delegate().user_decision(), + autofill::AutofillClient::SaveAddressProfileOfferUserDecision:: + kMessageDeclined); +}
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_interaction_handler.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_interaction_handler.h index 70470c39..2d48ff45 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_interaction_handler.h +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_interaction_handler.h
@@ -30,6 +30,10 @@ virtual void SaveEditedProfile(InfoBarIOS* infobar, NSDictionary* profileData); + // Instructs the handler to inform the delegate that the view has been + // cancelled. + virtual void CancelModal(InfoBarIOS* infobar, BOOL fromEditModal); + private: // InfobarModalInteractionHandler: std::unique_ptr<InfobarModalOverlayRequestCallbackInstaller>
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_interaction_handler.mm b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_interaction_handler.mm index e81b919..09ec419 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_interaction_handler.mm +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_interaction_handler.mm
@@ -37,7 +37,18 @@ std::u16string data = base::SysNSStringToUTF16(profileData[key]); GetInfoBarDelegate(infobar)->SetProfileInfo(type, data); } - infobar->set_accepted(GetInfoBarDelegate(infobar)->EditAccepted()); + GetInfoBarDelegate(infobar)->EditAccepted(); + infobar->set_accepted(true); +} + +void SaveAddressProfileInfobarModalInteractionHandler::CancelModal( + InfoBarIOS* infobar, + BOOL fromEditModal) { + if (fromEditModal) { + GetInfoBarDelegate(infobar)->EditDeclined(); + } else { + GetInfoBarDelegate(infobar)->Cancel(); + } } #pragma mark - Private
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_interaction_handler_unittest.mm b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_interaction_handler_unittest.mm index b8e11aa..c98c1f9a 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_interaction_handler_unittest.mm +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_interaction_handler_unittest.mm
@@ -53,6 +53,20 @@ TEST_F(SaveAddressProfileInfobarModalInteractionHandlerTest, SaveEditedProfile) { - EXPECT_CALL(mock_delegate(), EditAccepted()).WillOnce(testing::Return(true)); + EXPECT_CALL(mock_delegate(), EditAccepted()); handler_.SaveEditedProfile(infobar_.get(), @{}.mutableCopy); } + +TEST_F(SaveAddressProfileInfobarModalInteractionHandlerTest, EditDeclined) { + handler_.CancelModal(infobar_.get(), /*fromEditModal=*/YES); + EXPECT_EQ(mock_delegate().user_decision(), + autofill::AutofillClient::SaveAddressProfileOfferUserDecision:: + kEditDeclined); +} + +TEST_F(SaveAddressProfileInfobarModalInteractionHandlerTest, Cancel) { + handler_.CancelModal(infobar_.get(), /*fromEditModal=*/NO); + EXPECT_EQ( + mock_delegate().user_decision(), + autofill::AutofillClient::SaveAddressProfileOfferUserDecision::kDeclined); +}
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_overlay_request_callback_installer.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_overlay_request_callback_installer.h index 34abf92..c9fd884 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_overlay_request_callback_installer.h +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_overlay_request_callback_installer.h
@@ -29,6 +29,12 @@ void SaveEditedProfileDetailsCallback(OverlayRequest* request, OverlayResponse* response); + // Used as a callback for OverlayResponses dispatched through |request|'s + // callback manager. The OverlayDispatchCallback is created with an + // OverlayResponseSupport that guarantees that |response| is created with a + // save_address_profile_infobar_modal_responses::CancelViewAction. + void CancelModalCallback(OverlayRequest* request, OverlayResponse* response); + // OverlayRequestCallbackInstaller: void InstallCallbacksInternal(OverlayRequest* request) override;
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_overlay_request_callback_installer.mm b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_overlay_request_callback_installer.mm index b381969..b13997eb 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_overlay_request_callback_installer.mm +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_overlay_request_callback_installer.mm
@@ -22,6 +22,7 @@ using autofill_address_profile_infobar_overlays:: SaveAddressProfileModalRequestConfig; using save_address_profile_infobar_modal_responses::EditedProfileSaveAction; +using save_address_profile_infobar_modal_responses::CancelViewAction; SaveAddressProfileInfobarModalOverlayRequestCallbackInstaller:: SaveAddressProfileInfobarModalOverlayRequestCallbackInstaller( @@ -47,8 +48,18 @@ } EditedProfileSaveAction* info = response->GetInfo<EditedProfileSaveAction>(); - interaction_handler_->SaveEditedProfile(GetOverlayRequestInfobar(request), - info->profile_data()); + interaction_handler_->SaveEditedProfile(infobar, info->profile_data()); +} + +void SaveAddressProfileInfobarModalOverlayRequestCallbackInstaller:: + CancelModalCallback(OverlayRequest* request, OverlayResponse* response) { + InfoBarIOS* infobar = GetOverlayRequestInfobar(request); + if (!infobar) { + return; + } + + CancelViewAction* info = response->GetInfo<CancelViewAction>(); + interaction_handler_->CancelModal(infobar, info->edit_view_is_dismissed()); } #pragma mark - OverlayRequestCallbackInstaller @@ -65,4 +76,11 @@ SaveEditedProfileDetailsCallback, weak_factory_.GetWeakPtr(), request), EditedProfileSaveAction::ResponseSupport())); + + manager->AddDispatchCallback(OverlayDispatchCallback( + base::BindRepeating( + &SaveAddressProfileInfobarModalOverlayRequestCallbackInstaller:: + CancelModalCallback, + weak_factory_.GetWeakPtr(), request), + CancelViewAction::ResponseSupport())); }
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_overlay_request_callback_installer_unittest.mm b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_overlay_request_callback_installer_unittest.mm index 9cc2364..19e76ad 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_overlay_request_callback_installer_unittest.mm +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_overlay_request_callback_installer_unittest.mm
@@ -31,6 +31,7 @@ using autofill_address_profile_infobar_overlays:: SaveAddressProfileModalRequestConfig; using save_address_profile_infobar_modal_responses::EditedProfileSaveAction; +using save_address_profile_infobar_modal_responses::CancelViewAction; // Test fixture for // SaveAddressProfileInfobarModalOverlayRequestCallbackInstaller. @@ -92,3 +93,11 @@ request_->GetCallbackManager()->DispatchResponse( OverlayResponse::CreateWithInfo<EditedProfileSaveAction>(empty)); } + +TEST_F(SaveAddressProfileInfobarModalOverlayRequestCallbackInstallerTest, + CancelAction) { + BOOL fakeFromEditModal = NO; + EXPECT_CALL(mock_handler_, CancelModal(infobar_, fakeFromEditModal)); + request_->GetCallbackManager()->DispatchResponse( + OverlayResponse::CreateWithInfo<CancelViewAction>(fakeFromEditModal)); +}
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_autofill_save_update_address_profile_delegate_ios.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_autofill_save_update_address_profile_delegate_ios.h index b7a2fd6..b99ed1db 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_autofill_save_update_address_profile_delegate_ios.h +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_autofill_save_update_address_profile_delegate_ios.h
@@ -25,8 +25,7 @@ ~MockAutofillSaveUpdateAddressProfileDelegateIOS() override; MOCK_METHOD0(Accept, bool()); - MOCK_METHOD0(InfoBarDismissed, void()); - MOCK_METHOD0(EditAccepted, bool()); + MOCK_METHOD0(EditAccepted, void()); }; class MockAutofillSaveUpdateAddressProfileDelegateIOSFactory {
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_save_address_profile_modal_infobar_interaction_handler.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_save_address_profile_modal_infobar_interaction_handler.h index 696c1a9..cc09123c 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_save_address_profile_modal_infobar_interaction_handler.h +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_save_address_profile_modal_infobar_interaction_handler.h
@@ -21,6 +21,7 @@ MOCK_METHOD2(SaveEditedProfile, void(InfoBarIOS* infobar, NSDictionary* profileData)); + MOCK_METHOD2(CancelModal, void(InfoBarIOS* infobar, BOOL fromEditView)); }; #endif // IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_TEST_MOCK_SAVE_ADDRESS_PROFILE_MODAL_INFOBAR_INTERACTION_HANDLER_H_
diff --git a/ios/chrome/browser/overlays/public/infobar_modal/save_address_profile_infobar_modal_overlay_responses.h b/ios/chrome/browser/overlays/public/infobar_modal/save_address_profile_infobar_modal_overlay_responses.h index c50aea50..a8eaa4c 100644 --- a/ios/chrome/browser/overlays/public/infobar_modal/save_address_profile_infobar_modal_overlay_responses.h +++ b/ios/chrome/browser/overlays/public/infobar_modal/save_address_profile_infobar_modal_overlay_responses.h
@@ -27,6 +27,21 @@ NSDictionary* profile_data_; }; +// Response info used to create dispatched OverlayResponses once the user +// cancels the modal. +class CancelViewAction : public OverlayResponseInfo<CancelViewAction> { + public: + ~CancelViewAction() override; + + BOOL edit_view_is_dismissed() const { return edit_view_is_dismissed_; } + + private: + OVERLAY_USER_DATA_SETUP(CancelViewAction); + CancelViewAction(BOOL edit_view_is_dismissed); + + BOOL edit_view_is_dismissed_; +}; + } // namespace save_address_profile_infobar_modal_responses #endif // IOS_CHROME_BROWSER_OVERLAYS_PUBLIC_INFOBAR_MODAL_SAVE_ADDRESS_PROFILE_INFOBAR_MODAL_OVERLAY_RESPONSES_H_
diff --git a/ios/chrome/browser/overlays/public/infobar_modal/save_address_profile_infobar_modal_overlay_responses.mm b/ios/chrome/browser/overlays/public/infobar_modal/save_address_profile_infobar_modal_overlay_responses.mm index 0c0f1b7d..c5f1137 100644 --- a/ios/chrome/browser/overlays/public/infobar_modal/save_address_profile_infobar_modal_overlay_responses.mm +++ b/ios/chrome/browser/overlays/public/infobar_modal/save_address_profile_infobar_modal_overlay_responses.mm
@@ -19,4 +19,13 @@ EditedProfileSaveAction::~EditedProfileSaveAction() = default; +#pragma mark - CancelViewAction + +OVERLAY_USER_DATA_SETUP_IMPL(CancelViewAction); + +CancelViewAction::CancelViewAction(BOOL edit_view_is_dismissed) + : edit_view_is_dismissed_(edit_view_is_dismissed) {} + +CancelViewAction::~CancelViewAction() = default; + } // save_address_profile_infobar_modal_responses
diff --git a/ios/chrome/browser/reading_list/offline_page_tab_helper_unittest.mm b/ios/chrome/browser/reading_list/offline_page_tab_helper_unittest.mm index a78a63b..9922e1ba 100644 --- a/ios/chrome/browser/reading_list/offline_page_tab_helper_unittest.mm +++ b/ios/chrome/browser/reading_list/offline_page_tab_helper_unittest.mm
@@ -151,14 +151,10 @@ class OfflinePageTabHelperTest : public web::WebTest { public: void SetUp() override { - web::WebTest::SetUp(); - TestChromeBrowserState::Builder test_cbs_builder; - base::FilePath test_data_dir; - ASSERT_TRUE(base::PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir)); - test_data_dir = test_data_dir.AppendASCII(kTestDirectory); - test_cbs_builder.SetPath(test_data_dir); - chrome_browser_state_ = test_cbs_builder.Build(); - fake_web_state_.SetBrowserState(chrome_browser_state_.get()); + // Ensure that the EXPECT_TRUE in CreateBrowserState() passed. + ASSERT_NO_FATAL_FAILURE(web::WebTest::SetUp()); + + fake_web_state_.SetBrowserState(GetBrowserState()); fake_web_state_.SetNavigationManager( std::make_unique<web::FakeNavigationManager>()); reading_list_model_ = std::make_unique<ReadingListModelImpl>( @@ -170,8 +166,16 @@ reading_list_model_.get()); } + std::unique_ptr<web::BrowserState> CreateBrowserState() override { + TestChromeBrowserState::Builder test_cbs_builder; + base::FilePath test_data_dir; + EXPECT_TRUE(base::PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir)); + test_data_dir = test_data_dir.AppendASCII(kTestDirectory); + test_cbs_builder.SetPath(test_data_dir); + return test_cbs_builder.Build(); + } + protected: - std::unique_ptr<TestChromeBrowserState> chrome_browser_state_; std::unique_ptr<ReadingListModelImpl> reading_list_model_; web::FakeWebState fake_web_state_; }; @@ -180,14 +184,10 @@ // ReadingListModel. class OfflinePageTabHelperDelayedModelTest : public web::WebTest { void SetUp() override { - web::WebTest::SetUp(); - TestChromeBrowserState::Builder test_cbs_builder; - base::FilePath test_data_dir; - ASSERT_TRUE(base::PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir)); - test_data_dir = test_data_dir.AppendASCII(kTestDirectory); - test_cbs_builder.SetPath(test_data_dir); - chrome_browser_state_ = test_cbs_builder.Build(); - fake_web_state_.SetBrowserState(chrome_browser_state_.get()); + // Ensure that the EXPECT_TRUE in CreateBrowserState() passed. + ASSERT_NO_FATAL_FAILURE(web::WebTest::SetUp()); + + fake_web_state_.SetBrowserState(GetBrowserState()); fake_web_state_.SetNavigationManager( std::make_unique<web::FakeNavigationManager>()); fake_reading_list_model_ = std::make_unique<FakeReadingListModel>(); @@ -202,8 +202,16 @@ fake_reading_list_model_.get()); } + std::unique_ptr<web::BrowserState> CreateBrowserState() override { + TestChromeBrowserState::Builder test_cbs_builder; + base::FilePath test_data_dir; + EXPECT_TRUE(base::PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir)); + test_data_dir = test_data_dir.AppendASCII(kTestDirectory); + test_cbs_builder.SetPath(test_data_dir); + return test_cbs_builder.Build(); + } + protected: - std::unique_ptr<TestChromeBrowserState> chrome_browser_state_; std::unique_ptr<FakeReadingListModel> fake_reading_list_model_; web::FakeWebState fake_web_state_; std::unique_ptr<ReadingListEntry> entry_;
diff --git a/ios/chrome/browser/safe_browsing/safe_browsing_egtest.mm b/ios/chrome/browser/safe_browsing/safe_browsing_egtest.mm index 3518d97..aa93408 100644 --- a/ios/chrome/browser/safe_browsing/safe_browsing_egtest.mm +++ b/ios/chrome/browser/safe_browsing/safe_browsing_egtest.mm
@@ -137,6 +137,20 @@ _safeURL2 = self.testServer->GetURL("/echo_also_safe"); _safeContent2 = "also_safe"; + if (@available(iOS 15.1, *)) { + } else { + if (@available(iOS 14.5, *)) { + // Workaround https://bugs.webkit.org/show_bug.cgi?id=226323, which breaks + // some back/forward navigations between pages that share a renderer + // process. Use 'localhost' instead of '127.0.0.1' for safe URLs to + // prevent sharing renderer processes with unsafe URLs. + GURL::Replacements replacements; + replacements.SetHostStr("localhost"); + _safeURL1 = _safeURL1.ReplaceComponents(replacements); + _safeURL2 = _safeURL2.ReplaceComponents(replacements); + } + } + // |appConfigurationForTestCase| is called during [super setUp], and // depends on the URLs initialized above. [super setUp];
diff --git a/ios/chrome/browser/signin/gaia_auth_fetcher_ios_ns_url_session_bridge_unittests.mm b/ios/chrome/browser/signin/gaia_auth_fetcher_ios_ns_url_session_bridge_unittests.mm index 00ae940..edf5087d 100644 --- a/ios/chrome/browser/signin/gaia_auth_fetcher_ios_ns_url_session_bridge_unittests.mm +++ b/ios/chrome/browser/signin/gaia_auth_fetcher_ios_ns_url_session_bridge_unittests.mm
@@ -159,8 +159,6 @@ friend TestGaiaAuthFetcherIOSNSURLSessionBridge; - // Browser state for the tests. - std::unique_ptr<ChromeBrowserState> browser_state_; // Instance used for the tests. std::unique_ptr<TestGaiaAuthFetcherIOSNSURLSessionBridge> ns_url_session_bridge_; @@ -196,10 +194,11 @@ #pragma mark - GaiaAuthFetcherIOSNSURLSessionBridgeTest void GaiaAuthFetcherIOSNSURLSessionBridgeTest::SetUp() { + ChromeWebTest::SetUp(); + delegate_.reset(new FakeGaiaAuthFetcherIOSBridgeDelegate()); - browser_state_ = TestChromeBrowserState::Builder().Build(); ns_url_session_bridge_.reset(new TestGaiaAuthFetcherIOSNSURLSessionBridge( - delegate_.get(), browser_state_.get(), this)); + delegate_.get(), GetBrowserState(), this)); url_session_configuration_ = NSURLSessionConfiguration.ephemeralSessionConfiguration; url_session_configuration_.HTTPShouldSetCookies = YES; @@ -220,6 +219,7 @@ void GaiaAuthFetcherIOSNSURLSessionBridgeTest::TearDown() { ASSERT_OCMOCK_VERIFY((id)url_session_mock_); + ChromeWebTest::TearDown(); } NSURLSession* GaiaAuthFetcherIOSNSURLSessionBridgeTest::CreateNSURLSession( @@ -242,7 +242,7 @@ std::vector<net::CanonicalCookie> cookies_out; base::RunLoop run_loop; network::mojom::CookieManager* cookie_manager = - browser_state_->GetCookieManager(); + GetBrowserState()->GetCookieManager(); cookie_manager->GetAllCookies(base::BindOnce(base::BindLambdaForTesting( [&run_loop, &cookies_out](const std::vector<net::CanonicalCookie>& cookies) { @@ -301,7 +301,7 @@ bool GaiaAuthFetcherIOSNSURLSessionBridgeTest::SetCookiesInCookieManager( NSArray<NSHTTPCookie*>* cookies) { network::mojom::CookieManager* cookie_manager = - browser_state_->GetCookieManager(); + GetBrowserState()->GetCookieManager(); for (NSHTTPCookie* cookie in cookies) { std::unique_ptr<net::CanonicalCookie> canonical_cookie = net::CanonicalCookieFromSystemCookie(cookie, base::Time::Now());
diff --git a/ios/chrome/browser/ssl/ios_ssl_error_handler_unittest.mm b/ios/chrome/browser/ssl/ios_ssl_error_handler_unittest.mm index 6b71024..a7fbe9d 100644 --- a/ios/chrome/browser/ssl/ios_ssl_error_handler_unittest.mm +++ b/ios/chrome/browser/ssl/ios_ssl_error_handler_unittest.mm
@@ -36,8 +36,7 @@ class IOSSSLErrorHandlerTest : public web::WebTestWithWebState { protected: IOSSSLErrorHandlerTest() - : browser_state_(builder_.Build()), - cert_(net::ImportCertFromFile(net::GetTestCertsDirectory(), + : cert_(net::ImportCertFromFile(net::GetTestCertsDirectory(), kTestCertFileName)) {} // web::WebTestWithWebState overrides: @@ -64,15 +63,17 @@ AddPendingItem(GURL(kTestHostName), ui::PageTransition::PAGE_TRANSITION_TYPED); } - web::BrowserState* GetBrowserState() override { return browser_state_.get(); } + + std::unique_ptr<web::BrowserState> CreateBrowserState() override { + TestChromeBrowserState::Builder builder; + return builder.Build(); + } // Returns certificate for testing. scoped_refptr<net::X509Certificate> cert() { return cert_; } private: network::TestURLLoaderFactory test_loader_factory_; - TestChromeBrowserState::Builder builder_; - std::unique_ptr<TestChromeBrowserState> browser_state_; scoped_refptr<net::X509Certificate> cert_; };
diff --git a/ios/chrome/browser/ui/content_suggestions/BUILD.gn b/ios/chrome/browser/ui/content_suggestions/BUILD.gn index 11e88ed..dbfc569 100644 --- a/ios/chrome/browser/ui/content_suggestions/BUILD.gn +++ b/ios/chrome/browser/ui/content_suggestions/BUILD.gn
@@ -331,6 +331,7 @@ "//ios/chrome/browser:utils", "//ios/chrome/browser/ui/ntp:constants", "//ios/chrome/browser/ui/settings:constants", + "//ios/chrome/browser/ui/start_surface:feature_flags", "//ios/chrome/browser/ui/toolbar/public:constants", "//ios/chrome/test:eg_test_support+eg2", "//ios/chrome/test/earl_grey:eg_test_support+eg2",
diff --git a/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm b/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm index c583ae0..b79eaee 100644 --- a/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm +++ b/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm
@@ -15,6 +15,7 @@ #import "ios/chrome/browser/ui/content_suggestions/ntp_home_constant.h" #import "ios/chrome/browser/ui/ntp/new_tab_page_constants.h" #import "ios/chrome/browser/ui/settings/settings_table_view_controller_constants.h" +#import "ios/chrome/browser/ui/start_surface/start_surface_features.h" #import "ios/chrome/browser/ui/toolbar/public/toolbar_constants.h" #include "ios/chrome/grit/ios_strings.h" #import "ios/chrome/test/earl_grey/chrome_earl_grey.h" @@ -127,6 +128,7 @@ AppLaunchConfiguration config; config.additional_args.push_back(std::string("--") + switches::kEnableDiscoverFeed); + config.features_disabled.push_back(kStartSurface); return config; }
diff --git a/ios/chrome/browser/ui/main/scene_controller.mm b/ios/chrome/browser/ui/main/scene_controller.mm index afc1ac09..bf350d8 100644 --- a/ios/chrome/browser/ui/main/scene_controller.mm +++ b/ios/chrome/browser/ui/main/scene_controller.mm
@@ -1584,12 +1584,6 @@ return; } - // Suppress iPad web sign-in. - // TODO(crbug.com/1211794): Remove iPad suppression once the UI is adapted. - if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) { - return; - } - self.signinCoordinator = [SigninCoordinator consistencyPromoSigninCoordinatorWithBaseViewController:baseViewController browser:self.mainInterface
diff --git a/ios/chrome/browser/ui/overlays/infobar_modal/autofill_address_profile/BUILD.gn b/ios/chrome/browser/ui/overlays/infobar_modal/autofill_address_profile/BUILD.gn index 1ce3b31..7e4eb8db 100644 --- a/ios/chrome/browser/ui/overlays/infobar_modal/autofill_address_profile/BUILD.gn +++ b/ios/chrome/browser/ui/overlays/infobar_modal/autofill_address_profile/BUILD.gn
@@ -21,6 +21,7 @@ "//ios/chrome/browser/overlays/public/common/infobars", "//ios/chrome/browser/overlays/public/infobar_modal", "//ios/chrome/browser/ui/infobars/modals", + "//ios/chrome/browser/ui/infobars/modals:public", "//ios/chrome/browser/ui/overlays:coordinators", "//ios/chrome/browser/ui/overlays/infobar_modal:coordinators", "//ios/chrome/browser/ui/overlays/infobar_modal:mediators",
diff --git a/ios/chrome/browser/ui/overlays/infobar_modal/autofill_address_profile/save_address_profile_infobar_modal_overlay_mediator.mm b/ios/chrome/browser/ui/overlays/infobar_modal/autofill_address_profile/save_address_profile_infobar_modal_overlay_mediator.mm index 7ba26d4..8ea2b038 100644 --- a/ios/chrome/browser/ui/overlays/infobar_modal/autofill_address_profile/save_address_profile_infobar_modal_overlay_mediator.mm +++ b/ios/chrome/browser/ui/overlays/infobar_modal/autofill_address_profile/save_address_profile_infobar_modal_overlay_mediator.mm
@@ -4,10 +4,13 @@ #import "ios/chrome/browser/ui/overlays/infobar_modal/autofill_address_profile/save_address_profile_infobar_modal_overlay_mediator.h" +#include "base/metrics/user_metrics.h" +#include "base/metrics/user_metrics_action.h" #include "base/strings/sys_string_conversions.h" #import "ios/chrome/browser/overlays/public/infobar_modal/save_address_profile_infobar_modal_overlay_request_config.h" #import "ios/chrome/browser/overlays/public/infobar_modal/save_address_profile_infobar_modal_overlay_responses.h" #import "ios/chrome/browser/ui/infobars/modals/infobar_edit_address_profile_modal_consumer.h" +#import "ios/chrome/browser/ui/infobars/modals/infobar_modal_constants.h" #import "ios/chrome/browser/ui/infobars/modals/infobar_save_address_profile_modal_consumer.h" #import "ios/chrome/browser/ui/overlays/infobar_modal/infobar_modal_overlay_coordinator+modal_configuration.h" #import "ios/chrome/browser/ui/overlays/overlay_request_mediator+subclassing.h" @@ -20,11 +23,14 @@ using autofill_address_profile_infobar_overlays:: SaveAddressProfileModalRequestConfig; using save_address_profile_infobar_modal_responses::EditedProfileSaveAction; +using save_address_profile_infobar_modal_responses::CancelViewAction; @interface SaveAddressProfileInfobarModalOverlayMediator () // The save address profile modal config from the request. @property(nonatomic, assign, readonly) SaveAddressProfileModalRequestConfig* config; +// YES if the edit modal is being shown. +@property(nonatomic, assign) BOOL currentViewIsEditView; @end @implementation SaveAddressProfileInfobarModalOverlayMediator @@ -91,6 +97,8 @@ if (!self.request) { return; } + + self.currentViewIsEditView = YES; [self.saveAddressProfileMediatorDelegate showEditView]; } @@ -103,4 +111,13 @@ [self dismissOverlay]; } +- (void)dismissInfobarModal:(id)infobarModal { + [self dispatchResponse:OverlayResponse::CreateWithInfo<CancelViewAction>( + self.currentViewIsEditView)]; + base::RecordAction(base::UserMetricsAction(kInfobarModalCancelButtonTapped)); + [self dismissOverlay]; + + self.currentViewIsEditView = NO; +} + @end
diff --git a/ios/chrome/browser/ui/overlays/infobar_modal/autofill_address_profile/save_address_profile_infobar_modal_overlay_mediator_unittest.mm b/ios/chrome/browser/ui/overlays/infobar_modal/autofill_address_profile/save_address_profile_infobar_modal_overlay_mediator_unittest.mm index 8b55889..aeb5081 100644 --- a/ios/chrome/browser/ui/overlays/infobar_modal/autofill_address_profile/save_address_profile_infobar_modal_overlay_mediator_unittest.mm +++ b/ios/chrome/browser/ui/overlays/infobar_modal/autofill_address_profile/save_address_profile_infobar_modal_overlay_mediator_unittest.mm
@@ -29,13 +29,15 @@ using autofill_address_profile_infobar_overlays:: SaveAddressProfileModalRequestConfig; using save_address_profile_infobar_modal_responses::EditedProfileSaveAction; +using save_address_profile_infobar_modal_responses::CancelViewAction; // Test fixture for SaveAddressProfileInfobarModalOverlayMediator. class SaveAddressProfileInfobarModalOverlayMediatorTest : public PlatformTest { public: SaveAddressProfileInfobarModalOverlayMediatorTest() : callback_installer_(&callback_receiver_, - {EditedProfileSaveAction::ResponseSupport()}), + {EditedProfileSaveAction::ResponseSupport(), + CancelViewAction::ResponseSupport()}), mediator_delegate_( OCMStrictProtocolMock(@protocol(OverlayRequestMediatorDelegate))) { autofill::AutofillProfile profile = autofill::test::GetFullProfile(); @@ -83,3 +85,12 @@ OCMExpect([mediator_delegate_ stopOverlayForMediator:mediator_]); [mediator_ saveEditedProfileWithData:@{}.mutableCopy]; } + +// Tests that calling dismissInfobarModal triggers a CancelViewAction response. +TEST_F(SaveAddressProfileInfobarModalOverlayMediatorTest, CancelAction) { + EXPECT_CALL( + callback_receiver_, + DispatchCallback(request_.get(), CancelViewAction::ResponseSupport())); + OCMExpect([mediator_delegate_ stopOverlayForMediator:mediator_]); + [mediator_ dismissInfobarModal:nil]; +}
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_mediator_unittest.mm b/ios/chrome/browser/ui/popup_menu/popup_menu_mediator_unittest.mm index 33477b2..ba02c134 100644 --- a/ios/chrome/browser/ui/popup_menu/popup_menu_mediator_unittest.mm +++ b/ios/chrome/browser/ui/popup_menu/popup_menu_mediator_unittest.mm
@@ -94,7 +94,12 @@ class PopupMenuMediatorTest : public ChromeWebTest { public: - PopupMenuMediatorTest() : ChromeWebTest(std::make_unique<ChromeWebClient>()) { + PopupMenuMediatorTest() + : ChromeWebTest(std::make_unique<ChromeWebClient>()) {} + + void SetUp() override { + ChromeWebTest::SetUp(); + reading_list_model_.reset(new ReadingListModelImpl( nullptr, nullptr, base::DefaultClock::GetInstance())); popup_menu_ = OCMClassMock([PopupMenuTableViewController class]); @@ -105,9 +110,7 @@ SetUpWebStateList(); // Set up the TestBrowser. - TestChromeBrowserState::Builder browser_state_builder; - browser_state_ = browser_state_builder.Build(); - browser_ = std::make_unique<TestBrowser>(browser_state_.get(), + browser_ = std::make_unique<TestBrowser>(GetTestChromeBrowserState(), web_state_list_.get()); // Set up the OverlayPresenter. OverlayPresenter::FromBrowser(browser_.get(), @@ -115,13 +118,24 @@ ->SetPresentationContext(&presentation_context_); } - // Explicitly disconnect the mediator so there won't be any WebStateList - // observers when web_state_list_ gets dealloc. - ~PopupMenuMediatorTest() override { + void TearDown() override { + // Explicitly disconnect the mediator so there won't be any WebStateList + // observers when web_state_list_ gets dealloc. [mediator_ disconnect]; + + ChromeWebTest::TearDown(); + } + + std::unique_ptr<web::BrowserState> CreateBrowserState() override { + TestChromeBrowserState::Builder builder; + return builder.Build(); } protected: + TestChromeBrowserState* GetTestChromeBrowserState() { + return static_cast<TestChromeBrowserState*>(GetBrowserState()); + } + PopupMenuMediator* CreateMediator(PopupMenuType type, BOOL is_incognito, BOOL trigger_incognito_hint) { @@ -156,9 +170,9 @@ } void SetUpBookmarks() { - browser_state_->CreateBookmarkModel(false); - bookmark_model_ = - ios::BookmarkModelFactory::GetForBrowserState(browser_state_.get()); + GetTestChromeBrowserState()->CreateBookmarkModel(false); + bookmark_model_ = ios::BookmarkModelFactory::GetForBrowserState( + GetTestChromeBrowserState()); bookmarks::test::WaitForBookmarkModelToLoad(bookmark_model_); mediator_.bookmarkModel = bookmark_model_; } @@ -252,7 +266,6 @@ FakeOverlayPresentationContext presentation_context_; std::unique_ptr<WebStateList> web_state_list_; FakeWebStateListDelegate web_state_list_delegate_; - std::unique_ptr<TestChromeBrowserState> browser_state_; std::unique_ptr<Browser> browser_; PopupMenuMediator* mediator_; BookmarkModel* bookmark_model_;
diff --git a/ios/chrome/browser/ui/settings/block_popups_table_view_controller.mm b/ios/chrome/browser/ui/settings/block_popups_table_view_controller.mm index afe4dae..9176f6cd0 100644 --- a/ios/chrome/browser/ui/settings/block_popups_table_view_controller.mm +++ b/ios/chrome/browser/ui/settings/block_popups_table_view_controller.mm
@@ -292,7 +292,11 @@ for (NSIndexPath* indexPath in indexPaths) { size_t urlIndex = indexPath.item; std::string urlToRemove; - _exceptions.GetString(urlIndex, &urlToRemove); + base::Value::ListView exceptions_view = _exceptions.GetList(); + if (urlIndex < exceptions_view.size() && + exceptions_view[urlIndex].is_string()) { + urlToRemove = exceptions_view[urlIndex].GetString(); + } // Remove the exception for the site by resetting its popup setting to the // default. @@ -303,7 +307,7 @@ CONTENT_SETTING_DEFAULT); // Remove the site from |_exceptions|. - _exceptions.Remove(urlIndex, NULL); + _exceptions.EraseListIter(exceptions_view.begin() + urlIndex); } [self.tableView performBatchUpdates:^{ NSInteger exceptionsSection = [self.tableViewModel
diff --git a/ios/chrome/browser/ui/settings/privacy/privacy_table_view_controller.mm b/ios/chrome/browser/ui/settings/privacy/privacy_table_view_controller.mm index f552798..de38f4eb 100644 --- a/ios/chrome/browser/ui/settings/privacy/privacy_table_view_controller.mm +++ b/ios/chrome/browser/ui/settings/privacy/privacy_table_view_controller.mm
@@ -177,7 +177,7 @@ [model addItem:[self handoffDetailItem] toSectionWithIdentifier:SectionIdentifierWebServices]; - // Do not show the incognito authentication setting when Incongito mode is + // Do not show the incognito authentication setting when Incognito mode is // disabled. if (base::FeatureList::IsEnabled(kIncognitoAuthentication) && !IsIncognitoModeDisabled(_browserState->GetPrefs())) {
diff --git a/ios/chrome/browser/ui/start_surface/start_surface_egtest.mm b/ios/chrome/browser/ui/start_surface/start_surface_egtest.mm index e1f1fe93..ce05d00 100644 --- a/ios/chrome/browser/ui/start_surface/start_surface_egtest.mm +++ b/ios/chrome/browser/ui/start_surface/start_surface_egtest.mm
@@ -24,9 +24,6 @@ - (AppLaunchConfiguration)appConfigurationForTestCase { AppLaunchConfiguration config; - config.additional_args.push_back( - std::string("--enable-features=StartSurface:" - "ReturnToStartSurfaceInactiveDurationInSeconds/0")); config.relaunch_policy = ForceRelaunchByCleanShutdown; return config; }
diff --git a/ios/chrome/browser/web/lookalike_url_app_interface.mm b/ios/chrome/browser/web/lookalike_url_app_interface.mm index b2ec43e..1c1e8b1 100644 --- a/ios/chrome/browser/web/lookalike_url_app_interface.mm +++ b/ios/chrome/browser/web/lookalike_url_app_interface.mm
@@ -46,6 +46,16 @@ if (response_url.path() == kLookalikePagePathForTesting) { GURL::Replacements safeReplacements; safeReplacements.SetPathStr("echo"); + if (@available(iOS 15.1, *)) { + } else { + if (@available(iOS 14.5, *)) { + // Workaround https://bugs.webkit.org/show_bug.cgi?id=226323, which + // breaks some back/forward navigations between pages that share a + // renderer process. Use 'localhost' instead of '127.0.0.1' for the + // safe URL to prevent sharing renderer processes with unsafe URLs. + safeReplacements.SetHostStr("localhost"); + } + } lookalike_container->SetLookalikeUrlInfo( response_url.ReplaceComponents(safeReplacements), response_url, LookalikeUrlMatchType::kSkeletonMatchTop5k);
diff --git a/ios/chrome/browser/web/lookalike_url_egtest.mm b/ios/chrome/browser/web/lookalike_url_egtest.mm index 0531dfc..23b8a24 100644 --- a/ios/chrome/browser/web/lookalike_url_egtest.mm +++ b/ios/chrome/browser/web/lookalike_url_egtest.mm
@@ -96,6 +96,19 @@ l10n_util::GetStringUTF8(IDS_LOOKALIKE_URL_PRIMARY_PARAGRAPH); _lookalikeBlockingPageNoSuggestionContent = l10n_util::GetStringUTF8( IDS_LOOKALIKE_URL_PRIMARY_PARAGRAPH_NO_SUGGESTED_URL); + + if (@available(iOS 15.1, *)) { + } else { + if (@available(iOS 14.5, *)) { + // Workaround https://bugs.webkit.org/show_bug.cgi?id=226323, which breaks + // some back/forward navigations between pages that share a renderer + // process. Use 'localhost' instead of '127.0.0.1' for the safe URL to + // prevent sharing renderer processes with unsafe URLs. + GURL::Replacements replacements; + replacements.SetHostStr("localhost"); + _safeURL = _safeURL.ReplaceComponents(replacements); + } + } } - (void)tearDown {
diff --git a/ios/web/js_messaging/crw_wk_script_message_router_unittest.mm b/ios/web/js_messaging/crw_wk_script_message_router_unittest.mm index 789d831..fd66b2b2 100644 --- a/ios/web/js_messaging/crw_wk_script_message_router_unittest.mm +++ b/ios/web/js_messaging/crw_wk_script_message_router_unittest.mm
@@ -87,15 +87,15 @@ // Test fixture for CRWWKScriptMessageRouter. class CRWWKScriptMessageRouterTest : public web::WebTest { public: - CRWWKScriptMessageRouterTest() - : web_client_(base::WrapUnique(new web::WebClient())) {} + CRWWKScriptMessageRouterTest() = default; protected: void SetUp() override { web::WebTest::SetUp(); web::WKWebViewConfigurationProvider& configuration_provider = - web::WKWebViewConfigurationProvider::FromBrowserState(&browser_state_); + web::WKWebViewConfigurationProvider::FromBrowserState( + GetBrowserState()); WKWebViewConfiguration* configuration = configuration_provider.GetWebViewConfiguration(); // Mock WKUserContentController object. @@ -117,9 +117,9 @@ name1_ = [@"name1" copy]; name2_ = [@"name2" copy]; name3_ = [@"name3" copy]; - web_view1_ = web::BuildWKWebView(CGRectZero, &browser_state_); - web_view2_ = web::BuildWKWebView(CGRectZero, &browser_state_); - web_view3_ = web::BuildWKWebView(CGRectZero, &browser_state_); + web_view1_ = web::BuildWKWebView(CGRectZero, GetBrowserState()); + web_view2_ = web::BuildWKWebView(CGRectZero, GetBrowserState()); + web_view3_ = web::BuildWKWebView(CGRectZero, GetBrowserState()); } void TearDown() override { [user_content_controller_ checkExpectations]; @@ -143,11 +143,6 @@ WKWebView* web_view1_; WKWebView* web_view2_; WKWebView* web_view3_; - - private: - // WebClient and BrowserState for testing. - web::ScopedTestingWebClient web_client_; - web::FakeBrowserState browser_state_; }; // Tests CRWWKScriptMessageRouter designated initializer.
diff --git a/ios/web/web_state/ui/crw_web_controller_unittest.mm b/ios/web/web_state/ui/crw_web_controller_unittest.mm index cb7af00..7a3a559 100644 --- a/ios/web/web_state/ui/crw_web_controller_unittest.mm +++ b/ios/web/web_state/ui/crw_web_controller_unittest.mm
@@ -857,10 +857,13 @@ return policy_match; } - // Return an owned BrowserState in order to set off the record state. - BrowserState* GetBrowserState() override { return &browser_state_; } + std::unique_ptr<BrowserState> CreateBrowserState() override { + return std::make_unique<FakeBrowserState>(); + } - FakeBrowserState browser_state_; + FakeBrowserState* GetFakeBrowserState() { + return static_cast<FakeBrowserState*>(GetBrowserState()); + } }; // Tests that App specific URLs in iframes are allowed if the main frame is App @@ -880,7 +883,7 @@ // Tests that URL is allowed in OffTheRecord mode when the // |kBlockUniversalLinksInOffTheRecordMode| feature is disabled. TEST_F(CRWWebControllerPolicyDeciderTest, AllowOffTheRecordNavigation) { - browser_state_.SetOffTheRecord(true); + GetFakeBrowserState()->SetOffTheRecord(true); base::test::ScopedFeatureList feature_list; feature_list.InitAndDisableFeature( web::features::kBlockUniversalLinksInOffTheRecordMode); @@ -897,7 +900,7 @@ // and the BLOCK_UNIVERSAL_LINKS_IN_OFF_THE_RECORD_MODE buildflag is set. TEST_F(CRWWebControllerPolicyDeciderTest, AllowOffTheRecordNavigationBlockUniversalLinks) { - browser_state_.SetOffTheRecord(true); + GetFakeBrowserState()->SetOffTheRecord(true); base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature( web::features::kBlockUniversalLinksInOffTheRecordMode); @@ -1301,7 +1304,7 @@ protected: void SetUp() override { WebTestWithWebController::SetUp(); - FakeBrowserState browser_state; + web_view_ = [[CRWFakeWKWebViewObserverCount alloc] init]; CRWFakeWebViewContentView* webViewContentView = [[CRWFakeWebViewContentView alloc]
diff --git a/ios/web/web_state/web_state_impl_unittest.mm b/ios/web/web_state/web_state_impl_unittest.mm index a2a643f..e6edce30 100644 --- a/ios/web/web_state/web_state_impl_unittest.mm +++ b/ios/web/web_state/web_state_impl_unittest.mm
@@ -29,7 +29,6 @@ #import "ios/web/public/session/crw_session_storage.h" #import "ios/web/public/session/serializable_user_data_manager.h" #import "ios/web/public/test/fakes/async_web_state_policy_decider.h" -#include "ios/web/public/test/fakes/fake_browser_state.h" #import "ios/web/public/test/fakes/fake_java_script_dialog_presenter.h" #import "ios/web/public/test/fakes/fake_navigation_context.h" #import "ios/web/public/test/fakes/fake_web_frame.h"
diff --git a/media/blink/key_system_config_selector.cc b/media/blink/key_system_config_selector.cc index 0acaf77d..1175e7e4 100644 --- a/media/blink/key_system_config_selector.cc +++ b/media/blink/key_system_config_selector.cc
@@ -12,6 +12,7 @@ #include "base/metrics/histogram_macros.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" +#include "build/build_config.h" #include "media/base/cdm_config.h" #include "media/base/key_system_names.h" #include "media/base/key_systems.h" @@ -657,14 +658,18 @@ // permission has already been denied. This would happen anyway later. EmeFeatureSupport distinctive_identifier_support = key_systems_->GetDistinctiveIdentifierSupport(key_system); +#if !defined(OS_ANDROID) // NOTE: This is an additional action we are taking here that is not in the // spec currently. Specifically, we are not allowing a distinctive identifier - // for cross-origin frames. + // for cross-origin frames. We do not do this on Android because there is no + // CDM selection available to Chrome that doesn't require a distinct + // identifier. if (web_frame_delegate_->IsCrossOriginToMainFrame()) { if (distinctive_identifier_support == EmeFeatureSupport::ALWAYS_ENABLED) return CONFIGURATION_NOT_SUPPORTED; distinctive_identifier_support = EmeFeatureSupport::NOT_SUPPORTED; } +#endif // !defined(OS_ANDROID) EmeConfigRule di_rule = GetDistinctiveIdentifierConfigRule( distinctive_identifier_support, distinctive_identifier); if (!config_state->IsRuleSupported(di_rule)) {
diff --git a/media/blink/key_system_config_selector_unittest.cc b/media/blink/key_system_config_selector_unittest.cc index ea82741..3b6d68b 100644 --- a/media/blink/key_system_config_selector_unittest.cc +++ b/media/blink/key_system_config_selector_unittest.cc
@@ -8,6 +8,7 @@ #include "base/bind.h" #include "base/macros.h" #include "base/strings/pattern.h" +#include "build/build_config.h" #include "media/base/cdm_config.h" #include "media/base/eme_constants.h" #include "media/base/key_systems.h" @@ -733,7 +734,13 @@ config.distinctive_identifier = MediaKeysRequirement::kOptional; configs_.push_back(config); +#if defined(OS_ANDROID) + SelectConfigRequestsPermissionAndReturnsConfig(); + EXPECT_EQ(MediaKeysRequirement::kRequired, config_.distinctive_identifier); + EXPECT_TRUE(cdm_config_.allow_distinctive_identifier); +#else SelectConfigReturnsError(); +#endif // defined(OS_ANDROID) } TEST_F(KeySystemConfigSelectorTest, @@ -746,7 +753,13 @@ config.distinctive_identifier = MediaKeysRequirement::kRequired; configs_.push_back(config); +#if defined(OS_ANDROID) + SelectConfigRequestsPermissionAndReturnsConfig(); + EXPECT_EQ(MediaKeysRequirement::kRequired, config_.distinctive_identifier); + EXPECT_TRUE(cdm_config_.allow_distinctive_identifier); +#else SelectConfigReturnsError(); +#endif // defined(OS_ANDROID) } // --- persistentState --- @@ -1248,9 +1261,13 @@ config.video_capabilities = video_capabilities; configs_.push_back(config); +#if defined(OS_ANDROID) + SelectConfigRequestsPermissionAndReturnsConfig(); +#else SelectConfigReturnsConfig(); - ASSERT_EQ(1u, config_.video_capabilities.size()); +#endif // defined(OS_ANDROID) EXPECT_EQ(MediaKeysRequirement::kNotAllowed, config_.distinctive_identifier); + ASSERT_EQ(1u, config_.video_capabilities.size()); } TEST_F(KeySystemConfigSelectorTest,
diff --git a/net/base/features.cc b/net/base/features.cc index 54f8b3e..630d372d 100644 --- a/net/base/features.cc +++ b/net/base/features.cc
@@ -239,5 +239,8 @@ base::FEATURE_DISABLED_BY_DEFAULT}; #endif // defined(OS_POSIX) || defined(OS_FUCHSIA) +const base::Feature kCookieSameSiteConsidersRedirectChain{ + "CookieSameSiteConsidersRedirectChain", base::FEATURE_DISABLED_BY_DEFAULT}; + } // namespace features } // namespace net
diff --git a/net/base/features.h b/net/base/features.h index b91cc925..b97d7dd 100644 --- a/net/base/features.h +++ b/net/base/features.h
@@ -348,6 +348,14 @@ NET_EXPORT extern const base::Feature kUdpSocketPosixAlwaysUpdateBytesReceived; #endif // defined(OS_POSIX) || defined(OS_FUCHSIA) +// When this feature is enabled, redirected requests will be considered +// cross-site for the purpose of SameSite cookies if any redirect hop was +// cross-site to the target URL, even if the original initiator of the +// redirected request was same-site with the target URL (and the +// site-for-cookies). +// See spec changes in https://github.com/httpwg/http-extensions/pull/1348 +NET_EXPORT extern const base::Feature kCookieSameSiteConsidersRedirectChain; + } // namespace features } // namespace net
diff --git a/net/cookies/canonical_cookie.cc b/net/cookies/canonical_cookie.cc index 83232c7..adba3ec 100644 --- a/net/cookies/canonical_cookie.cc +++ b/net/cookies/canonical_cookie.cc
@@ -475,7 +475,6 @@ } // static -// TODO(crbug.com/957184): This should ideally return a CookieInclusionStatus. std::unique_ptr<CanonicalCookie> CanonicalCookie::CreateSanitizedCookie( const GURL& url, const std::string& name, @@ -489,49 +488,88 @@ bool http_only, CookieSameSite same_site, CookiePriority priority, - bool same_party) { + bool same_party, + CookieInclusionStatus* status) { + // Put a pointer on the stack so the rest of the function can assign to it if + // the default nullptr is passed in. + CookieInclusionStatus blank_status; + if (status == nullptr) { + status = &blank_status; + } + *status = CookieInclusionStatus(); + // Validate consistency of passed arguments. if (ParsedCookie::ParseTokenString(name) != name || - ParsedCookie::ParseValueString(value) != value || - !ParsedCookie::IsValidCookieAttributeValue(name) || - !ParsedCookie::IsValidCookieAttributeValue(value) || - ParsedCookie::ParseValueString(domain) != domain || - ParsedCookie::ParseValueString(path) != path) { - return nullptr; + !ParsedCookie::IsValidCookieAttributeValue(name)) { + status->AddExclusionReason( + net::CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE); + } else if (ParsedCookie::ParseValueString(value) != value || + !ParsedCookie::IsValidCookieAttributeValue(value)) { + status->AddExclusionReason( + net::CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE); + } else if (ParsedCookie::ParseValueString(path) != path) { + status->AddExclusionReason( + net::CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE); + } else if (name.empty() && value.empty()) { + status->AddExclusionReason( + net::CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE); } - if (name.empty() && value.empty()) - return nullptr; - - // This validation step must happen before GetCookieDomainWithString, so it - // doesn't fail DCHECKs. - if (!cookie_util::DomainIsHostOnly(url.host())) - return nullptr; + if (ParsedCookie::ParseValueString(domain) != domain) { + status->AddExclusionReason( + net::CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN); + } std::string cookie_domain; - if (!cookie_util::GetCookieDomainWithString(url, domain, &cookie_domain)) - return nullptr; + // This validation step must happen before GetCookieDomainWithString, so it + // doesn't fail DCHECKs. + if (!cookie_util::DomainIsHostOnly(url.host())) { + status->AddExclusionReason( + net::CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN); + } else if (!cookie_util::GetCookieDomainWithString(url, domain, + &cookie_domain)) { + status->AddExclusionReason( + net::CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN); + } - CookieSourceScheme source_scheme = url.SchemeIsCryptographic() - ? CookieSourceScheme::kSecure - : CookieSourceScheme::kNonSecure; + CookieSourceScheme source_scheme = CookieSourceScheme::kNonSecure; + // This validation step must happen before SchemeIsCryptographic, so it + // doesn't fail DCHECKs. + if (!url.is_valid()) { + status->AddExclusionReason( + net::CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN); + } else { + source_scheme = url.SchemeIsCryptographic() + ? CookieSourceScheme::kSecure + : CookieSourceScheme::kNonSecure; + } // Get the port, this will get a default value if a port isn't provided. int source_port = url.EffectiveIntPort(); std::string cookie_path = CanonicalCookie::CanonPathWithString(url, path); - if (!path.empty() && cookie_path != path) - return nullptr; + if (!path.empty() && cookie_path != path) { + status->AddExclusionReason( + net::CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE); + } if (!IsCookiePrefixValid(GetCookiePrefix(name), url, secure, domain, cookie_path)) { - return nullptr; + status->AddExclusionReason( + net::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX); } - if (!IsCookieSamePartyValid(same_party, secure, same_site)) - return nullptr; + if (!IsCookieSamePartyValid(same_party, secure, same_site)) { + status->AddExclusionReason( + net::CookieInclusionStatus::EXCLUDE_INVALID_SAMEPARTY); + } - if (!last_access_time.is_null() && creation_time.is_null()) + if (!last_access_time.is_null() && creation_time.is_null()) { + status->AddExclusionReason( + net::CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE); + } + + if (!status->IsInclude()) return nullptr; // Canonicalize path again to make sure it escapes characters as needed.
diff --git a/net/cookies/canonical_cookie.h b/net/cookies/canonical_cookie.h index f716ed3f..d012b081 100644 --- a/net/cookies/canonical_cookie.h +++ b/net/cookies/canonical_cookie.h
@@ -89,8 +89,9 @@ // Create a canonical cookie based on sanitizing the passed inputs in the // context of the passed URL. Returns a null unique pointer if the inputs - // cannot be sanitized. If a cookie is created, |cookie->IsCanonical()| - // will be true. + // cannot be sanitized. If `status` is provided it will have any relevant + // CookieInclusionStatus rejection reasons set. If a cookie is created, + // `cookie->IsCanonical()` will be true. static std::unique_ptr<CanonicalCookie> CreateSanitizedCookie( const GURL& url, const std::string& name, @@ -104,7 +105,8 @@ bool http_only, CookieSameSite same_site, CookiePriority priority, - bool same_party); + bool same_party, + CookieInclusionStatus* status = nullptr); // FromStorage is a factory method which is meant for creating a new // CanonicalCookie using properties of a previously existing cookie
diff --git a/net/cookies/canonical_cookie_unittest.cc b/net/cookies/canonical_cookie_unittest.cc index 871d85fa..a07e60f 100644 --- a/net/cookies/canonical_cookie_unittest.cc +++ b/net/cookies/canonical_cookie_unittest.cc
@@ -2212,13 +2212,14 @@ base::Time one_hour_ago = base::Time::Now() - base::TimeDelta::FromHours(1); base::Time one_hour_from_now = base::Time::Now() + base::TimeDelta::FromHours(1); - + CookieInclusionStatus status; std::unique_ptr<CanonicalCookie> cc; + cc = CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "A", "B", std::string(), "/foo", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, - COOKIE_PRIORITY_DEFAULT, false /*same_party*/); + COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status); EXPECT_TRUE(cc); EXPECT_EQ("A", cc->Name()); EXPECT_EQ("B", cc->Value()); @@ -2233,87 +2234,97 @@ EXPECT_EQ(COOKIE_PRIORITY_MEDIUM, cc->Priority()); EXPECT_FALSE(cc->IsSameParty()); EXPECT_FALSE(cc->IsDomainCookie()); + EXPECT_TRUE(status.IsInclude()); // Creation date cc = CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "A", "B", std::string(), "/foo", two_hours_ago, base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, - COOKIE_PRIORITY_DEFAULT, false /*same_party*/); + COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status); EXPECT_TRUE(cc); EXPECT_EQ(two_hours_ago, cc->CreationDate()); + EXPECT_TRUE(status.IsInclude()); // Last access date cc = CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "A", "B", std::string(), "/foo", two_hours_ago, base::Time(), one_hour_ago, false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, - COOKIE_PRIORITY_DEFAULT, false /*same_party*/); + COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status); EXPECT_TRUE(cc); EXPECT_EQ(one_hour_ago, cc->LastAccessDate()); + EXPECT_TRUE(status.IsInclude()); // Expiry cc = CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "A", "B", std::string(), "/foo", base::Time(), one_hour_from_now, base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, - COOKIE_PRIORITY_DEFAULT, false /*same_party*/); + COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status); EXPECT_TRUE(cc); EXPECT_EQ(one_hour_from_now, cc->ExpiryDate()); + EXPECT_TRUE(status.IsInclude()); // Secure cc = CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "A", "B", std::string(), "/foo", base::Time(), base::Time(), base::Time(), true /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, - COOKIE_PRIORITY_DEFAULT, false /*same_party*/); + COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status); EXPECT_TRUE(cc); EXPECT_TRUE(cc->IsSecure()); + EXPECT_TRUE(status.IsInclude()); // Httponly cc = CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "A", "B", std::string(), "/foo", base::Time(), base::Time(), base::Time(), false /*secure*/, true /*httponly*/, CookieSameSite::NO_RESTRICTION, - COOKIE_PRIORITY_DEFAULT, false /*same_party*/); + COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status); EXPECT_TRUE(cc); EXPECT_TRUE(cc->IsHttpOnly()); + EXPECT_TRUE(status.IsInclude()); // Same site cc = CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "A", "B", std::string(), "/foo", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::LAX_MODE, COOKIE_PRIORITY_DEFAULT, - false /*same_party*/); + false /*same_party*/, &status); EXPECT_TRUE(cc); EXPECT_EQ(CookieSameSite::LAX_MODE, cc->SameSite()); + EXPECT_TRUE(status.IsInclude()); // Priority cc = CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "A", "B", std::string(), "/foo", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW, - false /*same_party*/); + false /*same_party*/, &status); EXPECT_TRUE(cc); EXPECT_EQ(COOKIE_PRIORITY_LOW, cc->Priority()); + EXPECT_TRUE(status.IsInclude()); // Domain cookie cc = CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "A", "B", "www.foo.com", "/foo", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, - COOKIE_PRIORITY_DEFAULT, false /*same_party*/); + COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status); EXPECT_TRUE(cc); EXPECT_TRUE(cc->IsDomainCookie()); + EXPECT_TRUE(status.IsInclude()); // SameParty cc = CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "A", "B", std::string(), "/foo", base::Time(), base::Time(), base::Time(), true /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW, - true /*same_party*/); + true /*same_party*/, &status); EXPECT_TRUE(cc); EXPECT_TRUE(cc->IsSameParty()); + EXPECT_TRUE(status.IsInclude()); } // Make sure sanitization and blocking of cookies works correctly. @@ -2322,103 +2333,135 @@ base::Time one_hour_ago = base::Time::Now() - base::TimeDelta::FromHours(1); base::Time one_hour_from_now = base::Time::Now() + base::TimeDelta::FromHours(1); + CookieInclusionStatus status; // Simple path and domain variations. EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com/foo"), "A", "B", std::string(), "/foo", one_hour_ago, one_hour_from_now, base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, - COOKIE_PRIORITY_DEFAULT, false /*same_party*/)); + COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status)); + EXPECT_TRUE(status.IsInclude()); EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com/bar"), "C", "D", "www.foo.com", "/", two_hours_ago, base::Time(), one_hour_ago, false /*secure*/, true /*httponly*/, CookieSameSite::NO_RESTRICTION, - COOKIE_PRIORITY_DEFAULT, false /*same_party*/)); + COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status)); + EXPECT_TRUE(status.IsInclude()); EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "E", "F", std::string(), std::string(), base::Time(), base::Time(), base::Time(), true /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, - COOKIE_PRIORITY_DEFAULT, false /*same_party*/)); + COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status)); + EXPECT_TRUE(status.IsInclude()); // Test the file:// protocol. EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie( GURL("file:///"), "A", "B", std::string(), "/foo", one_hour_ago, one_hour_from_now, base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT, - false /*same_party*/)); + false /*same_party*/, &status)); + EXPECT_TRUE(status.IsInclude()); EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie( GURL("file:///home/user/foo.txt"), "A", "B", std::string(), "/foo", one_hour_ago, one_hour_from_now, base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, - COOKIE_PRIORITY_DEFAULT, false /*same_party*/)); + COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status)); + EXPECT_TRUE(status.IsInclude()); EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("file:///home/user/foo.txt"), "A", "B", "home", "/foo", one_hour_ago, one_hour_from_now, base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT, - false /*same_party*/)); + false /*same_party*/, &status)); + EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN})); // Test that malformed attributes fail to set the cookie. EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com/foo"), " A", "B", std::string(), "/foo", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, - COOKIE_PRIORITY_DEFAULT, false /*same_party*/)); + COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status)); + EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE})); EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com/foo"), "A;", "B", std::string(), "/foo", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, - COOKIE_PRIORITY_DEFAULT, false /*same_party*/)); + COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status)); + EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE})); EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com/foo"), "A=", "B", std::string(), "/foo", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, - COOKIE_PRIORITY_DEFAULT, false /*same_party*/)); + COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status)); + EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE})); EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com/foo"), "A\x07", "B", std::string(), "/foo", one_hour_ago, one_hour_from_now, base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, - COOKIE_PRIORITY_DEFAULT, false /*same_party*/)); + COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status)); + EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE})); EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com"), "A", " B", std::string(), "/foo", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, - COOKIE_PRIORITY_DEFAULT, false /*same_party*/)); + COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status)); + EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE})); EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com"), "A", "\x0fZ", std::string(), "/foo", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, - COOKIE_PRIORITY_DEFAULT, false /*same_party*/)); + COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status)); + EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE})); EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com"), "A", "B", "www.foo.com ", "/foo", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, - COOKIE_PRIORITY_DEFAULT, false /*same_party*/)); + COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status)); + EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN})); EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com/foo"), "A", "B", "foo.ozzzzzzle", "/foo", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, - COOKIE_PRIORITY_DEFAULT, false /*same_party*/)); + COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status)); + EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN})); EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com/foo"), "A", "B", std::string(), "foo", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, - COOKIE_PRIORITY_DEFAULT, false /*same_party*/)); + COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status)); + EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE})); EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com"), "A", "B", std::string(), "/foo ", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, - COOKIE_PRIORITY_DEFAULT, false /*same_party*/)); + COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status)); + EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE})); EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com/foo"), "A", "B", "%2Efoo.com", "/foo", one_hour_ago, one_hour_from_now, base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, - COOKIE_PRIORITY_DEFAULT, false /*same_party*/)); + COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status)); + EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN})); EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("http://domaintest.%E3%81%BF%E3%82%93%E3%81%AA"), "A", "B", "domaintest.%E3%81%BF%E3%82%93%E3%81%AA", "/foo", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT, - false /*same_party*/)); + false /*same_party*/, &status)); + EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN})); std::unique_ptr<CanonicalCookie> cc; @@ -2428,133 +2471,163 @@ GURL("http://www.foo.com/foo"), "A", "B", "www.foo.com", "/foo", one_hour_ago, one_hour_from_now, base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, - COOKIE_PRIORITY_DEFAULT, false /*same_party*/); + COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status); ASSERT_TRUE(cc); EXPECT_TRUE(cc->IsDomainCookie()); EXPECT_EQ(".www.foo.com", cc->Domain()); + EXPECT_TRUE(status.IsInclude()); cc = CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com/foo"), "A", "B", ".www.foo.com", "/foo", one_hour_ago, one_hour_from_now, base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, - COOKIE_PRIORITY_DEFAULT, false /*same_party*/); + COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status); ASSERT_TRUE(cc); EXPECT_TRUE(cc->IsDomainCookie()); EXPECT_EQ(".www.foo.com", cc->Domain()); + EXPECT_TRUE(status.IsInclude()); cc = CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com/foo"), "A", "B", ".foo.com", "/foo", one_hour_ago, one_hour_from_now, base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, - COOKIE_PRIORITY_DEFAULT, false /*same_party*/); + COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status); ASSERT_TRUE(cc); EXPECT_TRUE(cc->IsDomainCookie()); EXPECT_EQ(".foo.com", cc->Domain()); + EXPECT_TRUE(status.IsInclude()); cc = CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com/foo"), "A", "B", ".www2.www.foo.com", "/foo", one_hour_ago, one_hour_from_now, base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, - COOKIE_PRIORITY_DEFAULT, false /*same_party*/); + COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status); EXPECT_FALSE(cc); + EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN})); // Secure/URL Scheme mismatch. EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com"), "A", "B", std::string(), "/foo ", base::Time(), base::Time(), base::Time(), true /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, - COOKIE_PRIORITY_DEFAULT, false /*same_party*/)); + COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status)); + EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE})); // Null creation date/non-null last access date conflict. EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com"), "A", "B", std::string(), "/foo", base::Time(), base::Time(), base::Time::Now(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT, - false /*same_party*/)); + false /*same_party*/, &status)); + EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE})); // Domain doesn't match URL EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com"), "A", "B", "www.bar.com", "/", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT, - false /*same_party*/)); + false /*same_party*/, &status)); + EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN})); // Path with unusual characters escaped. cc = CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com"), "A", "B", std::string(), "/foo", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, - COOKIE_PRIORITY_DEFAULT, false /*same_party*/); + COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status); ASSERT_TRUE(cc); EXPECT_EQ("/foo%7F", cc->Path()); + EXPECT_TRUE(status.IsInclude()); // Empty name and value. EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com"), "", "", std::string(), "/", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT, - false /*same_party*/)); + false /*same_party*/, &status)); + EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE})); // A __Secure- cookie must be Secure. EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "__Secure-A", "B", ".www.foo.com", "/", two_hours_ago, one_hour_from_now, one_hour_ago, true, false, CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT, - false)); + false /*same_party*/, &status)); + EXPECT_TRUE(status.IsInclude()); EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "__Secure-A", "B", ".www.foo.com", "/", two_hours_ago, one_hour_from_now, one_hour_ago, false, false, CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT, - false)); + false /*same_party*/, &status)); + EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); // A __Host- cookie must be Secure. EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "__Host-A", "B", std::string(), "/", two_hours_ago, one_hour_from_now, one_hour_ago, true, false, CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT, - false)); + false /*same_party*/, &status)); + EXPECT_TRUE(status.IsInclude()); EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "__Host-A", "B", std::string(), "/", two_hours_ago, one_hour_from_now, one_hour_ago, false, false, CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT, - false)); + false /*same_party*/, &status)); + EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); // A __Host- cookie must have path "/". EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "__Host-A", "B", std::string(), "/", two_hours_ago, one_hour_from_now, one_hour_ago, true, false, CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT, - false)); + false /*same_party*/, &status)); + EXPECT_TRUE(status.IsInclude()); EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "__Host-A", "B", std::string(), "/foo", two_hours_ago, one_hour_from_now, one_hour_ago, true, false, CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT, - false)); + false /*same_party*/, &status)); + EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); // A __Host- cookie must not specify a domain. EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "__Host-A", "B", std::string(), "/", two_hours_ago, one_hour_from_now, one_hour_ago, true, false, CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT, - false)); + false /*same_party*/, &status)); + EXPECT_TRUE(status.IsInclude()); EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "__Host-A", "B", ".www.foo.com", "/", two_hours_ago, one_hour_from_now, one_hour_ago, true, false, CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT, - false)); + false /*same_party*/, &status)); + EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); + // Without __Host- prefix, this is a valid host cookie because it does not // specify a domain. EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "A", "B", std::string(), "/", two_hours_ago, one_hour_from_now, one_hour_ago, true, false, CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT, - false)); + false /*same_party*/, &status)); + EXPECT_TRUE(status.IsInclude()); + // Without __Host- prefix, this is a valid domain (not host) cookie. EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "A", "B", ".www.foo.com", "/", two_hours_ago, one_hour_from_now, one_hour_ago, true, false, CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT, - false)); + false /*same_party*/, &status)); + EXPECT_TRUE(status.IsInclude()); // The __Host- prefix should not prevent otherwise-valid host cookies from // being accepted. @@ -2562,24 +2635,29 @@ GURL("https://127.0.0.1"), "A", "B", std::string(), "/", two_hours_ago, one_hour_from_now, one_hour_ago, true, false, CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT, - false)); + false /*same_party*/, &status)); + EXPECT_TRUE(status.IsInclude()); EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie( GURL("https://127.0.0.1"), "__Host-A", "B", std::string(), "/", two_hours_ago, one_hour_from_now, one_hour_ago, true, false, CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT, - false)); + false /*same_party*/, &status)); + EXPECT_TRUE(status.IsInclude()); + // Host cookies should not specify domain unless it is an IP address that // matches the URL. EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie( GURL("https://127.0.0.1"), "A", "B", "127.0.0.1", "/", two_hours_ago, one_hour_from_now, one_hour_ago, true, false, CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT, - false)); + false /*same_party*/, &status)); + EXPECT_TRUE(status.IsInclude()); EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie( GURL("https://127.0.0.1"), "__Host-A", "B", "127.0.0.1", "/", two_hours_ago, one_hour_from_now, one_hour_ago, true, false, CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT, - false)); + false /*same_party*/, &status)); + EXPECT_TRUE(status.IsInclude()); // SameParty attribute requires Secure and forbids SameSite=Strict. EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie( @@ -2587,21 +2665,28 @@ one_hour_from_now, one_hour_ago, true /*secure*/, false, CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT, true /*same_party*/)); + EXPECT_TRUE(status.IsInclude()); EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "A", "B", ".www.foo.com", "/", two_hours_ago, one_hour_from_now, one_hour_ago, false /*secure*/, false, CookieSameSite::LAX_MODE, CookiePriority::COOKIE_PRIORITY_DEFAULT, - true /*same_party*/)); + true /*same_party*/, &status)); + EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_INVALID_SAMEPARTY})); EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "A", "B", ".www.foo.com", "/", two_hours_ago, one_hour_from_now, one_hour_ago, true /*secure*/, false, CookieSameSite::STRICT_MODE, CookiePriority::COOKIE_PRIORITY_DEFAULT, - true /*same_party*/)); + true /*same_party*/, &status)); + EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_INVALID_SAMEPARTY})); EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "A", "B", ".www.foo.com", "/", two_hours_ago, one_hour_from_now, one_hour_ago, false /*secure*/, false, CookieSameSite::STRICT_MODE, CookiePriority::COOKIE_PRIORITY_DEFAULT, - true /*same_party*/)); + true /*same_party*/, &status)); + EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_INVALID_SAMEPARTY})); // Check that CreateSanitizedCookie can gracefully fail on inputs that would // crash cookie_util::GetCookieDomainWithString due to failing @@ -2611,36 +2696,60 @@ EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("http://..."), "A", "B", "...", "/", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, - CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT, false)); + CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT, + false /*same_party*/, &status)); + EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN})); EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("http://."), "A", "B", std::string(), "/", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, - CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT, false)); + CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT, + false /*same_party*/, &status)); + EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN})); EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("http://.chromium.org"), "A", "B", ".chromium.org", "/", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, - COOKIE_PRIORITY_DEFAULT, false)); + COOKIE_PRIORITY_DEFAULT, false /*same_party*/, &status)); + EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN})); // Check that a file URL with an IPv6 host, and matching IPv6 domain, are // valid. EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie( GURL("file://[A::]"), "A", "B", "[A::]", "", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, - CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT, false)); + CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT, + false /*same_party*/, &status)); + EXPECT_TRUE(status.IsInclude()); // On Windows, URLs beginning with two backslashes are considered file // URLs. On other platforms, they are invalid. auto double_backslash_ipv6_cookie = CanonicalCookie::CreateSanitizedCookie( GURL("\\\\[A::]"), "A", "B", "[A::]", "", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, - CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT, false); + CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT, + false /*same_party*/, &status); #if defined(OS_WIN) EXPECT_TRUE(double_backslash_ipv6_cookie); EXPECT_TRUE(double_backslash_ipv6_cookie->IsCanonical()); + EXPECT_TRUE(status.IsInclude()); #else EXPECT_FALSE(double_backslash_ipv6_cookie); + EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN})); #endif + + // Confirm multiple error types can be set. + EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( + GURL(""), "", "", "", "", base::Time(), base::Time(), base::Time::Now(), + true /*secure*/, true /*httponly*/, CookieSameSite::STRICT_MODE, + COOKIE_PRIORITY_DEFAULT, true /*same_party*/, &status)); + EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE, + CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN, + CookieInclusionStatus::EXCLUDE_INVALID_SAMEPARTY})); } TEST(CanonicalCookieTest, FromStorage) {
diff --git a/net/cookies/cookie_util.cc b/net/cookies/cookie_util.cc index e1ecfcbd5..5300a57 100644 --- a/net/cookies/cookie_util.cc +++ b/net/cookies/cookie_util.cc
@@ -146,8 +146,12 @@ url_chain.size() == 1u || base::ranges::all_of(url_chain, is_same_site_with_site_for_cookies); - if (same_site_initiator && same_site_redirect_chain) + if (same_site_initiator && + (!base::FeatureList::IsEnabled( + features::kCookieSameSiteConsidersRedirectChain) || + same_site_redirect_chain)) { return {ContextType::SAME_SITE_STRICT, false}; + } if (is_http) { base::UmaHistogramBoolean("Cookie.SameSiteContextAffectedByBugfix1166211",
diff --git a/net/cookies/cookie_util_unittest.cc b/net/cookies/cookie_util_unittest.cc index 166b397..e41c755 100644 --- a/net/cookies/cookie_util_unittest.cc +++ b/net/cookies/cookie_util_unittest.cc
@@ -363,17 +363,25 @@ // Tests for the various ComputeSameSiteContextFor*() functions. The first // boolean test param is whether the results of the computations are evaluated // schemefully. The second boolean test param is whether the fix for -// crbug.com/1166211 is enabled. +// crbug.com/1166211 is enabled. The third boolean param is whether SameSite +// considers redirect chains. class CookieUtilComputeSameSiteContextTest - : public ::testing::TestWithParam<std::tuple<bool, bool>> { + : public ::testing::TestWithParam<std::tuple<bool, bool, bool>> { public: CookieUtilComputeSameSiteContextTest() { - // No need to explicitly enable the feature because it is enabled by - // default. - if (!IsBugfix1166211Enabled()) { - feature_list_.InitAndDisableFeature( - features::kSameSiteCookiesBugfix1166211); + std::vector<base::Feature> enabled_features; + std::vector<base::Feature> disabled_features; + // No need to explicitly enable the Bugfix1166211 feature because it + // is enabled by default. + if (!IsBugfix1166211Enabled()) + disabled_features.push_back(features::kSameSiteCookiesBugfix1166211); + // No need to explicitly disable the redirect chain feature because it + // is disabled by default. + if (DoesSameSiteConsiderRedirectChain()) { + enabled_features.push_back( + features::kCookieSameSiteConsidersRedirectChain); } + feature_list_.InitWithFeatures(enabled_features, disabled_features); } ~CookieUtilComputeSameSiteContextTest() override = default; @@ -384,6 +392,10 @@ bool IsBugfix1166211Enabled() const { return std::get<1>(GetParam()); } + bool DoesSameSiteConsiderRedirectChain() const { + return std::get<2>(GetParam()); + } + // Returns the proper gtest matcher to use for the schemeless/schemeful mode. auto ContextTypeIs(ContextType context_type) const { return ContextTypeIsWithSchemefulMode(context_type, IsSchemeful()); @@ -967,38 +979,66 @@ bool url_chain_is_same_site; bool site_for_cookies_is_same_site; bool initiator_is_same_site; + // These are the expected context types considering redirect chains: ContextType expected_context_type; // for non-main-frame-nav requests. ContextType expected_context_type_for_main_frame_navigation; + // These are the expected context types not considering redirect chains: + ContextType expected_context_type_without_chain; + ContextType expected_context_type_for_main_frame_navigation_without_chain; } kTestCases[] = { + // If the url chain is same-site, then the result is the same with or + // without considering the redirect chain. {"GET", true, true, true, ContextType::SAME_SITE_STRICT, + ContextType::SAME_SITE_STRICT, ContextType::SAME_SITE_STRICT, ContextType::SAME_SITE_STRICT}, - {"GET", true, true, false, incorrectly_lax, ContextType::SAME_SITE_LAX}, + {"GET", true, true, false, incorrectly_lax, ContextType::SAME_SITE_LAX, + incorrectly_lax, ContextType::SAME_SITE_LAX}, {"GET", true, false, true, ContextType::CROSS_SITE, + ContextType::CROSS_SITE, ContextType::CROSS_SITE, ContextType::CROSS_SITE}, {"GET", true, false, false, ContextType::CROSS_SITE, + ContextType::CROSS_SITE, ContextType::CROSS_SITE, ContextType::CROSS_SITE}, - {"GET", false, true, true, incorrectly_lax, ContextType::SAME_SITE_LAX}, - {"GET", false, true, false, incorrectly_lax, ContextType::SAME_SITE_LAX}, + // If the url chain is cross-site, then the result will differ depending + // on whether the redirect chain is considered, when the site-for-cookies + // and initiator are both same-site. + {"GET", false, true, true, incorrectly_lax, ContextType::SAME_SITE_LAX, + ContextType::SAME_SITE_STRICT, ContextType::SAME_SITE_STRICT}, + {"GET", false, true, false, incorrectly_lax, ContextType::SAME_SITE_LAX, + incorrectly_lax, ContextType::SAME_SITE_LAX}, {"GET", false, false, true, ContextType::CROSS_SITE, + ContextType::CROSS_SITE, ContextType::CROSS_SITE, ContextType::CROSS_SITE}, {"GET", false, false, false, ContextType::CROSS_SITE, + ContextType::CROSS_SITE, ContextType::CROSS_SITE, ContextType::CROSS_SITE}, + // If the url chain is same-site, then the result is the same with or + // without considering the redirect chain. {"POST", true, true, true, ContextType::SAME_SITE_STRICT, + ContextType::SAME_SITE_STRICT, ContextType::SAME_SITE_STRICT, ContextType::SAME_SITE_STRICT}, {"POST", true, true, false, incorrectly_lax_unsafe, + ContextType::SAME_SITE_LAX_METHOD_UNSAFE, incorrectly_lax_unsafe, ContextType::SAME_SITE_LAX_METHOD_UNSAFE}, {"POST", true, false, true, ContextType::CROSS_SITE, + ContextType::CROSS_SITE, ContextType::CROSS_SITE, ContextType::CROSS_SITE}, {"POST", true, false, false, ContextType::CROSS_SITE, + ContextType::CROSS_SITE, ContextType::CROSS_SITE, ContextType::CROSS_SITE}, + // If the url chain is cross-site, then the result will differ depending + // on whether the redirect chain is considered, when the site-for-cookies + // and initiator are both same-site. {"POST", false, true, true, incorrectly_lax_unsafe, - ContextType::SAME_SITE_LAX_METHOD_UNSAFE}, + ContextType::SAME_SITE_LAX_METHOD_UNSAFE, ContextType::SAME_SITE_STRICT, + ContextType::SAME_SITE_STRICT}, {"POST", false, true, false, incorrectly_lax_unsafe, + ContextType::SAME_SITE_LAX_METHOD_UNSAFE, incorrectly_lax_unsafe, ContextType::SAME_SITE_LAX_METHOD_UNSAFE}, {"POST", false, false, true, ContextType::CROSS_SITE, - ContextType::CROSS_SITE}, + ContextType::CROSS_SITE, ContextType::CROSS_SITE}, {"POST", false, false, false, ContextType::CROSS_SITE, - ContextType::CROSS_SITE}, + ContextType::CROSS_SITE, ContextType::CROSS_SITE}, }; for (const auto& test_case : kTestCases) { @@ -1011,6 +1051,15 @@ std::vector<absl::optional<url::Origin>> initiators = test_case.initiator_is_same_site ? GetSameSiteInitiators() : GetCrossSiteInitiators(); + ContextType expected_context_type = + DoesSameSiteConsiderRedirectChain() + ? test_case.expected_context_type + : test_case.expected_context_type_without_chain; + ContextType expected_context_type_for_main_frame_navigation = + DoesSameSiteConsiderRedirectChain() + ? test_case.expected_context_type_for_main_frame_navigation + : test_case + .expected_context_type_for_main_frame_navigation_without_chain; for (const std::vector<GURL>& url_chain : url_chains) { for (const SiteForCookies& site_for_cookies : sites_for_cookies) { for (const absl::optional<url::Origin>& initiator : initiators) { @@ -1018,7 +1067,7 @@ test_case.method, url_chain, site_for_cookies, initiator, false /* is_main_frame_navigation */, false /* force_ignore_site_for_cookies */), - ContextTypeIs(test_case.expected_context_type)) + ContextTypeIs(expected_context_type)) << UrlChainToString(url_chain) << " " << site_for_cookies.ToDebugString() << " " << (initiator ? initiator->Serialize() : "nullopt"); @@ -1029,8 +1078,7 @@ test_case.method, url_chain, site_for_cookies, initiator, true /* is_main_frame_navigation */, false /* force_ignore_site_for_cookies */), - ContextTypeIs( - test_case.expected_context_type_for_main_frame_navigation)) + ContextTypeIs(expected_context_type_for_main_frame_navigation)) << UrlChainToString(url_chain) << " " << site_for_cookies.ToDebugString() << " " << (initiator ? initiator->Serialize() : "nullopt"); @@ -1220,18 +1268,34 @@ bool url_chain_is_same_site; bool site_for_cookies_is_same_site; bool initiator_is_same_site; + // These are the expected context types considering redirect chains: ContextType expected_context_type; // for non-main-frame-nav requests. ContextType expected_context_type_for_main_frame_navigation; + // These are the expected context types not considering redirect chains: + ContextType expected_context_type_without_chain; + ContextType expected_context_type_for_main_frame_navigation_without_chain; } kTestCases[] = { - {true, true, true, ContextType::SAME_SITE_LAX, - ContextType::SAME_SITE_LAX}, - {true, true, false, incorrectly_lax, ContextType::SAME_SITE_LAX}, - {true, false, true, ContextType::CROSS_SITE, ContextType::CROSS_SITE}, - {true, false, false, ContextType::CROSS_SITE, ContextType::CROSS_SITE}, - {false, true, true, incorrectly_lax, ContextType::SAME_SITE_LAX}, - {false, true, false, incorrectly_lax, ContextType::SAME_SITE_LAX}, - {false, false, true, ContextType::CROSS_SITE, ContextType::CROSS_SITE}, - {false, false, false, ContextType::CROSS_SITE, ContextType::CROSS_SITE}, + // If the url chain is same-site, then the result is the same with or + // without considering the redirect chain. + {true, true, true, ContextType::SAME_SITE_LAX, ContextType::SAME_SITE_LAX, + ContextType::SAME_SITE_LAX, ContextType::SAME_SITE_LAX}, + {true, true, false, incorrectly_lax, ContextType::SAME_SITE_LAX, + incorrectly_lax, ContextType::SAME_SITE_LAX}, + {true, false, true, ContextType::CROSS_SITE, ContextType::CROSS_SITE, + ContextType::CROSS_SITE, ContextType::CROSS_SITE}, + {true, false, false, ContextType::CROSS_SITE, ContextType::CROSS_SITE, + ContextType::CROSS_SITE, ContextType::CROSS_SITE}, + // If the url chain is cross-site, then the result will differ depending + // on whether the redirect chain is considered, when the site-for-cookies + // and initiator are both same-site. + {false, true, true, incorrectly_lax, ContextType::SAME_SITE_LAX, + ContextType::SAME_SITE_LAX, ContextType::SAME_SITE_LAX}, + {false, true, false, incorrectly_lax, ContextType::SAME_SITE_LAX, + incorrectly_lax, ContextType::SAME_SITE_LAX}, + {false, false, true, ContextType::CROSS_SITE, ContextType::CROSS_SITE, + ContextType::CROSS_SITE, ContextType::CROSS_SITE}, + {false, false, false, ContextType::CROSS_SITE, ContextType::CROSS_SITE, + ContextType::CROSS_SITE, ContextType::CROSS_SITE}, }; for (const auto& test_case : kTestCases) { std::vector<std::vector<GURL>> url_chains = @@ -1243,6 +1307,15 @@ std::vector<absl::optional<url::Origin>> initiators = test_case.initiator_is_same_site ? GetSameSiteInitiators() : GetCrossSiteInitiators(); + ContextType expected_context_type = + DoesSameSiteConsiderRedirectChain() + ? test_case.expected_context_type + : test_case.expected_context_type_without_chain; + ContextType expected_context_type_for_main_frame_navigation = + DoesSameSiteConsiderRedirectChain() + ? test_case.expected_context_type_for_main_frame_navigation + : test_case + .expected_context_type_for_main_frame_navigation_without_chain; for (const std::vector<GURL>& url_chain : url_chains) { for (const SiteForCookies& site_for_cookies : sites_for_cookies) { for (const absl::optional<url::Origin>& initiator : initiators) { @@ -1250,7 +1323,7 @@ url_chain, site_for_cookies, initiator, false /* is_main_frame_navigation */, false /* force_ignore_site_for_cookies */), - ContextTypeIs(test_case.expected_context_type)) + ContextTypeIs(expected_context_type)) << UrlChainToString(url_chain) << " " << site_for_cookies.ToDebugString() << " " << (initiator ? initiator->Serialize() : "nullopt"); @@ -1261,8 +1334,7 @@ url_chain, site_for_cookies, initiator, true /* is_main_frame_navigation */, false /* force_ignore_site_for_cookies */), - ContextTypeIs( - test_case.expected_context_type_for_main_frame_navigation)) + ContextTypeIs(expected_context_type_for_main_frame_navigation)) << UrlChainToString(url_chain) << " " << site_for_cookies.ToDebugString() << " " << (initiator ? initiator->Serialize() : "nullopt"); @@ -1367,6 +1439,7 @@ INSTANTIATE_TEST_SUITE_P(/* no label */, CookieUtilComputeSameSiteContextTest, ::testing::Combine(::testing::Bool(), + ::testing::Bool(), ::testing::Bool())); TEST(CookieUtilTest, AdaptCookieAccessResultToBool) {
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index 798f85a..47cb01bf 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.cc
@@ -1243,13 +1243,14 @@ return rv; #if BUILDFLAG(ENABLE_REPORTING) + // Note: This just handles the legacy Report-To header, which is still + // required for NEL. The newer Reporting-Endpoints header is processed in + // network::PopulateParsedHeaders(). + ProcessReportToHeader(); + // Note: Unless there is a pre-existing NEL policy for this origin, any NEL // reports generated before the NEL header is processed here will just be // dropped by the NetworkErrorLoggingService. - ProcessReportToHeader(); - if (base::FeatureList::IsEnabled(net::features::kDocumentReporting)) { - ProcessReportingEndpointsHeader(); - } ProcessNetworkErrorLoggingHeader(); // Generate NEL report here if we have to report an HTTP error (4xx or 5xx @@ -1382,26 +1383,6 @@ } #if BUILDFLAG(ENABLE_REPORTING) -void HttpNetworkTransaction::ProcessReportingEndpointsHeader() { - std::string value; - if (!response_.headers->GetNormalizedHeader("Reporting-Endpoints", &value)) - return; - - ReportingService* service = session_->reporting_service(); - if (!service) - return; - - // Only accept Reporting-Endpoints headers on HTTPS connections that have no - // certificate errors. - if (!response_.ssl_info.is_valid()) - return; - if (IsCertStatusError(response_.ssl_info.cert_status)) - return; - - service->ProcessReportingEndpointsHeader(url::Origin::Create(url_), - network_isolation_key_, value); -} - void HttpNetworkTransaction::ProcessReportToHeader() { std::string value; if (!response_.headers->GetNormalizedHeader("Report-To", &value))
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc index 34289b7..fa449f0 100644 --- a/net/http/http_network_transaction_unittest.cc +++ b/net/http/http_network_transaction_unittest.cc
@@ -19952,7 +19952,7 @@ } // Makes an HTTPS request that should install a valid Reporting policy - // using either Report-To header or Reporting-Endpoints header. + // using Report-To header. void RequestPolicy(CertStatus cert_status = 0) { HttpRequestInfo request; request.method = "GET"; @@ -19968,15 +19968,10 @@ }; MockRead reporting_header; - if (UseDocumentReporting()) { - reporting_header = MockRead( - "Reporting-Endpoints: nel=\"https://www.example.org/upload/\"\r\n"); - } else { - reporting_header = MockRead( - "Report-To: {\"group\": \"nel\", \"max_age\": 86400, " - "\"endpoints\": [{\"url\": " - "\"https://www.example.org/upload/\"}]}\r\n"); - } + reporting_header = MockRead( + "Report-To: {\"group\": \"nel\", \"max_age\": 86400, " + "\"endpoints\": [{\"url\": " + "\"https://www.example.org/upload/\"}]}\r\n"); MockRead data_reads[] = { MockRead("HTTP/1.0 200 OK\r\n"), std::move(reporting_header),
diff --git a/net/proxy_resolution/win/windows_system_proxy_resolver_unittest.cc b/net/proxy_resolution/win/windows_system_proxy_resolver_unittest.cc index 72a8dda68..61a794d 100644 --- a/net/proxy_resolution/win/windows_system_proxy_resolver_unittest.cc +++ b/net/proxy_resolution/win/windows_system_proxy_resolver_unittest.cc
@@ -260,65 +260,30 @@ callback_info_ = std::make_unique<WINHTTP_ASYNC_RESULT>(); callback_info_->dwError = info_error; } - void AddToProxyResults(const ProxyServer& proxy_server, - bool bypass = false, - bool skip_port = false) { + void AddBypassToProxyResults() { EXPECT_LT(proxy_result_.cEntries, kMaxProxyEntryLimit - 1); + AllocateProxyResultEntriesIfNeeded(); + proxy_result_.pEntries[proxy_result_.cEntries].fBypass = TRUE; + proxy_result_.cEntries++; + } + void AddDirectToProxyResults() { + EXPECT_LT(proxy_result_.cEntries, kMaxProxyEntryLimit - 1); + AllocateProxyResultEntriesIfNeeded(); + proxy_result_.cEntries++; + } + void AddToProxyResults(INTERNET_SCHEME scheme, + std::wstring proxy_host, + INTERNET_PORT port) { + EXPECT_LT(proxy_result_.cEntries, kMaxProxyEntryLimit - 1); + AllocateProxyResultEntriesIfNeeded(); - // Assign memory as needed. - if (proxy_result_.cEntries == 0) { - proxy_result_.pEntries = - new WINHTTP_PROXY_RESULT_ENTRY[kMaxProxyEntryLimit]; - std::memset(proxy_result_.pEntries, 0, - kMaxProxyEntryLimit * sizeof(WINHTTP_PROXY_RESULT_ENTRY)); + proxy_list_.push_back(std::move(proxy_host)); + wchar_t* proxy_host_raw = const_cast<wchar_t*>(proxy_list_.back().data()); - // The memory of the strings above will be backed by a vector of strings. - proxy_list_.reserve(kMaxProxyEntryLimit); - } - - if (bypass) { - proxy_result_.pEntries[proxy_result_.cEntries].fBypass = TRUE; - } else if (!proxy_server.is_direct()) { - // Now translate the ProxyServer into a WINHTTP_PROXY_RESULT_ENTRY and - // assign. - proxy_result_.pEntries[proxy_result_.cEntries].fProxy = TRUE; - - switch (proxy_server.scheme()) { - case ProxyServer::Scheme::SCHEME_HTTP: - proxy_result_.pEntries[proxy_result_.cEntries].ProxyScheme = - INTERNET_SCHEME_HTTP; - break; - case ProxyServer::Scheme::SCHEME_HTTPS: - proxy_result_.pEntries[proxy_result_.cEntries].ProxyScheme = - INTERNET_SCHEME_HTTPS; - break; - case ProxyServer::Scheme::SCHEME_SOCKS4: - proxy_result_.pEntries[proxy_result_.cEntries].ProxyScheme = - INTERNET_SCHEME_SOCKS; - break; - default: - ADD_FAILURE() - << "Of the possible proxy schemes returned by WinHttp, Chrome " - "supports HTTP(S) and SOCKS4. The ProxyServer::Scheme that " - "triggered this message is: " - << proxy_server.scheme(); - break; - } - - std::wstring proxy_host(proxy_server.host_port_pair().host().begin(), - proxy_server.host_port_pair().host().end()); - proxy_list_.push_back(proxy_host); - - wchar_t* proxy_host_raw = const_cast<wchar_t*>(proxy_list_.back().data()); - proxy_result_.pEntries[proxy_result_.cEntries].pwszProxy = proxy_host_raw; - - if (skip_port) - proxy_result_.pEntries[proxy_result_.cEntries].ProxyPort = - INTERNET_DEFAULT_PORT; - else - proxy_result_.pEntries[proxy_result_.cEntries].ProxyPort = - proxy_server.host_port_pair().port(); - } + proxy_result_.pEntries[proxy_result_.cEntries].fProxy = TRUE; + proxy_result_.pEntries[proxy_result_.cEntries].ProxyScheme = scheme; + proxy_result_.pEntries[proxy_result_.cEntries].pwszProxy = proxy_host_raw; + proxy_result_.pEntries[proxy_result_.cEntries].ProxyPort = port; proxy_result_.cEntries++; } @@ -372,6 +337,19 @@ callback_info_.reset(); } + void AllocateProxyResultEntriesIfNeeded() { + if (proxy_result_.cEntries != 0) + return; + + proxy_result_.pEntries = + new WINHTTP_PROXY_RESULT_ENTRY[kMaxProxyEntryLimit]; + std::memset(proxy_result_.pEntries, 0, + kMaxProxyEntryLimit * sizeof(WINHTTP_PROXY_RESULT_ENTRY)); + + // The memory of the strings above will be backed by a vector of strings. + proxy_list_.reserve(kMaxProxyEntryLimit); + } + // Data configurable by tests to simulate errors and results from WinHttp. bool open_success_ = true; bool set_timeouts_success_ = true; @@ -442,55 +420,6 @@ bool InitializeResolver() { return proxy_resolver_->Initialize(); } - void AddNoPortProxyToResults() { - const ProxyServer proxy_result = - ProxyServer::FromPacString("PROXY foopy:8080"); - winhttp_api_wrapper_->AddToProxyResults(proxy_result, /*bypass=*/false, - /*skip_port=*/true); - } - - void AddDirectProxyToResults(ProxyList* out_proxy_list) { - winhttp_api_wrapper_->AddToProxyResults(ProxyServer::Direct()); - out_proxy_list->AddProxyServer(ProxyServer::Direct()); - } - - void AddBypassedProxyToResults(ProxyList* out_proxy_list) { - winhttp_api_wrapper_->AddToProxyResults(ProxyServer::Direct(), - /*bypass=*/true); - out_proxy_list->AddProxyServer(ProxyServer::Direct()); - } - - void AddHTTPProxyToResults(ProxyList* out_proxy_list) { - const ProxyServer proxy_result = - ProxyServer::FromPacString("PROXY foopy:8080"); - winhttp_api_wrapper_->AddToProxyResults(proxy_result); - out_proxy_list->AddProxyServer(proxy_result); - } - - void AddHTTPSProxyToResults(ProxyList* out_proxy_list) { - const ProxyServer proxy_result = - ProxyServer::FromPacString("HTTPS foopy:8443"); - winhttp_api_wrapper_->AddToProxyResults(proxy_result); - out_proxy_list->AddProxyServer(proxy_result); - } - - void AddSOCKSProxyToResults(ProxyList* out_proxy_list) { - const ProxyServer proxy_result = - ProxyServer::FromPacString("SOCKS4 foopy:8080"); - winhttp_api_wrapper_->AddToProxyResults(proxy_result); - out_proxy_list->AddProxyServer(proxy_result); - } - - void AddIDNProxyToResults(ProxyList* out_proxy_list) { - const ProxyServer proxy_result = - ProxyServer::FromPacString("HTTPS föopy:8080"); - winhttp_api_wrapper_->AddToProxyResults(proxy_result); - - const ProxyServer expected_proxy_result = - ProxyServer::FromPacString("HTTPS xn--fopy-5jr83a:8080"); - out_proxy_list->AddProxyServer(expected_proxy_result); - } - void PerformGetProxyForUrlAndValidateResult(const ProxyList& proxy_list, int net_error, int windows_error) { @@ -517,8 +446,10 @@ } void DoProxyConfigTest(const ProxyConfig& proxy_config) { + winhttp_api_wrapper()->AddToProxyResults(INTERNET_SCHEME_HTTPS, L"foopy", + 8443); ProxyList proxy_list; - AddHTTPSProxyToResults(&proxy_list); + proxy_list.AddProxyServer(ProxyServer::FromPacString("HTTPS foopy:8443")); std::wstring pac_url; if (proxy_config.has_pac_url()) @@ -626,7 +557,8 @@ } TEST_F(WindowsSystemProxyResolverTest, GetProxyForUrlFailOnDefaultPort) { - AddNoPortProxyToResults(); + winhttp_api_wrapper()->AddToProxyResults(INTERNET_SCHEME_HTTP, L"foopy", + INTERNET_DEFAULT_PORT); DoFailedGetProxyForUrlTest(ERR_FAILED, 0); } @@ -660,8 +592,11 @@ } TEST_F(WindowsSystemProxyResolverTest, GetProxyForUrlCancelAndRestart) { + winhttp_api_wrapper()->AddToProxyResults(INTERNET_SCHEME_HTTPS, L"foopy", + 8443); ProxyList expected_proxy_list; - AddHTTPSProxyToResults(&expected_proxy_list); + expected_proxy_list.AddProxyServer( + ProxyServer::FromPacString("HTTPS foopy:8443")); ASSERT_TRUE(InitializeResolver()); TestCompletionCallback unused_callback; @@ -738,52 +673,81 @@ } TEST_F(WindowsSystemProxyResolverTest, GetProxyForUrlDirect) { + winhttp_api_wrapper()->AddDirectToProxyResults(); ProxyList expected_proxy_list; - AddDirectProxyToResults(&expected_proxy_list); + expected_proxy_list.AddProxyServer(ProxyServer::Direct()); DoGetProxyForUrlTest(expected_proxy_list); } TEST_F(WindowsSystemProxyResolverTest, GetProxyForUrlBypass) { + winhttp_api_wrapper()->AddBypassToProxyResults(); ProxyList expected_proxy_list; - AddBypassedProxyToResults(&expected_proxy_list); + expected_proxy_list.AddProxyServer(ProxyServer::Direct()); DoGetProxyForUrlTest(expected_proxy_list); } TEST_F(WindowsSystemProxyResolverTest, GetProxyForUrlHTTP) { + winhttp_api_wrapper()->AddToProxyResults(INTERNET_SCHEME_HTTP, L"foopy", + 8080); ProxyList expected_proxy_list; - AddHTTPProxyToResults(&expected_proxy_list); + expected_proxy_list.AddProxyServer( + ProxyServer::FromPacString("PROXY foopy:8080")); DoGetProxyForUrlTest(expected_proxy_list); } TEST_F(WindowsSystemProxyResolverTest, GetProxyForUrlHTTPS) { + winhttp_api_wrapper()->AddToProxyResults(INTERNET_SCHEME_HTTPS, L"foopy", + 8443); ProxyList expected_proxy_list; - AddHTTPSProxyToResults(&expected_proxy_list); + expected_proxy_list.AddProxyServer( + ProxyServer::FromPacString("HTTPS foopy:8443")); DoGetProxyForUrlTest(expected_proxy_list); } TEST_F(WindowsSystemProxyResolverTest, GetProxyForUrlSOCKS) { + winhttp_api_wrapper()->AddToProxyResults(INTERNET_SCHEME_SOCKS, L"foopy", + 8080); ProxyList expected_proxy_list; - AddSOCKSProxyToResults(&expected_proxy_list); + expected_proxy_list.AddProxyServer( + ProxyServer::FromPacString("SOCKS4 foopy:8080")); DoGetProxyForUrlTest(expected_proxy_list); } TEST_F(WindowsSystemProxyResolverTest, GetProxyForUrlIDNProxy) { + winhttp_api_wrapper()->AddToProxyResults(INTERNET_SCHEME_HTTPS, L"föopy", + 8080); + + // Expect L"föopy" to be ascii-encoded as "xn--fopy-5qa". ProxyList expected_proxy_list; - AddIDNProxyToResults(&expected_proxy_list); + expected_proxy_list.AddProxyServer( + ProxyServer::FromPacString("HTTPS xn--fopy-5qa:8080")); + DoGetProxyForUrlTest(expected_proxy_list); } TEST_F(WindowsSystemProxyResolverTest, GetProxyForUrlMultipleResults) { + winhttp_api_wrapper()->AddToProxyResults(INTERNET_SCHEME_HTTPS, L"foopy", + 8443); + winhttp_api_wrapper()->AddDirectToProxyResults(); + ProxyList expected_proxy_list; - AddHTTPSProxyToResults(&expected_proxy_list); - AddDirectProxyToResults(&expected_proxy_list); + expected_proxy_list.AddProxyServer( + ProxyServer::FromPacString("HTTPS foopy:8443")); + expected_proxy_list.AddProxyServer(ProxyServer::Direct()); + DoGetProxyForUrlTest(expected_proxy_list); } TEST_F(WindowsSystemProxyResolverTest, MultipleCallsToGetProxyForUrl) { + winhttp_api_wrapper()->AddToProxyResults(INTERNET_SCHEME_HTTPS, L"foopy", + 8443); + winhttp_api_wrapper()->AddDirectToProxyResults(); + ProxyList expected_proxy_list; - AddHTTPSProxyToResults(&expected_proxy_list); - AddDirectProxyToResults(&expected_proxy_list); + expected_proxy_list.AddProxyServer( + ProxyServer::FromPacString("HTTPS foopy:8443")); + expected_proxy_list.AddProxyServer(ProxyServer::Direct()); + ASSERT_TRUE(InitializeResolver()); TestCompletionCallback unused_callback; @@ -818,9 +782,15 @@ TEST_F(WindowsSystemProxyResolverTest, MultipleCallsToGetProxyForUrlWithOneCancellation) { + winhttp_api_wrapper()->AddToProxyResults(INTERNET_SCHEME_HTTPS, L"foopy", + 8443); + winhttp_api_wrapper()->AddDirectToProxyResults(); + ProxyList expected_proxy_list; - AddHTTPSProxyToResults(&expected_proxy_list); - AddDirectProxyToResults(&expected_proxy_list); + expected_proxy_list.AddProxyServer( + ProxyServer::FromPacString("HTTPS foopy:8443")); + expected_proxy_list.AddProxyServer(ProxyServer::Direct()); + ASSERT_TRUE(InitializeResolver()); // This extra scope is needed so that the MockProxyResolutionRequests destruct
diff --git a/net/quic/quic_chromium_client_session_test.cc b/net/quic/quic_chromium_client_session_test.cc index a6688ce..e20205b 100644 --- a/net/quic/quic_chromium_client_session_test.cc +++ b/net/quic/quic_chromium_client_session_test.cc
@@ -1944,7 +1944,8 @@ quic::test::QuicStreamPeer::SendBuffer(stream).SaveStreamData(iov, 1, 0, 4); quic::test::QuicStreamPeer::SetStreamBytesWritten(4, stream); session_->WritevData(stream->id(), 4, 0, quic::NO_FIN, - quic::NOT_RETRANSMISSION, absl::nullopt); + quic::NOT_RETRANSMISSION, + quic::ENCRYPTION_FORWARD_SECURE); EXPECT_TRUE(quic_data2.AllReadDataConsumed()); EXPECT_TRUE(quic_data2.AllWriteDataConsumed());
diff --git a/net/quic/quic_chromium_client_stream_test.cc b/net/quic/quic_chromium_client_stream_test.cc index 6509df58..731f378 100644 --- a/net/quic/quic_chromium_client_stream_test.cc +++ b/net/quic/quic_chromium_client_stream_test.cc
@@ -18,6 +18,7 @@ #include "net/quic/quic_chromium_client_session.h" #include "net/test/gtest_util.h" #include "net/test/test_with_task_environment.h" +#include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h" #include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.h" #include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.h" #include "net/third_party/quiche/src/quic/core/http/spdy_utils.h" @@ -69,6 +70,8 @@ quic::StreamSendingState state, quic::TransmissionType type, absl::optional<quic::EncryptionLevel> level)); + MOCK_METHOD2(WriteControlFrame, + bool(const quic::QuicFrame&, quic::TransmissionType)); MOCK_METHOD4(SendRstStream, void(quic::QuicStreamId stream_id, quic::QuicRstStreamErrorCode error, @@ -185,6 +188,9 @@ session_.ActivateStream(base::WrapUnique(stream_)); handle_ = stream_->CreateHandle(); helper_.AdvanceTime(quic::QuicTime::Delta::FromSeconds(1)); + session_.connection()->SetEncrypter( + quic::ENCRYPTION_FORWARD_SECURE, + std::make_unique<quic::NullEncrypter>(quic::Perspective::IS_CLIENT)); } void InitializeHeaders() { @@ -973,10 +979,6 @@ version_.transport_version, 0), quic::QUIC_BAD_APPLICATION_PAYLOAD)); - EXPECT_CALL( - *static_cast<quic::test::MockQuicConnection*>(session_.connection()), - SendControlFrame(_)); - ProcessHeaders(headers); EXPECT_FALSE(handle_->IsOpen()); EXPECT_EQ(quic::QUIC_BAD_APPLICATION_PAYLOAD, handle_->stream_error()); @@ -992,10 +994,6 @@ version_.transport_version, 0), quic::QUIC_BAD_APPLICATION_PAYLOAD)); - EXPECT_CALL( - *static_cast<quic::test::MockQuicConnection*>(session_.connection()), - SendControlFrame(_)); - ProcessHeaders(informational_headers); EXPECT_FALSE(handle_->IsOpen()); EXPECT_EQ(quic::QUIC_BAD_APPLICATION_PAYLOAD, handle_->stream_error());
diff --git a/net/reporting/reporting_header_parser.cc b/net/reporting/reporting_header_parser.cc index 10f6cef..d26f179 100644 --- a/net/reporting/reporting_header_parser.cc +++ b/net/reporting/reporting_header_parser.cc
@@ -194,18 +194,15 @@ // Processes a single endpoint tuple received in a Reporting-Endpoints header. // // |group_key| is the key for the endpoint group this endpoint belongs. -// |value| is the parsed parameterized member representing the endpoint url. +// |endpoint_url_string| is the endpoint url as received in the header. // // |endpoint_info_out| is the endpoint info parsed out of the value. -bool ProcessEndpointStructuredHeader( - ReportingDelegate* delegate, - const ReportingEndpointGroupKey& group_key, - const structured_headers::ParameterizedMember& value, - ReportingEndpoint::EndpointInfo& endpoint_info_out) { - if (value.member_is_inner_list || !value.member.front().item.is_string()) +bool ProcessEndpoint(ReportingDelegate* delegate, + const ReportingEndpointGroupKey& group_key, + const std::string& endpoint_url_string, + ReportingEndpoint::EndpointInfo& endpoint_info_out) { + if (endpoint_url_string.empty()) return false; - const std::string& endpoint_url_string = - value.member.front().item.GetString(); GURL endpoint_url; if (!ProcessEndpointURLString(endpoint_url_string, group_key.origin, @@ -227,15 +224,16 @@ // the endpoint group we create here is just a wrapper for that endpoint. The // endpoint name will be stored in the group name here as individual endpoint // doesn't have names. -bool ProcessEndpointGroupStructuredHeader( +bool ProcessDocumentEndpoint( ReportingDelegate* delegate, ReportingCache* cache, const NetworkIsolationKey& network_isolation_key, const url::Origin& origin, - const structured_headers::DictionaryMember& value, + const std::string& endpoint_name, + const std::string& endpoint_url_string, ReportingEndpointGroup& parsed_endpoint_group_out) { ReportingEndpointGroupKey group_key(network_isolation_key, origin, - value.first); + endpoint_name); parsed_endpoint_group_out.group_key = group_key; // Default to a fixed number of days as Reporting-Endpoints doesn't have the @@ -246,8 +244,8 @@ ReportingEndpoint::EndpointInfo parsed_endpoint; - if (!ProcessEndpointStructuredHeader(delegate, group_key, value.second, - parsed_endpoint)) { + if (!ProcessEndpoint(delegate, group_key, endpoint_url_string, + parsed_endpoint)) { // Remove the group if it does not have a proper endpoint. cache->RemoveEndpointGroup(group_key); return false; @@ -258,6 +256,26 @@ } // namespace +absl::optional<base::flat_map<std::string, std::string>> +ParseReportingEndpoints(const std::string& header) { + absl::optional<structured_headers::Dictionary> header_dict = + structured_headers::ParseDictionary(header); + if (!header_dict) { + return absl::nullopt; + } + base::flat_map<std::string, std::string> parsed_header; + for (const structured_headers::DictionaryMember& entry : *header_dict) { + if (entry.second.member_is_inner_list || + !entry.second.member.front().item.is_string()) { + return absl::nullopt; + } + const std::string& endpoint_url_string = + entry.second.member.front().item.GetString(); + parsed_header[entry.first] = endpoint_url_string; + } + return parsed_header; +} + // static void ReportingHeaderParser::RecordReportingHeaderType( ReportingHeaderType header_type) { @@ -311,11 +329,11 @@ } // static -void ReportingHeaderParser::ParseReportingEndpointsHeader( +void ReportingHeaderParser::ProcessParsedReportingEndpointsHeader( ReportingContext* context, const NetworkIsolationKey& network_isolation_key, const url::Origin& origin, - std::unique_ptr<structured_headers::Dictionary> value) { + base::flat_map<std::string, std::string> header) { DCHECK(base::FeatureList::IsEnabled(net::features::kDocumentReporting)); DCHECK(GURL::SchemeIsCryptographic(origin.scheme())); @@ -324,12 +342,11 @@ std::vector<ReportingEndpointGroup> parsed_header; - for (const structured_headers::DictionaryMember& member : *value) { - ReportingEndpointGroup parsed_endpoint_group; - if (ProcessEndpointGroupStructuredHeader(delegate, cache, - network_isolation_key, origin, - member, parsed_endpoint_group)) { - parsed_header.push_back(std::move(parsed_endpoint_group)); + for (const auto& member : header) { + ReportingEndpointGroup parsed_endpoint; + if (ProcessDocumentEndpoint(delegate, cache, network_isolation_key, origin, + member.first, member.second, parsed_endpoint)) { + parsed_header.push_back(std::move(parsed_endpoint)); } }
diff --git a/net/reporting/reporting_header_parser.h b/net/reporting/reporting_header_parser.h index a332f45..6a1b955e 100644 --- a/net/reporting/reporting_header_parser.h +++ b/net/reporting/reporting_header_parser.h
@@ -7,9 +7,11 @@ #include <memory> +#include "base/containers/flat_map.h" #include "base/macros.h" #include "net/base/net_export.h" #include "net/http/structured_headers.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "url/gurl.h" #include "url/origin.h" @@ -22,6 +24,13 @@ class NetworkIsolationKey; class ReportingContext; +// Tries to parse a Reporting-Endpoints header. Returns base::nullopt if parsing +// failed and the header should be ignored; otherwise returns a (possibly +// empty) mapping of endpoint names to URLs. +NET_EXPORT +absl::optional<base::flat_map<std::string, std::string>> +ParseReportingEndpoints(const std::string& header); + class NET_EXPORT ReportingHeaderParser { public: // These values are persisted to logs. Entries should not be renumbered and @@ -38,11 +47,11 @@ const GURL& url, std::unique_ptr<base::Value> value); - static void ParseReportingEndpointsHeader( + static void ProcessParsedReportingEndpointsHeader( ReportingContext* context, const NetworkIsolationKey& network_isolation_key, const url::Origin& origin, - std::unique_ptr<structured_headers::Dictionary> value); + base::flat_map<std::string, std::string> parsed_header); static void RecordReportingHeaderType(ReportingHeaderType header_type);
diff --git a/net/reporting/reporting_header_parser_unittest.cc b/net/reporting/reporting_header_parser_unittest.cc index 6991ddac..af7eaf7 100644 --- a/net/reporting/reporting_header_parser_unittest.cc +++ b/net/reporting/reporting_header_parser_unittest.cc
@@ -1773,14 +1773,12 @@ void ParseHeader(const NetworkIsolationKey& network_isolation_key, const url::Origin& origin, const std::string& header_string) { - absl::optional<Dictionary> header_dict = - structured_headers::ParseDictionary(header_string); + absl::optional<base::flat_map<std::string, std::string>> header_map = + ParseReportingEndpoints(header_string); - if (header_dict) { - std::unique_ptr<Dictionary> header_value = - std::make_unique<Dictionary>(std::move(*header_dict)); - ReportingHeaderParser::ParseReportingEndpointsHeader( - context(), network_isolation_key, origin, std::move(header_value)); + if (header_map) { + ReportingHeaderParser::ProcessParsedReportingEndpointsHeader( + context(), network_isolation_key, origin, *header_map); } } };
diff --git a/net/reporting/reporting_service.cc b/net/reporting/reporting_service.cc index 3e237a8..d59d469 100644 --- a/net/reporting/reporting_service.cc +++ b/net/reporting/reporting_service.cc
@@ -32,7 +32,6 @@ constexpr int kMaxJsonSize = 16 * 1024; constexpr int kMaxJsonDepth = 5; -constexpr int kMaxSHSize = 16 * 1024; // If constructed with a PersistentReportingStore, the first call to any of // QueueReport(), ProcessHeader(), RemoveBrowsingData(), or @@ -56,6 +55,16 @@ context_->cache()->Flush(); } + void SetDocumentReportingEndpoints( + const url::Origin& origin, + const net::NetworkIsolationKey& network_isolation_key, + const base::flat_map<std::string, std::string>& endpoints) override { + DoOrBacklogTask(base::BindOnce( + &ReportingServiceImpl::DoSetDocumentReportingEndpoints, + base::Unretained(this), FixupNetworkIsolationKey(network_isolation_key), + origin, endpoints)); + } + void QueueReport(const GURL& url, const NetworkIsolationKey& network_isolation_key, const std::string& user_agent, @@ -104,31 +113,6 @@ std::move(header_value))); } - void ProcessReportingEndpointsHeader( - const url::Origin& origin, - const NetworkIsolationKey& network_isolation_key, - const std::string& header_string) override { - if (header_string.size() == 0 || header_string.size() > kMaxSHSize) - return; - - absl::optional<structured_headers::Dictionary> header_dict = - structured_headers::ParseDictionary(header_string); - if (!header_dict) { - DVLOG(1) << "Error processing Reporting-Endpoints header string: " - << header_string; - return; - } - std::unique_ptr<structured_headers::Dictionary> header_value = - std::make_unique<structured_headers::Dictionary>( - std::move(*header_dict)); - - DVLOG(1) << "Received Reporting-Endpoints header policy for " << origin; - DoOrBacklogTask(base::BindOnce( - &ReportingServiceImpl::DoProcessReportingEndpointsHeader, - base::Unretained(this), FixupNetworkIsolationKey(network_isolation_key), - origin, std::move(header_value))); - } - void RemoveBrowsingData(uint64_t data_type_mask, const base::RepeatingCallback<bool(const GURL&)>& origin_filter) override { @@ -201,12 +185,12 @@ context_.get(), network_isolation_key, url, std::move(header_value)); } - void DoProcessReportingEndpointsHeader( + void DoSetDocumentReportingEndpoints( const NetworkIsolationKey& network_isolation_key, const url::Origin& origin, - std::unique_ptr<structured_headers::Dictionary> header_value) { + base::flat_map<std::string, std::string> header_value) { DCHECK(initialized_); - ReportingHeaderParser::ParseReportingEndpointsHeader( + ReportingHeaderParser::ProcessParsedReportingEndpointsHeader( context_.get(), network_isolation_key, origin, std::move(header_value)); }
diff --git a/net/reporting/reporting_service.h b/net/reporting/reporting_service.h index ab2859a8..07d0c68 100644 --- a/net/reporting/reporting_service.h +++ b/net/reporting/reporting_service.h
@@ -9,6 +9,7 @@ #include <string> #include "base/callback.h" +#include "base/containers/flat_map.h" #include "base/macros.h" #include "net/base/net_export.h" #include "net/reporting/reporting_cache.h" @@ -71,13 +72,13 @@ const NetworkIsolationKey& network_isolation_key, const std::string& header_value) = 0; - // Processes a Reporting-Endpoints header. |url| is the URL that originated - // the header; |header_value| is the normalized value of the - // Reporting-Endpoints header. - virtual void ProcessReportingEndpointsHeader( + // Configures reporting endpoints set by the Reporting-Endpoints header, once + // the associated document has been committed. + // |endpoints| is a mapping of endpoint names to URLs. + virtual void SetDocumentReportingEndpoints( const url::Origin& origin, const NetworkIsolationKey& network_isolation_key, - const std::string& header_value) = 0; + const base::flat_map<std::string, std::string>& endpoints) = 0; // Removes browsing data from the Reporting system. See // ReportingBrowsingDataRemover for more details.
diff --git a/net/reporting/reporting_service_unittest.cc b/net/reporting/reporting_service_unittest.cc index 83874936..3ce13d2d 100644 --- a/net/reporting/reporting_service_unittest.cc +++ b/net/reporting/reporting_service_unittest.cc
@@ -188,8 +188,10 @@ TEST_P(ReportingServiceTest, ProcessReportingEndpointsHeader) { base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature(net::features::kDocumentReporting); - service()->ProcessReportingEndpointsHeader( - kOrigin_, kNik_, kGroup_ + "=\"" + kEndpoint_.spec() + "\""); + auto parsed_header = + ParseReportingEndpoints(kGroup_ + "=\"" + kEndpoint_.spec() + "\""); + ASSERT_TRUE(parsed_header.has_value()); + service()->SetDocumentReportingEndpoints(kOrigin_, kNik_, *parsed_header); FinishLoading(true /* load_success */); EXPECT_EQ(1u, context()->cache()->GetEndpointCount()); @@ -200,8 +202,9 @@ TEST_P(ReportingServiceTest, ProcessReportingEndpointsHeaderPathAbsolute) { base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature(net::features::kDocumentReporting); - service()->ProcessReportingEndpointsHeader(kOrigin_, kNik_, - kGroup_ + "=\"/path-absolute\""); + auto parsed_header = ParseReportingEndpoints(kGroup_ + "=\"/path-absolute\""); + ASSERT_TRUE(parsed_header.has_value()); + service()->SetDocumentReportingEndpoints(kOrigin_, kNik_, *parsed_header); FinishLoading(true /* load_success */); EXPECT_EQ(1u, context()->cache()->GetEndpointCount());
diff --git a/net/reporting/reporting_test_util.cc b/net/reporting/reporting_test_util.cc index 47c3d83..5a36a2f 100644 --- a/net/reporting/reporting_test_util.cc +++ b/net/reporting/reporting_test_util.cc
@@ -334,13 +334,6 @@ NOTREACHED(); } -void TestReportingService::ProcessReportingEndpointsHeader( - const url::Origin& origin, - const NetworkIsolationKey& network_isolation_key, - const std::string& header_value) { - NOTREACHED(); -} - void TestReportingService::RemoveBrowsingData( uint64_t data_type_mask, const base::RepeatingCallback<bool(const GURL&)>& origin_filter) {
diff --git a/net/reporting/reporting_test_util.h b/net/reporting/reporting_test_util.h index 629e7651..e4648d3 100644 --- a/net/reporting/reporting_test_util.h +++ b/net/reporting/reporting_test_util.h
@@ -313,6 +313,11 @@ ~TestReportingService() override; + void SetDocumentReportingEndpoints( + const url::Origin& origin, + const net::NetworkIsolationKey& network_isolation_key, + const base::flat_map<std::string, std::string>& endpoints) override {} + void QueueReport(const GURL& url, const NetworkIsolationKey& network_isolation_key, const std::string& user_agent, @@ -325,11 +330,6 @@ const NetworkIsolationKey& network_isolation_key, const std::string& header_value) override; - void ProcessReportingEndpointsHeader( - const url::Origin& origin, - const NetworkIsolationKey& network_isolation_key, - const std::string& header_value) override; - void RemoveBrowsingData( uint64_t data_type_mask, const base::RepeatingCallback<bool(const GURL&)>& origin_filter) override;
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc index cced331..4a41d3a3 100644 --- a/net/url_request/url_request_unittest.cc +++ b/net/url_request/url_request_unittest.cc
@@ -2185,7 +2185,26 @@ } } -TEST_F(URLRequestTest, SameSiteCookies) { +// Tests for SameSite cookies. The test param indicates whether the same-site +// calculation considers redirect chains. +class URLRequestSameSiteCookiesTest + : public URLRequestTest, + public ::testing::WithParamInterface<bool> { + public: + URLRequestSameSiteCookiesTest() { + if (DoesCookieSameSiteConsiderRedirectChain()) { + feature_list_.InitAndEnableFeature( + features::kCookieSameSiteConsidersRedirectChain); + } + } + + bool DoesCookieSameSiteConsiderRedirectChain() { return GetParam(); } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +TEST_P(URLRequestSameSiteCookiesTest, SameSiteCookies) { HttpTestServer test_server; ASSERT_TRUE(test_server.Start()); @@ -2390,7 +2409,7 @@ } } -TEST_F(URLRequestTest, SameSiteCookies_Redirect) { +TEST_P(URLRequestSameSiteCookiesTest, SameSiteCookies_Redirect) { EmbeddedTestServer http_server; RegisterDefaultHandlers(&http_server); EmbeddedTestServer https_server(EmbeddedTestServer::TYPE_HTTPS); @@ -2505,10 +2524,14 @@ EXPECT_NE(std::string::npos, d.data_received().find("LaxSameSiteCookie=1")); } + // If redirect chains are considered: // Verify that the Strict cookie may or may not be sent for a cross-scheme // (same-registrable-domain) redirected top level navigation, depending on the // status of Schemeful Same-Site. The Lax cookie is sent regardless, because // this is a top-level navigation. + // + // If redirect chains are not considered: + // Verify that both cookies are sent, because this is a top-level navigation. { base::test::ScopedFeatureList feature_list; feature_list.InitAndDisableFeature(features::kSchemefulSameSite); @@ -2524,7 +2547,7 @@ req->set_first_party_url_policy( RedirectInfo::FirstPartyURLPolicy::UPDATE_URL_ON_REDIRECT); req->set_site_for_cookies(kHttpSiteForCookies); - req->set_initiator(kHttpOrigin); + req->set_initiator(kOrigin); req->Start(); d.RunUntilComplete(); @@ -2548,18 +2571,20 @@ req->set_first_party_url_policy( RedirectInfo::FirstPartyURLPolicy::UPDATE_URL_ON_REDIRECT); req->set_site_for_cookies(kHttpSiteForCookies); - req->set_initiator(kHttpOrigin); + req->set_initiator(kOrigin); req->Start(); d.RunUntilComplete(); EXPECT_EQ(2u, req->url_chain().size()); - EXPECT_EQ(std::string::npos, - d.data_received().find("StrictSameSiteCookie=1")); + EXPECT_EQ( + DoesCookieSameSiteConsiderRedirectChain(), + std::string::npos == d.data_received().find("StrictSameSiteCookie=1")); EXPECT_NE(std::string::npos, d.data_received().find("LaxSameSiteCookie=1")); } - // Verify that the Strict cookie is not sent for a cross-site redirected top - // level navigation... + // Verify that (depending on whether redirect chains are considered), the + // Strict cookie is (not) sent for a cross-site redirected top level + // navigation... { TestDelegate d; GURL url = https_server.GetURL( @@ -2579,8 +2604,9 @@ d.RunUntilComplete(); EXPECT_EQ(2u, req->url_chain().size()); - EXPECT_EQ(std::string::npos, - d.data_received().find("StrictSameSiteCookie=1")); + EXPECT_EQ( + DoesCookieSameSiteConsiderRedirectChain(), + std::string::npos == d.data_received().find("StrictSameSiteCookie=1")); EXPECT_NE(std::string::npos, d.data_received().find("LaxSameSiteCookie=1")); } // ... even if the initial URL is same-site. @@ -2605,13 +2631,15 @@ d.RunUntilComplete(); EXPECT_EQ(3u, req->url_chain().size()); - EXPECT_EQ(std::string::npos, - d.data_received().find("StrictSameSiteCookie=1")); + EXPECT_EQ( + DoesCookieSameSiteConsiderRedirectChain(), + std::string::npos == d.data_received().find("StrictSameSiteCookie=1")); EXPECT_NE(std::string::npos, d.data_received().find("LaxSameSiteCookie=1")); } - // Verify that neither SameSite cookie is sent for a cross-site redirected - // subresource request... + // Verify that (depending on whether redirect chains are considered), neither + // (or both) SameSite cookie is sent for a cross-site redirected subresource + // request... { TestDelegate d; GURL url = https_server.GetURL( @@ -2629,9 +2657,12 @@ d.RunUntilComplete(); EXPECT_EQ(2u, req->url_chain().size()); - EXPECT_EQ(std::string::npos, - d.data_received().find("StrictSameSiteCookie=1")); - EXPECT_EQ(std::string::npos, d.data_received().find("LaxSameSiteCookie=1")); + EXPECT_EQ( + DoesCookieSameSiteConsiderRedirectChain(), + std::string::npos == d.data_received().find("StrictSameSiteCookie=1")); + EXPECT_EQ( + DoesCookieSameSiteConsiderRedirectChain(), + std::string::npos == d.data_received().find("LaxSameSiteCookie=1")); } // ... even if the initial URL is same-site. { @@ -2653,13 +2684,16 @@ d.RunUntilComplete(); EXPECT_EQ(3u, req->url_chain().size()); - EXPECT_EQ(std::string::npos, - d.data_received().find("StrictSameSiteCookie=1")); - EXPECT_EQ(std::string::npos, d.data_received().find("LaxSameSiteCookie=1")); + EXPECT_EQ( + DoesCookieSameSiteConsiderRedirectChain(), + std::string::npos == d.data_received().find("StrictSameSiteCookie=1")); + EXPECT_EQ( + DoesCookieSameSiteConsiderRedirectChain(), + std::string::npos == d.data_received().find("LaxSameSiteCookie=1")); } } -TEST_F(URLRequestTest, SettingSameSiteCookies) { +TEST_P(URLRequestSameSiteCookiesTest, SettingSameSiteCookies) { HttpTestServer test_server; ASSERT_TRUE(test_server.Start()); @@ -2855,7 +2889,7 @@ // Tests special chrome:// scheme that is supposed to always attach SameSite // cookies if the requested site is secure. -TEST_F(URLRequestTest, SameSiteCookiesSpecialScheme) { +TEST_P(URLRequestSameSiteCookiesTest, SameSiteCookiesSpecialScheme) { url::ScopedSchemeRegistryForTests scoped_registry; url::AddStandardScheme("chrome", url::SchemeType::SCHEME_WITH_HOST); @@ -2947,7 +2981,7 @@ } } -TEST_F(URLRequestTest, SettingSameSiteCookies_Redirect) { +TEST_P(URLRequestSameSiteCookiesTest, SettingSameSiteCookies_Redirect) { EmbeddedTestServer http_server; RegisterDefaultHandlers(&http_server); EmbeddedTestServer https_server(EmbeddedTestServer::TYPE_HTTPS); @@ -3115,9 +3149,9 @@ EXPECT_EQ(expected_set_cookie_count, network_delegate.set_cookie_count()); } - // Verify that SameSite cookies *cannot* be set for a cross-site redirected - // subresource request, even if the site-for-cookies and initiator are - // same-site, ... + // Verify that (depending on whether redirect chains are considered) SameSite + // cookies can/cannot be set for a cross-site redirected subresource request, + // even if the site-for-cookies and initiator are same-site, ... { TestDelegate d; GURL set_cookie_url = https_server.GetURL( @@ -3132,7 +3166,7 @@ req->set_site_for_cookies(kSiteForCookies); req->set_initiator(kOrigin); - expected_cookies += 0; + expected_cookies += DoesCookieSameSiteConsiderRedirectChain() ? 0 : 2; expected_set_cookie_count += 2; req->Start(); @@ -3158,7 +3192,7 @@ req->set_site_for_cookies(kSiteForCookies); req->set_initiator(kOrigin); - expected_cookies += 0; + expected_cookies += DoesCookieSameSiteConsiderRedirectChain() ? 0 : 2; expected_set_cookie_count += 2; req->Start(); @@ -3170,7 +3204,7 @@ // Verify that SameSite cookies may or may not be set for a cross-scheme // (same-registrable-domain) redirected subresource request, depending on the - // status of Schemeful Same-Site. + // status of Schemeful Same-Site and whether redirect chains are considered. { base::test::ScopedFeatureList feature_list; feature_list.InitAndDisableFeature(features::kSchemefulSameSite); @@ -3184,8 +3218,10 @@ req->set_isolation_info(IsolationInfo::Create( IsolationInfo::RequestType::kOther, kHttpOrigin, kHttpOrigin, kHttpSiteForCookies, {} /* party_context */)); + req->set_first_party_url_policy( + RedirectInfo::FirstPartyURLPolicy::UPDATE_URL_ON_REDIRECT); req->set_site_for_cookies(kHttpSiteForCookies); - req->set_initiator(kHttpOrigin); + req->set_initiator(kOrigin); expected_cookies += 2; expected_set_cookie_count += 2; @@ -3209,10 +3245,12 @@ req->set_isolation_info(IsolationInfo::Create( IsolationInfo::RequestType::kOther, kHttpOrigin, kHttpOrigin, kHttpSiteForCookies, {} /* party_context */)); + req->set_first_party_url_policy( + RedirectInfo::FirstPartyURLPolicy::UPDATE_URL_ON_REDIRECT); req->set_site_for_cookies(kHttpSiteForCookies); - req->set_initiator(kHttpOrigin); + req->set_initiator(kOrigin); - expected_cookies += 0; + expected_cookies += DoesCookieSameSiteConsiderRedirectChain() ? 0 : 2; expected_set_cookie_count += 2; req->Start(); @@ -3223,6 +3261,10 @@ } } +INSTANTIATE_TEST_SUITE_P(/* no label */, + URLRequestSameSiteCookiesTest, + ::testing::Bool()); + // Tests that __Secure- cookies can't be set on non-secure origins. TEST_F(URLRequestTest, SecureCookiePrefixOnNonsecureOrigin) { EmbeddedTestServer http_server;
diff --git a/remoting/client/software_video_renderer.cc b/remoting/client/software_video_renderer.cc index 77391b89..1b6a25aa 100644 --- a/remoting/client/software_video_renderer.cc +++ b/remoting/client/software_video_renderer.cc
@@ -160,7 +160,7 @@ std::move(frame)), base::BindOnce(&SoftwareVideoRenderer::RenderFrame, weak_factory_.GetWeakPtr(), std::move(frame_stats), - base::AdaptCallbackForRepeating(done_runner.Release()))); + done_runner.Release())); } void SoftwareVideoRenderer::RenderFrame(
diff --git a/remoting/protocol/webrtc_transport.cc b/remoting/protocol/webrtc_transport.cc index 03b04522..a92906a 100644 --- a/remoting/protocol/webrtc_transport.cc +++ b/remoting/protocol/webrtc_transport.cc
@@ -561,7 +561,12 @@ const std::string& name) { webrtc::DataChannelInit config; config.reliable = true; - auto data_channel = peer_connection()->CreateDataChannel(name, &config); + auto result = peer_connection()->CreateDataChannelOrError(name, &config); + if (!result.ok()) { + LOG(ERROR) << "CreateDataChannel() failed: " << result.error().message(); + return nullptr; + } + auto data_channel = result.MoveValue(); if (name == kControlChannelName) { DCHECK(!control_data_channel_); control_data_channel_ = data_channel;
diff --git a/services/media_session/audio_focus_manager.cc b/services/media_session/audio_focus_manager.cc index 7fe7f43..efd7d274 100644 --- a/services/media_session/audio_focus_manager.cc +++ b/services/media_session/audio_focus_manager.cc
@@ -84,6 +84,10 @@ observer_->OnFocusLost(std::move(session)); } + void OnRequestIdReleased(const base::UnguessableToken& request_id) { + observer_->OnRequestIdReleased(request_id); + } + private: const base::UnguessableToken identity_; mojo::Remote<mojom::AudioFocusObserver> observer_; @@ -264,6 +268,18 @@ std::move(callback).Run(std::move(requests)); } +void AudioFocusManager::RequestIdReleased( + const base::UnguessableToken& request_id) { + for (const auto& observer : observers_) + observer->OnRequestIdReleased(request_id); + + const base::UnguessableToken& source_id = GetBindingIdentity(); + for (auto& holder : source_observers_) { + if (holder->identity() == source_id) + holder->OnRequestIdReleased(request_id); + } +} + void AudioFocusManager::CreateActiveMediaController( mojo::PendingReceiver<mojom::MediaController> receiver) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
diff --git a/services/media_session/audio_focus_manager.h b/services/media_session/audio_focus_manager.h index 2ff9f053c..bba3381c 100644 --- a/services/media_session/audio_focus_manager.h +++ b/services/media_session/audio_focus_manager.h
@@ -74,6 +74,7 @@ mojo::PendingRemote<mojom::AudioFocusObserver> observer) override; void GetSourceFocusRequests(const base::UnguessableToken& source_id, GetFocusRequestsCallback callback) override; + void RequestIdReleased(const base::UnguessableToken& request_id) override; // mojom::AudioFocusManagerDebug. void GetDebugInfoForRequest(const RequestId& request_id,
diff --git a/services/media_session/public/cpp/test/audio_focus_test_util.h b/services/media_session/public/cpp/test/audio_focus_test_util.h index 62d1c95..f5392a5 100644 --- a/services/media_session/public/cpp/test/audio_focus_test_util.h +++ b/services/media_session/public/cpp/test/audio_focus_test_util.h
@@ -27,6 +27,7 @@ media_session::mojom::AudioFocusRequestStatePtr session) override; void OnFocusLost( media_session::mojom::AudioFocusRequestStatePtr session) override; + void OnRequestIdReleased(const base::UnguessableToken& request_id) override {} void WaitForGainedEvent(); void WaitForLostEvent();
diff --git a/services/media_session/public/mojom/audio_focus.mojom b/services/media_session/public/mojom/audio_focus.mojom index b10038c..ec8bb45 100644 --- a/services/media_session/public/mojom/audio_focus.mojom +++ b/services/media_session/public/mojom/audio_focus.mojom
@@ -7,7 +7,7 @@ import "mojo/public/mojom/base/unguessable_token.mojom"; import "services/media_session/public/mojom/media_session.mojom"; -// Next MinVersion: 8 +// Next MinVersion: 9 // These are the different modes the AudioFocusManager can enforce audio focus. [Stable, Extensible] @@ -73,6 +73,12 @@ // The given |session| lost audio focus. OnFocusLost@1(AudioFocusRequestState state); + + // The given |request_id| will no longer be used. This is the |request_id| + // attribute of the AudioFocusRequestState struct given in |OnFocusGained()| + // and |OnFocusLost()|. + [MinVersion=8] OnRequestIdReleased@2( + mojo_base.mojom.UnguessableToken request_id); }; // Controls audio focus for an associated request. @@ -154,6 +160,12 @@ [MinVersion=7] GetSourceFocusRequests@8( mojo_base.mojom.UnguessableToken source_id) => (array<AudioFocusRequestState> requests); + + // Informs the AudioFocusManager that the given request ID will no longer be + // used. This is the |request_id| provided by the client in + // |RequestGroupedAudioFocus()|. + [MinVersion=8] RequestIdReleased@9( + mojo_base.mojom.UnguessableToken request_id); }; // Provides debug information about audio focus requests.
diff --git a/services/network/network_context.cc b/services/network/network_context.cc index fa95b174..2928935f 100644 --- a/services/network/network_context.cc +++ b/services/network/network_context.cc
@@ -883,6 +883,18 @@ std::move(callback).Run(); } +void NetworkContext::SetDocumentReportingEndpoints( + const url::Origin& origin, + const net::NetworkIsolationKey& network_isolation_key, + const base::flat_map<std::string, std::string>& endpoints) { + net::ReportingService* reporting_service = + url_request_context()->reporting_service(); + if (reporting_service) { + reporting_service->SetDocumentReportingEndpoints( + origin, network_isolation_key, endpoints); + } +} + void NetworkContext::QueueReport( const std::string& type, const std::string& group, @@ -970,6 +982,13 @@ NOTREACHED(); } +void NetworkContext::SetDocumentReportingEndpoints( + const url::Origin& origin, + const net::NetworkIsolationKey& network_isolation_key, + const base::flat_map<std::string, std::string>& endpoints) { + NOTREACHED(); +} + void NetworkContext::QueueReport( const std::string& type, const std::string& group,
diff --git a/services/network/network_context.h b/services/network/network_context.h index 89451c6..a0fbfe1 100644 --- a/services/network/network_context.h +++ b/services/network/network_context.h
@@ -389,6 +389,10 @@ override; void CreateMdnsResponder( mojo::PendingReceiver<mojom::MdnsResponder> responder_receiver) override; + void SetDocumentReportingEndpoints( + const url::Origin& origin, + const net::NetworkIsolationKey& network_isolation_key, + const base::flat_map<std::string, std::string>& endpoints) override; void QueueReport(const std::string& type, const std::string& group, const GURL& url,
diff --git a/services/network/public/cpp/parsed_headers.cc b/services/network/public/cpp/parsed_headers.cc index 5db6782..5cf224a 100644 --- a/services/network/public/cpp/parsed_headers.cc +++ b/services/network/public/cpp/parsed_headers.cc
@@ -4,7 +4,10 @@ #include "services/network/public/cpp/parsed_headers.h" +#include "build/build_config.h" +#include "net/base/features.h" #include "net/http/http_response_headers.h" +#include "net/reporting/reporting_header_parser.h" #include "services/network/public/cpp/bfcache_opt_in_parser.h" #include "services/network/public/cpp/client_hints.h" #include "services/network/public/cpp/content_security_policy/content_security_policy.h" @@ -73,6 +76,13 @@ ParseBFCacheOptInUnload(bfcache_opt_in); } +#if BUILDFLAG(ENABLE_REPORTING) + std::string reporting_endpoints; + if (headers->GetNormalizedHeader("Reporting-Endpoints", &reporting_endpoints)) + parsed_headers->reporting_endpoints = + net::ParseReportingEndpoints(reporting_endpoints); +#endif + return parsed_headers; }
diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom index 8b74f2f..1769373 100644 --- a/services/network/public/mojom/network_context.mojom +++ b/services/network/public/mojom/network_context.mojom
@@ -885,6 +885,19 @@ // Returns a JSON value containing data for displaying on a debugging page. GetDomainReliabilityJSON() => (mojo_base.mojom.Value data); + // Configures per-resource reporting endpoints set with the + // Reporting-Endpoints header. + // |network_isolation_key| is used when creating the endpoints in the + // ReportingCache, and will need to match the key sent when reports are queued + // in order for these reporting endpoints to be considered for delivery. + // |endpoints| is a mapping of endpoint name to URL (URLs here are represented + // as strings, and will be rejected if they fail to parse or are not secure). + // + // Spec: https://w3c.github.io/reporting/#header + SetDocumentReportingEndpoints( + url.mojom.Origin origin, NetworkIsolationKey network_isolation_key, + map<string,string> endpoints); + // Queues a report via the Reporting API. |type| describes the type of report // (as well as what data will contained in |body|). |group| specifies the // endpoint group that the report will be delivered to. |url| indicates the
diff --git a/services/network/public/mojom/parsed_headers.mojom b/services/network/public/mojom/parsed_headers.mojom index 5880187..ba5a8dc 100644 --- a/services/network/public/mojom/parsed_headers.mojom +++ b/services/network/public/mojom/parsed_headers.mojom
@@ -77,4 +77,9 @@ // Parsed BFCache-Opt-In value. Currently "unload" is the only possible value, // so record if that's present. bool bfcache_opt_in_unload = false; + + // Parsed mapping of endpoint names to URLs from the Reporting-Endpoints + // header. Will be null if that header was not present in the response. + // URLs are represented here as strings, and have not been validated. + map<string,string>? reporting_endpoints; };
diff --git a/services/network/test/test_network_context.h b/services/network/test/test_network_context.h index a63f7675..a0b7e16 100644 --- a/services/network/test/test_network_context.h +++ b/services/network/test/test_network_context.h
@@ -104,6 +104,10 @@ ClearTrustTokenDataCallback callback) override {} void GetDomainReliabilityJSON( GetDomainReliabilityJSONCallback callback) override {} + void SetDocumentReportingEndpoints( + const url::Origin& origin, + const net::NetworkIsolationKey& network_isolation_key, + const base::flat_map<std::string, std::string>& endpoints) override {} void QueueReport(const std::string& type, const std::string& group, const GURL& url,
diff --git a/services/network/udp_socket_unittest.cc b/services/network/udp_socket_unittest.cc index 54640ee..51a8a7a2 100644 --- a/services/network/udp_socket_unittest.cc +++ b/services/network/udp_socket_unittest.cc
@@ -667,10 +667,11 @@ EXPECT_EQ(std::vector<uint8_t>(), result.data.value()); } -#if defined(OS_ANDROID) +#if defined(OS_ANDROID) || defined(OS_IOS) // Some Android devices do not support multicast socket. // The ones supporting multicast need WifiManager.MulticastLock to enable it. // https://developer.android.com/reference/android/net/wifi/WifiManager.MulticastLock.html +// TODO(crbug.com/1215667): Fails on iOS running on Mac 11 machines. #define MAYBE_JoinMulticastGroup DISABLED_JoinMulticastGroup #else #define MAYBE_JoinMulticastGroup JoinMulticastGroup
diff --git a/sql/README.md b/sql/README.md index e281fa9..e4443ede 100644 --- a/sql/README.md +++ b/sql/README.md
@@ -111,6 +111,17 @@ that is a primary key and has an `INTEGER` type is considered an alias for rowid. +Each SQLite index +[is stored in a B-tree](https://sqlite.org/fileformat2.html#representation_of_sql_indices). +Each index entry is stored as a B-tree node whose key is made up of the record's +index key column values, followed by the record's primary key column values. + +`WITHOUT ROWID` table indexes can include primary key columns without additional +storage costs. This is because indexes for `WITHOUT ROWID` tables enjoy +[a space optimization](https://sqlite.org/fileformat2.html#representation_of_sql_indices) +where columns in both the primary key and the index key are not stored twice in +B-tree nodes. + ### Query processing @@ -207,8 +218,8 @@ // clang-format on ``` -* SQLite keywords should use ALL CAPS. This makes SQL query literals easier to - distinguish and search for. +* [SQLite keywords](https://sqlite.org/lang_keywords.html) should use ALL CAPS. + This makes SQL query literals easier to distinguish and search for. * Identifiers, such as table and row names, should use snake_case. @@ -263,6 +274,11 @@ ### Schema style +Identifiers (table / index / column names and aliases) must not be +[current SQLite keywords](https://sqlite.org/lang_keywords.html). Identifiers +may not start with the `sqlite_` prefix, to avoid conflicting with the name of a +[SQLite internal schema object](https://www.sqlite.org/fileformat2.html#storage_of_the_sql_database_schema). + Column types should only be one of the the SQLite storage types (`INTEGER`, `REAL`, `TEXT`, `BLOB`), so readers can avoid reasoning about SQLite's type affinity.
diff --git a/storage/browser/file_system/file_system_context.cc b/storage/browser/file_system/file_system_context.cc index d78eea5..c28e98c 100644 --- a/storage/browser/file_system/file_system_context.cc +++ b/storage/browser/file_system/file_system_context.cc
@@ -575,10 +575,10 @@ // top of an external filesystem). Hence cracking needs to be iterated. for (;;) { FileSystemURL cracked = current; - for (size_t i = 0; i < url_crackers_.size(); ++i) { - if (!url_crackers_[i]->HandlesFileSystemMountType(current.type())) + for (MountPoints* url_cracker : url_crackers_) { + if (!url_cracker->HandlesFileSystemMountType(current.type())) continue; - cracked = url_crackers_[i]->CrackFileSystemURL(current); + cracked = url_cracker->CrackFileSystemURL(current); if (cracked.is_valid()) break; }
diff --git a/storage/browser/file_system/file_system_quota_client.cc b/storage/browser/file_system/file_system_quota_client.cc index 85f4505c3..e74b046 100644 --- a/storage/browser/file_system/file_system_quota_client.cc +++ b/storage/browser/file_system/file_system_quota_client.cc
@@ -4,34 +4,30 @@ #include "storage/browser/file_system/file_system_quota_client.h" -#include <algorithm> -#include <memory> +#include <string> +#include <utility> #include <vector> #include "base/bind.h" #include "base/check.h" -#include "base/files/file_util.h" +#include "base/files/file.h" #include "base/location.h" +#include "base/sequence_checker.h" #include "base/sequenced_task_runner.h" -#include "base/single_thread_task_runner.h" -#include "base/task_runner_util.h" +#include "storage/browser/file_system/file_system_backend.h" #include "storage/browser/file_system/file_system_context.h" -#include "storage/browser/file_system/file_system_usage_cache.h" -#include "storage/browser/file_system/sandbox_file_system_backend.h" +#include "storage/common/file_system/file_system_types.h" #include "storage/common/file_system/file_system_util.h" #include "third_party/blink/public/mojom/quota/quota_types.mojom.h" -#include "url/gurl.h" #include "url/origin.h" -using blink::mojom::StorageType; - namespace storage { namespace { std::vector<url::Origin> GetOriginsForTypeOnFileTaskRunner( FileSystemContext* context, - StorageType storage_type) { + blink::mojom::StorageType storage_type) { FileSystemType type = FileSystemQuotaClient::QuotaStorageTypeToFileSystemType(storage_type); DCHECK(type != kFileSystemTypeUnknown); @@ -44,7 +40,7 @@ std::vector<url::Origin> GetOriginsForHostOnFileTaskRunner( FileSystemContext* context, - StorageType storage_type, + blink::mojom::StorageType storage_type, const std::string& host) { FileSystemType type = FileSystemQuotaClient::QuotaStorageTypeToFileSystemType(storage_type); @@ -84,13 +80,19 @@ FileSystemQuotaClient::FileSystemQuotaClient( FileSystemContext* file_system_context) - : file_system_context_(file_system_context) {} + : file_system_context_(file_system_context) { + DETACH_FROM_SEQUENCE(sequence_checker_); +} -FileSystemQuotaClient::~FileSystemQuotaClient() = default; +FileSystemQuotaClient::~FileSystemQuotaClient() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); +} -void FileSystemQuotaClient::GetOriginUsage(const url::Origin& origin, - StorageType storage_type, - GetOriginUsageCallback callback) { +void FileSystemQuotaClient::GetOriginUsage( + const url::Origin& origin, + blink::mojom::StorageType storage_type, + GetOriginUsageCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!callback.is_null()); FileSystemType type = @@ -103,8 +105,8 @@ return; } - base::PostTaskAndReplyWithResult( - file_task_runner(), FROM_HERE, + file_task_runner()->PostTaskAndReplyWithResult( + FROM_HERE, // It is safe to pass Unretained(quota_util) since context owns it. base::BindOnce(&FileSystemQuotaUtil::GetOriginUsageOnFileTaskRunner, base::Unretained(quota_util), @@ -113,8 +115,9 @@ } void FileSystemQuotaClient::GetOriginsForType( - StorageType storage_type, + blink::mojom::StorageType storage_type, GetOriginsForTypeCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!callback.is_null()); file_task_runner()->PostTaskAndReplyWithResult( @@ -125,9 +128,10 @@ } void FileSystemQuotaClient::GetOriginsForHost( - StorageType storage_type, + blink::mojom::StorageType storage_type, const std::string& host, GetOriginsForHostCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!callback.is_null()); file_task_runner()->PostTaskAndReplyWithResult( @@ -140,21 +144,27 @@ void FileSystemQuotaClient::DeleteOriginData( const url::Origin& origin, - StorageType type, + blink::mojom::StorageType type, DeleteOriginDataCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(!callback.is_null()); + FileSystemType fs_type = QuotaStorageTypeToFileSystemType(type); DCHECK(fs_type != kFileSystemTypeUnknown); - base::PostTaskAndReplyWithResult( - file_task_runner(), FROM_HERE, + file_task_runner()->PostTaskAndReplyWithResult( + FROM_HERE, base::BindOnce(&DeleteOriginOnFileTaskRunner, base::RetainedRef(file_system_context_), origin, fs_type), std::move(callback)); } void FileSystemQuotaClient::PerformStorageCleanup( - StorageType type, + blink::mojom::StorageType type, PerformStorageCleanupCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(!callback.is_null()); + FileSystemType fs_type = QuotaStorageTypeToFileSystemType(type); DCHECK(fs_type != kFileSystemTypeUnknown); file_task_runner()->PostTaskAndReply( @@ -182,6 +192,7 @@ } base::SequencedTaskRunner* FileSystemQuotaClient::file_task_runner() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return file_system_context_->default_file_task_runner(); }
diff --git a/storage/browser/file_system/file_system_quota_client.h b/storage/browser/file_system/file_system_quota_client.h index bddbe642..b6f22d6d 100644 --- a/storage/browser/file_system/file_system_quota_client.h +++ b/storage/browser/file_system/file_system_quota_client.h
@@ -5,25 +5,24 @@ #ifndef STORAGE_BROWSER_FILE_SYSTEM_FILE_SYSTEM_QUOTA_CLIENT_H_ #define STORAGE_BROWSER_FILE_SYSTEM_FILE_SYSTEM_QUOTA_CLIENT_H_ -#include <set> #include <string> -#include <utility> -#include "base/compiler_specific.h" #include "base/component_export.h" -#include "base/macros.h" #include "base/memory/ref_counted.h" -#include "storage/browser/file_system/file_system_quota_util.h" +#include "base/sequence_checker.h" +#include "base/thread_annotations.h" #include "storage/browser/quota/quota_client.h" -#include "storage/browser/quota/quota_client_type.h" #include "storage/common/file_system/file_system_types.h" #include "third_party/blink/public/mojom/quota/quota_types.mojom.h" -#include "url/origin.h" namespace base { class SequencedTaskRunner; } +namespace url { +class Origin; +} + namespace storage { class FileSystemContext; @@ -35,6 +34,9 @@ public: explicit FileSystemQuotaClient(FileSystemContext* file_system_context); + FileSystemQuotaClient(const FileSystemQuotaClient&) = delete; + FileSystemQuotaClient& operator=(const FileSystemQuotaClient&) = delete; + // QuotaClient methods. void OnQuotaManagerDestroyed() override {} void GetOriginUsage(const url::Origin& origin, @@ -64,9 +66,10 @@ base::SequencedTaskRunner* file_task_runner() const; - scoped_refptr<FileSystemContext> file_system_context_; + SEQUENCE_CHECKER(sequence_checker_); - DISALLOW_COPY_AND_ASSIGN(FileSystemQuotaClient); + const scoped_refptr<FileSystemContext> file_system_context_ + GUARDED_BY_CONTEXT(sequence_checker_); }; } // namespace storage
diff --git a/styleguide/java/java.md b/styleguide/java/java.md index 67b6b57..2c6ca80 100644 --- a/styleguide/java/java.md +++ b/styleguide/java/java.md
@@ -132,6 +132,36 @@ * Always prefer `androidx.annotation.Nullable`. * It uses `@Retention(SOURCE)` rather than `@Retention(RUNTIME)`. +### IntDef Instead of Enum + +Java enums generate far more bytecode than integer constants. When integers are +sufficient, prefer using an [@IntDef annotation], which will have usage checked +by [Android lint]. + +Values can be declared outside or inside the `@interface`. We recommend the +latter, with constants nested within it as follows: + +```java +@IntDef({ContactsPickerAction.CANCEL, ContactsPickerAction.CONTACTS_SELECTED, + ContactsPickerAction.SELECT_ALL, ContactsPickerAction.UNDO_SELECT_ALL}) +@Retention(RetentionPolicy.SOURCE) +public @interface ContactsPickerAction { + int CANCEL = 0; + int CONTACTS_SELECTED = 1; + int SELECT_ALL = 2; + int UNDO_SELECT_ALL = 3; + int NUM_ENTRIES = 4; +} +// ... +void onContactsPickerUserAction(@ContactsPickerAction int action, ...); +``` + +Values of `Integer` type are also supported, which allows using a sentinel +`null` if needed. + +[@IntDef annotation]: https://developer.android.com/studio/write/annotations#enum-annotations +[Android lint]: https://chromium.googlesource.com/chromium/src/+/HEAD/build/android/docs/lint.md + ## Tools ### Automatically formatting edited files
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json index 8c6b2cd..4f6cb436 100644 --- a/testing/buildbot/chromium.chromiumos.json +++ b/testing/buildbot/chromium.chromiumos.json
@@ -4911,6 +4911,23 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "lacros_chrome_browsertests_run_in_series", + "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests_run_in_series/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "os": "Ubuntu-18.04" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, "test": "lacros_chrome_unittests", "test_id_prefix": "ninja://chrome/test:lacros_chrome_unittests/" }, @@ -5785,6 +5802,23 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "lacros_chrome_browsertests_run_in_series", + "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests_run_in_series/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "os": "Ubuntu-18.04" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, "test": "lacros_chrome_unittests", "test_id_prefix": "ninja://chrome/test:lacros_chrome_unittests/" },
diff --git a/testing/buildbot/chromium.clang.json b/testing/buildbot/chromium.clang.json index 8e0fca4d..f1f7c970 100644 --- a/testing/buildbot/chromium.clang.json +++ b/testing/buildbot/chromium.clang.json
@@ -43503,7 +43503,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -43553,7 +43553,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -43603,7 +43603,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -43653,7 +43653,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -43703,7 +43703,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -43753,7 +43753,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -43803,7 +43803,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -43853,7 +43853,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -43903,7 +43903,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -43953,7 +43953,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -44003,7 +44003,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -44053,7 +44053,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -44103,7 +44103,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -44153,7 +44153,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -44203,7 +44203,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -44253,7 +44253,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -44303,7 +44303,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -44353,7 +44353,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -44424,7 +44424,7 @@ { "cpu": "x86-64", "device": "iPhone8,1", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "expiration": 21600, @@ -44469,7 +44469,7 @@ { "cpu": "x86-64", "device": "iPhone8,1", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "expiration": 21600, @@ -44514,7 +44514,7 @@ { "cpu": "x86-64", "device": "iPhone8,1", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "expiration": 21600, @@ -44559,7 +44559,7 @@ { "cpu": "x86-64", "device": "iPhone8,1", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "expiration": 21600, @@ -44604,7 +44604,7 @@ { "cpu": "x86-64", "device": "iPhone8,1", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "expiration": 21600, @@ -44649,7 +44649,7 @@ { "cpu": "x86-64", "device": "iPhone8,1", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "expiration": 21600, @@ -44694,7 +44694,7 @@ { "cpu": "x86-64", "device": "iPhone8,1", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "expiration": 21600, @@ -44739,7 +44739,7 @@ { "cpu": "x86-64", "device": "iPhone8,1", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "expiration": 21600, @@ -44784,7 +44784,7 @@ { "cpu": "x86-64", "device": "iPhone8,1", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "expiration": 21600, @@ -44829,7 +44829,7 @@ { "cpu": "x86-64", "device": "iPhone8,1", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "expiration": 21600, @@ -44874,7 +44874,7 @@ { "cpu": "x86-64", "device": "iPhone8,1", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "expiration": 21600, @@ -44919,7 +44919,7 @@ { "cpu": "x86-64", "device": "iPhone8,1", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "expiration": 21600, @@ -44964,7 +44964,7 @@ { "cpu": "x86-64", "device": "iPhone8,1", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "expiration": 21600, @@ -45009,7 +45009,7 @@ { "cpu": "x86-64", "device": "iPhone8,1", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "expiration": 21600, @@ -45054,7 +45054,7 @@ { "cpu": "x86-64", "device": "iPhone8,1", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "expiration": 21600, @@ -45099,7 +45099,7 @@ { "cpu": "x86-64", "device": "iPhone8,1", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "expiration": 21600, @@ -45144,7 +45144,7 @@ { "cpu": "x86-64", "device": "iPhone8,1", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "expiration": 21600, @@ -45189,7 +45189,7 @@ { "cpu": "x86-64", "device": "iPhone8,1", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "expiration": 21600,
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json index a5ee086..4662287 100644 --- a/testing/buildbot/chromium.fyi.json +++ b/testing/buildbot/chromium.fyi.json
@@ -1765,6 +1765,23 @@ } ] }, + "Win x64 Builder (reclient)(cross)": { + "additional_compile_targets": [ + "pdf_fuzzers" + ], + "scripts": [ + { + "name": "check_network_annotations", + "script": "check_network_annotations.py", + "swarming": {} + }, + { + "name": "webkit_lint", + "script": "blink_lint_expectations.py", + "swarming": {} + } + ] + }, "android-backuprefptr-arm-fyi-rel": { "gtest_tests": [ { @@ -18353,7 +18370,8 @@ }, "swarming": { "can_use_on_swarming_builders": true, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 6 }, "test": "web_engine_integration_tests", "test_id_prefix": "ninja://fuchsia/engine:web_engine_integration_tests/" @@ -22869,7 +22887,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -22919,7 +22937,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -22969,7 +22987,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -23019,7 +23037,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -23069,7 +23087,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -23119,7 +23137,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -23169,7 +23187,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -23219,7 +23237,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -23269,7 +23287,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -23319,7 +23337,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -23369,7 +23387,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -23419,7 +23437,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -23469,7 +23487,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -23519,7 +23537,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -23569,7 +23587,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -23619,7 +23637,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -23669,7 +23687,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -23719,7 +23737,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -23769,7 +23787,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -23819,7 +23837,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -23869,7 +23887,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -23919,7 +23937,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -23969,7 +23987,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -24019,7 +24037,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -24069,7 +24087,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -24119,7 +24137,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -24169,7 +24187,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -24219,7 +24237,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -24269,7 +24287,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -24319,7 +24337,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -24369,7 +24387,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -24419,7 +24437,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -24469,7 +24487,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -24519,7 +24537,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -24569,7 +24587,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -24619,7 +24637,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -24669,7 +24687,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -24719,7 +24737,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -24769,7 +24787,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -24819,7 +24837,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -24869,7 +24887,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -24919,7 +24937,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -24969,7 +24987,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -25019,7 +25037,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -25069,7 +25087,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -25119,7 +25137,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -25176,7 +25194,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -25229,7 +25247,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -25282,7 +25300,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -25335,7 +25353,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -25388,7 +25406,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -25441,7 +25459,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -25494,7 +25512,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -25547,7 +25565,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -25600,7 +25618,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -25653,7 +25671,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -25706,7 +25724,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -25759,7 +25777,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -25812,7 +25830,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -25865,7 +25883,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -25918,7 +25936,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -25971,7 +25989,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -26024,7 +26042,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -26077,7 +26095,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -26130,7 +26148,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -26183,7 +26201,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -26236,7 +26254,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -26289,7 +26307,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -26342,7 +26360,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -26395,7 +26413,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -26448,7 +26466,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -26501,7 +26519,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -26554,7 +26572,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -26607,7 +26625,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -26660,7 +26678,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -26713,7 +26731,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -26766,7 +26784,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -26819,7 +26837,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -26872,7 +26890,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -26925,7 +26943,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -26979,7 +26997,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -27033,7 +27051,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -27087,7 +27105,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -27141,7 +27159,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -27195,7 +27213,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -27249,7 +27267,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -27303,7 +27321,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -27358,7 +27376,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -27413,7 +27431,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -27468,7 +27486,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -27523,7 +27541,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -27578,7 +27596,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -27633,7 +27651,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -27688,7 +27706,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -27743,7 +27761,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -27798,7 +27816,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -27853,7 +27871,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -27908,7 +27926,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -27963,7 +27981,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -28017,7 +28035,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -28071,7 +28089,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -28125,7 +28143,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -28179,7 +28197,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -28233,7 +28251,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -28287,7 +28305,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -28341,7 +28359,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -28395,7 +28413,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -28449,7 +28467,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -28503,7 +28521,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -28557,7 +28575,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -28611,7 +28629,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -28666,7 +28684,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -28721,7 +28739,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -28776,7 +28794,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -28831,7 +28849,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -28886,7 +28904,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -28940,7 +28958,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -28993,7 +29011,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -29046,7 +29064,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -29099,7 +29117,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -29152,7 +29170,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -29205,7 +29223,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -29258,7 +29276,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -29311,7 +29329,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -29365,7 +29383,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -29419,7 +29437,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -29473,7 +29491,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -29527,7 +29545,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -29581,7 +29599,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -29635,7 +29653,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -29688,7 +29706,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -29741,7 +29759,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -29794,7 +29812,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -29847,7 +29865,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -29900,7 +29918,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -29953,7 +29971,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -30007,7 +30025,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -30061,7 +30079,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -30115,7 +30133,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -30169,7 +30187,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -30223,7 +30241,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -30277,7 +30295,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -30330,7 +30348,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -30383,7 +30401,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -30436,7 +30454,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -30489,7 +30507,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -30542,7 +30560,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -30595,7 +30613,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -30648,7 +30666,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -30701,7 +30719,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -30754,7 +30772,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -30807,7 +30825,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -30861,7 +30879,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -30915,7 +30933,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -30969,7 +30987,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -31023,7 +31041,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -31077,7 +31095,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -31131,7 +31149,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -31184,7 +31202,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -31237,7 +31255,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -31290,7 +31308,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -31343,7 +31361,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -31396,7 +31414,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -31449,7 +31467,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -31502,7 +31520,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -31555,7 +31573,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -31608,7 +31626,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -31661,7 +31679,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -31714,7 +31732,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -31767,7 +31785,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -31820,7 +31838,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -31873,7 +31891,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -31926,7 +31944,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -31979,7 +31997,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -32032,7 +32050,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -32085,7 +32103,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -32138,7 +32156,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -32191,7 +32209,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -32244,7 +32262,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -32297,7 +32315,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -32350,7 +32368,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -32403,7 +32421,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -32456,7 +32474,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -32509,7 +32527,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -32562,7 +32580,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -32615,7 +32633,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -32668,7 +32686,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -32721,7 +32739,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -32774,7 +32792,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -32827,7 +32845,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -32880,7 +32898,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -32933,7 +32951,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -32986,7 +33004,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -33039,7 +33057,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -33092,7 +33110,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -33145,7 +33163,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -33198,7 +33216,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -33251,7 +33269,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -33304,7 +33322,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -33357,7 +33375,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -33410,7 +33428,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -33463,7 +33481,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -33516,7 +33534,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -33569,7 +33587,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -33622,7 +33640,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -33675,7 +33693,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -33729,7 +33747,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -33779,7 +33797,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -33833,7 +33851,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -33883,7 +33901,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -33933,7 +33951,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -33983,7 +34001,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -34033,7 +34051,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -34083,7 +34101,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -34133,7 +34151,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -34183,7 +34201,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -34234,7 +34252,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -34285,7 +34303,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -34337,7 +34355,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -34389,7 +34407,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -34440,7 +34458,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -34491,7 +34509,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -34542,7 +34560,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -34593,7 +34611,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -34643,7 +34661,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -34693,7 +34711,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -34743,7 +34761,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -34794,7 +34812,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -34844,7 +34862,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -34894,7 +34912,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -34945,7 +34963,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -34995,7 +35013,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -35045,7 +35063,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -35095,7 +35113,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -35145,7 +35163,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -35195,7 +35213,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -35245,7 +35263,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -35295,7 +35313,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -35345,7 +35363,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -35395,7 +35413,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -35451,7 +35469,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -35503,7 +35521,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -35555,7 +35573,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -35607,7 +35625,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -35659,7 +35677,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -35711,7 +35729,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -35763,7 +35781,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -35815,7 +35833,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -35867,7 +35885,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -35919,7 +35937,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -35971,7 +35989,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -36023,7 +36041,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -36075,7 +36093,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -36127,7 +36145,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -36179,7 +36197,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -36231,7 +36249,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -36284,7 +36302,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -36337,7 +36355,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -36390,7 +36408,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -36444,7 +36462,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -36498,7 +36516,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -36552,7 +36570,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -36606,7 +36624,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -36659,7 +36677,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -36712,7 +36730,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -36765,7 +36783,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -36818,7 +36836,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -36872,7 +36890,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -36925,7 +36943,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -36977,7 +36995,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -37030,7 +37048,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -37083,7 +37101,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -37135,7 +37153,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -37187,7 +37205,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -37239,7 +37257,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -37291,7 +37309,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -37343,7 +37361,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -37395,7 +37413,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -37448,7 +37466,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -37501,7 +37519,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -37553,7 +37571,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -37605,7 +37623,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -37657,7 +37675,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -37709,7 +37727,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -37762,7 +37780,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -37815,7 +37833,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -37867,7 +37885,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -37919,7 +37937,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -37971,7 +37989,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -38023,7 +38041,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -38075,7 +38093,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -38127,7 +38145,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -38179,7 +38197,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -38231,7 +38249,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -38283,7 +38301,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -38335,7 +38353,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -38387,7 +38405,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -38439,7 +38457,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -38491,7 +38509,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -38543,7 +38561,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -38595,7 +38613,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -38647,7 +38665,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -38699,7 +38717,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -38751,7 +38769,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -64410,6 +64428,19 @@ "can_use_on_swarming_builders": true, "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "lacros_chrome_browsertests_run_in_series", + "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests_run_in_series/" + }, + { + "isolate_profile_data": true, + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, "test": "lacros_chrome_unittests", "test_id_prefix": "ninja://chrome/test:lacros_chrome_unittests/" }, @@ -65746,6 +65777,24 @@ ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" }, + "test": "lacros_chrome_browsertests_run_in_series", + "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests_run_in_series/" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "os": "Ubuntu-18.04", + "ssd": "0" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, "test": "lacros_chrome_unittests", "test_id_prefix": "ninja://chrome/test:lacros_chrome_unittests/" }, @@ -66444,6 +66493,29 @@ }, "test": "lacros_chrome_browsertests", "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/" + }, + { + "args": [ + "--ash-chrome-path-override=../../lacros_version_skew_tests_M92/chrome" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 92.0.4499.0", + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", + "location": "lacros_version_skew_tests_M92", + "revision": "version:92.0.4499.0" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "lacros_chrome_browsertests_run_in_series", + "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests_run_in_series/" } ] },
diff --git a/testing/buildbot/chromium.mac.json b/testing/buildbot/chromium.mac.json index da91432..cfe6974 100644 --- a/testing/buildbot/chromium.mac.json +++ b/testing/buildbot/chromium.mac.json
@@ -12726,7 +12726,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -12777,7 +12777,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -12828,7 +12828,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -12879,7 +12879,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -12930,7 +12930,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -12981,7 +12981,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -13032,7 +13032,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -13083,7 +13083,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -13134,7 +13134,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -13185,7 +13185,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -13236,7 +13236,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -13287,7 +13287,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -13338,7 +13338,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -13389,7 +13389,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -13440,7 +13440,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -13491,7 +13491,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -13542,7 +13542,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -13593,7 +13593,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -13644,7 +13644,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -13695,7 +13695,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -13746,7 +13746,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -13797,7 +13797,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -13848,7 +13848,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -13899,7 +13899,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -13950,7 +13950,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -14001,7 +14001,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -14052,7 +14052,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -14103,7 +14103,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -14154,7 +14154,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -14205,7 +14205,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -14256,7 +14256,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -14307,7 +14307,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -14358,7 +14358,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -14409,7 +14409,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -14461,7 +14461,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -14514,7 +14514,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -14567,7 +14567,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -14619,7 +14619,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -14671,7 +14671,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -14724,7 +14724,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -14776,7 +14776,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -14827,7 +14827,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -14878,7 +14878,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -14929,7 +14929,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -14980,7 +14980,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -15031,7 +15031,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -15082,7 +15082,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -15133,7 +15133,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -15184,7 +15184,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -15235,7 +15235,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -15286,7 +15286,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -15337,7 +15337,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -15388,7 +15388,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -15439,7 +15439,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -15490,7 +15490,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -15541,7 +15541,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -15592,7 +15592,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -15643,7 +15643,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -15694,7 +15694,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -15745,7 +15745,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -15796,7 +15796,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -15847,7 +15847,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -15898,7 +15898,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -15949,7 +15949,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -16001,7 +16001,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -16053,7 +16053,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -16104,7 +16104,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -16155,7 +16155,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -16206,7 +16206,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -16257,7 +16257,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -16308,7 +16308,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -16359,7 +16359,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -16410,7 +16410,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -16461,7 +16461,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -16512,7 +16512,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -16563,7 +16563,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -16614,7 +16614,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -16665,7 +16665,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -16716,7 +16716,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -16767,7 +16767,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -16818,7 +16818,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -16869,7 +16869,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -16920,7 +16920,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -16971,7 +16971,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -17022,7 +17022,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -17073,7 +17073,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -17124,7 +17124,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -17175,7 +17175,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -17226,7 +17226,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -17277,7 +17277,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -17328,7 +17328,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -17379,7 +17379,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -17430,7 +17430,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -17481,7 +17481,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -17532,7 +17532,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -17583,7 +17583,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -17634,7 +17634,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -17685,7 +17685,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -17736,7 +17736,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -17787,7 +17787,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -17838,7 +17838,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -17889,7 +17889,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -17940,7 +17940,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -17991,7 +17991,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -18042,7 +18042,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -18093,7 +18093,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -18144,7 +18144,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -18195,7 +18195,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -18246,7 +18246,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -18297,7 +18297,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -18348,7 +18348,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -18399,7 +18399,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -18450,7 +18450,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -18501,7 +18501,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -18560,7 +18560,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -18612,7 +18612,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -18664,7 +18664,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -18716,7 +18716,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -18768,7 +18768,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -18820,7 +18820,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -18872,7 +18872,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -18925,7 +18925,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -18978,7 +18978,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -19031,7 +19031,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -19084,7 +19084,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -19137,7 +19137,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -19190,7 +19190,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -19243,7 +19243,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -19296,7 +19296,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -19349,7 +19349,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -19402,7 +19402,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -19454,7 +19454,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -19506,7 +19506,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -19558,7 +19558,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -19610,7 +19610,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -19662,7 +19662,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -19714,7 +19714,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -19766,7 +19766,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -19818,7 +19818,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -19870,7 +19870,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -19922,7 +19922,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -19975,7 +19975,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -20028,7 +20028,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -20081,7 +20081,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -20134,7 +20134,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -20186,7 +20186,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -20238,7 +20238,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -20290,7 +20290,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -20342,7 +20342,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -20394,7 +20394,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -20446,7 +20446,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -20498,7 +20498,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -20550,7 +20550,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -20602,7 +20602,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -20654,7 +20654,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -20706,7 +20706,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -20758,7 +20758,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -20810,7 +20810,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -20862,7 +20862,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -20914,7 +20914,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -20971,7 +20971,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -21021,7 +21021,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -21071,7 +21071,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -21121,7 +21121,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -21171,7 +21171,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -21222,7 +21222,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -21273,7 +21273,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -21324,7 +21324,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -21376,7 +21376,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -21428,7 +21428,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -21480,7 +21480,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -21532,7 +21532,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -21583,7 +21583,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -21634,7 +21634,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -21685,7 +21685,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -21736,7 +21736,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -21788,7 +21788,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -21840,7 +21840,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -21891,7 +21891,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -21941,7 +21941,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -21991,7 +21991,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -22041,7 +22041,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -22092,7 +22092,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -22143,7 +22143,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -22193,7 +22193,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -22244,7 +22244,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -22295,7 +22295,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -22345,7 +22345,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -22395,7 +22395,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -22445,7 +22445,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [ @@ -22495,7 +22495,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Mac-10.15" + "os": "Mac-10.15|Mac-10.16|Mac-11" } ], "named_caches": [
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl index ec50775..d7706c76 100644 --- a/testing/buildbot/gn_isolate_map.pyl +++ b/testing/buildbot/gn_isolate_map.pyl
@@ -1128,6 +1128,10 @@ "label": "//chrome/test:lacros_chrome_browsertests", "type": "windowed_test_launcher", }, + "lacros_chrome_browsertests_run_in_series": { + "label": "//chrome/test:lacros_chrome_browsertests_run_in_series", + "type": "windowed_test_launcher", + }, "lacros_chrome_unittests": { "label": "//chrome/test:lacros_chrome_unittests", "type": "console_test_launcher",
diff --git a/testing/buildbot/mixins.pyl b/testing/buildbot/mixins.pyl index d1eb3a0..70be22c 100644 --- a/testing/buildbot/mixins.pyl +++ b/testing/buildbot/mixins.pyl
@@ -687,6 +687,14 @@ }, }, }, + 'mac_10.15_or_mac_11': { + 'swarming': { + 'dimensions': { + 'cpu': 'x86-64', + 'os': 'Mac-10.15|Mac-10.16|Mac-11', + }, + }, + }, 'mac_11_beta_x64': { 'swarming': { 'dimensions': {
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl index ffc017f..7da90af 100644 --- a/testing/buildbot/test_suite_exceptions.pyl +++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -3142,6 +3142,15 @@ }, }, }, + 'web_engine_integration_tests': { + 'modifications': { + 'fuchsia-code-coverage': { + 'swarming': { + 'shards': 6, + }, + }, + }, + }, 'webdriver_tests_suite': { 'remove_from': [ 'Linux Tests', # https://crbug.com/929689, https://crbug.com/936557
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl index 557d8188..db069fb 100644 --- a/testing/buildbot/test_suites.pyl +++ b/testing/buildbot/test_suites.pyl
@@ -4331,6 +4331,7 @@ 'linux_lacros_chrome_browsertests_version_skew': { 'lacros_chrome_browsertests': { }, + 'lacros_chrome_browsertests_run_in_series': { }, }, 'linux_lacros_cq_gtests': { @@ -4348,6 +4349,7 @@ }, }, 'lacros_chrome_browsertests': {}, + 'lacros_chrome_browsertests_run_in_series': {}, 'lacros_chrome_unittests': {}, 'sync_integration_tests': {}, 'ui_base_unittests': {}, @@ -4356,6 +4358,7 @@ 'linux_lacros_specific_gtests': { 'lacros_chrome_browsertests': {}, + 'lacros_chrome_browsertests_run_in_series': {}, 'lacros_chrome_unittests': {}, },
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl index f7a88da..4b2d14f7a 100644 --- a/testing/buildbot/waterfalls.pyl +++ b/testing/buildbot/waterfalls.pyl
@@ -2041,7 +2041,7 @@ ], 'mixins': [ 'enable_resultdb', - 'mac_10.15', + 'mac_10.15_or_mac_11', 'mac_toolchain', 'out_dir_arg', 'xcode_12d4e', @@ -2075,7 +2075,7 @@ 'enable_resultdb', 'ios_restart_device', 'limited_capacity_bot', - 'mac_10.15', + 'mac_10.15_or_mac_11', 'mac_toolchain', 'out_dir_arg', 'xcode_12d4e', @@ -2707,6 +2707,16 @@ 'scripts': 'chromium_win_scripts', }, }, + 'Win x64 Builder (reclient)(cross)': { + # Copied from + # https://source.chromium.org/chromium/chromium/src/+/7b147a6777cb32d6a12e1716c61a0ed50dc1229a:testing/buildbot/waterfalls.pyl;l=6023-6030 + 'additional_compile_targets': [ + 'pdf_fuzzers' + ], + 'test_suites': { + 'scripts': 'chromium_win_scripts', + }, + }, 'android-backuprefptr-arm-fyi-rel': { 'test_suites': { 'gtest_tests': 'chromium_android_gtests', @@ -2866,7 +2876,7 @@ 'ios-asan': { 'mixins': [ 'enable_resultdb', - 'mac_10.15', + 'mac_10.15_or_mac_11', 'mac_toolchain', 'out_dir_arg', 'xcode_12d4e', @@ -2881,7 +2891,7 @@ 'enable_resultdb', 'ios_output_disabled_tests', 'isolate_profile_data', - 'mac_10.15', + 'mac_10.15_or_mac_11', 'mac_toolchain', 'out_dir_arg', 'xcode_12d4e', @@ -2894,7 +2904,7 @@ 'ios-simulator-cronet': { 'mixins': [ 'enable_resultdb', - 'mac_10.15', + 'mac_10.15_or_mac_11', 'mac_toolchain', 'out_dir_arg', 'xcode_12d4e', @@ -2907,7 +2917,7 @@ 'ios-simulator-multi-window': { 'mixins': [ 'enable_resultdb', - 'mac_10.15', + 'mac_10.15_or_mac_11', 'mac_toolchain', 'out_dir_arg', 'xcode_12d4e', @@ -2921,7 +2931,7 @@ 'mixins': [ 'enable_resultdb', 'ios_custom_webkit', - 'mac_10.15', + 'mac_10.15_or_mac_11', 'mac_toolchain', 'out_dir_arg', 'xcode_11e608c', @@ -5109,7 +5119,7 @@ 'mixins': [ 'enable_resultdb', 'isolate_profile_data', - 'mac_10.15', + 'mac_10.15_or_mac_11', 'mac_toolchain', 'out_dir_arg', 'xcode_12d4e', @@ -5126,7 +5136,7 @@ 'mixins': [ 'enable_resultdb', 'isolate_profile_data', - 'mac_10.15', + 'mac_10.15_or_mac_11', 'mac_toolchain', 'out_dir_arg', 'xcode_12d4e', @@ -5142,7 +5152,7 @@ ], 'mixins': [ 'enable_resultdb', - 'mac_10.15', + 'mac_10.15_or_mac_11', 'mac_toolchain', 'out_dir_arg', 'xcode_12d4e',
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index cc93da9..12f0e76 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -2280,7 +2280,9 @@ { "name": "Enabled", "enable_features": [ - "CopyLinkToText" + "CopyLinkToText", + "PreemptiveLinkToTextGeneration", + "SharedHighlightingV2" ] } ] @@ -4136,6 +4138,25 @@ ] } ], + "IOSStartSurface": [ + { + "platforms": [ + "ios" + ], + "experiments": [ + { + "name": "ShrinkLogo", + "params": { + "ReturnToStartSurfaceInactiveDurationInSeconds": "0", + "shrink_logo": "true" + }, + "enable_features": [ + "StartSurface" + ] + } + ] + } + ], "IOSUMABackgroundSessions": [ { "platforms": [ @@ -6323,6 +6344,25 @@ ] } ], + "ProcessHostOnUI": [ + { + "platforms": [ + "android", + "chromeos", + "linux", + "mac", + "windows" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "ProcessHostOnUI" + ] + } + ] + } + ], "ProtoDBSharedMigration": [ { "platforms": [
diff --git a/third_party/blink/public/platform/platform.h b/third_party/blink/public/platform/platform.h index 293b5754..6826455 100644 --- a/third_party/blink/public/platform/platform.h +++ b/third_party/blink/public/platform/platform.h
@@ -813,11 +813,14 @@ // MediaLog from any thread, but it must be destroyed on |owner_task_runner|. // MediaLog owners should destroy the MediaLog if the ExecutionContext is // destroyed, since |inspector_context| may no longer be valid at that point. + // |is_on_worker| is used to avoid logging to the chrome://media-internal + // page, which can only be logged to from the window main thread. // Note: |inspector_context| is only used on |owner_task_runner|, so // destroying the MediaLog on |owner_task_runner| should avoid races. virtual std::unique_ptr<media::MediaLog> GetMediaLog( MediaInspectorContext* inspector_context, - scoped_refptr<base::SingleThreadTaskRunner> owner_task_runner) { + scoped_refptr<base::SingleThreadTaskRunner> owner_task_runner, + bool is_on_worker) { return nullptr; }
diff --git a/third_party/blink/renderer/core/css/parser/css_supports_parser.cc b/third_party/blink/renderer/core/css/parser/css_supports_parser.cc index 10f1c17f..1b669f3 100644 --- a/third_party/blink/renderer/core/css/parser/css_supports_parser.cc +++ b/third_party/blink/renderer/core/css/parser/css_supports_parser.cc
@@ -13,16 +13,6 @@ namespace { -// The result kUnknown must be converted to 'false' if passed to a context -// which requires a boolean value. -// TODO(crbug.com/1052274): This is supposed to happen at the top-level, -// but currently happens on ConsumeGeneralEnclosed's result. -CSSSupportsParser::Result EvalUnknown(CSSSupportsParser::Result result) { - return result == CSSSupportsParser::Result::kUnknown - ? CSSSupportsParser::Result::kUnsupported - : result; -} - // https://drafts.csswg.org/css-syntax/#typedef-any-value bool IsNextTokenAllowedForAnyValue(CSSParserTokenRange& range) { switch (range.Peek().GetType()) { @@ -168,13 +158,7 @@ } // <general-enclosed> - // - // TODO(crbug.com/1052274): Support kUnknown beyond this point. - // - // The result kUnknown is supposed to be evaluated at the top level, but - // we have already shipped the behavior of evaluating it here, and Firefox - // does the same thing. - return EvalUnknown(ConsumeGeneralEnclosed(first_token, stream)); + return ConsumeGeneralEnclosed(first_token, stream); } // <supports-feature> = <supports-selector-fn> | <supports-decl> @@ -225,7 +209,7 @@ return Result::kParseFailure; stream.ConsumeWhitespace(); - return Result::kUnknown; + return Result::kUnsupported; } return Result::kParseFailure; }
diff --git a/third_party/blink/renderer/core/css/parser/css_supports_parser.h b/third_party/blink/renderer/core/css/parser/css_supports_parser.h index 478cacb2..a9f324d 100644 --- a/third_party/blink/renderer/core/css/parser/css_supports_parser.h +++ b/third_party/blink/renderer/core/css/parser/css_supports_parser.h
@@ -24,13 +24,6 @@ // don't support the feature. kUnsupported, kSupported, - // kUnknown is a special value used for productions that only match - // <general-enclosed> [1]. See note regarding Kleene 3-valued logic [2] - // for explanation of how this is different from kUnsupported. - // - // [1] https://drafts.csswg.org/css-conditional-3/#at-supports - // [2] https://drafts.csswg.org/mediaqueries-4/#evaluating - kUnknown, // This is used to signal parse failure in the @supports syntax itself. // This means that for a production like: // @@ -114,8 +107,6 @@ using Result = CSSSupportsParser::Result; if (a == Result::kParseFailure || b == Result::kParseFailure) return Result::kParseFailure; - if (a == Result::kUnknown && b == Result::kUnknown) - return Result::kUnknown; if (a != Result::kSupported || b != Result::kSupported) return Result::kUnsupported; return Result::kSupported; @@ -128,8 +119,6 @@ return Result::kParseFailure; if (a == Result::kSupported || b == Result::kSupported) return Result::kSupported; - if (a == Result::kUnknown || b == Result::kUnknown) - return Result::kUnknown; return Result::kUnsupported; }
diff --git a/third_party/blink/renderer/core/css/parser/css_supports_parser_test.cc b/third_party/blink/renderer/core/css/parser/css_supports_parser_test.cc index 438a118..ec9025d 100644 --- a/third_party/blink/renderer/core/css/parser/css_supports_parser_test.cc +++ b/third_party/blink/renderer/core/css/parser/css_supports_parser_test.cc
@@ -106,7 +106,6 @@ EXPECT_EQ(Result::kSupported, !Result::kUnsupported); EXPECT_EQ(Result::kUnsupported, !Result::kSupported); EXPECT_EQ(Result::kParseFailure, !Result::kParseFailure); - EXPECT_EQ(Result::kUnknown, !Result::kUnknown); } TEST_F(CSSSupportsParserTest, ResultAnd) { @@ -117,10 +116,6 @@ EXPECT_EQ(Result::kParseFailure, Result::kSupported & Result::kParseFailure); EXPECT_EQ(Result::kParseFailure, Result::kParseFailure & Result::kSupported); - - EXPECT_EQ(Result::kUnknown, Result::kUnknown & Result::kUnknown); - EXPECT_EQ(Result::kUnsupported, Result::kSupported & Result::kUnknown); - EXPECT_EQ(Result::kUnsupported, Result::kUnknown & Result::kSupported); } TEST_F(CSSSupportsParserTest, ResultOr) { @@ -131,10 +126,6 @@ EXPECT_EQ(Result::kParseFailure, Result::kSupported | Result::kParseFailure); EXPECT_EQ(Result::kParseFailure, Result::kParseFailure | Result::kSupported); - - EXPECT_EQ(Result::kUnknown, Result::kUnknown | Result::kUnknown); - EXPECT_EQ(Result::kSupported, Result::kSupported | Result::kUnknown); - EXPECT_EQ(Result::kSupported, Result::kUnknown | Result::kSupported); } TEST_F(CSSSupportsParserTest, ConsumeSupportsCondition) { @@ -318,12 +309,12 @@ } TEST_F(CSSSupportsParserTest, ConsumeGeneralEnclosed) { - EXPECT_EQ(Result::kUnknown, ConsumeGeneralEnclosed("(asdf)")); - EXPECT_EQ(Result::kUnknown, ConsumeGeneralEnclosed("( asdf )")); - EXPECT_EQ(Result::kUnknown, ConsumeGeneralEnclosed("(3)")); - EXPECT_EQ(Result::kUnknown, ConsumeGeneralEnclosed("max(1, 2)")); - EXPECT_EQ(Result::kUnknown, ConsumeGeneralEnclosed("asdf(1, 2)")); - EXPECT_EQ(Result::kUnknown, ConsumeGeneralEnclosed("asdf(1, 2)\t")); + EXPECT_EQ(Result::kUnsupported, ConsumeGeneralEnclosed("(asdf)")); + EXPECT_EQ(Result::kUnsupported, ConsumeGeneralEnclosed("( asdf )")); + EXPECT_EQ(Result::kUnsupported, ConsumeGeneralEnclosed("(3)")); + EXPECT_EQ(Result::kUnsupported, ConsumeGeneralEnclosed("max(1, 2)")); + EXPECT_EQ(Result::kUnsupported, ConsumeGeneralEnclosed("asdf(1, 2)")); + EXPECT_EQ(Result::kUnsupported, ConsumeGeneralEnclosed("asdf(1, 2)\t")); EXPECT_EQ(Result::kParseFailure, ConsumeGeneralEnclosed("(")); EXPECT_EQ(Result::kParseFailure, ConsumeGeneralEnclosed("()")); @@ -335,8 +326,8 @@ EXPECT_EQ(Result::kParseFailure, ConsumeGeneralEnclosed("(url(as'df))")); // Valid <any-value> - EXPECT_EQ(Result::kUnknown, ConsumeGeneralEnclosed("(as;df)")); - EXPECT_EQ(Result::kUnknown, ConsumeGeneralEnclosed("(as ! df)")); + EXPECT_EQ(Result::kUnsupported, ConsumeGeneralEnclosed("(as;df)")); + EXPECT_EQ(Result::kUnsupported, ConsumeGeneralEnclosed("(as ! df)")); } TEST_F(CSSSupportsParserTest, AtSupportsCondition) {
diff --git a/third_party/blink/renderer/core/css/resolver/style_adjuster.cc b/third_party/blink/renderer/core/css/resolver/style_adjuster.cc index 580d4d20..b91abc2e 100644 --- a/third_party/blink/renderer/core/css/resolver/style_adjuster.cc +++ b/third_party/blink/renderer/core/css/resolver/style_adjuster.cc
@@ -657,6 +657,7 @@ style.SetTextShadow(ComputedStyleInitialValues::InitialTextShadow()); style.SetBoxShadow(ComputedStyleInitialValues::InitialBoxShadow()); + style.SetColorScheme({"light", "dark"}); style.SetAccentColor(ComputedStyleInitialValues::InitialAccentColor()); if (!style.HasUrlBackgroundImage()) style.ClearBackgroundImage();
diff --git a/third_party/blink/renderer/core/events/pointer_event_factory.cc b/third_party/blink/renderer/core/events/pointer_event_factory.cc index ac9a6f2..7f72990 100644 --- a/third_party/blink/renderer/core/events/pointer_event_factory.cc +++ b/third_party/blink/renderer/core/events/pointer_event_factory.cc
@@ -217,6 +217,7 @@ return result; } +const PointerId PointerEventFactory::kReservedNonPointerId = -1; const PointerId PointerEventFactory::kInvalidId = 0; // Mouse id is 1 to behave the same as MS Edge for compatibility reasons.
diff --git a/third_party/blink/renderer/core/events/pointer_event_factory.h b/third_party/blink/renderer/core/events/pointer_event_factory.h index 82d3abec..252b24d 100644 --- a/third_party/blink/renderer/core/events/pointer_event_factory.h +++ b/third_party/blink/renderer/core/events/pointer_event_factory.h
@@ -85,6 +85,7 @@ static const PointerId kMouseId; static const PointerId kInvalidId; + static const PointerId kReservedNonPointerId; // Removes pointer_id from the map. void RemoveLastPosition(const PointerId pointer_id);
diff --git a/third_party/blink/renderer/core/events/simulated_event_util.cc b/third_party/blink/renderer/core/events/simulated_event_util.cc index 939380b..86d9a67 100644 --- a/third_party/blink/renderer/core/events/simulated_event_util.cc +++ b/third_party/blink/renderer/core/events/simulated_event_util.cc
@@ -124,9 +124,6 @@ // any event attributes not initialized in the |PointerEventInit| below get // their default values, all of which are appropriate for a simulated // |PointerEvent|. - // - // TODO(mustaq): Set |pointerId| to -1 after we have a spec change to fix the - // issue https://github.com/w3c/pointerevents/issues/343. PointerEventInit* initializer = PointerEventInit::Create(); PopulateSimulatedMouseEventInit(event_type, node, underlying_event, initializer, creation_scope); @@ -160,6 +157,8 @@ initializer->setPointerId(PointerEventFactory::kMouseId); initializer->setPointerType(pointer_type_names::kMouse); initializer->setIsPrimary(true); + } else { + initializer->setPointerId(PointerEventFactory::kReservedNonPointerId); } created_event = MakeGarbageCollected<PointerEvent>( event_type, initializer, timestamp, synthetic_type);
diff --git a/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.cc b/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.cc index 8e83b077..e93cdc1a 100644 --- a/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.cc +++ b/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.cc
@@ -17,6 +17,14 @@ #include "third_party/blink/renderer/platform/wtf/text/string_builder.h" #include "third_party/blink/renderer/platform/wtf/vector.h" +namespace { + +inline base::HistogramBase::Sample ToSample(int64_t value) { + return base::saturated_cast<base::HistogramBase::Sample>(value); +} + +} // namespace + namespace blink { LocalFrameUkmAggregator::ScopedUkmHierarchicalTimer::ScopedUkmHierarchicalTimer( @@ -40,13 +48,14 @@ LocalFrameUkmAggregator::ScopedUkmHierarchicalTimer:: ~ScopedUkmHierarchicalTimer() { if (aggregator_ && base::TimeTicks::IsHighResolution()) { - aggregator_->RecordSample(metric_index_, start_time_, clock_->NowTicks()); + aggregator_->RecordTimerSample(metric_index_, start_time_, + clock_->NowTicks()); } } void LocalFrameUkmAggregator::AbsoluteMetricRecord::reset() { - interval_duration = base::TimeDelta(); - main_frame_duration = base::TimeDelta(); + interval_count = 0; + main_frame_count = 0; } LocalFrameUkmAggregator::LocalFrameUkmAggregator(int64_t source_id, @@ -57,9 +66,9 @@ event_name_("Blink.UpdateTime") { // All of these are assumed to have one entry per sub-metric. DCHECK_EQ(base::size(absolute_metric_records_), metrics_data().size()); - DCHECK_EQ(base::size(current_sample_.sub_metrics_durations), + DCHECK_EQ(base::size(current_sample_.sub_metrics_counts), metrics_data().size()); - DCHECK_EQ(base::size(current_sample_.sub_main_frame_durations), + DCHECK_EQ(base::size(current_sample_.sub_main_frame_counts), metrics_data().size()); // Record average and worst case for the primary metric. @@ -90,7 +99,7 @@ // They have an associated UMA too that we own and allocate here. auto& absolute_record = absolute_metric_records_[metric_index]; absolute_record.reset(); - absolute_record.pre_fcp_aggregate = base::TimeDelta(); + absolute_record.pre_fcp_aggregate = 0; if (metric_data.has_uma) { StringBuilder uma_name; uma_name.Append(uma_preamble); @@ -144,37 +153,37 @@ // metrics and would result in double counting. std::unique_ptr<cc::BeginMainFrameMetrics> metrics_data = std::make_unique<cc::BeginMainFrameMetrics>(); - metrics_data->handle_input_events = + metrics_data->handle_input_events = base::TimeDelta::FromMicroseconds( absolute_metric_records_[static_cast<unsigned>( MetricId::kHandleInputEvents)] - .main_frame_duration; - metrics_data->animate = + .main_frame_count); + metrics_data->animate = base::TimeDelta::FromMicroseconds( absolute_metric_records_[static_cast<unsigned>(MetricId::kAnimate)] - .main_frame_duration; - metrics_data->style_update = + .main_frame_count); + metrics_data->style_update = base::TimeDelta::FromMicroseconds( absolute_metric_records_[static_cast<unsigned>(MetricId::kStyle)] - .main_frame_duration; - metrics_data->layout_update = + .main_frame_count); + metrics_data->layout_update = base::TimeDelta::FromMicroseconds( absolute_metric_records_[static_cast<unsigned>(MetricId::kLayout)] - .main_frame_duration; - metrics_data->prepaint = + .main_frame_count); + metrics_data->prepaint = base::TimeDelta::FromMicroseconds( absolute_metric_records_[static_cast<unsigned>(MetricId::kPrePaint)] - .main_frame_duration; - metrics_data->compositing_assignments = + .main_frame_count); + metrics_data->compositing_assignments = base::TimeDelta::FromMicroseconds( absolute_metric_records_[static_cast<unsigned>( MetricId::kCompositingAssignments)] - .main_frame_duration; - metrics_data->compositing_inputs = + .main_frame_count); + metrics_data->compositing_inputs = base::TimeDelta::FromMicroseconds( absolute_metric_records_[static_cast<unsigned>( MetricId::kCompositingInputs)] - .main_frame_duration; - metrics_data->paint = + .main_frame_count); + metrics_data->paint = base::TimeDelta::FromMicroseconds( absolute_metric_records_[static_cast<unsigned>(MetricId::kPaint)] - .main_frame_duration; - metrics_data->composite_commit = + .main_frame_count); + metrics_data->composite_commit = base::TimeDelta::FromMicroseconds( absolute_metric_records_[static_cast<unsigned>( MetricId::kCompositingCommit)] - .main_frame_duration; + .main_frame_count); metrics_data->should_measure_smoothness = (fcp_state_ >= kThisFrameReachedFCP); return metrics_data; @@ -197,34 +206,37 @@ fcp_state_ = kThisFrameReachedFCP; } -void LocalFrameUkmAggregator::RecordSample(size_t metric_index, - base::TimeTicks start, - base::TimeTicks end) { +void LocalFrameUkmAggregator::RecordTimerSample(size_t metric_index, + base::TimeTicks start, + base::TimeTicks end) { + RecordCountSample(metric_index, (end - start).InMicroseconds()); +} + +void LocalFrameUkmAggregator::RecordCountSample(size_t metric_index, + int64_t count) { // Always use RecordForcedLayoutSample for the kForcedStyleAndLayout // metric id. DCHECK_NE(metric_index, static_cast<size_t>(kForcedStyleAndLayout)); - base::TimeDelta duration = end - start; bool is_pre_fcp = (fcp_state_ != kHavePassedFCP); // Accumulate for UKM and record the UMA DCHECK_LT(metric_index, base::size(absolute_metric_records_)); auto& record = absolute_metric_records_[metric_index]; - record.interval_duration += duration; + record.interval_count += count; if (in_main_frame_update_) - record.main_frame_duration += duration; + record.main_frame_count += count; if (is_pre_fcp) - record.pre_fcp_aggregate += duration; + record.pre_fcp_aggregate += count; // Record the UMA // ForcedStyleAndLayout happen so frequently on some pages that we overflow // the signed 32 counter for number of events in a 30 minute period. So // randomly record with probability 1/100. if (record.pre_fcp_uma_counter) { - if (is_pre_fcp) { - record.pre_fcp_uma_counter->CountMicroseconds(duration); - } else { - record.post_fcp_uma_counter->CountMicroseconds(duration); - } + if (is_pre_fcp) + record.pre_fcp_uma_counter->Count(ToSample(count)); + else + record.post_fcp_uma_counter->Count(ToSample(count)); } } @@ -232,7 +244,7 @@ DocumentUpdateReason reason, base::TimeTicks start, base::TimeTicks end) { - base::TimeDelta duration = end - start; + int64_t count = (end - start).InMicroseconds(); bool is_pre_fcp = (fcp_state_ != kHavePassedFCP); // Accumulate for UKM always, but only record the UMA for a subset of cases to @@ -248,17 +260,17 @@ auto& record = absolute_metric_records_[static_cast<size_t>(kForcedStyleAndLayout)]; - record.interval_duration += duration; + record.interval_count += count; if (in_main_frame_update_) - record.main_frame_duration += duration; + record.main_frame_count += count; if (is_pre_fcp) - record.pre_fcp_aggregate += duration; + record.pre_fcp_aggregate += count; if (should_report_uma_this_frame) { if (is_pre_fcp) - record.pre_fcp_uma_counter->CountMicroseconds(duration); + record.pre_fcp_uma_counter->Count(ToSample(count)); else - record.post_fcp_uma_counter->CountMicroseconds(duration); + record.post_fcp_uma_counter->Count(ToSample(count)); } // Record a variety of DocumentUpdateReasons as distinct metrics @@ -322,16 +334,16 @@ if (sub_metric != kCount) { auto& sub_record = absolute_metric_records_[static_cast<size_t>(sub_metric)]; - sub_record.interval_duration += duration; + sub_record.interval_count += count; if (in_main_frame_update_) - sub_record.main_frame_duration += duration; + sub_record.main_frame_count += count; if (is_pre_fcp) - sub_record.pre_fcp_aggregate += duration; + sub_record.pre_fcp_aggregate += count; if (should_report_uma_this_frame) { if (is_pre_fcp) - sub_record.pre_fcp_uma_counter->CountMicroseconds(duration); + sub_record.pre_fcp_uma_counter->Count(ToSample(count)); else - sub_record.post_fcp_uma_counter->CountMicroseconds(duration); + sub_record.post_fcp_uma_counter->Count(ToSample(count)); } } } @@ -348,10 +360,10 @@ // all time to the compositor commit so as to not imply that wait time was // consumed. if (started == base::TimeTicks()) { - RecordSample(kImplCompositorCommit, requested, completed); + RecordTimerSample(kImplCompositorCommit, requested, completed); } else { - RecordSample(kWaitForCommit, requested, started); - RecordSample(kImplCompositorCommit, started, completed); + RecordTimerSample(kWaitForCommit, requested, started); + RecordTimerSample(kImplCompositorCommit, started, completed); } } @@ -359,14 +371,14 @@ base::TimeTicks start, base::TimeTicks end, cc::ActiveFrameSequenceTrackers trackers) { - const base::TimeDelta duration = end - start; + const int64_t count = (end - start).InMicroseconds(); const bool have_valid_metrics = // Any of the early outs in LocalFrameView::UpdateLifecyclePhases() will // mean we are not in a main frame update. Recording is triggered higher // in the stack, so we cannot know to avoid calling this method. in_main_frame_update_ && // In tests it's possible to reach here with zero duration. - (duration > base::TimeDelta()); + (count > 0); in_main_frame_update_ = false; if (!have_valid_metrics) { @@ -381,14 +393,14 @@ // Record UMA if (report_as_pre_fcp) - primary_metric_.pre_fcp_uma_counter->CountMicroseconds(duration); + primary_metric_.pre_fcp_uma_counter->Count(ToSample(count)); else - primary_metric_.post_fcp_uma_counter->CountMicroseconds(duration); + primary_metric_.post_fcp_uma_counter->Count(ToSample(count)); // Record primary time information - primary_metric_.interval_duration = duration; + primary_metric_.interval_count = count; if (report_as_pre_fcp) - primary_metric_.pre_fcp_aggregate += duration; + primary_metric_.pre_fcp_aggregate += count; UpdateEventTimeAndUpdateSampleIfNeeded(trackers); @@ -430,31 +442,31 @@ void LocalFrameUkmAggregator::UpdateSample( cc::ActiveFrameSequenceTrackers trackers) { - current_sample_.primary_metric_duration = primary_metric_.interval_duration; + current_sample_.primary_metric_count = primary_metric_.interval_count; for (size_t i = 0; i < metrics_data().size(); ++i) { - current_sample_.sub_metrics_durations[i] = - absolute_metric_records_[i].interval_duration; - current_sample_.sub_main_frame_durations[i] = - absolute_metric_records_[i].main_frame_duration; + current_sample_.sub_metrics_counts[i] = + absolute_metric_records_[i].interval_count; + current_sample_.sub_main_frame_counts[i] = + absolute_metric_records_[i].main_frame_count; } current_sample_.trackers = trackers; } void LocalFrameUkmAggregator::ReportPreFCPEvent() { -#define CASE_FOR_ID(name) \ - case k##name: \ - builder.Set##name(absolute_record.pre_fcp_aggregate.InMicroseconds()); \ +#define CASE_FOR_ID(name) \ + case k##name: \ + builder.Set##name(ToSample(absolute_record.pre_fcp_aggregate)); \ break ukm::builders::Blink_PageLoad builder(source_id_); - builder.SetMainFrame(primary_metric_.pre_fcp_aggregate.InMicroseconds()); - primary_metric_.uma_aggregate_counter->CountMicroseconds( - primary_metric_.pre_fcp_aggregate); + builder.SetMainFrame(primary_metric_.pre_fcp_aggregate); + primary_metric_.uma_aggregate_counter->Count( + ToSample(primary_metric_.pre_fcp_aggregate)); for (size_t i = 0; i < metrics_data().size(); ++i) { auto& absolute_record = absolute_metric_records_[i]; if (absolute_record.uma_aggregate_counter) { - absolute_record.uma_aggregate_counter->CountMicroseconds( - absolute_record.pre_fcp_aggregate); + absolute_record.uma_aggregate_counter->Count( + ToSample(absolute_record.pre_fcp_aggregate)); } switch (static_cast<MetricId>(i)) { @@ -499,18 +511,15 @@ if (!frames_since_last_report_) return; -#define CASE_FOR_ID(name, index) \ - case k##name: \ - builder \ - .Set##name( \ - current_sample_.sub_metrics_durations[index].InMicroseconds()) \ - .Set##name##BeginMainFrame( \ - current_sample_.sub_main_frame_durations[index].InMicroseconds()); \ +#define CASE_FOR_ID(name, index) \ + case k##name: \ + builder.Set##name(current_sample_.sub_metrics_counts[index]) \ + .Set##name##BeginMainFrame( \ + current_sample_.sub_main_frame_counts[index]); \ break ukm::builders::Blink_UpdateTime builder(source_id_); - builder.SetMainFrame( - current_sample_.primary_metric_duration.InMicroseconds()); + builder.SetMainFrame(current_sample_.primary_metric_count); builder.SetMainFrameIsBeforeFCP(fcp_state_ != kHavePassedFCP); builder.SetMainFrameReasons(current_sample_.trackers); for (size_t i = 0; i < metrics_data().size(); ++i) { @@ -561,13 +570,13 @@ } bool LocalFrameUkmAggregator::AllMetricsAreZero() { - if (!primary_metric_.interval_duration.is_zero()) + if (primary_metric_.interval_count != 0) return false; for (auto& record : absolute_metric_records_) { - if (!record.interval_duration.is_zero()) { + if (record.interval_count != 0) { return false; } - if (!record.main_frame_duration.is_zero()) { + if (record.main_frame_count != 0) { return false; } }
diff --git a/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h b/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h index 569e6a7..c470b02 100644 --- a/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h +++ b/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h
@@ -242,9 +242,12 @@ // Record a sample for a sub-metric. This should only be used when // a ScopedUkmHierarchicalTimer cannot be used (such as when the timed // interval does not fall inside a single calling function). - void RecordSample(size_t metric_index, - base::TimeTicks start, - base::TimeTicks end); + void RecordTimerSample(size_t metric_index, + base::TimeTicks start, + base::TimeTicks end); + + // Record a sample for a count-based sub-metric. + void RecordCountSample(size_t metric_index, int64_t count); // Record a ForcedLayout sample. The reason will determine which, if any, // additional metrics are reported in order to diagnose the cause of @@ -287,22 +290,22 @@ // Accumulated at each sample, then reset with a call to // RecordEndOfFrameMetrics. - base::TimeDelta interval_duration; + int64_t interval_count = 0; // Accumulated at each sample when within a BeginMainFrame, // reset with a call to RecordEndOfFrameMetrics. - base::TimeDelta main_frame_duration; + int64_t main_frame_count = 0; // Accumulated at each sample up to the time of First Contentful Paint. - base::TimeDelta pre_fcp_aggregate; + int64_t pre_fcp_aggregate = 0; void reset(); }; struct SampleToRecord { - base::TimeDelta primary_metric_duration; - std::array<base::TimeDelta, kCount> sub_metrics_durations; - std::array<base::TimeDelta, kCount> sub_main_frame_durations; + int64_t primary_metric_count; + std::array<int64_t, kCount> sub_metrics_counts; + std::array<int64_t, kCount> sub_main_frame_counts; cc::ActiveFrameSequenceTrackers trackers; };
diff --git a/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator_test.cc b/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator_test.cc index b02feae..8886107 100644 --- a/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator_test.cc +++ b/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator_test.cc
@@ -204,9 +204,8 @@ } bool SampleMatchesIteration(int64_t iteration_count) { - return aggregator() - .current_sample_.sub_metrics_durations[0] - .InMilliseconds() == iteration_count; + return aggregator().current_sample_.sub_metrics_counts[0] / 1000 == + iteration_count; } private:
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc index b224b2b..c9a7622 100644 --- a/third_party/blink/renderer/core/frame/local_frame_view.cc +++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -2332,7 +2332,7 @@ // in preparation for a hit test. if (reason == DocumentUpdateReason::kHitTest) { LocalFrameUkmAggregator& aggregator = EnsureUkmAggregator(); - aggregator.RecordSample( + aggregator.RecordTimerSample( static_cast<size_t>(LocalFrameUkmAggregator::kHitTestDocumentUpdate), lifecycle_data_.start_time, base::TimeTicks::Now()); } @@ -2841,6 +2841,12 @@ auto* layout_view = GetLayoutView(); DCHECK(layout_view); + + if (RuntimeEnabledFeatures::CullRectUpdateEnabled() && + !ShouldThrottleRendering()) { + CullRectUpdater(*layout_view->Layer()).Update(); + } + paint_frame_count_++; ForAllNonThrottledLocalFrameViews( [](LocalFrameView& frame_view) {
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc index fab478e9..6814fdb 100644 --- a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc +++ b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
@@ -2081,9 +2081,13 @@ void WebFrameWidgetImpl::RecordDispatchRafAlignedInputTime( base::TimeTicks raf_aligned_input_start_time) { if (LocalRootImpl()) { - LocalRootImpl()->GetFrame()->View()->EnsureUkmAggregator().RecordSample( - LocalFrameUkmAggregator::kHandleInputEvents, - raf_aligned_input_start_time, base::TimeTicks::Now()); + LocalRootImpl() + ->GetFrame() + ->View() + ->EnsureUkmAggregator() + .RecordTimerSample(LocalFrameUkmAggregator::kHandleInputEvents, + raf_aligned_input_start_time, + base::TimeTicks::Now()); } } @@ -2171,9 +2175,13 @@ void WebFrameWidgetImpl::EndUpdateLayers() { if (LocalRootImpl()) { DCHECK(update_layers_start_time_); - LocalRootImpl()->GetFrame()->View()->EnsureUkmAggregator().RecordSample( - LocalFrameUkmAggregator::kUpdateLayers, - update_layers_start_time_.value(), base::TimeTicks::Now()); + LocalRootImpl() + ->GetFrame() + ->View() + ->EnsureUkmAggregator() + .RecordTimerSample(LocalFrameUkmAggregator::kUpdateLayers, + update_layers_start_time_.value(), + base::TimeTicks::Now()); probe::LayerTreeDidChange(LocalRootImpl()->GetFrame()); } update_layers_start_time_.reset();
diff --git a/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.cc index c541017..3fe144a3 100644 --- a/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.cc
@@ -1081,7 +1081,7 @@ LayoutUnit intrinsic_block_size = BorderScrollbarPadding().BlockSum(); if (algorithm_.FlexLines().IsEmpty() && Node().HasLineIfEmpty()) { - intrinsic_block_size += Node().GetLayoutBox()->LogicalHeightForEmptyLine(); + intrinsic_block_size += Node().EmptyLineBlockSize(); } else { intrinsic_block_size += algorithm_.IntrinsicContentBlockSize(); }
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc index 22f40ba..06379cd7 100644 --- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc
@@ -190,6 +190,14 @@ grid_geometry.row_geometry.FinalGutterSize() + BorderScrollbarPadding().block_end; + // TODO(layout-dev): This isn't great but matches legacy. Ideally this would + // only apply when we have only flexible track(s). + if (grid_items.IsEmpty() && Node().HasLineIfEmpty()) { + intrinsic_block_size = + std::max(intrinsic_block_size, BorderScrollbarPadding().BlockSum() + + Node().EmptyLineBlockSize()); + } + // TODO(layout-dev): ClampIntrinsicBlockSize might not be correct for grid. // Specifically do we need to run the sizing algorithm assuming no children // for size containment.
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc index 1c50430..d30a8cf1 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
@@ -762,8 +762,7 @@ if (container_builder_.HasSeenAllChildren() && HasLineEvenIfEmpty(Node().GetLayoutBox())) { intrinsic_block_size_ += - std::max(intrinsic_block_size_, - Node().GetLayoutBox()->LogicalHeightForEmptyLine()); + std::max(intrinsic_block_size_, Node().EmptyLineBlockSize()); if (container_builder_.IsInitialColumnBalancingPass()) { container_builder_.PropagateTallestUnbreakableBlockSize( intrinsic_block_size_);
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc index 1f4715c..ebe2899 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
@@ -415,8 +415,7 @@ // We may have to update the margins on box_; we reuse the layout result // even if a percentage margin may have changed. - if (UNLIKELY(Style().MayHaveMargin() && !constraint_space.IsTableCell())) - box_->SetMargin(ComputePhysicalMargins(constraint_space, Style())); + UpdateMarginPaddingInfoIfNeeded(constraint_space); UpdateShapeOutsideInfoIfNeeded( *layout_result, constraint_space.PercentageResolutionInlineSize()); @@ -1110,21 +1109,7 @@ // TODO(mstensho): This should always be done by the parent algorithm, since // we may have auto margins, which only the parent is able to resolve. Remove // the following line when all layout modes do this properly. - if (UNLIKELY(box_->IsTableCell())) { - // Table-cell margins compute to zero. - box_->SetMargin(NGPhysicalBoxStrut()); - } else { - box_->SetMargin(ComputePhysicalMargins(constraint_space, Style())); - } - - // We copy back the %-size so that |LayoutBoxModelObject::ComputedCSSPadding| - // is able to return the correct value. This isn't ideal, but eventually - // we'll answer these queries from the fragment. - const auto* containing_block = box_->ContainingBlock(); - if (UNLIKELY(containing_block && containing_block->IsLayoutNGGrid())) { - box_->SetOverrideContainingBlockContentLogicalWidth( - constraint_space.PercentageResolutionInlineSizeForParentWritingMode()); - } + UpdateMarginPaddingInfoIfNeeded(constraint_space); auto* block_flow = DynamicTo<LayoutBlockFlow>(box_); LayoutMultiColumnFlowThread* flow_thread = GetFlowThread(block_flow); @@ -1830,7 +1815,28 @@ return box_->InlineBlockBaseline(line_direction); } -// Floats can optionally have a shape area, specifed by "shape-outside". The +void NGBlockNode::UpdateMarginPaddingInfoIfNeeded( + const NGConstraintSpace& space) const { + // Table-cells don't have margins, and aren't grid-items. + if (space.IsTableCell()) + return; + + if (Style().MayHaveMargin()) + box_->SetMargin(ComputePhysicalMargins(space, Style())); + + if (Style().MayHaveMargin() || Style().MayHavePadding()) { + // Copy back the %-size so that |LayoutBoxModelObject::ComputedCSSPadding| + // is able to return the correct value. This isn't ideal, but eventually + // we'll answer these queries from the fragment. + const auto* containing_block = box_->ContainingBlock(); + if (UNLIKELY(containing_block && containing_block->IsLayoutNGGrid())) { + box_->SetOverrideContainingBlockContentLogicalWidth( + space.PercentageResolutionInlineSizeForParentWritingMode()); + } + } +} + +// Floats can optionally have a shape area, specified by "shape-outside". The // current shape machinery requires setting the size of the float after layout // in the parents writing mode. void NGBlockNode::UpdateShapeOutsideInfoIfNeeded(
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_node.h b/third_party/blink/renderer/core/layout/ng/ng_block_node.h index 3cdc13d5..6711e82e 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_block_node.h +++ b/third_party/blink/renderer/core/layout/ng/ng_block_node.h
@@ -203,6 +203,9 @@ return block->HasLineIfEmpty(); return false; } + LayoutUnit EmptyLineBlockSize() const { + return box_->LogicalHeightForEmptyLine(); + } // After we run the layout algorithm, this function copies back the fragment // position to the layout box. @@ -257,6 +260,8 @@ LayoutUnit AtomicInlineBaselineFromLegacyLayout( const NGConstraintSpace&) const; + void UpdateMarginPaddingInfoIfNeeded(const NGConstraintSpace&) const; + void UpdateShapeOutsideInfoIfNeeded( const NGLayoutResult&, LayoutUnit percentage_resolution_inline_size) const;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc index f99ab56..a18e07ab 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
@@ -903,7 +903,7 @@ NGBoxStrut scrollbars_before = ComputeScrollbarsForNonAnonymous(node_info.node); scoped_refptr<const NGLayoutResult> layout_result = - Layout(oof_node_to_layout, fragmentainer_constraint_space); + Layout(oof_node_to_layout, offset_info, fragmentainer_constraint_space); NGBoxStrut scrollbars_after = ComputeScrollbarsForNonAnonymous(node_info.node); @@ -934,9 +934,8 @@ // so recompute the OffsetInfo. offset_info = CalculateOffset(node_info, only_layout, /* is_first_run */ false); - - layout_result = - Layout(oof_node_to_layout, fragmentainer_constraint_space); + layout_result = Layout(oof_node_to_layout, offset_info, + fragmentainer_constraint_space); scrollbars_after = ComputeScrollbarsForNonAnonymous(node_info.node); DCHECK(!freeze_horizontal || !freeze_vertical || @@ -1037,9 +1036,9 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::Layout( const NodeToLayout& oof_node_to_layout, + const OffsetInfo& offset_info, const NGConstraintSpace* fragmentainer_constraint_space) { const NodeInfo& node_info = oof_node_to_layout.node_info; - const OffsetInfo& offset_info = oof_node_to_layout.offset_info; const WritingDirectionMode candidate_writing_direction = node_info.node.Style().GetWritingDirection(); LogicalSize container_content_size_in_candidate_writing_mode =
diff --git a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h index 7aebd00..c332a3c 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h +++ b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h
@@ -222,6 +222,7 @@ scoped_refptr<const NGLayoutResult> Layout( const NodeToLayout& oof_node_to_layout, + const OffsetInfo& offset_info, const NGConstraintSpace* fragmentainer_constraint_space); bool IsContainingBlockForCandidate(const NGLogicalOutOfFlowPositionedNode&);
diff --git a/third_party/blink/renderer/core/loader/document_loader.cc b/third_party/blink/renderer/core/loader/document_loader.cc index 43ba55c7..6f87db4 100644 --- a/third_party/blink/renderer/core/loader/document_loader.cc +++ b/third_party/blink/renderer/core/loader/document_loader.cc
@@ -2168,9 +2168,6 @@ // // Use response_.AddressSpace() instead of frame_->DomWindow()->AddressSpace() // since the latter isn't populated in unit tests. - // - // TODO(crbug.com/1171214): move RecordAddressSpaceFeature() call from - // StartLoadingInternal to here. if (frame_->IsMainFrame()) { auto address_space = response_.AddressSpace(); if ((address_space == network::mojom::blink::IPAddressSpace::kPrivate ||
diff --git a/third_party/blink/renderer/core/paint/cull_rect_updater.cc b/third_party/blink/renderer/core/paint/cull_rect_updater.cc index eff7798..dc63743 100644 --- a/third_party/blink/renderer/core/paint/cull_rect_updater.cc +++ b/third_party/blink/renderer/core/paint/cull_rect_updater.cc
@@ -288,7 +288,7 @@ !root_layer.NeedsCullRectUpdate() && !root_layer.DescendantNeedsCullRectUpdate() && cull_rect == root_layer.GetLayoutObject().FirstFragment().GetCullRect()) { - // The cull rects calculated during PrePaint are good. + // The current cull rects are good. return; }
diff --git a/third_party/blink/renderer/core/paint/paint_controller_paint_test.h b/third_party/blink/renderer/core/paint/paint_controller_paint_test.h index 07713df9..2602df7 100644 --- a/third_party/blink/renderer/core/paint/paint_controller_paint_test.h +++ b/third_party/blink/renderer/core/paint/paint_controller_paint_test.h
@@ -8,6 +8,7 @@ #include "third_party/blink/renderer/core/editing/frame_selection.h" #include "third_party/blink/renderer/core/frame/local_frame_view.h" #include "third_party/blink/renderer/core/layout/layout_view.h" +#include "third_party/blink/renderer/core/paint/cull_rect_updater.h" #include "third_party/blink/renderer/core/paint/paint_layer.h" #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h" #include "third_party/blink/renderer/core/testing/core_unit_test_helper.h" @@ -49,6 +50,10 @@ void UpdateAllLifecyclePhasesExceptPaint() { GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint( DocumentUpdateReason::kTest); + // Run CullRectUpdater to ease testing of cull rects and repaint flags of + // PaintLayers on cull rect change. + if (RuntimeEnabledFeatures::CullRectUpdateEnabled()) + CullRectUpdater(*GetLayoutView().Layer()).Update(); } void PaintContents(const IntRect& interest_rect) {
diff --git a/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc b/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc index 08626f3..97e3958 100644 --- a/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc +++ b/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
@@ -28,7 +28,6 @@ #include "third_party/blink/renderer/core/page/page.h" #include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h" #include "third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h" -#include "third_party/blink/renderer/core/paint/cull_rect_updater.h" #include "third_party/blink/renderer/core/paint/paint_layer.h" #include "third_party/blink/renderer/core/paint/paint_property_tree_printer.h" #include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h" @@ -206,11 +205,6 @@ Walk(root_frame_view, context); paint_invalidator_.ProcessPendingDelayedPaintInvalidations(); - if (RuntimeEnabledFeatures::CullRectUpdateEnabled()) { - if (auto* layout_view = root_frame_view.GetLayoutView()) - CullRectUpdater(*layout_view->Layer()).Update(); - } - #if DCHECK_IS_ON() if (needs_tree_builder_context_update) { if (VLOG_IS_ON(2) && root_frame_view.GetLayoutView()) {
diff --git a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc index c8803095..b2d1e4a 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
@@ -624,7 +624,8 @@ DCHECK(!GetLayoutObject()); if (DisplayLockUtilities::NearestLockedExclusiveAncestor(*GetNode())) { - if (DisplayLockUtilities::ShouldIgnoreNodeDueToDisplayLock( + if (IsAriaHidden() || + DisplayLockUtilities::ShouldIgnoreNodeDueToDisplayLock( *GetNode(), DisplayLockActivationReason::kAccessibility)) { if (ignored_reasons) ignored_reasons->push_back(IgnoredReason(kAXNotRendered));
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object.cc b/third_party/blink/renderer/modules/accessibility/ax_object.cc index ce35c04..a8e4445b 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_object.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_object.cc
@@ -2930,6 +2930,7 @@ if (!node) return false; + // content-visibility:hidden or content-visibility: auto. if (DisplayLockUtilities::NearestLockedExclusiveAncestor(*node)) { // Ensure contents of head, style and script are never exposed. // Note: an AXObject is created for <title> to gather the document's name. @@ -2941,6 +2942,8 @@ DCHECK(!Traversal<HTMLScriptElement>::FirstAncestorOrSelf(*node)) << node; // content-visibility: hidden subtrees are always hidden. + // content-visibility: auto subtrees are treated as visible, as we must + // make a guess since computed style is not available. return DisplayLockUtilities::ShouldIgnoreNodeDueToDisplayLock( *node, DisplayLockActivationReason::kAccessibility); }
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_playback_speed_list_element.cc b/third_party/blink/renderer/modules/media_controls/elements/media_control_playback_speed_list_element.cc index 435855b..d6afb38 100644 --- a/third_party/blink/renderer/modules/media_controls/elements/media_control_playback_speed_list_element.cc +++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_playback_speed_list_element.cc
@@ -5,8 +5,11 @@ #include "third_party/blink/renderer/modules/media_controls/elements/media_control_playback_speed_list_element.h" #include "third_party/blink/public/strings/grit/blink_strings.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_scroll_into_view_options.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_union_boolean_scrollintoviewoptions.h" #include "third_party/blink/renderer/core/dom/events/event.h" #include "third_party/blink/renderer/core/dom/events/event_dispatch_forbidden_scope.h" +#include "third_party/blink/renderer/core/dom/frame_request_callback_collection.h" #include "third_party/blink/renderer/core/dom/text.h" #include "third_party/blink/renderer/core/html/forms/html_input_element.h" #include "third_party/blink/renderer/core/html/forms/html_label_element.h" @@ -45,6 +48,28 @@ } // anonymous namespace +class MediaControlPlaybackSpeedListElement::RequestAnimationFrameCallback final + : public FrameCallback { + public: + explicit RequestAnimationFrameCallback( + MediaControlPlaybackSpeedListElement* list) + : list_(list) {} + + RequestAnimationFrameCallback(const RequestAnimationFrameCallback&) = delete; + RequestAnimationFrameCallback& operator=( + const RequestAnimationFrameCallback&) = delete; + + void Invoke(double) override { list_->CenterCheckedItem(); } + + void Trace(Visitor* visitor) const override { + visitor->Trace(list_); + FrameCallback::Trace(visitor); + } + + private: + Member<MediaControlPlaybackSpeedListElement> list_; +}; + MediaControlPlaybackSpeedListElement::MediaControlPlaybackSpeedListElement( MediaControlsImpl& media_controls) : MediaControlPopupMenuElement(media_controls) { @@ -111,6 +136,7 @@ if (playback_rate == MediaElement().playbackRate()) { playback_speed_item_input->setChecked(true); playback_speed_item->setAttribute(html_names::kAriaCheckedAttr, "true"); + checked_item_ = playback_speed_item; } // Allows to focus the list entry instead of the button. playback_speed_item->setTabIndex(0); @@ -154,6 +180,8 @@ ParserAppendChild(CreatePlaybackSpeedHeaderItem()); + checked_item_ = nullptr; + // Construct a menu for playback speeds. for (unsigned i = 0; i < base::size(kPlaybackSpeeds); i++) { auto& playback_speed = kPlaybackSpeeds[i]; @@ -168,6 +196,24 @@ "menuitemcheckbox"); ParserAppendChild(playback_speed_item); } + RequestAnimationFrameCallback* callback = + MakeGarbageCollected<RequestAnimationFrameCallback>(this); + GetDocument().RequestAnimationFrame(callback); +} + +void MediaControlPlaybackSpeedListElement::CenterCheckedItem() { + if (!checked_item_) + return; + ScrollIntoViewOptions* options = ScrollIntoViewOptions::Create(); + options->setBlock("center"); + auto* arg = + MakeGarbageCollected<V8UnionBooleanOrScrollIntoViewOptions>(options); + checked_item_->scrollIntoView(arg); +} + +void MediaControlPlaybackSpeedListElement::Trace(Visitor* visitor) const { + visitor->Trace(checked_item_); + MediaControlPopupMenuElement::Trace(visitor); } } // namespace blink
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_playback_speed_list_element.h b/third_party/blink/renderer/modules/media_controls/elements/media_control_playback_speed_list_element.h index ff76bcf..a7eaf46 100644 --- a/third_party/blink/renderer/modules/media_controls/elements/media_control_playback_speed_list_element.h +++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_playback_speed_list_element.h
@@ -22,7 +22,11 @@ void SetIsWanted(bool) final; + void Trace(Visitor*) const override; + private: + class RequestAnimationFrameCallback; + void DefaultEventHandler(Event&) override; void RefreshPlaybackSpeedListMenu(); @@ -33,6 +37,11 @@ // Creates the header element of the playback speed list. Element* CreatePlaybackSpeedHeaderItem(); + + // Centers vertically the checked item in the playback speed list. + void CenterCheckedItem(); + + Member<Element> checked_item_; }; } // namespace blink
diff --git a/third_party/blink/renderer/modules/webcodecs/codec_logger.cc b/third_party/blink/renderer/modules/webcodecs/codec_logger.cc index 94a44c0d..257f84f 100644 --- a/third_party/blink/renderer/modules/webcodecs/codec_logger.cc +++ b/third_party/blink/renderer/modules/webcodecs/codec_logger.cc
@@ -10,6 +10,7 @@ #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" #include "third_party/blink/renderer/core/inspector/inspector_media_context_impl.h" +#include "third_party/blink/renderer/platform/wtf/wtf.h" namespace blink { @@ -25,7 +26,8 @@ // collected before |parent_media_log_| is destroyed. if (!context->IsContextDestroyed()) { parent_media_log_ = Platform::Current()->GetMediaLog( - MediaInspectorContextImpl::From(*context), task_runner); + MediaInspectorContextImpl::From(*context), task_runner, + /*is_on_worker=*/!IsMainThread()); } // NullMediaLog silently and safely does nothing. @@ -37,10 +39,6 @@ media_log_ = parent_media_log_->Clone(); } -CodecLogger::CodecLogger() - : parent_media_log_(std::make_unique<media::NullMediaLog>()), - media_log_(parent_media_log_->Clone()) {} - DOMException* CodecLogger::MakeException(std::string error_msg, media::Status status) { media_log_->NotifyError(status);
diff --git a/third_party/blink/renderer/modules/webcodecs/codec_logger.h b/third_party/blink/renderer/modules/webcodecs/codec_logger.h index 80bb6f6..0329c6e 100644 --- a/third_party/blink/renderer/modules/webcodecs/codec_logger.h +++ b/third_party/blink/renderer/modules/webcodecs/codec_logger.h
@@ -30,9 +30,6 @@ // call Neuter() if the ExecutionContext passed to the constructor is destroyed. class MODULES_EXPORT CodecLogger final { public: - // Creates a CodecLogger backed by a NullMediaLog, which does nothing. - CodecLogger(); - // Attempts to create CodecLogger backed by a BatchingMediaLog. Falls back to // a NullMediaLog on failure. CodecLogger(ExecutionContext*,
diff --git a/third_party/blink/renderer/modules/webcodecs/decoder_template.cc b/third_party/blink/renderer/modules/webcodecs/decoder_template.cc index bfdef322..e4ca1009 100644 --- a/third_party/blink/renderer/modules/webcodecs/decoder_template.cc +++ b/third_party/blink/renderer/modules/webcodecs/decoder_template.cc
@@ -75,14 +75,8 @@ ExecutionContext* context = GetExecutionContext(); DCHECK(context); - // TODO(crbug.com/1151005): Use a real MediaLog in worker contexts too. - if (IsMainThread()) { - logger_ = std::make_unique<CodecLogger>( - context, context->GetTaskRunner(TaskType::kInternalMedia)); - } else { - // This will create a logger backed by a NullMediaLog, which does nothing. - logger_ = std::make_unique<CodecLogger>(); - } + logger_ = std::make_unique<CodecLogger>( + context, context->GetTaskRunner(TaskType::kInternalMedia)); logger_->log()->SetProperty<media::MediaLogProperty::kFrameUrl>( context->Url().GetString().Ascii());
diff --git a/third_party/blink/renderer/modules/webcodecs/encoder_base.cc b/third_party/blink/renderer/modules/webcodecs/encoder_base.cc index f159c05..5bc5fc8f 100644 --- a/third_party/blink/renderer/modules/webcodecs/encoder_base.cc +++ b/third_party/blink/renderer/modules/webcodecs/encoder_base.cc
@@ -43,14 +43,8 @@ : ExecutionContextLifecycleObserver(ExecutionContext::From(script_state)), state_(V8CodecState::Enum::kUnconfigured), script_state_(script_state) { - // TODO(crbug.com/1151005): Use a real MediaLog in worker contexts too. - if (IsMainThread()) { - logger_ = std::make_unique<CodecLogger>( - GetExecutionContext(), Thread::MainThread()->GetTaskRunner()); - } else { - // This will create a logger backed by a NullMediaLog, which does nothing. - logger_ = std::make_unique<CodecLogger>(); - } + logger_ = std::make_unique<CodecLogger>(GetExecutionContext(), + Thread::Current()->GetTaskRunner()); media::MediaLog* log = logger_->log();
diff --git a/third_party/blink/renderer/modules/webcodecs/image_decoder_core.cc b/third_party/blink/renderer/modules/webcodecs/image_decoder_core.cc index 9ede7c13..9a9836f0 100644 --- a/third_party/blink/renderer/modules/webcodecs/image_decoder_core.cc +++ b/third_party/blink/renderer/modules/webcodecs/image_decoder_core.cc
@@ -135,12 +135,18 @@ std::unique_ptr<ImageDecoderCore::ImageDecodeResult> ImageDecoderCore::Decode( uint32_t frame_index, - bool complete_frames_only) { + bool complete_frames_only, + const base::AtomicFlag* abort_flag) { DCHECK(decoder_); auto result = std::make_unique<ImageDecodeResult>(); result->frame_index = frame_index; + if (abort_flag->IsSet()) { + result->status = Status::kAborted; + return result; + } + if (decoder_->Failed()) { result->status = Status::kDecodeError; return result;
diff --git a/third_party/blink/renderer/modules/webcodecs/image_decoder_core.h b/third_party/blink/renderer/modules/webcodecs/image_decoder_core.h index 0d38ad4..fdca0b1 100644 --- a/third_party/blink/renderer/modules/webcodecs/image_decoder_core.h +++ b/third_party/blink/renderer/modules/webcodecs/image_decoder_core.h
@@ -56,6 +56,7 @@ kNoImage, // No new images or no image could currently be decoded. kDecodeError, // ImageDecoder::Failed() became true. kIndexError, // |frame_index| out of range when |data_complete_| is true. + kAborted, // Decode was aborted by caller. }; struct ImageDecodeResult { @@ -76,9 +77,11 @@ }; // Decodes the frame at |frame_index|, returning partial frames relative to - // the last Decode() request if |complete_frames_only| is false. + // the last Decode() request if |complete_frames_only| is false. |abort_flag| + // may be used to cancel decoding; it must outlive this Decode() call. std::unique_ptr<ImageDecodeResult> Decode(uint32_t frame_index, - bool complete_frames_only); + bool complete_frames_only, + const base::AtomicFlag* abort_flag); // Calls ImageDecoder::SetData() after appending |data| to |stream_buffer_|. // May not be called after |data_complete| becomes true.
diff --git a/third_party/blink/renderer/modules/webcodecs/image_decoder_external.cc b/third_party/blink/renderer/modules/webcodecs/image_decoder_external.cc index 8c04c19..1eee849a 100644 --- a/third_party/blink/renderer/modules/webcodecs/image_decoder_external.cc +++ b/third_party/blink/renderer/modules/webcodecs/image_decoder_external.cc
@@ -83,7 +83,13 @@ bool complete_frames_only) : resolver(resolver), frame_index(frame_index), - complete_frames_only(complete_frames_only) {} + complete_frames_only(complete_frames_only), + abort_flag(std::make_unique<base::AtomicFlag>()) {} + +ImageDecoderExternal::DecodeRequest::~DecodeRequest() { + // This must have already been released to the decoder thread manually. + DCHECK(!abort_flag); +} void ImageDecoderExternal::DecodeRequest::Trace(Visitor* visitor) const { visitor->Trace(resolver); @@ -142,7 +148,7 @@ animation_option_ = AnimationOptionFromIsAnimated(*prefer_animation_); } - auto task_runner = base::ThreadPool::CreateSequencedTaskRunner( + decode_task_runner_ = base::ThreadPool::CreateSequencedTaskRunner( {base::TaskPriority::USER_VISIBLE, base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}); @@ -156,8 +162,9 @@ } decoder_ = std::make_unique<WTF::SequenceBound<ImageDecoderCore>>( - task_runner, mime_type_, /*data=*/nullptr, /*data_complete=*/false, - alpha_option, color_behavior, desired_size, animation_option_); + decode_task_runner_, mime_type_, /*data=*/nullptr, + /*data_complete=*/false, alpha_option, color_behavior, desired_size, + animation_option_); consumer_ = MakeGarbageCollected<ReadableStreamBytesConsumer>( script_state, init->data().GetAsReadableStream()); @@ -199,8 +206,9 @@ data_complete_ = true; completed_property_->ResolveWithUndefined(); decoder_ = std::make_unique<WTF::SequenceBound<ImageDecoderCore>>( - task_runner, mime_type_, std::move(segment_reader), data_complete_, - alpha_option, color_behavior, desired_size, animation_option_); + decode_task_runner_, mime_type_, std::move(segment_reader), + data_complete_, alpha_option, color_behavior, desired_size, + animation_option_); DecodeMetadata(); } @@ -300,12 +308,18 @@ num_submitted_decodes_ = 0u; decode_weak_factory_.InvalidateWeakPtrs(); - // Move all state to local variables since promise resolution is reentrant. + // Move all state to local variables since promise resolution is re-entrant. HeapVector<Member<DecodeRequest>> local_pending_decodes; local_pending_decodes.swap(pending_decodes_); - for (auto& request : local_pending_decodes) + for (auto& request : local_pending_decodes) { request->resolver->Reject(exception); + request->abort_flag->Set(); + + // Since the AtomicFlag may still be referenced by the decoder sequence, we + // need to delete it on that sequence. + decode_task_runner_->DeleteSoon(FROM_HERE, std::move(request->abort_flag)); + } } void ImageDecoderExternal::close() { @@ -454,7 +468,8 @@ ++num_submitted_decodes_; decoder_->AsyncCall(&ImageDecoderCore::Decode) - .WithArgs(request->frame_index, request->complete_frames_only) + .WithArgs(request->frame_index, request->complete_frames_only, + WTF::CrossThreadUnretained(request->abort_flag.get())) .Then(CrossThreadBindOnce(&ImageDecoderExternal::OnDecodeReady, decode_weak_factory_.GetWeakPtr())); } @@ -472,6 +487,7 @@ // Note: Promise resolution may invoke calls into this class. for (auto& request : completed_decodes) { + DCHECK(!request->abort_flag->IsSet()); if (request->exception) { request->resolver->Reject(request->exception); } else if (request->range_error_message) { @@ -481,6 +497,10 @@ } else { request->resolver->Resolve(request->result); } + + // Since the AtomicFlag may still be referenced by the decoder sequence, we + // need to delete it on that sequence. + decode_task_runner_->DeleteSoon(FROM_HERE, std::move(request->abort_flag)); } } @@ -501,6 +521,11 @@ } request->pending = false; + + // Abort always invalidates WeakPtrs, so OnDecodeReady() should never receive + // the kAborted status. + DCHECK_NE(result->status, ImageDecoderCore::Status::kAborted); + if (result->status == ImageDecoderCore::Status::kIndexError) { request->range_error_message = ExceptionMessages::IndexOutsideRange<uint32_t>(
diff --git a/third_party/blink/renderer/modules/webcodecs/image_decoder_external.h b/third_party/blink/renderer/modules/webcodecs/image_decoder_external.h index 185d4c0..c47c6c1 100644 --- a/third_party/blink/renderer/modules/webcodecs/image_decoder_external.h +++ b/third_party/blink/renderer/modules/webcodecs/image_decoder_external.h
@@ -126,6 +126,7 @@ int pending_metadata_requests_ = 0; // The workhorse which actually does the decoding. Bound to another sequence. + scoped_refptr<base::SequencedTaskRunner> decode_task_runner_; std::unique_ptr<WTF::SequenceBound<ImageDecoderCore>> decoder_; // List of tracks in this image. Filled in during OnMetadata(). @@ -139,6 +140,7 @@ DecodeRequest(ScriptPromiseResolver* resolver, uint32_t frame_index, bool complete_frames_only); + ~DecodeRequest(); void Trace(Visitor*) const; bool IsFinal() const; @@ -148,6 +150,7 @@ bool pending = false; absl::optional<size_t> bytes_read_index; Member<ImageDecodeResult> result; + std::unique_ptr<base::AtomicFlag> abort_flag; absl::optional<String> range_error_message; Member<DOMException> exception;
diff --git a/third_party/blink/renderer/modules/webcodecs/image_decoder_external_test.cc b/third_party/blink/renderer/modules/webcodecs/image_decoder_external_test.cc index fc3a87b..d752b66 100644 --- a/third_party/blink/renderer/modules/webcodecs/image_decoder_external_test.cc +++ b/third_party/blink/renderer/modules/webcodecs/image_decoder_external_test.cc
@@ -293,6 +293,38 @@ } } +TEST_F(ImageDecoderTest, DecodeAborted) { + V8TestingScope v8_scope; + constexpr char kImageType[] = "image/avif"; + EXPECT_TRUE(IsTypeSupported(&v8_scope, kImageType)); + + // Use an expensive-to-decode image to try and ensure work exists to abort. + auto* decoder = CreateDecoder( + &v8_scope, + "images/resources/avif/red-at-12-oclock-with-color-profile-12bpc.avif", + kImageType); + + ASSERT_TRUE(decoder); + ASSERT_FALSE(v8_scope.GetExceptionState().HadException()); + + { + auto promise = decoder->tracks().ready(v8_scope.GetScriptState()); + ScriptPromiseTester tester(v8_scope.GetScriptState(), promise); + tester.WaitUntilSettled(); + ASSERT_TRUE(tester.IsFulfilled()); + } + + // Setup a scenario where there should be work to abort. Since blink tests use + // real threads with the base::TaskEnvironment, we can't actually be sure that + // work hasn't completed by the time reset() is called. + for (int i = 0; i < 10; ++i) + decoder->decode(); + decoder->reset(); + + // There's no way to verify work was aborted, so just ensure nothing explodes. + base::RunLoop().RunUntilIdle(); +} + TEST_F(ImageDecoderTest, DecoderReset) { V8TestingScope v8_scope; constexpr char kImageType[] = "image/gif";
diff --git a/third_party/blink/renderer/platform/audio/pffft/fft_frame_pffft.cc b/third_party/blink/renderer/platform/audio/pffft/fft_frame_pffft.cc index 410c38a..3317e8a 100644 --- a/third_party/blink/renderer/platform/audio/pffft/fft_frame_pffft.cc +++ b/third_party/blink/renderer/platform/audio/pffft/fft_frame_pffft.cc
@@ -10,6 +10,7 @@ #include "third_party/blink/renderer/platform/audio/hrtf_panner.h" #include "third_party/blink/renderer/platform/audio/vector_math.h" #include "third_party/blink/renderer/platform/wtf/math_extras.h" +#include "third_party/blink/renderer/platform/wtf/threading_primitives.h" #include "third_party/pffft/src/pffft.h" namespace blink { @@ -43,19 +44,46 @@ // we're confident the first call is from the main thread. static bool first_call = true; - if (first_call) { - // Make sure we construct the fft_setups vector below on the main thread. - // Once constructed, we can access it from any thread. - DCHECK(IsMainThread()); - first_call = false; - } - // A HashMap to hold all of the possible FFT setups we need. The setups are // initialized lazily. The key is the fft size, and the value is the setup // data. typedef HashMap<unsigned, std::unique_ptr<FFTSetup>> FFTHashMap_t; - DEFINE_STATIC_LOCAL(FFTHashMap_t, fft_setups, ()); + DEFINE_THREAD_SAFE_STATIC_LOCAL(FFTHashMap_t, fft_setups, ()); + + if (first_call) { + DEFINE_STATIC_LOCAL(Mutex, setup_lock, ()); + + // Make sure we construct the fft_setups vector below on the main thread. + // Once constructed, we can access it from any thread. + DCHECK(IsMainThread()); + first_call = false; + + MutexLocker locker(setup_lock); + + // Initialize the hash map with all the possible keys (FFT sizes), with a + // value of nullptr because we want to initialize the setup data lazily. The + // set of valid FFT sizes for PFFFT are of the form 2^k*3^m*5*n where k >= + // 5, m >= 0, n >= 0. We only go up to a max size of 32768, because we need + // at least an FFT size of 32768 for the convolver node. + + // TODO(crbug.com/988121): Sync this with kMaxFFTPow2Size. + const int kMaxConvolverFFTSize = 32768; + + for (int n = 1; n <= kMaxConvolverFFTSize; n *= 5) { + for (int m = 1; m <= kMaxConvolverFFTSize / n; m *= 3) { + for (int k = 32; k <= kMaxConvolverFFTSize / (n * m); k *= 2) { + int size = k * m * n; + if (size <= kMaxConvolverFFTSize && !fft_setups.Contains(size)) { + fft_setups.insert(size, nullptr); + } + } + } + } + + // There should be 87 entries when we're done. + DCHECK_EQ(fft_setups.size(), 87u); + } return fft_setups; } @@ -63,13 +91,19 @@ void FFTFrame::InitializeFFTSetupForSize(wtf_size_t fft_size) { auto& setup = FFTSetups(); - if (!setup.Contains(fft_size)) { + DCHECK(setup.Contains(fft_size)); + + if (setup.find(fft_size)->value == nullptr) { + DEFINE_STATIC_LOCAL(Mutex, setup_lock, ()); + // Make sure allocation of a new setup only occurs on the main thread so we // don't have a race condition with multiple threads trying to write to the // same element of the vector. DCHECK(IsMainThread()); - setup.insert(fft_size, std::make_unique<FFTSetup>(fft_size)); + auto fft_data = std::make_unique<FFTSetup>(fft_size); + MutexLocker locker(setup_lock); + setup.find(fft_size)->value = std::move(fft_data); } } @@ -77,6 +111,7 @@ auto& setup = FFTSetups(); DCHECK(setup.Contains(fft_size)); + DCHECK(setup.find(fft_size)->value); return setup.find(fft_size)->value->GetSetup(); }
diff --git a/third_party/blink/renderer/platform/image-decoders/jxl/jxl_image_decoder.cc b/third_party/blink/renderer/platform/image-decoders/jxl/jxl_image_decoder.cc index 0a90f61..f9d9e41 100644 --- a/third_party/blink/renderer/platform/image-decoders/jxl/jxl_image_decoder.cc +++ b/third_party/blink/renderer/platform/image-decoders/jxl/jxl_image_decoder.cc
@@ -48,6 +48,81 @@ info_.have_animation = false; } +bool JXLImageDecoder::ReadBytes(size_t remaining, + size_t* offset, + WTF::Vector<uint8_t>* segment, + FastSharedBufferReader* reader, + const uint8_t** jxl_data, + size_t* jxl_size) { + *offset -= remaining; + if (*offset + remaining >= reader->size()) { + segment->clear(); + if (IsAllDataReceived()) { + DVLOG(1) << "need more input but all data received"; + SetFailed(); + return false; + } + // Return because we need more input from the reader, to continue + // decoding in the next call. + return false; + } + const char* buffer = nullptr; + size_t read = reader->GetSomeData(buffer, *offset); + + if (read > remaining) { + // Sufficient data present in the segment from the + // FastSharedBufferReader, no need to copy to segment_. + *jxl_data = reinterpret_cast<const uint8_t*>(buffer); + *jxl_size = read; + *offset += read; + segment->clear(); + } else { + if (segment->size() == remaining) { + // Keep reading from the end of the segment_ we already are + // appending to. The above read is ignored, and start reading after the + // end of the data we already have. + *offset += remaining; + read = 0; + } else { + // segment_->size() could be greater than or smaller than remaining. + // Typically, it'll be smaller than. If it is greater than, then we could + // do something similar as in the segment->size() == remaining case but + // remove the non-remaining bytes from the beginning of the segment_ + // vector. This would avoid re-reading, however the case where + // segment->size() > remaining is rare since normally if the JXL decoder + // returns a positive value for remaining, it will be consistent, making + // the sizes match exactly, so this more complex case is not implemented. + // Clear the segment, the bytes from the GetSomeData above will be + // appended and then we continue reading from the position after the + // above GetSomeData read. + segment->clear(); + } + + for (;;) { + if (read) { + *offset += read; + segment->Append(buffer, read); + } + if (segment->size() > remaining) { + *jxl_data = segment->data(); + *jxl_size = segment->size(); + // Have enough data, break and continue JXL decoding, rather than + // copy more input than needed into segment_. + break; + } + read = reader->GetSomeData(buffer, *offset); + if (read == 0) { + // We tested above that *offset + remaining >= reader.size() so + // should be able to read all data. + DVLOG(1) << "couldn't read all available data"; + SetFailed(); + return false; + } + } + } + return true; +} + void JXLImageDecoder::DecodeImpl(size_t index, bool only_size) { if (Failed()) return; @@ -104,28 +179,22 @@ return; } case JXL_DEC_NEED_MORE_INPUT: { + // The decoder returns how many bytes it has not yet processed, and + // must be included in the next JxlDecoderSetInput call. const size_t remaining = JxlDecoderReleaseInput(dec_.get()); - offset_ -= remaining; - if (offset_ >= reader.size()) { - if (IsAllDataReceived()) { - DVLOG(1) << "need more input but all data received"; - SetFailed(); - return; - } - // Return because we need more input from the reader, to continue - // decoding in the next call. + const uint8_t* jxl_data = nullptr; + size_t jxl_size = 0; + if (!ReadBytes(remaining, &offset_, &segment_, &reader, &jxl_data, + &jxl_size)) { return; } - const char* buffer = nullptr; - size_t read = reader.GetSomeData(buffer, offset_); + if (JXL_DEC_SUCCESS != - JxlDecoderSetInput( - dec_.get(), reinterpret_cast<const uint8_t*>(buffer), read)) { + JxlDecoderSetInput(dec_.get(), jxl_data, jxl_size)) { DVLOG(1) << "JxlDecoderSetInput failed"; SetFailed(); return; } - offset_ += read; break; } case JXL_DEC_BASIC_INFO: { @@ -357,6 +426,7 @@ case JXL_DEC_SUCCESS: { dec_ = nullptr; finished_ = true; + segment_.clear(); return; } default: { @@ -454,26 +524,25 @@ return frame_buffer_cache_.size(); } case JXL_DEC_NEED_MORE_INPUT: { - frame_count_offset_ -= JxlDecoderReleaseInput(frame_count_dec_.get()); - if (frame_count_offset_ >= reader.size()) { - if (IsAllDataReceived()) { - DVLOG(1) << "need more input but all data received"; - SetFailed(); + // The decoder returns how many bytes it has not yet processed, and + // must be included in the next JxlDecoderSetInput call. + const size_t remaining = JxlDecoderReleaseInput(frame_count_dec_.get()); + const uint8_t* jxl_data = nullptr; + size_t jxl_size = 0; + if (!ReadBytes(remaining, &frame_count_offset_, &frame_count_segment_, + &reader, &jxl_data, &jxl_size)) { + if (Failed()) { return frame_buffer_cache_.size(); } return frame_durations_.size(); } - const char* buffer = nullptr; - size_t read = reader.GetSomeData(buffer, frame_count_offset_); + if (JXL_DEC_SUCCESS != - JxlDecoderSetInput(frame_count_dec_.get(), - reinterpret_cast<const uint8_t*>(buffer), - read)) { + JxlDecoderSetInput(frame_count_dec_.get(), jxl_data, jxl_size)) { DVLOG(1) << "JxlDecoderSetInput failed"; SetFailed(); return frame_buffer_cache_.size(); } - frame_count_offset_ += read; break; } case JXL_DEC_FRAME: { @@ -497,6 +566,7 @@ // anymore: we can free the memory. frame_count_dec_ = nullptr; DCHECK(has_full_frame_count_); + frame_count_segment_.clear(); return frame_durations_.size(); } default: {
diff --git a/third_party/blink/renderer/platform/image-decoders/jxl/jxl_image_decoder.h b/third_party/blink/renderer/platform/image-decoders/jxl/jxl_image_decoder.h index 792ece1..3c687c6 100644 --- a/third_party/blink/renderer/platform/image-decoders/jxl/jxl_image_decoder.h +++ b/third_party/blink/renderer/platform/image-decoders/jxl/jxl_image_decoder.h
@@ -78,6 +78,18 @@ int RepetitionCount() const override; bool CanReusePreviousFrameBuffer(size_t) const override { return false; } + // Reads bytes from the segment reader, after releasing input from the JXL + // decoder, which required `remaining` previous bytes to still be available. + // Starts reading from *offset - remaining, and ensures more than remaining + // bytes are read, if possible. Returns false if not enough bytes are + // available or if Failed() was set. + bool ReadBytes(size_t remaining, + size_t* offset, + WTF::Vector<uint8_t>* segment, + FastSharedBufferReader* reader, + const uint8_t** jxl_data, + size_t* jxl_size); + JxlDecoderPtr dec_ = nullptr; size_t offset_ = 0; @@ -101,6 +113,11 @@ bool has_full_frame_count_ = false; size_t size_at_last_frame_count_ = 0; WTF::Vector<float> frame_durations_; + // Multiple concatenated segments from the FastSharedBufferReader, these are + // only used when a single segment did not contain enough data for the JXL + // parser. + WTF::Vector<uint8_t> segment_; + WTF::Vector<uint8_t> frame_count_segment_; }; } // namespace blink
diff --git a/third_party/blink/renderer/platform/image-decoders/jxl/jxl_image_decoder_test.cc b/third_party/blink/renderer/platform/image-decoders/jxl/jxl_image_decoder_test.cc index 9d2c7e7..76404d8 100644 --- a/third_party/blink/renderer/platform/image-decoders/jxl/jxl_image_decoder_test.cc +++ b/third_party/blink/renderer/platform/image-decoders/jxl/jxl_image_decoder_test.cc
@@ -180,6 +180,64 @@ } } +// SegmentReader implementation for testing, which always returns segments +// of size 1. This allows to test whether the decoder handles streaming +// correctly in the most fine-grained case. +class PerByteSegmentReader : public SegmentReader { + public: + PerByteSegmentReader(SharedBuffer& buffer) : buffer_(buffer) {} + size_t size() const override { return buffer_.size(); } + size_t GetSomeData(const char*& data, size_t position) const override { + if (position >= buffer_.size()) { + return 0; + } + data = buffer_.Data() + position; + return 1; + } + sk_sp<SkData> GetAsSkData() const override { return nullptr; } + + private: + SharedBuffer& buffer_; +}; + +// Tests whether the decoder successfully parses the file without errors or +// infinite loop in the worst case of the reader returning 1-byte segments. +void TestSegmented(const char* jxl_file, IntSize expected_size) { + auto decoder = std::make_unique<JXLImageDecoder>( + ImageDecoder::kAlphaNotPremultiplied, ImageDecoder::kDefaultBitDepth, + ColorBehavior::Tag(), ImageDecoder::kNoDecodedImageByteLimit); + scoped_refptr<SharedBuffer> data = ReadFile(jxl_file); + EXPECT_FALSE(data->IsEmpty()); + + scoped_refptr<SegmentReader> reader = + base::AdoptRef(new PerByteSegmentReader(*data.get())); + decoder->SetData(reader, true); + + ImageFrame* frame; + for (;;) { + frame = decoder->DecodeFrameBufferAtIndex(0); + if (decoder->Failed()) + break; + if (frame) + break; + } + + EXPECT_TRUE(decoder->IsSizeAvailable()); + EXPECT_LE(1u, decoder->FrameCount()); + EXPECT_TRUE(!!frame); + EXPECT_EQ(ImageFrame::kFrameComplete, frame->GetStatus()); + EXPECT_FALSE(decoder->Failed()); + EXPECT_EQ(expected_size, decoder->Size()); +} + +TEST(JXLTests, SegmentedTest) { + TestSegmented("/images/resources/jxl/alpha-lossless.jxl", IntSize(2, 10)); + TestSegmented("/images/resources/jxl/3x3_srgb_lossy.jxl", IntSize(3, 3)); + TestSegmented("/images/resources/jxl/pq_gradient_icc_lossy.jxl", + IntSize(16, 16)); + TestSegmented("/images/resources/jxl/animated.jxl", IntSize(16, 16)); +} + TEST(JXLTests, SizeTest) { TestSize("/images/resources/jxl/alpha-lossless.jxl", IntSize(2, 10)); }
diff --git a/third_party/blink/renderer/platform/network/http_parsers.cc b/third_party/blink/renderer/platform/network/http_parsers.cc index 602de86..8f83be6 100644 --- a/third_party/blink/renderer/platform/network/http_parsers.cc +++ b/third_party/blink/renderer/platform/network/http_parsers.cc
@@ -252,7 +252,10 @@ ? absl::make_optional(ConvertToBlink(in->critical_ch.value())) : absl::nullopt, in->xfo, ConvertToBlink(in->link_headers), - ConvertToBlink(in->timing_allow_origin), in->bfcache_opt_in_unload); + ConvertToBlink(in->timing_allow_origin), in->bfcache_opt_in_unload, + in->reporting_endpoints.has_value() + ? absl::make_optional(ConvertToBlink(in->reporting_endpoints.value())) + : absl::nullopt); } } // namespace mojom
diff --git a/third_party/blink/renderer/platform/widget/input/elastic_overscroll_controller.cc b/third_party/blink/renderer/platform/widget/input/elastic_overscroll_controller.cc index 01ad6416..c4c987d 100644 --- a/third_party/blink/renderer/platform/widget/input/elastic_overscroll_controller.cc +++ b/third_party/blink/renderer/platform/widget/input/elastic_overscroll_controller.cc
@@ -58,7 +58,7 @@ std::unique_ptr<ElasticOverscrollController> ElasticOverscrollController::Create(cc::ScrollElasticityHelper* helper) { #if defined(OS_WIN) - return base::FeatureList::IsEnabled(features::kElasticOverscrollWin) + return base::FeatureList::IsEnabled(features::kElasticOverscroll) ? std::make_unique<ElasticOverscrollControllerBezier>(helper) : nullptr; #endif
diff --git a/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py b/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py index 2d10d5fc..2cd58bf4 100644 --- a/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py +++ b/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py
@@ -1014,7 +1014,10 @@ if self.patchset: command.append('--patchset=' + str(self.patchset)) command += tests_to_rebaseline - self.host.executive.run_command(command) + rebaseline_output = self.host.executive.run_command(command) + _log.debug( + "Output of rebaseline-cl:\n%s\n--end of rebaseline-cl output --" % + rebaseline_output) return tests_to_rebaseline, test_results def get_tests_to_rebaseline(self, test_results):
diff --git a/third_party/blink/web_tests/FlagExpectations/enable-features=UseSkiaRenderer b/third_party/blink/web_tests/FlagExpectations/enable-features=UseSkiaRenderer index b3171a1..3a7cb85e 100644 --- a/third_party/blink/web_tests/FlagExpectations/enable-features=UseSkiaRenderer +++ b/third_party/blink/web_tests/FlagExpectations/enable-features=UseSkiaRenderer
@@ -31,6 +31,7 @@ crbug.com/1175758 [ Linux ] media/video-controls-hide-on-move-outside-controls.html [ Failure Pass ] crbug.com/1175758 [ Linux ] virtual/android/fullscreen/model/fully-exit-fullscreen-single.html [ Failure Pass ] [ Linux ] transforms/shadows.html [ Skip ] +crbug.com/1215248 [ Linux ] images/color-profile-mask-image-svg.html [ Failure ] # Flaky on Windows. crbug.com/1026375 [ Win ] media/video-currentTime-delay.html [ Timeout Pass ]
diff --git a/third_party/blink/web_tests/MSANExpectations b/third_party/blink/web_tests/MSANExpectations index e2257cc..ce21327c 100644 --- a/third_party/blink/web_tests/MSANExpectations +++ b/third_party/blink/web_tests/MSANExpectations
@@ -188,4 +188,5 @@ # Sheriff 2021-06-02 crbug.com/1215390 [ Linux ] external/wpt/pointerevents/pointerevent_pointerId_scope.html [ Pass Failure ] -crbug.com/1215530 [ Linux ] external/wpt/html/webappapis/scripting/events/event-handler-attributes-frameset-window.html [ Pass Timeout ] +crbug.com/1215632 [ Linux ] external/wpt/html/webappapis/scripting/events/event-handler-attributes-frameset-window.html [ Pass Timeout ] +crbug.com/1215632 [ Linux ] external/wpt/html/webappapis/scripting/events/event-handler-attributes-windowless-body.html [ Pass Timeout ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index b3a9767..a7bc0b13 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -3923,7 +3923,6 @@ crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-self-baseline-synthesized-004.html [ Failure ] crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-baseline-not-applied-if-sizing-cyclic-dependency-003.html [ Failure ] crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-intrinsic-size-with-orthogonal-items.html [ Failure ] -crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/percent-padding-margin-resolution-grid-item-update.html [ Failure ] ### Tests *expected* to be failing with LayoutNGGrid enabled: crbug.com/1108097 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-areas-overflowing-grid-container-004.html [ Failure ] @@ -5533,8 +5532,6 @@ # SwANGLE issues crbug.com/1204234 css3/blending/background-blend-mode-single-accelerated-element.html [ Failure ] -crbug.com/1204234 external/wpt/webxr/light-estimation/xrWebGLBinding_getReflectionCubeMap.https.html [ Failure ] -crbug.com/1204234 external/wpt/webxr/xrWebGLLayer_opaque_framebuffer_stencil.https.html [ Failure ] # Upcoming DevTools change crbug.com/1006759 http/tests/devtools/profiler/cpu-profiler-save-load.js [ Pass Failure Timeout ] @@ -6972,3 +6969,12 @@ crbug.com/1210687 [ Win ] virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-event-dispatch.js [ Pass Timeout ] crbug.com/1210687 [ Win ] virtual/split-http-cache-not-site-per-process/http/tests/devtools/isolated-code-cache/stale-revalidation-test.js [ Pass Timeout ] crbug.com/1210687 [ Win ] virtual/shared_array_buffer_on_desktop/http/tests/devtools/a11y-axe-core/sources/scope-pane-a11y-test.js [ Pass Timeout ] + +# Sheriff 2021-06-02 +crbug.com/1215575 [ Mac11.0 ] fast/peerconnection/RTCPeerConnection-applyConstraints-remoteVideoTrack.html [ Pass Timeout ] +crbug.com/1215575 [ Mac11.0 ] fast/peerconnection/RTCPeerConnection-createDTMFSender.html [ Pass Failure ] +crbug.com/1215575 [ Mac11.0 ] fast/peerconnection/RTCPeerConnection-datachannel.html [ Pass Timeout ] +crbug.com/1215575 [ Mac11.0 ] fast/peerconnection/RTCPeerConnection-lifetime.html [ Pass Timeout ] +crbug.com/1215575 [ Mac11.0 ] fast/peerconnection/RTCPeerConnection-sdes-gcm.html [ Pass Timeout ] +crbug.com/1215581 [ Mac11.0 ] svg/filters/feImage-preserveAspectRatio-all.svg [ Pass Failure ] +crbug.com/1215584 [ Mac11.0 ] inspector-protocol/layout-fonts/lang-fallback.js [ Pass Failure ]
diff --git a/third_party/blink/web_tests/external/wpt/css/css-position/crashtests/position-absolute-crash-014.html b/third_party/blink/web_tests/external/wpt/css/css-position/crashtests/position-absolute-crash-014.html new file mode 100644 index 0000000..a169a7b9 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-position/crashtests/position-absolute-crash-014.html
@@ -0,0 +1,24 @@ +<!DOCTYPE html> +<link rel="help" href="https://crbug.com/1021676"> +<link rel="author" title="Koji Ishii" href="mailto:kojii@chromium.org"> +<style> +#htmlvar00005 { + filter: drop-shadow(-1px -1px 1px yellow); + float: left; + line-height: 71vw; +} + +#htmlvar00006 { + overflow-x: scroll; + position: absolute; +} + +.class8 { + font: 52px sans-serif; +} +</style> +<ol id="htmlvar00005"> + <li id="htmlvar00006"> + <details class="class8"></details> + </li> +</ol>
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-51.html b/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-51.html new file mode 100644 index 0000000..0257714 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-51.html
@@ -0,0 +1,24 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Forced colors mode - color-scheme.</title> +<link rel="help" href="https://www.w3.org/TR/css-color-adjust-1/#forced-colors-properties"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<style> + #dark { + color-scheme: dark; + } + #light { + color-scheme: light; + forced-color-adjust: none; + } +</style> +<div id="dark"></div> +<div id="light"></div> + +<script> + test(function(){ + assert_equals(getComputedStyle(dark).colorScheme, "light dark"); + assert_equals(getComputedStyle(light).colorScheme, "light"); + }, "Color-scheme computes to 'light dark' in forced colors mode, unless forced-color-adjust is none."); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/uievents/interface/click-event.htm b/third_party/blink/web_tests/external/wpt/uievents/interface/click-event.htm index ff78ae95..b45dc29 100644 --- a/third_party/blink/web_tests/external/wpt/uievents/interface/click-event.htm +++ b/third_party/blink/web_tests/external/wpt/uievents/interface/click-event.htm
@@ -15,9 +15,9 @@ clicktarget.addEventListener('click', t.step_func(function (e) { assert_equals(e.constructor, window.PointerEvent, "Click is a PointerEvent"); assert_true(e instanceof window.PointerEvent, "Click is an instance of PointerEvent"); - // Since this click is not generated by a pointing device, pointerId and - // pointerType must have default values (0 and empty string) - assert_equals(e.pointerId, 0, "Click's pointerId has the default value of 0"); + // Since this click is not generated by a pointing device, pointerId must have + // the reserved value -1, and pointerType must have the default empty string + assert_equals(e.pointerId, -1, "Click's pointerId has the default value of -1"); assert_equals(e.pointerType, "", "Click's pointerType has the default value of empty string"); assert_equals(e.screenX, 0, "Click's screenX coordinate should not be set."); assert_equals(e.screenY, 0, "Click's screenY coordinate should not be set.");
diff --git a/third_party/blink/web_tests/external/wpt/uievents/interface/keyboard-click-event.html b/third_party/blink/web_tests/external/wpt/uievents/interface/keyboard-click-event.html index d70b8cc..2b5e06d 100644 --- a/third_party/blink/web_tests/external/wpt/uievents/interface/keyboard-click-event.html +++ b/third_party/blink/web_tests/external/wpt/uievents/interface/keyboard-click-event.html
@@ -24,7 +24,7 @@ currentTest.step(()=>{ if(e instanceof PointerEvent){ // We want the test to run on all browsers even if click is not a PointerEvent. - assert_equals(e.pointerId, 0, "Click's pointerId has default value"); + assert_equals(e.pointerId, -1, "Click's pointerId has reserved value"); assert_equals(e.pointerType, "", "Click's pointerType has default value"); } });
diff --git a/third_party/blink/web_tests/external/wpt/webxr/light-estimation/xrWebGLBinding_getReflectionCubeMap.https.html b/third_party/blink/web_tests/external/wpt/webxr/light-estimation/xrWebGLBinding_getReflectionCubeMap.https.html index b46f448..a68a0f2b5 100644 --- a/third_party/blink/web_tests/external/wpt/webxr/light-estimation/xrWebGLBinding_getReflectionCubeMap.https.html +++ b/third_party/blink/web_tests/external/wpt/webxr/light-estimation/xrWebGLBinding_getReflectionCubeMap.https.html
@@ -9,72 +9,79 @@ let testName = "Test that getReflectionCubeMap returns or throws appropriately without a reflection map."; let testFunction = (session, controller, t, sessionObjects) => new Promise((resolve) => { + let halfFloatExt = sessionObjects.gl.getExtension('OES_texture_half_float'); + // The preferredReflectionFormat used below is set to "rgba16f" by default. + // This means half float textures must be supported in order to run this test + if (!halfFloatExt) { + resolve(session.end()); + } else { let debug = xr_debug.bind(this, 'testFunction'); let lightProbe1 = null; let binding1 = new XRWebGLBinding(session, sessionObjects.gl); - // Request a default lightProbe - session.requestLightProbe({reflectionFormat: session.preferredReflectionFormat }).then((probe) => { - // Stash and end session. - lightProbe1 = probe; + // Request a default lightProbe + session.requestLightProbe({reflectionFormat: session.preferredReflectionFormat }).then((probe) => { + // Stash and end session. + lightProbe1 = probe; - debug("Querying first pair"); - t.step(() => { - assert_equals( - binding1.getReflectionCubeMap(lightProbe1), - null, - "Active binding and light probe shouldn't throw when requesting cube map"); - }); + debug("Querying first pair"); + t.step(() => { + assert_equals( + binding1.getReflectionCubeMap(lightProbe1), + null, + "Active binding and light probe shouldn't throw when requesting cube map"); + }); - return session.end(); - }).then(() => { - // Need to request a new session. - navigator.xr.test.simulateUserActivation( () => { - navigator.xr.requestSession('immersive-ar', { 'requiredFeatures': ['light-estimation'] }) - .then((newSession) => { - let newBinding = new XRWebGLBinding(newSession, sessionObjects.gl); - newSession.requestLightProbe({ reflectionFormat: newSession.preferredReflectionFormat }).then((newProbe) => { - t.step(() => { - debug("Querying second pair"); - assert_equals( - newBinding.getReflectionCubeMap(newProbe), - null, - "Newly created binding and light probe shouldn't throw"); - - debug("Querying old pair"); - assert_throws_dom( - "InvalidStateError", - () => binding1.getReflectionCubeMap(lightProbe1), - "Binding created with an ended session should throw InvalidStateError"); - debug("Querying mismatched pair"); - assert_throws_dom( - "InvalidStateError", - () => newBinding.getReflectionCubeMap(lightProbe1), - "Querying binding with a probe with a different backing session should throw InvalidStateError"); - }); - debug("losing context"); - - // Trigger a context loss and verify that we are unable to get the reflectionCubeMap. - let lose_context_ext = sessionObjects.gl.getExtension('WEBGL_lose_context'); - - sessionObjects.gl.canvas.addEventListener('webglcontextlost', (ev) => { - ev.preventDefault(); - + return session.end(); + }).then(() => { + // Need to request a new session. + navigator.xr.test.simulateUserActivation( () => { + navigator.xr.requestSession('immersive-ar', { 'requiredFeatures': ['light-estimation'] }) + .then((newSession) => { + let newBinding = new XRWebGLBinding(newSession, sessionObjects.gl); + newSession.requestLightProbe({ reflectionFormat: newSession.preferredReflectionFormat }).then((newProbe) => { t.step(() => { + debug("Querying second pair"); + assert_equals( + newBinding.getReflectionCubeMap(newProbe), + null, + "Newly created binding and light probe shouldn't throw"); + + debug("Querying old pair"); assert_throws_dom( "InvalidStateError", - () => newBinding.getReflectionCubeMap(newProbe), - "Querying for reflection cube map on a binding with context loss should throw InvalidStateError"); + () => binding1.getReflectionCubeMap(lightProbe1), + "Binding created with an ended session should throw InvalidStateError"); + debug("Querying mismatched pair"); + assert_throws_dom( + "InvalidStateError", + () => newBinding.getReflectionCubeMap(lightProbe1), + "Querying binding with a probe with a different backing session should throw InvalidStateError"); + }); + debug("losing context"); + + // Trigger a context loss and verify that we are unable to get the reflectionCubeMap. + let lose_context_ext = sessionObjects.gl.getExtension('WEBGL_lose_context'); + + sessionObjects.gl.canvas.addEventListener('webglcontextlost', (ev) => { + ev.preventDefault(); + + t.step(() => { + assert_throws_dom( + "InvalidStateError", + () => newBinding.getReflectionCubeMap(newProbe), + "Querying for reflection cube map on a binding with context loss should throw InvalidStateError"); + }); + + resolve(newSession.end()); }); - resolve(newSession.end()); - }); - - lose_context_ext.loseContext(); - }); // Request second light probe - }); // Request second session - }); // SimulateUserActivation - }); // .then on session end + lose_context_ext.loseContext(); + }); // Request second light probe + }); // Request second session + }); // SimulateUserActivation + }); // .then on session end + } // halfFloatExt }); // testFunction xr_session_promise_test(
diff --git a/third_party/blink/web_tests/external/wpt/webxr/xrWebGLLayer_opaque_framebuffer_stencil.https.html b/third_party/blink/web_tests/external/wpt/webxr/xrWebGLLayer_opaque_framebuffer_stencil.https.html index 7eadd005..17f991f 100644 --- a/third_party/blink/web_tests/external/wpt/webxr/xrWebGLLayer_opaque_framebuffer_stencil.https.html +++ b/third_party/blink/web_tests/external/wpt/webxr/xrWebGLLayer_opaque_framebuffer_stencil.https.html
@@ -183,7 +183,7 @@ // check that the main color is used correctly (green) pixels[0] = pixels[1] = pixels[2] = pixels[3] = 30; - gl.readPixels(xrViewport.x + xrViewport.width / 2, xrViewport.y + xrViewport.height/4, 1, 1, gl.RGB, gl.UNSIGNED_BYTE, pixels); + gl.readPixels(xrViewport.x + xrViewport.width / 2, xrViewport.y + xrViewport.height/4, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels); if (pixels[0] == 0x0 && pixels[1] == 0xFF && pixels[2] == 0x0) { // green? // PASSED. } else if (pixels[0] == 0xFF && pixels[1] == 0xFF && pixels[2] == 0xFF) { // white? @@ -194,7 +194,7 @@ // check if stencil worked, i.e. white pixels in the center pixels[0] = pixels[1] = pixels[2] = pixels[3] = 20; - gl.readPixels(xrViewport.x + xrViewport.width / 2, xrViewport.y + xrViewport.height/2, 1, 1, gl.RGB, gl.UNSIGNED_BYTE, pixels); + gl.readPixels(xrViewport.x + xrViewport.width / 2, xrViewport.y + xrViewport.height/2, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels); if (pixels[0] == 0xFF && pixels[1] == 0xFF && pixels[2] == 0xFF) { // white? // PASSED. } else if (pixels[0] == 0x0 && pixels[1] == 0xFF && pixels[2] == 0x0) { // green?
diff --git a/third_party/blink/web_tests/media/media-controls.js b/third_party/blink/web_tests/media/media-controls.js index 1e1865f0..2c2605c9 100644 --- a/third_party/blink/web_tests/media/media-controls.js +++ b/third_party/blink/web_tests/media/media-controls.js
@@ -489,8 +489,16 @@ return playbackSpeedItem; } } + function clickPlaybackSpeedButton(video, callback) { - openOverflowAndClickButton(video, playbackSpeedOverflowItem(video), callback); + openOverflowAndClickButton(video, playbackSpeedOverflowItem(video), function() { + var playbackSpeed = playbackSpeedListItemAtPlaybackRate(video, video.playbackRate); + var playbackSpeedsList = playbackSpeedMenu(video); + assert_between_inclusive(playbackSpeedsList.scrollTop, + playbackSpeed.offsetTop + playbackSpeed.offsetHeight - playbackSpeedsList.offsetHeight, + playbackSpeed.offsetTop); + callback(); + }); } function clickPlaybackSpeedAtPlaybackRate(video, playbackRate, callback) {
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl index cd4bf1c..022f4be 100644 --- a/tools/mb/mb_config.pyl +++ b/tools/mb/mb_config.pyl
@@ -137,7 +137,7 @@ 'linux-angle-builder': 'angle_specific_release_trybot', 'linux-angle-chromium-builder': 'gpu_tests_release_trybot', 'mac-angle-builder': 'angle_specific_release_trybot', - 'mac-angle-chromium-builder': 'gpu_tests_release_trybot_deterministic_mac', + 'mac-angle-chromium-builder': 'gpu_tests_release_trybot', 'win-angle-chromium-x64-builder': 'gpu_tests_release_trybot', 'win-angle-chromium-x86-builder': 'gpu_tests_release_trybot_x86', 'win-angle-x64-builder': 'angle_specific_release_trybot', @@ -291,8 +291,8 @@ 'linux-lacros-builder-fyi-rel': 'lacros_on_linux_release_bot', 'linux-lacros-tester-fyi-rel': 'lacros_on_linux_release_bot', 'Mac Builder Next': 'gpu_tests_release_bot_minimal_symbols', - 'Mac deterministic': 'release_bot_mac_strip_minimal_symbols_deterministic', - 'Mac deterministic (dbg)': 'debug_bot_deterministic', + 'Mac deterministic': 'release_bot_mac_strip_minimal_symbols', + 'Mac deterministic (dbg)': 'debug_bot', 'Site Isolation Android': 'android_release_bot_minimal_symbols_arm64', 'TSAN Debug (reclient)': 'tsan_disable_nacl_debug_bot_reclient', @@ -308,6 +308,7 @@ 'VR Linux (reclient)': 'vr_release_bot_reclient', 'Win 10 Fast Ring': 'release_trybot', 'Win x64 Builder (reclient)': 'gpu_tests_release_bot_minimal_symbols_reclient', + 'Win x64 Builder (reclient)(cross)': 'gpu_tests_release_bot_minimal_symbols_reclient_win_cross', 'android-code-coverage': 'gpu_tests_android_release_bot_minimal_symbols_arm64_fastbuild_java_coverage', 'android-code-coverage-native': 'gpu_tests_android_release_bot_no_symbols_arm64_fastbuild_native_coverage', 'android-backuprefptr-arm-fyi-rel': 'release_trybot_backuprefptr_arm', @@ -432,7 +433,7 @@ 'chromium.gpu': { # These all use the 'trybot' mixins to ensure that dcheck is on. - 'GPU Mac Builder': 'gpu_tests_release_trybot_deterministic_mac', + 'GPU Mac Builder': 'gpu_tests_release_trybot', 'GPU Mac Builder (dbg)': 'gpu_tests_debug_bot', 'GPU Linux Builder': 'gpu_tests_release_trybot', 'GPU Linux Builder (dbg)': 'gpu_tests_debug_bot', @@ -594,7 +595,7 @@ 'linux-swangle-tot-angle-x64': 'angle_deqp_release_trybot', 'linux-swangle-tot-swiftshader-x64': 'angle_deqp_release_trybot', 'linux-swangle-x64': 'angle_deqp_release_trybot', - 'mac-swangle-chromium-x64': 'gpu_tests_release_trybot_deterministic_mac', + 'mac-swangle-chromium-x64': 'gpu_tests_release_trybot', 'win-swangle-chromium-x86': 'gpu_tests_release_trybot_x86_resource_allowlisting', 'win-swangle-tot-angle-x64': 'angle_deqp_release_trybot', 'win-swangle-tot-angle-x86': 'angle_deqp_release_trybot_x86', @@ -866,7 +867,7 @@ 'linux-angle-chromium-try': 'gpu_tests_release_trybot', 'linux_angle_deqp_rel_ng': 'angle_deqp_release_trybot', 'linux-angle-try': 'angle_specific_release_trybot', - 'mac-angle-chromium-try': 'gpu_tests_release_trybot_deterministic_mac', + 'mac-angle-chromium-try': 'gpu_tests_release_trybot', 'mac-angle-try': 'angle_specific_release_trybot', 'win-angle-chromium-x64-try': 'gpu_tests_release_trybot', 'win-angle-chromium-x86-try': 'gpu_tests_release_trybot_x86', @@ -1090,9 +1091,9 @@ 'ios-simulator-noncq': 'ios_simulator_debug_static_bot_xctest', 'ios-simulator-multi-window': 'ios_simulator_debug_static_bot_xctest', 'ios-simulator-rts': 'ios_simulator_code_coverage_partial_instrumentation_xctest', - 'mac-osxbeta-rel': 'gpu_tests_release_trybot_deterministic_mac', - 'mac_chromium_10.11_rel_ng': 'gpu_tests_release_trybot_deterministic_mac', - 'mac_chromium_10.12_rel_ng': 'gpu_tests_release_trybot_deterministic_mac', + 'mac-osxbeta-rel': 'gpu_tests_release_trybot', + 'mac_chromium_10.11_rel_ng': 'gpu_tests_release_trybot', + 'mac_chromium_10.12_rel_ng': 'gpu_tests_release_trybot', 'mac_chromium_10.13_rel_ng': 'release_trybot', 'mac_chromium_10.14_rel_ng': 'release_trybot', 'mac_chromium_10.15_rel_ng': 'release_trybot_no_nacl', @@ -1100,14 +1101,14 @@ 'mac_chromium_archive_rel_ng': 'release_bot_mac_strip_minimal_symbols', 'mac_chromium_asan_rel_ng': 'asan_dcheck_disable_nacl_release_bot', 'mac_chromium_compile_dbg_ng': 'gpu_tests_debug_bot', - 'mac_chromium_compile_rel_ng': 'gpu_tests_release_trybot_deterministic_mac', + 'mac_chromium_compile_rel_ng': 'gpu_tests_release_trybot', 'mac_chromium_dbg_ng': 'gpu_tests_debug_bot', 'mac_optional_gpu_tests_rel': 'gpu_fyi_tests_release_trybot', 'mac_upload_clang': 'release_bot', 'mac_upload_clang_arm': 'release_bot', - 'mac-inverse-fieldtrials-fyi-rel': 'gpu_tests_release_trybot_deterministic_mac_invert_fieldtrials', - 'mac-rel': 'gpu_tests_release_trybot_deterministic_mac', - 'mac-rel-rts': 'gpu_tests_release_trybot_deterministic_mac', + 'mac-inverse-fieldtrials-fyi-rel': 'gpu_tests_release_trybot_invert_fieldtrials', + 'mac-rel': 'gpu_tests_release_trybot', + 'mac-rel-rts': 'gpu_tests_release_trybot', 'mac-arm64-rel': 'mac_arm64_release_trybot', }, @@ -1128,7 +1129,7 @@ 'linux-swangle-try-tot-angle-x64': 'angle_deqp_release_trybot', 'linux-swangle-try-tot-swiftshader-x64': 'angle_deqp_release_trybot', 'linux-swangle-try-x64': 'angle_deqp_release_trybot', - 'mac-swangle-chromium-try-x64': 'gpu_tests_release_trybot_deterministic_mac', + 'mac-swangle-chromium-try-x64': 'gpu_tests_release_trybot', 'win-swangle-chromium-try-x86': 'gpu_tests_release_trybot_x86_resource_allowlisting', 'win-swangle-try-tot-angle-x64': 'angle_deqp_release_trybot', 'win-swangle-try-tot-angle-x86': 'angle_deqp_release_trybot_x86', @@ -1995,10 +1996,6 @@ 'debug_bot_blink', ], - 'debug_bot_deterministic': [ - 'debug_bot', 'mac_deterministic_build', - ], - 'debug_bot_local_build': [ 'debug_bot_local_build', ], @@ -2174,6 +2171,10 @@ 'gpu_tests', 'release_bot_reclient', 'minimal_symbols', ], + 'gpu_tests_release_bot_minimal_symbols_reclient_win_cross': [ + 'gpu_tests', 'release_bot_reclient_win_cross', 'minimal_symbols', + ], + 'gpu_tests_release_bot_minimal_symbols_code_coverage': [ 'gpu_tests', 'release_bot', 'minimal_symbols', 'use_clang_coverage', 'partial_code_coverage_instrumentation', @@ -2199,6 +2200,10 @@ 'gpu_tests', 'release_trybot', ], + 'gpu_tests_release_trybot_invert_fieldtrials': [ + 'gpu_tests', 'release_trybot', 'invert_fieldtrials', + ], + 'gpu_tests_release_trybot_mbi_mode_per_render_process_host': [ 'gpu_tests', 'release_trybot', 'mbi_mode_per_render_process_host' ], @@ -2207,16 +2212,6 @@ 'gpu_tests', 'release_trybot', 'mbi_mode_per_site_instance' ], - # TODO(https://crbug.com/330262): Once deterministic builds are default on - # macOS, remove this special case of gpu_tests_release_trybot. - 'gpu_tests_release_trybot_deterministic_mac': [ - 'gpu_tests', 'release_trybot', 'mac_deterministic_build', - ], - - 'gpu_tests_release_trybot_deterministic_mac_invert_fieldtrials': [ - 'gpu_tests', 'release_trybot', 'mac_deterministic_build', 'invert_fieldtrials', - ], - 'gpu_tests_release_trybot_resource_allowlisting': [ 'gpu_tests', 'release_trybot', 'resource_allowlisting', ], @@ -2640,10 +2635,6 @@ 'release_bot', 'mac_strip', 'minimal_symbols', 'arm64', ], - 'release_bot_mac_strip_minimal_symbols_deterministic': [ - 'release_bot', 'mac_strip', 'minimal_symbols', 'mac_deterministic_build' - ], - 'release_bot_minimal_symbols': [ 'release_bot', 'minimal_symbols', ], @@ -3300,10 +3291,6 @@ 'gn_args': 'is_lsan=true', }, - 'mac_deterministic_build': { - 'gn_args': 'mac_deterministic_build=true', - }, - 'mac_strip': { 'gn_args': 'enable_stripping=true', }, @@ -3448,6 +3435,11 @@ 'gn_args': 'use_rbe=true', }, + # experiment windows cross. crbug.com/1213717 + 'reclient_win_cross': { + 'gn_args': 'use_rbe=true rbe_cfg_dir="../../buildtools/reclient_cfgs/win-cross-experiments"', + }, + 'release': { 'gn_args': 'is_debug=false', }, @@ -3466,6 +3458,10 @@ 'mixins': ['release', 'static', 'reclient'], }, + 'release_bot_reclient_win_cross': { + 'mixins': ['release', 'static', 'reclient_win_cross'], + }, + 'release_java': { 'gn_args': 'is_java_debug=false', },
diff --git a/tools/mb/mb_config_expectations/chromium.angle.json b/tools/mb/mb_config_expectations/chromium.angle.json index 9d01346..02830bf 100644 --- a/tools/mb/mb_config_expectations/chromium.angle.json +++ b/tools/mb/mb_config_expectations/chromium.angle.json
@@ -153,7 +153,6 @@ "ffmpeg_branding": "Chrome", "is_component_build": false, "is_debug": false, - "mac_deterministic_build": true, "proprietary_codecs": true, "symbol_level": 1, "use_goma": true
diff --git a/tools/mb/mb_config_expectations/chromium.fyi.json b/tools/mb/mb_config_expectations/chromium.fyi.json index 5d68f2d..1875778 100644 --- a/tools/mb/mb_config_expectations/chromium.fyi.json +++ b/tools/mb/mb_config_expectations/chromium.fyi.json
@@ -242,7 +242,6 @@ "enable_stripping": true, "is_component_build": false, "is_debug": false, - "mac_deterministic_build": true, "symbol_level": 1, "use_goma": true } @@ -251,7 +250,6 @@ "gn_args": { "is_component_build": true, "is_debug": true, - "mac_deterministic_build": true, "symbol_level": 1, "use_goma": true } @@ -387,6 +385,17 @@ "use_rbe": true } }, + "Win x64 Builder (reclient)(cross)": { + "gn_args": { + "ffmpeg_branding": "Chrome", + "is_component_build": false, + "is_debug": false, + "proprietary_codecs": true, + "rbe_cfg_dir": "../../buildtools/reclient_cfgs/win-cross-experiments", + "symbol_level": 1, + "use_rbe": true + } + }, "android-backuprefptr-arm-fyi-rel": { "gn_args": { "dcheck_always_on": true,
diff --git a/tools/mb/mb_config_expectations/chromium.gpu.json b/tools/mb/mb_config_expectations/chromium.gpu.json index a1809c5..e675d8f 100644 --- a/tools/mb/mb_config_expectations/chromium.gpu.json +++ b/tools/mb/mb_config_expectations/chromium.gpu.json
@@ -42,7 +42,6 @@ "ffmpeg_branding": "Chrome", "is_component_build": false, "is_debug": false, - "mac_deterministic_build": true, "proprietary_codecs": true, "symbol_level": 1, "use_goma": true
diff --git a/tools/mb/mb_config_expectations/chromium.swangle.json b/tools/mb/mb_config_expectations/chromium.swangle.json index 21bc3b62..917dd5a 100644 --- a/tools/mb/mb_config_expectations/chromium.swangle.json +++ b/tools/mb/mb_config_expectations/chromium.swangle.json
@@ -46,7 +46,6 @@ "ffmpeg_branding": "Chrome", "is_component_build": false, "is_debug": false, - "mac_deterministic_build": true, "proprietary_codecs": true, "symbol_level": 1, "use_goma": true
diff --git a/tools/mb/mb_config_expectations/tryserver.chromium.angle.json b/tools/mb/mb_config_expectations/tryserver.chromium.angle.json index ad2e467..d5986ff0 100644 --- a/tools/mb/mb_config_expectations/tryserver.chromium.angle.json +++ b/tools/mb/mb_config_expectations/tryserver.chromium.angle.json
@@ -194,7 +194,6 @@ "ffmpeg_branding": "Chrome", "is_component_build": false, "is_debug": false, - "mac_deterministic_build": true, "proprietary_codecs": true, "symbol_level": 1, "use_goma": true
diff --git a/tools/mb/mb_config_expectations/tryserver.chromium.mac.json b/tools/mb/mb_config_expectations/tryserver.chromium.mac.json index e6b90cc..21e0377 100644 --- a/tools/mb/mb_config_expectations/tryserver.chromium.mac.json +++ b/tools/mb/mb_config_expectations/tryserver.chromium.mac.json
@@ -421,7 +421,6 @@ "invert_fieldtrials": true, "is_component_build": false, "is_debug": false, - "mac_deterministic_build": true, "proprietary_codecs": true, "symbol_level": 1, "use_goma": true @@ -433,7 +432,6 @@ "ffmpeg_branding": "Chrome", "is_component_build": false, "is_debug": false, - "mac_deterministic_build": true, "proprietary_codecs": true, "symbol_level": 1, "use_goma": true @@ -445,7 +443,6 @@ "ffmpeg_branding": "Chrome", "is_component_build": false, "is_debug": false, - "mac_deterministic_build": true, "proprietary_codecs": true, "symbol_level": 1, "use_goma": true @@ -457,7 +454,6 @@ "ffmpeg_branding": "Chrome", "is_component_build": false, "is_debug": false, - "mac_deterministic_build": true, "proprietary_codecs": true, "symbol_level": 1, "use_goma": true @@ -469,7 +465,6 @@ "ffmpeg_branding": "Chrome", "is_component_build": false, "is_debug": false, - "mac_deterministic_build": true, "proprietary_codecs": true, "symbol_level": 1, "use_goma": true @@ -481,7 +476,6 @@ "ffmpeg_branding": "Chrome", "is_component_build": false, "is_debug": false, - "mac_deterministic_build": true, "proprietary_codecs": true, "symbol_level": 1, "use_goma": true @@ -559,7 +553,6 @@ "ffmpeg_branding": "Chrome", "is_component_build": false, "is_debug": false, - "mac_deterministic_build": true, "proprietary_codecs": true, "symbol_level": 1, "use_goma": true
diff --git a/tools/mb/mb_config_expectations/tryserver.chromium.swangle.json b/tools/mb/mb_config_expectations/tryserver.chromium.swangle.json index 3f97205..ee0e3232 100644 --- a/tools/mb/mb_config_expectations/tryserver.chromium.swangle.json +++ b/tools/mb/mb_config_expectations/tryserver.chromium.swangle.json
@@ -46,7 +46,6 @@ "ffmpeg_branding": "Chrome", "is_component_build": false, "is_debug": false, - "mac_deterministic_build": true, "proprietary_codecs": true, "symbol_level": 1, "use_goma": true
diff --git a/tools/metrics/histograms/PRESUBMIT.py b/tools/metrics/histograms/PRESUBMIT.py index 790a1faf..92461f63 100644 --- a/tools/metrics/histograms/PRESUBMIT.py +++ b/tools/metrics/histograms/PRESUBMIT.py
@@ -7,6 +7,8 @@ for more details on the presubmit API built into depot_tools. """ +USE_PYTHON3 = True + def GetPrettyPrintErrors(input_api, output_api, cwd, rel_path, results): """Runs pretty-print command for specified file."""
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index bf3dd08..e8f0bc8 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -46282,6 +46282,7 @@ <int value="-968675274" label="Rar2Fs:enabled"/> <int value="-968010468" label="SharedArrayBuffer:disabled"/> <int value="-967825290" label="WebViewConnectionlessSafeBrowsing:disabled"/> + <int value="-966661415" label="ElasticOverscroll:disabled"/> <int value="-966290456" label="WebAuthenticationCtap2:enabled"/> <int value="-965842218" label="MultiDeviceApi:disabled"/> <int value="-964676765" label="enable-accelerated-mjpeg-decode"/> @@ -47688,7 +47689,6 @@ <int value="296215399" label="WindowsMixedReality:disabled"/> <int value="296296761" label="MediaFoundationVideoCapture:disabled"/> <int value="297095559" label="ShowBluetoothDebugLogToggle:disabled"/> - <int value="297346310" label="ElasticOverscrollWin:enabled"/> <int value="297750703" label="DesktopPWAsAppIconShortcutsMenu:enabled"/> <int value="299792415" label="OmniboxSuggestionTransparencyOptions:enabled"/> <int value="300095239" label="FCMInvalidations:enabled"/> @@ -47959,6 +47959,7 @@ <int value="513728926" label="OsSettingsPolymer3:enabled"/> <int value="514406112" label="WebUIOmniboxPopup:disabled"/> <int value="514569020" label="RemoteCopyImageNotification:enabled"/> + <int value="515981953" label="ElasticOverscroll:enabled"/> <int value="516143995" label="EnableAriaElementReflection:enabled"/> <int value="516603570" label="QuickAnswersRichUi:disabled"/> <int value="517429103" label="AutofillImportDynamicForms:enabled"/> @@ -49355,7 +49356,6 @@ <int value="1714520147" label="MBIMode:disabled"/> <int value="1714922056" label="GlobalMediaControls:disabled"/> <int value="1715338237" label="ContextualSearchSecondTap:disabled"/> - <int value="1715382788" label="ElasticOverscrollWin:disabled"/> <int value="1716104463" label="enable-fullscreen-app-list"/> <int value="1717788959" label="SlowDCTimerInterruptsWin:disabled"/> <int value="1717987538" label="NTPTilesLowerResolutionFavicons:enabled"/> @@ -54353,7 +54353,9 @@ <enum name="NearbyConnectionsUtilityProcessShutdownReason"> <int value="0" label="Normal"/> <int value="1" label="Crash"/> - <int value="2" label="Mojo pipe disconnection"/> + <int value="2" label="Mojo pipe disconnection (deprecated)"/> + <int value="3" label="Utility process disconnected Decoder mojo pipe"/> + <int value="4" label="Utility process disconnected Connections mojo pipe"/> </enum> <enum name="NearbyShareAttachmentType"> @@ -62942,6 +62944,24 @@ <int value="1" label="Started"/> </enum> +<enum name="PlatformCellularConnectResult"> + <summary> + The return status as a result of a call to connect to a cellular device at + the shill layer. + </summary> + <int value="0" label="Success"/> + <int value="1" label="Unknown"/> + <int value="2" label="Wrong State"/> + <int value="3" label="Operation Failed"/> + <int value="4" label="Already Connected"/> + <int value="5" label="Not Registered"/> + <int value="6" label="Not On Home Network"/> + <int value="7" label="Incorrect Pin"/> + <int value="8" label="Pin Required"/> + <int value="9" label="Pin Blocked"/> + <int value="10" label="Invalid APN"/> +</enum> + <enum name="PlatformFileError"> <summary>Errors from base::File::Error</summary> <int value="0" label="OK"/> @@ -76676,6 +76696,24 @@ <int value="5" label="Unknown response code"/> </enum> +<enum name="SurveyDownloadResponseCodes2"> +<!-- This enum allocations are not without meaning. Thus, these allocations + should never be changed, and new possible return values should be appended + as new items with new values. + --> + + <summary> + Results when download survey response is available. Used by + Android.Survey.SurveyDownloadResponseCodes2. + </summary> + <int value="0" label="Success"/> + <int value="1" label="Backend timeout"/> + <int value="2" label="Failed to fetch survey"/> + <int value="3" label="No available survey"/> + <int value="4" label="Trigger Id not set"/> + <int value="5" label="Unsupported Cronet engine"/> +</enum> + <enum name="SurveyFilteringResult"> <int value="0" label="Survey info bar already displayed"/> <int value="1" label="Chrome Home enabled for less than one week [removed]"/>
diff --git a/tools/metrics/histograms/histograms_xml/METRIC_REVIEWER_OWNERS b/tools/metrics/histograms/histograms_xml/METRIC_REVIEWER_OWNERS index d28864b..9ab9d251 100644 --- a/tools/metrics/histograms/histograms_xml/METRIC_REVIEWER_OWNERS +++ b/tools/metrics/histograms/histograms_xml/METRIC_REVIEWER_OWNERS
@@ -11,6 +11,7 @@ dewittj@chromium.org dschinazi@chromium.org drubery@chromium.org +dullweber@chromium.org eirage@chromium.org ellyjones@chromium.org ender@chromium.org
diff --git a/tools/metrics/histograms/histograms_xml/android/histograms.xml b/tools/metrics/histograms/histograms_xml/android/histograms.xml index b2692cd..e9ebfc8b 100644 --- a/tools/metrics/histograms/histograms_xml/android/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/android/histograms.xml
@@ -2490,13 +2490,27 @@ <histogram name="Android.Survey.DownloadResponseCode" enum="SurveyDownloadResponseCodes" expires_after="2021-06-01"> <obsolete> - Deprecated as of 05/2021. + Deprecated as of 05/2021 with the old library. Replaced by + Android.Survey.DownloadResponseCode2. </obsolete> <owner>twellington@chromium.org</owner> <owner>clank-app-team@google.com</owner> <summary>The response code of the completed survey download request.</summary> </histogram> +<histogram name="Android.Survey.DownloadResponseCode2" + enum="SurveyDownloadResponseCodes2" expires_after="2022-06-01"> + <owner>skym@chromium.org</owner> + <owner>wenyufu@chromium.org</owner> + <owner>clank-app-team@google.com</owner> + <summary> + The result of the completed survey download request. A survey download is + initiated on ChromeTabbedActivity cold start iff the user passes a series of + eligibility checks. Recorded when a valid survey response is received. + Android only. + </summary> +</histogram> + <histogram name="Android.Survey.InfoBarClosingState" enum="InfoBarClosingStates" expires_after="2022-06-01"> <owner>twellington@chromium.org</owner> @@ -2518,6 +2532,18 @@ </summary> </histogram> +<histogram name="Android.Survey.SurveyCompleted" enum="BooleanCompleted" + expires_after="2022-06-01"> + <owner>skym@chromium.org</owner> + <owner>wenyufu@chromium.org</owner> + <owner>clank-app-team@google.com</owner> + <summary> + Whether a user completed the survey after it was presented. This histogram + is agnostic to the content of the survey, which is configured server side, + and will be recorded for all surveys shown in Chrome. Android only. + </summary> +</histogram> + <histogram name="Android.Survey.SurveyFilteringResults" enum="SurveyFilteringResult" expires_after="2022-06-01"> <owner>twellington@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/history/OWNERS b/tools/metrics/histograms/histograms_xml/history/OWNERS new file mode 100644 index 0000000..6be499c8 --- /dev/null +++ b/tools/metrics/histograms/histograms_xml/history/OWNERS
@@ -0,0 +1,7 @@ +per-file OWNERS=file://tools/metrics/histograms/histograms_xml/METRIC_REVIEWER_OWNERS + +# Prefer sending CLs to the owners listed below. +# Use chromium-metrics-reviews@google.com as a backup. + +# For History.ClearBrowsingData.* histograms +dullweber@chromium.org
diff --git a/tools/metrics/histograms/histograms_xml/nearby/histograms.xml b/tools/metrics/histograms/histograms_xml/nearby/histograms.xml index ebdc106f..8fa7d4a5 100644 --- a/tools/metrics/histograms/histograms_xml/nearby/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/nearby/histograms.xml
@@ -233,9 +233,11 @@ <owner>hansberry@chromium.org</owner> <owner>nearby-share-chromeos-eng@google.com</owner> <summary> - Records which Mojo dependency of the Sharing utility process disconnected. - This is a break down of the "Mojo pipe disconnection" bucket of - Nearby.Connections.UtilityProcessShutdownReason. + Records which Mojo dependency of the Sharing utility process disconnected + from the browser process. This will not necessarily line up with the counts + in the Mojo disconnect bucket of + Nearby.Connections.UtilityProcessShutdownReason which tracks disconnects on + the utility process side. </summary> </histogram>
diff --git a/tools/metrics/histograms/histograms_xml/network/histograms.xml b/tools/metrics/histograms/histograms_xml/network/histograms.xml index 884d3af..dfe69c73 100644 --- a/tools/metrics/histograms/histograms_xml/network/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/network/histograms.xml
@@ -485,6 +485,19 @@ </summary> </histogram> +<histogram name="Network.Shill.Cellular.ConnectResult" + enum="PlatformCellularConnectResult" expires_after="2021-12-01"> + <owner>danielwinkler@google.com</owner> + <owner>cros-connectivity@google.com</owner> + <summary> + Reports the result of Cellular connection attempts through the platform + layers. This captures any success or failure as a result of a Connect call + through ModemManager, or any causes of early failure in shill that prevents + a connect attempt altogether. Refer to go/cros-cellular-apn-metrics for + details. + </summary> +</histogram> + <histogram name="Network.Shill.Cellular.DevicePresenceStatus" enum="BooleanPresent" expires_after="2021-12-01"> <owner>ejcaruso@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/notifications/histograms.xml b/tools/metrics/histograms/histograms_xml/notifications/histograms.xml index 0d024f9..3d65e7e 100644 --- a/tools/metrics/histograms/histograms_xml/notifications/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/notifications/histograms.xml
@@ -630,7 +630,7 @@ </histogram> <histogram name="Notifications.Scheduler.BackgroundTask.Event" - enum="NotificationSchedulerBackgroundTaskEvent" expires_after="2021-07-01"> + enum="NotificationSchedulerBackgroundTaskEvent" expires_after="2021-12-31"> <owner>xingliu@chromium.org</owner> <owner>hesen@chromium.org</owner> <summary> @@ -640,7 +640,7 @@ </histogram> <histogram name="Notifications.Scheduler.BackgroundTask.NotificationShown" - units="notifications" expires_after="2021-07-01"> + units="notifications" expires_after="2021-12-31"> <owner>xingliu@chromium.org</owner> <owner>hesen@chromium.org</owner> <summary> @@ -649,7 +649,7 @@ </histogram> <histogram name="Notifications.Scheduler.BackgroundTask.Start" units="hours" - expires_after="2021-09-05"> + expires_after="2021-12-31"> <owner>xingliu@chromium.org</owner> <owner>hesen@chromium.org</owner> <summary> @@ -659,7 +659,7 @@ </histogram> <histogram name="Notifications.Scheduler.IconDb.InitResult" - enum="BooleanSuccess" expires_after="2021-09-05"> + enum="BooleanSuccess" expires_after="2021-12-31"> <owner>xingliu@chromium.org</owner> <owner>hesen@chromium.org</owner> <summary> @@ -669,7 +669,7 @@ </histogram> <histogram name="Notifications.Scheduler.IconDb.OperationResult" - enum="BooleanSuccess" expires_after="2021-07-01"> + enum="BooleanSuccess" expires_after="2021-12-31"> <owner>xingliu@chromium.org</owner> <owner>hesen@chromium.org</owner> <summary> @@ -679,7 +679,7 @@ </histogram> <histogram name="Notifications.Scheduler.IconDb.RecordCount" units="records" - expires_after="2021-07-01"> + expires_after="2021-12-31"> <owner>xingliu@chromium.org</owner> <owner>hesen@chromium.org</owner> <summary> @@ -689,7 +689,7 @@ </histogram> <histogram name="Notifications.Scheduler.IhnrActionButtonEvent" - enum="NotificationSchedulerActionButtonEvent" expires_after="2021-07-01"> + enum="NotificationSchedulerActionButtonEvent" expires_after="2021-12-31"> <!-- Name completed by histogram_suffixes name="NotificationSchedulerClientType" --> <owner>xingliu@chromium.org</owner> @@ -701,7 +701,7 @@ </histogram> <histogram name="Notifications.Scheduler.Impression.Count" units="records" - expires_after="2021-11-07"> + expires_after="2021-12-31"> <!-- Name completed by histogram_suffixes name="NotificationSchedulerClientType" --> <owner>xingliu@chromium.org</owner> @@ -713,7 +713,7 @@ </histogram> <histogram name="Notifications.Scheduler.Impression.Event" - enum="NotificationSchedulerImpressionEvent" expires_after="2021-07-01"> + enum="NotificationSchedulerImpressionEvent" expires_after="2021-12-31"> <owner>xingliu@chromium.org</owner> <owner>hesen@chromium.org</owner> <summary> @@ -723,7 +723,7 @@ </histogram> <histogram name="Notifications.Scheduler.ImpressionDb.InitResult" - enum="BooleanSuccess" expires_after="2021-07-01"> + enum="BooleanSuccess" expires_after="2021-12-31"> <owner>xingliu@chromium.org</owner> <owner>hesen@chromium.org</owner> <summary> @@ -733,7 +733,7 @@ </histogram> <histogram name="Notifications.Scheduler.ImpressionDb.OperationResult" - enum="BooleanSuccess" expires_after="2021-07-01"> + enum="BooleanSuccess" expires_after="2021-12-31"> <owner>xingliu@chromium.org</owner> <owner>hesen@chromium.org</owner> <summary> @@ -743,7 +743,7 @@ </histogram> <histogram name="Notifications.Scheduler.ImpressionDb.RecordCount" - units="records" expires_after="2021-07-01"> + units="records" expires_after="2021-12-31"> <owner>xingliu@chromium.org</owner> <owner>hesen@chromium.org</owner> <summary> @@ -753,7 +753,7 @@ </histogram> <histogram name="Notifications.Scheduler.NotificationDb.InitResult" - enum="BooleanSuccess" expires_after="2021-11-07"> + enum="BooleanSuccess" expires_after="2021-12-31"> <owner>xingliu@chromium.org</owner> <owner>hesen@chromium.org</owner> <summary> @@ -763,7 +763,7 @@ </histogram> <histogram name="Notifications.Scheduler.NotificationDb.OperationResult" - enum="BooleanSuccess" expires_after="2021-07-01"> + enum="BooleanSuccess" expires_after="2021-12-31"> <owner>xingliu@chromium.org</owner> <owner>hesen@chromium.org</owner> <summary> @@ -773,7 +773,7 @@ </histogram> <histogram name="Notifications.Scheduler.NotificationDb.RecordCount" - units="records" expires_after="2021-07-01"> + units="records" expires_after="2021-12-31"> <owner>xingliu@chromium.org</owner> <owner>hesen@chromium.org</owner> <summary> @@ -784,7 +784,7 @@ <histogram name="Notifications.Scheduler.NotificationLifeCycleEvent" enum="NotificationSchedulerNotificationLifeCycleEvent" - expires_after="2021-11-07"> + expires_after="2021-12-31"> <!-- Name completed by histogram_suffixes name="NotificationSchedulerClientType" --> <owner>xingliu@chromium.org</owner> @@ -796,7 +796,7 @@ </histogram> <histogram name="Notifications.Scheduler.PngIconConverter.DecodeResult" - enum="BooleanSuccess" expires_after="2021-07-01"> + enum="BooleanSuccess" expires_after="2021-12-31"> <owner>xingliu@chromium.org</owner> <owner>hesen@chromium.org</owner> <summary> @@ -808,7 +808,7 @@ </histogram> <histogram name="Notifications.Scheduler.PngIconConverter.EncodeResult" - enum="BooleanSuccess" expires_after="2021-07-01"> + enum="BooleanSuccess" expires_after="2021-12-31"> <owner>xingliu@chromium.org</owner> <owner>hesen@chromium.org</owner> <summary> @@ -820,7 +820,7 @@ </histogram> <histogram name="Notifications.Scheduler.UserAction" - enum="NotificationSchedulerUserActionType" expires_after="2021-11-07"> + enum="NotificationSchedulerUserActionType" expires_after="2021-12-31"> <!-- Name completed by histogram_suffixes name="NotificationSchedulerClientType" --> <owner>xingliu@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/others/OWNERS b/tools/metrics/histograms/histograms_xml/others/OWNERS index 14dfe8d..7cba7e77 100644 --- a/tools/metrics/histograms/histograms_xml/others/OWNERS +++ b/tools/metrics/histograms/histograms_xml/others/OWNERS
@@ -18,3 +18,5 @@ sebsg@chromium.org # For Compositor*, Gpu.*, Graphics* and Viz.* histograms: jonross@chromium.org +# For Privacy* and WebsiteSettings.* histograms: +dullweber@chromium.org
diff --git a/tools/metrics/histograms/histograms_xml/print/histograms.xml b/tools/metrics/histograms/histograms_xml/print/histograms.xml index 2f04736e..cb806d3 100644 --- a/tools/metrics/histograms/histograms_xml/print/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/print/histograms.xml
@@ -178,7 +178,7 @@ </histogram> <histogram name="PrintPreview.PrintDocumentType" - enum="PrintPreviewPrintDocumentTypeBuckets" expires_after="2021-07-11"> + enum="PrintPreviewPrintDocumentTypeBuckets" expires_after="2022-02-11"> <owner>rbpotter@chromium.org</owner> <owner>awscreen@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/subresource/histograms.xml b/tools/metrics/histograms/histograms_xml/subresource/histograms.xml index 45d7c0b..95d80c2d 100644 --- a/tools/metrics/histograms/histograms_xml/subresource/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/subresource/histograms.xml
@@ -258,7 +258,7 @@ <histogram name="SubresourceFilter.DocumentLoad.SubframeFilteringDelay.Disallowed2" - units="microseconds" expires_after="M92"> + units="microseconds" expires_after="2022-06-01"> <owner>alexmt@chromium.org</owner> <owner>chrome-ads-histograms@google.com</owner> <summary> @@ -273,7 +273,7 @@ <histogram name="SubresourceFilter.DocumentLoad.SubframeFilteringDelay.WouldDisallow" - units="microseconds" expires_after="M92"> + units="microseconds" expires_after="2022-06-01"> <owner>alexmt@chromium.org</owner> <owner>chrome-ads-histograms@google.com</owner> <summary> @@ -363,7 +363,7 @@ </histogram> <histogram name="SubresourceFilter.IndexRuleset.Verify2.WallDuration" - units="ms" expires_after="M92"> + units="ms" expires_after="2022-06-01"> <owner>alexmt@chromium.org</owner> <owner>chrome-ads-histograms@google.com</owner> <summary> @@ -375,7 +375,7 @@ </histogram> <histogram name="SubresourceFilter.IndexRuleset.WallDuration" units="ms" - expires_after="M92"> + expires_after="2022-06-01"> <owner>jkarlin@chromium.org</owner> <owner>chrome-ads-histograms@google.com</owner> <summary> @@ -514,7 +514,7 @@ </histogram> <histogram name="SubresourceFilter.PageLoad.NumSubresourceLoads.Evaluated" - units="resource loads" expires_after="M92"> + units="resource loads" expires_after="2022-06-01"> <owner>jkarlin@chromium.org</owner> <owner>chrome-ads-histograms@google.com</owner> <summary> @@ -538,7 +538,7 @@ </histogram> <histogram name="SubresourceFilter.PageLoad.NumSubresourceLoads.Total" - units="resource loads" expires_after="M92"> + units="resource loads" expires_after="2022-06-01"> <owner>jkarlin@chromium.org</owner> <owner>chrome-ads-histograms@google.com</owner> <summary> @@ -549,7 +549,7 @@ </histogram> <histogram name="SubresourceFilter.PageLoad.SafeBrowsingDelay" units="ms" - expires_after="M92"> + expires_after="2022-06-01"> <owner>alexmt@chromium.org</owner> <owner>chrome-ads-histograms@google.com</owner> <summary> @@ -674,7 +674,7 @@ </histogram> <histogram name="SubresourceFilter.WriteRuleset.Result" - enum="SubresourceFilterWriteRulesetResult" expires_after="M92"> + enum="SubresourceFilterWriteRulesetResult" expires_after="2022-06-01"> <owner>alexmt@chromium.org</owner> <owner>chrome-ads-histograms@google.com</owner> <summary>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json index b3f0d36..27482ca6 100644 --- a/tools/perf/core/perfetto_binary_roller/binary_deps.json +++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -10,7 +10,7 @@ }, "linux": { "hash": "5b5e6db44c3cd71a42adcad20800c9a4e35b3fd8", - "remote_path": "perfetto_binaries/trace_processor_shell/linux/34eb6a14728a870046c2637dbfb909d02936b84c/trace_processor_shell" + "remote_path": "perfetto_binaries/trace_processor_shell/linux/8545284860afe328993751b80a9cf856872463df/trace_processor_shell" } }, "power_profile.sql": {
diff --git a/tools/typescript/definitions/activity_log_private.d.ts b/tools/typescript/definitions/activity_log_private.d.ts index f4e944b..90b60c7 100644 --- a/tools/typescript/definitions/activity_log_private.d.ts +++ b/tools/typescript/definitions/activity_log_private.d.ts
@@ -5,87 +5,84 @@ /** @fileoverview Definitions for chrome.activityLogPrivate API. */ // TODO(crbug.com/1203307): Auto-generate this file. -declare namespace chrome { - export namespace activityLogPrivate { +import {ChromeEvent} from './chrome_event.js'; - export enum ExtensionActivityType { - API_CALL = 'api_call', - API_EVENT = 'api_event', - CONTENT_SCRIPT = 'content_script', - DOM_ACCESS = 'dom_access', - DOM_EVENT = 'dom_event', - WEB_REQUEST = 'web_request', +declare global { + export namespace chrome { + export namespace activityLogPrivate { + + export enum ExtensionActivityType { + API_CALL = 'api_call', + API_EVENT = 'api_event', + CONTENT_SCRIPT = 'content_script', + DOM_ACCESS = 'dom_access', + DOM_EVENT = 'dom_event', + WEB_REQUEST = 'web_request', + } + + export enum ExtensionActivityFilter { + API_CALL = 'api_call', + API_EVENT = 'api_event', + CONTENT_SCRIPT = 'content_script', + DOM_ACCESS = 'dom_access', + DOM_EVENT = 'dom_event', + WEB_REQUEST = 'web_request', + ANY = 'any', + } + + export enum ExtensionActivityDomVerb { + GETTER = 'getter', + SETTER = 'setter', + METHOD = 'method', + INSERTED = 'inserted', + XHR = 'xhr', + WEBREQUEST = 'webrequest', + MODIFIED = 'modified', + } + + export type ExtensionActivity = { + activityId?: string, + extensionId?: string, activityType: ExtensionActivityType, + time?: number, + apiCall?: string, + args?: string, + count?: number, + pageUrl?: string, + pageTitle?: string, + argUrl?: string, + other?: { + prerender?: boolean, + domVerb?: ExtensionActivityDomVerb, + webRequest?: string, + extra?: string, + }, + }; + + export type Filter = { + extensionId?: string, activityType: ExtensionActivityFilter, + apiCall?: string, + pageUrl?: string, + argUrl?: string, + daysAgo?: number + }; + + export type ActivityResultSet = { + activities: chrome.activityLogPrivate.ExtensionActivity[], + }; + + type VoidCallback = () => void; + + export function getExtensionActivities( + filter: Filter, callback: (result: ActivityResultSet) => void): void; + export function deleteActivities( + activityIds: string[], callback?: VoidCallback): void; + export function deleteActivitiesByExtension( + extensionId: string, callback?: VoidCallback): void; + export function deleteDatabase(): void; + export function deleteUrls(urls: string[]): void; + + export const onExtensionActivity: + ChromeEvent<(activity: ExtensionActivity) => void>; } - - export enum ExtensionActivityFilter { - API_CALL = 'api_call', - API_EVENT = 'api_event', - CONTENT_SCRIPT = 'content_script', - DOM_ACCESS = 'dom_access', - DOM_EVENT = 'dom_event', - WEB_REQUEST = 'web_request', - ANY = 'any', - } - - export enum ExtensionActivityDomVerb { - GETTER = 'getter', - SETTER = 'setter', - METHOD = 'method', - INSERTED = 'inserted', - XHR = 'xhr', - WEBREQUEST = 'webrequest', - MODIFIED = 'modified', - } - - export type ExtensionActivity = { - activityId?: string, - extensionId?: string, activityType: ExtensionActivityType, - time?: number, - apiCall?: string, - args?: string, - count?: number, - pageUrl?: string, - pageTitle?: string, - argUrl?: string, - other?: { - prerender?: boolean, - domVerb?: ExtensionActivityDomVerb, - webRequest?: string, - extra?: string, - }, - }; - - export type Filter = { - extensionId?: string, activityType: ExtensionActivityFilter, - apiCall?: string, - pageUrl?: string, - argUrl?: string, - daysAgo?: number - }; - - export type ActivityResultSet = { - activities: chrome.activityLogPrivate.ExtensionActivity[], - }; - - type VoidCallback = () => void; - - export function getExtensionActivities( - filter: Filter, callback: (result: ActivityResultSet) => void): void; - export function deleteActivities( - activityIds: string[], callback?: VoidCallback): void; - export function deleteActivitiesByExtension( - extensionId: string, callback?: VoidCallback): void; - export function deleteDatabase(): void; - export function deleteUrls(urls: string[]): void; - - // This is a workaround for the fact that importing other .d.ts files does - // not work. ChromeEvent is also used elsewhere so should be in its own - // file. - export interface ChromeEvent<ListenerType> { - addListener(listener: ListenerType): void; - removeListener(listener: ListenerType): void; - } - - export const onExtensionActivity: ChromeEvent<(activity: ExtensionActivity) => void>; } }
diff --git a/tools/typescript/definitions/bookmark_manager_private.d.ts b/tools/typescript/definitions/bookmark_manager_private.d.ts index c9fd4a35..e832a92 100644 --- a/tools/typescript/definitions/bookmark_manager_private.d.ts +++ b/tools/typescript/definitions/bookmark_manager_private.d.ts
@@ -5,41 +5,53 @@ /** @fileoverview Definitions for chrome.bookmarkManagerPrivate API. */ // TODO(crbug.com/1203307): Auto-generate this file. -declare namespace chrome { - export namespace bookmarkManagerPrivate { - export interface BookmarkNodeDataElement { - id?: string; - parentId?: string; - title: string; - url?: string; - children: BookmarkNodeDataElement[]; +import {ChromeEvent} from './chrome_event.js'; + +declare global { + export namespace chrome { + export namespace bookmarkManagerPrivate { + export interface BookmarkNodeDataElement { + id?: string; + parentId?: string; + title: string; + url?: string; + children: BookmarkNodeDataElement[]; + } + + export interface BookmarkNodeData { + sameProfile: boolean; + elements: BookmarkNodeDataElement[]; + } + + export function copy(idList: string[], callback: () => void): void; + export function cut(idList: string[], callback?: () => void): void; + export function paste( + parentId: string, selectedIdList?: string[], + callback?: () => void): void; + export function canPaste( + parentId: string, callback: (p1: boolean) => void): void; + export function sortChildren(parentId: string): void; + export function startDrag( + idList: string[], dragNodeIndex: number, isFromTouch: boolean, + x: number, y: number): void; + export function drop( + parentId: string, index?: number, callback?: () => void): void; + export function getSubtree( + id: string, foldersOnly: boolean, + callback: (p1: chrome.bookmarks.BookmarkTreeNode[]) => void): void; + export function removeTrees(idList: string[], callback?: () => void): + void; + export function undo(): void; + export function redo(): void; + + type DragData = { + elements: chrome.bookmarks.BookmarkTreeNode[]|null; + sameProfile: boolean; + }; + + export const onDragEnter: ChromeEvent<(p1: DragData) => void>; + export const onDragLeave: ChromeEvent<() => void>; + export const onDrop: ChromeEvent<() => void>; } - - export interface BookmarkNodeData { - sameProfile: boolean, - elements: BookmarkNodeDataElement[]; - } - - export function copy(idList: string[], callback: () => void): void; - export function cut(idList: string[], callback?: () => void): void; - export function paste(parentId: string, selectedIdList?: string[], - callback?: () => void): void; - export function canPaste( - parentId: string, callback: (boolean) => void): void; - export function sortChildren(parentId: string): void; - export function startDrag(idList: string[], dragNodeIndex: number, - isFromTouch: boolean, x: number, y: number): void; - export function drop(parentId: string, index?: number, - callback?: () => void): void; - export function getSubtree( - id: string, foldersOnly: boolean, - callback: (p1: chrome.bookmarks.BookmarkTreeNode[]) => void): void; - export function removeTrees(idList: string[], callback?: () => void): void; - export function undo(): void; - export function redo(): void; - - export const onDragEnter: chrome.bookmarks.ChromeEvent<() => void>; - export const onDragLeave: chrome.bookmarks.ChromeEvent<() => void>; - export const onDrop: chrome.bookmarks.ChromeEvent<() => void>; } }
diff --git a/tools/typescript/definitions/bookmarks.d.ts b/tools/typescript/definitions/bookmarks.d.ts index 9a963d3..b775b239 100644 --- a/tools/typescript/definitions/bookmarks.d.ts +++ b/tools/typescript/definitions/bookmarks.d.ts
@@ -5,123 +5,120 @@ /** @fileoverview Definitions for chrome.bookmarks API. */ // TODO(crbug.com/1203307): Auto-generate this file. -declare namespace chrome { - export namespace bookmarks { - export enum BookmarkTreeNodeUnmodifiable { - MANAGED = 'managed', +import {ChromeEvent} from './chrome_event.js'; + +declare global { + export namespace chrome { + export namespace bookmarks { + export enum BookmarkTreeNodeUnmodifiable { + MANAGED = 'managed', + } + + export interface BookmarkTreeNode { + id: string; + parentId?: string; + index?: number; + url?: string; + title: string; + dateAdded?: number; + dateGroupModified?: number; + unmodifiable?: BookmarkTreeNodeUnmodifiable; + children?: BookmarkTreeNode[]; + } + + export interface CreateDetails { + parentId?: string|null; + index?: number; + title?: string; + url?: string; + } + + export const MAX_WRITE_OPERATIONS_PER_HOUR: number; + export const MAX_SUSTAINED_WRITE_OPERATIONS_PER_MINUTE: number; + + export function get( + idOrIdList: string|string[], + callback: (p1: BookmarkTreeNode[]) => void): void; + + export function getChildren( + id: string, callback: (p1: BookmarkTreeNode[]) => void): void; + + export function getRecent( + numberOfItems: number, + callback: (p1: BookmarkTreeNode[]) => void): void; + + export function getTree(callback: (p1: BookmarkTreeNode[]) => void): void; + + export function getSubTree( + id: string, callback: (p1: BookmarkTreeNode[]) => void): void; + + export function search( + query: string|{ + query: string | undefined, + url: string|undefined, + title: string|undefined + }, + callback: (p1: BookmarkTreeNode[]) => void): void; + + export function create( + bookmark: CreateDetails, + callback?: (p1: BookmarkTreeNode) => void): void; + + export function move( + id: string, + destination: {parentId: string|undefined, index: number|undefined}, + callback?: (p1: BookmarkTreeNode) => void): void; + + export function update( + id: string, changes: {title?: string, url?: string}, + callback?: (p1: BookmarkTreeNode) => void): void; + + export function remove(id: string, callback?: () => void): void; + export function removeTree(id: string, callback?: () => void): void; + function _import(callback?: () => void): void; + function _export(callback?: () => void): void; + export { _import as import } + export { _export as export } + + export const onCreated: + ChromeEvent<(id: string, bookmark: BookmarkTreeNode) => void>; + + export interface ChangeInfo { + title: string; + url: string; + } + + export const onChanged: + ChromeEvent<(id: string, changeInfo: ChangeInfo) => void>; + + export interface ReorderInfo { + childIds: string[], + } + + export const onChildrenReordered: + ChromeEvent<(id: string, reorderInfo: ReorderInfo) => void>; + + export interface RemoveInfo { + index: number; + node: BookmarkTreeNode; + parentId: string; + } + + export const onRemoved: + ChromeEvent<(id: string, removeInfo: RemoveInfo) => void>; + + export interface MoveInfo { + index: number; + oldIndex: number; + oldParentId: string; + parentId: string; + } + + export const onMoved: + ChromeEvent<(id: string, moveInfo: MoveInfo) => void>; + + export const onImportEnded: ChromeEvent<() => void>; + export const onImportBegan: ChromeEvent<() => void>; } - - export interface BookmarkTreeNode { - id: string; - parentId?: string; - index?: number; - url?: string; - title: string; - dateAdded?: number; - dateGroupModified?: number; - unmodifiable?: BookmarkTreeNodeUnmodifiable; - children?: BookmarkTreeNode[]; - } - - export interface CreateDetails { - parentId?: string; - index?: number; - title?: string; - url?: string; - } - - export const MAX_WRITE_OPERATIONS_PER_HOUR: number; - export const MAX_SUSTAINED_WRITE_OPERATIONS_PER_MINUTE: number; - - export function get( - idOrIdList: string|string[], - callback: (p1: BookmarkTreeNode[]) => void): void; - - export function getChildren( - id: string, callback: (p1: BookmarkTreeNode[]) => void): void; - - export function getRecent( - numberOfItems: number, - callback: (p1: BookmarkTreeNode[]) => void): void; - - export function getTree(callback: (p1: BookmarkTreeNode[]) => void): void; - - export function getSubTree( - id: string, callback: (p1: BookmarkTreeNode[]) => void): void; - - export function search( - query: string|{ - query: string | undefined, - url: string|undefined, - title: string|undefined - }, - callback: (p1: BookmarkTreeNode[]) => void): void; - - export function create( - bookmark: CreateDetails, - callback?: (p1: BookmarkTreeNode) => void): void; - - export function move( - id: string, - destination: {parentId: string|undefined, index: number|undefined}, - callback?: (p1: BookmarkTreeNode) => void): void; - - export function update( - id: string, changes: {title?: string, url?: string}, - callback?: (p1: BookmarkTreeNode) => void): void; - - export function remove(id: string, callback?: () => void): void; - export function removeTree(id: string, callback?: () => void): void; - function _import(callback?: () => void): void; - function _export(callback?: () => void): void; - export {_import as import} - export {_export as export} - - // This is a workaround for the fact that importing other .d.ts files does - // not work. ChromeEvent is also used elsewhere so should be in its own - // file. - export interface ChromeEvent<ListenerType> { - addListener(listener: ListenerType): void; - removeListener(listener: ListenerType): void; - } - - export const onCreated: - ChromeEvent<(id: string, bookmark: BookmarkTreeNode) => void>; - - export interface ChangeInfo { - title: string, - url: string, - } - - export const onChanged: - ChromeEvent<(id: string, changeInfo: ChangeInfo) => void>; - - export interface ReorderInfo { - childIds: string[], - } - - export const onChildrenReordered: - ChromeEvent<(id: string, reorderInfo: ReorderInfo) => void>; - - export interface RemoveInfo { - index: number, - node: BookmarkTreeNode, - parentId: string, - } - - export const onRemoved: - ChromeEvent<(id: string, removeInfo: RemoveInfo) => void>; - - export interface MoveInfo { - index: number, - oldIndex: number, - oldParentId: string, - parentId: string, - } - - export const onMoved: ChromeEvent<(id: string, moveInfo: MoveInfo) => void>; - - export const onImportEnded: ChromeEvent<() => void>; - export const onImportBegan: ChromeEvent<() => void>; } }
diff --git a/tools/typescript/definitions/chrome_event.d.ts b/tools/typescript/definitions/chrome_event.d.ts new file mode 100644 index 0000000..0ce7cf1 --- /dev/null +++ b/tools/typescript/definitions/chrome_event.d.ts
@@ -0,0 +1,8 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +export interface ChromeEvent<ListenerType> { + addListener(listener: ListenerType): void; + removeListener(listener: ListenerType): void; +}
diff --git a/tools/typescript/definitions/developer_private.d.ts b/tools/typescript/definitions/developer_private.d.ts index 2edd0c1..5a1930ad 100644 --- a/tools/typescript/definitions/developer_private.d.ts +++ b/tools/typescript/definitions/developer_private.d.ts
@@ -5,433 +5,430 @@ /** @fileoverview Definitions for chrome.developerPrivate API */ // TODO(crbug.com/1203307): Auto-generate this file. -declare namespace chrome { - export namespace developerPrivate { +import {ChromeEvent} from './chrome_event.js'; - export enum ItemType { - HOSTED_APP = 'hosted_app', - PACKAGED_APP = 'packaged_app', - LEGACY_PACKAGED_APP = 'legacy_packaged_app', - EXTENSION = 'extension', - THEME = 'theme', +declare global { + export namespace chrome { + export namespace developerPrivate { + + export enum ItemType { + HOSTED_APP = 'hosted_app', + PACKAGED_APP = 'packaged_app', + LEGACY_PACKAGED_APP = 'legacy_packaged_app', + EXTENSION = 'extension', + THEME = 'theme', + } + + export type ItemInspectView = { + path: string, + render_process_id: number, + render_view_id: number, + incognito: boolean, + generatedBackgroundPage: boolean, + }; + + export type InstallWarning = { + message: string, + }; + + export enum ExtensionType { + HOSTED_APP = 'HOSTED_APP', + PLATFORM_APP = 'PLATFORM_APP', + LEGACY_PACKAGED_APP = 'LEGACY_PACKAGED_APP', + EXTENSION = 'EXTENSION', + THEME = 'THEME', + SHARED_MODULE = 'SHARED_MODULE', + } + + export enum Location { + FROM_STORE = 'FROM_STORE', + UNPACKED = 'UNPACKED', + THIRD_PARTY = 'THIRD_PARTY', + UNKNOWN = 'UNKNOWN', + } + + export enum ViewType { + APP_WINDOW = 'APP_WINDOW', + BACKGROUND_CONTENTS = 'BACKGROUND_CONTENTS', + COMPONENT = 'COMPONENT', + EXTENSION_BACKGROUND_PAGE = 'EXTENSION_BACKGROUND_PAGE', + EXTENSION_DIALOG = 'EXTENSION_DIALOG', + EXTENSION_GUEST = 'EXTENSION_GUEST', + EXTENSION_POPUP = 'EXTENSION_POPUP', + EXTENSION_SERVICE_WORKER_BACKGROUND = + 'EXTENSION_SERVICE_WORKER_BACKGROUND', + TAB_CONTENTS = 'TAB_CONTENTS', + } + + export enum ErrorType { + MANIFEST = 'MANIFEST', + RUNTIME = 'RUNTIME', + } + + export enum ErrorLevel { + LOG = 'LOG', + WARN = 'WARN', + ERROR = 'ERROR', + } + + export enum ExtensionState { + ENABLED = 'ENABLED', + DISABLED = 'DISABLED', + TERMINATED = 'TERMINATED', + BLACKLISTED = 'BLACKLISTED', + } + + export enum ComandScope { + GLOBAL = 'GLOBAL', + CHROME = 'CHROME', + } + + export type GetExtensionsInfoOptions = { + includeDisabled?: boolean, + includeTerminated?: boolean, + }; + + export enum CommandScope { + GLOBAL = 'GLOBAL', + CHROME = 'CHROME', + } + + export type AccessModifier = { + isEnabled: boolean, + isActive: boolean, + }; + + export type StackFrame = { + lineNumber: number, + columnNumber: number, + url: string, + functionName: string, + }; + + export type ManifestError = { + type: ErrorType, + extensionId: string, + fromIncognito: boolean, + source: string, + message: string, + id: number, + manifestKey: string, + manifestSpecific?: string, + }; + + export type RuntimeError = { + type: ErrorType, + extensionId: string, + fromIncognito: boolean, + source: string, + message: string, + id: number, + severity: ErrorLevel, + contextUrl: string, + occurrences: number, + renderViewId: number, + renderProcessId: number, + canInspect: boolean, + stackTrace: StackFrame[], + }; + + export type DisableReasons = { + suspiciousInstall: boolean, + corruptInstall: boolean, + updateRequired: boolean, + blockedByPolicy: boolean, + reloading: boolean, + custodianApprovalRequired: boolean, + parentDisabledPermissions: boolean, + }; + + export type OptionsPage = { + openInTab: boolean, + url: string, + }; + + export type HomePage = { + url: string, + specified: boolean, + }; + + export type ExtensionView = { + url: string, + renderProcessId: number, + renderViewId: number, + incognito: boolean, + isIframe: boolean, + type: ViewType, + }; + + export enum HostAccess { + ON_CLICK = 'ON_CLICK', + ON_SPECIFIC_SITES = 'ON_SPECIFIC_SITES', + ON_ALL_SITES = 'ON_ALL_SITES', + } + + export type ControlledInfo = { + text: string, + }; + + export type Command = { + description: string, + keybinding: string, + name: string, + isActive: boolean, + scope: CommandScope, + isExtensionAction: boolean, + }; + + export type DependentExtension = { + id: string, + name: string, + }; + + export type Permission = { + message: string, + submessages: string[], + }; + + export type SiteControl = { + host: string, + granted: boolean, + }; + + export type RuntimeHostPermissions = { + hasAllHosts: boolean, + hostAccess: HostAccess, + hosts: chrome.developerPrivate.SiteControl[], + }; + + export type Permissions = { + simplePermissions: chrome.developerPrivate.Permission[], + runtimeHostPermissions?: RuntimeHostPermissions, + }; + + export type ExtensionInfo = { + blacklistText?: string, + commands: Command[], + controlledInfo?: ControlledInfo, + dependentExtensions: DependentExtension[], + description: string, + disableReasons: DisableReasons, + errorCollection: AccessModifier, + fileAccess: AccessModifier, + homePage: HomePage, + iconUrl: string, + id: string, + incognitoAccess: AccessModifier, + installWarnings: string[], + launchUrl?: string, location: Location, + locationText?: string, + manifestErrors: ManifestError[], + manifestHomePageUrl: string, + mustRemainInstalled: boolean, + name: string, + offlineEnabled: boolean, + optionsPage?: OptionsPage, + path?: string, + permissions: Permissions, + prettifiedPath?: string, + runtimeErrors: RuntimeError[], + runtimeWarnings: string[], + state: ExtensionState, + type: ExtensionType, + updateUrl: string, + userMayModify: boolean, + version: string, + views: ExtensionView[], + webStoreUrl: string, + showSafeBrowsingAllowlistWarning: boolean, + }; + + export type ProfileInfo = { + canLoadUnpacked: boolean, + inDeveloperMode: boolean, + isDeveloperModeControlledByPolicy: boolean, + isIncognitoAvailable: boolean, + isSupervised: boolean, + }; + + export type ExtensionConfigurationUpdate = { + extensionId: string, + fileAccess?: boolean, + incognitoAccess?: boolean, + errorCollection?: boolean, + hostAccess?: HostAccess, + }; + + export type ProfileConfigurationUpdate = { + inDeveloperMode: boolean, + }; + + export type ExtensionCommandUpdate = { + extensionId: string, + commandName: string, + scope?: CommandScope, + keybinding?: string, + }; + + export type ReloadOptions = { + failQuietly?: boolean, + populateErrorForUnpacked?: boolean, + }; + + export type LoadUnpackedOptions = { + failQuietly?: boolean, + populateError?: boolean, + retryGuid?: string, + useDraggedPath?: boolean, + }; + + export enum PackStatus { + SUCCESS = 'SUCCESS', + ERROR = 'ERROR', + WARNING = 'WARNING', + } + + export enum FileType { + LOAD = 'LOAD', + PEM = 'PEM', + } + + export enum SelectType { + FILE = 'FILE', + FOLDER = 'FOLDER', + } + + export enum EventType { + INSTALLED = 'INSTALLED', + UNINSTALLED = 'UNINSTALLED', + LOADED = 'LOADED', + UNLOADED = 'UNLOADED', + VIEW_REGISTERED = 'VIEW_REGISTERED', + VIEW_UNREGISTERED = 'VIEW_UNREGISTERED', + ERROR_ADDED = 'ERROR_ADDED', + ERRORS_REMOVED = 'ERRORS_REMOVED', + PREFS_CHANGED = 'PREFS_CHANGED', + WARNINGS_CHANGED = 'WARNINGS_CHANGED', + COMMAND_ADDED = 'COMMAND_ADDED', + COMMAND_REMOVED = 'COMMAND_REMOVED', + PERMISSIONS_CHANGED = 'PERMISSIONS_CHANGED', + SERVICE_WORKER_STARTED = 'SERVICE_WORKER_STARTED', + SERVICE_WORKER_STOPPED = 'SERVICE_WORKER_STOPPED', + } + + export type PackDirectoryResponse = { + message: string, + item_path: string, + pem_path: string, + override_flags: number, + status: PackStatus, + }; + + export type EventData = { + event_type: EventType, + item_id: string, + extensionInfo?: ExtensionInfo, + }; + + export type ErrorFileSource = { + beforeHighlight: string, + highlight: string, + afterHighlight: string, + }; + + export type LoadError = { + error: string, + path: string, + source?: ErrorFileSource, retryGuid: string, + }; + + export type RequestFileSourceProperties = { + extensionId: string, + pathSuffix: string, + message: string, + manifestKey?: string, + manifestSpecific?: string, + lineNumber?: number, + }; + + export type RequestFileSourceResponse = { + highlight: string, + beforeHighlight: string, + afterHighlight: string, + title: string, + message: string + }; + + export type OpenDevToolsProperties = { + extensionId?: string, renderViewId: number, renderProcessId: number, + isServiceWorker?: boolean, + incognito?: boolean, + url?: string, + lineNumber?: number, + columnNumber?: number + }; + + export type DeleteExtensionErrorsProperties = { + extensionId: string, + errorIds?: number[], + type?: ErrorType, + }; + + type VoidCallback = () => void; + type StringCallback = (s: string) => void; + + export function addHostPermission( + extensionId: string, host: string, callback: VoidCallback): void; + export function autoUpdate(callback: VoidCallback): void; + export function choosePath( + selectType: SelectType, fileType: FileType, + callback: StringCallback): void; + export function deleteExtensionErrors( + properties: DeleteExtensionErrorsProperties, + callback?: VoidCallback): void; + export function getExtensionsInfo( + options: GetExtensionsInfoOptions, + callback: (info: ExtensionInfo) => void): void; + export function getExtensionSize(id: string, callback: StringCallback): + void; + export function getProfileConfiguration( + callback: (info: ProfileInfo) => void): void; + export function installDroppedFile(callback?: VoidCallback): void; + export function loadUnpacked( + options: LoadUnpackedOptions, + callback: (error?: LoadError) => void): void; + export function notifyDragInstallInProgress(): void; + export function openDevTools( + properties: OpenDevToolsProperties, callback?: VoidCallback): void; + export function packDirectory( + path: string, privateKeyPath: string, flags?: number, + callback?: (response: PackDirectoryResponse) => void): void; + export function reload( + extensionId: string, options?: ReloadOptions, + callback?: (error?: LoadError) => void): void; + export function removeHostPermission( + extensionId: string, host: string, callback: VoidCallback): void; + export function repairExtension( + extensionId: string, callback?: VoidCallback): void; + export function requestFileSource( + properties: RequestFileSourceProperties, + callback: (response: RequestFileSourceResponse) => void): void; + export function setShortcutHandlingSuspended( + isSuspended: boolean, callback?: VoidCallback): void; + export function showOptions(extensionId: string, callback?: VoidCallback): + void; + export function showPath(extensionId: string, callback?: VoidCallback): + void; + export function updateExtensionCommand( + update: ExtensionCommandUpdate, callback?: VoidCallback): void; + export function updateExtensionConfiguration( + update: ExtensionConfigurationUpdate, callback?: VoidCallback): void; + export function updateProfileConfiguration( + update: ProfileConfigurationUpdate, callback?: VoidCallback): void; + + export const onItemStateChanged: ChromeEvent<(data: EventData) => void>; + export const onProfileStateChanged: + ChromeEvent<(info: ProfileInfo) => void>; } - - export type ItemInspectView = { - path: string, - render_process_id: number, - render_view_id: number, - incognito: boolean, - generatedBackgroundPage: boolean, - }; - - export type InstallWarning = { - message: string, - }; - - export enum ExtensionType { - HOSTED_APP = 'HOSTED_APP', - PLATFORM_APP = 'PLATFORM_APP', - LEGACY_PACKAGED_APP = 'LEGACY_PACKAGED_APP', - EXTENSION = 'EXTENSION', - THEME = 'THEME', - SHARED_MODULE = 'SHARED_MODULE', - } - - export enum Location { - FROM_STORE = 'FROM_STORE', - UNPACKED = 'UNPACKED', - THIRD_PARTY = 'THIRD_PARTY', - UNKNOWN = 'UNKNOWN', - } - - export enum ViewType { - APP_WINDOW = 'APP_WINDOW', - BACKGROUND_CONTENTS = 'BACKGROUND_CONTENTS', - COMPONENT = 'COMPONENT', - EXTENSION_BACKGROUND_PAGE = 'EXTENSION_BACKGROUND_PAGE', - EXTENSION_DIALOG = 'EXTENSION_DIALOG', - EXTENSION_GUEST = 'EXTENSION_GUEST', - EXTENSION_POPUP = 'EXTENSION_POPUP', - EXTENSION_SERVICE_WORKER_BACKGROUND = - 'EXTENSION_SERVICE_WORKER_BACKGROUND', - TAB_CONTENTS = 'TAB_CONTENTS', - } - - export enum ErrorType { - MANIFEST = 'MANIFEST', - RUNTIME = 'RUNTIME', - } - - export enum ErrorLevel { - LOG = 'LOG', - WARN = 'WARN', - ERROR = 'ERROR', - } - - export enum ExtensionState { - ENABLED = 'ENABLED', - DISABLED = 'DISABLED', - TERMINATED = 'TERMINATED', - BLACKLISTED = 'BLACKLISTED', - } - - export enum ComandScope { - GLOBAL = 'GLOBAL', - CHROME = 'CHROME', - } - - export type GetExtensionsInfoOptions = { - includeDisabled?: boolean, - includeTerminated?: boolean, - }; - - export enum CommandScope { - GLOBAL = 'GLOBAL', - CHROME = 'CHROME', - } - - export type AccessModifier = { - isEnabled: boolean, - isActive: boolean, - }; - - export type StackFrame = { - lineNumber: number, - columnNumber: number, - url: string, - functionName: string, - }; - - export type ManifestError = { - type: ErrorType, - extensionId: string, - fromIncognito: boolean, - source: string, - message: string, - id: number, - manifestKey: string, - manifestSpecific?: string, - }; - - export type RuntimeError = { - type: ErrorType, - extensionId: string, - fromIncognito: boolean, - source: string, - message: string, - id: number, - severity: ErrorLevel, - contextUrl: string, - occurrences: number, - renderViewId: number, - renderProcessId: number, - canInspect: boolean, - stackTrace: StackFrame[], - }; - - export type DisableReasons = { - suspiciousInstall: boolean, - corruptInstall: boolean, - updateRequired: boolean, - blockedByPolicy: boolean, - reloading: boolean, - custodianApprovalRequired: boolean, - parentDisabledPermissions: boolean, - }; - - export type OptionsPage = { - openInTab: boolean, - url: string, - }; - - export type HomePage = { - url: string, - specified: boolean, - }; - - export type ExtensionView = { - url: string, - renderProcessId: number, - renderViewId: number, - incognito: boolean, - isIframe: boolean, - type: ViewType, - }; - - export enum HostAccess { - ON_CLICK = 'ON_CLICK', - ON_SPECIFIC_SITES = 'ON_SPECIFIC_SITES', - ON_ALL_SITES = 'ON_ALL_SITES', - } - - export type ControlledInfo = { - text: string, - }; - - export type Command = { - description: string, - keybinding: string, - name: string, - isActive: boolean, - scope: CommandScope, - isExtensionAction: boolean, - }; - - export type DependentExtension = { - id: string, - name: string, - }; - - export type Permission = { - message: string, - submessages: string[], - }; - - export type SiteControl = { - host: string, - granted: boolean, - }; - - export type RuntimeHostPermissions = { - hasAllHosts: boolean, - hostAccess: HostAccess, - hosts: chrome.developerPrivate.SiteControl[], - }; - - export type Permissions = { - simplePermissions: chrome.developerPrivate.Permission[], - runtimeHostPermissions?: RuntimeHostPermissions, - }; - - export type ExtensionInfo = { - blacklistText?: string, - commands: Command[], - controlledInfo?: ControlledInfo, - dependentExtensions: DependentExtension[], - description: string, - disableReasons: DisableReasons, - errorCollection: AccessModifier, - fileAccess: AccessModifier, - homePage: HomePage, - iconUrl: string, - id: string, - incognitoAccess: AccessModifier, - installWarnings: string[], - launchUrl?: string, location: Location, - locationText?: string, - manifestErrors: ManifestError[], - manifestHomePageUrl: string, - mustRemainInstalled: boolean, - name: string, - offlineEnabled: boolean, - optionsPage?: OptionsPage, - path?: string, - permissions: Permissions, - prettifiedPath?: string, - runtimeErrors: RuntimeError[], - runtimeWarnings: string[], - state: ExtensionState, - type: ExtensionType, - updateUrl: string, - userMayModify: boolean, - version: string, - views: ExtensionView[], - webStoreUrl: string, - showSafeBrowsingAllowlistWarning: boolean, - }; - - export type ProfileInfo = { - canLoadUnpacked: boolean, - inDeveloperMode: boolean, - isDeveloperModeControlledByPolicy: boolean, - isIncognitoAvailable: boolean, - isSupervised: boolean, - }; - - export type ExtensionConfigurationUpdate = { - extensionId: string, - fileAccess?: boolean, - incognitoAccess?: boolean, - errorCollection?: boolean, - hostAccess?: HostAccess, - }; - - export type ProfileConfigurationUpdate = { - inDeveloperMode: boolean, - }; - - export type ExtensionCommandUpdate = { - extensionId: string, - commandName: string, - scope?: CommandScope, - keybinding?: string, - }; - - export type ReloadOptions = { - failQuietly?: boolean, - populateErrorForUnpacked?: boolean, - }; - - export type LoadUnpackedOptions = { - failQuietly?: boolean, - populateError?: boolean, - retryGuid?: string, - useDraggedPath?: boolean, - }; - - export enum PackStatus { - SUCCESS = 'SUCCESS', - ERROR = 'ERROR', - WARNING = 'WARNING', - } - - export enum FileType { - LOAD = 'LOAD', - PEM = 'PEM', - } - - export enum SelectType { - FILE = 'FILE', - FOLDER = 'FOLDER', - } - - export enum EventType { - INSTALLED = 'INSTALLED', - UNINSTALLED = 'UNINSTALLED', - LOADED = 'LOADED', - UNLOADED = 'UNLOADED', - VIEW_REGISTERED = 'VIEW_REGISTERED', - VIEW_UNREGISTERED = 'VIEW_UNREGISTERED', - ERROR_ADDED = 'ERROR_ADDED', - ERRORS_REMOVED = 'ERRORS_REMOVED', - PREFS_CHANGED = 'PREFS_CHANGED', - WARNINGS_CHANGED = 'WARNINGS_CHANGED', - COMMAND_ADDED = 'COMMAND_ADDED', - COMMAND_REMOVED = 'COMMAND_REMOVED', - PERMISSIONS_CHANGED = 'PERMISSIONS_CHANGED', - SERVICE_WORKER_STARTED = 'SERVICE_WORKER_STARTED', - SERVICE_WORKER_STOPPED = 'SERVICE_WORKER_STOPPED', - } - - export type PackDirectoryResponse = { - message: string, - item_path: string, - pem_path: string, - override_flags: number, - status: PackStatus, - }; - - export type EventData = { - event_type: EventType, - item_id: string, - extensionInfo?: ExtensionInfo, - }; - - export type ErrorFileSource = { - beforeHighlight: string, - highlight: string, - afterHighlight: string, - }; - - export type LoadError = { - error: string, - path: string, - source?: ErrorFileSource, retryGuid: string, - }; - - export type RequestFileSourceProperties = { - extensionId: string, - pathSuffix: string, - message: string, - manifestKey?: string, - manifestSpecific?: string, - lineNumber?: number, - }; - - export type RequestFileSourceResponse = { - highlight: string, - beforeHighlight: string, - afterHighlight: string, - title: string, - message: string - }; - - export type OpenDevToolsProperties = { - extensionId?: string, renderViewId: number, renderProcessId: number, - isServiceWorker?: boolean, - incognito?: boolean, - url?: string, - lineNumber?: number, - columnNumber?: number - }; - - export type DeleteExtensionErrorsProperties = { - extensionId: string, - errorIds?: number[], - type?: ErrorType, - }; - - type VoidCallback = () => void; - type StringCallback = (s: string) => void; - - export function addHostPermission( - extensionId: string, host: string, callback: VoidCallback): void; - export function autoUpdate(callback: VoidCallback): void; - export function choosePath( - selectType: SelectType, fileType: FileType, - callback: StringCallback): void; - export function deleteExtensionErrors( - properties: DeleteExtensionErrorsProperties, - callback?: VoidCallback): void; - export function getExtensionsInfo( - options: GetExtensionsInfoOptions, - callback: (info: ExtensionInfo) => void): void; - export function getExtensionSize(id: string, callback: StringCallback): - void; - export function getProfileConfiguration( - callback: (info: ProfileInfo) => void): void; - export function installDroppedFile(callback?: VoidCallback): void; - export function loadUnpacked( - options: LoadUnpackedOptions, - callback: (error?: LoadError) => void): void; - export function notifyDragInstallInProgress(): void; - export function openDevTools( - properties: OpenDevToolsProperties, callback?: VoidCallback): void; - export function packDirectory( - path: string, privateKeyPath: string, flags?: number, - callback?: (response: PackDirectoryResponse) => void): void; - export function reload( - extensionId: string, options?: ReloadOptions, - callback?: (error?: LoadError) => void): void; - export function removeHostPermission( - extensionId: string, host: string, callback: VoidCallback): void; - export function repairExtension( - extensionId: string, callback?: VoidCallback): void; - export function requestFileSource( - properties: RequestFileSourceProperties, - callback: (response: RequestFileSourceResponse) => void): void; - export function setShortcutHandlingSuspended( - isSuspended: boolean, callback?: VoidCallback): void; - export function showOptions(extensionId: string, callback?: VoidCallback): - void; - export function showPath(extensionId: string, callback?: VoidCallback): - void; - export function updateExtensionCommand( - update: ExtensionCommandUpdate, callback?: VoidCallback): void; - export function updateExtensionConfiguration( - update: ExtensionConfigurationUpdate, callback?: VoidCallback): void; - export function updateProfileConfiguration( - update: ProfileConfigurationUpdate, callback?: VoidCallback): void; - - // This is a workaround for the fact that importing other .d.ts files does - // not work. ChromeEvent is also used elsewhere so should be in its own - // file. - export interface ChromeEvent<ListenerType> { - addListener(listener: ListenerType): void; - removeListener(listener: ListenerType): void; - } - - export const onItemStateChanged: ChromeEvent<(data: EventData) => void>; - export const onProfileStateChanged: ChromeEvent<(info: ProfileInfo) => void>; } }
diff --git a/ui/accessibility/ax_tree.cc b/ui/accessibility/ax_tree.cc index ad99efb..7591e3a 100644 --- a/ui/accessibility/ax_tree.cc +++ b/ui/accessibility/ax_tree.cc
@@ -163,7 +163,7 @@ create_node_count(0), node_exists(!!node), parent_node_id((node && node->parent()) - ? absl::optional<AXNodeID>{node->parent()->id()} + ? absl::make_optional<AXNodeID>(node->parent()->id()) : absl::nullopt), last_known_data(node ? &node->data() : nullptr) {} @@ -541,10 +541,14 @@ // We need to keep this around in order to correctly fire post-update events. std::map<AXNodeID, AXNodeData> old_node_id_to_data; - // Optional copy of the old tree data, only populated when the tree - // data has changed. + // Optional copy of the old tree data, only populated when the tree data will + // need to be updated. absl::optional<AXTreeData> old_tree_data; + // Optional copy of the updated tree data, used when calculating what changes + // will occur during an update before the update applies changes. + absl::optional<AXTreeData> new_tree_data; + // Keep track of the pending tree update to help create useful error messages. // TODO(crbug.com/1156601) Revert this once we have the crash data we need // (crrev.com/c/2892259). @@ -710,14 +714,14 @@ } } -void AXTree::UpdateData(const AXTreeData& new_data) { +void AXTree::UpdateDataForTesting(const AXTreeData& new_data) { if (data_ == new_data) return; - AXTreeData old_data = data_; - data_ = new_data; - for (AXTreeObserver& observer : observers_) - observer.OnTreeDataChanged(this, old_data, new_data); + AXTreeUpdate update; + update.has_tree_data = true; + update.tree_data = new_data; + Unserialize(update); } gfx::RectF AXTree::RelativeToTreeBoundsInternal(const AXNode* node, @@ -990,6 +994,12 @@ // false whenever this function exits. base::AutoReset<bool> update_state_resetter(&tree_update_in_progress_, true); + // Update the tree data. Do not call `UpdateDataForTesting` since this method + // should be used only for testing, but importantly, we want to defer the + // `OnTreeDataChanged` event until after the tree has finished updating. + if (update_state.new_tree_data) + data_ = update.tree_data; + // Handle |node_id_to_clear| before applying ordinary node updates. // We distinguish between updating the root, e.g. changing its children or // some of its attributes, or replacing the root completely. If the root is @@ -1040,13 +1050,6 @@ DCHECK_EQ(!GetFromId(update.root_id), update_state.root_will_be_created); - // Update the tree data, do not call |UpdateData| since we want to defer - // the |OnTreeDataChanged| event until after the tree has finished updating. - if (update.has_tree_data && data_ != update.tree_data) { - update_state.old_tree_data = data_; - data_ = update.tree_data; - } - // Update all of the nodes in the update. for (size_t i = 0; i < update.nodes.size(); ++i) { const bool is_new_root = update_state.root_will_be_created && @@ -1148,10 +1151,15 @@ // Tree is no longer updating. SetTreeUpdateInProgressState(false); - // Now that the tree is stable and its nodes have been updated, notify if - // the tree data changed. We must do this after updating nodes in case the - // root has been replaced, so observers have the most up-to-date information. if (update_state.old_tree_data) { + DCHECK(update.has_tree_data) + << "If `UpdateState::old_tree_data` exists, then there must be a " + "request to update the tree data."; + + // Now that the tree is stable and its nodes have been updated, notify if + // the tree data changed. We must do this after updating nodes in case the + // root has been replaced, so observers have the most up-to-date + // information. for (AXTreeObserver& observer : observers_) observer.OnTreeDataChanged(this, *update_state.old_tree_data, data_); } @@ -1266,9 +1274,17 @@ update_state->pending_update_status = AXTreePendingStructureStatus::kComputing; + // The ID of the current root is temporarily stored in `update_state`, + // but reset after all pending updates have been computed in order to + // avoid stale data hanging around. base::AutoReset<absl::optional<AXNodeID>> pending_root_id_resetter( &update_state->pending_root_id, - root_ ? absl::optional<AXNodeID>{root_->id()} : absl::nullopt); + root_ ? absl::make_optional<AXNodeID>(root_->id()) : absl::nullopt); + + if (update.has_tree_data && data_ != update.tree_data) { + update_state->old_tree_data = data_; + update_state->new_tree_data = update.tree_data; + } // We distinguish between updating the root, e.g. changing its children or // some of its attributes, or replacing the root completely. If the root is
diff --git a/ui/accessibility/ax_tree.h b/ui/accessibility/ax_tree.h index 1a836fbd..dcbeb5ca 100644 --- a/ui/accessibility/ax_tree.h +++ b/ui/accessibility/ax_tree.h
@@ -105,7 +105,9 @@ // should not be trusted any longer. virtual bool Unserialize(const AXTreeUpdate& update); - virtual void UpdateData(const AXTreeData& data); + // Used by tests to update the tree data without changing any of the nodes in + // the tree, notifying all tree observers in the process. + virtual void UpdateDataForTesting(const AXTreeData& data); // Convert any rectangle from the local coordinate space of one node in // the tree, to bounds in the coordinate space of the tree.
diff --git a/ui/accessibility/platform/test_ax_node_wrapper.cc b/ui/accessibility/platform/test_ax_node_wrapper.cc index cbe632fb..aab1b98c 100644 --- a/ui/accessibility/platform/test_ax_node_wrapper.cc +++ b/ui/accessibility/platform/test_ax_node_wrapper.cc
@@ -444,7 +444,7 @@ new_tree_data.sel_focus_object_id = focus_node_id; new_tree_data.sel_focus_offset = focus_offset; - tree_->UpdateData(new_tree_data); + tree_->UpdateDataForTesting(new_tree_data); } bool TestAXNodeWrapper::IsTable() const {
diff --git a/ui/base/ui_base_features.cc b/ui/base/ui_base_features.cc index b183e79..88ddc1c 100644 --- a/ui/base/ui_base_features.cc +++ b/ui/base/ui_base_features.cc
@@ -142,9 +142,12 @@ #endif }; +#if defined(OS_WIN) || defined(OS_ANDROID) +const base::Feature kElasticOverscroll = {"ElasticOverscroll", + base::FEATURE_DISABLED_BY_DEFAULT}; +#endif // defined(OS_WIN) || defined(OS_ANDROID) + #if defined(OS_WIN) -const base::Feature kElasticOverscrollWin = {"ElasticOverscrollWin", - base::FEATURE_DISABLED_BY_DEFAULT}; // Enables InputPane API for controlling on screen keyboard. const base::Feature kInputPaneOnScreenKeyboard = { @@ -177,20 +180,6 @@ } #endif // defined(OS_CHROMEOS) -#if defined(OS_WIN) || defined(OS_APPLE) || defined(OS_LINUX) || \ - defined(OS_CHROMEOS) -// Enables stylus appearing as touch when in contact with digitizer. -const base::Feature kDirectManipulationStylus = { - "DirectManipulationStylus", -#if defined(OS_WIN) - base::FEATURE_ENABLED_BY_DEFAULT -#else - base::FEATURE_DISABLED_BY_DEFAULT -#endif -}; -#endif // defined(OS_WIN) || defined(OS_APPLE) || defined(OS_LINUX) || - // defined(OS_CHROMEOS) - // Enables forced colors mode for web content. const base::Feature kForcedColors{"ForcedColors", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/ui/base/ui_base_features.h b/ui/base/ui_base_features.h index 7e2ebc5..48fc88f 100644 --- a/ui/base/ui_base_features.h +++ b/ui/base/ui_base_features.h
@@ -44,12 +44,15 @@ COMPONENT_EXPORT(UI_BASE_FEATURES) bool IsUiGpuRasterizationEnabled(); +#if defined(OS_WIN) || defined(OS_ANDROID) +COMPONENT_EXPORT(UI_BASE_FEATURES) +extern const base::Feature kElasticOverscroll; +#endif // defined(OS_WIN) || defined(OS_ANDROID) + #if defined(OS_WIN) COMPONENT_EXPORT(UI_BASE_FEATURES) extern const base::Feature kCalculateNativeWinOcclusion; COMPONENT_EXPORT(UI_BASE_FEATURES) -extern const base::Feature kElasticOverscrollWin; -COMPONENT_EXPORT(UI_BASE_FEATURES) extern const base::Feature kInputPaneOnScreenKeyboard; COMPONENT_EXPORT(UI_BASE_FEATURES) extern const base::Feature kPointerEventsForTouch; @@ -71,13 +74,6 @@ bool IsImprovedKeyboardShortcutsEnabled(); #endif // defined(OS_CHROMEOS) -#if defined(OS_WIN) || defined(OS_APPLE) || defined(OS_LINUX) || \ - defined(OS_CHROMEOS) -COMPONENT_EXPORT(UI_BASE_FEATURES) -extern const base::Feature kDirectManipulationStylus; -#endif // defined(OS_WIN) || defined(OS_APPLE) || defined(OS_LINUX) || - // defined(OS_CHROMEOS) - // Used to enable forced colors mode for web content. COMPONENT_EXPORT(UI_BASE_FEATURES) extern const base::Feature kForcedColors; COMPONENT_EXPORT(UI_BASE_FEATURES) bool IsForcedColorsEnabled();
diff --git a/ui/base/ui_features.gni b/ui/base/ui_features.gni index c664f73..7865a56 100644 --- a/ui/base/ui_features.gni +++ b/ui/base/ui_features.gni
@@ -31,4 +31,4 @@ # AXPlatformNode to implement a native C++ API, instead it bridges to a Java API. has_platform_accessibility_support = has_native_accessibility || is_android -enable_hidpi = is_mac || is_win || is_linux || is_chromeos || is_ios +enable_hidpi = !is_android
diff --git a/ui/events/ozone/evdev/event_device_info.cc b/ui/events/ozone/evdev/event_device_info.cc index 067929d..6347457 100644 --- a/ui/events/ozone/evdev/event_device_info.cc +++ b/ui/events/ozone/evdev/event_device_info.cc
@@ -70,6 +70,11 @@ {0x413c, 0x81d5}, // Dell Active Pen PN579X }; +// Note: this is not SteelSeries's actual VID; the Stratus Duo just reports it +// incorrectly over Bluetooth. +const uint16_t kSteelSeriesStratusDuoBluetoothVendorId = 0x0111; +const uint16_t kSteelSeriesStratusDuoBluetoothProductId = 0x1431; + bool GetEventBits(int fd, const base::FilePath& path, unsigned int type, @@ -536,6 +541,13 @@ } bool EventDeviceInfo::HasMouse() const { + // The SteelSeries Stratus Duo claims to be a mouse over Bluetooth, preventing + // it from being set up as a gamepad correctly, so check for its vendor and + // product ID. (b/189491809) + if (input_id_.vendor == kSteelSeriesStratusDuoBluetoothVendorId && + input_id_.product == kSteelSeriesStratusDuoBluetoothProductId) { + return false; + } return HasRelXY() && !HasProp(INPUT_PROP_POINTING_STICK); }
diff --git a/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn b/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn index fbbf408..21de756 100644 --- a/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn +++ b/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn
@@ -551,7 +551,7 @@ "//ui/webui/resources/js/cr/ui:dialogs.m", "//ui/webui/resources/js/cr/ui:menu.m", "//ui/webui/resources/js/cr/ui:menu_item.m", - "//ui/webui/resources/js/cr/ui:splitter.m", + "//ui/webui/resources/js/cr/ui:splitter", ] visibility += [ "//ui/file_manager/file_manager/externs:command_handler_deps.m" ]
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js b/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js index 46fb47810..79f3888 100644 --- a/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js +++ b/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js
@@ -17,7 +17,7 @@ // #import {ImportCrostiniImageDialog} from './import_crostini_image_dialog.m.js'; // #import {DialogFooter} from './dialog_footer.m.js'; // #import {InstallLinuxPackageDialog} from './install_linux_package_dialog.m.js'; -// #import {Splitter} from 'chrome://resources/js/cr/ui/splitter.m.js'; +// #import {Splitter} from 'chrome://resources/js/cr/ui/splitter.js'; // #import {FilesMenuItem} from './files_menu.m.js'; // #import {decorate, define as crUiDefine} from 'chrome://resources/js/cr/ui.m.js'; // #import {MenuItem} from 'chrome://resources/js/cr/ui/menu_item.m.js';
diff --git a/ui/file_manager/file_manager/foreground/js/ui/table/BUILD.gn b/ui/file_manager/file_manager/foreground/js/ui/table/BUILD.gn index 0ebcc5c..b0de3a2c 100644 --- a/ui/file_manager/file_manager/foreground/js/ui/table/BUILD.gn +++ b/ui/file_manager/file_manager/foreground/js/ui/table/BUILD.gn
@@ -117,7 +117,7 @@ deps = [ "//ui/webui/resources/js:cr.m", "//ui/webui/resources/js/cr:event_target.m", - "//ui/webui/resources/js/cr/ui:splitter.m", + "//ui/webui/resources/js/cr/ui:splitter", ] extra_deps = [ ":modulize" ]
diff --git a/ui/file_manager/file_manager/foreground/js/ui/table/table_splitter.js b/ui/file_manager/file_manager/foreground/js/ui/table/table_splitter.js index 52d0ac4..8fdc3e4 100644 --- a/ui/file_manager/file_manager/foreground/js/ui/table/table_splitter.js +++ b/ui/file_manager/file_manager/foreground/js/ui/table/table_splitter.js
@@ -11,7 +11,7 @@ */ // clang-format off -// #import {Splitter} from 'chrome://resources/js/cr/ui/splitter.m.js'; +// #import {Splitter} from 'chrome://resources/js/cr/ui/splitter.js'; // #import {Table} from './table.m.js'; // #import {getPropertyDescriptor, dispatchSimpleEvent} from 'chrome://resources/js/cr.m.js'; // clang-format on
diff --git a/ui/gl/generate_bindings.py b/ui/gl/generate_bindings.py index 4f6e487b..0713478 100755 --- a/ui/gl/generate_bindings.py +++ b/ui/gl/generate_bindings.py
@@ -2923,7 +2923,6 @@ 'GLES2/gl2extchromium.h' ], [ "GL_ANGLE_robust_resource_initialization", - "GL_ANGLE_texture_rectangle", "GL_ARB_texture_swizzle", "GL_EXT_texture_swizzle", "GL_EXT_texture_format_BGRA8888",
diff --git a/ui/gl/gl_bindings_autogen_gl.cc b/ui/gl/gl_bindings_autogen_gl.cc index b3c6dc2..fe40cf0c 100644 --- a/ui/gl/gl_bindings_autogen_gl.cc +++ b/ui/gl/gl_bindings_autogen_gl.cc
@@ -307,8 +307,6 @@ gfx::HasExtension(extensions, "GL_ANGLE_semaphore_fuchsia"); ext.b_GL_ANGLE_texture_external_update = gfx::HasExtension(extensions, "GL_ANGLE_texture_external_update"); - ext.b_GL_ANGLE_texture_rectangle = - gfx::HasExtension(extensions, "GL_ANGLE_texture_rectangle"); ext.b_GL_ANGLE_translated_shader_source = gfx::HasExtension(extensions, "GL_ANGLE_translated_shader_source"); ext.b_GL_APPLE_fence = gfx::HasExtension(extensions, "GL_APPLE_fence");
diff --git a/ui/gl/gl_bindings_autogen_gl.h b/ui/gl/gl_bindings_autogen_gl.h index ec4f2ce..cf41327ad5 100644 --- a/ui/gl/gl_bindings_autogen_gl.h +++ b/ui/gl/gl_bindings_autogen_gl.h
@@ -1965,7 +1965,6 @@ bool b_GL_ANGLE_robust_resource_initialization; bool b_GL_ANGLE_semaphore_fuchsia; bool b_GL_ANGLE_texture_external_update; - bool b_GL_ANGLE_texture_rectangle; bool b_GL_ANGLE_translated_shader_source; bool b_GL_APPLE_fence; bool b_GL_APPLE_sync;
diff --git a/ui/gl/gl_stub_autogen_gl.h b/ui/gl/gl_stub_autogen_gl.h index 72a2fdf..84c2e018 100644 --- a/ui/gl/gl_stub_autogen_gl.h +++ b/ui/gl/gl_stub_autogen_gl.h
@@ -8,8 +8,8 @@ // clang-format -i -style=chromium filename // DO NOT EDIT! -#ifndef UI_GL_GL_STUB_AUTOGEN_H_ -#define UI_GL_GL_STUB_AUTOGEN_H_ +#ifndef UI_GL_GL_STUB_AUTOGEN_GL_H_ +#define UI_GL_GL_STUB_AUTOGEN_GL_H_ void glActiveShaderProgramFn(GLuint pipeline, GLuint program) override {} void glActiveTextureFn(GLenum texture) override {} @@ -1664,4 +1664,4 @@ GLsizei n, const GLint* box) override {} -#endif // UI_GL_GL_STUB_AUTOGEN_H_ \ No newline at end of file +#endif // UI_GL_GL_STUB_AUTOGEN_GL_H_
diff --git a/ui/gl/gl_utils.cc b/ui/gl/gl_utils.cc index 24a9f02..70fa53a 100644 --- a/ui/gl/gl_utils.cc +++ b/ui/gl/gl_utils.cc
@@ -33,10 +33,6 @@ #include "ui/gl/gl_implementation.h" // nogncheck #endif -#if defined(OS_MAC) -#include "ui/gl/gl_bindings.h" -#endif - namespace gl { // Used by chrome://gpucrash and gpu_benchmarking_extension's @@ -190,24 +186,4 @@ } #endif // defined(USE_X11) || BUILDFLAG(OZONE_PLATFORM_X11) -#if defined(OS_MAC) - -ScopedEnableTextureRectangleInShaderCompiler:: - ScopedEnableTextureRectangleInShaderCompiler(gl::GLApi* gl_api) { - if (gl_api && !gl_api->glIsEnabledFn(GL_TEXTURE_RECTANGLE_ANGLE)) { - gl_api->glEnableFn(GL_TEXTURE_RECTANGLE_ANGLE); - gl_api_ = gl_api; - } else { - gl_api_ = nullptr; // Signal to the destructor that this is a no-op. - } -} - -ScopedEnableTextureRectangleInShaderCompiler:: - ~ScopedEnableTextureRectangleInShaderCompiler() { - if (gl_api_) - gl_api_->glDisableFn(GL_TEXTURE_RECTANGLE_ANGLE); -} - -#endif // defined(OS_MAC) - } // namespace gl
diff --git a/ui/gl/gl_utils.h b/ui/gl/gl_utils.h index b4fdf6d..0ac70a4a 100644 --- a/ui/gl/gl_utils.h +++ b/ui/gl/gl_utils.h
@@ -31,8 +31,6 @@ #endif namespace gl { -class GLApi; - GL_EXPORT void Crash(); GL_EXPORT void Hang(); @@ -69,31 +67,6 @@ gfx::GpuExtraInfo& info); #endif -// Temporarily allows compilation of shaders that use the -// ARB_texture_rectangle/ANGLE_texture_rectangle extension. We don't want to -// expose the extension to WebGL user shaders but we still need to use it for -// parts of the implementation on macOS. Note that the extension is always -// enabled on macOS and this only controls shader compilation. -class GL_EXPORT ScopedEnableTextureRectangleInShaderCompiler { - public: - ScopedEnableTextureRectangleInShaderCompiler( - const ScopedEnableTextureRectangleInShaderCompiler&) = delete; - ScopedEnableTextureRectangleInShaderCompiler& operator=( - const ScopedEnableTextureRectangleInShaderCompiler&) = delete; - - // This class is a no-op except on macOS. -#if !defined(OS_MAC) - explicit ScopedEnableTextureRectangleInShaderCompiler(gl::GLApi* gl_api) {} - -#else - explicit ScopedEnableTextureRectangleInShaderCompiler(gl::GLApi* gl_api); - ~ScopedEnableTextureRectangleInShaderCompiler(); - - private: - gl::GLApi* gl_api_; -#endif -}; - } // namespace gl #endif // UI_GL_GL_UTILS_H_
diff --git a/ui/gl/yuv_to_rgb_converter.cc b/ui/gl/yuv_to_rgb_converter.cc index ac354da..e6be831 100644 --- a/ui/gl/yuv_to_rgb_converter.cc +++ b/ui/gl/yuv_to_rgb_converter.cc
@@ -9,7 +9,6 @@ #include "base/strings/stringprintf.h" #include "ui/gfx/color_transform.h" #include "ui/gl/gl_helper.h" -#include "ui/gl/gl_utils.h" #include "ui/gl/gl_version_info.h" #include "ui/gl/scoped_binders.h" @@ -159,23 +158,17 @@ glGenFramebuffersEXT(1, &framebuffer_); - { - ScopedEnableTextureRectangleInShaderCompiler enable( - g_current_gl_driver->ext.b_GL_ANGLE_texture_rectangle - ? g_current_gl_context - : nullptr); - vertex_buffer_ = GLHelper::SetupQuadVertexBuffer(); - vertex_shader_ = GLHelper::LoadShader( - GL_VERTEX_SHADER, - base::StringPrintf("%s\n%s", vertex_header, kVertexShader).c_str()); - fragment_shader_ = GLHelper::LoadShader( - GL_FRAGMENT_SHADER, - base::StringPrintf("%s\n%s\n%s", fragment_header, - do_color_conversion.c_str(), - (is_rect ? kFragmentShaderRect : kFragmentShader2D)) - .c_str()); - program_ = GLHelper::SetupProgram(vertex_shader_, fragment_shader_); - } + vertex_buffer_ = GLHelper::SetupQuadVertexBuffer(); + vertex_shader_ = GLHelper::LoadShader( + GL_VERTEX_SHADER, + base::StringPrintf("%s\n%s", vertex_header, kVertexShader).c_str()); + fragment_shader_ = GLHelper::LoadShader( + GL_FRAGMENT_SHADER, + base::StringPrintf("%s\n%s\n%s", fragment_header, + do_color_conversion.c_str(), + (is_rect ? kFragmentShaderRect : kFragmentShader2D)) + .c_str()); + program_ = GLHelper::SetupProgram(vertex_shader_, fragment_shader_); ScopedUseProgram use_program(program_); size_location_ = glGetUniformLocation(program_, "a_texScale");
diff --git a/ui/strings/ui_strings.grd b/ui/strings/ui_strings.grd index 32b38281..89e1df1 100644 --- a/ui/strings/ui_strings.grd +++ b/ui/strings/ui_strings.grd
@@ -1153,6 +1153,9 @@ <message name="IDS_BROWSER_SHARING_OMNIBOX_SENDING_LABEL" desc="The label to be shown next to the omnibox icon when the message is being sent to the other device."> Sending... </message> + <message name="IDS_BROWSER_SHARING_OMNIBOX_SENT_LABEL" translateable="false" desc="The label to be shown next to the omnibox icon when the message is returned from the other device."> + Sent + </message> <message name="IDS_BROWSER_SHARING_DIALOG_DEVICE_SUBTITLE_LAST_ACTIVE_DAYS" desc="The label to be shown below the name of a valid device indicating the last active time of device,"> {DAYS, plural, =0 {Active today} =1 {Active 1 day ago} other {Active # days ago}} </message>
diff --git a/ui/views/controls/focus_ring.cc b/ui/views/controls/focus_ring.cc index 677bd52..699c15f 100644 --- a/ui/views/controls/focus_ring.cc +++ b/ui/views/controls/focus_ring.cc
@@ -28,7 +28,6 @@ namespace { DEFINE_UI_CLASS_PROPERTY_KEY(int, kFocusRingBackgroundColorId, -1) -DEFINE_UI_CLASS_PROPERTY_KEY(int, kFocusRingFallbackColorId, -1) bool IsPathUsable(const SkPath& path) { return !path.isEmpty() && (path.isRect(nullptr) || path.isOval(nullptr) || @@ -40,50 +39,36 @@ : ui::NativeTheme::kColorId_AlertSeverityHigh; } -View* GetViewForSubtreeColors(View* view) { +int GetBackgroundColorId(View* view) { int color_id_property = view->GetProperty(kFocusRingBackgroundColorId); if (color_id_property != -1) - return view; + return color_id_property; if (!view->parent()) - return nullptr; - return GetViewForSubtreeColors(view->parent()); + return -1; + return GetBackgroundColorId(view->parent()); +} + +SkColor GetBackgroundColor(View* view) { + int color_id = GetBackgroundColorId(view); + return color_id == -1 ? view->GetNativeTheme()->GetSystemColor( + ui::NativeTheme::kColorId_WindowBackground) + : view->GetThemeProvider()->GetColor(color_id); } SkColor GetColor(View* focus_ring, bool valid) { - const ui::NativeTheme* const native_theme = focus_ring->GetNativeTheme(); const SkColor default_color = - native_theme->GetSystemColor(ColorIdForValidity(valid)); + focus_ring->GetNativeTheme()->GetSystemColor(ColorIdForValidity(valid)); if (!valid) return default_color; - View* const fallback_color_view = GetViewForSubtreeColors(focus_ring); - - const SkColor background_color = - fallback_color_view - ? focus_ring->GetThemeProvider()->GetColor( - fallback_color_view->GetProperty(kFocusRingBackgroundColorId)) - : focus_ring->GetNativeTheme()->GetSystemColor( - ui::NativeTheme::kColorId_WindowBackground); - - const SkColor focus_ring_color = - color_utils::PickGoogleColor(default_color, background_color, - color_utils::kMinimumVisibleContrastRatio); - - // If the Google color is contrasty enough, use it. - if (color_utils::GetContrastRatio(focus_ring_color, background_color) > - color_utils::kMinimumVisibleContrastRatio) { - return focus_ring_color; - } - - return fallback_color_view - ? focus_ring->GetThemeProvider()->GetColor( - fallback_color_view->GetProperty(kFocusRingFallbackColorId)) - : focus_ring_color; + return color_utils::PickGoogleColor( + default_color, GetBackgroundColor(focus_ring), + color_utils::kMinimumVisibleContrastRatio); } double GetCornerRadius() { - double thickness = PlatformStyle::kFocusHaloThickness / 2.f; + const double thickness = PlatformStyle::kFocusHaloThickness / 2.f; return FocusableBorder::kCornerRadiusDp + thickness; } @@ -120,11 +105,9 @@ return parent->AddChildView(std::move(ring)); } -void FocusRing::SetColorContextForSubtree(View* view, - int background_color_id, - int fallback_color_id) { +void FocusRing::SetBackgroundColorIdForSubtree(View* view, + int background_color_id) { view->SetProperty(kFocusRingBackgroundColorId, background_color_id); - view->SetProperty(kFocusRingFallbackColorId, fallback_color_id); } FocusRing::~FocusRing() = default;
diff --git a/ui/views/controls/focus_ring.h b/ui/views/controls/focus_ring.h index b576d27..3c50c76 100644 --- a/ui/views/controls/focus_ring.h +++ b/ui/views/controls/focus_ring.h
@@ -38,16 +38,19 @@ static FocusRing* Install(View* parent); // Configures `view` so that FocusRings under it are aware of the background - // they are painted against. If the default color can't be made to contrast - // against `background_color_id` then `fallback_color_id` will be used. + // they are painted against. Unless the color of the FocusRing has been + // explicitly set, a color will be chosen that contrasts well against + // `background_color_id`. // Warning: The FocusRing ThemeProvider is queried for these IDs, do not use // NativeTheme color IDs here. // WARNING: This is temporary shenanigans to solve an accessibility problem. // DO NOT COPY this pattern or its implementation to other places in its // current state. - static void SetColorContextForSubtree(View* view, - int background_color_id, - int fallback_color_id); + // TODO(pbos): This seems not directly related to the FocusRing anymore, + // perhaps we could inform the view of what background color it's being + // painted onto orthogonally to how FocusRing uses it. + static void SetBackgroundColorIdForSubtree(View* view, + int background_color_id); ~FocusRing() override;
diff --git a/ui/views/controls/webview/web_dialog_view.cc b/ui/views/controls/webview/web_dialog_view.cc index cd3f3c8..606f82c 100644 --- a/ui/views/controls/webview/web_dialog_view.cc +++ b/ui/views/controls/webview/web_dialog_view.cc
@@ -110,6 +110,15 @@ //////////////////////////////////////////////////////////////////////////////// // WebDialogView, views::View implementation: +void WebDialogView::AddedToWidget() { + gfx::RoundedCornersF corner_radii( + delegate_ && delegate_->GetWebDialogFrameKind() == + WebDialogDelegate::FrameKind::kDialog + ? GetCornerRadius() + : 0); + web_view_->holder()->SetCornerRadii(corner_radii); +} + gfx::Size WebDialogView::CalculatePreferredSize() const { gfx::Size out; if (delegate_)
diff --git a/ui/views/controls/webview/web_dialog_view.h b/ui/views/controls/webview/web_dialog_view.h index 96896f5..978155ad 100644 --- a/ui/views/controls/webview/web_dialog_view.h +++ b/ui/views/controls/webview/web_dialog_view.h
@@ -18,8 +18,8 @@ #include "ui/views/controls/webview/unhandled_keyboard_event_handler.h" #include "ui/views/controls/webview/webview.h" #include "ui/views/controls/webview/webview_export.h" -#include "ui/views/widget/widget_delegate.h" #include "ui/views/window/client_view.h" +#include "ui/views/window/dialog_delegate.h" #include "ui/web_dialogs/web_dialog_delegate.h" #include "ui/web_dialogs/web_dialog_web_contents_delegate.h" @@ -74,7 +74,7 @@ class WEBVIEW_EXPORT WebDialogView : public ClientView, public ui::WebDialogWebContentsDelegate, public ui::WebDialogDelegate, - public WidgetDelegate { + public DialogDelegate { public: METADATA_HEADER(WebDialogView); @@ -91,6 +91,7 @@ content::WebContents* web_contents(); // ClientView: + void AddedToWidget() override; gfx::Size CalculatePreferredSize() const override; gfx::Size GetMinimumSize() const override; bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
diff --git a/ui/views/controls/webview/webview.h b/ui/views/controls/webview/webview.h index 1bb2399..71883873 100644 --- a/ui/views/controls/webview/webview.h +++ b/ui/views/controls/webview/webview.h
@@ -144,11 +144,6 @@ content::RenderFrameHost* new_host) override; void DidToggleFullscreenModeForTab(bool entered_fullscreen, bool will_cause_resize) override; - // Workaround for MSVC++ linker bug/feature that requires - // instantiation of the inline IPC::Listener methods in all translation units. - void OnChannelConnected(int32_t peer_id) override {} - void OnChannelError() override {} - void OnBadMessageReceived(const IPC::Message& message) override {} void OnWebContentsFocused( content::RenderWidgetHost* render_widget_host) override; void AXTreeIDForMainFrameHasChanged() override;
diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc index aabbdffa0..a221915d 100644 --- a/ui/views/win/hwnd_message_handler.cc +++ b/ui/views/win/hwnd_message_handler.cc
@@ -415,9 +415,7 @@ is_first_nccalc_(true), menu_depth_(0), id_generator_(0), - pen_processor_( - &id_generator_, - base::FeatureList::IsEnabled(::features::kDirectManipulationStylus)), + pen_processor_(&id_generator_, true), touch_down_contexts_(0), last_mouse_hwheel_time_(0), dwm_transition_desired_(false),
diff --git a/ui/views/window/dialog_delegate.cc b/ui/views/window/dialog_delegate.cc index 7d8d1149..e3b8dcc 100644 --- a/ui/views/window/dialog_delegate.cc +++ b/ui/views/window/dialog_delegate.cc
@@ -420,6 +420,8 @@ if (GetModalType() == ui::MODAL_TYPE_WINDOW) return 2; #endif + if (params_.corner_radius) + return *params_.corner_radius; return LayoutProvider::Get()->GetCornerRadiusMetric(views::Emphasis::kMedium); }
diff --git a/ui/views/window/dialog_delegate.h b/ui/views/window/dialog_delegate.h index d0de3f3..47bf36d 100644 --- a/ui/views/window/dialog_delegate.h +++ b/ui/views/window/dialog_delegate.h
@@ -45,6 +45,8 @@ ~Params(); absl::optional<int> default_button = absl::nullopt; bool round_corners = true; + absl::optional<int> corner_radius = absl::nullopt; + bool draggable = false; // Whether to use the Views-styled frame (if true) or a platform-native @@ -203,6 +205,12 @@ void DialogModelChanged(); void set_use_round_corners(bool round) { params_.round_corners = round; } + void set_corner_radius(int corner_radius) { + params_.corner_radius = corner_radius; + } + const absl::optional<int> corner_radius() const { + return params_.corner_radius; + } void set_draggable(bool draggable) { params_.draggable = draggable; } bool draggable() const { return params_.draggable; } void set_use_custom_frame(bool use) { params_.custom_frame = use; }
diff --git a/ui/webui/resources/css/text_defaults.css b/ui/webui/resources/css/text_defaults.css index 33942fb..4724fdf 100644 --- a/ui/webui/resources/css/text_defaults.css +++ b/ui/webui/resources/css/text_defaults.css
@@ -15,11 +15,6 @@ * to an HTML string. * Otherwise its placeholders won't be expanded. */ -html { - /* TODO(dbeam): remove this soon. Prefer dir= in HTML. */ - direction: $i18n{textDirection}; -} - body { font-family: $i18nRaw{fontFamily}; font-size: $i18n{fontSize};
diff --git a/ui/webui/resources/css/text_defaults_md.css b/ui/webui/resources/css/text_defaults_md.css index a862419..d85fc32 100644 --- a/ui/webui/resources/css/text_defaults_md.css +++ b/ui/webui/resources/css/text_defaults_md.css
@@ -17,11 +17,6 @@ @import url(chrome://resources/css/roboto.css); -html { - /* TODO(dbeam): remove this soon. Prefer dir= in HTML. */ - direction: $i18n{textDirection}; -} - body { font-family: Roboto, $i18nRaw{fontFamily}; font-size: 81.25%;
diff --git a/ui/webui/resources/html/BUILD.gn b/ui/webui/resources/html/BUILD.gn index 0ede812..e2fe30ec 100644 --- a/ui/webui/resources/html/BUILD.gn +++ b/ui/webui/resources/html/BUILD.gn
@@ -32,7 +32,6 @@ "cr/ui/menu.html", "cr/ui/menu_item.html", "cr/ui/position_util.html", - "cr/ui/splitter.html", "cr/ui/store_client.html", "cr/ui/store.html", "event_tracker.html",
diff --git a/ui/webui/resources/html/cr/ui/splitter.html b/ui/webui/resources/html/cr/ui/splitter.html deleted file mode 100644 index 4397d22..0000000 --- a/ui/webui/resources/html/cr/ui/splitter.html +++ /dev/null
@@ -1,2 +0,0 @@ -<link rel="import" href="../../../html/cr/ui.html"> -<script src="../../../js/cr/ui/splitter.js"></script>
diff --git a/ui/webui/resources/js/cr/ui/BUILD.gn b/ui/webui/resources/js/cr/ui/BUILD.gn index 7cc6657d..bb7d672b 100644 --- a/ui/webui/resources/js/cr/ui/BUILD.gn +++ b/ui/webui/resources/js/cr/ui/BUILD.gn
@@ -38,6 +38,7 @@ in_files = [ "drag_wrapper.js", "focus_outline_manager.js", + "splitter.js", ] if (is_chromeos_ash) { @@ -62,7 +63,6 @@ "menu_item.js", "menu.js", "position_util.js", - "splitter.js", "store_client.js", "store.js", "tabs.js", @@ -86,7 +86,6 @@ "list.m.js", "list_selection_controller.m.js", "list_selection_model.m.js", - "splitter.m.js", "store_client.m.js", "store.m.js", "tabs.m.js", @@ -145,7 +144,6 @@ ":menu_button", ":menu_item", ":position_util", - ":splitter", ":store", ":store_client", ":tabs", @@ -302,13 +300,6 @@ deps = [ "../..:cr" ] } -js_library("splitter") { - deps = [ - "..:ui", - "../..:cr", - ] -} - js_library("store") { deps = [ "../..:cr" ] } @@ -359,7 +350,6 @@ "menu_button.js", "menu_item.js", "position_util.js", - "splitter.js", "store.js", "store_client.js", "tabs.js", @@ -392,7 +382,7 @@ ":menu_button.m", ":menu_item.m", ":position_util.m", - ":splitter.m", + ":splitter", ":store.m", ":store_client.m", ":tabs.m", @@ -606,13 +596,11 @@ extra_deps = [ ":modulize" ] } -js_library("splitter.m") { - sources = [ "$root_gen_dir/ui/webui/resources/js/cr/ui/splitter.m.js" ] +js_library("splitter") { deps = [ "..:ui.m", "../..:cr.m", ] - extra_deps = [ ":modulize" ] } js_library("store.m") {
diff --git a/ui/webui/resources/js/cr/ui/splitter.js b/ui/webui/resources/js/cr/ui/splitter.js index 7048e87c..1c7f07d8 100644 --- a/ui/webui/resources/js/cr/ui/splitter.js +++ b/ui/webui/resources/js/cr/ui/splitter.js
@@ -18,233 +18,226 @@ * */ -// #import {define as crUiDefine} from '../ui.m.js'; -// #import {dispatchSimpleEvent} from '../../cr.m.js'; +import {dispatchSimpleEvent} from '../../cr.m.js'; +import {define as crUiDefine} from '../ui.m.js'; -cr.define('cr.ui', function() { +/** + * Creates a new splitter element. + * @param {Object=} opt_propertyBag Optional properties. + * @constructor + * @extends {HTMLDivElement} + */ +export const Splitter = crUiDefine('div'); + +Splitter.prototype = { + __proto__: HTMLDivElement.prototype, + /** - * Creates a new splitter element. - * @param {Object=} opt_propertyBag Optional properties. - * @constructor - * @extends {HTMLDivElement} + * Initializes the element. */ - /* #export */ const Splitter = cr.ui.define('div'); + decorate() { + this.addEventListener('mousedown', this.handleMouseDown_.bind(this), true); + this.addEventListener( + 'touchstart', this.handleTouchStart_.bind(this), true); + this.resizeNextElement_ = false; + }, - Splitter.prototype = { - __proto__: HTMLDivElement.prototype, + /** + * @param {boolean} resizeNext True if resize the next element. + * By default, splitter resizes previous (left) element. + */ + set resizeNextElement(resizeNext) { + this.resizeNextElement_ = resizeNext; + }, - /** - * Initializes the element. - */ - decorate() { - this.addEventListener( - 'mousedown', this.handleMouseDown_.bind(this), true); - this.addEventListener( - 'touchstart', this.handleTouchStart_.bind(this), true); - this.resizeNextElement_ = false; - }, - - /** - * @param {boolean} resizeNext True if resize the next element. - * By default, splitter resizes previous (left) element. - */ - set resizeNextElement(resizeNext) { - this.resizeNextElement_ = resizeNext; - }, - - /** - * Starts the dragging of the splitter. Adds listeners for mouse or touch - * events and calls splitter drag start handler. - * @param {number} clientX X position of the mouse or touch event that - * started the drag. - * @param {boolean} isTouchEvent True if the drag started by touch event. - */ - startDrag(clientX, isTouchEvent) { - if (this.handlers_) { - console.log('Concurent drags'); - this.endDrag_(); - } - if (isTouchEvent) { - const endDragBound = this.endDrag_.bind(this); - this.handlers_ = { - 'touchmove': this.handleTouchMove_.bind(this), - 'touchend': endDragBound, - 'touchcancel': endDragBound, - - // Another touch start (we somehow missed touchend or touchcancel). - 'touchstart': endDragBound, - }; - } else { - this.handlers_ = { - 'mousemove': this.handleMouseMove_.bind(this), - 'mouseup': this.handleMouseUp_.bind(this), - }; - } - - const doc = this.ownerDocument; - - // Use capturing events on the document to get events when the mouse - // leaves the document. - for (const eventType in this.handlers_) { - doc.addEventListener(eventType, this.handlers_[eventType], true); - } - - this.startX_ = clientX; - this.handleSplitterDragStart(); - }, - - /** - * Ends the dragging of the splitter. Removes listeners set in startDrag - * and calls splitter drag end handler. - * @private - */ - endDrag_() { - const doc = this.ownerDocument; - for (const eventType in this.handlers_) { - doc.removeEventListener(eventType, this.handlers_[eventType], true); - } - this.handlers_ = null; - this.handleSplitterDragEnd(); - }, - - /** - * @return {Element} - * @private - */ - getResizeTarget_() { - return this.resizeNextElement_ ? this.nextElementSibling : - this.previousElementSibling; - }, - - /** - * Calculate width to resize target element. - * @param {number} deltaX horizontal drag amount - * @return {number} - * @private - */ - calcDeltaX_(deltaX) { - return this.resizeNextElement_ ? -deltaX : deltaX; - }, - - /** - * Handles the mousedown event which starts the dragging of the splitter. - * @param {!Event} e The mouse event. - * @private - */ - handleMouseDown_(e) { - e = /** @type {!MouseEvent} */ (e); - if (e.button) { - return; - } - this.startDrag(e.clientX, false); - // Default action is to start selection and to move focus. - e.preventDefault(); - }, - - /** - * Handles the touchstart event which starts the dragging of the splitter. - * @param {!Event} e The touch event. - * @private - */ - handleTouchStart_(e) { - e = /** @type {!TouchEvent} */ (e); - if (e.touches.length === 1) { - this.startDrag(e.touches[0].clientX, true); - e.preventDefault(); - } - }, - - /** - * Handles the mousemove event which moves the splitter as the user moves - * the mouse. - * @param {!MouseEvent} e The mouse event. - * @private - */ - handleMouseMove_(e) { - this.handleMove_(e.clientX); - }, - - /** - * Handles the touch move event. - * @param {!TouchEvent} e The touch event. - */ - handleTouchMove_(e) { - if (e.touches.length === 1) { - this.handleMove_(e.touches[0].clientX); - } - }, - - /** - * Common part of handling mousemove and touchmove. Calls splitter drag - * move handler. - * @param {number} clientX X position of the mouse or touch event. - * @private - */ - handleMove_(clientX) { - const rtl = - this.ownerDocument.defaultView.getComputedStyle(this).direction === - 'rtl'; - const dirMultiplier = rtl ? -1 : 1; - const deltaX = dirMultiplier * (clientX - this.startX_); - this.handleSplitterDragMove(deltaX); - }, - - /** - * Handles the mouse up event which ends the dragging of the splitter. - * @param {!MouseEvent} e The mouse event. - * @private - */ - handleMouseUp_(e) { + /** + * Starts the dragging of the splitter. Adds listeners for mouse or touch + * events and calls splitter drag start handler. + * @param {number} clientX X position of the mouse or touch event that + * started the drag. + * @param {boolean} isTouchEvent True if the drag started by touch event. + */ + startDrag(clientX, isTouchEvent) { + if (this.handlers_) { + console.log('Concurent drags'); this.endDrag_(); - }, + } + if (isTouchEvent) { + const endDragBound = this.endDrag_.bind(this); + this.handlers_ = { + 'touchmove': this.handleTouchMove_.bind(this), + 'touchend': endDragBound, + 'touchcancel': endDragBound, - /** - * Handles start of the splitter dragging. Saves current width of the - * element being resized. - */ - handleSplitterDragStart() { - // Use the computed width style as the base so that we can ignore what - // box sizing the element has. Add the difference between offset and - // client widths to account for any scrollbars. - const targetElement = this.getResizeTarget_(); - const doc = targetElement.ownerDocument; - this.startWidth_ = - parseFloat(doc.defaultView.getComputedStyle(targetElement).width) + - targetElement.offsetWidth - targetElement.clientWidth; + // Another touch start (we somehow missed touchend or touchcancel). + 'touchstart': endDragBound, + }; + } else { + this.handlers_ = { + 'mousemove': this.handleMouseMove_.bind(this), + 'mouseup': this.handleMouseUp_.bind(this), + }; + } - this.classList.add('splitter-active'); - }, + const doc = this.ownerDocument; - /** - * Handles splitter moves. Updates width of the element being resized. - * @param {number} deltaX The change of splitter horizontal position. - */ - handleSplitterDragMove(deltaX) { - const targetElement = this.getResizeTarget_(); - const newWidth = this.startWidth_ + this.calcDeltaX_(deltaX); - targetElement.style.width = newWidth + 'px'; - cr.dispatchSimpleEvent(this, 'dragmove'); - }, + // Use capturing events on the document to get events when the mouse + // leaves the document. + for (const eventType in this.handlers_) { + doc.addEventListener(eventType, this.handlers_[eventType], true); + } - /** - * Handles end of the splitter dragging. This fires a 'resize' event if the - * size changed. - */ - handleSplitterDragEnd() { - // Check if the size changed. - const targetElement = this.getResizeTarget_(); - const doc = targetElement.ownerDocument; - const computedWidth = - parseFloat(doc.defaultView.getComputedStyle(targetElement).width); - if (this.startWidth_ !== computedWidth) { - cr.dispatchSimpleEvent(this, 'resize'); - } + this.startX_ = clientX; + this.handleSplitterDragStart(); + }, - this.classList.remove('splitter-active'); - }, - }; + /** + * Ends the dragging of the splitter. Removes listeners set in startDrag + * and calls splitter drag end handler. + * @private + */ + endDrag_() { + const doc = this.ownerDocument; + for (const eventType in this.handlers_) { + doc.removeEventListener(eventType, this.handlers_[eventType], true); + } + this.handlers_ = null; + this.handleSplitterDragEnd(); + }, - // #cr_define_end - console.warn('crbug/1173575, non-JS module files deprecated.'); - return {Splitter: Splitter}; -}); + /** + * @return {Element} + * @private + */ + getResizeTarget_() { + return this.resizeNextElement_ ? this.nextElementSibling : + this.previousElementSibling; + }, + + /** + * Calculate width to resize target element. + * @param {number} deltaX horizontal drag amount + * @return {number} + * @private + */ + calcDeltaX_(deltaX) { + return this.resizeNextElement_ ? -deltaX : deltaX; + }, + + /** + * Handles the mousedown event which starts the dragging of the splitter. + * @param {!Event} e The mouse event. + * @private + */ + handleMouseDown_(e) { + e = /** @type {!MouseEvent} */ (e); + if (e.button) { + return; + } + this.startDrag(e.clientX, false); + // Default action is to start selection and to move focus. + e.preventDefault(); + }, + + /** + * Handles the touchstart event which starts the dragging of the splitter. + * @param {!Event} e The touch event. + * @private + */ + handleTouchStart_(e) { + e = /** @type {!TouchEvent} */ (e); + if (e.touches.length === 1) { + this.startDrag(e.touches[0].clientX, true); + e.preventDefault(); + } + }, + + /** + * Handles the mousemove event which moves the splitter as the user moves + * the mouse. + * @param {!MouseEvent} e The mouse event. + * @private + */ + handleMouseMove_(e) { + this.handleMove_(e.clientX); + }, + + /** + * Handles the touch move event. + * @param {!TouchEvent} e The touch event. + */ + handleTouchMove_(e) { + if (e.touches.length === 1) { + this.handleMove_(e.touches[0].clientX); + } + }, + + /** + * Common part of handling mousemove and touchmove. Calls splitter drag + * move handler. + * @param {number} clientX X position of the mouse or touch event. + * @private + */ + handleMove_(clientX) { + const rtl = + this.ownerDocument.defaultView.getComputedStyle(this).direction === + 'rtl'; + const dirMultiplier = rtl ? -1 : 1; + const deltaX = dirMultiplier * (clientX - this.startX_); + this.handleSplitterDragMove(deltaX); + }, + + /** + * Handles the mouse up event which ends the dragging of the splitter. + * @param {!MouseEvent} e The mouse event. + * @private + */ + handleMouseUp_(e) { + this.endDrag_(); + }, + + /** + * Handles start of the splitter dragging. Saves current width of the + * element being resized. + */ + handleSplitterDragStart() { + // Use the computed width style as the base so that we can ignore what + // box sizing the element has. Add the difference between offset and + // client widths to account for any scrollbars. + const targetElement = this.getResizeTarget_(); + const doc = targetElement.ownerDocument; + this.startWidth_ = + parseFloat(doc.defaultView.getComputedStyle(targetElement).width) + + targetElement.offsetWidth - targetElement.clientWidth; + + this.classList.add('splitter-active'); + }, + + /** + * Handles splitter moves. Updates width of the element being resized. + * @param {number} deltaX The change of splitter horizontal position. + */ + handleSplitterDragMove(deltaX) { + const targetElement = this.getResizeTarget_(); + const newWidth = this.startWidth_ + this.calcDeltaX_(deltaX); + targetElement.style.width = newWidth + 'px'; + dispatchSimpleEvent(this, 'dragmove'); + }, + + /** + * Handles end of the splitter dragging. This fires a 'resize' event if the + * size changed. + */ + handleSplitterDragEnd() { + // Check if the size changed. + const targetElement = this.getResizeTarget_(); + const doc = targetElement.ownerDocument; + const computedWidth = + parseFloat(doc.defaultView.getComputedStyle(targetElement).width); + if (this.startWidth_ !== computedWidth) { + dispatchSimpleEvent(this, 'resize'); + } + + this.classList.remove('splitter-active'); + }, +};
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/ProfileImpl.java b/weblayer/browser/java/org/chromium/weblayer_private/ProfileImpl.java index 7e22d97..e65abe977 100644 --- a/weblayer/browser/java/org/chromium/weblayer_private/ProfileImpl.java +++ b/weblayer/browser/java/org/chromium/weblayer_private/ProfileImpl.java
@@ -78,7 +78,7 @@ // Normal profiles have restrictions on the name. if (!isIncognito && !name.matches("^\\w+$")) { throw new IllegalArgumentException( - "Non-incongito profiles names can only contain words: " + name); + "Non-incognito profiles names can only contain words: " + name); } mIsIncognito = isIncognito; mName = name;
diff --git a/weblayer/public/java/org/chromium/weblayer/WebLayer.java b/weblayer/public/java/org/chromium/weblayer/WebLayer.java index 1f22436..b281ba8 100644 --- a/weblayer/public/java/org/chromium/weblayer/WebLayer.java +++ b/weblayer/public/java/org/chromium/weblayer/WebLayer.java
@@ -514,7 +514,7 @@ /** * Creates a new WebLayer Fragment using the incognito profile with the specified name. * - * @param profileName The name of the incongito profile, null is mapped to an empty string. + * @param profileName The name of the incognito profile, null is mapped to an empty string. * @param persistenceId If non-null and not empty uniquely identifies the Browser for saving * state. *
diff --git a/weblayer/shell/android/shell_apk/AndroidManifest.xml b/weblayer/shell/android/shell_apk/AndroidManifest.xml index a7734e0..8b47b41 100644 --- a/weblayer/shell/android/shell_apk/AndroidManifest.xml +++ b/weblayer/shell/android/shell_apk/AndroidManifest.xml
@@ -7,6 +7,7 @@ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" package="org.chromium.weblayer.shell"> <application android:label="WebLayer shell" @@ -63,6 +64,14 @@ <meta-data android:name="org.chromium.weblayer.ENABLE_LOGGING_OF_JS_CONSOLE_MESSAGES" android:value="true"/> + <!-- Disables at startup init of Emoji2. See http://crbug.com/1205141 --> + <provider + android:authorities="org.chromium.weblayer.shell.androidx-startup" + android:name="androidx.startup.InitializationProvider" + android:exported="false" + tools:node="remove"> + </provider> + {% if weblayer_package is defined %} <meta-data android:name="org.chromium.weblayer.WebLayerPackage" android:value="{{ weblayer_package }}"/>