diff --git a/DEPS b/DEPS index 0663d3bc..2f9a0a2 100644 --- a/DEPS +++ b/DEPS
@@ -195,11 +195,11 @@ # 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': 'c4245f475be744ef91f55764b43d9dcaefe63d3b', + 'skia_revision': '5cfa7194d55e066477524b9edeacae9f6f2f758c', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': 'f8df7e0af9c692d5e3b3aa3aa4bd17aa686d4134', + 'v8_revision': '0c2650adcc949784fe629ebba7b7255ebe2b48f5', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling swarming_client # and whatever else without interference from each other. @@ -207,7 +207,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': 'd852ad24adc0c62ecb520835c1a835a42d3495e2', + 'angle_revision': '064bbf297d3702ff9b7ecfb8a81de7cc97a9a12b', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -266,7 +266,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': '467b0b16324b77b597e69237ae934f80118e55f6', + 'devtools_frontend_revision': '4c7d5ed732ae2027045d439fdfa76e831868a56e', # 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. @@ -302,7 +302,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. - 'spv_tools_revision': 'b4c4da3e76065180a7c5ce4ac6e5346e58833335', + 'spv_tools_revision': 'b8de4f57e9838c107bcbf17cf1e02608651c0e1d', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -875,7 +875,7 @@ # Build tools for Chrome OS. 'src/third_party/chromite': { - 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '39fbb307bc9a3f044427d0bdafafe45d4b12a040', + 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '12c6d67a42982a73417a0aa289244be2c5d350fe', 'condition': 'checkout_chromeos', }, @@ -895,7 +895,7 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '3bd3c99b4d5c884798648198ba7b01755214fd90', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'b93d82c4c5a812e4807852b9020fa0d28859aa69', 'src/third_party/devtools-frontend/src': Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), @@ -946,7 +946,7 @@ Var('chromium_git') + '/codecs/libgav1.git' + '@' + 'e46493b9148e0d1e63f55b5890bff503822616e5', 'src/third_party/glslang/src': - Var('chromium_git') + '/external/github.com/KhronosGroup/glslang.git' + '@' + '758b30727efce459aea368ac21b73ad10ebe9565', + Var('chromium_git') + '/external/github.com/KhronosGroup/glslang.git' + '@' + 'f257e0ea6b9aeab2dc7af3207ac6d29d2bbc01d0', 'src/third_party/google_toolbox_for_mac/src': { 'url': Var('chromium_git') + '/external/github.com/google/google-toolbox-for-mac.git' + '@' + Var('google_toolbox_for_mac_revision'), @@ -1248,7 +1248,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + '22e7f7a0d7d761f391e41ad2b9767e2251cb0749', + Var('android_git') + '/platform/external/perfetto.git' + '@' + '699711c7e3cdf2adf40f882b97b13f2fcb3e3737', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3', @@ -2433,6 +2433,17 @@ 'dep_type': 'cipd', }, + 'src/third_party/android_deps/libs/androidx_window_window': { + 'packages': [ + { + 'package': 'chromium/third_party/android_deps/libs/androidx_window_window', + 'version': 'version:1.0.0-alpha01-cr0', + }, + ], + 'condition': 'checkout_android', + 'dep_type': 'cipd', + }, + 'src/third_party/android_deps/libs/backport_util_concurrent_backport_util_concurrent': { 'packages': [ {
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd index 2e767f5..3a3b1e9 100644 --- a/ash/ash_strings.grd +++ b/ash/ash_strings.grd
@@ -2186,6 +2186,12 @@ <message name="IDS_ASH_LOGIN_SCREEN_UNVERIFIED_CODE_WARNING" desc="Message shown at the bottom of the login screen when the device has ran or is capable to run unverified code."> This device may contain apps that haven't been verified by Google. </message> + <message name="IDS_ASH_LOGIN_POD_TPM_LOCKED_ISSUE_WARNING" desc="Message shown as part of the TPM locked warning bubble when TPM is locked."> + Your Chromebook is locked due to a known issue. You will be able to sign in after: <ph name="TIME_LEFT">$1<ex>1 hour, 15 minutes, 10 seconds</ex></ph>. + </message> + <message name="IDS_ASH_LOGIN_POD_TPM_LOCKED_ISSUE_DESCRIPTION" desc="Message shown as part of the TPM locked warning bubble when TPM is locked."> + Your Chromebook needs to stay on and connected to power during this time. Make sure the charger or adapter cables are completely plugged in, both to your Chromebook and the power outlet. Do not turn off your Chromebook. + </message> <!-- Multi-profiles intro dialog --> <message name="IDS_ASH_MULTIPROFILES_INTRO_HEADLINE" desc="Describes which feature multi-profiles intro dialog presents.">
diff --git a/ash/ash_strings_grd/IDS_ASH_LOGIN_POD_TPM_LOCKED_ISSUE_DESCRIPTION.png.sha1 b/ash/ash_strings_grd/IDS_ASH_LOGIN_POD_TPM_LOCKED_ISSUE_DESCRIPTION.png.sha1 new file mode 100644 index 0000000..954f11ab --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_LOGIN_POD_TPM_LOCKED_ISSUE_DESCRIPTION.png.sha1
@@ -0,0 +1 @@ +f51cff68354bd8a9f31e7c0bc42b520d6ae2b591 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_LOGIN_POD_TPM_LOCKED_ISSUE_WARNING.png.sha1 b/ash/ash_strings_grd/IDS_ASH_LOGIN_POD_TPM_LOCKED_ISSUE_WARNING.png.sha1 new file mode 100644 index 0000000..954f11ab --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_LOGIN_POD_TPM_LOCKED_ISSUE_WARNING.png.sha1
@@ -0,0 +1 @@ +f51cff68354bd8a9f31e7c0bc42b520d6ae2b591 \ No newline at end of file
diff --git a/ash/login/ui/lock_contents_view.cc b/ash/login/ui/lock_contents_view.cc index f48b2c2..7a39127 100644 --- a/ash/login/ui/lock_contents_view.cc +++ b/ash/login/ui/lock_contents_view.cc
@@ -1049,6 +1049,17 @@ } } +void LockContentsView::OnSetTpmLockedState(const AccountId& user, + bool is_locked, + base::TimeDelta time_left) { + LoginBigUserView* big_user = + TryToFindBigUser(user, false /*require_auth_active*/); + if (big_user && big_user->auth_user()) { + LayoutAuth(big_user, nullptr /*opt_to_hide*/, true /*animate*/); + big_user->auth_user()->SetTpmLockedState(is_locked, time_left); + } +} + void LockContentsView::OnTapToUnlockEnabledForUserChanged(const AccountId& user, bool enabled) { LockContentsView::UserState* state = FindStateForUser(user);
diff --git a/ash/login/ui/lock_contents_view.h b/ash/login/ui/lock_contents_view.h index 750e493c..e88f880 100644 --- a/ash/login/ui/lock_contents_view.h +++ b/ash/login/ui/lock_contents_view.h
@@ -172,6 +172,9 @@ void OnAuthDisabledForUser( const AccountId& user, const AuthDisabledData& auth_disabled_data) override; + void OnSetTpmLockedState(const AccountId& user, + bool is_locked, + base::TimeDelta time_left) override; void OnLockScreenNoteStateChanged(mojom::TrayActionState state) override; void OnTapToUnlockEnabledForUserChanged(const AccountId& user, bool enabled) override;
diff --git a/ash/login/ui/login_auth_user_view.cc b/ash/login/ui/login_auth_user_view.cc index 692d41f..e77e506 100644 --- a/ash/login/ui/login_auth_user_view.cc +++ b/ash/login/ui/login_auth_user_view.cc
@@ -34,6 +34,7 @@ #include "base/i18n/time_formatting.h" #include "base/memory/ptr_util.h" #include "base/strings/utf_string_conversions.h" +#include "base/time/time.h" #include "base/timer/timer.h" #include "chromeos/constants/chromeos_features.h" #include "components/user_manager/user.h" @@ -54,6 +55,7 @@ #include "ui/views/border.h" #include "ui/views/controls/button/md_text_button.h" #include "ui/views/controls/highlight_path_generator.h" +#include "ui/views/controls/label.h" #include "ui/views/layout/box_layout.h" #include "ui/views/layout/fill_layout.h" #include "ui/views/layout/flex_layout.h" @@ -123,6 +125,15 @@ constexpr int kDisabledAuthMessageContentsFontSizeDeltaDp = -1; constexpr int kDisabledAuthMessageRoundedCornerRadiusDp = 8; +constexpr int kLockedTpmMessageVerticalBorderDp = 16; +constexpr int kLockedTpmMessageHorizontalBorderDp = 16; +constexpr int kLockedTpmMessageChildrenSpacingDp = 4; +constexpr int kLockedTpmMessageWidthDp = 360; +constexpr int kLockedTpmMessageHeightDp = 108; +constexpr int kLockedTpmMessageIconSizeDp = 24; +constexpr int kLockedTpmMessageDeltaDp = 0; +constexpr int kLockedTpmMessageRoundedCornerRadiusDp = 8; + constexpr int kNonEmptyWidthDp = 1; // Returns an observer that will hide |view| when it fires. The observer will @@ -744,6 +755,88 @@ DISALLOW_COPY_AND_ASSIGN(DisabledAuthMessageView); }; +// The message shown to user when TPM is locked. +class LoginAuthUserView::LockedTpmMessageView : public views::View { + public: + LockedTpmMessageView() { + SetLayoutManager(std::make_unique<views::BoxLayout>( + views::BoxLayout::Orientation::kVertical, + gfx::Insets(kLockedTpmMessageVerticalBorderDp, + kLockedTpmMessageHorizontalBorderDp), + kLockedTpmMessageChildrenSpacingDp)); + SetPaintToLayer(); + layer()->SetFillsBoundsOpaquely(false); + SetPreferredSize( + gfx::Size(kLockedTpmMessageWidthDp, kLockedTpmMessageHeightDp)); + SetFocusBehavior(FocusBehavior::ALWAYS); + + auto message_icon = std::make_unique<views::ImageView>(); + message_icon->SetPreferredSize( + gfx::Size(kLockedTpmMessageIconSizeDp, kLockedTpmMessageIconSizeDp)); + message_icon->SetImage( + gfx::CreateVectorIcon(kLockScreenAlertIcon, SK_ColorWHITE)); + message_icon_ = AddChildView(std::move(message_icon)); + + message_warning_ = CreateLabel(); + message_description_ = CreateLabel(); + + // Set content. + base::string16 message_description = l10n_util::GetStringUTF16( + IDS_ASH_LOGIN_POD_TPM_LOCKED_ISSUE_DESCRIPTION); + message_description_->SetText(message_description); + } + + LockedTpmMessageView(const LockedTpmMessageView&) = delete; + LockedTpmMessageView& operator=(const LockedTpmMessageView&) = delete; + ~LockedTpmMessageView() override = default; + + // Set the parameters needed to render the message. + void SetRemainingTime(base::TimeDelta time_left) { + base::string16 time_left_message; + if (base::TimeDurationFormatWithSeconds( + time_left, base::DurationFormatWidth::DURATION_WIDTH_WIDE, + &time_left_message)) { + base::string16 message_warning = l10n_util::GetStringFUTF16( + IDS_ASH_LOGIN_POD_TPM_LOCKED_ISSUE_WARNING, time_left_message); + message_warning_->SetText(message_warning); + } + Layout(); + } + + // views::View: + void OnPaint(gfx::Canvas* canvas) override { + views::View::OnPaint(canvas); + + cc::PaintFlags flags; + flags.setStyle(cc::PaintFlags::kFill_Style); + flags.setColor( + PinRequestView::GetChildUserDialogColor(false /*using blur*/)); + canvas->DrawRoundRect(GetContentsBounds(), + kLockedTpmMessageRoundedCornerRadiusDp, flags); + } + void RequestFocus() override { message_warning_->RequestFocus(); } + + private: + views::Label* CreateLabel() { + auto label = std::make_unique<views::Label>(base::string16(), + views::style::CONTEXT_LABEL, + views::style::STYLE_PRIMARY); + label->SetFontList(gfx::FontList().Derive(kLockedTpmMessageDeltaDp, + gfx::Font::NORMAL, + gfx::Font::Weight::NORMAL)); + label->SetSubpixelRenderingEnabled(false); + label->SetAutoColorReadabilityEnabled(false); + label->SetEnabledColor(SK_ColorWHITE); + label->SetFocusBehavior(FocusBehavior::ALWAYS); + label->SetMultiLine(true); + return AddChildView(std::move(label)); + } + + views::Label* message_warning_; + views::Label* message_description_; + views::ImageView* message_icon_; +}; + struct LoginAuthUserView::AnimationState { explicit AnimationState(LoginAuthUserView* view) { non_pin_y_start_in_screen = view->GetBoundsInScreen().y(); @@ -884,6 +977,9 @@ auto disabled_auth_message = std::make_unique<DisabledAuthMessageView>(); disabled_auth_message_ = disabled_auth_message.get(); + auto locked_tpm_message_view = std::make_unique<LockedTpmMessageView>(); + locked_tpm_message_view_ = locked_tpm_message_view.get(); + auto fingerprint_view = std::make_unique<FingerprintView>(); fingerprint_view_ = fingerprint_view.get(); @@ -904,6 +1000,9 @@ auto wrapped_disabled_auth_message_view = login_views_utils::WrapViewForPreferredSize( std::move(disabled_auth_message)); + auto wrapped_locked_tpm_message_view = + login_views_utils::WrapViewForPreferredSize( + std::move(locked_tpm_message_view)); auto wrapped_user_view = login_views_utils::WrapViewForPreferredSize(std::move(user_view)); auto wrapped_pin_view = @@ -927,6 +1026,8 @@ AddChildView(std::move(wrapped_online_sign_in_message_view)); views::View* wrapped_disabled_auth_message_view_ptr = AddChildView(std::move(wrapped_disabled_auth_message_view)); + views::View* wrapped_locked_tpm_message_view_ptr = + AddChildView(std::move(wrapped_locked_tpm_message_view)); views::View* wrapped_pin_view_ptr = AddChildView(std::move(wrapped_pin_view)); views::View* wrapped_fingerprint_view_ptr = AddChildView(std::move(wrapped_fingerprint_view)); @@ -960,6 +1061,7 @@ add_padding(kDistanceFromTopOfBigUserViewToUserIconDp); add_view(wrapped_user_view_ptr); add_view(wrapped_padding_below_user_view_ptr); + add_view(wrapped_locked_tpm_message_view_ptr); add_view(wrapped_password_view_ptr); add_view(wrapped_online_sign_in_message_view_ptr); add_view(wrapped_disabled_auth_message_view_ptr); @@ -992,13 +1094,17 @@ bool has_challenge_response = HasAuthMethod(AUTH_CHALLENGE_RESPONSE); bool auth_disabled = HasAuthMethod(AUTH_DISABLED); - bool hide_auth = auth_disabled || force_online_sign_in; + bool hide_auth = auth_disabled || force_online_sign_in || tpm_is_locked_; online_sign_in_message_->SetVisible(force_online_sign_in); disabled_auth_message_->SetVisible(auth_disabled); - if (auth_disabled) + if (auth_disabled && !tpm_is_locked_) disabled_auth_message_->RequestFocus(); + locked_tpm_message_view_->SetVisible(tpm_is_locked_); + if (tpm_is_locked_) + locked_tpm_message_view_->RequestFocus(); + // Adjust the PIN keyboard visibility before the password textfield's one, so // that when both are about to be hidden the focus doesn't jump to the "1" // keyboard button, causing unexpected accessibility effects. @@ -1248,6 +1354,15 @@ Layout(); } +void LoginAuthUserView::SetTpmLockedState(bool is_locked, + base::TimeDelta time_left) { + if (is_locked) + locked_tpm_message_view_->SetRemainingTime(time_left); + tpm_is_locked_ = is_locked; + // Update auth methods which are available. + SetAuthMethods(auth_methods_, auth_metadata_); +} + const LoginUserInfo& LoginAuthUserView::current_user() const { return user_view_->current_user(); }
diff --git a/ash/login/ui/login_auth_user_view.h b/ash/login/ui/login_auth_user_view.h index e6006dfc..7852319 100644 --- a/ash/login/ui/login_auth_user_view.h +++ b/ash/login/ui/login_auth_user_view.h
@@ -9,6 +9,7 @@ #include <memory> #include "ash/ash_export.h" +#include "ash/login/ui/login_error_bubble.h" #include "ash/login/ui/login_password_view.h" #include "ash/login/ui/login_user_view.h" #include "ash/login/ui/non_accessible_view.h" @@ -156,6 +157,8 @@ // auth method is |AUTH_DISABLED|. void SetAuthDisabledMessage(const AuthDisabledData& auth_disabled_data); + void SetTpmLockedState(bool is_locked, base::TimeDelta time_left); + const LoginUserInfo& current_user() const; // Provides the view that should be the anchor to message bubbles. Either the @@ -176,6 +179,7 @@ class FingerprintView; class ChallengeResponseView; class DisabledAuthMessageView; + class LockedTpmMessageView; // Called when the user submits an auth method. Runs mojo call. void OnAuthSubmit(const base::string16& password); @@ -240,6 +244,7 @@ DisabledAuthMessageView* disabled_auth_message_ = nullptr; FingerprintView* fingerprint_view_ = nullptr; ChallengeResponseView* challenge_response_view_ = nullptr; + LockedTpmMessageView* locked_tpm_message_view_ = nullptr; // Padding below the user view. Grows when there isn't an input field // or smart card login. @@ -252,6 +257,8 @@ const OnAuthCallback on_auth_; const LoginUserView::OnTap on_tap_; + bool tpm_is_locked_ = false; + // Animation state that was cached from before a layout. Generated by // |CaptureStateForAnimationPreLayout| and consumed by // |ApplyAnimationPostLayout|.
diff --git a/ash/login/ui/login_data_dispatcher.cc b/ash/login/ui/login_data_dispatcher.cc index 22340cd..07e3555 100644 --- a/ash/login/ui/login_data_dispatcher.cc +++ b/ash/login/ui/login_data_dispatcher.cc
@@ -38,6 +38,11 @@ const AccountId& user, const AuthDisabledData& auth_disabled_data) {} +void LoginDataDispatcher::Observer::OnSetTpmLockedState( + const AccountId& user, + bool is_locked, + base::TimeDelta time_left) {} + void LoginDataDispatcher::Observer::OnTapToUnlockEnabledForUserChanged( const AccountId& user, bool enabled) {} @@ -154,6 +159,13 @@ observer.OnAuthDisabledForUser(account_id, auth_disabled_data); } +void LoginDataDispatcher::SetTpmLockedState(const AccountId& account_id, + bool is_locked, + base::TimeDelta time_left) { + for (auto& observer : observers_) + observer.OnSetTpmLockedState(account_id, is_locked, time_left); +} + void LoginDataDispatcher::SetTapToUnlockEnabledForUser(const AccountId& user, bool enabled) { for (auto& observer : observers_)
diff --git a/ash/login/ui/login_data_dispatcher.h b/ash/login/ui/login_data_dispatcher.h index f9a8211..e54ec78 100644 --- a/ash/login/ui/login_data_dispatcher.h +++ b/ash/login/ui/login_data_dispatcher.h
@@ -15,6 +15,7 @@ #include "ash/public/mojom/tray_action.mojom.h" #include "base/macros.h" #include "base/observer_list.h" +#include "base/time/time.h" namespace ash { @@ -76,6 +77,11 @@ const AccountId& user, const AuthDisabledData& auth_disabled_data); + // Called when TPM is locked. + virtual void OnSetTpmLockedState(const AccountId& user, + bool is_locked, + base::TimeDelta time_left); + // Called when the given user can click their pod to unlock. virtual void OnTapToUnlockEnabledForUserChanged(const AccountId& user, bool enabled); @@ -167,6 +173,9 @@ void EnableAuthForUser(const AccountId& account_id) override; void DisableAuthForUser(const AccountId& account_id, const AuthDisabledData& auth_disabled_data) override; + void SetTpmLockedState(const AccountId& user, + bool is_locked, + base::TimeDelta time_left) override; void SetTapToUnlockEnabledForUser(const AccountId& user, bool enabled) override; void ForceOnlineSignInForUser(const AccountId& user) override;
diff --git a/ash/public/cpp/BUILD.gn b/ash/public/cpp/BUILD.gn index 2ae7e8ec..5fcfe08 100644 --- a/ash/public/cpp/BUILD.gn +++ b/ash/public/cpp/BUILD.gn
@@ -117,6 +117,8 @@ "default_scale_factor_retriever.h", "desks_helper.cc", "desks_helper.h", + "esim_manager.cc", + "esim_manager.h", "fps_counter.cc", "fps_counter.h", "frame_header.cc", @@ -306,6 +308,7 @@ "//chromeos/constants", "//chromeos/dbus/power:power_manager_proto", "//chromeos/services/assistant/public/cpp", + "//chromeos/services/cellular_setup:in_process_esim_manager", "//chromeos/services/network_config:in_process_instance", "//components/prefs", "//components/sync:rest_of_sync", @@ -330,6 +333,7 @@ "//base", "//chromeos/components/security_token_pin", "//chromeos/services/assistant/public/mojom", + "//chromeos/services/cellular_setup/public/mojom", "//chromeos/services/network_config/public/mojom", "//components/arc/mojom:notifications", "//components/session_manager:base",
diff --git a/ash/public/cpp/esim_manager.cc b/ash/public/cpp/esim_manager.cc new file mode 100644 index 0000000..e23d6f8 --- /dev/null +++ b/ash/public/cpp/esim_manager.cc
@@ -0,0 +1,17 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/public/cpp/esim_manager.h" + +#include "chromeos/services/cellular_setup/in_process_esim_manager.h" + +namespace ash { + +void GetESimManager( + mojo::PendingReceiver<chromeos::cellular_setup::mojom::ESimManager> + receiver) { + chromeos::cellular_setup::BindToInProcessESimManager(std::move(receiver)); +} + +} // namespace ash
diff --git a/ash/public/cpp/esim_manager.h b/ash/public/cpp/esim_manager.h new file mode 100644 index 0000000..59645f7 --- /dev/null +++ b/ash/public/cpp/esim_manager.h
@@ -0,0 +1,20 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_PUBLIC_CPP_ESIM_MANAGER_H_ +#define ASH_PUBLIC_CPP_ESIM_MANAGER_H_ + +#include "ash/public/cpp/ash_public_export.h" +#include "chromeos/services/cellular_setup/public/mojom/esim_manager.mojom.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" + +namespace ash { + +ASH_PUBLIC_EXPORT void GetESimManager( + mojo::PendingReceiver<chromeos::cellular_setup::mojom::ESimManager> + receiver); + +} // namespace ash + +#endif // ASH_PUBLIC_CPP_ESIM_MANAGER_H_
diff --git a/ash/public/cpp/login_screen_model.h b/ash/public/cpp/login_screen_model.h index 9f72a49a5..0d0524431 100644 --- a/ash/public/cpp/login_screen_model.h +++ b/ash/public/cpp/login_screen_model.h
@@ -9,6 +9,7 @@ #include "ash/public/cpp/ash_public_export.h" #include "base/strings/string16.h" +#include "base/time/time.h" class AccountId; @@ -77,6 +78,10 @@ const AccountId& account_id, const AuthDisabledData& auth_disabled_data) = 0; + virtual void SetTpmLockedState(const AccountId& user, + bool is_locked, + base::TimeDelta time_left) = 0; + // Enables or disables the authentication type to tap-to-unlock for the user. virtual void SetTapToUnlockEnabledForUser(const AccountId& account_id, bool enabled) = 0;
diff --git a/ash/style/ash_color_provider.cc b/ash/style/ash_color_provider.cc index 00659488..01e6a33 100644 --- a/ash/style/ash_color_provider.cc +++ b/ash/style/ash_color_provider.cc
@@ -359,8 +359,8 @@ break; case ContentLayerType::kButtonLabelColorPrimary: case ContentLayerType::kButtonIconColorPrimary: - light_color = gfx::kGoogleRed900; - dark_color = gfx::kGoogleRed200; + light_color = gfx::kGoogleGrey900; + dark_color = gfx::kGoogleGrey200; break; case ContentLayerType::kSliderThumbColorDisabled: light_color = gfx::kGoogleGrey600;
diff --git a/base/OWNERS b/base/OWNERS index eeb4191..7555c11f 100644 --- a/base/OWNERS +++ b/base/OWNERS
@@ -5,6 +5,7 @@ dcheng@chromium.org fdoray@chromium.org gab@chromium.org +jdoerrie@chromium.org kylechar@chromium.org mark@chromium.org thakis@chromium.org @@ -34,7 +35,4 @@ # For TCMalloc tests: per-file security_unittest.cc=jln@chromium.org -# For Value: -per-file value*=jdoerrie@chromium.org - # COMPONENT: Internals>Core
diff --git a/base/process/kill.h b/base/process/kill.h index 9d33283b..b955870f 100644 --- a/base/process/kill.h +++ b/base/process/kill.h
@@ -84,12 +84,6 @@ int exit_code, const ProcessFilter* filter); -#if defined(OS_POSIX) -// Attempts to kill the process group identified by |process_group_id|. Returns -// true on success. -BASE_EXPORT bool KillProcessGroup(ProcessHandle process_group_id); -#endif // defined(OS_POSIX) - // Get the termination status of the process by interpreting the // circumstances of the child process' death. |exit_code| is set to // the status returned by waitpid() on POSIX, and from GetExitCodeProcess() on
diff --git a/base/process/kill_fuchsia.cc b/base/process/kill_fuchsia.cc index 1b7bbd6a..456033e5 100644 --- a/base/process/kill_fuchsia.cc +++ b/base/process/kill_fuchsia.cc
@@ -13,14 +13,6 @@ namespace base { -bool KillProcessGroup(ProcessHandle process_group_id) { - // |process_group_id| is really a job on Fuchsia. - zx_status_t status = zx_task_kill(process_group_id); - DLOG_IF(ERROR, status != ZX_OK) - << "unable to terminate job " << process_group_id; - return status == ZX_OK; -} - TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) { DCHECK(exit_code);
diff --git a/base/process/kill_posix.cc b/base/process/kill_posix.cc index 86d5096..0750d9a 100644 --- a/base/process/kill_posix.cc +++ b/base/process/kill_posix.cc
@@ -78,15 +78,6 @@ } // namespace -#if !defined(OS_NACL_NONSFI) -bool KillProcessGroup(ProcessHandle process_group_id) { - bool result = kill(-1 * process_group_id, SIGKILL) == 0; - if (!result) - DPLOG(ERROR) << "Unable to terminate process group " << process_group_id; - return result; -} -#endif // !defined(OS_NACL_NONSFI) - TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) { return GetTerminationStatusImpl(handle, false /* can_block */, exit_code); }
diff --git a/base/test/launcher/test_launcher.cc b/base/test/launcher/test_launcher.cc index 66c4c89c..1c3b097 100644 --- a/base/test/launcher/test_launcher.cc +++ b/base/test/launcher/test_launcher.cc
@@ -438,38 +438,17 @@ // Cleanup the data directory. CHECK(DeletePathRecursively(nested_data_path)); #elif defined(OS_POSIX) - -#if BUILDFLAG(CLANG_PROFILING) - // TODO(crbug.com/1094369): Remove this condition once the child process - // leaking bug is fixed. - // - // TODO(crbug.com/1095075): Make test launcher treat lingering child - // processes hard failures so that they can be detected and surfaced - // gracefully. - // - // When profiling is enabled, browser child processes take extra time to - // dump profiles, which means that lingering processes are much more likely - // to happen than non-profiling build. Therefore, on POSIX, in order to - // avoid polluting the machine state, ensure any child processes that the - // test might have created are cleaned up to avoid potential leaking even - // when tests have passed. On Windows, child processes are automatically - // cleaned up using JobObjects. - // - // On non-profiling build, when tests have passed, we don't clean up the - // lingering processes even when there are any, and the reason is that they - // usually indicate prod issues, letting them slip to the following test - // tasks and cause failures increses the chance of them being surfaced. + // It is not possible to waitpid() on any leaked sub-processes of the test + // batch process, since those are not direct children of this process. + // kill()ing the process-group will return a result indicating whether the + // group was found (i.e. processes were still running in it) or not (i.e. + // sub-processes had exited already). Unfortunately many tests (e.g. browser + // tests) have processes exit asynchronously, so checking the kill() result + // will report false failures. + // Unconditionally kill the process group, regardless of the batch exit-code + // until a better solution is available. kill(-1 * process.Handle(), SIGKILL); -#else - if (exit_code != 0) { - // On POSIX, in case the test does not exit cleanly, either due to a crash - // or due to it timing out, we need to clean up any child processes that - // it might have created. On Windows, child processes are automatically - // cleaned up using JobObjects. - KillProcessGroup(process.Handle()); - } -#endif -#endif +#endif // defined(OS_POSIX) GetLiveProcesses()->erase(process.Handle()); }
diff --git a/base/test/launcher/test_launcher_unittest.cc b/base/test/launcher/test_launcher_unittest.cc index bcf7df0..8e17f5fd 100644 --- a/base/test/launcher/test_launcher_unittest.cc +++ b/base/test/launcher/test_launcher_unittest.cc
@@ -708,12 +708,12 @@ TEST(MockUnitTests, DISABLED_CrashTest) { IMMEDIATE_CRASH(); } -// Basic test will not be reached with default batch size. +// Basic test will not be reached, due to the preceding crash in the same batch. TEST(MockUnitTests, DISABLED_NoRunTest) { ASSERT_TRUE(true); } -// Using TestLauncher to launch 3 simple unitests +// Using TestLauncher to launch 3 basic unitests // and validate the resulting json file. TEST_F(UnitTestLauncherDelegateTester, RunMockTests) { CommandLine command_line(CommandLine::ForCurrentProcess()->GetProgram());
diff --git a/base/trace_event/builtin_categories.h b/base/trace_event/builtin_categories.h index 732db68..b945977 100644 --- a/base/trace_event/builtin_categories.h +++ b/base/trace_event/builtin_categories.h
@@ -242,6 +242,7 @@ X(TRACE_DISABLED_BY_DEFAULT("v8.turbofan")) \ X(TRACE_DISABLED_BY_DEFAULT("v8.wasm.detailed")) \ X(TRACE_DISABLED_BY_DEFAULT("video_and_image_capture")) \ + X(TRACE_DISABLED_BY_DEFAULT("viz.gpu_composite_time")) \ X(TRACE_DISABLED_BY_DEFAULT("viz.debug.overlay_planes")) \ X(TRACE_DISABLED_BY_DEFAULT("viz.hit_testing_flow")) \ X(TRACE_DISABLED_BY_DEFAULT("viz.overdraw")) \
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1 index d9420410..464277b6 100644 --- a/build/fuchsia/linux.sdk.sha1 +++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@ -0.20200816.3.1 +0.20200817.2.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1 index d9420410..464277b6 100644 --- a/build/fuchsia/mac.sdk.sha1 +++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@ -0.20200816.3.1 +0.20200817.2.1
diff --git a/cc/animation/scroll_offset_animation_curve.cc b/cc/animation/scroll_offset_animation_curve.cc index 538fa280..8a67e0f 100644 --- a/cc/animation/scroll_offset_animation_curve.cc +++ b/cc/animation/scroll_offset_animation_curve.cc
@@ -294,19 +294,15 @@ gfx::ScrollOffset ScrollOffsetAnimationCurve::GetValue( base::TimeDelta t) const { - base::TimeDelta duration = total_animation_duration_ - last_retarget_; + const base::TimeDelta duration = total_animation_duration_ - last_retarget_; t -= last_retarget_; - if (duration.is_zero()) + if (duration.is_zero() || (t >= duration)) return target_value_; - if (t <= base::TimeDelta()) return initial_value_; - if (t >= duration) - return target_value_; - - double progress = timing_function_->GetValue(t / duration); + const double progress = timing_function_->GetValue(t / duration); return gfx::ScrollOffset( gfx::Tween::FloatValueBetween(progress, initial_value_.x(), target_value_.x()),
diff --git a/cc/input/scrollbar_animation_controller.cc b/cc/input/scrollbar_animation_controller.cc index 8e763e39..39d3ec0 100644 --- a/cc/input/scrollbar_animation_controller.cc +++ b/cc/input/scrollbar_animation_controller.cc
@@ -159,9 +159,8 @@ float ScrollbarAnimationController::AnimationProgressAtTime( base::TimeTicks now) { - base::TimeDelta delta = now - last_awaken_time_; - float progress = delta / fade_duration_; - return base::ClampToRange(progress, 0.0f, 1.0f); + const base::TimeDelta delta = now - last_awaken_time_; + return base::ClampToRange(float{delta / fade_duration_}, 0.0f, 1.0f); } void ScrollbarAnimationController::RunAnimationFrame(float progress) {
diff --git a/cc/input/single_scrollbar_animation_controller_thinning.cc b/cc/input/single_scrollbar_animation_controller_thinning.cc index 1d57f7e..9cc85ab 100644 --- a/cc/input/single_scrollbar_animation_controller_thinning.cc +++ b/cc/input/single_scrollbar_animation_controller_thinning.cc
@@ -98,9 +98,8 @@ if (thinning_duration_.is_zero()) return 1.0f; - base::TimeDelta delta = now - last_awaken_time_; - float progress = delta / thinning_duration_; - return base::ClampToRange(progress, 0.0f, 1.0f); + const base::TimeDelta delta = now - last_awaken_time_; + return base::ClampToRange(float{delta / thinning_duration_}, 0.0f, 1.0f); } void SingleScrollbarAnimationControllerThinning::RunAnimationFrame(
diff --git a/cc/input/snap_fling_curve.cc b/cc/input/snap_fling_curve.cc index e73bbfb..e63dba1 100644 --- a/cc/input/snap_fling_curve.cc +++ b/cc/input/snap_fling_curve.cc
@@ -81,7 +81,7 @@ const double current_frame = current_time / kFrameTime + 1; const double sum = first_delta_ * (1 - std::pow(kRatio, current_frame)) / (1 - kRatio); - return sum <= total_distance_ ? sum : total_distance_; + return std::min(sum, total_distance_); } gfx::Vector2dF SnapFlingCurve::GetScrollDelta(base::TimeTicks time_stamp) {
diff --git a/cc/metrics/video_playback_roughness_reporter.cc b/cc/metrics/video_playback_roughness_reporter.cc index 50f3d2a0..ac5e4d72 100644 --- a/cc/metrics/video_playback_roughness_reporter.cc +++ b/cc/metrics/video_playback_roughness_reporter.cc
@@ -8,6 +8,7 @@ #include "base/bind_helpers.h" #include "base/metrics/histogram_macros.h" +#include "base/numerics/ranges.h" #include "base/numerics/safe_conversions.h" #include "components/viz/common/quads/compositor_frame_metadata.h" @@ -31,7 +32,6 @@ constexpr int VideoPlaybackRoughnessReporter::kMaxWindowsBeforeSubmit; constexpr int VideoPlaybackRoughnessReporter::kMinWindowsBeforeSubmit; constexpr int VideoPlaybackRoughnessReporter::kPercentileToSubmit; -constexpr double VideoPlaybackRoughnessReporter::kDesiredWindowDuration; VideoPlaybackRoughnessReporter::VideoPlaybackRoughnessReporter( PlaybackRoughnessReportingCallback reporting_cb) @@ -73,10 +73,10 @@ } // Adjust frame window size to fit about 1 second of playback - int win_size = base::ClampRound(kDesiredWindowDuration * - info.intended_duration.value().ToHz()); - frames_window_size_ = std::max(kMinWindowSize, win_size); - frames_window_size_ = std::min(frames_window_size_, kMaxWindowSize); + const int win_size = + base::ClampRound(info.intended_duration.value().ToHz()); + frames_window_size_ = + base::ClampToRange(win_size, kMinWindowSize, kMaxWindowSize); } frames_.push_back(info);
diff --git a/cc/metrics/video_playback_roughness_reporter.h b/cc/metrics/video_playback_roughness_reporter.h index 820ac9f..ebced5e2 100644 --- a/cc/metrics/video_playback_roughness_reporter.h +++ b/cc/metrics/video_playback_roughness_reporter.h
@@ -81,13 +81,6 @@ static_assert(kPercentileToSubmit > 0 && kPercentileToSubmit < 100, "invalid percentile value"); - // Desired duration of ConsecutiveFramesWindow in seconds. - // This value and the video FPS are being used when calculating actual - // number of frames in the ConsecutiveFramesWindow. - // kMinWindowSize and kMaxWindowSize put bounds to the window length - // and superseed this value. - static constexpr double kDesiredWindowDuration = 1.0; - private: friend class VideoPlaybackRoughnessReporterTest; struct FrameInfo {
diff --git a/cc/test/animation_test_common.cc b/cc/test/animation_test_common.cc index 7e60848..562dcdbe 100644 --- a/cc/test/animation_test_common.cc +++ b/cc/test/animation_test_common.cc
@@ -4,6 +4,7 @@ #include "cc/test/animation_test_common.h" +#include <algorithm> #include <memory> #include <utility> @@ -231,9 +232,7 @@ } float FakeFloatTransition::GetValue(base::TimeDelta time) const { - double progress = time / duration_; - if (progress >= 1.0) - progress = 1.0; + const double progress = std::min(time / duration_, 1.0); return (1.0 - progress) * from_ + progress * to_; }
diff --git a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java index cb0100e4..5b61ad84 100644 --- a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java +++ b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java
@@ -406,6 +406,14 @@ pressBack(); onViewWaiting(withId(R.id.primary_tasks_surface_view)); + if (isInstantReturn() + && (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M + && Build.VERSION.SDK_INT < Build.VERSION_CODES.O)) { + // TODO(crbug.com/1092642): Fix androidx.test.espresso.PerformException issue when + // performing a single click on position: 0. See code below. + return; + } + OverviewModeBehaviorWatcher hideWatcher = TabUiTestHelper.createOverviewHideWatcher(mActivityTestRule.getActivity()); onView(allOf(withParent(withId( @@ -468,6 +476,14 @@ pressBack(); onViewWaiting(withId(R.id.primary_tasks_surface_view)); + if (isInstantReturn() + && (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M + && Build.VERSION.SDK_INT < Build.VERSION_CODES.O)) { + // TODO(crbug.com/1092642): Fix androidx.test.espresso.PerformException issue when + // performing a single click on position: 0. See code below. + return; + } + OverviewModeBehaviorWatcher hideWatcher = TabUiTestHelper.createOverviewHideWatcher(mActivityTestRule.getActivity()); onView(allOf(withParent(withId(
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/v2/FeedStreamSurface.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/v2/FeedStreamSurface.java index 0202327..3bb9186 100644 --- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/v2/FeedStreamSurface.java +++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/v2/FeedStreamSurface.java
@@ -174,6 +174,8 @@ * Clear all the data related to all surfaces. */ public static void clearAll() { + if (sSurfaces == null) return; + ArrayList<FeedStreamSurface> openSurfaces = new ArrayList<FeedStreamSurface>(); for (FeedStreamSurface surface : sSurfaces) { if (surface.isOpened()) openSurfaces.add(surface);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/QualityEnforcer.java b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/QualityEnforcer.java index 6b0515c..3dc9e27 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/QualityEnforcer.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/QualityEnforcer.java
@@ -24,6 +24,8 @@ import org.chromium.chrome.browser.customtabs.content.TabObserverRegistrar.CustomTabTabObserver; import org.chromium.chrome.browser.dependency_injection.ActivityScope; import org.chromium.chrome.browser.flags.ChromeFeatureList; +import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; +import org.chromium.chrome.browser.lifecycle.NativeInitObserver; import org.chromium.chrome.browser.tab.Tab; import org.chromium.content_public.browser.NavigationHandle; import org.chromium.net.NetError; @@ -44,7 +46,7 @@ * will crash. We should hold web apps to the same standard. */ @ActivityScope -public class QualityEnforcer { +public class QualityEnforcer implements NativeInitObserver { @VisibleForTesting static final String NOTIFY = "quality_enforcement.notify"; @VisibleForTesting @@ -58,6 +60,7 @@ private final CustomTabsConnection mConnection; private final CustomTabsSessionToken mSessionToken; private final ClientPackageNameProvider mClientPackageNameProvider; + private final BrowserServicesIntentDataProvider mIntentDataProvider; private final TrustedWebActivityUmaRecorder mUmaRecorder; private boolean mOriginVerified; @@ -104,19 +107,33 @@ }; @Inject - public QualityEnforcer(ChromeActivity<?> activity, TabObserverRegistrar tabObserverRegistrar, + public QualityEnforcer(ChromeActivity<?> activity, + ActivityLifecycleDispatcher lifecycleDispatcher, + TabObserverRegistrar tabObserverRegistrar, BrowserServicesIntentDataProvider intentDataProvider, CustomTabsConnection connection, Verifier verifier, ClientPackageNameProvider clientPackageNameProvider, TrustedWebActivityUmaRecorder umaRecorder) { mActivity = activity; mVerifier = verifier; - mConnection = connection; mSessionToken = intentDataProvider.getSession(); + mIntentDataProvider = intentDataProvider; + mConnection = connection; mClientPackageNameProvider = clientPackageNameProvider; mUmaRecorder = umaRecorder; // Initialize the value to true before the first navigation. mOriginVerified = true; tabObserverRegistrar.registerActivityTabObserver(mTabObserver); + lifecycleDispatcher.register(this); + } + + @Override + public void onFinishNativeInitialization() { + String url = mIntentDataProvider.getUrlToLoad(); + mVerifier.verify(url).then((verified) -> { + if (!verified) { + trigger(ViolationType.DIGITAL_ASSERTLINKS, mIntentDataProvider.getUrlToLoad(), 0); + } + }); } private void trigger(@ViolationType int type, String url, int httpStatusCode) { @@ -160,14 +177,20 @@ /* Get the localized string for toast message. */ private String getToastMessage(@ViolationType int type, String url, int httpStatusCode) { - if (type == ViolationType.ERROR_404 || type == ViolationType.ERROR_5XX) { - return ContextUtils.getApplicationContext().getString( - R.string.twa_quality_enforcement_violation_error, httpStatusCode, url); - } else if (type == ViolationType.UNAVAILABLE_OFFLINE) { - return ContextUtils.getApplicationContext().getString( - R.string.twa_quality_enforcement_violation_offline, url); + switch (type) { + case ViolationType.ERROR_404: + case ViolationType.ERROR_5XX: + return ContextUtils.getApplicationContext().getString( + R.string.twa_quality_enforcement_violation_error, httpStatusCode, url); + case ViolationType.UNAVAILABLE_OFFLINE: + return ContextUtils.getApplicationContext().getString( + R.string.twa_quality_enforcement_violation_offline, url); + case ViolationType.DIGITAL_ASSERTLINKS: + return ContextUtils.getApplicationContext().getString( + R.string.twa_quality_enforcement_violation_assert_link, url); + default: + return ""; } - return ""; } /* @@ -175,11 +198,16 @@ * the toast because this is used in TWA's crash message. */ private String toTwaCrashMessage(@ViolationType int type, String url, int httpStatusCode) { - if (type == ViolationType.ERROR_404 || type == ViolationType.ERROR_5XX) { - return httpStatusCode + " on " + url; - } else if (type == ViolationType.UNAVAILABLE_OFFLINE) { - return "Page unavailable offline: " + url; + switch (type) { + case ViolationType.ERROR_404: + case ViolationType.ERROR_5XX: + return httpStatusCode + " on " + url; + case ViolationType.UNAVAILABLE_OFFLINE: + return "Page unavailable offline: " + url; + case ViolationType.DIGITAL_ASSERTLINKS: + return "Digital assert links verification failed on " + url; + default: + return ""; } - return ""; } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/browserservices/QualityEnforcerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/browserservices/QualityEnforcerTest.java index 476931b..5fde3cc 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/browserservices/QualityEnforcerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/browserservices/QualityEnforcerTest.java
@@ -119,7 +119,30 @@ assertEquals(mErrorMessage, "Page unavailable offline: https://example.com/"); } + @Test + @MediumTest + public void notifiedDigitalAssertLinkFailed() throws TimeoutException { + launchNotVerify(mTestPage); + mCallbackHelper.waitForFirst(); + } + public void launch(String testPage) throws TimeoutException { + Intent intent = createTrustedWebActivityIntentWithCallback(testPage); + spoofVerification(PACKAGE_NAME, testPage); + createSession(intent, PACKAGE_NAME); + + mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent); + } + + public void launchNotVerify(String testPage) throws TimeoutException { + Intent intent = createTrustedWebActivityIntentWithCallback(testPage); + createSession(intent, PACKAGE_NAME); + + mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent); + } + + private Intent createTrustedWebActivityIntentWithCallback(String testPage) + throws TimeoutException { CustomTabsSession session = CustomTabsTestUtils.bindWithCallback(mCallback).session; Intent intent = new CustomTabsIntent.Builder(session).build().intent; intent.setComponent(new ComponentName( @@ -128,10 +151,6 @@ intent.setData(Uri.parse(testPage)); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtra(TrustedWebUtils.EXTRA_LAUNCH_AS_TRUSTED_WEB_ACTIVITY, true); - - spoofVerification(PACKAGE_NAME, testPage); - createSession(intent, PACKAGE_NAME); - - mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent); + return intent; } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetRenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetRenderTest.java index 2c5c0cc..ecd36543 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetRenderTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetRenderTest.java
@@ -10,6 +10,8 @@ import static org.mockito.MockitoAnnotations.initMocks; +import android.view.View; + import androidx.test.filters.MediumTest; import org.junit.AfterClass; @@ -123,6 +125,32 @@ mRenderTestRule.render(mCoordinator.getBottomSheetViewForTesting(), "expanded_sheet"); } + @Test + @MediumTest + @Feature("RenderTest") + @ParameterAnnotations.UseMethodParameter(NightModeTestUtils.NightModeParams.class) + public void testSignInInProgressView(boolean nightModeEnabled) throws IOException { + mAccountManagerTestRule.addAccount(PROFILE_DATA1); + buildAndShowCollapsedBottomSheet(); + View bottomSheetView = mCoordinator.getBottomSheetViewForTesting(); + TestThreadUtils.runOnUiThreadBlocking(() -> { + bottomSheetView.findViewById(R.id.account_picker_continue_as_button).performClick(); + }); + CriteriaHelper.pollUiThread( + bottomSheetView.findViewById(R.id.account_picker_signin_spinner_view)::isShown); + // Currently the ProgressBar animation cannot be disabled on android-marshmallow-arm64-rel + // bot with DisableAnimationsTestRule, we hide the ProgressBar manually here to enable + // checks of other elements on the screen. + // TODO(https://crbug.com/1115067): Delete this line and use DisableAnimationsTestRule + // once DisableAnimationsTestRule is fixed. + TestThreadUtils.runOnUiThreadBlocking(() -> { + bottomSheetView.findViewById(R.id.account_picker_signin_spinner_view) + .setVisibility(View.INVISIBLE); + }); + mRenderTestRule.render( + mCoordinator.getBottomSheetViewForTesting(), "signin_in_progress_sheet"); + } + private void buildAndShowCollapsedBottomSheet() { TestThreadUtils.runOnUiThreadBlocking(() -> { mCoordinator = new AccountPickerBottomSheetCoordinator(mActivityTestRule.getActivity(),
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/WebsitePermissionsFetcherTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/WebsitePermissionsFetcherTest.java index ad26b47..60fa40b 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/WebsitePermissionsFetcherTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/WebsitePermissionsFetcherTest.java
@@ -536,20 +536,19 @@ // Check content setting exception types. Assert.assertEquals(Integer.valueOf(ContentSettingValues.DEFAULT), - site.getContentSettingPermission(ContentSettingException.Type.COOKIE)); + site.getContentSettingPermission(ContentSettingsType.COOKIES)); Assert.assertEquals(Integer.valueOf(ContentSettingValues.DEFAULT), - site.getContentSettingPermission(ContentSettingException.Type.POPUP)); + site.getContentSettingPermission(ContentSettingsType.POPUPS)); Assert.assertEquals(Integer.valueOf(ContentSettingValues.DEFAULT), - site.getContentSettingPermission(ContentSettingException.Type.ADS)); + site.getContentSettingPermission(ContentSettingsType.ADS)); Assert.assertEquals(Integer.valueOf(ContentSettingValues.DEFAULT), - site.getContentSettingPermission(ContentSettingException.Type.JAVASCRIPT)); + site.getContentSettingPermission(ContentSettingsType.JAVASCRIPT)); Assert.assertEquals(Integer.valueOf(ContentSettingValues.DEFAULT), - site.getContentSettingPermission(ContentSettingException.Type.SOUND)); + site.getContentSettingPermission(ContentSettingsType.SOUND)); Assert.assertEquals(Integer.valueOf(ContentSettingValues.DEFAULT), - site.getContentSettingPermission(ContentSettingException.Type.BACKGROUND_SYNC)); + site.getContentSettingPermission(ContentSettingsType.BACKGROUND_SYNC)); Assert.assertEquals(Integer.valueOf(ContentSettingValues.DEFAULT), - site.getContentSettingPermission( - ContentSettingException.Type.AUTOMATIC_DOWNLOADS)); + site.getContentSettingPermission(ContentSettingsType.AUTOMATIC_DOWNLOADS)); // Check storage info. ArrayList<StorageInfo> storageInfos = new ArrayList<>(site.getStorageInfo()); @@ -705,26 +704,21 @@ String googleOrigin = "https://google.com"; String preferenceSource = "preference"; - ArrayList<Integer> contentSettingExceptionTypes = new ArrayList<>(Arrays.asList( - ContentSettingException.Type.ADS, ContentSettingException.Type.AUTOMATIC_DOWNLOADS, - ContentSettingException.Type.BACKGROUND_SYNC, - ContentSettingException.Type.BLUETOOTH_SCANNING, - ContentSettingException.Type.COOKIE, ContentSettingException.Type.JAVASCRIPT, - ContentSettingException.Type.POPUP, ContentSettingException.Type.SOUND)); - Assert.assertEquals(8, ContentSettingException.Type.NUM_ENTRIES); + ArrayList<Integer> contentSettingExceptionTypes = new ArrayList<>( + Arrays.asList(ContentSettingsType.ADS, ContentSettingsType.AUTOMATIC_DOWNLOADS, + ContentSettingsType.BACKGROUND_SYNC, ContentSettingsType.BLUETOOTH_SCANNING, + ContentSettingsType.COOKIES, ContentSettingsType.JAVASCRIPT, + ContentSettingsType.POPUPS, ContentSettingsType.SOUND)); for (@ContentSettingsType int type : contentSettingExceptionTypes) { - @ContentSettingsType - int contentSettingsType = ContentSettingException.getContentSettingsType(type); { - ContentSettingException fakeContentSettingException = - new ContentSettingException(contentSettingsType, googleOrigin, - ContentSettingValues.DEFAULT, preferenceSource); + ContentSettingException fakeContentSettingException = new ContentSettingException( + type, googleOrigin, ContentSettingValues.DEFAULT, preferenceSource); websitePreferenceBridge.addContentSettingException(fakeContentSettingException); fetcher.fetchPreferencesForCategory( SiteSettingsCategory.createFromContentSettingsType( - UNUSED_BROWSER_CONTEXT_HANDLE, contentSettingsType), + UNUSED_BROWSER_CONTEXT_HANDLE, type), (sites) -> { Assert.assertEquals(1, sites.size()); @@ -736,14 +730,13 @@ // Make sure that the content setting value is updated. { - ContentSettingException fakeContentSettingException = - new ContentSettingException(contentSettingsType, googleOrigin, - ContentSettingValues.BLOCK, preferenceSource); + ContentSettingException fakeContentSettingException = new ContentSettingException( + type, googleOrigin, ContentSettingValues.BLOCK, preferenceSource); websitePreferenceBridge.addContentSettingException(fakeContentSettingException); fetcher.fetchPreferencesForCategory( SiteSettingsCategory.createFromContentSettingsType( - UNUSED_BROWSER_CONTEXT_HANDLE, contentSettingsType), + UNUSED_BROWSER_CONTEXT_HANDLE, type), (sites) -> { Assert.assertEquals(1, sites.size()); @@ -766,11 +759,8 @@ String mainSite = "https://a.com"; String thirdPartySite = "https://b.com"; String preferenceSource = "preference"; - @ContentSettingException.Type - int contentSettingExceptionType = ContentSettingException.Type.COOKIE; @ContentSettingsType - int contentSettingsType = - ContentSettingException.getContentSettingsType(contentSettingExceptionType); + int contentSettingsType = ContentSettingsType.COOKIES; // Test the advanced exception combinations of: // b.com on a.com @@ -797,7 +787,7 @@ Website site = sites.iterator().next(); assertContentSettingExceptionEquals(fakeContentSettingException, - site.getContentSettingException(contentSettingExceptionType)); + site.getContentSettingException(contentSettingsType)); }); } @@ -816,7 +806,7 @@ Website site = sites.iterator().next(); assertContentSettingExceptionEquals(fakeContentSettingException, - site.getContentSettingException(contentSettingExceptionType)); + site.getContentSettingException(contentSettingsType)); }); } }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/browserservices/QualityEnforcerUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/browserservices/QualityEnforcerUnitTest.java index c02f286..5c52510 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/browserservices/QualityEnforcerUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/browserservices/QualityEnforcerUnitTest.java
@@ -39,6 +39,7 @@ import org.chromium.chrome.browser.customtabs.content.TabObserverRegistrar; import org.chromium.chrome.browser.customtabs.content.TabObserverRegistrar.CustomTabTabObserver; import org.chromium.chrome.browser.flags.ChromeFeatureList; +import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.test.util.browser.Features; import org.chromium.chrome.test.util.browser.Features.DisableFeatures; @@ -63,6 +64,8 @@ @Mock private ChromeActivity mActivity; @Mock + ActivityLifecycleDispatcher mLifecycleDispatcher; + @Mock private CustomTabIntentDataProvider mIntentDataProvider; @Mock private CustomTabsConnection mCustomTabsConnection; @@ -93,9 +96,9 @@ when(mVerifier.verify(TRUSTED_ORIGIN_PAGE)).thenReturn(Promise.fulfilled(true)); when(mVerifier.verify(UNTRUSTED_PAGE)).thenReturn(Promise.fulfilled(false)); - mQualityEnforcer = - new QualityEnforcer(mActivity, mTabObserverRegistrar, mIntentDataProvider, - mCustomTabsConnection, mVerifier, mClientPackageNameProvider, mUmaRecorder); + mQualityEnforcer = new QualityEnforcer(mActivity, mLifecycleDispatcher, + mTabObserverRegistrar, mIntentDataProvider, mCustomTabsConnection, mVerifier, + mClientPackageNameProvider, mUmaRecorder); } @Test @@ -160,7 +163,30 @@ @Test public void trigger_offline() { navigateToUrlInternet(TRUSTED_ORIGIN_PAGE); - verifyTriggeredOffline(); + Assert.assertEquals( + ContextUtils.getApplicationContext().getString( + R.string.twa_quality_enforcement_violation_offline, TRUSTED_ORIGIN_PAGE), + ShadowToast.getTextOfLatestToast()); + verifyNotifyClientApp(); + } + + @Test + public void notTrigger_digitalAssertLinkPass() { + when(mIntentDataProvider.getUrlToLoad()).thenReturn(TRUSTED_ORIGIN_PAGE); + mQualityEnforcer.onFinishNativeInitialization(); + verifyNotTriggered(); + } + + @Test + public void trigger_digitalAssertLinkFailed() { + when(mIntentDataProvider.getUrlToLoad()).thenReturn(UNTRUSTED_PAGE); + mQualityEnforcer.onFinishNativeInitialization(); + + Assert.assertEquals( + ContextUtils.getApplicationContext().getString( + R.string.twa_quality_enforcement_violation_assert_link, UNTRUSTED_PAGE), + ShadowToast.getTextOfLatestToast()); + verifyNotifyClientApp(); } private void verifyTriggered404() { @@ -168,15 +194,10 @@ R.string.twa_quality_enforcement_violation_error, HTTP_ERROR_NOT_FOUND, TRUSTED_ORIGIN_PAGE), ShadowToast.getTextOfLatestToast()); - verify(mCustomTabsConnection) - .sendExtraCallbackWithResult(any(), eq(QualityEnforcer.NOTIFY), any()); + verifyNotifyClientApp(); } - private void verifyTriggeredOffline() { - Assert.assertEquals( - ContextUtils.getApplicationContext().getString( - R.string.twa_quality_enforcement_violation_offline, TRUSTED_ORIGIN_PAGE), - ShadowToast.getTextOfLatestToast()); + private void verifyNotifyClientApp() { verify(mCustomTabsConnection) .sendExtraCallbackWithResult(any(), eq(QualityEnforcer.NOTIFY), any()); }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/site_settings/SingleWebsiteSettingsTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/site_settings/SingleWebsiteSettingsTest.java index 4a4d6e9..49b7b89a 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/site_settings/SingleWebsiteSettingsTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/site_settings/SingleWebsiteSettingsTest.java
@@ -73,8 +73,9 @@ @Test @SmallTest public void testCorrectMapOfPreferenceKeyToContentSettingsType() { + SingleWebsiteSettings settings = new SingleWebsiteSettings(); for (String key : SingleWebsiteSettings.PERMISSION_PREFERENCE_KEYS) { - Assert.assertEquals(SingleWebsiteSettings.getContentSettingsTypeFromPreferenceKey(key), + Assert.assertEquals(settings.getContentSettingsTypeFromPreferenceKey(key), getCorrectContentSettingsTypeForPreferenceKey(key)); } }
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc index fcdc1368..49a1f223 100644 --- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc +++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
@@ -710,7 +710,7 @@ g_browser_process->safe_browsing_service(); if (sb_service) { mojo::Remote<network::mojom::CookieManager> cookie_manager; - sb_service->GetNetworkContext()->GetCookieManager( + sb_service->GetNetworkContext(profile_)->GetCookieManager( cookie_manager.BindNewPipeAndPassReceiver()); network::mojom::CookieManager* manager_ptr = cookie_manager.get();
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.h b/chrome/browser/chromeos/accessibility/accessibility_manager.h index 36ad43b4..a4b7310 100644 --- a/chrome/browser/chromeos/accessibility/accessibility_manager.h +++ b/chrome/browser/chromeos/accessibility/accessibility_manager.h
@@ -80,14 +80,12 @@ bool enabled; }; -typedef base::RepeatingCallback<void(const AccessibilityStatusEventDetails&)> - AccessibilityStatusCallback; - -typedef base::CallbackList<void(const AccessibilityStatusEventDetails&)> - AccessibilityStatusCallbackList; - -typedef AccessibilityStatusCallbackList::Subscription - AccessibilityStatusSubscription; +using AccessibilityStatusCallbackList = + base::CallbackList<void(const AccessibilityStatusEventDetails&)>; +using AccessibilityStatusCallback = + AccessibilityStatusCallbackList::CallbackType; +using AccessibilityStatusSubscription = + AccessibilityStatusCallbackList::Subscription; class AccessibilityPanelWidgetObserver;
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc b/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc index a07ff3a..eba96b0d 100644 --- a/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc +++ b/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc
@@ -468,7 +468,7 @@ const base::FilePath test_dir = temp_dir_.GetPath(); AddLocalFileSystem(browser()->profile(), test_dir); - // Get the source tree media/test/data directory path. + // Get source media/test/data directory path. base::FilePath root_dir; CHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &root_dir)); const base::FilePath media_test_data_dir = @@ -479,7 +479,7 @@ return media_test_data_dir.Append(base::FilePath::FromUTF8Unsafe(file)); }; - // Create test files. + // Create media test files. { base::ScopedAllowBlockingForTesting allow_io; @@ -490,6 +490,32 @@ ASSERT_TRUE(base::CopyFile(audio, test_dir.Append(audio.BaseName()))); } + // Get source chrome/test/data/chromeos/file_manager directory path. + const base::FilePath files_test_data_dir = root_dir.AppendASCII("chrome") + .AppendASCII("test") + .AppendASCII("data") + .AppendASCII("chromeos") + .AppendASCII("file_manager"); + + // Returns a path to a chrome/test/data/chromeos/file_manager test file. + auto get_files_test_data_dir = [&](const std::string& file) { + return files_test_data_dir.Append(base::FilePath::FromUTF8Unsafe(file)); + }; + + // Create files test files. + { + base::ScopedAllowBlockingForTesting allow_io; + + const base::FilePath broke = get_files_test_data_dir("broken.jpg"); + ASSERT_TRUE(base::CopyFile(broke, test_dir.Append(broke.BaseName()))); + + const base::FilePath empty = get_files_test_data_dir("empty.txt"); + ASSERT_TRUE(base::CopyFile(empty, test_dir.Append(empty.BaseName()))); + + const base::FilePath image = get_files_test_data_dir("image3.jpg"); + ASSERT_TRUE(base::CopyFile(image, test_dir.Append(image.BaseName()))); + } + ASSERT_TRUE(RunComponentExtensionTest("file_browser/media_metadata")); }
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_media_parser.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_media_parser.cc index 24037814..cffa8f3 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_media_parser.cc +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_media_parser.cc
@@ -34,6 +34,10 @@ std::string blob_uuid; EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &blob_uuid)); + if (blob_uuid.empty()) { + return RespondNow(Error("fileEntry.file() blob error.")); + } + content::GetUIThreadTaskRunner({})->PostTask( FROM_HERE, base::BindOnce( @@ -83,6 +87,10 @@ const std::unique_ptr<Params> params(Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params); + if (params->blob_uuid.empty()) { + return RespondNow(Error("fileEntry.file() blob error.")); + } + bool include_images = false; if (params->type == api::file_manager_private::CONTENT_METADATA_TYPE_METADATATAGSIMAGES) {
diff --git a/chrome/browser/chromeos/login/active_directory_login_browsertest.cc b/chrome/browser/chromeos/login/active_directory_login_browsertest.cc index fc385cb4..feb92f2 100644 --- a/chrome/browser/chromeos/login/active_directory_login_browsertest.cc +++ b/chrome/browser/chromeos/login/active_directory_login_browsertest.cc
@@ -104,6 +104,7 @@ // Test successful Active Directory login. IN_PROC_BROWSER_TEST_F(ActiveDirectoryLoginTest, LoginSuccess) { ASSERT_TRUE(InstallAttributes::Get()->IsActiveDirectoryManaged()); + ad_login_.NavigateToGaiaScreen(); ad_login_.TestNoError(); ad_login_.TestDomainHidden(); ad_login_.SubmitActiveDirectoryCredentials(test_user_, kPassword); @@ -114,6 +115,7 @@ // Tests that the Kerberos SSO environment variables are set correctly after // an Active Directory log in. IN_PROC_BROWSER_TEST_F(ActiveDirectoryLoginTest, KerberosVarsCopied) { + ad_login_.NavigateToGaiaScreen(); ad_login_.TestNoError(); ad_login_.TestDomainHidden(); ad_login_.SubmitActiveDirectoryCredentials(test_user_, kPassword); @@ -133,6 +135,7 @@ // Test different UI errors for Active Directory login. IN_PROC_BROWSER_TEST_F(ActiveDirectoryLoginTest, LoginErrors) { ASSERT_TRUE(InstallAttributes::Get()->IsActiveDirectoryManaged()); + ad_login_.NavigateToGaiaScreen(); ad_login_.TestNoError(); ad_login_.TestDomainHidden(); @@ -173,6 +176,7 @@ // Test successful Active Directory login from the password change screen. IN_PROC_BROWSER_TEST_F(ActiveDirectoryLoginTest, PasswordChange_LoginSuccess) { ASSERT_TRUE(InstallAttributes::Get()->IsActiveDirectoryManaged()); + ad_login_.NavigateToGaiaScreen(); ad_login_.TestLoginVisible(); ad_login_.TestDomainHidden(); @@ -189,6 +193,7 @@ // Test different UI errors for Active Directory password change screen. IN_PROC_BROWSER_TEST_F(ActiveDirectoryLoginTest, PasswordChange_UIErrors) { ASSERT_TRUE(InstallAttributes::Get()->IsActiveDirectoryManaged()); + ad_login_.NavigateToGaiaScreen(); ad_login_.TestLoginVisible(); ad_login_.TestDomainHidden(); @@ -223,6 +228,7 @@ IN_PROC_BROWSER_TEST_F(ActiveDirectoryLoginTest, PasswordChange_ReopenClearErrors) { ASSERT_TRUE(InstallAttributes::Get()->IsActiveDirectoryManaged()); + ad_login_.NavigateToGaiaScreen(); ad_login_.TestLoginVisible(); ad_login_.TestDomainHidden(); @@ -233,6 +239,7 @@ ad_login_.TestPasswordChangeOldPasswordError(); ad_login_.ClosePasswordChangeScreen(); + ad_login_.NavigateToGaiaScreen(); ad_login_.TestLoginVisible(); ad_login_.TriggerPasswordChangeScreen(); ad_login_.TestPasswordChangeNoErrors(); @@ -241,6 +248,7 @@ // Tests that autocomplete works. Submits username without domain. IN_PROC_BROWSER_TEST_F(ActiveDirectoryLoginAutocompleteTest, LoginSuccess) { ASSERT_TRUE(InstallAttributes::Get()->IsActiveDirectoryManaged()); + ad_login_.NavigateToGaiaScreen(); ad_login_.TestNoError(); ad_login_.TestDomainVisible(); @@ -253,7 +261,7 @@ // Tests that user could override autocomplete domain. IN_PROC_BROWSER_TEST_F(ActiveDirectoryLoginAutocompleteTest, TestAutocomplete) { ASSERT_TRUE(InstallAttributes::Get()->IsActiveDirectoryManaged()); - + ad_login_.NavigateToGaiaScreen(); ad_login_.TestLoginVisible(); ad_login_.TestDomainVisible(); fake_authpolicy_client()->set_auth_error(authpolicy::ERROR_BAD_PASSWORD);
diff --git a/chrome/browser/chromeos/login/arc_terms_of_service_browsertest.cc b/chrome/browser/chromeos/login/arc_terms_of_service_browsertest.cc index f0d1a17..532ab4fa 100644 --- a/chrome/browser/chromeos/login/arc_terms_of_service_browsertest.cc +++ b/chrome/browser/chromeos/login/arc_terms_of_service_browsertest.cc
@@ -36,9 +36,9 @@ #include "chrome/browser/consent_auditor/consent_auditor_test_utils.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.h" -#include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/recommend_apps_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h" +#include "chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.h" #include "chrome/common/pref_names.h" #include "chrome/grit/generated_resources.h" #include "chromeos/constants/chromeos_features.h" @@ -215,7 +215,7 @@ void LoginAsRegularUser() { SetUpExitCallback(); login_manager_mixin_.LoginAsNewRegularUser(); - OobeScreenExitWaiter(GaiaView::kScreenId).Wait(); + OobeScreenExitWaiter(UserCreationView::kScreenId).Wait(); } void ShowArcTosScreen() {
diff --git a/chrome/browser/chromeos/login/demo_mode/demo_setup_browsertest.cc b/chrome/browser/chromeos/login/demo_mode/demo_setup_browsertest.cc index e74227f..ce894dd 100644 --- a/chrome/browser/chromeos/login/demo_mode/demo_setup_browsertest.cc +++ b/chrome/browser/chromeos/login/demo_mode/demo_setup_browsertest.cc
@@ -37,8 +37,8 @@ #include "chrome/browser/ui/webui/chromeos/login/demo_preferences_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/demo_setup_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/eula_screen_handler.h" -#include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/network_screen_handler.h" +#include "chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.h" #include "chrome/grit/generated_resources.h" #include "chromeos/constants/chromeos_features.h" @@ -583,7 +583,7 @@ // TODO(agawronska): Progress dialog transition is async - extra work is // needed to be able to check it reliably. - OobeScreenWaiter(GaiaView::kScreenId).Wait(); + OobeScreenWaiter(UserCreationView::kScreenId).Wait(); EXPECT_TRUE(StartupUtils::IsOobeCompleted()); EXPECT_TRUE(StartupUtils::IsDeviceRegistered()); } @@ -671,7 +671,7 @@ EXPECT_EQ("admin-fr@cros-demo-mode.com", DemoSetupController::GetSubOrganizationEmail()); - OobeScreenWaiter(GaiaView::kScreenId).Wait(); + OobeScreenWaiter(UserCreationView::kScreenId).Wait(); EXPECT_TRUE(StartupUtils::IsOobeCompleted()); EXPECT_TRUE(StartupUtils::IsDeviceRegistered()); } @@ -931,7 +931,7 @@ // TODO(agawronska): Progress dialog transition is async - extra work is // needed to be able to check it reliably. - OobeScreenWaiter(GaiaView::kScreenId).Wait(); + OobeScreenWaiter(UserCreationView::kScreenId).Wait(); EXPECT_TRUE(StartupUtils::IsOobeCompleted()); EXPECT_TRUE(StartupUtils::IsDeviceRegistered()); } @@ -1155,7 +1155,7 @@ JSExecution::kAsync); // TODO(agawronska): Progress dialog transition is async - extra work is // needed to be able to check it reliably. - OobeScreenWaiter(GaiaView::kScreenId).Wait(); + OobeScreenWaiter(UserCreationView::kScreenId).Wait(); } // Test is flaky: crbug.com/1099402 @@ -1337,7 +1337,7 @@ // TODO(agawronska): Progress dialog transition is async - extra work is // needed to be able to check it reliably. - OobeScreenWaiter(GaiaView::kScreenId).Wait(); + OobeScreenWaiter(UserCreationView::kScreenId).Wait(); EXPECT_TRUE(StartupUtils::IsOobeCompleted()); EXPECT_TRUE(StartupUtils::IsDeviceRegistered()); } @@ -1372,7 +1372,7 @@ // TODO(agawronska): Progress dialog transition is async - extra work is // needed to be able to check it reliably. - OobeScreenWaiter(GaiaView::kScreenId).Wait(); + OobeScreenWaiter(UserCreationView::kScreenId).Wait(); EXPECT_TRUE(StartupUtils::IsOobeCompleted()); EXPECT_TRUE(StartupUtils::IsDeviceRegistered()); } @@ -1408,7 +1408,7 @@ // TODO(agawronska): Progress dialog transition is async - extra work is // needed to be able to check it reliably. - OobeScreenWaiter(GaiaView::kScreenId).Wait(); + OobeScreenWaiter(UserCreationView::kScreenId).Wait(); EXPECT_TRUE(StartupUtils::IsOobeCompleted()); EXPECT_TRUE(StartupUtils::IsDeviceRegistered()); }
diff --git a/chrome/browser/chromeos/login/encryption_migration_browsertest.cc b/chrome/browser/chromeos/login/encryption_migration_browsertest.cc index 4327385..88ed3cea 100644 --- a/chrome/browser/chromeos/login/encryption_migration_browsertest.cc +++ b/chrome/browser/chromeos/login/encryption_migration_browsertest.cc
@@ -21,8 +21,8 @@ #include "chrome/browser/chromeos/login/ui/login_display_host.h" #include "chrome/browser/chromeos/login/wizard_controller.h" #include "chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.h" -#include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h" +#include "chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.h" #include "chromeos/constants/chromeos_switches.h" #include "chromeos/dbus/cryptohome/account_identifier_operators.h" #include "chromeos/dbus/cryptohome/fake_cryptohome_client.h" @@ -369,7 +369,7 @@ cryptohome::DIRCRYPTO_MIGRATION_SUCCESS, 5 /*current*/, 5 /*total*/); EXPECT_EQ(0, FakePowerManagerClient::Get()->num_request_restart_calls()); - OobeScreenWaiter(GaiaView::kScreenId).Wait(); + OobeScreenWaiter(UserCreationView::kScreenId).Wait(); } IN_PROC_BROWSER_TEST_F(EncryptionMigrationTest, @@ -449,7 +449,7 @@ SetUpStubAuthenticatorAndAttemptLogin(false /* has_incomplete_migration */); // Wipe is expected to wipe the cryptohome, and force online login. - OobeScreenWaiter(GaiaView::kScreenId).Wait(); + OobeScreenWaiter(UserCreationView::kScreenId).Wait(); EXPECT_FALSE(FakeCryptohomeClient::Get() ->get_id_for_disk_migrated_to_dircrypto()
diff --git a/chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.h b/chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.h index 8e3299c..dc8716f 100644 --- a/chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.h +++ b/chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.h
@@ -32,8 +32,8 @@ // make a decision. class AutoEnrollmentController { public: - typedef base::CallbackList<void(policy::AutoEnrollmentState)> - ProgressCallbackList; + using ProgressCallbackList = + base::CallbackList<void(policy::AutoEnrollmentState)>; // Parameter values for the kEnterpriseEnableForcedReEnrollment flag. static const char kForcedReEnrollmentAlways[];
diff --git a/chrome/browser/chromeos/login/enrollment/enrollment_local_policy_server_browsertest.cc b/chrome/browser/chromeos/login/enrollment/enrollment_local_policy_server_browsertest.cc index bbeb374..a9d9fc5 100644 --- a/chrome/browser/chromeos/login/enrollment/enrollment_local_policy_server_browsertest.cc +++ b/chrome/browser/chromeos/login/enrollment/enrollment_local_policy_server_browsertest.cc
@@ -36,8 +36,8 @@ #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/webui/chromeos/login/device_disabled_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/error_screen_handler.h" -#include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h" +#include "chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.h" #include "chrome/grit/generated_resources.h" #include "chromeos/attestation/mock_attestation_flow.h" #include "chromeos/constants/chromeos_switches.h" @@ -463,7 +463,7 @@ auto login_waiter = CreateLoginVisibleWaiter(); enrollment_ui_.LeaveDeviceAttributeErrorScreen(); login_waiter->Wait(); - OobeScreenWaiter(GaiaView::kScreenId).Wait(); + OobeScreenWaiter(UserCreationView::kScreenId).Wait(); } // Error during enrollment : Error fetching policy : 500 server error. @@ -515,7 +515,7 @@ // No state keys on the server. Auto enrollment check should proceed to login. IN_PROC_BROWSER_TEST_F(AutoEnrollmentLocalPolicyServer, AutoEnrollmentCheck) { host()->StartWizard(AutoEnrollmentCheckScreenView::kScreenId); - OobeScreenWaiter(GaiaView::kScreenId).Wait(); + OobeScreenWaiter(UserCreationView::kScreenId).Wait(); } // State keys are present but restore mode is not requested. @@ -525,7 +525,7 @@ enterprise_management::DeviceStateRetrievalResponse::RESTORE_MODE_NONE, test::kTestDomain)); host()->StartWizard(AutoEnrollmentCheckScreenView::kScreenId); - OobeScreenWaiter(GaiaView::kScreenId).Wait(); + OobeScreenWaiter(UserCreationView::kScreenId).Wait(); } // Reenrollment requested. User can skip. @@ -538,7 +538,7 @@ host()->StartWizard(AutoEnrollmentCheckScreenView::kScreenId); OobeScreenWaiter(EnrollmentScreenView::kScreenId).Wait(); enrollment_screen()->OnCancel(); - OobeScreenWaiter(GaiaView::kScreenId).Wait(); + OobeScreenWaiter(UserCreationView::kScreenId).Wait(); } // Reenrollment forced. User can not skip. @@ -595,7 +595,7 @@ // normal signin. IN_PROC_BROWSER_TEST_F(AutoEnrollmentNoStateKeys, NotRequired) { host()->StartWizard(AutoEnrollmentCheckScreenView::kScreenId); - OobeScreenWaiter(GaiaView::kScreenId).Wait(); + OobeScreenWaiter(UserCreationView::kScreenId).Wait(); } // FRE explicitly not required in VPD, so it should not even contact the policy @@ -611,7 +611,7 @@ test::kTestDomain)); host()->StartWizard(AutoEnrollmentCheckScreenView::kScreenId); - OobeScreenWaiter(GaiaView::kScreenId).Wait(); + OobeScreenWaiter(UserCreationView::kScreenId).Wait(); } // FRE is not required when VPD is valid and activate date is not there. @@ -624,7 +624,7 @@ test::kTestDomain)); host()->StartWizard(AutoEnrollmentCheckScreenView::kScreenId); - OobeScreenWaiter(GaiaView::kScreenId).Wait(); + OobeScreenWaiter(UserCreationView::kScreenId).Wait(); } // FRE is required when VPD is valid and activate date is there. @@ -806,7 +806,7 @@ TriggerEnrollmentAndSignInSuccessfully(); enrollment_ui_.WaitForStep(test::ui::kEnrollmentStepSuccess); ConfirmAndWaitLoginScreen(); - OobeScreenWaiter(GaiaView::kScreenId).Wait(); + OobeScreenWaiter(UserCreationView::kScreenId).Wait(); ASSERT_EQ(GetParam(), user_manager::UserManager::Get()->IsGuestSessionAllowed());
diff --git a/chrome/browser/chromeos/login/enrollment/enrollment_screen_browsertest.cc b/chrome/browser/chromeos/login/enrollment/enrollment_screen_browsertest.cc index 074dce30..70880b3 100644 --- a/chrome/browser/chromeos/login/enrollment/enrollment_screen_browsertest.cc +++ b/chrome/browser/chromeos/login/enrollment/enrollment_screen_browsertest.cc
@@ -19,7 +19,7 @@ #include "chrome/browser/chromeos/login/ui/login_display_host.h" #include "chrome/browser/chromeos/login/ui/webui_login_view.h" #include "chrome/browser/chromeos/login/wizard_controller.h" -#include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h" +#include "chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.h" #include "chromeos/constants/chromeos_switches.h" #include "chromeos/test/chromeos_test_utils.h" #include "content/public/test/browser_test.h" @@ -205,7 +205,7 @@ // Tests that enrollment screen could be triggered after OOBE completed and // Chrome restarted (or device rebooted). IN_PROC_BROWSER_TEST_F(OobeCompletedUnownedTest, TriggerEnrollment) { - OobeScreenWaiter(GaiaView::kScreenId).Wait(); + OobeScreenWaiter(UserCreationView::kScreenId).Wait(); LoginDisplayHost::default_host()->StartWizard( EnrollmentScreenView::kScreenId); OobeScreenWaiter(EnrollmentScreenView::kScreenId).Wait();
diff --git a/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc b/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc index 46231cd9..3827c04 100644 --- a/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc +++ b/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc
@@ -42,9 +42,9 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/browser.h" -#include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/terms_of_service_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/tpm_error_screen_handler.h" +#include "chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.h" #include "chrome/grit/generated_resources.h" #include "chrome/test/base/testing_browser_process.h" #include "chromeos/constants/chromeos_switches.h" @@ -1080,7 +1080,7 @@ CryptohomeMissing) { SetUpStubAuthenticatorAndAttemptLogin(AuthFailure::MISSING_CRYPTOHOME); - OobeScreenWaiter(GaiaView::kScreenId).Wait(); + OobeScreenWaiter(UserCreationView::kScreenId).Wait(); const user_manager::User* user = user_manager::UserManager::Get()->FindUser(test_user_.account_id); ASSERT_TRUE(user);
diff --git a/chrome/browser/chromeos/login/kiosk_browsertest.cc b/chrome/browser/chromeos/login/kiosk_browsertest.cc index 8ee63d42..fbfed5c 100644 --- a/chrome/browser/chromeos/login/kiosk_browsertest.cc +++ b/chrome/browser/chromeos/login/kiosk_browsertest.cc
@@ -78,6 +78,7 @@ #include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/kiosk_autolaunch_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/kiosk_enable_screen_handler.h" +#include "chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_paths.h" @@ -584,6 +585,13 @@ PrepareAppLaunch(); network_portal_detector_.SimulateDefaultNetworkState(network_status); + + // TODO(crbug.com/1101318): LaunchAppUserCancel and + // LaunchAppWithNetworkConfigAccelerator are failing without skipping + // user creation screen. Need to investigate and fix this. + chromeos::WizardController::default_controller() + ->get_wizard_context_for_testing() + ->skip_to_login_for_tests = true; EXPECT_TRUE(LaunchApp(test_app_id())); } @@ -1150,7 +1158,7 @@ test::OobeJS().TapOnPath({"kiosk-enable", "close"}); // Wait for the kiosk_enable screen to disappear. - OobeScreenWaiter(GaiaView::kScreenId).Wait(); + OobeScreenWaiter(UserCreationView::kScreenId).Wait(); // Check that the status still says configurable. EXPECT_EQ(KioskAppManager::CONSUMER_KIOSK_AUTO_LAUNCH_CONFIGURABLE, @@ -1207,6 +1215,10 @@ OobeScreenWaiter(KioskEnableScreenView::kScreenId).Wait(); test::OobeJS().TapOnPath({"kiosk-enable", "close"}); + // Navigate to gaia sign in screen. + OobeScreenWaiter(UserCreationView::kScreenId).Wait(); + test::OobeJS().TapOnPath({"user-creation", "nextButton"}); + // Wait for signin screen to appear again. OobeScreenWaiter(GaiaView::kScreenId).Wait();
diff --git a/chrome/browser/chromeos/login/login_screen_policy_browsertest.cc b/chrome/browser/chromeos/login/login_screen_policy_browsertest.cc index ec4ef75..49b2e3f 100644 --- a/chrome/browser/chromeos/login/login_screen_policy_browsertest.cc +++ b/chrome/browser/chromeos/login/login_screen_policy_browsertest.cc
@@ -25,7 +25,7 @@ #include "chrome/browser/chromeos/settings/cros_settings.h" #include "chrome/browser/lifetime/application_lifetime.h" #include "chrome/browser/ui/ash/login_screen_client.h" -#include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h" +#include "chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.h" #include "chrome/grit/generated_resources.h" #include "chrome/test/base/ui_test_utils.h" #include "chromeos/constants/chromeos_switches.h" @@ -98,7 +98,7 @@ }; IN_PROC_BROWSER_TEST_F(LoginScreenGuestButtonPolicyTest, NoUsers) { - OobeScreenWaiter(GaiaView::kScreenId).Wait(); + OobeScreenWaiter(UserCreationView::kScreenId).Wait(); // Default. EXPECT_TRUE(ash::LoginScreenTestApi::IsGuestButtonShown()); @@ -122,7 +122,7 @@ } IN_PROC_BROWSER_TEST_F(LoginScreenGuestButtonPolicyTest, HasUsers) { - OobeScreenWaiter(GaiaView::kScreenId).Wait(); + OobeScreenWaiter(UserCreationView::kScreenId).Wait(); // Default. EXPECT_TRUE(ash::LoginScreenTestApi::IsGuestButtonShown());
diff --git a/chrome/browser/chromeos/login/oobe_interactive_ui_test.cc b/chrome/browser/chromeos/login/oobe_interactive_ui_test.cc index 2c4bbac8..51a411c 100644 --- a/chrome/browser/chromeos/login/oobe_interactive_ui_test.cc +++ b/chrome/browser/chromeos/login/oobe_interactive_ui_test.cc
@@ -695,6 +695,8 @@ void OobeInteractiveUITest::PerformSessionSignInSteps( const ScopedQuickUnlockPrivateGetAuthTokenFunctionObserver& get_auth_token_observer) { + test::WaitForUserCreationScreen(); + test::TapUserCreationNext(); WaitForGaiaSignInScreen(test_setup()->arc_state() != ArcState::kNotAvailable); LogInAsRegularUser();
diff --git a/chrome/browser/chromeos/login/proxy_auth_dialog_browsertest.cc b/chrome/browser/chromeos/login/proxy_auth_dialog_browsertest.cc index 06f920a9..f500462 100644 --- a/chrome/browser/chromeos/login/proxy_auth_dialog_browsertest.cc +++ b/chrome/browser/chromeos/login/proxy_auth_dialog_browsertest.cc
@@ -12,7 +12,7 @@ #include "chrome/browser/chromeos/login/test/login_manager_mixin.h" #include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h" #include "chrome/browser/ui/login/login_handler.h" -#include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h" +#include "chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.h" #include "chrome/common/chrome_switches.h" #include "content/public/common/content_switches.h" #include "content/public/test/browser_test.h" @@ -86,7 +86,7 @@ ASSERT_FALSE(ash::LoginScreenTestApi::IsOobeDialogVisible()); ProxyAuthDialogWaiter auth_dialog_waiter; ASSERT_TRUE(ash::LoginScreenTestApi::ClickAddUserButton()); - OobeScreenWaiter(GaiaView::kScreenId).Wait(); + OobeScreenWaiter(UserCreationView::kScreenId).Wait(); auth_dialog_waiter.Wait(); ASSERT_TRUE(auth_dialog_waiter.login_handler()); }
diff --git a/chrome/browser/chromeos/login/saml/saml_browsertest.cc b/chrome/browser/chromeos/login/saml/saml_browsertest.cc index 75ff8423..fd9245b9 100644 --- a/chrome/browser/chromeos/login/saml/saml_browsertest.cc +++ b/chrome/browser/chromeos/login/saml/saml_browsertest.cc
@@ -61,6 +61,7 @@ #include "chrome/browser/ui/login/login_handler_test_utils.h" #include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/saml_challenge_key_handler.h" +#include "chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.h" #include "chrome/browser/ui/webui/signin/signin_utils.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_paths.h" @@ -649,7 +650,7 @@ } virtual void StartSamlAndWaitForIdpPageLoad(const std::string& gaia_email) { - OobeScreenWaiter(GaiaView::kScreenId).Wait(); + OobeScreenWaiter(UserCreationView::kScreenId).Wait(); content::DOMMessageQueue message_queue; // Start observe before SAML. SetupAuthFlowChangeListener();
diff --git a/chrome/browser/chromeos/login/screens/app_downloading_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/app_downloading_screen_browsertest.cc index 7122455..aa12af48 100644 --- a/chrome/browser/chromeos/login/screens/app_downloading_screen_browsertest.cc +++ b/chrome/browser/chromeos/login/screens/app_downloading_screen_browsertest.cc
@@ -22,8 +22,8 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/webui/chromeos/login/app_downloading_screen_handler.h" -#include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h" +#include "chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.h" #include "chrome/grit/generated_resources.h" #include "chromeos/constants/chromeos_features.h" #include "components/arc/arc_prefs.h" @@ -53,7 +53,7 @@ void Login() { login_manager_.LoginAsNewRegularUser(); - OobeScreenExitWaiter(GaiaView::kScreenId).Wait(); + OobeScreenExitWaiter(UserCreationView::kScreenId).Wait(); } void ShowAppDownloadingScreen() {
diff --git a/chrome/browser/chromeos/login/screens/assistant_optin_flow_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/assistant_optin_flow_screen_browsertest.cc index e158c94..9b3d7205 100644 --- a/chrome/browser/chromeos/login/screens/assistant_optin_flow_screen_browsertest.cc +++ b/chrome/browser/chromeos/login/screens/assistant_optin_flow_screen_browsertest.cc
@@ -25,8 +25,8 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.h" -#include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h" +#include "chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.h" #include "chrome/common/chrome_paths.h" #include "chromeos/constants/chromeos_features.h" #include "chromeos/constants/chromeos_switches.h" @@ -333,7 +333,7 @@ void ShowAssistantOptInFlowScreen() { login_manager_.LoginAsNewRegularUser(); - OobeScreenExitWaiter(GaiaView::kScreenId).Wait(); + OobeScreenExitWaiter(UserCreationView::kScreenId).Wait(); if (!screen_exited_) { LoginDisplayHost::default_host()->StartWizard( AssistantOptInFlowScreenView::kScreenId);
diff --git a/chrome/browser/chromeos/login/screens/discover_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/discover_screen_browsertest.cc index f674abb..795c19d 100644 --- a/chrome/browser/chromeos/login/screens/discover_screen_browsertest.cc +++ b/chrome/browser/chromeos/login/screens/discover_screen_browsertest.cc
@@ -19,7 +19,7 @@ #include "chrome/browser/chromeos/login/ui/login_display_host.h" #include "chrome/browser/chromeos/login/wizard_controller.h" #include "chrome/browser/ui/webui/chromeos/login/discover_screen_handler.h" -#include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h" +#include "chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.h" #include "chromeos/constants/chromeos_features.h" #include "chromeos/login/auth/stub_authenticator_builder.h" #include "components/user_manager/user_type.h" @@ -86,7 +86,7 @@ void ShowDiscoverScreen() { LogIn(); - OobeScreenExitWaiter(GaiaView::kScreenId).Wait(); + OobeScreenExitWaiter(UserCreationView::kScreenId).Wait(); if (!screen_exited_) { LoginDisplayHost::default_host()->StartWizard( DiscoverScreenView::kScreenId);
diff --git a/chrome/browser/chromeos/login/screens/family_link_notice_browsertest.cc b/chrome/browser/chromeos/login/screens/family_link_notice_browsertest.cc index d8d7a55..997111f 100644 --- a/chrome/browser/chromeos/login/screens/family_link_notice_browsertest.cc +++ b/chrome/browser/chromeos/login/screens/family_link_notice_browsertest.cc
@@ -16,7 +16,7 @@ #include "chrome/browser/chromeos/login/wizard_controller.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/webui/chromeos/login/family_link_notice_screen_handler.h" -#include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h" +#include "chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.h" #include "chrome/common/pref_names.h" #include "chromeos/constants/chromeos_features.h" #include "chromeos/login/auth/stub_authenticator_builder.h" @@ -53,7 +53,7 @@ void LoginAsRegularUser() { login_manager_mixin_.LoginAsNewRegularUser(); - OobeScreenExitWaiter(GaiaView::kScreenId).Wait(); + OobeScreenExitWaiter(UserCreationView::kScreenId).Wait(); } void ExpectHelpAppPrefValue(bool expected) { @@ -138,7 +138,7 @@ void LoginAsChildUser() { login_manager_mixin_.LoginAsNewChildUser(); - OobeScreenExitWaiter(GaiaView::kScreenId).Wait(); + OobeScreenExitWaiter(UserCreationView::kScreenId).Wait(); } private: @@ -179,7 +179,7 @@ void LoginAsManagedUser() { user_policy_mixin_.RequestPolicyUpdate(); login_manager_mixin_.LoginWithDefaultContext(test_user_); - OobeScreenExitWaiter(GaiaView::kScreenId).Wait(); + OobeScreenExitWaiter(UserCreationView::kScreenId).Wait(); } private:
diff --git a/chrome/browser/chromeos/login/screens/gaia_screen.cc b/chrome/browser/chromeos/login/screens/gaia_screen.cc index a38979e7..d810433 100644 --- a/chrome/browser/chromeos/login/screens/gaia_screen.cc +++ b/chrome/browser/chromeos/login/screens/gaia_screen.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/chromeos/login/screens/gaia_screen.h" #include "chrome/browser/chromeos/login/screen_manager.h" +#include "chrome/browser/chromeos/login/wizard_context.h" #include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h" #include "components/account_id/account_id.h" @@ -55,6 +56,8 @@ } void GaiaScreen::ShowImpl() { + // Landed on the login screen. No longer skipping enrollment for tests. + context()->skip_to_login_for_tests = false; view_->Show(); }
diff --git a/chrome/browser/chromeos/login/screens/marketing_opt_in_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/marketing_opt_in_screen_browsertest.cc index fb345bf..d9c6c4f 100644 --- a/chrome/browser/chromeos/login/screens/marketing_opt_in_screen_browsertest.cc +++ b/chrome/browser/chromeos/login/screens/marketing_opt_in_screen_browsertest.cc
@@ -32,8 +32,8 @@ #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_window.h" -#include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/marketing_opt_in_screen_handler.h" +#include "chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.h" #include "chrome/common/chrome_features.h" #include "chrome/common/pref_names.h" #include "chromeos/constants/chromeos_features.h" @@ -180,7 +180,7 @@ OobeBaseTest::SetUpOnMainThread(); login_manager_mixin_.LoginAsNewRegularUser(); - OobeScreenExitWaiter(GaiaView::kScreenId).Wait(); + OobeScreenExitWaiter(UserCreationView::kScreenId).Wait(); ProfileManager::GetActiveUserProfile()->GetPrefs()->SetBoolean( ash::prefs::kGestureEducationNotificationShown, true); }
diff --git a/chrome/browser/chromeos/login/screens/multidevice_setup_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/multidevice_setup_screen_browsertest.cc index fff1201f..41a5769a 100644 --- a/chrome/browser/chromeos/login/screens/multidevice_setup_screen_browsertest.cc +++ b/chrome/browser/chromeos/login/screens/multidevice_setup_screen_browsertest.cc
@@ -15,8 +15,8 @@ #include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h" #include "chrome/browser/chromeos/login/ui/login_display_host.h" #include "chrome/browser/chromeos/login/wizard_controller.h" -#include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/multidevice_setup_screen_handler.h" +#include "chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.h" #include "chromeos/constants/chromeos_features.h" #include "chromeos/services/multidevice_setup/public/cpp/fake_multidevice_setup_client.h" #include "content/public/test/browser_test.h" @@ -58,7 +58,7 @@ void ShowMultiDeviceSetupScreen() { login_manager_mixin_.LoginAsNewRegularUser(); - OobeScreenExitWaiter(GaiaView::kScreenId).Wait(); + OobeScreenExitWaiter(UserCreationView::kScreenId).Wait(); if (!screen_exited_) { LoginDisplayHost::default_host()->StartWizard( MultiDeviceSetupScreenView::kScreenId);
diff --git a/chrome/browser/chromeos/login/screens/recommend_apps_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/recommend_apps_screen_browsertest.cc index 25d9ebea..930eaca 100644 --- a/chrome/browser/chromeos/login/screens/recommend_apps_screen_browsertest.cc +++ b/chrome/browser/chromeos/login/screens/recommend_apps_screen_browsertest.cc
@@ -29,9 +29,9 @@ #include "chrome/browser/policy/profile_policy_connector.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_manager.h" -#include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h" #include "chrome/browser/ui/webui/chromeos/login/recommend_apps_screen_handler.h" +#include "chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.h" #include "chromeos/constants/chromeos_features.h" #include "components/account_id/account_id.h" #include "components/arc/arc_prefs.h" @@ -142,7 +142,7 @@ void ShowRecommendAppsScreen() { login_manager_.LoginAsNewRegularUser(); - OobeScreenExitWaiter(GaiaView::kScreenId).Wait(); + OobeScreenExitWaiter(UserCreationView::kScreenId).Wait(); LoginDisplayHost::default_host()->StartWizard( RecommendAppsScreenView::kScreenId); } @@ -562,7 +562,7 @@ user_policy_mixin_.RequestPolicyUpdate(); login_manager_.LoginWithDefaultContext(test_user_); - OobeScreenExitWaiter(GaiaView::kScreenId).Wait(); + OobeScreenExitWaiter(UserCreationView::kScreenId).Wait(); if (!screen_result_.has_value()) { // Skip screens to the tested one. LoginDisplayHost::default_host()->StartWizard(
diff --git a/chrome/browser/chromeos/login/screens/sync_consent_browsertest.cc b/chrome/browser/chromeos/login/screens/sync_consent_browsertest.cc index 3310746..9b89ef8 100644 --- a/chrome/browser/chromeos/login/screens/sync_consent_browsertest.cc +++ b/chrome/browser/chromeos/login/screens/sync_consent_browsertest.cc
@@ -28,9 +28,9 @@ #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/signin/identity_manager_factory.h" #include "chrome/browser/sync/profile_sync_service_factory.h" -#include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/marketing_opt_in_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h" +#include "chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.h" #include "chrome/common/pref_names.h" #include "chrome/grit/generated_resources.h" #include "chrome/test/base/testing_profile_manager.h" @@ -191,7 +191,7 @@ void LoginToSyncConsentScreen() { login_manager_mixin_.LoginAsNewRegularUser(); - OobeScreenExitWaiter(GaiaView::kScreenId).Wait(); + OobeScreenExitWaiter(UserCreationView::kScreenId).Wait(); // No need to explicitly show the screen as it is the first one after login. } @@ -653,6 +653,7 @@ IN_PROC_BROWSER_TEST_F(SyncConsentActiveDirectoryTest, LoginDoesNotStartSync) { // Sign in Active Directory user. + ad_login_.NavigateToGaiaScreen(); ad_login_.TestLoginVisible(); ad_login_.SubmitActiveDirectoryCredentials( "test-user@locally-managed.localhost", "password");
diff --git a/chrome/browser/chromeos/login/screens/update_required_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/update_required_screen_browsertest.cc index 95ca0ac..855c55f 100644 --- a/chrome/browser/chromeos/login/screens/update_required_screen_browsertest.cc +++ b/chrome/browser/chromeos/login/screens/update_required_screen_browsertest.cc
@@ -25,9 +25,9 @@ #include "chrome/browser/chromeos/policy/device_policy_builder.h" #include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h" #include "chrome/browser/ui/webui/chromeos/login/error_screen_handler.h" -#include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h" #include "chrome/browser/ui/webui/chromeos/login/update_required_screen_handler.h" +#include "chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.h" #include "chrome/grit/chromium_strings.h" #include "chrome/grit/generated_resources.h" #include "chromeos/dbus/constants/dbus_switches.h" @@ -127,7 +127,7 @@ network_state_test_helper_->manager_test()->SetupDefaultEnvironment(); // Fake networks have been set up. Connect to WiFi network. SetConnected(kWifiServicePath); - chromeos::OobeScreenWaiter(chromeos::GaiaView::kScreenId).Wait(); + chromeos::OobeScreenWaiter(chromeos::UserCreationView::kScreenId).Wait(); } void TearDownOnMainThread() override { network_state_test_helper_.reset();
diff --git a/chrome/browser/chromeos/login/screens/user_selection_screen.cc b/chrome/browser/chromeos/login/screens/user_selection_screen.cc index 60f257bc..a5e25f8 100644 --- a/chrome/browser/chromeos/login/screens/user_selection_screen.cc +++ b/chrome/browser/chromeos/login/screens/user_selection_screen.cc
@@ -18,6 +18,7 @@ #include "base/metrics/histogram_macros.h" #include "base/optional.h" #include "base/strings/utf_string_conversions.h" +#include "base/time/time.h" #include "base/values.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process_platform_part.h" @@ -56,7 +57,10 @@ #include "components/user_manager/known_user.h" #include "components/user_manager/user_manager.h" #include "components/user_manager/user_type.h" +#include "content/public/browser/device_service.h" #include "google_apis/gaia/gaia_auth_util.h" +#include "services/device/public/mojom/wake_lock.mojom.h" +#include "services/device/public/mojom/wake_lock_provider.mojom.h" #include "services/network/public/cpp/shared_url_loader_factory.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" @@ -69,6 +73,9 @@ bool g_skip_force_online_signin_for_testing = false; +const char kWakeLockReason[] = "TPMLockedIssue"; +const int kWaitingOvertimeInSeconds = 1; + // User dictionary keys. const char kKeyUsername[] = "username"; const char kKeyDisplayName[] = "displayName"; @@ -376,6 +383,113 @@ DISALLOW_COPY_AND_ASSIGN(DircryptoMigrationChecker); }; +// Helper class to call cryptohome to check whether tpm is locked and update +// UI with time left to unlocking. +class UserSelectionScreen::TpmLockedChecker { + public: + explicit TpmLockedChecker(UserSelectionScreen* owner) : owner_(owner) {} + TpmLockedChecker(const TpmLockedChecker&) = delete; + TpmLockedChecker& operator=(const TpmLockedChecker&) = delete; + ~TpmLockedChecker() = default; + + void Check() { + CryptohomeClient::Get()->WaitForServiceToBeAvailable(base::BindOnce( + &TpmLockedChecker::RunCryptohomeCheck, weak_ptr_factory_.GetWeakPtr())); + } + + private: + void RunCryptohomeCheck(bool service_is_ready) { + if (!service_is_ready) { + LOG(ERROR) << "Cryptohome is not available."; + return; + } + + chromeos::CryptohomeClient::Get()->GetTpmStatus( + cryptohome::GetTpmStatusRequest(), + base::BindOnce(&TpmLockedChecker::OnGetTpmStatus, + weak_ptr_factory_.GetWeakPtr())); + } + + // Callback invoked when GetTpmStatus call is finished. + void OnGetTpmStatus(base::Optional<cryptohome::BaseReply> reply) { + check_finised_ = base::TimeTicks::Now(); + + if (!reply.has_value()) { + return; + } + if (reply->has_error() && + reply->error() != cryptohome::CRYPTOHOME_ERROR_NOT_SET) { + return; + } + if (!reply->HasExtension(cryptohome::GetTpmStatusReply::reply)) { + return; + } + auto reply_proto = + reply->GetExtension(cryptohome::GetTpmStatusReply::reply); + + if (reply_proto.dictionary_attack_lockout_in_effect()) { + int time_remaining = + reply_proto.dictionary_attack_lockout_seconds_remaining(); + // Add `kWaitingOvertimeInSeconds` for safetiness, i.e hiding UI and + // releasing `wake_lock_` happens after TPM becomes unlocked. + dictionary_attack_lockout_time_remaining_ = base::TimeDelta::FromSeconds( + time_remaining + kWaitingOvertimeInSeconds); + OnTpmIsLocked(); + } else { + TpmIsUnlocked(); + } + } + + void OnTpmIsLocked() { + AcquireWakeLock(); + clock_ticking_animator_.Start(FROM_HERE, base::TimeDelta::FromSeconds(1), + this, &TpmLockedChecker::UpdateUI); + tpm_recheck_.Start(FROM_HERE, base::TimeDelta::FromMinutes(1), this, + &TpmLockedChecker::Check); + } + + void UpdateUI() { + const base::TimeDelta time_spent = base::TimeTicks::Now() - check_finised_; + if (time_spent > dictionary_attack_lockout_time_remaining_) { + Check(); + } else { + owner_->SetTpmLockedState( + true, dictionary_attack_lockout_time_remaining_ - time_spent); + } + } + + void TpmIsUnlocked() { + clock_ticking_animator_.Stop(); + tpm_recheck_.Stop(); + owner_->SetTpmLockedState(false, base::TimeDelta()); + } + + void AcquireWakeLock() { + if (!wake_lock_) { + mojo::Remote<device::mojom::WakeLockProvider> provider; + content::GetDeviceService().BindWakeLockProvider( + provider.BindNewPipeAndPassReceiver()); + provider->GetWakeLockWithoutContext( + device::mojom::WakeLockType::kPreventDisplaySleep, + device::mojom::WakeLockReason::kOther, kWakeLockReason, + wake_lock_.BindNewPipeAndPassReceiver()); + } + wake_lock_->RequestWakeLock(); + } + + UserSelectionScreen* const owner_; + + base::TimeTicks check_finised_; + base::TimeDelta dictionary_attack_lockout_time_remaining_; + + base::RepeatingTimer clock_ticking_animator_; + base::RepeatingTimer tpm_recheck_; + + mojo::Remote<device::mojom::WakeLock> wake_lock_; + + base::WeakPtrFactory<TpmLockedChecker> weak_ptr_factory_{this}; +}; + UserSelectionScreen::UserSelectionScreen(const std::string& display_type) : BaseScreen(UserBoardView::kScreenId, OobeScreenPriority::DEFAULT), display_type_(display_type) { @@ -402,6 +516,13 @@ proximity_auth::ScreenlockBridge::Get()->SetLockHandler(this); } +void UserSelectionScreen::SetTpmLockedState(bool is_locked, + base::TimeDelta time_left) { + for (user_manager::User* user : users_) { + view_->SetTpmLockedState(user->GetAccountId(), is_locked, time_left); + } +} + // static void UserSelectionScreen::FillUserDictionary( const user_manager::User* user, @@ -584,6 +705,12 @@ activity_detector->AddObserver(this); if (!ime_state_.get()) ime_state_ = input_method::InputMethodManager::Get()->GetActiveIMEState(); + + if (tpm_locked_checker_) + return; + + tpm_locked_checker_ = std::make_unique<TpmLockedChecker>(this); + tpm_locked_checker_->Check(); } void UserSelectionScreen::OnUserImageChanged(const user_manager::User& user) {
diff --git a/chrome/browser/chromeos/login/screens/user_selection_screen.h b/chrome/browser/chromeos/login/screens/user_selection_screen.h index 6c502829..1b627f4 100644 --- a/chrome/browser/chromeos/login/screens/user_selection_screen.h +++ b/chrome/browser/chromeos/login/screens/user_selection_screen.h
@@ -6,6 +6,7 @@ #define CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_USER_SELECTION_SCREEN_H_ #include <map> +#include <memory> #include <string> #include <vector> @@ -13,6 +14,7 @@ #include "ash/public/cpp/session/user_info.h" #include "base/compiler_specific.h" #include "base/macros.h" +#include "base/time/time.h" #include "base/timer/timer.h" #include "base/values.h" #include "chrome/browser/chromeos/login/screens/base_screen.h" @@ -20,6 +22,7 @@ #include "chrome/browser/chromeos/login/ui/login_display.h" #include "chrome/browser/chromeos/settings/cros_settings.h" #include "chromeos/components/proximity_auth/screenlock_bridge.h" +#include "chromeos/dbus/cryptohome/rpc.pb.h" #include "components/account_id/account_id.h" #include "components/session_manager/core/session_manager_observer.h" #include "components/user_manager/user.h" @@ -76,6 +79,8 @@ void InitEasyUnlock(); + void SetTpmLockedState(bool is_locked, base::TimeDelta time_left); + // proximity_auth::ScreenlockBridge::LockHandler implementation: void ShowBannerMessage(const base::string16& message, bool is_warning) override; @@ -144,6 +149,7 @@ private: class DircryptoMigrationChecker; + class TpmLockedChecker; EasyUnlockService* GetEasyUnlockServiceForUser( const AccountId& account_id) const; @@ -173,6 +179,9 @@ // Helper to check whether a user needs dircrypto migration. std::unique_ptr<DircryptoMigrationChecker> dircrypto_migration_checker_; + // Helper to check whether TPM is locked or not. + std::unique_ptr<TpmLockedChecker> tpm_locked_checker_; + user_manager::UserList users_to_send_; AccountId focused_pod_account_id_;
diff --git a/chrome/browser/chromeos/login/session/chrome_session_manager_browsertest.cc b/chrome/browser/chromeos/login/session/chrome_session_manager_browsertest.cc index 538c133..1908799 100644 --- a/chrome/browser/chromeos/login/session/chrome_session_manager_browsertest.cc +++ b/chrome/browser/chromeos/login/session/chrome_session_manager_browsertest.cc
@@ -23,6 +23,7 @@ #include "chrome/browser/google/google_brand_chromeos.h" #include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h" +#include "chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.h" #include "chrome/common/chrome_switches.h" #include "chromeos/constants/chromeos_switches.h" #include "chromeos/system/fake_statistics_provider.h" @@ -99,7 +100,7 @@ fake_gaia_.SetupFakeGaiaForLoginManager(); fake_gaia_.fake_gaia()->SetFakeMergeSessionParams( FakeGaiaMixin::kFakeUserEmail, "fake_sid", "fake_lsid"); - OobeScreenWaiter(GaiaView::kScreenId).Wait(); + OobeScreenWaiter(UserCreationView::kScreenId).Wait(); LoginDisplayHost::default_host() ->GetOobeUI()
diff --git a/chrome/browser/chromeos/login/test/active_directory_login_mixin.cc b/chrome/browser/chromeos/login/test/active_directory_login_mixin.cc index c988c186..dee417d 100644 --- a/chrome/browser/chromeos/login/test/active_directory_login_mixin.cc +++ b/chrome/browser/chromeos/login/test/active_directory_login_mixin.cc
@@ -15,6 +15,7 @@ #include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h" #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h" +#include "chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.h" #include "chromeos/dbus/authpolicy/fake_authpolicy_client.h" #include "content/public/test/browser_test_utils.h" @@ -54,6 +55,8 @@ const test::UIPath kAdNewPassword2InputPath = {kPasswordChangeId, kAdNewPassword2Input}; +const test::UIPath kUserCreationNextButton = {"user-creation", "nextButton"}; + } // namespace ActiveDirectoryLoginMixin::ActiveDirectoryLoginMixin( @@ -91,6 +94,11 @@ test::OobeJS().TapOnPath(kCloseButtonId); } +void ActiveDirectoryLoginMixin::NavigateToGaiaScreen() { + OobeScreenWaiter(UserCreationView::kScreenId).Wait(); + test::OobeJS().TapOnPath(kUserCreationNextButton); +} + // Checks if Active Directory login is visible. void ActiveDirectoryLoginMixin::TestLoginVisible() { OobeScreenWaiter screen_waiter(GaiaView::kScreenId);
diff --git a/chrome/browser/chromeos/login/test/active_directory_login_mixin.h b/chrome/browser/chromeos/login/test/active_directory_login_mixin.h index cb46460..60558c3 100644 --- a/chrome/browser/chromeos/login/test/active_directory_login_mixin.h +++ b/chrome/browser/chromeos/login/test/active_directory_login_mixin.h
@@ -34,6 +34,8 @@ autocomplete_realm_ = autocomplete_realm; } + // Navigates to gaia screen from user creation screen. + void NavigateToGaiaScreen(); // Checks if Active Directory login is visible. void TestLoginVisible(); // Checks if Active Directory password change screen is shown.
diff --git a/chrome/browser/chromeos/login/test/oobe_screens_utils.cc b/chrome/browser/chromeos/login/test/oobe_screens_utils.cc index 893f355..aefef7d3 100644 --- a/chrome/browser/chromeos/login/test/oobe_screens_utils.cc +++ b/chrome/browser/chromeos/login/test/oobe_screens_utils.cc
@@ -21,6 +21,7 @@ #include "chrome/browser/ui/webui/chromeos/login/marketing_opt_in_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/network_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/update_screen_handler.h" +#include "chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.h" #include "content/public/browser/notification_service.h" #include "content/public/test/browser_test_utils.h" @@ -135,6 +136,14 @@ WaitFor(EnrollmentScreenView::kScreenId); } +void WaitForUserCreationScreen() { + WaitFor(UserCreationView::kScreenId); +} + +void TapUserCreationNext() { + test::OobeJS().TapOnPath({"user-creation", "nextButton"}); +} + void WaitForLastScreenAndTapGetStarted() { WaitFor(MarketingOptInScreenView::kScreenId); test::OobeJS().TapOnPath(
diff --git a/chrome/browser/chromeos/login/test/oobe_screens_utils.h b/chrome/browser/chromeos/login/test/oobe_screens_utils.h index e727595..208172b 100644 --- a/chrome/browser/chromeos/login/test/oobe_screens_utils.h +++ b/chrome/browser/chromeos/login/test/oobe_screens_utils.h
@@ -24,6 +24,8 @@ void ExitDiscoverPinSetupScreen(); void SkipToEnrollmentOnRecovery(); void WaitForEnrollmentScreen(); +void WaitForUserCreationScreen(); +void TapUserCreationNext(); void WaitForEulaScreen(); void TapEulaAccept();
diff --git a/chrome/browser/chromeos/login/ui/captive_portal_window_browsertest.cc b/chrome/browser/chromeos/login/ui/captive_portal_window_browsertest.cc index f05d0f33..e1d4798 100644 --- a/chrome/browser/chromeos/login/ui/captive_portal_window_browsertest.cc +++ b/chrome/browser/chromeos/login/ui/captive_portal_window_browsertest.cc
@@ -20,8 +20,10 @@ #include "chrome/browser/chromeos/login/ui/captive_portal_window_proxy.h" #include "chrome/browser/chromeos/login/ui/login_display_host.h" #include "chrome/browser/chromeos/login/ui/webui_login_view.h" +#include "chrome/browser/chromeos/login/wizard_controller.h" #include "chrome/browser/chromeos/net/network_portal_detector_test_impl.h" #include "chrome/browser/ui/webui/chromeos/login/error_screen_handler.h" +#include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h" #include "chrome/test/base/in_process_browser_test.h" #include "chromeos/constants/chromeos_switches.h" #include "chromeos/dbus/shill/fake_shill_manager_client.h" @@ -220,6 +222,10 @@ OobeUI* oobe = host->GetOobeUI(); ASSERT_TRUE(oobe); + // Skip to gaia screen. + host->GetWizardController()->SkipToLoginForTesting(); + OobeScreenWaiter(GaiaView::kScreenId).Wait(); + // Error screen asks portal detector to change detection strategy. ErrorScreen* error_screen = oobe->GetErrorScreen(); ASSERT_TRUE(error_screen);
diff --git a/chrome/browser/chromeos/login/ui/views/user_board_view.h b/chrome/browser/chromeos/login/ui/views/user_board_view.h index 28180292..95d5ade2 100644 --- a/chrome/browser/chromeos/login/ui/views/user_board_view.h +++ b/chrome/browser/chromeos/login/ui/views/user_board_view.h
@@ -54,6 +54,10 @@ virtual void SetAuthType(const AccountId& account_id, proximity_auth::mojom::AuthType auth_type, const base::string16& initial_value) = 0; + + virtual void SetTpmLockedState(const AccountId& account_id, + bool is_locked, + base::TimeDelta time_left) = 0; }; } // namespace chromeos
diff --git a/chrome/browser/chromeos/login/user_board_view_mojo.cc b/chrome/browser/chromeos/login/user_board_view_mojo.cc index 80035407..19a68af 100644 --- a/chrome/browser/chromeos/login/user_board_view_mojo.cc +++ b/chrome/browser/chromeos/login/user_board_view_mojo.cc
@@ -130,6 +130,13 @@ } } +void UserBoardViewMojo::SetTpmLockedState(const AccountId& account_id, + bool is_locked, + base::TimeDelta time_left) { + ash::LoginScreen::Get()->GetModel()->SetTpmLockedState(account_id, is_locked, + time_left); +} + base::WeakPtr<UserBoardView> UserBoardViewMojo::GetWeakPtr() { return weak_factory_.GetWeakPtr(); }
diff --git a/chrome/browser/chromeos/login/user_board_view_mojo.h b/chrome/browser/chromeos/login/user_board_view_mojo.h index 4d34e25e..3d477f5 100644 --- a/chrome/browser/chromeos/login/user_board_view_mojo.h +++ b/chrome/browser/chromeos/login/user_board_view_mojo.h
@@ -36,6 +36,9 @@ void SetAuthType(const AccountId& account_id, proximity_auth::mojom::AuthType auth_type, const base::string16& initial_value) override; + void SetTpmLockedState(const AccountId& account_id, + bool is_locked, + base::TimeDelta time_left) override; void Bind(UserSelectionScreen* screen) override {} void Unbind() override {} base::WeakPtr<UserBoardView> GetWeakPtr() override;
diff --git a/chrome/browser/chromeos/login/webview_login_browsertest.cc b/chrome/browser/chromeos/login/webview_login_browsertest.cc index acd5e27..1786596c 100644 --- a/chrome/browser/chromeos/login/webview_login_browsertest.cc +++ b/chrome/browser/chromeos/login/webview_login_browsertest.cc
@@ -33,6 +33,7 @@ #include "chrome/browser/chromeos/login/test/js_checker.h" #include "chrome/browser/chromeos/login/test/local_policy_test_server_mixin.h" #include "chrome/browser/chromeos/login/test/oobe_base_test.h" +#include "chrome/browser/chromeos/login/test/oobe_screen_exit_waiter.h" #include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h" #include "chrome/browser/chromeos/login/test/session_manager_state_waiter.h" #include "chrome/browser/chromeos/login/ui/login_display_host.h" @@ -48,6 +49,7 @@ #include "chrome/browser/ui/webui/chromeos/login/error_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/eula_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h" +#include "chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.h" #include "chrome/browser/ui/webui/signin/signin_utils.h" #include "chrome/test/base/ui_test_utils.h" #include "chromeos/constants/chromeos_features.h" @@ -303,9 +305,9 @@ protected: chromeos::ScopedTestingCrosSettings scoped_testing_cros_settings_; FakeGaiaMixin fake_gaia_{&mixin_host_, embedded_test_server()}; + base::test::ScopedFeatureList scoped_feature_list_; private: - base::test::ScopedFeatureList scoped_feature_list_; DISALLOW_COPY_AND_ASSIGN(WebviewLoginTest); }; @@ -423,18 +425,16 @@ test::WaitForPrimaryUserSessionStart(); } -IN_PROC_BROWSER_TEST_F(WebviewLoginTest, ErrorScreenOnGaiaError) { +IN_PROC_BROWSER_TEST_F(WebviewLoginTest, BackToUserCreationScreen) { WaitForGaiaPageLoadAndPropertyUpdate(); + + // Start with identifier page. ExpectIdentifierPage(); - // Make gaia landing page unreachable - fake_gaia_.fake_gaia()->SetErrorResponse( - GaiaUrls::GetInstance()->embedded_setup_chromeos_url(2), - net::HTTP_NOT_FOUND); - - // Click back to reload (unreachable) identifier page. + // Click back to exit gaia screen. test::OobeJS().ClickOnPath({"gaia-signin", "signin-back-button"}); - OobeScreenWaiter(ErrorScreenView::kScreenId).Wait(); + OobeScreenExitWaiter(GaiaView::kScreenId).Wait(); + OobeScreenWaiter(UserCreationView::kScreenId).Wait(); } // Create new account option should be available only if the settings allow it. @@ -658,7 +658,12 @@ // Base class for tests of the client certificates in the sign-in frame. class WebviewClientCertsLoginTestBase : public WebviewLoginTest { public: - WebviewClientCertsLoginTestBase() = default; + WebviewClientCertsLoginTestBase() { + // TODO(crbug.com/1101318): Fix tests when kChildSpecificSignin is enabled. + scoped_feature_list_.Reset(); + scoped_feature_list_.InitWithFeatures({features::kGaiaActionButtons}, + {features::kChildSpecificSignin}); + } WebviewClientCertsLoginTestBase(const WebviewClientCertsLoginTestBase&) = delete; WebviewClientCertsLoginTestBase& operator=( @@ -1327,4 +1332,28 @@ ExpectIdentifierPage(); } +class WebviewLoginTestWithChildSigninDisabled : public WebviewLoginTest { + public: + WebviewLoginTestWithChildSigninDisabled() { + scoped_feature_list_.Reset(); + scoped_feature_list_.InitWithFeatures({features::kGaiaActionButtons}, + {features::kChildSpecificSignin}); + } +}; + +IN_PROC_BROWSER_TEST_F(WebviewLoginTestWithChildSigninDisabled, + ErrorScreenOnGaiaError) { + WaitForGaiaPageLoadAndPropertyUpdate(); + ExpectIdentifierPage(); + + // Make gaia landing page unreachable + fake_gaia_.fake_gaia()->SetErrorResponse( + GaiaUrls::GetInstance()->embedded_setup_chromeos_url(2), + net::HTTP_NOT_FOUND); + + // Click back to reload (unreachable) identifier page. + test::OobeJS().ClickOnPath({"gaia-signin", "signin-back-button"}); + OobeScreenWaiter(ErrorScreenView::kScreenId).Wait(); +} + } // namespace chromeos
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc index f8ef4cf..7b4df43 100644 --- a/chrome/browser/chromeos/login/wizard_controller.cc +++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -654,9 +654,6 @@ if (login_screen_started_) return; - // Landed on the login screen. No longer skipping enrollment for tests. - wizard_context_->skip_to_login_for_tests = false; - if (!time_eula_accepted_.is_null()) { base::TimeDelta delta = base::TimeTicks::Now() - time_eula_accepted_; UMA_HISTOGRAM_MEDIUM_TIMES("OOBE.EULAToSignInTime", delta); @@ -1538,10 +1535,10 @@ void WizardController::SetCurrentScreen(BaseScreen* new_current) { VLOG(1) << "SetCurrentScreen: " << (new_current ? new_current->screen_id().name : "null"); - if (current_screen_ == new_current || GetOobeUI() == nullptr) + if (new_current && new_current->MaybeSkip(wizard_context_.get())) return; - if (new_current && new_current->MaybeSkip(wizard_context_.get())) + if (current_screen_ == new_current || GetOobeUI() == nullptr) return; if (current_screen_) {
diff --git a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc index b541e95..787eee9 100644 --- a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc +++ b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
@@ -66,11 +66,11 @@ #include "chrome/browser/lifetime/browser_shutdown.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/webui/chromeos/login/error_screen_handler.h" -#include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h" #include "chrome/browser/ui/webui/chromeos/login/reset_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/update_required_screen_handler.h" +#include "chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/pref_names.h" #include "chrome/grit/generated_resources.h" @@ -1460,7 +1460,7 @@ // Don't expect that the auto enrollment screen will be hidden, because // OOBE is exited from the auto enrollment screen. Instead only expect // that the sign-in screen is reached. - OobeScreenWaiter(GaiaView::kScreenId).Wait(); + OobeScreenWaiter(UserCreationView::kScreenId).Wait(); EXPECT_EQ( 0, FakeCryptohomeClient::Get() ->remove_firmware_management_parameters_from_tpm_call_count());
diff --git a/chrome/browser/chromeos/policy/cloud_external_data_manager_base.cc b/chrome/browser/chromeos/policy/cloud_external_data_manager_base.cc index 51bfd47..4f0ebac50 100644 --- a/chrome/browser/chromeos/policy/cloud_external_data_manager_base.cc +++ b/chrome/browser/chromeos/policy/cloud_external_data_manager_base.cc
@@ -10,11 +10,11 @@ #include <map> #include <string> #include <utility> -#include <vector> #include "base/bind.h" #include "base/bind_helpers.h" #include "base/callback.h" +#include "base/callback_list.h" #include "base/check_op.h" #include "base/files/file_path.h" #include "base/location.h" @@ -22,6 +22,7 @@ #include "base/notreached.h" #include "base/sequenced_task_runner.h" #include "base/single_thread_task_runner.h" +#include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "base/threading/thread_task_runner_handle.h" #include "base/values.h" @@ -104,10 +105,11 @@ private: // List of callbacks to invoke when the attempt to retrieve external data // referenced by a policy completes successfully or fails permanently. - typedef std::vector<ExternalDataFetcher::FetchCallback> FetchCallbackList; + using FetchCallbackList = + base::OnceCallbackList<void(const std::string*, const base::FilePath&)>; // Map from policy names to the lists of callbacks defined above. - typedef std::map<std::string, FetchCallbackList> FetchCallbackMap; + using FetchCallbackMap = std::map<std::string, FetchCallbackList>; // Looks up the maximum size that the data referenced by |policy| can have. size_t GetMaxExternalDataSize(const std::string& policy) const; @@ -214,11 +216,8 @@ // Cancel the external data download. updater_->CancelExternalDataFetch(policy); } - for (ExternalDataFetcher::FetchCallback& callback : it->second) { - // Invoke all callbacks for |policy|, indicating permanent failure. - RunCallback(std::move(callback), std::unique_ptr<std::string>(), - base::FilePath()); - } + // Invoke all callbacks for |policy|, indicating permanent failure. + it->second.Notify(nullptr, base::FilePath()); pending_downloads_.erase(it++); continue; } @@ -244,11 +243,7 @@ if (external_data_store_) file_path = external_data_store_->Store(policy, hash, data); - FetchCallbackList& pending_callbacks = pending_downloads_[policy]; - for (ExternalDataFetcher::FetchCallback& callback : pending_callbacks) { - RunCallback(std::move(callback), std::make_unique<std::string>(data), - file_path); - } + pending_downloads_[policy].Notify(&data, file_path); pending_downloads_.erase(policy); return true; } @@ -262,22 +257,14 @@ if (metadata == metadata_.end()) { // If |policy| does not reference any external data, indicate permanent // failure. - RunCallback(std::move(callback), std::unique_ptr<std::string>(), - base::FilePath()); + RunCallback(std::move(callback), nullptr, base::FilePath()); return; } - if (pending_downloads_.find(policy) != pending_downloads_.end()) { - // If a download of the external data referenced by |policy| has already - // been requested, add |callback| to the list of callbacks for |policy| and - // return. - pending_downloads_[policy].push_back(std::move(callback)); - return; - } - - std::unique_ptr<std::string> data(new std::string); - if (external_data_store_) { - base::FilePath file_path = + const bool has_pending_download = base::Contains(pending_downloads_, policy); + if (!has_pending_download && external_data_store_) { + auto data = std::make_unique<std::string>(); + const base::FilePath file_path = external_data_store_->Load(policy, metadata->second.hash, GetMaxExternalDataSize(policy), data.get()); if (!file_path.empty()) { @@ -288,10 +275,22 @@ } } - // Request a download of the the external data referenced by |policy| and - // initialize the list of callbacks by adding |callback|. - pending_downloads_[policy].push_back(std::move(callback)); - StartDownload(policy); + // Callback lists cannot hold callbacks that take move-only args, since + // Notify()ing such a list would move the arg into the first callback, leaving + // it null or unspecified for remaining callbacks. Instead, adapt the + // provided callbacks to accept a raw pointer, which can be copied, and then + // wrap in a separate scoping object for each callback. + pending_downloads_[policy].AddUnsafe(base::BindOnce( + [](const CloudExternalDataManagerBase::Backend* backend, + ExternalDataFetcher::FetchCallback callback, const std::string* data, + const base::FilePath& file_path) { + backend->RunCallback( + std::move(callback), + data ? std::make_unique<std::string>(*data) : nullptr, file_path); + }, + base::Unretained(this), std::move(callback))); + if (!has_pending_download) + StartDownload(policy); } void CloudExternalDataManagerBase::Backend::FetchAll() { @@ -300,7 +299,7 @@ for (const auto& it : metadata_) { const std::string& policy = it.first; std::unique_ptr<std::string> data(new std::string); - if (pending_downloads_.find(policy) != pending_downloads_.end() || + if (base::Contains(pending_downloads_, policy) || (external_data_store_ && !external_data_store_ ->Load(policy, it.second.hash, GetMaxExternalDataSize(policy), @@ -349,7 +348,7 @@ void CloudExternalDataManagerBase::Backend::StartDownload( const std::string& policy) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(pending_downloads_.find(policy) != pending_downloads_.end()); + DCHECK(base::Contains(pending_downloads_, policy)); if (!updater_) return;
diff --git a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc index b6a2560..f0b18e4 100644 --- a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc +++ b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
@@ -97,10 +97,10 @@ #include "chrome/browser/ui/browser_list_observer.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" -#include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h" #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/terms_of_service_screen_handler.h" +#include "chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.h" #include "chrome/browser/web_applications/web_app_provider.h" #include "chrome/common/chrome_features.h" #include "chrome/common/chrome_paths.h" @@ -465,7 +465,7 @@ run_loop.Run(); // Skip to the login screen. - chromeos::OobeScreenWaiter(chromeos::GaiaView::kScreenId).Wait(); + chromeos::OobeScreenWaiter(chromeos::UserCreationView::kScreenId).Wait(); chromeos::test::UserSessionManagerTestApi session_manager_test_api( chromeos::UserSessionManager::GetInstance());
diff --git a/chrome/browser/chromeos/policy/device_login_screen_policy_browsertest.cc b/chrome/browser/chromeos/policy/device_login_screen_policy_browsertest.cc index 8519462..89512a9d 100644 --- a/chrome/browser/chromeos/policy/device_login_screen_policy_browsertest.cc +++ b/chrome/browser/chromeos/policy/device_login_screen_policy_browsertest.cc
@@ -27,8 +27,8 @@ #include "chrome/browser/lifetime/application_lifetime.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_manager.h" -#include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/reset_screen_handler.h" +#include "chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.h" #include "chrome/common/pref_names.h" #include "chromeos/constants/chromeos_switches.h" #include "components/policy/core/common/policy_types.h" @@ -230,7 +230,7 @@ // Tests that adding public accounts does not close the Oobe dialog when it // shows a screen different from the Gaia login screen. IN_PROC_BROWSER_TEST_F(DeviceLoginScreenPolicyBrowsertest, ResetScreen) { - chromeos::OobeScreenWaiter(chromeos::GaiaView::kScreenId).Wait(); + chromeos::OobeScreenWaiter(chromeos::UserCreationView::kScreenId).Wait(); EXPECT_TRUE(ash::LoginScreenTestApi::IsOobeDialogVisible()); EXPECT_EQ(ash::LoginScreenTestApi::GetUsersCount(), 0);
diff --git a/chrome/browser/chromeos/policy/minimum_version_policy_handler_browsertest.cc b/chrome/browser/chromeos/policy/minimum_version_policy_handler_browsertest.cc index 7117af81..1ae56b2 100644 --- a/chrome/browser/chromeos/policy/minimum_version_policy_handler_browsertest.cc +++ b/chrome/browser/chromeos/policy/minimum_version_policy_handler_browsertest.cc
@@ -40,8 +40,8 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" -#include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/update_required_screen_handler.h" +#include "chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.h" #include "chrome/browser/upgrade_detector/upgrade_detector.h" #include "chrome/common/pref_names.h" #include "chromeos/constants/chromeos_features.h" @@ -804,7 +804,7 @@ IN_PROC_BROWSER_TEST_F(MinimumVersionNoUsersLoginTest, CriticalUpdateOnLoginScreen) { - chromeos::OobeScreenWaiter(chromeos::GaiaView::kScreenId).Wait(); + chromeos::OobeScreenWaiter(chromeos::UserCreationView::kScreenId).Wait(); EXPECT_EQ(ash::LoginScreenTestApi::GetUsersCount(), 0); // Create and set policy value. @@ -825,7 +825,7 @@ SetDevicePolicyAndWaitForSettingChange(empty_policy); chromeos::OobeScreenExitWaiter(chromeos::UpdateRequiredView::kScreenId) .Wait(); - chromeos::OobeScreenWaiter(chromeos::GaiaView::kScreenId).Wait(); + chromeos::OobeScreenWaiter(chromeos::UserCreationView::kScreenId).Wait(); } class MinimumVersionPolicyPresentTest : public MinimumVersionPolicyTestBase {
diff --git a/chrome/browser/chromeos/policy/policy_certs_browsertest.cc b/chrome/browser/chromeos/policy/policy_certs_browsertest.cc index 3c6715c..f0b03aa 100644 --- a/chrome/browser/chromeos/policy/policy_certs_browsertest.cc +++ b/chrome/browser/chromeos/policy/policy_certs_browsertest.cc
@@ -36,6 +36,7 @@ #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h" +#include "chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.h" #include "chrome/common/chrome_paths.h" #include "chrome/test/base/in_process_browser_test.h" #include "chromeos/constants/chromeos_switches.h" @@ -881,7 +882,7 @@ // caches), the test is able to catch that. IN_PROC_BROWSER_TEST_P(PolicyProvidedCertsForSigninExtensionTest, ActiveOnlyInSelectedExtension) { - chromeos::OobeScreenWaiter(chromeos::GaiaView::kScreenId).Wait(); + chromeos::OobeScreenWaiter(chromeos::UserCreationView::kScreenId).Wait(); content::StoragePartition* signin_profile_default_partition = content::BrowserContext::GetDefaultStoragePartition(signin_profile_);
diff --git a/chrome/browser/chromeos/policy/server_backed_state_keys_broker.cc b/chrome/browser/chromeos/policy/server_backed_state_keys_broker.cc index 32f2298d..ada95496 100644 --- a/chrome/browser/chromeos/policy/server_backed_state_keys_broker.cc +++ b/chrome/browser/chromeos/policy/server_backed_state_keys_broker.cc
@@ -32,7 +32,7 @@ ServerBackedStateKeysBroker::Subscription ServerBackedStateKeysBroker::RegisterUpdateCallback( - const base::RepeatingClosure& callback) { + const UpdateCallback& callback) { if (!available()) FetchStateKeys(); return update_callbacks_.Add(callback); @@ -40,7 +40,7 @@ void ServerBackedStateKeysBroker::RequestStateKeys(StateKeysCallback callback) { if (!available()) { - request_callbacks_.push_back(std::move(callback)); + request_callbacks_.AddUnsafe(std::move(callback)); FetchStateKeys(); return; } @@ -80,12 +80,7 @@ if (send_notification) update_callbacks_.Notify(); - std::vector<StateKeysCallback> callbacks; - request_callbacks_.swap(callbacks); - for (auto& callback : callbacks) { - if (!callback.is_null()) - std::move(callback).Run(state_keys_); - } + request_callbacks_.Notify(state_keys_); base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE,
diff --git a/chrome/browser/chromeos/policy/server_backed_state_keys_broker.h b/chrome/browser/chromeos/policy/server_backed_state_keys_broker.h index b42ab2a..6d5099b 100644 --- a/chrome/browser/chromeos/policy/server_backed_state_keys_broker.h +++ b/chrome/browser/chromeos/policy/server_backed_state_keys_broker.h
@@ -25,10 +25,12 @@ // register callbacks to invoke when the state keys change. class ServerBackedStateKeysBroker { public: - typedef std::unique_ptr<base::CallbackList<void()>::Subscription> - Subscription; - typedef base::OnceCallback<void(const std::vector<std::string>&)> - StateKeysCallback; + using UpdateCallbackList = base::CallbackList<void()>; + using UpdateCallback = UpdateCallbackList::CallbackType; + using Subscription = std::unique_ptr<UpdateCallbackList::Subscription>; + using StateKeysCallbackList = + base::OnceCallbackList<void(const std::vector<std::string>&)>; + using StateKeysCallback = StateKeysCallbackList::CallbackType; ServerBackedStateKeysBroker( chromeos::SessionManagerClient* session_manager_client); @@ -38,7 +40,7 @@ // Note that consuming code needs to hold on to the returned Subscription as // long as it wants to receive the callback. If the state keys haven't been // requested yet, calling this will also trigger their initial fetch. - Subscription RegisterUpdateCallback(const base::RepeatingClosure& callback); + Subscription RegisterUpdateCallback(const UpdateCallback& callback); // Requests state keys asynchronously. Invokes the passed callback at most // once, with the current state keys passed as a parameter to the callback. If @@ -80,10 +82,10 @@ bool requested_; // List of callbacks to receive update notifications. - base::CallbackList<void()> update_callbacks_; + UpdateCallbackList update_callbacks_; // List of pending one-shot state key request callbacks. - std::vector<StateKeysCallback> request_callbacks_; + StateKeysCallbackList request_callbacks_; base::WeakPtrFactory<ServerBackedStateKeysBroker> weak_factory_{this};
diff --git a/chrome/browser/chromeos/system/device_disabling_browsertest.cc b/chrome/browser/chromeos/system/device_disabling_browsertest.cc index d290cf9..359e166 100644 --- a/chrome/browser/chromeos/system/device_disabling_browsertest.cc +++ b/chrome/browser/chromeos/system/device_disabling_browsertest.cc
@@ -26,10 +26,10 @@ #include "chrome/browser/chromeos/settings/cros_settings.h" #include "chrome/browser/chromeos/system/device_disabling_manager.h" #include "chrome/browser/ui/webui/chromeos/login/device_disabled_screen_handler.h" -#include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/network_state_informer.h" #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h" #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h" +#include "chrome/browser/ui/webui/chromeos/login/user_creation_screen_handler.h" #include "chromeos/constants/chromeos_switches.h" #include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/session_manager/fake_session_manager_client.h" @@ -159,7 +159,7 @@ connect_run_loop.Run(); // Skip to the login screen. - OobeScreenWaiter(GaiaView::kScreenId).Wait(); + OobeScreenWaiter(UserCreationView::kScreenId).Wait(); // Mark the device as disabled and wait until cros settings update. MarkDisabledAndWaitForPolicyFetch(); @@ -227,7 +227,7 @@ IN_PROC_BROWSER_TEST_F(DeviceDisablingWithUsersTest, DialogNotHidden) { EXPECT_TRUE(ash::LoginScreenTestApi::ClickAddUserButton()); EXPECT_TRUE(ash::LoginScreenTestApi::IsOobeDialogVisible()); - OobeScreenWaiter(GaiaView::kScreenId).Wait(); + OobeScreenWaiter(UserCreationView::kScreenId).Wait(); MarkDisabledAndWaitForPolicyFetch(); OobeScreenWaiter(DeviceDisabledScreenView::kScreenId).Wait(); LoginDisplayHost::default_host()->StartSignInScreen();
diff --git a/chrome/browser/chromeos/system_token_cert_db_initializer.cc b/chrome/browser/chromeos/system_token_cert_db_initializer.cc index 3376299..c0245b3 100644 --- a/chrome/browser/chromeos/system_token_cert_db_initializer.cc +++ b/chrome/browser/chromeos/system_token_cert_db_initializer.cc
@@ -139,10 +139,11 @@ DCHECK(callback); - if (system_token_cert_database_) + if (system_token_cert_database_) { std::move(callback).Run(system_token_cert_database_.get()); - else - get_system_token_cert_db_callback_list_.push_back(std::move(callback)); + } else { + get_system_token_cert_db_callback_list_.AddUnsafe(std::move(callback)); + } } void SystemTokenCertDBInitializer::AddObserver( @@ -210,18 +211,6 @@ FROM_HERE, base::BindOnce(&GetSystemSlotOnIOThread, callback)); } -void SystemTokenCertDBInitializer:: - RunAndClearGetSystemTokenCertDbCallbackList() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(system_token_cert_database_); - - std::vector<GetSystemTokenCertDbCallback> callback_list = - std::move(get_system_token_cert_db_callback_list_); - for (auto& callback : callback_list) { - std::move(callback).Run(system_token_cert_database_.get()); - } -} - void SystemTokenCertDBInitializer::InitializeDatabase( crypto::ScopedPK11Slot system_slot) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -239,7 +228,8 @@ database->SetSystemSlot(std::move(system_slot_copy)); system_token_cert_database_ = std::move(database); - RunAndClearGetSystemTokenCertDbCallbackList(); + get_system_token_cert_db_callback_list_.Notify( + system_token_cert_database_.get()); VLOG(1) << "SystemTokenCertDBInitializer: Passing system token NSS " "database to NetworkCertLoader.";
diff --git a/chrome/browser/chromeos/system_token_cert_db_initializer.h b/chrome/browser/chromeos/system_token_cert_db_initializer.h index 1950607..a44b63a 100644 --- a/chrome/browser/chromeos/system_token_cert_db_initializer.h +++ b/chrome/browser/chromeos/system_token_cert_db_initializer.h
@@ -9,6 +9,7 @@ #include <vector> #include "base/callback_forward.h" +#include "base/callback_list.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" @@ -86,10 +87,6 @@ // database, unless it was already started before. void MaybeStartInitializingDatabase(); - // This is called when the system token certificate database is created to run - // all entries in |get_system_token_cert_db_callback_list_| and clear it. - void RunAndClearGetSystemTokenCertDbCallbackList(); - // Initializes the global system token NSSCertDatabase with |system_slot|. // Also starts NetworkCertLoader with the system token database. void InitializeDatabase(crypto::ScopedPK11Slot system_slot); @@ -102,7 +99,7 @@ // List of callbacks that should be executed when the system token certificate // database is created. - std::vector<GetSystemTokenCertDbCallback> + base::OnceCallbackList<GetSystemTokenCertDbCallback::RunType> get_system_token_cert_db_callback_list_; // List of observers that will be notified when the global system token
diff --git a/chrome/browser/devtools/devtools_ui_bindings.cc b/chrome/browser/devtools/devtools_ui_bindings.cc index ddd8f65..20f850f2 100644 --- a/chrome/browser/devtools/devtools_ui_bindings.cc +++ b/chrome/browser/devtools/devtools_ui_bindings.cc
@@ -1523,11 +1523,13 @@ return agent_host_.get() == agent_host; } -void DevToolsUIBindings::CallClientMethod(const std::string& object_name, - const std::string& method_name, - const base::Value& arg1, - const base::Value& arg2, - const base::Value& arg3) { +void DevToolsUIBindings::CallClientMethod( + const std::string& object_name, + const std::string& method_name, + const base::Value& arg1, + const base::Value& arg2, + const base::Value& arg3, + base::OnceCallback<void(base::Value)> completion_callback) { // If we're not exposing bindings, we shouldn't call functions either. if (!frontend_host_) return; @@ -1547,7 +1549,7 @@ } javascript.append(");"); web_contents_->GetMainFrame()->ExecuteJavaScript( - base::UTF8ToUTF16(javascript), base::NullCallback()); + base::UTF8ToUTF16(javascript), std::move(completion_callback)); } void DevToolsUIBindings::ReadyToCommitNavigation(
diff --git a/chrome/browser/devtools/devtools_ui_bindings.h b/chrome/browser/devtools/devtools_ui_bindings.h index b3e3ad1d..d7d4361 100644 --- a/chrome/browser/devtools/devtools_ui_bindings.h +++ b/chrome/browser/devtools/devtools_ui_bindings.h
@@ -80,11 +80,14 @@ // Takes ownership over the |delegate|. void SetDelegate(Delegate* delegate); - void CallClientMethod(const std::string& object_name, - const std::string& method_name, - const base::Value& arg1 = {}, - const base::Value& arg2 = {}, - const base::Value& arg3 = {}); + void CallClientMethod( + const std::string& object_name, + const std::string& method_name, + const base::Value& arg1 = {}, + const base::Value& arg2 = {}, + const base::Value& arg3 = {}, + base::OnceCallback<void(base::Value)> completion_callback = + base::OnceCallback<void(base::Value)>()); void AttachTo(const scoped_refptr<content::DevToolsAgentHost>& agent_host); void Detach(); bool IsAttachedTo(content::DevToolsAgentHost* agent_host);
diff --git a/chrome/browser/devtools/devtools_window.cc b/chrome/browser/devtools/devtools_window.cc index 3c29640d..7ebe9562 100644 --- a/chrome/browser/devtools/devtools_window.cc +++ b/chrome/browser/devtools/devtools_window.cc
@@ -406,6 +406,10 @@ if (throttle_) throttle_->ResumeThrottle(); + if (reattach_complete_callback_) { + std::move(reattach_complete_callback_).Run(); + } + life_stage_ = kClosing; UpdateBrowserWindow(); @@ -767,12 +771,19 @@ } void DevToolsWindow::UpdateInspectedWebContents( - content::WebContents* new_web_contents) { + content::WebContents* new_web_contents, + base::OnceCallback<void()> callback) { + DCHECK(!reattach_complete_callback_); + reattach_complete_callback_ = std::move(callback); + inspected_contents_observer_ = std::make_unique<ObserverWithAccessor>(new_web_contents); bindings_->AttachTo( content::DevToolsAgentHost::GetOrCreateFor(new_web_contents)); - bindings_->CallClientMethod("DevToolsAPI", "reattachMainTarget"); + bindings_->CallClientMethod( + "DevToolsAPI", "reattachMainTarget", {}, {}, {}, + base::BindOnce(&DevToolsWindow::OnReattachMainTargetComplete, + base::Unretained(this))); } void DevToolsWindow::ScheduleShow(const DevToolsToggleAction& action) { @@ -1640,3 +1651,7 @@ web_modal::WebContentsModalDialogManager::FromWebContents(main_web_contents_) ->SetDelegate(browser); } + +void DevToolsWindow::OnReattachMainTargetComplete(base::Value) { + std::move(reattach_complete_callback_).Run(); +}
diff --git a/chrome/browser/devtools/devtools_window.h b/chrome/browser/devtools/devtools_window.h index e2c979c..18fa5e9 100644 --- a/chrome/browser/devtools/devtools_window.h +++ b/chrome/browser/devtools/devtools_window.h
@@ -128,7 +128,8 @@ // Updates the WebContents inspected by the DevToolsWindow by reattaching // the binding to |new_web_contents|. Called when swapping an outer // WebContents with its inner WebContents. - void UpdateInspectedWebContents(content::WebContents* new_web_contents); + void UpdateInspectedWebContents(content::WebContents* new_web_contents, + base::OnceCallback<void()> callback); // Sets closure to be called after load is done. If already loaded, calls // closure immediately. @@ -381,6 +382,8 @@ // display web modal dialogs triggered by it. void RegisterModalDialogManager(Browser* browser); + void OnReattachMainTargetComplete(base::Value); + std::unique_ptr<ObserverWithAccessor> inspected_contents_observer_; FrontendType frontend_type_; @@ -426,6 +429,8 @@ Throttle* throttle_ = nullptr; bool open_new_window_for_popups_ = false; + base::OnceCallback<void()> reattach_complete_callback_; + friend class DevToolsEventForwarder; DISALLOW_COPY_AND_ASSIGN(DevToolsWindow); };
diff --git a/chrome/browser/nearby_sharing/fake_nearby_connection.cc b/chrome/browser/nearby_sharing/fake_nearby_connection.cc index b44d3371..5b346694 100644 --- a/chrome/browser/nearby_sharing/fake_nearby_connection.cc +++ b/chrome/browser/nearby_sharing/fake_nearby_connection.cc
@@ -52,6 +52,10 @@ return bytes; } +bool FakeNearbyConnection::IsClosed() { + return closed_; +} + void FakeNearbyConnection::MaybeRunCallback() { DCHECK(!closed_); if (!callback_ || read_data_.empty())
diff --git a/chrome/browser/nearby_sharing/fake_nearby_connection.h b/chrome/browser/nearby_sharing/fake_nearby_connection.h index a54578b..aa64111 100644 --- a/chrome/browser/nearby_sharing/fake_nearby_connection.h +++ b/chrome/browser/nearby_sharing/fake_nearby_connection.h
@@ -24,6 +24,8 @@ void AppendReadableData(std::vector<uint8_t> bytes); std::vector<uint8_t> GetWrittenData(); + bool IsClosed(); + private: void MaybeRunCallback();
diff --git a/chrome/browser/nearby_sharing/fake_nearby_connections_manager.cc b/chrome/browser/nearby_sharing/fake_nearby_connections_manager.cc index 3a77f7db..c1859105 100644 --- a/chrome/browser/nearby_sharing/fake_nearby_connections_manager.cc +++ b/chrome/browser/nearby_sharing/fake_nearby_connections_manager.cc
@@ -99,10 +99,20 @@ FakeNearbyConnectionsManager::GetRawAuthenticationToken( const std::string& endpoint_id) { DCHECK(!IsShutdown()); - // TODO(alexchau): Implement. + + auto iter = endpoint_auth_tokens_.find(endpoint_id); + if (iter != endpoint_auth_tokens_.end()) + return iter->second; + return base::nullopt; } +void FakeNearbyConnectionsManager::SetRawAuthenticationToken( + const std::string& endpoint_id, + std::vector<uint8_t> token) { + endpoint_auth_tokens_[endpoint_id] = std::move(token); +} + void FakeNearbyConnectionsManager::UpgradeBandwidth( const std::string& endpoint_id) { upgrade_bandwidth_endpoint_ids_.insert(endpoint_id);
diff --git a/chrome/browser/nearby_sharing/fake_nearby_connections_manager.h b/chrome/browser/nearby_sharing/fake_nearby_connections_manager.h index 83703abf..3e606f1 100644 --- a/chrome/browser/nearby_sharing/fake_nearby_connections_manager.h +++ b/chrome/browser/nearby_sharing/fake_nearby_connections_manager.h
@@ -51,6 +51,9 @@ const std::string& endpoint_id) override; void UpgradeBandwidth(const std::string& endpoint_id) override; + void SetRawAuthenticationToken(const std::string& endpoint_id, + std::vector<uint8_t> token); + // mojom::EndpointDiscoveryListener: void OnEndpointFound( const std::string& endpoint_id, @@ -73,6 +76,7 @@ DataUsage advertising_data_usage_ = DataUsage::kUnknown; PowerLevel advertising_power_level_ = PowerLevel::kUnknown; std::set<std::string> upgrade_bandwidth_endpoint_ids_; + std::map<std::string, std::vector<uint8_t>> endpoint_auth_tokens_; }; #endif // CHROME_BROWSER_NEARBY_SHARING_FAKE_NEARBY_CONNECTIONS_MANAGER_H_
diff --git a/chrome/browser/nearby_sharing/mock_nearby_connections.h b/chrome/browser/nearby_sharing/mock_nearby_connections.h index d0086f36..934bae1 100644 --- a/chrome/browser/nearby_sharing/mock_nearby_connections.h +++ b/chrome/browser/nearby_sharing/mock_nearby_connections.h
@@ -78,6 +78,10 @@ CancelPayload, (int64_t payload_id, CancelPayloadCallback callback), (override)); + MOCK_METHOD(void, + StopAllEndpoints, + (DisconnectFromEndpointCallback callback), + (override)); }; #endif // CHROME_BROWSER_NEARBY_SHARING_MOCK_NEARBY_CONNECTIONS_H_
diff --git a/chrome/browser/nearby_sharing/nearby_connections_manager.h b/chrome/browser/nearby_sharing/nearby_connections_manager.h index 7447d75..5fcd337 100644 --- a/chrome/browser/nearby_sharing/nearby_connections_manager.h +++ b/chrome/browser/nearby_sharing/nearby_connections_manager.h
@@ -66,6 +66,8 @@ virtual ~NearbyConnectionsManager() = default; // Disconnects from all endpoints and shut down Nearby Connections. + // As a side effect of this call, both StopAdvertising and StopDiscovery may + // be invoked if Nearby Connections is advertising or discovering. virtual void Shutdown() = 0; // Starts advertising through Nearby Connections. Caller is expected to ensure
diff --git a/chrome/browser/nearby_sharing/nearby_connections_manager_impl.cc b/chrome/browser/nearby_sharing/nearby_connections_manager_impl.cc index 7d37df3..1aa7c34f7 100644 --- a/chrome/browser/nearby_sharing/nearby_connections_manager_impl.cc +++ b/chrome/browser/nearby_sharing/nearby_connections_manager_impl.cc
@@ -59,6 +59,8 @@ void NearbyConnectionsManagerImpl::Shutdown() { // TOOD(crbug/1076008): Implement. + // Disconnects from all endpoints and shut down Nearby Connections. + Reset(); } void NearbyConnectionsManagerImpl::StartAdvertising( @@ -95,8 +97,15 @@ } void NearbyConnectionsManagerImpl::StopAdvertising() { - if (nearby_connections_) - nearby_connections_->StopAdvertising(base::DoNothing()); + if (nearby_connections_) { + nearby_connections_->StopAdvertising(base::BindOnce([](ConnectionsStatus + status) { + NS_LOG(VERBOSE) + << __func__ + << ": Stop advertising attempted over Nearby Connections with result " + << status; + })); + } incoming_connection_listener_ = nullptr; } @@ -120,8 +129,15 @@ } void NearbyConnectionsManagerImpl::StopDiscovery() { - if (nearby_connections_) - nearby_connections_->StopDiscovery(base::DoNothing()); + if (nearby_connections_) { + nearby_connections_->StopDiscovery( + base::BindOnce([](ConnectionsStatus status) { + NS_LOG(VERBOSE) << __func__ + << ": Stop discovery attempted over Nearby " + "Connections with result " + << status; + })); + } discovered_endpoints_.clear(); discovery_listener_ = nullptr; @@ -158,7 +174,16 @@ ConnectionsStatus status) { if (status != ConnectionsStatus::kSuccess) { NS_LOG(ERROR) << "Failed to connect to the remote shareTarget: " << status; - nearby_connections_->DisconnectFromEndpoint(endpoint_id, base::DoNothing()); + nearby_connections_->DisconnectFromEndpoint( + endpoint_id, + base::BindOnce( + [](const std::string& endpoint_id, ConnectionsStatus status) { + NS_LOG(VERBOSE) + << __func__ << ": Disconnecting from endpoint " << endpoint_id + << " attempted over Nearby Connections with result " + << status; + }, + endpoint_id)); std::move(callback).Run(nullptr); return; } @@ -174,7 +199,16 @@ if (!nearby_connections_) return; - nearby_connections_->DisconnectFromEndpoint(endpoint_id, base::DoNothing()); + nearby_connections_->DisconnectFromEndpoint( + endpoint_id, + base::BindOnce( + [](const std::string& endpoint_id, ConnectionsStatus status) { + NS_LOG(VERBOSE) + << __func__ << ": Disconnecting from endpoint " << endpoint_id + << " attempted over Nearby Connections with result " << status; + }, + endpoint_id)); + OnDisconnected(endpoint_id); NS_LOG(INFO) << "Disconnected from " << endpoint_id; } @@ -188,8 +222,15 @@ if (listener) RegisterPayloadStatusListener(payload->id, listener); - nearby_connections_->SendPayload({endpoint_id}, std::move(payload), - base::DoNothing()); + nearby_connections_->SendPayload( + {endpoint_id}, std::move(payload), + base::BindOnce( + [](const std::string& endpoint_id, ConnectionsStatus status) { + NS_LOG(VERBOSE) + << __func__ << ": Sending payload to endpoint " << endpoint_id + << " attempted over Nearby Connections with result " << status; + }, + endpoint_id)); } void NearbyConnectionsManagerImpl::RegisterPayloadStatusListener( @@ -216,7 +257,16 @@ /*bytes_transferred=*/0)); payload_status_listeners_.erase(it); } - nearby_connections_->CancelPayload(payload_id, base::DoNothing()); + nearby_connections_->CancelPayload( + payload_id, base::BindOnce( + [](int64_t payload_id, ConnectionsStatus status) { + NS_LOG(VERBOSE) + << __func__ << ": Cancelling payload to id " + << payload_id + << " attempted over Nearby Connections with result " + << status; + }, + payload_id)); NS_LOG(INFO) << "Cancelling payload: " << payload_id; } @@ -249,6 +299,9 @@ void NearbyConnectionsManagerImpl::OnNearbyProcessStopped() { NS_LOG(VERBOSE) << __func__; + // Not safe to use nearby_connections after we are notified the process has + // been stopped. + nearby_connections_ = nullptr; Reset(); } @@ -310,7 +363,15 @@ payload_listener.InitWithNewPipeAndPassReceiver()); nearby_connections_->AcceptConnection( - endpoint_id, std::move(payload_listener), base::DoNothing()); + endpoint_id, std::move(payload_listener), + base::BindOnce( + [](const std::string& endpoint_id, ConnectionsStatus status) { + NS_LOG(VERBOSE) + << __func__ << ": Accept connection attempted to endpoint " + << endpoint_id << "over Nearby Connections with result " + << status; + }, + endpoint_id)); } void NearbyConnectionsManagerImpl::OnConnectionAccepted( @@ -414,6 +475,15 @@ } void NearbyConnectionsManagerImpl::Reset() { + if (nearby_connections_) { + nearby_connections_->StopAllEndpoints( + base::BindOnce([](ConnectionsStatus status) { + NS_LOG(VERBOSE) << __func__ + << ": Stop all endpoints attempted over Nearby " + "Connections with result " + << status; + })); + } nearby_connections_ = nullptr; discovered_endpoints_.clear(); discovery_listener_ = nullptr;
diff --git a/chrome/browser/nearby_sharing/nearby_connections_manager_impl.h b/chrome/browser/nearby_sharing/nearby_connections_manager_impl.h index 3b331abf..303b923 100644 --- a/chrome/browser/nearby_sharing/nearby_connections_manager_impl.h +++ b/chrome/browser/nearby_sharing/nearby_connections_manager_impl.h
@@ -63,6 +63,9 @@ const std::string& endpoint_id) override; void UpgradeBandwidth(const std::string& endpoint_id) override; + // Converts the status to a logging-friendly string. + static std::string ConnectionsStatusToString(ConnectionsStatus status); + private: using AdvertisingOptions = location::nearby::connections::mojom::AdvertisingOptions;
diff --git a/chrome/browser/nearby_sharing/nearby_connections_manager_impl_unittest.cc b/chrome/browser/nearby_sharing/nearby_connections_manager_impl_unittest.cc index 45bf1aa3..845384d0 100644 --- a/chrome/browser/nearby_sharing/nearby_connections_manager_impl_unittest.cc +++ b/chrome/browser/nearby_sharing/nearby_connections_manager_impl_unittest.cc
@@ -344,6 +344,7 @@ testing::NiceMock<MockDiscoveryListener> discovery_listener; StartDiscovery(listener_remote, discovery_listener); + EXPECT_CALL(nearby_connections_, StopAllEndpoints).Times(0); nearby_connections_manager_.OnNearbyProcessStopped(); // Invoking OnEndpointFound will do nothing. @@ -868,3 +869,43 @@ EXPECT_CALL(nearby_connections_, StopAdvertising); nearby_connections_manager_.StopAdvertising(); } + +TEST_F(NearbyConnectionsManagerImplTest, ShutdownAdvertising) { + mojo::Remote<ConnectionLifecycleListener> listener_remote; + testing::NiceMock<MockIncomingConnectionListener> + incoming_connection_listener; + StartAdvertising(listener_remote, incoming_connection_listener); + + EXPECT_CALL(nearby_connections_, StopAllEndpoints); + nearby_connections_manager_.Shutdown(); +} + +TEST_F(NearbyConnectionsManagerImplTest, ShutdownDiscoveryConnectionFails) { + mojo::Remote<EndpointDiscoveryListener> discovery_listener_remote; + testing::NiceMock<MockDiscoveryListener> discovery_listener; + StartDiscovery(discovery_listener_remote, discovery_listener); + + EXPECT_CALL(nearby_connections_, StopAllEndpoints); + nearby_connections_manager_.Shutdown(); + + // RequestConnection will fail. + const std::vector<uint8_t> local_endpoint_info(std::begin(kEndpointInfo), + std::end(kEndpointInfo)); + base::RunLoop run_loop; + NearbyConnection* nearby_connection; + nearby_connections_manager_.Connect( + local_endpoint_info, kRemoteEndpointId, + /*bluetooth_mac_address=*/base::nullopt, DataUsage::kOffline, + base::BindLambdaForTesting([&](NearbyConnection* connection) { + nearby_connection = connection; + run_loop.Quit(); + })); + + EXPECT_FALSE(nearby_connection); +} + +TEST_F(NearbyConnectionsManagerImplTest, + ShutdownBeforeStartDiscoveryOrAdvertising) { + EXPECT_CALL(nearby_connections_, StopAllEndpoints).Times(0); + nearby_connections_manager_.Shutdown(); +}
diff --git a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc index 273bc531..491c11d4 100644 --- a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc +++ b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc
@@ -8,6 +8,7 @@ #include "base/bind.h" #include "base/logging.h" +#include "base/strings/stringprintf.h" #include "base/task/post_task.h" #include "base/task_runner_util.h" #include "base/threading/sequenced_task_runner_handle.h" @@ -20,6 +21,7 @@ #include "chrome/browser/nearby_sharing/local_device_data/nearby_share_local_device_data_manager_impl.h" #include "chrome/browser/nearby_sharing/logging/logging.h" #include "chrome/browser/nearby_sharing/nearby_connections_manager.h" +#include "chrome/browser/nearby_sharing/paired_key_verification_runner.h" #include "chrome/browser/nearby_sharing/transfer_metadata_builder.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/signin/identity_manager_factory.h" @@ -42,6 +44,10 @@ constexpr base::TimeDelta kInvalidateDelay = base::TimeDelta::FromMilliseconds(500); +// Used to hash a token into a 4 digit string. +constexpr int kHashModulo = 9973; +constexpr int kHashBaseMultiplier = 31; + std::string ReceiveSurfaceStateToString( NearbySharingService::ReceiveSurfaceState state) { switch (state) { @@ -54,19 +60,6 @@ } } -std::string DataUsageToString(DataUsage usage) { - switch (usage) { - case DataUsage::kOffline: - return "OFFLINE"; - case DataUsage::kOnline: - return "ONLINE"; - case DataUsage::kWifiOnly: - return "WIFI_ONLY"; - case DataUsage::kUnknown: - return "UNKNOWN"; - } -} - std::string PowerLevelToString(PowerLevel level) { switch (level) { case PowerLevel::kLowPower: @@ -80,55 +73,6 @@ } } -std::string VisibilityToString(Visibility visibility) { - switch (visibility) { - case Visibility::kNoOne: - return "NO_ONE"; - case Visibility::kAllContacts: - return "ALL_CONTACTS"; - case Visibility::kSelectedContacts: - return "SELECTED_CONTACTS"; - case Visibility::kUnknown: - return "UNKNOWN"; - } -} - -std::string ConnectionsStatusToString( - NearbyConnectionsManager::ConnectionsStatus status) { - switch (status) { - case NearbyConnectionsManager::ConnectionsStatus::kSuccess: - return "SUCCESS"; - case NearbyConnectionsManager::ConnectionsStatus::kError: - return "ERROR"; - case NearbyConnectionsManager::ConnectionsStatus::kOutOfOrderApiCall: - return "OUT_OF_ORDER_API_CALL"; - case NearbyConnectionsManager::ConnectionsStatus:: - kAlreadyHaveActiveStrategy: - return "ALREADY_HAVE_ACTIVE_STRATEGY"; - case NearbyConnectionsManager::ConnectionsStatus::kAlreadyAdvertising: - return "ALREADY_ADVERTISING"; - case NearbyConnectionsManager::ConnectionsStatus::kAlreadyDiscovering: - return "ALREADY_DISCOVERING"; - case NearbyConnectionsManager::ConnectionsStatus::kEndpointIOError: - return "ENDPOINT_IO_ERROR"; - case NearbyConnectionsManager::ConnectionsStatus::kEndpointUnknown: - return "ENDPOINT_UNKNOWN"; - case NearbyConnectionsManager::ConnectionsStatus::kConnectionRejected: - return "CONNECTION_REJECTED"; - case NearbyConnectionsManager::ConnectionsStatus:: - kAlreadyConnectedToEndpoint: - return "ALREADY_CONNECTED_TO_ENDPOINT"; - case NearbyConnectionsManager::ConnectionsStatus::kNotConnectedToEndpoint: - return "NOT_CONNECTED_TO_ENDPOINT"; - case NearbyConnectionsManager::ConnectionsStatus::kBluetoothError: - return "BLUETOOTH_ERROR"; - case NearbyConnectionsManager::ConnectionsStatus::kWifiLanError: - return "WIFI_LAN_ERROR"; - case NearbyConnectionsManager::ConnectionsStatus::kPayloadUnknown: - return "PAYLOAD_UNKNOWN"; - } -} - base::Optional<std::string> GetDeviceName( const sharing::mojom::AdvertisementPtr& advertisement, const base::Optional<NearbyShareDecryptedPublicCertificate>& certificate) { @@ -155,6 +99,17 @@ return std::string(certificate->id().begin(), certificate->id().end()); } +std::string ToFourDigitString(const std::vector<uint8_t>& bytes) { + int hash = 0; + int multiplier = 1; + for (auto byte : bytes) { + hash = (hash + byte * multiplier) % kHashModulo; + multiplier = (multiplier * kHashBaseMultiplier) % kHashModulo; + } + + return base::StringPrintf("%04d", std::abs(hash)); +} + } // namespace NearbySharingServiceImpl::NearbySharingServiceImpl( @@ -518,12 +473,23 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(connection); + ShareTarget placeholder_share_target; + auto& share_target_info = + GetIncomingShareTargetInfo(placeholder_share_target); + share_target_info.set_connection(connection); + share_target_info.set_endpoint_id(endpoint_id); + + connection->SetDisconnectionListener( + base::BindOnce(&NearbySharingServiceImpl::RefreshUIOnDisconnection, + weak_ptr_factory_.GetWeakPtr(), placeholder_share_target)); + process_manager_->GetOrStartNearbySharingDecoder(profile_) ->DecodeAdvertisement( endpoint_info, base::BindOnce( &NearbySharingServiceImpl::OnIncomingAdvertisementDecoded, - weak_ptr_factory_.GetWeakPtr(), endpoint_id, connection)); + weak_ptr_factory_.GetWeakPtr(), endpoint_id, + std::move(placeholder_share_target))); } void NearbySharingServiceImpl::OnEndpointDiscovered( @@ -700,7 +666,7 @@ void NearbySharingServiceImpl::OnVisibilityChanged(Visibility new_visibility) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); NS_LOG(VERBOSE) << __func__ << ": Nearby sharing visibility changed to " - << VisibilityToString(new_visibility); + << new_visibility; if (advertising_power_level_ != PowerLevel::kUnknown) StopAdvertising(); @@ -710,7 +676,7 @@ void NearbySharingServiceImpl::OnDataUsageChanged(DataUsage data_usage) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); NS_LOG(VERBOSE) << __func__ << ": Nearby sharing data usage changed to " - << DataUsageToString(data_usage); + << data_usage; if (advertising_power_level_ != PowerLevel::kUnknown) StopAdvertising(); @@ -955,15 +921,14 @@ << ": Failed to advertise because we're already advertising with " "power level " << PowerLevelToString(advertising_power_level_) - << " and data usage preference " << DataUsageToString(data_usage); + << " and data usage preference " << data_usage; return; } StopAdvertising(); NS_LOG(VERBOSE) << __func__ << ": Restart advertising with power level " << PowerLevelToString(power_level) - << " and data usage preference " - << DataUsageToString(data_usage); + << " and data usage preference " << data_usage; } base::Optional<std::string> device_name; @@ -988,16 +953,15 @@ NS_LOG(VERBOSE) << __func__ << ": Advertising attempted over Nearby Connections with result " - << ConnectionsStatusToString(status); + << status; })); advertising_power_level_ = power_level; NS_LOG(VERBOSE) << __func__ << ": Advertising has started over Nearby Connections: " << " power level " << PowerLevelToString(power_level) - << " visibility " - << VisibilityToString(settings_.GetVisibility()) - << " data usage " << DataUsageToString(data_usage); + << " visibility " << settings_.GetVisibility() + << " data usage " << data_usage; return; } @@ -1113,7 +1077,7 @@ NS_LOG(VERBOSE) << __func__ << ": Scanning start attempted over Nearby Connections " "with result " - << ConnectionsStatusToString(status); + << status; })); InvalidateSendSurfaceState(); @@ -1323,8 +1287,16 @@ void NearbySharingServiceImpl::OnIncomingAdvertisementDecoded( const std::string& endpoint_id, - NearbyConnection* connection, + ShareTarget placeholder_share_target, sharing::mojom::AdvertisementPtr advertisement) { + NearbyConnection* connection = + GetIncomingConnection(placeholder_share_target); + if (!connection) { + NS_LOG(VERBOSE) << __func__ << ": Invalid connection for endoint id - " + << endpoint_id; + return; + } + if (!advertisement) { NS_LOG(VERBOSE) << __func__ << "Failed to parse incoming connection from endpoint - " @@ -1338,15 +1310,28 @@ GetCertificateManager()->GetDecryptedPublicCertificate( std::move(encrypted_metadata_key), base::BindOnce(&NearbySharingServiceImpl::OnIncomingDecryptedCertificate, - weak_ptr_factory_.GetWeakPtr(), endpoint_id, connection, - std::move(advertisement))); + weak_ptr_factory_.GetWeakPtr(), endpoint_id, + std::move(advertisement), + std::move(placeholder_share_target))); } void NearbySharingServiceImpl::OnIncomingDecryptedCertificate( const std::string& endpoint_id, - NearbyConnection* connection, sharing::mojom::AdvertisementPtr advertisement, + ShareTarget placeholder_share_target, base::Optional<NearbyShareDecryptedPublicCertificate> certificate) { + NearbyConnection* connection = + GetIncomingConnection(placeholder_share_target); + if (!connection) { + NS_LOG(VERBOSE) << __func__ << ": Invalid connection for endpoint id - " + << endpoint_id; + return; + } + + // Remove placeholder share target since we are creating the actual share + // target below. + incoming_share_target_info_map_.erase(placeholder_share_target.id); + base::Optional<ShareTarget> share_target = CreateShareTarget( endpoint_id, advertisement, std::move(certificate), /*is_incoming=*/true); @@ -1369,10 +1354,98 @@ connection->SetDisconnectionListener( base::BindOnce(&NearbySharingServiceImpl::UnregisterShareTarget, weak_ptr_factory_.GetWeakPtr(), *share_target)); + base::Optional<std::vector<uint8_t>> token = + nearby_connections_manager_->GetRawAuthenticationToken(endpoint_id); + if (!token) { + NS_LOG(VERBOSE) << __func__ + << ": Failed to read authentication token from endpoint - " + << endpoint_id; + OnIncomingConnectionKeyVerificationDone( + std::move(*share_target), std::move(token), + PairedKeyVerificationRunner::PairedKeyVerificationResult::kFail); + return; + } - // TODO(himanshujaju) - Implement RunPairedKeyVerification. + share_target_info.set_frames_reader(std::make_unique<IncomingFramesReader>( + process_manager_, profile_, connection)); - ReceiveIntroduction(std::move(*share_target), /*token=*/base::nullopt); + bool restrict_to_contacts = + advertising_power_level_ != PowerLevel::kHighPower; + share_target_info.set_key_verification_runner( + std::make_unique<PairedKeyVerificationRunner>( + *share_target, endpoint_id, *token, connection, + share_target_info.certificate(), GetCertificateManager(), + settings_.GetVisibility(), restrict_to_contacts, + share_target_info.frames_reader(), kReadFramesTimeout)); + share_target_info.key_verification_runner()->Run(base::BindOnce( + &NearbySharingServiceImpl::OnIncomingConnectionKeyVerificationDone, + weak_ptr_factory_.GetWeakPtr(), std::move(*share_target), + std::move(token))); +} + +void NearbySharingServiceImpl::OnIncomingConnectionKeyVerificationDone( + ShareTarget share_target, + base::Optional<std::vector<uint8_t>> token, + PairedKeyVerificationRunner::PairedKeyVerificationResult result) { + NearbyConnection* connection = GetIncomingConnection(share_target); + const base::Optional<std::string>& endpoint_id = + GetIncomingShareTargetInfo(share_target).endpoint_id(); + if (!connection || !endpoint_id) { + NS_LOG(VERBOSE) << __func__ << ": Invalid connection or endpoint id"; + return; + } + + base::Optional<std::string> token_string; + if (token) + token_string = ToFourDigitString(*token); + + switch (result) { + case PairedKeyVerificationRunner::PairedKeyVerificationResult::kFail: + NS_LOG(VERBOSE) << __func__ + << ": Paired key handshake failed, disconnecting."; + connection->Close(); + return; + + case PairedKeyVerificationRunner::PairedKeyVerificationResult::kSuccess: + NS_LOG(VERBOSE) << __func__ + << ": Paired key handshake succeeded for target - " + << share_target.device_name; + nearby_connections_manager_->UpgradeBandwidth(*endpoint_id); + ReceiveIntroduction(share_target, /*token=*/base::nullopt); + break; + + case PairedKeyVerificationRunner::PairedKeyVerificationResult::kUnable: + NS_LOG(VERBOSE) << __func__ + << ": Unable to verify paired key encryption when " + "receiving connection from target - " + << share_target.device_name; + if (advertising_power_level_ == PowerLevel::kHighPower) + nearby_connections_manager_->UpgradeBandwidth(*endpoint_id); + + if (token_string) + GetIncomingShareTargetInfo(share_target).set_token(*token_string); + + ReceiveIntroduction(share_target, std::move(token_string)); + break; + + case PairedKeyVerificationRunner::PairedKeyVerificationResult::kUnknown: + NS_LOG(VERBOSE) + << __func__ + << ": Unknown PairedKeyVerificationResult, disconnecting."; + connection->Close(); + break; + } +} + +void NearbySharingServiceImpl::RefreshUIOnDisconnection( + ShareTarget share_target) { + OnIncomingTransferUpdate( + share_target, + TransferMetadataBuilder() + .set_status(TransferMetadata::Status::kAwaitingRemoteAcceptanceFailed) + .build()); + + UnregisterShareTarget(share_target); } void NearbySharingServiceImpl::ReceiveIntroduction( @@ -1390,8 +1463,6 @@ } auto& share_target_info = GetIncomingShareTargetInfo(share_target); - share_target_info.set_frames_reader(std::make_unique<IncomingFramesReader>( - process_manager_, profile_, connection)); share_target_info.frames_reader()->ReadFrame( sharing::mojom::V1Frame::Tag::INTRODUCTION, base::BindOnce(&NearbySharingServiceImpl::OnReceivedIntroduction, @@ -1490,6 +1561,7 @@ share_target, TransferMetadataBuilder() .set_status(TransferMetadata::Status::kAwaitingLocalConfirmation) + .set_token(std::move(token)) .build()); if (!incoming_share_target_info_map_.count(share_target.id)) { @@ -1670,6 +1742,9 @@ void NearbySharingServiceImpl::UnregisterShareTarget( const ShareTarget& share_target) { + NS_LOG(VERBOSE) << __func__ << ": Unregistering share target - " + << share_target.device_name; + if (share_target.is_incoming) { incoming_share_target_info_map_.erase(share_target.id); // Clear legacy incoming payloads to release resource
diff --git a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.h b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.h index 1345467..6503dd3 100644 --- a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.h +++ b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.h
@@ -174,16 +174,21 @@ StatusCodes StopScanning(); void OnIncomingAdvertisementDecoded( const std::string& endpoint_id, - NearbyConnection* connection, + ShareTarget placeholder_share_target, sharing::mojom::AdvertisementPtr advertisement); void OnIncomingTransferUpdate(const ShareTarget& share_target, TransferMetadata metadata); void CloseConnection(const ShareTarget& share_target); void OnIncomingDecryptedCertificate( const std::string& endpoint_id, - NearbyConnection* connection, sharing::mojom::AdvertisementPtr advertisement, + ShareTarget placeholder_share_target, base::Optional<NearbyShareDecryptedPublicCertificate> certificate); + void OnIncomingConnectionKeyVerificationDone( + ShareTarget share_target, + base::Optional<std::vector<uint8_t>> token, + PairedKeyVerificationRunner::PairedKeyVerificationResult result); + void RefreshUIOnDisconnection(ShareTarget share_target); void ReceiveIntroduction(ShareTarget share_target, base::Optional<std::string> token); void OnReceivedIntroduction(ShareTarget share_target,
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 9934a99..3e82347b 100644 --- a/chrome/browser/nearby_sharing/nearby_sharing_service_impl_unittest.cc +++ b/chrome/browser/nearby_sharing/nearby_sharing_service_impl_unittest.cc
@@ -176,6 +176,19 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 100, 101, 118, 105, 99, 101, 78, 97, 109, 101}; +const std::vector<uint8_t> kToken = {0, 1, 2}; +const char kFourDigitToken[] = "1953"; + +const std::vector<uint8_t> kPrivateCertificateHashAuthToken = { + 0x8b, 0xcb, 0xa2, 0xf8, 0xe4, 0x06}; +const std::vector<uint8_t> kIncomingConnectionSignedData = { + 0x30, 0x45, 0x02, 0x20, 0x4f, 0x83, 0x72, 0xbd, 0x02, 0x70, 0xd9, 0xda, + 0x62, 0x83, 0x5d, 0xb2, 0xdc, 0x6e, 0x3f, 0xa6, 0xa8, 0xa1, 0x4f, 0x5f, + 0xd3, 0xe3, 0xd9, 0x1a, 0x5d, 0x2d, 0x61, 0xd2, 0x6c, 0xdd, 0x8d, 0xa5, + 0x02, 0x21, 0x00, 0xd4, 0xe1, 0x1d, 0x14, 0xcb, 0x58, 0xf7, 0x02, 0xd5, + 0xab, 0x48, 0xe2, 0x2f, 0xcb, 0xc0, 0x53, 0x41, 0x06, 0x50, 0x65, 0x95, + 0x19, 0xa9, 0x22, 0x92, 0x00, 0x42, 0x01, 0x26, 0x25, 0xcb, 0x8c}; + sharing::mojom::FramePtr GetValidIntroductionFrame() { std::vector<sharing::mojom::TextMetadataPtr> mojo_text_metadatas; // TODO(himanshujaju) - Parameterise number of text and file metadatas. @@ -207,7 +220,8 @@ class NearbySharingServiceImplTest : public testing::Test { public: - NearbySharingServiceImplTest() { + NearbySharingServiceImplTest() + : task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME) { scoped_feature_list_.InitAndEnableFeature(features::kNearbySharing); RegisterNearbySharingPrefs(prefs_.registry()); } @@ -269,6 +283,11 @@ return service; } + void SetVisibility(nearby_share::mojom::Visibility visibility) { + NearbyShareSettings settings(&prefs_); + settings.SetVisibility(visibility); + } + void SetFakeFastInitiationManagerFactory(bool should_succeed_on_start) { fast_initiation_manager_factory_ = std::make_unique<FakeFastInitiationManagerFactory>( @@ -295,7 +314,8 @@ return mock_nearby_process_manager_; } - void SetUpReceiveSurface(NiceMock<MockTransferUpdateCallback>& callback) { + void SetUpForegroundReceiveSurface( + NiceMock<MockTransferUpdateCallback>& callback) { NearbySharingService::StatusCodes result = service_->RegisterReceiveSurface( &callback, NearbySharingService::ReceiveSurfaceState::kForeground); EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk); @@ -326,6 +346,52 @@ } } + void SetUpKeyVerification( + sharing::mojom::PairedKeyResultFrame::Status status) { + SetVisibility(nearby_share::mojom::Visibility::kAllContacts); + + std::string encryption_frame = "test_encryption_frame"; + std::vector<uint8_t> encryption_bytes(encryption_frame.begin(), + encryption_frame.end()); + EXPECT_CALL(mock_decoder_, + DecodeFrame(testing::Eq(encryption_bytes), testing::_)) + .WillOnce(testing::Invoke( + [](const std::vector<uint8_t>& data, + MockNearbySharingDecoder::DecodeFrameCallback callback) { + sharing::mojom::V1FramePtr mojo_v1frame = + sharing::mojom::V1Frame::New(); + mojo_v1frame->set_paired_key_encryption( + sharing::mojom::PairedKeyEncryptionFrame::New( + kIncomingConnectionSignedData, + kPrivateCertificateHashAuthToken)); + sharing::mojom::FramePtr mojo_frame = + sharing::mojom::Frame::New(); + mojo_frame->set_v1(std::move(mojo_v1frame)); + std::move(callback).Run(std::move(mojo_frame)); + })); + connection_.AppendReadableData(encryption_bytes); + + std::string encryption_result = "test_encryption_result"; + std::vector<uint8_t> result_bytes(encryption_result.begin(), + encryption_result.end()); + EXPECT_CALL(mock_decoder_, + DecodeFrame(testing::Eq(result_bytes), testing::_)) + .WillOnce(testing::Invoke( + [=](const std::vector<uint8_t>& data, + MockNearbySharingDecoder::DecodeFrameCallback callback) { + sharing::mojom::V1FramePtr mojo_v1frame = + sharing::mojom::V1Frame::New(); + mojo_v1frame->set_paired_key_result( + sharing::mojom::PairedKeyResultFrame::New(status)); + + sharing::mojom::FramePtr mojo_frame = + sharing::mojom::Frame::New(); + mojo_frame->set_v1(std::move(mojo_v1frame)); + std::move(callback).Run(std::move(mojo_frame)); + })); + connection_.AppendReadableData(result_bytes); + } + void SetUpAdvertisementDecoder(const std::vector<uint8_t>& endpoint_info, bool return_empty_advertisement) { EXPECT_CALL(mock_decoder_, @@ -364,6 +430,8 @@ ShareTarget SetUpIncomingConnection( NiceMock<MockTransferUpdateCallback>& callback) { + fake_nearby_connections_manager_->SetRawAuthenticationToken(kEndpointId, + kToken); SetUpAdvertisementDecoder(kValidV1EndpointInfo, /*return_empty_advertisement=*/false); SetUpIntroductionFrameDecoder(/*return_empty_introduction_frame=*/false); @@ -381,16 +449,48 @@ share_target = incoming_share_target; run_loop.Quit(); })); - SetUpReceiveSurface(callback); + + SetUpKeyVerification(sharing::mojom::PairedKeyResultFrame_Status::kSuccess); + SetUpForegroundReceiveSurface(callback); service_->OnIncomingConnection(kEndpointId, kValidV1EndpointInfo, &connection_); ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1, /*success=*/true); run_loop.Run(); + EXPECT_TRUE( + fake_nearby_connections_manager_->DidUpgradeBandwidth(kEndpointId)); + return share_target; } + sharing::nearby::Frame GetWrittenFrame() { + std::vector<uint8_t> data = connection_.GetWrittenData(); + sharing::nearby::Frame frame; + frame.ParseFromArray(data.data(), data.size()); + return frame; + } + + void ExpectPairedKeyEncryptionFrame() { + sharing::nearby::Frame frame = GetWrittenFrame(); + ASSERT_TRUE(frame.has_v1()); + ASSERT_TRUE(frame.v1().has_paired_key_encryption()); + } + + void ExpectPairedKeyResultFrame() { + sharing::nearby::Frame frame = GetWrittenFrame(); + ASSERT_TRUE(frame.has_v1()); + ASSERT_TRUE(frame.v1().has_paired_key_result()); + } + + void ExpectConnectionResponseFrame( + sharing::nearby::ConnectionResponseFrame::Status status) { + sharing::nearby::Frame frame = GetWrittenFrame(); + ASSERT_TRUE(frame.has_v1()); + ASSERT_TRUE(frame.v1().has_connection_response()); + EXPECT_EQ(status, frame.v1().connection_response().status()); + } + protected: FakeNearbyShareLocalDeviceDataManager* local_device_data_manager() { EXPECT_EQ(1u, local_device_data_manager_factory_.instances().size()); @@ -1328,6 +1428,8 @@ TEST_F(NearbySharingServiceImplTest, IncomingConnection_ClosedReadingIntroduction) { + fake_nearby_connections_manager_->SetRawAuthenticationToken(kEndpointId, + kToken); SetUpAdvertisementDecoder(kValidV1EndpointInfo, /*return_empty_advertisement=*/false); @@ -1335,7 +1437,9 @@ SetConnectionType(net::NetworkChangeNotifier::CONNECTION_WIFI); NiceMock<MockTransferUpdateCallback> callback; EXPECT_CALL(callback, OnTransferUpdate(testing::_, testing::_)).Times(0); - SetUpReceiveSurface(callback); + + SetUpKeyVerification(sharing::mojom::PairedKeyResultFrame_Status::kSuccess); + SetUpForegroundReceiveSurface(callback); service_->OnIncomingConnection(kEndpointId, kValidV1EndpointInfo, &connection_); ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1, @@ -1350,6 +1454,8 @@ TEST_F(NearbySharingServiceImplTest, IncomingConnection_EmptyIntroductionFrame) { + fake_nearby_connections_manager_->SetRawAuthenticationToken(kEndpointId, + kToken); SetUpAdvertisementDecoder(kValidV1EndpointInfo, /*return_empty_advertisement=*/false); SetUpIntroductionFrameDecoder(/*return_empty_introduction_frame=*/true); @@ -1377,7 +1483,9 @@ EXPECT_TRUE(metadata.is_final_status()); run_loop.Quit(); })); - SetUpReceiveSurface(callback); + + SetUpKeyVerification(sharing::mojom::PairedKeyResultFrame_Status::kSuccess); + SetUpForegroundReceiveSurface(callback); service_->OnIncomingConnection(kEndpointId, kValidV1EndpointInfo, &connection_); ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1, @@ -1385,15 +1493,10 @@ run_loop.Run(); // Check data written to connection_. - std::vector<uint8_t> data = connection_.GetWrittenData(); - sharing::nearby::Frame frame; - frame.ParseFromArray(data.data(), data.size()); - - EXPECT_TRUE(frame.has_v1()); - EXPECT_TRUE(frame.v1().has_connection_response()); - EXPECT_EQ( - sharing::nearby::ConnectionResponseFrame::UNSUPPORTED_ATTACHMENT_TYPE, - frame.v1().connection_response().status()); + ExpectPairedKeyEncryptionFrame(); + ExpectPairedKeyResultFrame(); + ExpectConnectionResponseFrame( + sharing::nearby::ConnectionResponseFrame::UNSUPPORTED_ATTACHMENT_TYPE); // To avoid UAF in OnIncomingTransferUpdate(). service_->UnregisterReceiveSurface(&callback); @@ -1401,6 +1504,8 @@ TEST_F(NearbySharingServiceImplTest, IncomingConnection_ValidIntroductionFrame_InvalidCertificate) { + fake_nearby_connections_manager_->SetRawAuthenticationToken(kEndpointId, + kToken); SetUpAdvertisementDecoder(kValidV1EndpointInfo, /*return_empty_advertisement=*/false); SetUpIntroductionFrameDecoder(/*return_empty_introduction_frame=*/false); @@ -1429,13 +1534,17 @@ EXPECT_FALSE(metadata.is_final_status()); run_loop.Quit(); })); - SetUpReceiveSurface(callback); + + SetUpKeyVerification(sharing::mojom::PairedKeyResultFrame_Status::kSuccess); + SetUpForegroundReceiveSurface(callback); service_->OnIncomingConnection(kEndpointId, kValidV1EndpointInfo, &connection_); ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1, /*success=*/false); run_loop.Run(); + EXPECT_FALSE(connection_.IsClosed()); + // To avoid UAF in OnIncomingTransferUpdate(). service_->UnregisterReceiveSurface(&callback); } @@ -1463,6 +1572,8 @@ TEST_F(NearbySharingServiceImplTest, IncomingConnection_ValidIntroductionFrame_ValidCertificate) { + fake_nearby_connections_manager_->SetRawAuthenticationToken(kEndpointId, + kToken); SetUpAdvertisementDecoder(kValidV1EndpointInfo, /*return_empty_advertisement=*/false); SetUpIntroductionFrameDecoder(/*return_empty_introduction_frame=*/false); @@ -1487,18 +1598,24 @@ EXPECT_NE(kEndpointId, share_target.device_id); EXPECT_EQ(kTestMetadataFullName, share_target.full_name); + EXPECT_FALSE(metadata.token().has_value()); + EXPECT_EQ(TransferMetadata::Status::kAwaitingLocalConfirmation, metadata.status()); EXPECT_FALSE(metadata.is_final_status()); run_loop.Quit(); })); - SetUpReceiveSurface(callback); + + SetUpKeyVerification(sharing::mojom::PairedKeyResultFrame_Status::kSuccess); + SetUpForegroundReceiveSurface(callback); service_->OnIncomingConnection(kEndpointId, kValidV1EndpointInfo, &connection_); ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1, /*success=*/true); run_loop.Run(); + EXPECT_FALSE(connection_.IsClosed()); + // To avoid UAF in OnIncomingTransferUpdate(). service_->UnregisterReceiveSurface(&callback); } @@ -1543,15 +1660,14 @@ EXPECT_TRUE( fake_nearby_connections_manager_->DidUpgradeBandwidth(kEndpointId)); - // Check data written to connection_. - std::vector<uint8_t> data = connection_.GetWrittenData(); - sharing::nearby::Frame frame; - frame.ParseFromArray(data.data(), data.size()); - EXPECT_TRUE(frame.has_v1()); - EXPECT_TRUE(frame.v1().has_connection_response()); - EXPECT_EQ(sharing::nearby::ConnectionResponseFrame::ACCEPT, - frame.v1().connection_response().status()); + // Check data written to connection_. + ExpectPairedKeyEncryptionFrame(); + ExpectPairedKeyResultFrame(); + ExpectConnectionResponseFrame( + sharing::nearby::ConnectionResponseFrame::ACCEPT); + + EXPECT_FALSE(connection_.IsClosed()); // To avoid UAF in OnIncomingTransferUpdate(). service_->UnregisterReceiveSurface(&callback); @@ -1595,14 +1711,185 @@ run_loop_reject.Run(); // Check data written to connection_. - std::vector<uint8_t> data = connection_.GetWrittenData(); - sharing::nearby::Frame frame; - frame.ParseFromArray(data.data(), data.size()); + ExpectPairedKeyEncryptionFrame(); + ExpectPairedKeyResultFrame(); + ExpectConnectionResponseFrame( + sharing::nearby::ConnectionResponseFrame::REJECT); - EXPECT_TRUE(frame.has_v1()); - EXPECT_TRUE(frame.v1().has_connection_response()); - EXPECT_EQ(sharing::nearby::ConnectionResponseFrame::REJECT, - frame.v1().connection_response().status()); + // TODO(himanshujaju) - Extract out to a common constant b/w impl and test. + task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(2)); + EXPECT_TRUE(connection_.IsClosed()); + + // To avoid UAF in OnIncomingTransferUpdate(). + service_->UnregisterReceiveSurface(&callback); +} + +TEST_F(NearbySharingServiceImplTest, + IncomingConnection_KeyVerificationRunnerStatusUnable) { + fake_nearby_connections_manager_->SetRawAuthenticationToken(kEndpointId, + kToken); + SetUpAdvertisementDecoder(kValidV1EndpointInfo, + /*return_empty_advertisement=*/false); + SetUpIntroductionFrameDecoder(/*return_empty_introduction_frame=*/false); + + ui::ScopedSetIdleState unlocked(ui::IDLE_STATE_IDLE); + SetConnectionType(net::NetworkChangeNotifier::CONNECTION_WIFI); + NiceMock<MockTransferUpdateCallback> callback; + base::RunLoop run_loop; + EXPECT_CALL(callback, OnTransferUpdate(testing::_, testing::_)) + .WillOnce(testing::Invoke([&run_loop](const ShareTarget& share_target, + TransferMetadata metadata) { + EXPECT_TRUE(share_target.is_incoming); + EXPECT_TRUE(share_target.is_known); + EXPECT_TRUE(share_target.has_attachments()); + EXPECT_EQ(3u, share_target.text_attachments.size()); + EXPECT_EQ(0u, share_target.file_attachments.size()); + EXPECT_EQ(kDeviceName, share_target.device_name); + EXPECT_EQ(GURL(kTestMetadataIconUrl), share_target.image_url); + EXPECT_EQ(nearby_share::mojom::ShareTargetType::kUnknown, + share_target.type); + EXPECT_TRUE(share_target.device_id); + EXPECT_NE(kEndpointId, share_target.device_id); + EXPECT_EQ(kTestMetadataFullName, share_target.full_name); + + EXPECT_EQ(kFourDigitToken, metadata.token()); + EXPECT_EQ(TransferMetadata::Status::kAwaitingLocalConfirmation, + metadata.status()); + EXPECT_FALSE(metadata.is_final_status()); + run_loop.Quit(); + })); + + SetUpKeyVerification(sharing::mojom::PairedKeyResultFrame_Status::kUnable); + SetUpForegroundReceiveSurface(callback); + + service_->OnIncomingConnection(kEndpointId, kValidV1EndpointInfo, + &connection_); + ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1, + /*success=*/true); + run_loop.Run(); + + EXPECT_TRUE( + fake_nearby_connections_manager_->DidUpgradeBandwidth(kEndpointId)); + + EXPECT_FALSE(connection_.IsClosed()); + + // To avoid UAF in OnIncomingTransferUpdate(). + service_->UnregisterReceiveSurface(&callback); +} + +TEST_F(NearbySharingServiceImplTest, + IncomingConnection_KeyVerificationRunnerStatusUnable_LowPower) { + fake_nearby_connections_manager_->SetRawAuthenticationToken(kEndpointId, + kToken); + SetUpAdvertisementDecoder(kValidV1EndpointInfo, + /*return_empty_advertisement=*/false); + SetUpIntroductionFrameDecoder(/*return_empty_introduction_frame=*/false); + + ui::ScopedSetIdleState unlocked(ui::IDLE_STATE_IDLE); + SetConnectionType(net::NetworkChangeNotifier::CONNECTION_WIFI); + NiceMock<MockTransferUpdateCallback> callback; + base::RunLoop run_loop; + EXPECT_CALL(callback, OnTransferUpdate(testing::_, testing::_)) + .WillOnce(testing::Invoke([&run_loop](const ShareTarget& share_target, + TransferMetadata metadata) { + EXPECT_TRUE(share_target.is_incoming); + EXPECT_TRUE(share_target.is_known); + EXPECT_TRUE(share_target.has_attachments()); + EXPECT_EQ(3u, share_target.text_attachments.size()); + EXPECT_EQ(0u, share_target.file_attachments.size()); + EXPECT_EQ(kDeviceName, share_target.device_name); + EXPECT_EQ(GURL(kTestMetadataIconUrl), share_target.image_url); + EXPECT_EQ(nearby_share::mojom::ShareTargetType::kUnknown, + share_target.type); + EXPECT_TRUE(share_target.device_id); + EXPECT_NE(kEndpointId, share_target.device_id); + EXPECT_EQ(kTestMetadataFullName, share_target.full_name); + + EXPECT_EQ(kFourDigitToken, metadata.token()); + EXPECT_EQ(TransferMetadata::Status::kAwaitingLocalConfirmation, + metadata.status()); + EXPECT_FALSE(metadata.is_final_status()); + run_loop.Quit(); + })); + + SetUpKeyVerification(sharing::mojom::PairedKeyResultFrame_Status::kUnable); + + NearbySharingService::StatusCodes result = service_->RegisterReceiveSurface( + &callback, NearbySharingService::ReceiveSurfaceState::kBackground); + EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk); + EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising()); + + service_->OnIncomingConnection(kEndpointId, kValidV1EndpointInfo, + &connection_); + ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1, + /*success=*/true); + run_loop.Run(); + + EXPECT_FALSE( + fake_nearby_connections_manager_->DidUpgradeBandwidth(kEndpointId)); + + EXPECT_FALSE(connection_.IsClosed()); + + // To avoid UAF in OnIncomingTransferUpdate(). + service_->UnregisterReceiveSurface(&callback); +} + +TEST_F(NearbySharingServiceImplTest, + IncomingConnection_KeyVerificationRunnerStatusFail) { + fake_nearby_connections_manager_->SetRawAuthenticationToken(kEndpointId, + kToken); + SetUpAdvertisementDecoder(kValidV1EndpointInfo, + /*return_empty_advertisement=*/false); + + ui::ScopedSetIdleState unlocked(ui::IDLE_STATE_IDLE); + SetConnectionType(net::NetworkChangeNotifier::CONNECTION_WIFI); + NiceMock<MockTransferUpdateCallback> callback; + + SetUpKeyVerification(sharing::mojom::PairedKeyResultFrame_Status::kFail); + SetUpForegroundReceiveSurface(callback); + + // Ensures that introduction is never received for failed key verification. + std::string intro = "introduction_frame"; + std::vector<uint8_t> bytes(intro.begin(), intro.end()); + EXPECT_CALL(mock_decoder_, DecodeFrame(testing::Eq(bytes), testing::_)) + .Times(0); + connection_.AppendReadableData(bytes); + + service_->OnIncomingConnection(kEndpointId, kValidV1EndpointInfo, + &connection_); + ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1, + /*success=*/true); + + EXPECT_TRUE(connection_.IsClosed()); + + // To avoid UAF in OnIncomingTransferUpdate(). + service_->UnregisterReceiveSurface(&callback); +} + +TEST_F(NearbySharingServiceImplTest, + IncomingConnection_EmptyAuthToken_KeyVerificationRunnerStatusFail) { + SetUpAdvertisementDecoder(kValidV1EndpointInfo, + /*return_empty_advertisement=*/false); + + ui::ScopedSetIdleState unlocked(ui::IDLE_STATE_IDLE); + SetConnectionType(net::NetworkChangeNotifier::CONNECTION_WIFI); + NiceMock<MockTransferUpdateCallback> callback; + + SetUpForegroundReceiveSurface(callback); + + // Ensures that introduction is never received for empty auth token. + std::string intro = "introduction_frame"; + std::vector<uint8_t> bytes(intro.begin(), intro.end()); + EXPECT_CALL(mock_decoder_, DecodeFrame(testing::Eq(bytes), testing::_)) + .Times(0); + connection_.AppendReadableData(bytes); + + service_->OnIncomingConnection(kEndpointId, kValidV1EndpointInfo, + &connection_); + ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1, + /*success=*/true); + + EXPECT_TRUE(connection_.IsClosed()); // To avoid UAF in OnIncomingTransferUpdate(). service_->UnregisterReceiveSurface(&callback);
diff --git a/chrome/browser/nearby_sharing/share_target_info.h b/chrome/browser/nearby_sharing/share_target_info.h index 38833893..d44c8ce 100644 --- a/chrome/browser/nearby_sharing/share_target_info.h +++ b/chrome/browser/nearby_sharing/share_target_info.h
@@ -11,6 +11,7 @@ #include "base/optional.h" #include "chrome/browser/nearby_sharing/certificates/nearby_share_decrypted_public_certificate.h" #include "chrome/browser/nearby_sharing/incoming_frames_reader.h" +#include "chrome/browser/nearby_sharing/paired_key_verification_runner.h" class NearbyConnection; @@ -55,12 +56,22 @@ frames_reader_ = std::move(frames_reader); } + PairedKeyVerificationRunner* key_verification_runner() { + return key_verification_runner_.get(); + } + + void set_key_verification_runner( + std::unique_ptr<PairedKeyVerificationRunner> key_verification_runner) { + key_verification_runner_ = std::move(key_verification_runner); + } + private: base::Optional<std::string> endpoint_id_; base::Optional<NearbyShareDecryptedPublicCertificate> certificate_; NearbyConnection* connection_ = nullptr; base::Optional<std::string> token_; std::unique_ptr<IncomingFramesReader> frames_reader_; + std::unique_ptr<PairedKeyVerificationRunner> key_verification_runner_; }; #endif // CHROME_BROWSER_NEARBY_SHARING_SHARE_TARGET_INFO_H_
diff --git a/chrome/browser/net/nss_context_chromeos.cc b/chrome/browser/net/nss_context_chromeos.cc index ef9fdf1..482f261 100644 --- a/chrome/browser/net/nss_context_chromeos.cc +++ b/chrome/browser/net/nss_context_chromeos.cc
@@ -7,6 +7,7 @@ #include <utility> #include "base/bind.h" +#include "base/callback_list.h" #include "base/macros.h" #include "base/memory/ptr_util.h" #include "base/memory/weak_ptr.h" @@ -46,12 +47,13 @@ if (nss_cert_database_) return nss_cert_database_.get(); - ready_callback_list_.push_back(std::move(callback)); + ready_callback_list_.AddUnsafe(std::move(callback)); return NULL; } private: - typedef std::vector<GetNSSCertDatabaseCallback> ReadyCallbackList; + using ReadyCallbackList = + base::OnceCallbackList<GetNSSCertDatabaseCallback::RunType>; void DidGetPrivateSlot(crypto::ScopedPK11Slot private_slot) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); @@ -59,10 +61,7 @@ crypto::GetPublicSlotForChromeOSUser(username_hash_), std::move(private_slot))); - ReadyCallbackList callback_list; - callback_list.swap(ready_callback_list_); - for (auto& callback : callback_list) - std::move(callback).Run(nss_cert_database_.get()); + ready_callback_list_.Notify(nss_cert_database_.get()); } std::string username_hash_;
diff --git a/chrome/browser/page_load_metrics/observers/third_party_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/third_party_metrics_observer.cc index f4c47e52..e1ff28c2 100644 --- a/chrome/browser/page_load_metrics/observers/third_party_metrics_observer.cc +++ b/chrome/browser/page_load_metrics/observers/third_party_metrics_observer.cc
@@ -113,11 +113,19 @@ AccessType::kCookieWrite); } -void ThirdPartyMetricsObserver::RecordStorageUseCounter( +void ThirdPartyMetricsObserver::RecordStorageAccessUseCounter( AccessType access_type) { page_load_metrics::mojom::PageLoadFeatures third_party_storage_features; switch (access_type) { + case AccessType::kCookieRead: + third_party_storage_features.features.push_back( + blink::mojom::WebFeature::kThirdPartyCookieRead); + break; + case AccessType::kCookieWrite: + third_party_storage_features.features.push_back( + blink::mojom::WebFeature::kThirdPartyCookieWrite); + break; case AccessType::kLocalStorage: third_party_storage_features.features.push_back( blink::mojom::WebFeature::kThirdPartyLocalStorage); @@ -249,7 +257,7 @@ } } - RecordStorageUseCounter(access_type); + RecordStorageAccessUseCounter(access_type); GURL representative_url( base::StrCat({url.scheme(), "://", registrable_domain, "/"}));
diff --git a/chrome/browser/page_load_metrics/observers/third_party_metrics_observer.h b/chrome/browser/page_load_metrics/observers/third_party_metrics_observer.h index 59683a12..107656b5 100644 --- a/chrome/browser/page_load_metrics/observers/third_party_metrics_observer.h +++ b/chrome/browser/page_load_metrics/observers/third_party_metrics_observer.h
@@ -74,7 +74,7 @@ const page_load_metrics::mojom::PageLoadTiming& main_frame_timing); // Records feature usage for |access_type| with use counters. - void RecordStorageUseCounter(AccessType accesse_type); + void RecordStorageAccessUseCounter(AccessType access_type); AccessType StorageTypeToAccessType( page_load_metrics::StorageType storage_type);
diff --git a/chrome/browser/page_load_metrics/observers/third_party_metrics_observer_browsertest.cc b/chrome/browser/page_load_metrics/observers/third_party_metrics_observer_browsertest.cc index 61e6876..9994f2b2 100644 --- a/chrome/browser/page_load_metrics/observers/third_party_metrics_observer_browsertest.cc +++ b/chrome/browser/page_load_metrics/observers/third_party_metrics_observer_browsertest.cc
@@ -221,6 +221,12 @@ histogram_tester.ExpectBucketCount( "Blink.UseCounter.Features", blink::mojom::WebFeature::kThirdPartyCacheStorage, 0); + histogram_tester.ExpectBucketCount( + "Blink.UseCounter.Features", + blink::mojom::WebFeature::kThirdPartyCookieRead, 0); + histogram_tester.ExpectBucketCount( + "Blink.UseCounter.Features", + blink::mojom::WebFeature::kThirdPartyCookieWrite, 0); } IN_PROC_BROWSER_TEST_F(ThirdPartyMetricsObserverBrowserTest, @@ -232,6 +238,12 @@ histogram_tester.ExpectUniqueSample(kReadCookieHistogram, 0, 1); histogram_tester.ExpectUniqueSample(kWriteCookieHistogram, 0, 1); + histogram_tester.ExpectBucketCount( + "Blink.UseCounter.Features", + blink::mojom::WebFeature::kThirdPartyCookieRead, 0); + histogram_tester.ExpectBucketCount( + "Blink.UseCounter.Features", + blink::mojom::WebFeature::kThirdPartyCookieWrite, 0); } IN_PROC_BROWSER_TEST_F(ThirdPartyMetricsObserverBrowserTest, @@ -246,6 +258,12 @@ histogram_tester.ExpectUniqueSample(kReadCookieHistogram, 1, 1); histogram_tester.ExpectUniqueSample(kWriteCookieHistogram, 1, 1); + histogram_tester.ExpectBucketCount( + "Blink.UseCounter.Features", + blink::mojom::WebFeature::kThirdPartyCookieRead, 1); + histogram_tester.ExpectBucketCount( + "Blink.UseCounter.Features", + blink::mojom::WebFeature::kThirdPartyCookieWrite, 1); } IN_PROC_BROWSER_TEST_F(ThirdPartyMetricsObserverBrowserTest, @@ -265,6 +283,12 @@ histogram_tester.ExpectUniqueSample(kReadCookieHistogram, 1, 1); histogram_tester.ExpectUniqueSample(kWriteCookieHistogram, 1, 1); + histogram_tester.ExpectBucketCount( + "Blink.UseCounter.Features", + blink::mojom::WebFeature::kThirdPartyCookieRead, 1); + histogram_tester.ExpectBucketCount( + "Blink.UseCounter.Features", + blink::mojom::WebFeature::kThirdPartyCookieWrite, 1); } IN_PROC_BROWSER_TEST_F(ThirdPartyMetricsObserverBrowserTest, @@ -283,6 +307,12 @@ histogram_tester.ExpectUniqueSample(kReadCookieHistogram, 2, 1); histogram_tester.ExpectUniqueSample(kWriteCookieHistogram, 2, 1); + histogram_tester.ExpectBucketCount( + "Blink.UseCounter.Features", + blink::mojom::WebFeature::kThirdPartyCookieRead, 1); + histogram_tester.ExpectBucketCount( + "Blink.UseCounter.Features", + blink::mojom::WebFeature::kThirdPartyCookieWrite, 1); } IN_PROC_BROWSER_TEST_F(ThirdPartyMetricsObserverBrowserTest, @@ -302,6 +332,12 @@ histogram_tester.ExpectUniqueSample(kReadCookieHistogram, 0, 1); histogram_tester.ExpectUniqueSample(kWriteCookieHistogram, 0, 1); + histogram_tester.ExpectBucketCount( + "Blink.UseCounter.Features", + blink::mojom::WebFeature::kThirdPartyCookieRead, 0); + histogram_tester.ExpectBucketCount( + "Blink.UseCounter.Features", + blink::mojom::WebFeature::kThirdPartyCookieWrite, 0); } IN_PROC_BROWSER_TEST_F(ThirdPartyMetricsObserverBrowserTest, @@ -322,6 +358,12 @@ histogram_tester.ExpectUniqueSample(kReadCookieHistogram, 1, 1); histogram_tester.ExpectUniqueSample(kWriteCookieHistogram, 1, 1); + histogram_tester.ExpectBucketCount( + "Blink.UseCounter.Features", + blink::mojom::WebFeature::kThirdPartyCookieRead, 1); + histogram_tester.ExpectBucketCount( + "Blink.UseCounter.Features", + blink::mojom::WebFeature::kThirdPartyCookieWrite, 1); } IN_PROC_BROWSER_TEST_F(ThirdPartyMetricsObserverBrowserTest, @@ -339,6 +381,12 @@ // No read is counted since no cookie has previously been set. histogram_tester.ExpectUniqueSample(kReadCookieHistogram, 0, 1); histogram_tester.ExpectUniqueSample(kWriteCookieHistogram, 0, 1); + histogram_tester.ExpectBucketCount( + "Blink.UseCounter.Features", + blink::mojom::WebFeature::kThirdPartyCookieRead, 0); + histogram_tester.ExpectBucketCount( + "Blink.UseCounter.Features", + blink::mojom::WebFeature::kThirdPartyCookieWrite, 0); } IN_PROC_BROWSER_TEST_F(ThirdPartyMetricsObserverBrowserTest, @@ -356,6 +404,12 @@ histogram_tester.ExpectUniqueSample(kReadCookieHistogram, 0, 1); histogram_tester.ExpectUniqueSample(kWriteCookieHistogram, 1, 1); + histogram_tester.ExpectBucketCount( + "Blink.UseCounter.Features", + blink::mojom::WebFeature::kThirdPartyCookieRead, 0); + histogram_tester.ExpectBucketCount( + "Blink.UseCounter.Features", + blink::mojom::WebFeature::kThirdPartyCookieWrite, 1); } class ThirdPartyDomStorageAccessMetricsObserverBrowserTest
diff --git a/chrome/browser/paint_preview/paint_preview_compositor_browsertest.cc b/chrome/browser/paint_preview/paint_preview_compositor_browsertest.cc index ae146e6..0da01f8 100644 --- a/chrome/browser/paint_preview/paint_preview_compositor_browsertest.cc +++ b/chrome/browser/paint_preview/paint_preview_compositor_browsertest.cc
@@ -113,9 +113,8 @@ IN_PROC_BROWSER_TEST_F(PaintPreviewCompositorBrowserTest, CompositorCreate) { CreateServiceInstance(); - auto* base_service = GetBaseService(); - auto compositor_service = ToCompositorServiceImpl( - base_service->StartCompositorService(base::DoNothing())); + auto compositor_service = + ToCompositorServiceImpl(StartCompositorService(base::DoNothing())); base::RunLoop loop; auto compositor = ToCompositorClientImpl( @@ -133,9 +132,8 @@ IN_PROC_BROWSER_TEST_F(PaintPreviewCompositorBrowserTest, MultipleCompositorCreate) { CreateServiceInstance(); - auto* base_service = GetBaseService(); - auto compositor_service = ToCompositorServiceImpl( - base_service->StartCompositorService(base::DoNothing())); + auto compositor_service = + ToCompositorServiceImpl(StartCompositorService(base::DoNothing())); EXPECT_EQ(0U, compositor_service->ActiveClientsForTesting().size()); EXPECT_FALSE(compositor_service->HasActiveClients()); @@ -174,12 +172,11 @@ IN_PROC_BROWSER_TEST_F(PaintPreviewCompositorBrowserTest, KillWithActiveCompositors) { CreateServiceInstance(); - auto* base_service = GetBaseService(); // NOTE: the disconnect handler for the service as a whole only triggers if // the service is killed unexpectedly. Here the |compositor_service| object // is deleted (performing a graceful shutdown) so the handler won't run. - auto compositor_service = ToCompositorServiceImpl( - base_service->StartCompositorService(base::DoNothing())); + auto compositor_service = + ToCompositorServiceImpl(StartCompositorService(base::DoNothing())); base::RunLoop loop; auto compositor = ToCompositorClientImpl(
diff --git a/chrome/browser/password_check/android/BUILD.gn b/chrome/browser/password_check/android/BUILD.gn index 4833287e..1737d4c 100644 --- a/chrome/browser/password_check/android/BUILD.gn +++ b/chrome/browser/password_check/android/BUILD.gn
@@ -44,9 +44,11 @@ "//third_party/android_deps:androidx_fragment_fragment_java", "//third_party/android_deps:androidx_preference_preference_java", "//third_party/android_deps:androidx_recyclerview_recyclerview_java", + "//third_party/android_deps:material_design_java", ] sources = [ "java/src/org/chromium/chrome/browser/password_check/PasswordCheck.java", + "java/src/org/chromium/chrome/browser/password_check/PasswordCheckEditFragmentView.java", "java/src/org/chromium/chrome/browser/password_check/PasswordCheckFragmentView.java", "java/src/org/chromium/chrome/browser/password_check/PasswordCheckPreference.java", "java/src/org/chromium/chrome/browser/password_check/PasswordCheckReferrer.java", @@ -93,6 +95,7 @@ testonly = true sources = [ + "javatests/src/org/chromium/chrome/browser/password_check/PasswordCheckEditViewTest.java", "javatests/src/org/chromium/chrome/browser/password_check/PasswordCheckIntegrationTest.java", "javatests/src/org/chromium/chrome/browser/password_check/PasswordCheckViewTest.java", ] @@ -122,6 +125,7 @@ "//third_party/android_deps:androidx_recyclerview_recyclerview_java", "//third_party/android_deps:androidx_test_runner_java", "//third_party/android_deps:espresso_java", + "//third_party/android_sdk:android_test_base_java", "//third_party/hamcrest:hamcrest_java", "//third_party/junit", "//third_party/mockito:mockito_java", @@ -145,7 +149,9 @@ "java/res/drawable-night/password_checkup_warning.xml", "java/res/drawable/password_check_neutral.xml", "java/res/drawable/password_checkup_warning.xml", + "java/res/layout/password_check_edit_fragment.xml", "java/res/layout/password_check_preference_button.xml", + "java/res/menu/password_check_editor_action_bar_menu.xml", "java/res/values-night/colors.xml", "java/res/values/colors.xml", ]
diff --git a/chrome/browser/password_check/android/internal/BUILD.gn b/chrome/browser/password_check/android/internal/BUILD.gn index e26f2b95..21ec5869 100644 --- a/chrome/browser/password_check/android/internal/BUILD.gn +++ b/chrome/browser/password_check/android/internal/BUILD.gn
@@ -88,6 +88,7 @@ "java/src/org/chromium/chrome/browser/password_check/PasswordCheckProperties.java", "java/src/org/chromium/chrome/browser/password_check/PasswordCheckViewBinder.java", "java/src/org/chromium/chrome/browser/password_check/PasswordCheckViewHolder.java", + "java/src/org/chromium/chrome/browser/password_check/helper/PasswordCheckChangePasswordHelper.java", "java/src/org/chromium/chrome/browser/password_check/helper/PasswordCheckReauthenticationHelper.java", ] annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
diff --git a/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckBridge.java b/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckBridge.java index 95cf296..ee57286 100644 --- a/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckBridge.java +++ b/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckBridge.java
@@ -106,9 +106,8 @@ /** * @return The timestamp of the last completed check. */ - long getCheckTimestamp() { - // TODO(crbug.com/1102025): Add method to retrieve the timestamp. - return 0L; + long getLastCheckTimestamp() { + return PasswordCheckBridgeJni.get().getLastCheckTimestamp(mNativePasswordCheckBridge); } /** @@ -164,6 +163,7 @@ long create(PasswordCheckBridge passwordCheckBridge); void startCheck(long nativePasswordCheckBridge); void stopCheck(long nativePasswordCheckBridge); + long getLastCheckTimestamp(long nativePasswordCheckBridge); int getCompromisedCredentialsCount(long nativePasswordCheckBridge); int getSavedPasswordsCount(long nativePasswordCheckBridge); void getCompromisedCredentials(
diff --git a/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckCoordinator.java b/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckCoordinator.java index 039dc70..097b25e 100644 --- a/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckCoordinator.java +++ b/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckCoordinator.java
@@ -4,41 +4,23 @@ package org.chromium.chrome.browser.password_check; -import android.app.Activity; -import android.content.Intent; -import android.net.Uri; -import android.provider.Browser; import android.view.MenuItem; import androidx.annotation.VisibleForTesting; -import androidx.browser.customtabs.CustomTabsIntent; import androidx.lifecycle.LifecycleObserver; -import org.chromium.base.IntentUtils; -import org.chromium.chrome.browser.IntentHandler; -import org.chromium.chrome.browser.LaunchIntentDispatcher; import org.chromium.chrome.browser.help.HelpAndFeedback; +import org.chromium.chrome.browser.password_check.helper.PasswordCheckChangePasswordHelper; import org.chromium.chrome.browser.password_check.helper.PasswordCheckReauthenticationHelper; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.ui.modelutil.PropertyModel; import org.chromium.ui.modelutil.PropertyModelChangeProcessor; -import java.util.Objects; - /** * Creates the PasswordCheckComponentUi. This class is responsible for managing the UI for the check * of the leaked password. */ -class PasswordCheckCoordinator implements PasswordCheckComponentUi, LifecycleObserver, - PasswordCheckComponentUi.ChangePasswordDelegate { - private static final String AUTOFILL_ASSISTANT_PACKAGE = - "org.chromium.chrome.browser.autofill_assistant."; - private static final String AUTOFILL_ASSISTANT_ENABLED_KEY = - AUTOFILL_ASSISTANT_PACKAGE + "ENABLED"; - private static final String PASSWORD_CHANGE_USERNAME_PARAMETER = "PASSWORD_CHANGE_USERNAME"; - private static final String INTENT_PARAMETER = "INTENT"; - private static final String INTENT = "PASSWORD_CHANGE"; - +class PasswordCheckCoordinator implements PasswordCheckComponentUi, LifecycleObserver { private final PasswordCheckFragmentView mFragmentView; private final PasswordCheckReauthenticationHelper mReauthenticationHelper; private final PasswordCheckMediator mMediator; @@ -86,7 +68,9 @@ mReauthenticationHelper = new PasswordCheckReauthenticationHelper( mFragmentView.getActivity(), mFragmentView.getParentFragmentManager()); - mMediator = new PasswordCheckMediator(this, mReauthenticationHelper); + mMediator = new PasswordCheckMediator( + new PasswordCheckChangePasswordHelper(mFragmentView.getActivity()), + mReauthenticationHelper); } @Override @@ -143,72 +127,4 @@ PropertyModelChangeProcessor.create( model, view, PasswordCheckViewBinder::bindPasswordCheckView); } - - /** - * Launches a CCT that points to the change password form or home page of |origin|. - * @param credential A {@link CompromisedCredential} to be changed in an App or in a CCT. - */ - @Override - public void launchAppOrCctWithChangePasswordUrl(CompromisedCredential credential) { - // TODO(crbug.com/1092444): Always launch the URL if possible and let Android handle the - // match to open it. - IntentUtils.safeStartActivity(mFragmentView.getActivity(), - credential.getAssociatedApp().isEmpty() - ? buildIntent(credential.getPasswordChangeUrl()) - : getPackageLaunchIntent(credential.getAssociatedApp())); - } - - @Override - public boolean canManuallyChangeCredential(CompromisedCredential credential) { - return !credential.getPasswordChangeUrl().isEmpty() - || getPackageLaunchIntent(credential.getAssociatedApp()) != null; - } - - /** - * Launches a CCT that starts a password change script for a {@link CompromisedCredential}. - * @param credential A {@link CompromisedCredential} to be changed with a script. - */ - @Override - public void launchCctWithScript(CompromisedCredential credential) { - Intent intent = buildIntent(credential.getOrigin().getSpec()); - populateAutofillAssistantExtras(intent, credential.getUsername()); - IntentUtils.safeStartActivity(mFragmentView.getActivity(), intent); - } - - private Intent getPackageLaunchIntent(String packageName) { - return Objects.requireNonNull(mFragmentView.getActivity()) - .getPackageManager() - .getLaunchIntentForPackage(packageName); - } - - /** - * Builds an intent to launch a CCT. - * @param initialUrl Initial URL to launch a CCT. - * @return {@link Intent} for CCT. - */ - private Intent buildIntent(String initialUrl) { - final Activity activity = mFragmentView.getActivity(); - CustomTabsIntent customTabIntent = - new CustomTabsIntent.Builder().setShowTitle(true).build(); - customTabIntent.intent.setData(Uri.parse(initialUrl)); - Intent intent = LaunchIntentDispatcher.createCustomTabActivityIntent( - activity, customTabIntent.intent); - intent.setPackage(activity.getPackageName()); - intent.putExtra(Browser.EXTRA_APPLICATION_ID, activity.getPackageName()); - IntentHandler.addTrustedIntentExtras(intent); - return intent; - } - - /** - * Populates intent extras for an Autofill Assistant script. - * @param intent An {@link Intent} to be populated. - * @param username A username for a password change script. One of extras to put. - */ - private void populateAutofillAssistantExtras(Intent intent, String username) { - intent.putExtra(AUTOFILL_ASSISTANT_ENABLED_KEY, /* value= */ true); - intent.putExtra(AUTOFILL_ASSISTANT_PACKAGE + PASSWORD_CHANGE_USERNAME_PARAMETER, username); - intent.putExtra(AUTOFILL_ASSISTANT_PACKAGE + INTENT_PARAMETER, INTENT); - // TODO(crbug.com/1086114): Also add the following parameters when server side changes is - // ready: CALLER, SOURCE. That would be useful for metrics. - } }
diff --git a/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckImpl.java b/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckImpl.java index 054abd9..f48461d 100644 --- a/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckImpl.java +++ b/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckImpl.java
@@ -100,8 +100,8 @@ } @Override - public long getCheckTimestamp() { - return mPasswordCheckBridge.getCheckTimestamp(); + public long getLastCheckTimestamp() { + return mPasswordCheckBridge.getLastCheckTimestamp(); } @Override
diff --git a/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckMediator.java b/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckMediator.java index 47978a7..cd7b6373 100644 --- a/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckMediator.java +++ b/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckMediator.java
@@ -22,7 +22,7 @@ import androidx.appcompat.app.AlertDialog; -import org.chromium.chrome.browser.password_check.PasswordCheckComponentUi.ChangePasswordDelegate; +import org.chromium.chrome.browser.password_check.helper.PasswordCheckChangePasswordHelper; import org.chromium.chrome.browser.password_check.helper.PasswordCheckReauthenticationHelper; import org.chromium.chrome.browser.password_check.helper.PasswordCheckReauthenticationHelper.ReauthReason; import org.chromium.ui.modelutil.ListModel; @@ -35,12 +35,12 @@ */ class PasswordCheckMediator implements PasswordCheckCoordinator.CredentialEventHandler, PasswordCheck.Observer { - private final PasswordCheckComponentUi.ChangePasswordDelegate mChangePasswordDelegate; private final PasswordCheckReauthenticationHelper mReauthenticationHelper; + private final PasswordCheckChangePasswordHelper mChangePasswordDelegate; private PropertyModel mModel; private PasswordCheckComponentUi.Delegate mDelegate; - PasswordCheckMediator(ChangePasswordDelegate changePasswordDelegate, + PasswordCheckMediator(PasswordCheckChangePasswordHelper changePasswordDelegate, PasswordCheckReauthenticationHelper reauthenticationHelper) { mChangePasswordDelegate = changePasswordDelegate; mReauthenticationHelper = reauthenticationHelper; @@ -108,7 +108,7 @@ Integer compromisedCredentialCount = null; if (status == PasswordCheckUIStatus.IDLE) { compromisedCredentialCount = getPasswordCheck().getCompromisedCredentialsCount(); - checkTimestamp = getPasswordCheck().getCheckTimestamp(); + checkTimestamp = getPasswordCheck().getLastCheckTimestamp(); } header.set(CHECK_TIMESTAMP, checkTimestamp); header.set(COMPROMISED_CREDENTIALS_COUNT, compromisedCredentialCount); @@ -146,11 +146,9 @@ return; } - mReauthenticationHelper.reauthenticate(ReauthReason.EDIT_PASSWORD, - reauthSucceeded - -> { - // TODO(crbug.com/1114720): Show edit fragment if reauth succeeded. - }); + mReauthenticationHelper.reauthenticate(ReauthReason.EDIT_PASSWORD, reauthSucceeded -> { + if (reauthSucceeded) mChangePasswordDelegate.launchEditPage(credential); + }); } @Override
diff --git a/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/helper/PasswordCheckChangePasswordHelper.java b/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/helper/PasswordCheckChangePasswordHelper.java new file mode 100644 index 0000000..0f32ff4 --- /dev/null +++ b/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/helper/PasswordCheckChangePasswordHelper.java
@@ -0,0 +1,126 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.password_check.helper; + +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.provider.Browser; + +import androidx.browser.customtabs.CustomTabsIntent; + +import org.chromium.base.IntentUtils; +import org.chromium.chrome.browser.IntentHandler; +import org.chromium.chrome.browser.LaunchIntentDispatcher; +import org.chromium.chrome.browser.password_check.CompromisedCredential; +import org.chromium.chrome.browser.password_check.PasswordCheckEditFragmentView; +import org.chromium.chrome.browser.settings.SettingsLauncher; +import org.chromium.chrome.browser.settings.SettingsLauncherImpl; + +import java.util.Objects; + +/** + * Helper to launch apps, settings screens, or Chrome Custom tabs that enable the user to change a + * compromised password. + */ +public class PasswordCheckChangePasswordHelper { + private static final String AUTOFILL_ASSISTANT_PACKAGE = + "org.chromium.chrome.browser.autofill_assistant."; + private static final String AUTOFILL_ASSISTANT_ENABLED_KEY = + AUTOFILL_ASSISTANT_PACKAGE + "ENABLED"; + private static final String PASSWORD_CHANGE_USERNAME_PARAMETER = "PASSWORD_CHANGE_USERNAME"; + private static final String INTENT_PARAMETER = "INTENT"; + private static final String INTENT = "PASSWORD_CHANGE"; + + private final Context mContext; + + public PasswordCheckChangePasswordHelper(Context context) { + mContext = context; + } + + /** + * Launches an app (if available) or a CCT with the site the given credential was used on. + * @param credential A {@link CompromisedCredential}. + */ + public void launchAppOrCctWithChangePasswordUrl(CompromisedCredential credential) { + // TODO(crbug.com/1092444): Always launch the URL if possible and let Android handle the + // match to open it. + IntentUtils.safeStartActivity(mContext, + credential.getAssociatedApp().isEmpty() + ? buildIntent(credential.getPasswordChangeUrl()) + : getPackageLaunchIntent(credential.getAssociatedApp())); + } + + /** + * @param credential A {@link CompromisedCredential}. + * @return True iff there is a valid URL to navigate to or an app that can be opened. + */ + public boolean canManuallyChangeCredential(CompromisedCredential credential) { + return !credential.getPasswordChangeUrl().isEmpty() + || getPackageLaunchIntent(credential.getAssociatedApp()) != null; + } + + /** + * Launches a CCT with the site the given credential was used on and invokes the script that + * fixes the compromised credential automatically. + * @param credential A {@link CompromisedCredential}. + */ + public void launchCctWithScript(CompromisedCredential credential) { + Intent intent = buildIntent(credential.getOrigin().getSpec()); + populateAutofillAssistantExtras(intent, credential.getUsername()); + IntentUtils.safeStartActivity(mContext, intent); + } + + /** + * Launches a settings fragment to edit the given credential. + * @param credential A {@link CompromisedCredential} to change. + */ + public void launchEditPage(CompromisedCredential credential) { + SettingsLauncher launcher = new SettingsLauncherImpl(); + Bundle fragmentArgs = new Bundle(); + fragmentArgs.putParcelable( + PasswordCheckEditFragmentView.EXTRA_COMPROMISED_CREDENTIAL, credential); + launcher.launchSettingsActivity( + mContext, PasswordCheckEditFragmentView.class, fragmentArgs); + } + + private Intent getPackageLaunchIntent(String packageName) { + return Objects.requireNonNull(mContext).getPackageManager().getLaunchIntentForPackage( + packageName); + } + + /** + * Builds an intent to launch a CCT. + * + * @param initialUrl Initial URL to launch a CCT. + * @return {@link Intent} for CCT. + */ + private Intent buildIntent(String initialUrl) { + CustomTabsIntent customTabIntent = + new CustomTabsIntent.Builder().setShowTitle(true).build(); + customTabIntent.intent.setData(Uri.parse(initialUrl)); + Intent intent = LaunchIntentDispatcher.createCustomTabActivityIntent( + mContext, customTabIntent.intent); + intent.setPackage(mContext.getPackageName()); + intent.putExtra(Browser.EXTRA_APPLICATION_ID, mContext.getPackageName()); + IntentHandler.addTrustedIntentExtras(intent); + return intent; + } + + /** + * Populates intent extras for an Autofill Assistant script. + * + * @param intent An {@link Intent} to be populated. + * @param username A username for a password change script. One of extras to put. + */ + private void populateAutofillAssistantExtras(Intent intent, String username) { + intent.putExtra(AUTOFILL_ASSISTANT_ENABLED_KEY, true); + intent.putExtra(AUTOFILL_ASSISTANT_PACKAGE + PASSWORD_CHANGE_USERNAME_PARAMETER, username); + intent.putExtra(AUTOFILL_ASSISTANT_PACKAGE + INTENT_PARAMETER, INTENT); + // TODO(crbug.com/1086114): Also add the following parameters when server side changes is + // ready: CALLER, SOURCE. That would be useful for metrics. + } +} \ No newline at end of file
diff --git a/chrome/browser/password_check/android/java/res/layout/password_check_edit_fragment.xml b/chrome/browser/password_check/android/java/res/layout/password_check_edit_fragment.xml new file mode 100644 index 0000000..88681c3c --- /dev/null +++ b/chrome/browser/password_check/android/java/res/layout/password_check_edit_fragment.xml
@@ -0,0 +1,96 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2020 The Chromium Authors. All rights reserved. + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. --> + +<!-- Layout for a preference with a title and a compound drawable above. --> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:paddingStart="@dimen/password_entry_editor_content_spacing" + android:paddingEnd="@dimen/password_entry_editor_content_spacing" + android:paddingLeft="@dimen/password_entry_editor_content_spacing" + android:paddingRight="@dimen/password_entry_editor_content_spacing"> + + <!-- Site --> + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/site_label" + android:labelFor="@+id/site_edit" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/password_entry_editor_field_large_top_margin" + android:layout_marginBottom="@dimen/password_entry_editor_field_bottom_margin"> + + <EditText + tools:ignore="LabelFor" + android:id="@+id/site_edit" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:imeOptions="flagNoExtractUi" + android:inputType="text" + android:hint="@string/password_entry_viewer_site_title" + android:enabled="false"/> + </com.google.android.material.textfield.TextInputLayout> + + <!-- Username --> + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/username_label" + android:labelFor="@+id/username_edit" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/password_entry_editor_field_top_margin" + android:layout_marginBottom="@dimen/password_entry_editor_field_bottom_margin"> + + <EditText + tools:ignore="LabelFor" + android:id="@+id/username_edit" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:imeOptions="flagNoExtractUi" + android:inputType="text" + android:hint="@string/password_entry_viewer_username_title" + android:enabled="false"/> + </com.google.android.material.textfield.TextInputLayout> + + <!-- Password --> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:gravity="center"> + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/password_label" + android:labelFor="@+id/password_edit" + android:layout_height="wrap_content" + android:layout_width="0dp" + android:layout_weight="1" + android:layout_marginTop="@dimen/password_entry_editor_field_top_margin" + android:layout_marginBottom="@dimen/password_entry_editor_field_bottom_margin"> + + <EditText + tools:ignore="LabelFor" + android:id="@+id/password_edit" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:imeOptions="flagNoExtractUi" + android:inputType="textVisiblePassword" + android:hint="@string/password_entry_viewer_password"/> + </com.google.android.material.textfield.TextInputLayout> + + + <org.chromium.ui.widget.ChromeImageButton + android:id="@+id/password_entry_editor_view_password" + android:background="?attr/selectableItemBackground" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + app:srcCompat="@drawable/ic_visibility_black" + app:tint="@color/default_icon_color_tint_list" + style="?android:attr/buttonStyleSmall"/> + + </LinearLayout> + +</LinearLayout> \ No newline at end of file
diff --git a/chrome/browser/password_check/android/java/res/menu/password_check_editor_action_bar_menu.xml b/chrome/browser/password_check/android/java/res/menu/password_check_editor_action_bar_menu.xml new file mode 100644 index 0000000..ba93132 --- /dev/null +++ b/chrome/browser/password_check/android/java/res/menu/password_check_editor_action_bar_menu.xml
@@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2020 The Chromium Authors. All rights reserved. + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. --> + +<menu xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" > + + <item + android:id="@+id/action_save_edited_password" + android:title="@string/save" + app:showAsAction="always"/> +</menu> \ No newline at end of file
diff --git a/chrome/browser/password_check/android/java/src/org/chromium/chrome/browser/password_check/CompromisedCredential.java b/chrome/browser/password_check/android/java/src/org/chromium/chrome/browser/password_check/CompromisedCredential.java index 3db553c..6da6e52 100644 --- a/chrome/browser/password_check/android/java/src/org/chromium/chrome/browser/password_check/CompromisedCredential.java +++ b/chrome/browser/password_check/android/java/src/org/chromium/chrome/browser/password_check/CompromisedCredential.java
@@ -155,8 +155,9 @@ @Override public int hashCode() { - return Objects.hash(mSignonRealm, mOrigin, mUsername, mDisplayOrigin, mDisplayUsername, - mPassword, mPasswordChangeUrl, mAssociatedApp, mPhished, mHasScript); + return Objects.hash(mSignonRealm, mOrigin.getPossiblyInvalidSpec(), mUsername, + mDisplayOrigin, mDisplayUsername, mPassword, mPasswordChangeUrl, mAssociatedApp, + mPhished, mHasScript); } @Override
diff --git a/chrome/browser/password_check/android/java/src/org/chromium/chrome/browser/password_check/PasswordCheck.java b/chrome/browser/password_check/android/java/src/org/chromium/chrome/browser/password_check/PasswordCheck.java index aa3a8a0..c8067aa 100644 --- a/chrome/browser/password_check/android/java/src/org/chromium/chrome/browser/password_check/PasswordCheck.java +++ b/chrome/browser/password_check/android/java/src/org/chromium/chrome/browser/password_check/PasswordCheck.java
@@ -69,7 +69,7 @@ /** * @return The timestamp of the last completed check. */ - long getCheckTimestamp(); + long getLastCheckTimestamp(); /** * @return The last known status of the check.
diff --git a/chrome/browser/password_check/android/java/src/org/chromium/chrome/browser/password_check/PasswordCheckComponentUi.java b/chrome/browser/password_check/android/java/src/org/chromium/chrome/browser/password_check/PasswordCheckComponentUi.java index f0d0ec6b..86b6252 100644 --- a/chrome/browser/password_check/android/java/src/org/chromium/chrome/browser/password_check/PasswordCheckComponentUi.java +++ b/chrome/browser/password_check/android/java/src/org/chromium/chrome/browser/password_check/PasswordCheckComponentUi.java
@@ -9,7 +9,7 @@ /** * This component is responsible for handling the UI logic for the password check. */ -interface PasswordCheckComponentUi { +public interface PasswordCheckComponentUi { /** * A delegate that handles native tasks for the UI component. */ @@ -22,31 +22,6 @@ } /** - * Implementers of this delegate are expected to launch apps or Chrome Custom tabs that enable - * the user to change a compromised password. - */ - interface ChangePasswordDelegate { - /** - * @param credential A {@link CompromisedCredential}. - * @return True iff there is a valid URL to navigate to or an app that can be opened. - */ - boolean canManuallyChangeCredential(CompromisedCredential credential); - - /** - * Launches an app (if available) or a CCT with the site the given credential was used on. - * @param credential A {@link CompromisedCredential}. - */ - void launchAppOrCctWithChangePasswordUrl(CompromisedCredential credential); - - /** - * Launches a CCT with the site the given credential was used on and invokes the script that - * fixes the compromised credential automatically. - * @param credential A {@link CompromisedCredential}. - */ - void launchCctWithScript(CompromisedCredential credential); - } - - /** * Handle the request of the user to show the help page for the Check Passwords view. * @param item A {@link MenuItem}. */
diff --git a/chrome/browser/password_check/android/java/src/org/chromium/chrome/browser/password_check/PasswordCheckEditFragmentView.java b/chrome/browser/password_check/android/java/src/org/chromium/chrome/browser/password_check/PasswordCheckEditFragmentView.java new file mode 100644 index 0000000..132d528 --- /dev/null +++ b/chrome/browser/password_check/android/java/src/org/chromium/chrome/browser/password_check/PasswordCheckEditFragmentView.java
@@ -0,0 +1,118 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.password_check; + +import android.os.Bundle; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.EditText; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; +import androidx.preference.PreferenceFragmentCompat; + +/** + * This class is responsible for rendering the edit fragment where users can provide a new password + * for compromised credentials. + * TODO(crbug.com/1092444): Make this a component that is reusable in password settings as well. + */ +public class PasswordCheckEditFragmentView extends PreferenceFragmentCompat { + public static final String EXTRA_COMPROMISED_CREDENTIAL = "extra_compromised_credential"; + @VisibleForTesting + static final String EXTRA_NEW_PASSWORD = "extra_new_password"; + + private String mNewPassword; + private CompromisedCredential mCredential; + + private EditText mPasswordText; + + @Override + public void onCreatePreferences(Bundle bundle, String s) {} + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + setHasOptionsMenu(true); + getActivity().setTitle(R.string.password_entry_viewer_edit_stored_password_action_title); + return inflater.inflate(R.layout.password_check_edit_fragment, container, false); + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + mCredential = getCredentialFromInstanceStateOrLaunchBundle(savedInstanceState); + mNewPassword = getNewPasswordFromInstanceStateOrLaunchBundle(savedInstanceState); + + EditText siteText = (EditText) view.findViewById(R.id.site_edit); + siteText.setText(mCredential.getDisplayOrigin()); + + EditText usernameText = (EditText) view.findViewById(R.id.username_edit); + usernameText.setText(mCredential.getDisplayUsername()); + + mPasswordText = (EditText) view.findViewById(R.id.password_edit); + mPasswordText.setText(mCredential.getPassword()); + mPasswordText.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) {} + + @Override + public void afterTextChanged(Editable editable) { + mNewPassword = mPasswordText.getText().toString(); + if (TextUtils.isEmpty(mNewPassword)) { + // TODO(crbug.com/1114720): setError on R.id.password_label. + } + } + }); + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + menu.clear(); // Remove help and feedback for this screen. + inflater.inflate(R.menu.password_check_editor_action_bar_menu, menu); + // TODO(crbug.com/1092444): Make the back arrow an 'X'. + } + + @Override + public void onSaveInstanceState(@NonNull Bundle outState) { + super.onSaveInstanceState(outState); + outState.putParcelable(EXTRA_COMPROMISED_CREDENTIAL, mCredential); + outState.putString(EXTRA_NEW_PASSWORD, mNewPassword); + } + + private CompromisedCredential getCredentialFromInstanceStateOrLaunchBundle( + Bundle savedInstanceState) { + if (savedInstanceState != null + && savedInstanceState.containsKey(EXTRA_COMPROMISED_CREDENTIAL)) { + return savedInstanceState.getParcelable(EXTRA_COMPROMISED_CREDENTIAL); + } + Bundle extras = getArguments(); + assert extras != null + && extras.containsKey(EXTRA_COMPROMISED_CREDENTIAL) + : "PasswordCheckEditFragmentView must be launched with a compromised credential " + + "extra!"; + return extras.getParcelable(EXTRA_COMPROMISED_CREDENTIAL); + } + + private String getNewPasswordFromInstanceStateOrLaunchBundle(Bundle savedInstanceState) { + if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_NEW_PASSWORD)) { + return savedInstanceState.getParcelable(EXTRA_NEW_PASSWORD); + } + Bundle extras = getArguments(); + if (extras != null && extras.containsKey(EXTRA_NEW_PASSWORD)) { + return extras.getParcelable(EXTRA_NEW_PASSWORD); + } + return mCredential.getPassword(); + } +}
diff --git a/chrome/browser/password_check/android/javatests/src/org/chromium/chrome/browser/password_check/PasswordCheckEditViewTest.java b/chrome/browser/password_check/android/javatests/src/org/chromium/chrome/browser/password_check/PasswordCheckEditViewTest.java new file mode 100644 index 0000000..14a2dcba --- /dev/null +++ b/chrome/browser/password_check/android/javatests/src/org/chromium/chrome/browser/password_check/PasswordCheckEditViewTest.java
@@ -0,0 +1,112 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.password_check; + +import static junit.framework.Assert.assertTrue; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; + +import static org.chromium.chrome.browser.password_check.PasswordCheckEditFragmentView.EXTRA_COMPROMISED_CREDENTIAL; +import static org.chromium.chrome.browser.password_check.PasswordCheckEditFragmentView.EXTRA_NEW_PASSWORD; +import static org.chromium.content_public.browser.test.util.CriteriaHelper.pollUiThread; +import static org.chromium.content_public.browser.test.util.TestThreadUtils.runOnUiThreadBlocking; + +import android.os.Bundle; +import android.text.InputType; +import android.widget.EditText; + +import androidx.test.filters.MediumTest; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; + +import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.chrome.browser.flags.ChromeSwitches; +import org.chromium.chrome.browser.settings.SettingsActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; +import org.chromium.url.GURL; + +/** + * View tests for the Password Check Edit screen only. + */ +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) +public class PasswordCheckEditViewTest { + private static final CompromisedCredential ANA = + new CompromisedCredential("https://some-url.com/signin", + new GURL("https://some-url.com/"), "Ana", "some-url.com", "Ana", "password", + "https://some-url.com/.well-known/change-password", "", false, false); + + private PasswordCheckEditFragmentView mPasswordCheckEditView; + + @Rule + public SettingsActivityTestRule<PasswordCheckEditFragmentView> mTestRule = + new SettingsActivityTestRule<>(PasswordCheckEditFragmentView.class); + + @Before + public void setUp() throws InterruptedException { + MockitoAnnotations.initMocks(this); + setUpUiLaunchedFromSettings(); + } + + @Test + @MediumTest + public void testLoadsCredential() { + pollUiThread(() -> mPasswordCheckEditView != null); + + EditText origin = mPasswordCheckEditView.getView().findViewById(R.id.site_edit); + assertNotNull(origin); + assertNotNull(origin.getText()); + assertNotNull(origin.getText().toString()); + assertThat(origin.getText().toString(), equalTo(ANA.getDisplayOrigin())); + + EditText username = mPasswordCheckEditView.getView().findViewById(R.id.username_edit); + assertNotNull(username); + assertNotNull(username.getText()); + assertNotNull(username.getText().toString()); + assertThat(username.getText().toString(), equalTo(ANA.getDisplayUsername())); + + EditText password = mPasswordCheckEditView.getView().findViewById(R.id.password_edit); + assertNotNull(password); + assertNotNull(password.getText()); + assertNotNull(password.getText().toString()); + assertThat(password.getText().toString(), equalTo(ANA.getPassword())); + assertTrue((password.getInputType() & InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) != 0); + } + + @Test + @MediumTest + public void testSavesCredentialAndChangedPasswordInBundle() { + pollUiThread(() -> mPasswordCheckEditView != null); + + // Change the password. + final String newPassword = "NewPassword"; + EditText password = mPasswordCheckEditView.getView().findViewById(R.id.password_edit); + assertNotNull(password); + runOnUiThreadBlocking(() -> password.setText(newPassword)); + + // Save state (e.g. like happening on destruction). + Bundle bundle = new Bundle(); + mPasswordCheckEditView.onSaveInstanceState(bundle); + + // Verify the data that reconstructs the page contains all updated information. + assertTrue(bundle.containsKey(EXTRA_COMPROMISED_CREDENTIAL)); + assertTrue(bundle.containsKey(EXTRA_NEW_PASSWORD)); + assertThat(bundle.getParcelable(EXTRA_COMPROMISED_CREDENTIAL), equalTo(ANA)); + assertThat(bundle.getString(EXTRA_NEW_PASSWORD), equalTo(newPassword)); + } + + private void setUpUiLaunchedFromSettings() { + Bundle fragmentArgs = new Bundle(); + fragmentArgs.putParcelable(EXTRA_COMPROMISED_CREDENTIAL, ANA); + mTestRule.startSettingsActivity(fragmentArgs); + mPasswordCheckEditView = mTestRule.getFragment(); + } +}
diff --git a/chrome/browser/password_check/android/junit/src/org/chromium/chrome/browser/password_check/PasswordCheckControllerTest.java b/chrome/browser/password_check/android/junit/src/org/chromium/chrome/browser/password_check/PasswordCheckControllerTest.java index af4bca23..be863c3 100644 --- a/chrome/browser/password_check/android/junit/src/org/chromium/chrome/browser/password_check/PasswordCheckControllerTest.java +++ b/chrome/browser/password_check/android/junit/src/org/chromium/chrome/browser/password_check/PasswordCheckControllerTest.java
@@ -12,7 +12,9 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.notNull; import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -50,6 +52,7 @@ import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.password_check.PasswordCheckProperties.ItemType; +import org.chromium.chrome.browser.password_check.helper.PasswordCheckChangePasswordHelper; import org.chromium.chrome.browser.password_check.helper.PasswordCheckReauthenticationHelper; import org.chromium.chrome.browser.password_check.helper.PasswordCheckReauthenticationHelper.ReauthReason; import org.chromium.chrome.test.util.browser.Features; @@ -81,7 +84,7 @@ @Mock private PasswordCheckComponentUi.Delegate mDelegate; @Mock - private PasswordCheckComponentUi.ChangePasswordDelegate mChangePasswordDelegate; + private PasswordCheckChangePasswordHelper mChangePasswordDelegate; @Mock private PasswordCheck mPasswordCheck; @Mock @@ -278,6 +281,20 @@ verify(mChangePasswordDelegate).launchCctWithScript(eq(BOB)); } + @Test + public void testOnEditPasswordButtonClick() { + when(mReauthenticationHelper.canReauthenticate()).thenReturn(true); + doAnswer(invocation -> { + Callback<Boolean> cb = invocation.getArgument(1); + cb.onResult(true); + return true; + }) + .when(mReauthenticationHelper) + .reauthenticate(anyInt(), notNull()); + mMediator.onEdit(ANA); + verify(mChangePasswordDelegate).launchEditPage(eq(ANA)); + } + private void assertIdleHeader(MVCListAdapter.ListItem header) { assertHeaderTypeWithStatus(header, IDLE); assertNull(header.model.get(CHECK_PROGRESS));
diff --git a/chrome/browser/password_check/android/password_check_bridge.cc b/chrome/browser/password_check/android/password_check_bridge.cc index df92480..4a327c3 100644 --- a/chrome/browser/password_check/android/password_check_bridge.cc +++ b/chrome/browser/password_check/android/password_check_bridge.cc
@@ -51,6 +51,10 @@ check_manager_.StopCheck(); } +int64_t PasswordCheckBridge::GetLastCheckTimestamp(JNIEnv* env) { + return check_manager_.GetLastCheckTimestamp().ToJavaTime(); +} + jint PasswordCheckBridge::GetCompromisedCredentialsCount(JNIEnv* env) { return check_manager_.GetCompromisedCredentialsCount(); }
diff --git a/chrome/browser/password_check/android/password_check_bridge.h b/chrome/browser/password_check/android/password_check_bridge.h index 858ce7b3..74c74856f 100644 --- a/chrome/browser/password_check/android/password_check_bridge.h +++ b/chrome/browser/password_check/android/password_check_bridge.h
@@ -28,6 +28,9 @@ // Called by Java to stop the password check. void StopCheck(JNIEnv* env); + // Called by Java to retrieve the time when the last check finished. + int64_t GetLastCheckTimestamp(JNIEnv* env); + // Called by Java to get the number of compromised credentials. jint GetCompromisedCredentialsCount(JNIEnv* env);
diff --git a/chrome/browser/password_check/android/password_check_manager.cc b/chrome/browser/password_check/android/password_check_manager.cc index d479247..7461f821c 100644 --- a/chrome/browser/password_check/android/password_check_manager.cc +++ b/chrome/browser/password_check/android/password_check_manager.cc
@@ -16,6 +16,8 @@ #include "components/password_manager/core/browser/password_manager_util.h" #include "components/password_manager/core/browser/ui/compromised_credentials_manager.h" #include "components/password_manager/core/common/password_manager_features.h" +#include "components/password_manager/core/common/password_manager_pref_names.h" +#include "components/prefs/pref_service.h" #include "components/strings/grit/components_strings.h" #include "components/sync/driver/profile_sync_service.h" #include "components/url_formatter/url_formatter.h" @@ -92,6 +94,7 @@ // The request is being handled, so reset the boolean. was_start_requested_ = false; + is_check_running_ = true; bulk_leak_check_service_adapter_.StartBulkLeakCheck(); } @@ -99,6 +102,11 @@ bulk_leak_check_service_adapter_.StopBulkLeakCheck(); } +base::Time PasswordCheckManager::GetLastCheckTimestamp() { + return base::Time::FromDoubleT(profile_->GetPrefs()->GetDouble( + password_manager::prefs::kLastTimePasswordCheckCompleted)); +} + int PasswordCheckManager::GetCompromisedCredentialsCount() const { return compromised_credentials_manager_.GetCompromisedCredentials().size(); } @@ -157,6 +165,17 @@ } void PasswordCheckManager::OnStateChanged(State state) { + if (state == State::kIdle && is_check_running_) { + // Save the time at which the last successful check finished. + profile_->GetPrefs()->SetDouble( + password_manager::prefs::kLastTimePasswordCheckCompleted, + base::Time::Now().ToDoubleT()); + } + + if (state != State::kRunning) { + is_check_running_ = false; + } + observer_->OnPasswordCheckStatusChanged(GetUIStatus(state)); }
diff --git a/chrome/browser/password_check/android/password_check_manager.h b/chrome/browser/password_check/android/password_check_manager.h index 0985da3..bd8725f 100644 --- a/chrome/browser/password_check/android/password_check_manager.h +++ b/chrome/browser/password_check/android/password_check_manager.h
@@ -60,6 +60,9 @@ // Stops a running check. void StopCheck(); + // Called by java to retireve the timestamp of the last password check. + base::Time GetLastCheckTimestamp(); + // Called by java to retrieve the number of compromised credentials. If the // credentials haven't been fetched yet, this will return 0. int GetCompromisedCredentialsCount() const; @@ -156,6 +159,9 @@ // Whether the check start was requested. bool was_start_requested_ = false; + // Whether a check is currently running. + bool is_check_running_ = false; + // A scoped observer for `saved_passwords_presenter_`. ScopedObserver<password_manager::SavedPasswordsPresenter, password_manager::SavedPasswordsPresenter::Observer>
diff --git a/chrome/browser/password_check/android/password_check_manager_unittest.cc b/chrome/browser/password_check/android/password_check_manager_unittest.cc index f3421f2e..e5985131 100644 --- a/chrome/browser/password_check/android/password_check_manager_unittest.cc +++ b/chrome/browser/password_check/android/password_check_manager_unittest.cc
@@ -12,6 +12,7 @@ #include "base/strings/strcat.h" #include "base/strings/utf_string_conversions.h" #include "base/test/bind_test_util.h" +#include "base/time/time.h" #include "chrome/browser/password_check/android/password_check_ui_status.h" #include "chrome/browser/password_manager/bulk_leak_check_service_factory.h" #include "chrome/browser/password_manager/password_store_factory.h" @@ -19,8 +20,11 @@ #include "components/password_manager/core/browser/bulk_leak_check_service.h" #include "components/password_manager/core/browser/password_manager_test_utils.h" #include "components/password_manager/core/browser/test_password_store.h" +#include "components/password_manager/core/common/password_manager_pref_names.h" +#include "components/prefs/testing_pref_service.h" #include "components/signin/public/identity_manager/identity_manager.h" #include "components/signin/public/identity_manager/identity_test_environment.h" +#include "components/sync_preferences/testing_pref_service_syncable.h" #include "content/public/browser/browser_context.h" #include "content/public/test/browser_task_environment.h" #include "services/network/test/test_shared_url_loader_factory.h" @@ -33,6 +37,7 @@ using password_manager::CompromiseType; using password_manager::PasswordCheckUIStatus; using password_manager::TestPasswordStore; +using password_manager::prefs::kLastTimePasswordCheckCompleted; using testing::_; using testing::ElementsAre; using testing::Field; @@ -41,6 +46,7 @@ using CompromisedCredentialForUI = PasswordCheckManager::CompromisedCredentialForUI; +using State = password_manager::BulkLeakCheckService::State; namespace { @@ -169,6 +175,7 @@ void RunUntilIdle() { task_env_.RunUntilIdle(); } + BulkLeakCheckService* service() { return service_; } TestPasswordStore& store() { return *store_; } protected: @@ -176,11 +183,10 @@ std::unique_ptr<PasswordCheckManager> manager_; private: - content::BrowserTaskEnvironment task_env_{ - base::test::TaskEnvironment::TimeSource::MOCK_TIME}; + content::BrowserTaskEnvironment task_env_; signin::IdentityTestEnvironment identity_test_env_; TestingProfile profile_; - BulkLeakCheckService* bulk_leak_check_service_ = + BulkLeakCheckService* service_ = CreateAndUseBulkLeakCheckService(identity_test_env_.identity_manager(), &profile_); scoped_refptr<TestPasswordStore> store_ = @@ -264,3 +270,29 @@ "com.example.app", base::nullopt, /*is_android_credential=*/true, /*has_script=*/false))); } + +TEST_F(PasswordCheckManagerTest, SetsTimestampOnSuccessfulCheck) { + InitializeManager(); + store().AddLogin(MakeSavedPassword(kExampleCom, kUsername1)); + RunUntilIdle(); + + // Pretend to start the check so that the manager thinks a check is running. + manager_->StartCheck(); + + // Change the state to idle to simulate a successful check finish. + service()->set_state_and_notify(State::kIdle); + EXPECT_NE(0.0, manager_->GetLastCheckTimestamp().ToDoubleT()); +} + +TEST_F(PasswordCheckManagerTest, DoesntRecordTimestampOfUnsuccessfulCheck) { + InitializeManager(); + store().AddLogin(MakeSavedPassword(kExampleCom, kUsername1)); + RunUntilIdle(); + + // Pretend to start the check so that the manager thinks a check is running. + manager_->StartCheck(); + + // Change the state to an error state to simulate a unsuccessful check finish. + service()->set_state_and_notify(State::kSignedOut); + EXPECT_EQ(0.0, manager_->GetLastCheckTimestamp().ToDoubleT()); +}
diff --git a/chrome/browser/payments/android_payment_app_factory_browsertest.cc b/chrome/browser/payments/android_payment_app_factory_browsertest.cc index 76af1b1..f29dae01e 100644 --- a/chrome/browser/payments/android_payment_app_factory_browsertest.cc +++ b/chrome/browser/payments/android_payment_app_factory_browsertest.cc
@@ -25,16 +25,58 @@ base::test::ScopedFeatureList feature_list_; }; -IN_PROC_BROWSER_TEST_F(AndroidPaymentAppFactoryTest, SmokeTest) { - NavigateTo("a.com", "/app_store_billing_tests/index.html"); - ASSERT_EQ("success", content::EvalJs(GetActiveWebContents(), - content::JsReplace( - "addSupportedMethod($1)", - "https://play.google.com/billing"))); +// Even if a service worker app for app store payment method is installed, it +// should be ignored. +IN_PROC_BROWSER_TEST_F(AndroidPaymentAppFactoryTest, + IgnoreInstalledPlayBillingServiceWorker) { + NavigateTo("a.com", "/payment_handler_installer.html"); ASSERT_EQ("success", - content::EvalJs(GetActiveWebContents(), "createPaymentRequest()")); - ASSERT_EQ("false", - content::EvalJs(GetActiveWebContents(), "canMakePayment()")); + content::EvalJs(GetActiveWebContents(), + "install('alicepay.com/app1/app.js', " + "['https://play.google.com/billing'], false)")); + NavigateTo("b.com", "/can_make_payment_checker.html"); + ASSERT_EQ("false", content::EvalJs( + GetActiveWebContents(), + "canMakePayment('https://play.google.com/billing')")); +} + +// When an app store payment method app is available in a trusted web activity, +// then ignore other payment apps, since this is considered to be a digital +// goods purchase. +IN_PROC_BROWSER_TEST_F(AndroidPaymentAppFactoryTest, + IgnoreOtherPaymentAppsInTwaWhenHaveAppStoreBilling) { + std::string method_name = https_server()->GetURL("a.com", "/").spec(); + method_name = method_name.substr(0, method_name.length() - 1); + ASSERT_NE('/', method_name[method_name.length() - 1]); + NavigateTo("a.com", "/payment_handler_installer.html"); + ASSERT_EQ( + "success", + content::EvalJs( + GetActiveWebContents(), + content::JsReplace( + "install('payment_request_success_responder.js', [$1], false)", + method_name))); + + // The "payment_request_success_responder.js" always replies with "{status: + // success}", so the |response| here has to be distinct. + std::string response = "App store payment method app response for test."; + test_controller()->SetTwaPackageName("com.example.app"); + test_controller()->SetTwaPaymentApp("https://play.google.com/billing", + "{\"status\": \"" + response + "\"}"); + +#if defined(OS_CHROMEOS) + std::string expected_response = response; +#else + std::string expected_response = "success"; +#endif // OS_CHROMEOS + + NavigateTo("b.com", "/payment_handler_status.html"); + ASSERT_EQ(expected_response, + content::EvalJs( + GetActiveWebContents(), + content::JsReplace( + "getStatusList(['https://play.google.com/billing', $1])", + method_name))); } } // namespace
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_browsertest.cc b/chrome/browser/policy/cloud/user_policy_signin_service_browsertest.cc index 8ee1c223..0e6bb0d 100644 --- a/chrome/browser/policy/cloud/user_policy_signin_service_browsertest.cc +++ b/chrome/browser/policy/cloud/user_policy_signin_service_browsertest.cc
@@ -39,6 +39,8 @@ namespace { const char kTestEmail[] = "enterprise@example.com"; +const char kTestRefreshToken[] = + "test_refresh_token_for_enterprise@example.com"; // Dummy delegate forwarding all the calls the test fixture. // Owned by the DiceTurnOnSyncHelper. @@ -210,6 +212,9 @@ account_info_ = signin::MakeAccountAvailable( IdentityManagerFactory::GetForProfile(profile()), kTestEmail); + signin::SetRefreshTokenForAccount( + IdentityManagerFactory::GetForProfile(profile()), + account_info_.account_id, kTestRefreshToken); SetupFakeGaiaResponses(); } @@ -237,9 +242,8 @@ access_token_info.audience = GaiaUrls::GetInstance()->oauth2_chrome_client_id(); access_token_info.email = kTestEmail; - fake_gaia_.IssueOAuthToken( - base::StringPrintf("refresh_token_for_%s", account_info_.gaia.c_str()), - access_token_info); + fake_gaia_.IssueOAuthToken(base::StringPrintf(kTestRefreshToken), + access_token_info); } std::unique_ptr<net::test_server::HttpResponse> HandleUserInfoRequest(
diff --git a/chrome/browser/policy/messaging_layer/public/report_client.cc b/chrome/browser/policy/messaging_layer/public/report_client.cc index 348d813..8dda31d 100644 --- a/chrome/browser/policy/messaging_layer/public/report_client.cc +++ b/chrome/browser/policy/messaging_layer/public/report_client.cc
@@ -171,7 +171,7 @@ } std::vector<EncryptedRecord>* const records_; - const std::vector<const uint8_t> data_; + const std::vector<uint8_t> data_; }; Start<ProcessBlobContext>(data.ValueOrDie(), encrypted_records_.get(),
diff --git a/chrome/browser/portal/portal_browsertest.cc b/chrome/browser/portal/portal_browsertest.cc index 25cba5f..038d741 100644 --- a/chrome/browser/portal/portal_browsertest.cc +++ b/chrome/browser/portal/portal_browsertest.cc
@@ -110,6 +110,26 @@ browser()->tab_strip_model()->GetActiveWebContents(), nullptr)); } +IN_PROC_BROWSER_TEST_F( + PortalBrowserTest, + DevToolsWindowIsAttachedToOriginalWebContentsWhenActivationFails) { + ASSERT_TRUE(embedded_test_server()->Start()); + GURL url(embedded_test_server()->GetURL("/portal/portal-no-src.html")); + ui_test_utils::NavigateToURL(browser(), url); + WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents(); + DevToolsWindow* dev_tools_window = + DevToolsWindowTesting::OpenDevToolsWindowSync(browser(), true); + WebContents* main_web_contents = + DevToolsWindowTesting::Get(dev_tools_window)->main_web_contents(); + EXPECT_EQ(main_web_contents, + DevToolsWindow::GetInTabWebContents(contents, nullptr)); + + EXPECT_EQ(true, content::EvalJs(contents, "activate()")); + EXPECT_EQ(main_web_contents, + DevToolsWindow::GetInTabWebContents( + browser()->tab_strip_model()->GetActiveWebContents(), nullptr)); +} + IN_PROC_BROWSER_TEST_F(PortalBrowserTest, HttpBasicAuthenticationInPortal) { ASSERT_TRUE(embedded_test_server()->Start()); GURL url(embedded_test_server()->GetURL("/title1.html"));
diff --git a/chrome/browser/resources/chromeos/login/screen_gaia_signin.js b/chrome/browser/resources/chromeos/login/screen_gaia_signin.js index 343cc204..9d12f7f 100644 --- a/chrome/browser/resources/chromeos/login/screen_gaia_signin.js +++ b/chrome/browser/resources/chromeos/login/screen_gaia_signin.js
@@ -523,7 +523,7 @@ */ onBackButtonClicked_() { if (!this.canGoBack_()) { - if (this.childSpecificSigninFeatureEnabled_) { + if (!this.isSaml_ && this.childSpecificSigninFeatureEnabled_) { this.userActed('back'); } else { this.cancel();
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_impl_win.h b/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_impl_win.h index a34f0d7e..aab771a9 100644 --- a/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_impl_win.h +++ b/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_impl_win.h
@@ -145,7 +145,7 @@ base::Time time_scanning_started_; base::Time time_cleanup_started_; - base::ObserverList<Observer>::Unchecked observer_list_; + base::ObserverList<Observer> observer_list_; // Mutex that guards |pending_invocation_type_|, // |on_demand_sw_reporter_fetcher_| and |cached_reporter_invocations_|.
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_win.h b/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_win.h index 2ba56e22..13cc678 100644 --- a/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_win.h +++ b/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_win.h
@@ -11,6 +11,7 @@ #include "base/callback.h" #include "base/files/file_path.h" #include "base/macros.h" +#include "base/observer_list.h" #include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_scanner_results_win.h" #include "chrome/browser/safe_browsing/chrome_cleaner/sw_reporter_invocation_win.h" @@ -97,7 +98,7 @@ kDismissed, }; - class Observer { + class Observer : public base::CheckedObserver { public: virtual void OnIdle(IdleReason idle_reason) {} virtual void OnReporterRunning() {} @@ -110,9 +111,6 @@ const ChromeCleanerScannerResults& scanner_results) {} virtual void OnRebootRequired() {} virtual void OnRebootFailed() {} - - protected: - virtual ~Observer() = default; }; // Returns the global controller object.
diff --git a/chrome/browser/safe_browsing/download_protection/download_protection_util.h b/chrome/browser/safe_browsing/download_protection/download_protection_util.h index e6f29a6..0baa98a 100644 --- a/chrome/browser/safe_browsing/download_protection/download_protection_util.h +++ b/chrome/browser/safe_browsing/download_protection/download_protection_util.h
@@ -107,47 +107,34 @@ typedef base::RepeatingCallback<void(DownloadCheckResult)> CheckDownloadRepeatingCallback; -// A type of callback run on the main thread when a ClientDownloadRequest has +// Callbacks run on the main thread when a ClientDownloadRequest has // been formed for a download, or when one has not been formed for a supported // download. -typedef base::RepeatingCallback<void(download::DownloadItem*, - const ClientDownloadRequest*)> - ClientDownloadRequestCallback; +using ClientDownloadRequestCallbackList = + base::CallbackList<void(download::DownloadItem*, + const ClientDownloadRequest*)>; +using ClientDownloadRequestCallback = + ClientDownloadRequestCallbackList::CallbackType; +using ClientDownloadRequestSubscription = + std::unique_ptr<ClientDownloadRequestCallbackList::Subscription>; -// A list of ClientDownloadRequest callbacks. -typedef base::CallbackList<void(download::DownloadItem*, - const ClientDownloadRequest*)> - ClientDownloadRequestCallbackList; +// Callbacks run on the main thread when a NativeFileSystemWriteRequest has been +// formed for a write operation. +using NativeFileSystemWriteRequestCallbackList = + base::CallbackList<void(const ClientDownloadRequest*)>; +using NativeFileSystemWriteRequestCallback = + NativeFileSystemWriteRequestCallbackList::CallbackType; +using NativeFileSystemWriteRequestSubscription = + std::unique_ptr<NativeFileSystemWriteRequestCallbackList::Subscription>; -// A subscription to a registered ClientDownloadRequest callback. -typedef std::unique_ptr<ClientDownloadRequestCallbackList::Subscription> - ClientDownloadRequestSubscription; - -// A type of callback run on the main thread when a NativeFileSystemWriteRequest -// has been formed for a write operation. -typedef base::Callback<void(const ClientDownloadRequest*)> - NativeFileSystemWriteRequestCallback; - -// A list of NativeFileSystemWriteRequest callbacks. -typedef base::CallbackList<void(const ClientDownloadRequest*)> - NativeFileSystemWriteRequestCallbackList; - -// A subscription to a registered NativeFileSystemWriteRequest callback. -typedef std::unique_ptr<NativeFileSystemWriteRequestCallbackList::Subscription> - NativeFileSystemWriteRequestSubscription; - -// A type of callback run on the main thread when a PPAPI -// ClientDownloadRequest has been formed for a download. -typedef base::RepeatingCallback<void(const ClientDownloadRequest*)> - PPAPIDownloadRequestCallback; - -// A list of PPAPI ClientDownloadRequest callbacks. -typedef base::CallbackList<void(const ClientDownloadRequest*)> - PPAPIDownloadRequestCallbackList; - -// A subscription to a registered PPAPI ClientDownloadRequest callback. -typedef std::unique_ptr<PPAPIDownloadRequestCallbackList::Subscription> - PPAPIDownloadRequestSubscription; +// Callbacks run on the main thread when a PPAPI ClientDownloadRequest has been +// formed for a download. +using PPAPIDownloadRequestCallbackList = + base::CallbackList<void(const ClientDownloadRequest*)>; +using PPAPIDownloadRequestCallback = + PPAPIDownloadRequestCallbackList::CallbackType; +using PPAPIDownloadRequestSubscription = + std::unique_ptr<PPAPIDownloadRequestCallbackList::Subscription>; void RecordCountOfWhitelistedDownload(WhitelistType type);
diff --git a/chrome/browser/sharing/sharing_message_model_type_controller.cc b/chrome/browser/sharing/sharing_message_model_type_controller.cc index 9b2a352..3474430 100644 --- a/chrome/browser/sharing/sharing_message_model_type_controller.cc +++ b/chrome/browser/sharing/sharing_message_model_type_controller.cc
@@ -33,10 +33,7 @@ syncer::DataTypeController::PreconditionState SharingMessageModelTypeController::GetPreconditionState() const { DCHECK(CalledOnValidThread()); - if (syncer::IsWebSignout(sync_service_->GetAuthError())) { - return PreconditionState::kMustStopAndClearData; - } - if (sync_service_->GetBackedOffDataTypes().Has(syncer::SHARING_MESSAGE)) { + if (sync_service_->GetAuthError().IsPersistentError()) { return PreconditionState::kMustStopAndClearData; } return PreconditionState::kPreconditionsMet;
diff --git a/chrome/browser/sync/test/integration/single_client_sharing_message_sync_test.cc b/chrome/browser/sync/test/integration/single_client_sharing_message_sync_test.cc index 0316c80..a2aa380b 100644 --- a/chrome/browser/sync/test/integration/single_client_sharing_message_sync_test.cc +++ b/chrome/browser/sync/test/integration/single_client_sharing_message_sync_test.cc
@@ -5,17 +5,36 @@ #include <vector> #include "base/test/mock_callback.h" +#include "base/test/scoped_feature_list.h" +#include "chrome/browser/sharing/features.h" #include "chrome/browser/sharing/sharing_message_bridge.h" #include "chrome/browser/sharing/sharing_message_bridge_factory.h" #include "chrome/browser/sync/test/integration/profile_sync_service_harness.h" #include "chrome/browser/sync/test/integration/single_client_status_change_checker.h" #include "chrome/browser/sync/test/integration/sync_test.h" +#include "components/sync/driver/sync_token_status.h" #include "components/sync/test/fake_server/fake_server_http_post_provider.h" #include "content/public/test/browser_test.h" namespace { using sync_pb::SharingMessageSpecifics; +using testing::_; + +constexpr char kEmptyOAuth2Token[] = ""; + +constexpr char kInvalidGrantOAuth2Token[] = R"( + { + "error": "invalid_grant" + })"; + +constexpr char kValidOAuth2Token[] = R"( + { + "refresh_token": "new_refresh_token", + "access_token": "new_access_token", + "expires_in": 3600, // 1 hour. + "token_type": "Bearer" + })"; MATCHER_P(HasErrorCode, expected_error_code, "") { return arg.error_code() == expected_error_code; @@ -43,13 +62,26 @@ base::Time last_synced_time_; }; -class BackedOffSharingMessageChecker : public SingleClientStatusChangeChecker { +class DisabledSharingMessageChecker : public SingleClientStatusChangeChecker { public: - explicit BackedOffSharingMessageChecker(syncer::ProfileSyncService* service) + explicit DisabledSharingMessageChecker(syncer::ProfileSyncService* service) : SingleClientStatusChangeChecker(service) {} bool IsExitConditionSatisfied(std::ostream* os) override { - return service()->GetBackedOffDataTypes().Has(syncer::SHARING_MESSAGE); + *os << "Waiting for disabled SHARING_MESSAGE data type"; + return !service()->GetActiveDataTypes().Has(syncer::SHARING_MESSAGE); + } +}; + +class RetryingAccessTokenFetchChecker : public SingleClientStatusChangeChecker { + public: + explicit RetryingAccessTokenFetchChecker(syncer::ProfileSyncService* service) + : SingleClientStatusChangeChecker(service) {} + + // StatusChangeChecker implementation. + bool IsExitConditionSatisfied(std::ostream* os) override { + *os << "Waiting for auth error"; + return service()->IsRetryingAccessTokenFetchForTest(); } }; @@ -106,6 +138,11 @@ public: SingleClientSharingMessageSyncTest() : SyncTest(SINGLE_CLIENT) { DisableVerifier(); + // Replace the default value (5 seconds) with 1 minute to reduce possibility + // of test flakiness. + feature_list_.InitAndEnableFeatureWithParameters( + kSharingMessageBridgeTimeout, + {{"SharingMessageBridgeTimeoutSeconds", "60"}}); } bool WaitForSharingMessage( @@ -193,39 +230,6 @@ } IN_PROC_BROWSER_TEST_F(SingleClientSharingMessageSyncTest, - ShouldStopDataTypeWhenBackedOff) { - base::MockRepeatingCallback<void(const sync_pb::SharingMessageCommitError&)> - callback; - - ASSERT_TRUE(SetupSync()); - SharingMessageBridge* sharing_message_bridge = - SharingMessageBridgeFactory::GetForBrowserContext(GetProfile(0)); - SharingMessageSpecifics specifics; - specifics.set_payload("payload"); - sharing_message_bridge->SendSharingMessage( - std::make_unique<SharingMessageSpecifics>(specifics), callback.Get()); - - EXPECT_CALL( - callback, - Run(HasErrorCode(sync_pb::SharingMessageCommitError::SYNC_TURNED_OFF))); - ASSERT_FALSE( - GetSyncService(0)->GetBackedOffDataTypes().Has(syncer::SHARING_MESSAGE)); - - // Run the data type into backed off state before the message gets sent. - fake_server::FakeServerHttpPostProvider::DisableNetwork(); - - ASSERT_TRUE(BackedOffSharingMessageChecker(GetSyncService(0)).Wait()); - - EXPECT_TRUE( - GetSyncService(0)->GetBackedOffDataTypes().Has(syncer::SHARING_MESSAGE)); - EXPECT_CALL( - callback, - Run(HasErrorCode(sync_pb::SharingMessageCommitError::SYNC_TURNED_OFF))); - sharing_message_bridge->SendSharingMessage( - std::make_unique<SharingMessageSpecifics>(specifics), callback.Get()); -} - -IN_PROC_BROWSER_TEST_F(SingleClientSharingMessageSyncTest, ShouldCleanPendingMessagesAfterSyncPaused) { base::MockOnceCallback<void(const sync_pb::SharingMessageCommitError&)> callback; @@ -242,32 +246,6 @@ sharing_message_bridge->SendSharingMessage( std::make_unique<SharingMessageSpecifics>(specifics), callback.Get()); - GetClient(0)->StopSyncServiceWithoutClearingData(); - GetClient(0)->StartSyncService(); - ASSERT_TRUE(NextCycleIterationChecker(GetSyncService(0)).Wait()); - - EXPECT_TRUE(GetFakeServer() - ->GetSyncEntitiesByModelType(syncer::SHARING_MESSAGE) - .empty()); -} - -IN_PROC_BROWSER_TEST_F(SingleClientSharingMessageSyncTest, - ShouldCleanPendingMessagesAfterSyncTurnedOff) { - base::MockOnceCallback<void(const sync_pb::SharingMessageCommitError&)> - callback; - EXPECT_CALL( - callback, - Run(HasErrorCode(sync_pb::SharingMessageCommitError::SYNC_TURNED_OFF))); - - ASSERT_TRUE(SetupSync()); - - SharingMessageBridge* sharing_message_bridge = - SharingMessageBridgeFactory::GetForBrowserContext(GetProfile(0)); - SharingMessageSpecifics specifics; - specifics.set_payload("payload"); - sharing_message_bridge->SendSharingMessage( - std::make_unique<SharingMessageSpecifics>(specifics), callback.Get()); - GetClient(0)->StopSyncServiceAndClearData(); GetClient(0)->StartSyncService(); ASSERT_TRUE(NextCycleIterationChecker(GetSyncService(0)).Wait()); @@ -277,4 +255,55 @@ .empty()); } +IN_PROC_BROWSER_TEST_F( + SingleClientSharingMessageSyncTest, + ShouldTurnOffSharingMessageDataTypeOnPersistentAuthError) { + ASSERT_TRUE(SetupSync()); + GetFakeServer()->SetHttpError(net::HTTP_UNAUTHORIZED); + SetOAuth2TokenResponse(kInvalidGrantOAuth2Token, net::HTTP_BAD_REQUEST, + net::OK); + + base::MockOnceCallback<void(const sync_pb::SharingMessageCommitError&)> + callback; + EXPECT_CALL( + callback, + Run(HasErrorCode(sync_pb::SharingMessageCommitError::SYNC_TURNED_OFF))); + + SharingMessageBridge* sharing_message_bridge = + SharingMessageBridgeFactory::GetForBrowserContext(GetProfile(0)); + SharingMessageSpecifics specifics; + specifics.set_payload("payload"); + sharing_message_bridge->SendSharingMessage( + std::make_unique<SharingMessageSpecifics>(specifics), callback.Get()); + + EXPECT_TRUE(DisabledSharingMessageChecker(GetSyncService(0)).Wait()); +} + +IN_PROC_BROWSER_TEST_F( + SingleClientSharingMessageSyncTest, + ShouldRetrySendingSharingMessageDataTypeOnTransientAuthError) { + ASSERT_TRUE(SetupSync()); + GetFakeServer()->SetHttpError(net::HTTP_UNAUTHORIZED); + SetOAuth2TokenResponse(kEmptyOAuth2Token, net::HTTP_INTERNAL_SERVER_ERROR, + net::OK); + + base::MockOnceCallback<void(const sync_pb::SharingMessageCommitError&)> + callback; + EXPECT_CALL(callback, + Run(HasErrorCode(sync_pb::SharingMessageCommitError::NONE))); + + SharingMessageBridge* sharing_message_bridge = + SharingMessageBridgeFactory::GetForBrowserContext(GetProfile(0)); + SharingMessageSpecifics specifics; + specifics.set_payload("payload"); + sharing_message_bridge->SendSharingMessage( + std::make_unique<SharingMessageSpecifics>(specifics), callback.Get()); + + ASSERT_TRUE(RetryingAccessTokenFetchChecker(GetSyncService(0)).Wait()); + GetFakeServer()->ClearHttpError(); + SetOAuth2TokenResponse(kValidOAuth2Token, net::HTTP_OK, net::OK); + + EXPECT_TRUE(WaitForSharingMessage({specifics})); +} + } // namespace
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd index 0a2a2db..b4ed2d8 100644 --- a/chrome/browser/ui/android/strings/android_chrome_strings.grd +++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -3354,6 +3354,9 @@ <message name="IDS_TWA_QUALITY_ENFORCEMENT_VIOLATION_ERROR" desc="Text shown on a toast when TWA violation 404."> <ph name="ERROR_CODE">%1$s<ex>404</ex></ph> on <ph name="VIOLATED_URL">%2$s<ex>https://example.com/</ex></ph> </message> + <message name="IDS_TWA_QUALITY_ENFORCEMENT_VIOLATION_ASSERT_LINK" desc="Text shown on a toast when TWA violate the quality enforcement criteria: digital assert link verification failed."> + Digital assert links verification failed on <ph name="VIOLATED_URL">%1$s<ex>https://example.com/</ex></ph> + </message> <message name="IDS_TWA_QUALITY_ENFORCEMENT_VIOLATION_OFFLINE" desc="Text shown on a toast when TWA violate the quality enforcement criteria: page unavailable offline."> Page unavailable offline: <ph name="VIOLATED_URL">%1$s<ex>https://example.com/</ex></ph> </message>
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_TWA_QUALITY_ENFORCEMENT_VIOLATION_ASSERT_LINK.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_TWA_QUALITY_ENFORCEMENT_VIOLATION_ASSERT_LINK.png.sha1 new file mode 100644 index 0000000..b083392 --- /dev/null +++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_TWA_QUALITY_ENFORCEMENT_VIOLATION_ASSERT_LINK.png.sha1
@@ -0,0 +1 @@ +2c71d89861d1abe6c3c2d571702bd360e75ba7cd \ No newline at end of file
diff --git a/chrome/browser/ui/ash/test_login_screen_model.cc b/chrome/browser/ui/ash/test_login_screen_model.cc index e6e168f..299d990 100644 --- a/chrome/browser/ui/ash/test_login_screen_model.cc +++ b/chrome/browser/ui/ash/test_login_screen_model.cc
@@ -22,6 +22,9 @@ void TestLoginScreenModel::DisableAuthForUser( const AccountId& account_id, const ash::AuthDisabledData& auth_disabled_data) {} +void TestLoginScreenModel::SetTpmLockedState(const AccountId& user, + bool is_locked, + base::TimeDelta time_left) {} void TestLoginScreenModel::SetTapToUnlockEnabledForUser( const AccountId& account_id, bool enabled) {}
diff --git a/chrome/browser/ui/ash/test_login_screen_model.h b/chrome/browser/ui/ash/test_login_screen_model.h index 5991cc1e..0b438bc 100644 --- a/chrome/browser/ui/ash/test_login_screen_model.h +++ b/chrome/browser/ui/ash/test_login_screen_model.h
@@ -27,6 +27,9 @@ void DisableAuthForUser( const AccountId& account_id, const ash::AuthDisabledData& auth_disabled_data) override; + void SetTpmLockedState(const AccountId& user, + bool is_locked, + base::TimeDelta time_left) override; void SetTapToUnlockEnabledForUser(const AccountId& account_id, bool enabled) override; void ForceOnlineSignInForUser(const AccountId& account_id) override;
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc index e73a8a97..e1e2225 100644 --- a/chrome/browser/ui/browser.cc +++ b/chrome/browser/ui/browser.cc
@@ -1491,6 +1491,20 @@ return SwapWebContents(predecessor_contents, std::move(portal_contents)); } +void Browser::UpdateInspectedWebContentsIfNecessary( + content::WebContents* old_contents, + content::WebContents* new_contents, + base::OnceCallback<void()> callback) { + DevToolsWindow* dev_tools_window = + DevToolsWindow::GetInstanceForInspectedWebContents(old_contents); + if (dev_tools_window) { + dev_tools_window->UpdateInspectedWebContents(new_contents, + std::move(callback)); + } else { + std::move(callback).Run(); + } +} + std::unique_ptr<content::WebContents> Browser::SwapWebContents( content::WebContents* old_contents, std::unique_ptr<content::WebContents> new_contents) { @@ -1506,11 +1520,6 @@ new_view->TakeFallbackContentFrom(old_view); } - DevToolsWindow* dev_tools_window = - DevToolsWindow::GetInstanceForInspectedWebContents(old_contents); - if (dev_tools_window) - dev_tools_window->UpdateInspectedWebContents(new_contents.get()); - // TODO(crbug.com/836409): TabLoadTracker should not rely on being notified // directly about tab contents swaps. resource_coordinator::TabLoadTracker::Get()->SwapTabContents(
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h index 7705113..5ad265fb 100644 --- a/chrome/browser/ui/browser.h +++ b/chrome/browser/ui/browser.h
@@ -611,6 +611,10 @@ std::unique_ptr<content::WebContents> ActivatePortalWebContents( content::WebContents* predecessor_contents, std::unique_ptr<content::WebContents> portal_contents) override; + void UpdateInspectedWebContentsIfNecessary( + content::WebContents* old_contents, + content::WebContents* new_contents, + base::OnceCallback<void()> callback) override; bool ShouldShowStaleContentOnEviction(content::WebContents* source) override; bool IsFrameLowPriority( const content::WebContents* web_contents,
diff --git a/chrome/browser/ui/omnibox/omnibox_pedals_unittest.cc b/chrome/browser/ui/omnibox/omnibox_pedals_unittest.cc index 68c4c27..48eeb9be 100644 --- a/chrome/browser/ui/omnibox/omnibox_pedals_unittest.cc +++ b/chrome/browser/ui/omnibox/omnibox_pedals_unittest.cc
@@ -25,12 +25,20 @@ }; const TestCase test_cases[] = { // clang-format off - {"am", "ሰርዝ ታሪክ"}, - {"de", "leeren cache"}, - {"en", "clear history"}, - {"fr", "supprime historique"}, - {"ja", "消す 履歴"}, - {"zh-CN", "清除 数据"}, + // Test cases generated by pedal_processor: + {"am", "አስወግድ መሸጎጫ"}, + {"ar", "إزالة ذاكرة التخزين المؤقت"}, + {"bg", "премахване"}, + {"bn", "মিটিয়ে দিন ক্যাশে ফাইল"}, + {"ca", "suprimeix memòria cau"}, + {"cs", "odstranit soubory cookie"}, + {"da", "fjern browseroplysninger"}, + {"de", "entfernen browserverlauf"}, + {"el", "εκκαθάριση πληροφορίες"}, + {"en", "delete information"}, + {"fr", "suppression informations"}, + {"ja", "クリアキャッシュ"}, + {"zh-CN", "清除浏览数据"}, // clang-format on }; for (const TestCase& test_case : test_cases) {
diff --git a/chrome/browser/ui/passwords/well_known_change_password_navigation_throttle.cc b/chrome/browser/ui/passwords/well_known_change_password_navigation_throttle.cc index 8a43ce8..9a4b8a32 100644 --- a/chrome/browser/ui/passwords/well_known_change_password_navigation_throttle.cc +++ b/chrome/browser/ui/passwords/well_known_change_password_navigation_throttle.cc
@@ -16,10 +16,7 @@ #include "content/public/browser/storage_partition.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_user_data.h" -#include "net/base/load_flags.h" -#include "net/http/http_status_code.h" #include "services/network/public/cpp/shared_url_loader_factory.h" -#include "services/network/public/cpp/simple_url_loader.h" #include "url/gurl.h" #include "url/origin.h" @@ -28,10 +25,8 @@ using content::NavigationHandle; using content::NavigationThrottle; using content::WebContents; -using password_manager::CreateWellKnownNonExistingResourceURL; using password_manager::IsWellKnownChangePasswordUrl; -using password_manager::kWellKnownChangePasswordPath; -using password_manager::kWellKnownNotExistingResourcePath; +using password_manager::WellKnownChangePasswordState; // Used to scope the posted navigation task to the lifetime of |web_contents|. class WebContentsLifetimeHelper @@ -93,75 +88,49 @@ NavigationThrottle::ThrottleCheckResult WellKnownChangePasswordNavigationThrottle::WillStartRequest() { - FetchNonExistingResource(navigation_handle()); + auto url_loader_factory = + content::BrowserContext::GetDefaultStoragePartition( + navigation_handle()->GetWebContents()->GetBrowserContext()) + ->GetURLLoaderFactoryForBrowserProcess(); + well_known_change_password_state_.FetchNonExistingResource( + url_loader_factory.get(), navigation_handle()->GetURL()); return NavigationThrottle::PROCEED; } NavigationThrottle::ThrottleCheckResult WellKnownChangePasswordNavigationThrottle::WillFailRequest() { - url_loader_.reset(); return NavigationThrottle::PROCEED; } NavigationThrottle::ThrottleCheckResult WellKnownChangePasswordNavigationThrottle::WillProcessResponse() { - change_password_response_code_ = - navigation_handle()->GetResponseHeaders()->response_code(); - return BothRequestsFinished() ? ContinueProcessing() - : NavigationThrottle::DEFER; + // PostTask because the Throttle needs to be deferred before the status code + // is set. After setting the status code Resume() can be called synchronous + // and thereby before the throttle is deferred. This would result in a crash. + // Unretained is safe because the NavigationThrottle is deferred and can only + // be continued after the callback finished. + base::SequencedTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce( + &WellKnownChangePasswordState::SetChangePasswordResponseCode, + base::Unretained(&well_known_change_password_state_), + navigation_handle()->GetResponseHeaders()->response_code())); + return NavigationThrottle::DEFER; } const char* WellKnownChangePasswordNavigationThrottle::GetNameForLogging() { return "WellKnownChangePasswordNavigationThrottle"; } -void WellKnownChangePasswordNavigationThrottle::FetchNonExistingResource( - NavigationHandle* handle) { - auto url_loader_factory = content::BrowserContext::GetDefaultStoragePartition( - handle->GetWebContents()->GetBrowserContext()) - ->GetURLLoaderFactoryForBrowserProcess(); - url_loader_ = - password_manager::CreateResourceRequestToWellKnownNonExistingResourceFor( - handle->GetURL()); - // Binding the callback to |this| is safe, because the navigationthrottle - // defers if the request is not received yet. Thereby the throttle still exist - // when the response arrives. - url_loader_->DownloadHeadersOnly( - url_loader_factory.get(), - base::BindOnce(&WellKnownChangePasswordNavigationThrottle:: - FetchNonExistingResourceCallback, - base::Unretained(this))); -} - -void WellKnownChangePasswordNavigationThrottle:: - FetchNonExistingResourceCallback( - scoped_refptr<net::HttpResponseHeaders> headers) { - if (!headers) { - non_existing_resource_response_code_ = -1; - return; - } - non_existing_resource_response_code_ = headers->response_code(); - if (BothRequestsFinished()) { - ThrottleAction action = ContinueProcessing(); - if (action == NavigationThrottle::PROCEED) { - Resume(); - } else if (action == NavigationThrottle::CANCEL) { - CancelDeferredNavigation(NavigationThrottle::CANCEL); - } - } -} - -NavigationThrottle::ThrottleAction -WellKnownChangePasswordNavigationThrottle::ContinueProcessing() { - DCHECK(BothRequestsFinished()); - if (SupportsChangePasswordUrl()) { - return NavigationThrottle::PROCEED; +void WellKnownChangePasswordNavigationThrottle::OnProcessingFinished( + bool is_supported) { + if (is_supported) { + Resume(); } else { - // Redirect call creates PostTask GURL url = navigation_handle()->GetURL(); GURL redirect_url = change_password_url_service_->GetChangePasswordUrl(url); Redirect(redirect_url.is_valid() ? redirect_url : url.GetOrigin()); - return NavigationThrottle::CANCEL; + CancelDeferredNavigation(NavigationThrottle::CANCEL); } } @@ -183,15 +152,3 @@ helper->GetWeakPtr(), std::move(params))); } -bool WellKnownChangePasswordNavigationThrottle::BothRequestsFinished() const { - return non_existing_resource_response_code_ != 0 && - change_password_response_code_ != 0; -} - -bool WellKnownChangePasswordNavigationThrottle::SupportsChangePasswordUrl() - const { - DCHECK(BothRequestsFinished()); - return 200 <= change_password_response_code_ && - change_password_response_code_ < 300 && - non_existing_resource_response_code_ == net::HTTP_NOT_FOUND; -}
diff --git a/chrome/browser/ui/passwords/well_known_change_password_navigation_throttle.h b/chrome/browser/ui/passwords/well_known_change_password_navigation_throttle.h index 89e83dd..5e23313 100644 --- a/chrome/browser/ui/passwords/well_known_change_password_navigation_throttle.h +++ b/chrome/browser/ui/passwords/well_known_change_password_navigation_throttle.h
@@ -9,18 +9,13 @@ #include "content/public/browser/navigation_throttle.h" +#include "components/password_manager/core/browser/well_known_change_password_state.h" + class GURL; namespace content { class NavigationHandle; } // namespace content -namespace net { -class HttpResponseHeaders; -} // namespace net - -namespace network { -class SimpleURLLoader; -} // namespace network namespace password_manager { class ChangePasswordUrlService; @@ -34,7 +29,8 @@ // support the change password url, the user gets redirected to the base path // '/'. class WellKnownChangePasswordNavigationThrottle - : public content::NavigationThrottle { + : public content::NavigationThrottle, + public password_manager::WellKnownChangePasswordStateDelegate { public: ~WellKnownChangePasswordNavigationThrottle() override; @@ -52,24 +48,13 @@ private: explicit WellKnownChangePasswordNavigationThrottle( content::NavigationHandle* handle); - // Request the status code from a path that is expected to return 404. - void FetchNonExistingResource(content::NavigationHandle* handle); - // Callback for the request to the "not exist" path. - void FetchNonExistingResourceCallback( - scoped_refptr<net::HttpResponseHeaders> headers); - // Function is called when both requests are finished. Decides to continue or - // redirect to homepage. - ThrottleAction ContinueProcessing(); + // password_manager::WellKnownChangePasswordStateDelegate: + void OnProcessingFinished(bool is_supported) override; // Redirects to a given URL in the same tab. void Redirect(const GURL& url); - // Checks if both requests are finished. - bool BothRequestsFinished() const; - // Checks the status codes and returns if change password is supported. - bool SupportsChangePasswordUrl() const; - int non_existing_resource_response_code_ = 0; - int change_password_response_code_ = 0; - std::unique_ptr<network::SimpleURLLoader> url_loader_; + password_manager::WellKnownChangePasswordState + well_known_change_password_state_{this}; password_manager::ChangePasswordUrlService* change_password_url_service_; };
diff --git a/chrome/browser/ui/views/session_crashed_bubble_view.cc b/chrome/browser/ui/views/session_crashed_bubble_view.cc index 211c16b2..4330e2e 100644 --- a/chrome/browser/ui/views/session_crashed_bubble_view.cc +++ b/chrome/browser/ui/views/session_crashed_bubble_view.cc
@@ -254,8 +254,8 @@ gfx::Range after_link_range(offset + link_text.length(), uma_text.length()); if (!after_link_range.is_empty()) uma_label->AddStyleRange(after_link_range, uma_style); - // Shift the text down by 1px to align with the checkbox. - uma_label->SetBorder(views::CreateEmptyBorder(1, 0, 0, 0)); + // Shift the text down by 3px to align with the checkbox. + uma_label->SetBorder(views::CreateEmptyBorder(3, 0, 0, 0)); // Checkbox for metric reporting setting. auto uma_option = std::make_unique<views::Checkbox>(base::string16()); @@ -276,7 +276,7 @@ ChromeLayoutProvider::Get()->GetDistanceMetric( views::DISTANCE_RELATED_LABEL_HORIZONTAL)); cs->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1.0, - views::GridLayout::ColumnSize::kUsePreferred, 0, 0); + views::GridLayout::ColumnSize::kFixed, 0, 0); uma_layout->StartRow(views::GridLayout::kFixedSize, kReportColumnSetId); uma_option_ = uma_layout->AddView(std::move(uma_option));
diff --git a/chrome/browser/ui/webui/chromeos/login/user_board_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/user_board_screen_handler.cc index e4b7d64..e11e262c 100644 --- a/chrome/browser/ui/webui/chromeos/login/user_board_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/user_board_screen_handler.cc
@@ -94,6 +94,10 @@ static_cast<int>(auth_type), base::Value(initial_value)); } +void UserBoardScreenHandler::SetTpmLockedState(const AccountId& account_id, + bool is_locked, + base::TimeDelta time_left) {} + void UserBoardScreenHandler::Bind(UserSelectionScreen* screen) { screen_ = screen; SetBaseScreen(screen_);
diff --git a/chrome/browser/ui/webui/chromeos/login/user_board_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/user_board_screen_handler.h index 8aadb91..247a174 100644 --- a/chrome/browser/ui/webui/chromeos/login/user_board_screen_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/user_board_screen_handler.h
@@ -58,6 +58,10 @@ void SetAuthType(const AccountId& account_id, proximity_auth::mojom::AuthType auth_type, const base::string16& initial_value) override; + void SetTpmLockedState(const AccountId& account_id, + bool is_locked, + base::TimeDelta time_left) override; + void Bind(UserSelectionScreen* screen) override; void Unbind() override; base::WeakPtr<UserBoardView> GetWeakPtr() override;
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt index 92243517..72cd91d5 100644 --- a/chrome/build/mac.pgo.txt +++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@ -chrome-mac-master-1597574780-11032f77f0853e1d71f33728c0242d630bf5af1f.profdata +chrome-mac-master-1597665194-0d53ac1a851921d9b7ac1e88ae497b998bf9af0d.profdata
diff --git a/chrome/common/extensions/api/file_manager_private.idl b/chrome/common/extensions/api/file_manager_private.idl index 4e23be6..5bcd169 100644 --- a/chrome/common/extensions/api/file_manager_private.idl +++ b/chrome/common/extensions/api/file_manager_private.idl
@@ -942,27 +942,27 @@ static void getFileTasks([instanceof=Entry] object[] entries, GetFileTasksCallback callback); - // Gets the MIME type of a file. - // |entry| Entry to be checked. + // Gets the MIME type of an entry. + // |entry| The entry to be checked. // |callback| [nocompile] static void getMimeType([instanceof=Entry] object entry, GetMimeTypeCallback callback); // Gets the content sniffed MIME type of a file. - // |fileBlob| Blob created from the file. + // |fileEntry| The file entry to be checked. // |callback| [nocompile] - static void getContentMimeType([instanceof=Blob] object fileBlob, + static void getContentMimeType([instanceof=FileEntry] object fileEntry, GetContentMimeTypeCallback callback); // Gets metadata from an Audio or Video file. - // |fileBlob| Blob created from the file. + // |fileEntry| The file entry to be checked. // |mimeType| Content sniffed mimeType of the file. // |type| Content metadata type to extact. // |callback| [nocompile] - static void getContentMetadata([instanceof=Blob] object fileBlob, + static void getContentMetadata([instanceof=FileEntry] object fileEntry, DOMString mimeType, ContentMetadataType type, GetContentMetadataCallback callback);
diff --git a/chrome/renderer/resources/extensions/file_manager_private_custom_bindings.js b/chrome/renderer/resources/extensions/file_manager_private_custom_bindings.js index f10ddea..b27f6ff5 100644 --- a/chrome/renderer/resources/extensions/file_manager_private_custom_bindings.js +++ b/chrome/renderer/resources/extensions/file_manager_private_custom_bindings.js
@@ -119,36 +119,61 @@ }); apiFunctions.setHandleRequest('getContentMimeType', - function(fileBlob, callback) { - var uuid = blobNatives.GetBlobUuid(fileBlob); + function(fileEntry, callback) { + fileEntry.file(blob => { + var blobUUID = blobNatives.GetBlobUuid(blob); - if (!fileBlob || !fileBlob.size) { - callback(undefined); - return; - } + if (!blob || !blob.size) { + callback(undefined); + return; + } - var onGetContentMimeType = function(blob, mimeType) { - callback(mimeType ? mimeType : undefined); - }.bind(this, fileBlob); // Bind a blob reference: crbug.com/415792#c12 + var onGetContentMimeType = function(blob, mimeType) { + callback(mimeType ? mimeType : undefined); + }.bind(this, blob); // Bind a blob reference: crbug.com/415792#c12 - fileManagerPrivateInternal.getContentMimeType(uuid, onGetContentMimeType); + fileManagerPrivateInternal.getContentMimeType( + blobUUID, onGetContentMimeType); + }, (error) => { + var errorUUID = ''; + + var onGetContentMimeType = function() { + chrome.runtime.lastError.DOMError = /** @type {!DOMError} */ (error); + callback(undefined); + }.bind(this); + + fileManagerPrivateInternal.getContentMimeType( + errorUUID, onGetContentMimeType); + }); }); apiFunctions.setHandleRequest('getContentMetadata', - function(fileBlob, mimeType, type, callback) { - var uuid = blobNatives.GetBlobUuid(fileBlob); + function(fileEntry, mimeType, type, callback) { + fileEntry.file(blob => { + var blobUUID = blobNatives.GetBlobUuid(blob); - if (!fileBlob || !fileBlob.size) { - callback(undefined); - return; - } + if (!blob || !blob.size) { + callback(undefined); + return; + } - var onGetContentMetadata = function(blob, metadata) { - callback(metadata ? metadata : undefined); - }.bind(this, fileBlob); // Bind a blob reference: crbug.com/415792#c12 + var onGetContentMetadata = function(blob, metadata) { + callback(metadata ? metadata : undefined); + }.bind(this, blob); // Bind a blob reference: crbug.com/415792#c12 - fileManagerPrivateInternal.getContentMetadata( - uuid, mimeType, type, onGetContentMetadata); + fileManagerPrivateInternal.getContentMetadata( + blobUUID, mimeType, type, onGetContentMetadata); + }, (error) => { + var errorUUID = ''; + + var onGetContentMetadata = function() { + chrome.runtime.lastError.DOMError = /** @type {!DOMError} */ (error); + callback(undefined); + }.bind(this); + + fileManagerPrivateInternal.getContentMetadata( + errorUUID, mimeType, type, onGetContentMetadata); + }); }); apiFunctions.setHandleRequest('pinDriveFile', function(entry, pin, callback) {
diff --git a/chrome/services/sharing/nearby/nearby_connections.cc b/chrome/services/sharing/nearby/nearby_connections.cc index 06c702f..de77722 100644 --- a/chrome/services/sharing/nearby/nearby_connections.cc +++ b/chrome/services/sharing/nearby/nearby_connections.cc
@@ -337,6 +337,10 @@ ResultCallbackFromMojom(std::move(callback))); } +void NearbyConnections::StopAllEndpoints(StopAllEndpointsCallback callback) { + core_->StopAllEndpoints(ResultCallbackFromMojom(std::move(callback))); +} + base::File NearbyConnections::ExtractFileForPayload(int64_t payload_id) { auto file_it = outgoing_file_map_.find(payload_id); if (file_it == outgoing_file_map_.end())
diff --git a/chrome/services/sharing/nearby/nearby_connections.h b/chrome/services/sharing/nearby/nearby_connections.h index 0fd61af0..3ab57c79 100644 --- a/chrome/services/sharing/nearby/nearby_connections.h +++ b/chrome/services/sharing/nearby/nearby_connections.h
@@ -93,6 +93,7 @@ SendPayloadCallback callback) override; void CancelPayload(int64_t payload_id, CancelPayloadCallback callback) override; + void StopAllEndpoints(StopAllEndpointsCallback callback) override; // Return the file associated with |payload_id|. base::File ExtractFileForPayload(int64_t payload_id);
diff --git a/chrome/services/sharing/nearby/nearby_connections_unittest.cc b/chrome/services/sharing/nearby/nearby_connections_unittest.cc index c8114bb7..41d4a09d 100644 --- a/chrome/services/sharing/nearby/nearby_connections_unittest.cc +++ b/chrome/services/sharing/nearby/nearby_connections_unittest.cc
@@ -14,6 +14,7 @@ #include "base/files/file_util.h" #include "base/memory/ptr_util.h" #include "base/run_loop.h" +#include "base/strings/string_number_conversions.h" #include "base/test/bind_test_util.h" #include "base/test/task_environment.h" #include "chrome/services/sharing/nearby/nearby_connections_conversions.h" @@ -53,6 +54,21 @@ /*enforce_topology_constraints=*/true); } +struct EndpointData { + std::string remote_endpoint_id; + std::vector<uint8_t> remote_endpoint_info; +}; + +const EndpointData CreateEndpointData(int suffix) { + EndpointData endpoint_data; + endpoint_data.remote_endpoint_id = + kRemoteEndpointId + base::NumberToString(suffix); + endpoint_data.remote_endpoint_info = std::vector<uint8_t>( + std::begin(kRemoteEndpointInfo), std::end(kRemoteEndpointInfo)); + endpoint_data.remote_endpoint_info.push_back(suffix); + return endpoint_data; +} + } // namespace class FakeEndpointDiscoveryListener : public mojom::EndpointDiscoveryListener { @@ -127,6 +143,9 @@ payload_progress_cb = base::DoNothing(); }; +using ::testing::_; +using ::testing::Return; + class NearbyConnectionsTest : public testing::Test { public: NearbyConnectionsTest() { @@ -182,14 +201,14 @@ } ClientProxy* RequestConnection( - FakeConnectionLifecycleListener& fake_connection_life_cycle_listener) { + FakeConnectionLifecycleListener& fake_connection_life_cycle_listener, + const EndpointData& endpoint_data) { ClientProxy* client_proxy; EXPECT_CALL(*service_controller_ptr_, RequestConnection) - .WillOnce([&client_proxy](ClientProxy* client, - const std::string& endpoint_id, - const ConnectionRequestInfo& info) { + .WillOnce([&](ClientProxy* client, const std::string& endpoint_id, + const ConnectionRequestInfo& info) { client_proxy = client; - EXPECT_EQ(kRemoteEndpointId, endpoint_id); + EXPECT_EQ(endpoint_data.remote_endpoint_id, endpoint_id); EXPECT_EQ( std::string(std::begin(kEndpointInfo), std::end(kEndpointInfo)), info.name); @@ -198,8 +217,9 @@ {.authentication_token = kAuthenticationToken, .raw_authentication_token = ByteArray( kRawAuthenticationToken, sizeof(kRawAuthenticationToken)), - .endpoint_info = - ByteArray(kRemoteEndpointInfo, sizeof(kRemoteEndpointInfo)), + .endpoint_info = ByteArray( + std::string(endpoint_data.remote_endpoint_info.begin(), + endpoint_data.remote_endpoint_info.end())), .is_incoming_connection = false}, info.listener); return Status{Status::kSuccess}; @@ -209,7 +229,7 @@ nearby_connections_->RequestConnection( std::vector<uint8_t>(std::begin(kEndpointInfo), std::end(kEndpointInfo)), - kRemoteEndpointId, + endpoint_data.remote_endpoint_id, fake_connection_life_cycle_listener.receiver.BindNewPipeAndPassRemote(), base::BindLambdaForTesting([&](mojom::Status status) { EXPECT_EQ(mojom::Status::kSuccess, status); @@ -220,14 +240,15 @@ return client_proxy; } - ClientProxy* AcceptConnection(FakePayloadListener& fake_payload_listener) { + ClientProxy* AcceptConnection(FakePayloadListener& fake_payload_listener, + const std::string& remote_endpoint_id) { ClientProxy* client_proxy; EXPECT_CALL(*service_controller_ptr_, AcceptConnection) - .WillOnce([&client_proxy](ClientProxy* client, - const std::string& endpoint_id, - const PayloadListener& listener) { + .WillOnce([&client_proxy, &remote_endpoint_id]( + ClientProxy* client, const std::string& endpoint_id, + const PayloadListener& listener) { client_proxy = client; - EXPECT_EQ(kRemoteEndpointId, endpoint_id); + EXPECT_EQ(remote_endpoint_id, endpoint_id); client_proxy->LocalEndpointAcceptedConnection(endpoint_id, listener); client_proxy->OnConnectionAccepted(endpoint_id); return Status{Status::kSuccess}; @@ -235,7 +256,7 @@ base::RunLoop accept_connection_run_loop; nearby_connections_->AcceptConnection( - kRemoteEndpointId, + remote_endpoint_id, fake_payload_listener.receiver.BindNewPipeAndPassRemote(), base::BindLambdaForTesting([&](mojom::Status status) { EXPECT_EQ(mojom::Status::kSuccess, status); @@ -341,148 +362,162 @@ TEST_F(NearbyConnectionsTest, RequestConnectionInitiated) { FakeEndpointDiscoveryListener fake_discovery_listener; + EndpointData endpoint_data = CreateEndpointData(1); ClientProxy* client_proxy = StartDiscovery(fake_discovery_listener); - client_proxy->OnEndpointFound(kServiceId, kRemoteEndpointId, - std::string(std::begin(kRemoteEndpointInfo), - std::end(kRemoteEndpointInfo)), - /*mediums=*/{}); + client_proxy->OnEndpointFound( + kServiceId, endpoint_data.remote_endpoint_id, + std::string(endpoint_data.remote_endpoint_info.begin(), + endpoint_data.remote_endpoint_info.end()), + /*mediums=*/{}); base::RunLoop initiated_run_loop; FakeConnectionLifecycleListener fake_connection_life_cycle_listener; fake_connection_life_cycle_listener.initiated_cb = base::BindLambdaForTesting( [&](const std::string& endpoint_id, mojom::ConnectionInfoPtr info) { - EXPECT_EQ(kRemoteEndpointId, endpoint_id); + EXPECT_EQ(endpoint_data.remote_endpoint_id, endpoint_id); EXPECT_EQ(kAuthenticationToken, info->authentication_token); EXPECT_EQ(std::vector<uint8_t>(std::begin(kRawAuthenticationToken), std::end(kRawAuthenticationToken)), info->raw_authentication_token); - EXPECT_EQ(std::vector<uint8_t>(std::begin(kRemoteEndpointInfo), - std::end(kRemoteEndpointInfo)), - info->endpoint_info); + EXPECT_EQ(endpoint_data.remote_endpoint_info, info->endpoint_info); EXPECT_FALSE(info->is_incoming_connection); initiated_run_loop.Quit(); }); - client_proxy = RequestConnection(fake_connection_life_cycle_listener); + RequestConnection(fake_connection_life_cycle_listener, endpoint_data); initiated_run_loop.Run(); } TEST_F(NearbyConnectionsTest, RequestConnectionAccept) { FakeEndpointDiscoveryListener fake_discovery_listener; + EndpointData endpoint_data = CreateEndpointData(1); ClientProxy* client_proxy = StartDiscovery(fake_discovery_listener); - client_proxy->OnEndpointFound(kServiceId, kRemoteEndpointId, - std::string(std::begin(kRemoteEndpointInfo), - std::end(kRemoteEndpointInfo)), - /*mediums=*/{}); + client_proxy->OnEndpointFound( + kServiceId, endpoint_data.remote_endpoint_id, + std::string(endpoint_data.remote_endpoint_info.begin(), + endpoint_data.remote_endpoint_info.end()), + /*mediums=*/{}); FakeConnectionLifecycleListener fake_connection_life_cycle_listener; - client_proxy = RequestConnection(fake_connection_life_cycle_listener); + RequestConnection(fake_connection_life_cycle_listener, endpoint_data); base::RunLoop accepted_run_loop; fake_connection_life_cycle_listener.accepted_cb = base::BindLambdaForTesting([&](const std::string& endpoint_id) { - EXPECT_EQ(kRemoteEndpointId, endpoint_id); + EXPECT_EQ(endpoint_data.remote_endpoint_id, endpoint_id); accepted_run_loop.Quit(); }); FakePayloadListener fake_payload_listener; - client_proxy = AcceptConnection(fake_payload_listener); + AcceptConnection(fake_payload_listener, endpoint_data.remote_endpoint_id); accepted_run_loop.Run(); } TEST_F(NearbyConnectionsTest, RequestConnectionOnRejected) { FakeEndpointDiscoveryListener fake_discovery_listener; + EndpointData endpoint_data = CreateEndpointData(1); ClientProxy* client_proxy = StartDiscovery(fake_discovery_listener); - client_proxy->OnEndpointFound(kServiceId, kRemoteEndpointId, - std::string(std::begin(kRemoteEndpointInfo), - std::end(kRemoteEndpointInfo)), - /*mediums=*/{}); + client_proxy->OnEndpointFound( + kServiceId, endpoint_data.remote_endpoint_id, + std::string(endpoint_data.remote_endpoint_info.begin(), + endpoint_data.remote_endpoint_info.end()), + /*mediums=*/{}); FakeConnectionLifecycleListener fake_connection_life_cycle_listener; - client_proxy = RequestConnection(fake_connection_life_cycle_listener); + client_proxy = + RequestConnection(fake_connection_life_cycle_listener, endpoint_data); base::RunLoop rejected_run_loop; fake_connection_life_cycle_listener.rejected_cb = base::BindLambdaForTesting( [&](const std::string& endpoint_id, mojom::Status status) { - EXPECT_EQ(kRemoteEndpointId, endpoint_id); + EXPECT_EQ(endpoint_data.remote_endpoint_id, endpoint_id); EXPECT_EQ(mojom::Status::kConnectionRejected, status); rejected_run_loop.Quit(); }); - client_proxy->OnConnectionRejected(kRemoteEndpointId, + client_proxy->OnConnectionRejected(endpoint_data.remote_endpoint_id, {Status::kConnectionRejected}); rejected_run_loop.Run(); } TEST_F(NearbyConnectionsTest, RequestConnectionOnBandwidthUpgrade) { FakeEndpointDiscoveryListener fake_discovery_listener; + EndpointData endpoint_data = CreateEndpointData(1); ClientProxy* client_proxy = StartDiscovery(fake_discovery_listener); - client_proxy->OnEndpointFound(kServiceId, kRemoteEndpointId, - std::string(std::begin(kRemoteEndpointInfo), - std::end(kRemoteEndpointInfo)), - /*mediums=*/{}); + client_proxy->OnEndpointFound( + kServiceId, endpoint_data.remote_endpoint_id, + std::string(endpoint_data.remote_endpoint_info.begin(), + endpoint_data.remote_endpoint_info.end()), + /*mediums=*/{}); FakeConnectionLifecycleListener fake_connection_life_cycle_listener; - client_proxy = RequestConnection(fake_connection_life_cycle_listener); + RequestConnection(fake_connection_life_cycle_listener, endpoint_data); FakePayloadListener fake_payload_listener; - client_proxy = AcceptConnection(fake_payload_listener); + client_proxy = + AcceptConnection(fake_payload_listener, endpoint_data.remote_endpoint_id); base::RunLoop bandwidth_changed_run_loop; fake_connection_life_cycle_listener.bandwidth_changed_cb = base::BindLambdaForTesting( [&](const std::string& endpoint_id, int32_t quality) { - EXPECT_EQ(kRemoteEndpointId, endpoint_id); + EXPECT_EQ(endpoint_data.remote_endpoint_id, endpoint_id); EXPECT_EQ(kQuality, quality); bandwidth_changed_run_loop.Quit(); }); - client_proxy->OnBandwidthChanged(kRemoteEndpointId, kQuality); + client_proxy->OnBandwidthChanged(endpoint_data.remote_endpoint_id, kQuality); bandwidth_changed_run_loop.Run(); } TEST_F(NearbyConnectionsTest, RequestConnectionOnDisconnected) { FakeEndpointDiscoveryListener fake_discovery_listener; + EndpointData endpoint_data = CreateEndpointData(1); ClientProxy* client_proxy = StartDiscovery(fake_discovery_listener); - client_proxy->OnEndpointFound(kServiceId, kRemoteEndpointId, - std::string(std::begin(kRemoteEndpointInfo), - std::end(kRemoteEndpointInfo)), - /*mediums=*/{}); + client_proxy->OnEndpointFound( + kServiceId, endpoint_data.remote_endpoint_id, + std::string(endpoint_data.remote_endpoint_info.begin(), + endpoint_data.remote_endpoint_info.end()), + /*mediums=*/{}); FakeConnectionLifecycleListener fake_connection_life_cycle_listener; - client_proxy = RequestConnection(fake_connection_life_cycle_listener); + RequestConnection(fake_connection_life_cycle_listener, endpoint_data); FakePayloadListener fake_payload_listener; - client_proxy = AcceptConnection(fake_payload_listener); + client_proxy = + AcceptConnection(fake_payload_listener, endpoint_data.remote_endpoint_id); base::RunLoop disconnected_run_loop; fake_connection_life_cycle_listener.disconnected_cb = base::BindLambdaForTesting([&](const std::string& endpoint_id) { - EXPECT_EQ(kRemoteEndpointId, endpoint_id); + EXPECT_EQ(endpoint_data.remote_endpoint_id, endpoint_id); disconnected_run_loop.Quit(); }); - client_proxy->OnDisconnected(kRemoteEndpointId, /*notify=*/true); + client_proxy->OnDisconnected(endpoint_data.remote_endpoint_id, + /*notify=*/true); disconnected_run_loop.Run(); } TEST_F(NearbyConnectionsTest, RequestConnectionDisconnect) { FakeEndpointDiscoveryListener fake_discovery_listener; + EndpointData endpoint_data = CreateEndpointData(1); ClientProxy* client_proxy = StartDiscovery(fake_discovery_listener); - client_proxy->OnEndpointFound(kServiceId, kRemoteEndpointId, - std::string(std::begin(kRemoteEndpointInfo), - std::end(kRemoteEndpointInfo)), - /*mediums=*/{}); + client_proxy->OnEndpointFound( + kServiceId, endpoint_data.remote_endpoint_id, + std::string(endpoint_data.remote_endpoint_info.begin(), + endpoint_data.remote_endpoint_info.end()), + /*mediums=*/{}); FakeConnectionLifecycleListener fake_connection_life_cycle_listener; - client_proxy = RequestConnection(fake_connection_life_cycle_listener); + RequestConnection(fake_connection_life_cycle_listener, endpoint_data); FakePayloadListener fake_payload_listener; - client_proxy = AcceptConnection(fake_payload_listener); + AcceptConnection(fake_payload_listener, endpoint_data.remote_endpoint_id); EXPECT_CALL(*service_controller_ptr_, DisconnectFromEndpoint) - .WillOnce([](ClientProxy* client, const std::string& endpoint_id) { - EXPECT_EQ(kRemoteEndpointId, endpoint_id); + .WillOnce([&](ClientProxy* client, const std::string& endpoint_id) { + EXPECT_EQ(endpoint_data.remote_endpoint_id, endpoint_id); client->OnDisconnected(endpoint_id, /*notify=*/true); return Status{Status::kSuccess}; }); @@ -490,13 +525,14 @@ base::RunLoop disconnected_run_loop; fake_connection_life_cycle_listener.disconnected_cb = base::BindLambdaForTesting([&](const std::string& endpoint_id) { - EXPECT_EQ(kRemoteEndpointId, endpoint_id); + EXPECT_EQ(endpoint_data.remote_endpoint_id, endpoint_id); disconnected_run_loop.Quit(); }); base::RunLoop disconnect_from_endpoint_run_loop; nearby_connections_->DisconnectFromEndpoint( - kRemoteEndpointId, base::BindLambdaForTesting([&](mojom::Status status) { + endpoint_data.remote_endpoint_id, + base::BindLambdaForTesting([&](mojom::Status status) { EXPECT_EQ(mojom::Status::kSuccess, status); disconnect_from_endpoint_run_loop.Quit(); })); @@ -506,27 +542,30 @@ TEST_F(NearbyConnectionsTest, OnPayloadTransferUpdate) { FakeEndpointDiscoveryListener fake_discovery_listener; + EndpointData endpoint_data = CreateEndpointData(1); ClientProxy* client_proxy = StartDiscovery(fake_discovery_listener); - client_proxy->OnEndpointFound(kServiceId, kRemoteEndpointId, - std::string(std::begin(kRemoteEndpointInfo), - std::end(kRemoteEndpointInfo)), - /*mediums=*/{}); + client_proxy->OnEndpointFound( + kServiceId, endpoint_data.remote_endpoint_id, + std::string(endpoint_data.remote_endpoint_info.begin(), + endpoint_data.remote_endpoint_info.end()), + /*mediums=*/{}); FakeConnectionLifecycleListener fake_connection_life_cycle_listener; - RequestConnection(fake_connection_life_cycle_listener); + RequestConnection(fake_connection_life_cycle_listener, endpoint_data); FakePayloadListener fake_payload_listener; - client_proxy = AcceptConnection(fake_payload_listener); + client_proxy = + AcceptConnection(fake_payload_listener, endpoint_data.remote_endpoint_id); base::RunLoop payload_progress_run_loop; fake_payload_listener.payload_progress_cb = base::BindLambdaForTesting([&](const std::string& endpoint_id, mojom::PayloadTransferUpdatePtr info) { - EXPECT_EQ(kRemoteEndpointId, endpoint_id); + EXPECT_EQ(endpoint_data.remote_endpoint_id, endpoint_id); payload_progress_run_loop.Quit(); }); - client_proxy->OnPayloadProgress(kRemoteEndpointId, {}); + client_proxy->OnPayloadProgress(endpoint_data.remote_endpoint_id, {}); payload_progress_run_loop.Run(); } @@ -536,24 +575,26 @@ std::end(kPayload)); FakeEndpointDiscoveryListener fake_discovery_listener; + EndpointData endpoint_data = CreateEndpointData(1); ClientProxy* client_proxy = StartDiscovery(fake_discovery_listener); - client_proxy->OnEndpointFound(kServiceId, kRemoteEndpointId, - std::string(std::begin(kRemoteEndpointInfo), - std::end(kRemoteEndpointInfo)), - /*mediums=*/{}); + client_proxy->OnEndpointFound( + kServiceId, endpoint_data.remote_endpoint_id, + std::string(endpoint_data.remote_endpoint_info.begin(), + endpoint_data.remote_endpoint_info.end()), + /*mediums=*/{}); FakeConnectionLifecycleListener fake_connection_life_cycle_listener; - client_proxy = RequestConnection(fake_connection_life_cycle_listener); + RequestConnection(fake_connection_life_cycle_listener, endpoint_data); FakePayloadListener fake_payload_listener; - client_proxy = AcceptConnection(fake_payload_listener); + AcceptConnection(fake_payload_listener, endpoint_data.remote_endpoint_id); EXPECT_CALL(*service_controller_ptr_, SendPayload) .WillOnce([&](ClientProxy* client, const std::vector<std::string>& endpoint_ids, Payload payload) { ASSERT_EQ(1u, endpoint_ids.size()); - EXPECT_EQ(kRemoteEndpointId, endpoint_ids.front()); + EXPECT_EQ(endpoint_data.remote_endpoint_id, endpoint_ids.front()); EXPECT_EQ(Payload::Type::kBytes, payload.GetType()); std::string payload_bytes(payload.AsBytes()); EXPECT_EQ(expected_payload, ByteArrayToMojom(payload.AsBytes())); @@ -561,7 +602,7 @@ base::RunLoop send_payload_run_loop; nearby_connections_->SendPayload( - {kRemoteEndpointId}, + {endpoint_data.remote_endpoint_id}, mojom::Payload::New(kPayloadId, mojom::PayloadContent::NewBytes( mojom::BytesPayload::New(expected_payload))), @@ -578,24 +619,26 @@ std::end(kPayload)); FakeEndpointDiscoveryListener fake_discovery_listener; + EndpointData endpoint_data = CreateEndpointData(1); ClientProxy* client_proxy = StartDiscovery(fake_discovery_listener); - client_proxy->OnEndpointFound(kServiceId, kRemoteEndpointId, - std::string(std::begin(kRemoteEndpointInfo), - std::end(kRemoteEndpointInfo)), - /*mediums=*/{}); + client_proxy->OnEndpointFound( + kServiceId, endpoint_data.remote_endpoint_id, + std::string(endpoint_data.remote_endpoint_info.begin(), + endpoint_data.remote_endpoint_info.end()), + /*mediums=*/{}); FakeConnectionLifecycleListener fake_connection_life_cycle_listener; - client_proxy = RequestConnection(fake_connection_life_cycle_listener); + RequestConnection(fake_connection_life_cycle_listener, endpoint_data); FakePayloadListener fake_payload_listener; - client_proxy = AcceptConnection(fake_payload_listener); + AcceptConnection(fake_payload_listener, endpoint_data.remote_endpoint_id); EXPECT_CALL(*service_controller_ptr_, SendPayload) .WillOnce([&](ClientProxy* client, const std::vector<std::string>& endpoint_ids, Payload payload) { ASSERT_EQ(1u, endpoint_ids.size()); - EXPECT_EQ(kRemoteEndpointId, endpoint_ids.front()); + EXPECT_EQ(endpoint_data.remote_endpoint_id, endpoint_ids.front()); EXPECT_EQ(Payload::Type::kFile, payload.GetType()); InputFile* file = payload.AsFile(); ASSERT_TRUE(file); @@ -614,7 +657,7 @@ base::RunLoop send_payload_run_loop; nearby_connections_->SendPayload( - {kRemoteEndpointId}, + {endpoint_data.remote_endpoint_id}, mojom::Payload::New(kPayloadId, mojom::PayloadContent::NewFile( mojom::FilePayload::New(std::move(file)))), @@ -711,14 +754,8 @@ connections_listener); initiated_run_loop_2.Run(); - base::RunLoop accepted_run_loop; - fake_connection_life_cycle_listener.accepted_cb = - base::BindLambdaForTesting([&](const std::string& endpoint_id) { - EXPECT_EQ(kRemoteEndpointId, endpoint_id); - accepted_run_loop.Quit(); - }); - client_proxy->OnConnectionAccepted(kRemoteEndpointId); - accepted_run_loop.Run(); + FakePayloadListener fake_payload_listener; + AcceptConnection(fake_payload_listener, kRemoteEndpointId); } TEST_F(NearbyConnectionsTest, StopAdvertising) { @@ -758,6 +795,64 @@ EXPECT_CALL(*service_controller_ptr_, StopAdvertising); } +TEST_F(NearbyConnectionsTest, DisconnectAllEndpoints) { + FakeEndpointDiscoveryListener fake_discovery_listener; + EndpointData endpoint_data = CreateEndpointData(1); + ClientProxy* client_proxy = StartDiscovery(fake_discovery_listener); + client_proxy->OnEndpointFound( + kServiceId, + std::string(endpoint_data.remote_endpoint_id.begin(), + endpoint_data.remote_endpoint_id.end()), + std::string(endpoint_data.remote_endpoint_info.begin(), + endpoint_data.remote_endpoint_info.end()), + /*mediums=*/{}); + + // Set up a connection to one endpoint. + FakeConnectionLifecycleListener fake_connection_life_cycle_listener; + ConnectionListener connections_listener; + RequestConnection(fake_connection_life_cycle_listener, endpoint_data); + + FakePayloadListener fake_payload_listener; + AcceptConnection(fake_payload_listener, endpoint_data.remote_endpoint_id); + + // Set up a pending connection to a different endpoint. + EndpointData endpoint_data2 = CreateEndpointData(2); + client_proxy->OnEndpointFound( + kServiceId, + std::string(endpoint_data2.remote_endpoint_id.begin(), + endpoint_data2.remote_endpoint_id.end()), + std::string(endpoint_data2.remote_endpoint_info.begin(), + endpoint_data2.remote_endpoint_info.end()), + /*mediums=*/{}); + + FakeConnectionLifecycleListener fake_connection_life_cycle_listener2; + ConnectionListener connections_listener2; + RequestConnection(fake_connection_life_cycle_listener2, endpoint_data2); + + // Stop all endpoints should invoke disconnect for both endpoints. + EXPECT_CALL(*service_controller_ptr_, + DisconnectFromEndpoint(_, endpoint_data.remote_endpoint_id)) + .WillOnce([](ClientProxy* client, const std::string& endpoint_id) { + return Status{Status::kSuccess}; + }); + EXPECT_CALL(*service_controller_ptr_, + DisconnectFromEndpoint(_, endpoint_data2.remote_endpoint_id)) + .WillOnce([](ClientProxy* client, const std::string& endpoint_id) { + return Status{Status::kSuccess}; + }); + // Stop all endpoints should stop both advertising and discovery. + EXPECT_CALL(*service_controller_ptr_, StopAdvertising); + EXPECT_CALL(*service_controller_ptr_, StopDiscovery); + + base::RunLoop stop_endpoints_run_loop; + nearby_connections_->StopAllEndpoints( + base::BindLambdaForTesting([&](mojom::Status status) { + EXPECT_EQ(mojom::Status::kSuccess, status); + stop_endpoints_run_loop.Quit(); + })); + stop_endpoints_run_loop.Run(); +} + } // namespace connections } // namespace nearby } // namespace location
diff --git a/chrome/services/sharing/public/mojom/nearby_connections.mojom b/chrome/services/sharing/public/mojom/nearby_connections.mojom index 0c0a1a8..0b3b2e1e 100644 --- a/chrome/services/sharing/public/mojom/nearby_connections.mojom +++ b/chrome/services/sharing/public/mojom/nearby_connections.mojom
@@ -258,6 +258,16 @@ // Possible return values include: // Status::kSuccess if the payload got canceled. CancelPayload(int64 payload_id) => (Status status); + + // Disconnects from, and removes all traces of, all connected and/or + // discovered endpoints. As a side effect of this call, both + // StopAdvertising and StopDiscovery are invoked. After calling + // StopAllEndpoints, no further operations with remote endpoints will + // be possible until a new call to one of StartAdvertising or + // StartDiscovery. + // Possible return values include: + // Status::kSuccess disconnected from all endpoints successfully. + StopAllEndpoints() => (Status status); }; // Provide all the dependencies that NearbyConnections library requires.
diff --git a/chrome/test/data/chromeos/file_manager/empty.txt b/chrome/test/data/chromeos/file_manager/empty.txt new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/chrome/test/data/chromeos/file_manager/empty.txt
diff --git a/chrome/test/data/extensions/api_test/file_browser/media_metadata/test.js b/chrome/test/data/extensions/api_test/file_browser/media_metadata/test.js index 7e7007f7..aeb29a82 100644 --- a/chrome/test/data/extensions/api_test/file_browser/media_metadata/test.js +++ b/chrome/test/data/extensions/api_test/file_browser/media_metadata/test.js
@@ -5,16 +5,19 @@ /** * Test files should be created before running the tests. */ -let audioBlob = null; -let videoBlob = null; +let audioEntry = null; +let brokeEntry = null; +let emptyEntry = null; +let imageEntry = null; +let videoEntry = null; /* - * getContentMineType of an empty blob is undefined. + * getContentMineType of an empty entry is undefined. */ function testGetContentMimeTypeEmpty() { - const blob = new Blob([]); + const entry = emptyEntry; - chrome.fileManagerPrivate.getContentMimeType(blob, (mimeType) => { + chrome.fileManagerPrivate.getContentMimeType(entry, (mimeType) => { chrome.test.assertEq(undefined, mimeType); chrome.test.assertNoLastError(); chrome.test.succeed(); @@ -25,16 +28,10 @@ * getContentMineType detects content mime types: image. */ function testGetContentMimeTypeImage() { - const image = new Uint8Array([ - 71, 73, 70, 56, 57, 97, 1, 0, 1, 0, 128, 0, 0, 0, - 0, 0, 255, 255, 255, 33, 249, 4, 1, 0, 0, 0, 0, 44, - 0, 0, 0, 0, 1, 0, 1, 0, 0, 2, 1, 68, 0, 59 - ]); + const entry = imageEntry; - const blob = new Blob([image]); - - chrome.fileManagerPrivate.getContentMimeType(blob, (mimeType) => { - chrome.test.assertEq('image/gif', mimeType); + chrome.fileManagerPrivate.getContentMimeType(entry, (mimeType) => { + chrome.test.assertEq('image/jpeg', mimeType); chrome.test.assertNoLastError(); chrome.test.succeed(); }); @@ -44,9 +41,9 @@ * getContentMineType detects content mime types: audio. */ function testGetContentMimeTypeAudio() { - const blob = audioBlob; + const entry = audioEntry; - chrome.fileManagerPrivate.getContentMimeType(blob, (mimeType) => { + chrome.fileManagerPrivate.getContentMimeType(entry, (mimeType) => { chrome.test.assertEq('audio/mpeg', mimeType); chrome.test.assertNoLastError(); chrome.test.succeed(); @@ -57,9 +54,9 @@ * getContentMineType detects content mime types: video. */ function testGetContentMimeTypeVideo() { - const blob = videoBlob; + const entry = videoEntry; - chrome.fileManagerPrivate.getContentMimeType(blob, (mimeType) => { + chrome.fileManagerPrivate.getContentMimeType(entry, (mimeType) => { chrome.test.assertEq('video/mp4', mimeType); chrome.test.assertNoLastError(); chrome.test.succeed(); @@ -71,9 +68,9 @@ * chrome.runtime.lastError in that case. */ function testGetContentMimeTypeUnknownMimeTypeError() { - const blob = new Blob([42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42]); + const entry = brokeEntry; - chrome.fileManagerPrivate.getContentMimeType(blob, (mimeType) => { + chrome.fileManagerPrivate.getContentMimeType(entry, (mimeType) => { chrome.test.assertEq(undefined, mimeType); if (!chrome.runtime.lastError) { @@ -118,13 +115,13 @@ } /* - * getContentMetadata of an empty blob is undefined. + * getContentMetadata of an empty entry is undefined. */ function testGetContentMetadataEmpty() { - const blob = new Blob([]); + const entry = emptyEntry; chrome.fileManagerPrivate.getContentMetadata( - blob, 'audio/mpeg', 'metadataTags', (metadata) => { + entry, 'audio/mpeg', 'metadataTags', (metadata) => { chrome.test.assertEq(undefined, metadata); chrome.test.assertNoLastError(); chrome.test.succeed(); @@ -135,10 +132,10 @@ * getContentMetadata 'metadataTags' returns tags only. */ function testGetContentMetadataAudioTags() { - const blob = audioBlob; + const entry = audioEntry; chrome.fileManagerPrivate.getContentMetadata( - blob, 'audio/mpeg', 'metadataTags', (metadata) => { + entry, 'audio/mpeg', 'metadataTags', (metadata) => { chrome.test.assertEq('audio/mpeg', metadata.mimeType); chrome.test.assertNoLastError(); @@ -153,10 +150,10 @@ * getContentMetadata 'metadataTagsImages' returns tags and images. */ function testGetContentMetadataAudioTagsImages() { - const blob = audioBlob; + const entry = audioEntry; chrome.fileManagerPrivate.getContentMetadata( - blob, 'audio/mpeg', 'metadataTagsImages', (metadata) => { + entry, 'audio/mpeg', 'metadataTagsImages', (metadata) => { chrome.test.assertEq('audio/mpeg', metadata.mimeType); chrome.test.assertNoLastError(); @@ -217,10 +214,10 @@ * video file has no attached images. */ function testGetContentMetadataVideoTagsImages() { - const blob = videoBlob; + const entry = videoEntry; chrome.fileManagerPrivate.getContentMetadata( - blob, 'video/mp4', 'metadataTagsImages', (metadata) => { + entry, 'video/mp4', 'metadataTagsImages', (metadata) => { chrome.test.assertEq('video/mp4', metadata.mimeType); chrome.test.assertNoLastError(); @@ -235,10 +232,10 @@ * getContentMetadata returns the input mime type in the metadata mime type. */ function testGetContentMetadataRetainsInputMimeType() { - const blob = audioBlob; + const entry = audioEntry; chrome.fileManagerPrivate.getContentMetadata( - blob, 'audio/input-type', 'metadataTags', (metadata) => { + entry, 'audio/input-type', 'metadataTags', (metadata) => { chrome.test.assertEq('audio/input-type', metadata.mimeType); chrome.test.assertNoLastError(); chrome.test.succeed(); @@ -250,10 +247,10 @@ * the video has width and height. */ function testGetContentMetadataVideoResetsAudioMime() { - const blob = videoBlob; + const entry = videoEntry; chrome.fileManagerPrivate.getContentMetadata( - blob, 'audio/input-type', 'metadataTagsImages', (metadata) => { + entry, 'audio/input-type', 'metadataTagsImages', (metadata) => { chrome.test.assertEq('video/input-type', metadata.mimeType); chrome.test.assertNoLastError(); @@ -269,10 +266,10 @@ * chrome.runtime.lastError given other mime types. */ function testGetContentMetadataUnsupportedMimetypeError() { - const blob = new Blob([71, 73, 70, 56, 57, 97, 1, 0, 1, 0, 128, 0]); + const entry = imageEntry; chrome.fileManagerPrivate.getContentMetadata( - blob, 'image/gif', 'metadataTags', (metadata) => { + entry, 'image/jpeg', 'metadataTags', (metadata) => { chrome.test.assertEq(undefined, metadata); if (!chrome.runtime.lastError) { @@ -308,30 +305,24 @@ } /* - * Resolves the content of |fileName| as a Blob. + * Resolves the fileEntry for |fileName|. */ -function resolveFileBlob(fileSystem, fileName) { +function resolveFileEntry(fileSystem, fileName) { return new Promise((resolve) => { const failure = (error) => { - chrome.test.fail('While reading file system: ' + error); + chrome.test.fail('While resolving ' + fileName + ': ' + error); }; - const readEntry = (fileEntry) => { - fileEntry.file((file) => { - const reader = new FileReader(); - reader.onerror = failure; - reader.onload = () => resolve(new Blob([reader.result])); - reader.readAsArrayBuffer(file); - }, failure); - }; - - fileSystem.root.getFile(fileName, {}, readEntry, failure); + fileSystem.root.getFile(fileName, {}, resolve, failure); }); } resolveTestFileSystem().then(async (fileSystem) => { - audioBlob = await resolveFileBlob(fileSystem, 'id3_png_test.mp3'); - videoBlob = await resolveFileBlob(fileSystem, '90rotation.mp4'); + audioEntry = await resolveFileEntry(fileSystem, 'id3_png_test.mp3'); + brokeEntry = await resolveFileEntry(fileSystem, 'broken.jpg'); + emptyEntry = await resolveFileEntry(fileSystem, 'empty.txt'); + imageEntry = await resolveFileEntry(fileSystem, 'image3.jpg'); + videoEntry = await resolveFileEntry(fileSystem, '90rotation.mp4'); chrome.test.runTests([ // fileManagerPrivate.getContentMimeType tests.
diff --git a/chrome/test/data/portal/portal-no-src.html b/chrome/test/data/portal/portal-no-src.html new file mode 100644 index 0000000..6172ffa --- /dev/null +++ b/chrome/test/data/portal/portal-no-src.html
@@ -0,0 +1,9 @@ +<!DOCTYPE html> +<body> + <portal></portal> + <script> + function activate() { + return document.querySelector("portal").activate().catch(err => true); + } + </script> +</body>
diff --git a/chrome/test/data/webui/signin/BUILD.gn b/chrome/test/data/webui/signin/BUILD.gn index a495623..09d855d 100644 --- a/chrome/test/data/webui/signin/BUILD.gn +++ b/chrome/test/data/webui/signin/BUILD.gn
@@ -48,6 +48,7 @@ "//chrome/browser/resources/signin/profile_picker:navigation_behavior", "//chrome/browser/resources/signin/profile_picker:profile_picker_app", "//chrome/browser/resources/signin/profile_picker/profile_creation_flow:ensure_lazy_loaded", + "//chrome/browser/resources/signin/profile_picker/profile_creation_flow:local_profile_customization", ] }
diff --git a/chrome/test/data/webui/signin/profile_picker_app_test.js b/chrome/test/data/webui/signin/profile_picker_app_test.js index b7147fc..b2fe07db 100644 --- a/chrome/test/data/webui/signin/profile_picker_app_test.js +++ b/chrome/test/data/webui/signin/profile_picker_app_test.js
@@ -55,4 +55,23 @@ return browserProxy.whenCalled('loadSignInProfileCreationFlow'); }); }); + + test('notNowButtonImplementation', function() { + navigateTo(Routes.NEW_PROFILE); + return waitForLoad() + .then(() => { + return waitBeforeNextRender(app); + }) + .then(() => { + const choice = /** @type {!ProfileTypeChoiceElement} */ ( + app.$$('profile-type-choice')); + assertTrue(!!choice); + choice.$$('#notNowButton').click(); + const customization = + /** @type {!LocalProfileCustomizationElement} */ ( + app.$$('local-profile-customization')); + assertTrue(!!customization); + assertTrue(customization.classList.contains('active')); + }); + }); });
diff --git a/chrome/test/data/webui/signin/signin_browsertest.js b/chrome/test/data/webui/signin/signin_browsertest.js index 2d432a4f..676c3e1 100644 --- a/chrome/test/data/webui/signin/signin_browsertest.js +++ b/chrome/test/data/webui/signin/signin_browsertest.js
@@ -125,6 +125,6 @@ } }; -TEST_F('ProfilePickerAppTest', 'SignInButtonImplementation', function() { +TEST_F('ProfilePickerAppTest', 'ButtonsImplementation', function() { mocha.run(); });
diff --git a/chrome/test/payments/payment_request_test_controller.h b/chrome/test/payments/payment_request_test_controller.h index e0cbc8ab..29cc7333 100644 --- a/chrome/test/payments/payment_request_test_controller.h +++ b/chrome/test/payments/payment_request_test_controller.h
@@ -66,6 +66,8 @@ void SetValidSsl(bool valid_ssl); void SetCanMakePaymentEnabledPref(bool can_make_payment_enabled); void SetTwaPackageName(const std::string& twa_package_name); + void SetTwaPaymentApp(const std::string& method_name, + const std::string& response); // Get the WebContents of the Payment Handler for testing purpose, or null if // nonexistent. To guarantee a non-null return, this function should be called @@ -120,6 +122,8 @@ bool valid_ssl_ = true; bool can_make_payment_pref_ = true; std::string twa_package_name_; + std::string twa_payment_app_method_name_; + std::string twa_payment_app_response_; std::vector<AppDescription> app_descriptions_; #if !defined(OS_ANDROID)
diff --git a/chrome/test/payments/payment_request_test_controller_android.cc b/chrome/test/payments/payment_request_test_controller_android.cc index d304033..7ed55e9 100644 --- a/chrome/test/payments/payment_request_test_controller_android.cc +++ b/chrome/test/payments/payment_request_test_controller_android.cc
@@ -112,6 +112,12 @@ /*skip_ui_for_basic_card=*/false, twa_package_name_); } +void PaymentRequestTestController::SetTwaPaymentApp( + const std::string& method_name, + const std::string& response) { + // Intentionally left blank. +} + void PaymentRequestTestController::OnCanMakePaymentCalled() { if (observer_) observer_->OnCanMakePaymentCalled();
diff --git a/chrome/test/payments/payment_request_test_controller_desktop.cc b/chrome/test/payments/payment_request_test_controller_desktop.cc index a0b1acc..8f2afd5 100644 --- a/chrome/test/payments/payment_request_test_controller_desktop.cc +++ b/chrome/test/payments/payment_request_test_controller_desktop.cc
@@ -10,6 +10,7 @@ #include "base/strings/utf_string_conversions.h" #include "chrome/browser/payments/chrome_payment_request_delegate.h" #include "chrome/browser/payments/payment_request_factory.h" +#include "components/payments/content/android_app_communication.h" #include "components/payments/content/payment_request.h" #include "components/payments/content/payment_request_web_contents_manager.h" #include "components/payments/core/payment_prefs.h" @@ -158,11 +159,21 @@ UpdateDelegateFactory(); } +void PaymentRequestTestController::SetTwaPaymentApp( + const std::string& method_name, + const std::string& response) { + twa_payment_app_method_name_ = method_name; + twa_payment_app_response_ = response; + UpdateDelegateFactory(); +} + void PaymentRequestTestController::UpdateDelegateFactory() { SetPaymentRequestFactoryForTesting(base::BindRepeating( [](PaymentRequest::ObserverForTest* observer_for_test, bool is_off_the_record, bool valid_ssl, PrefService* prefs, const std::string& twa_package_name, + const std::string& twa_payment_app_method_name, + const std::string& twa_payment_app_response, mojo::PendingReceiver<payments::mojom::PaymentRequest> receiver, content::RenderFrameHost* render_frame_host) { content::WebContents* web_contents = @@ -174,12 +185,19 @@ PaymentRequestWebContentsManager* manager = PaymentRequestWebContentsManager::GetOrCreateForWebContents( web_contents); + if (!twa_payment_app_method_name.empty()) { + AndroidAppCommunication::GetForBrowserContext( + web_contents->GetBrowserContext()) + ->SetAppForTesting(twa_package_name, twa_payment_app_method_name, + twa_payment_app_response); + } manager->CreatePaymentRequest(render_frame_host, web_contents, std::move(delegate), std::move(receiver), observer_for_test); }, observer_converter_.get(), is_off_the_record_, valid_ssl_, prefs_.get(), - twa_package_name_)); + twa_package_name_, twa_payment_app_method_name_, + twa_payment_app_response_)); } void PaymentRequestTestController::OnCanMakePaymentCalled() {
diff --git a/chromeos/BUILD.gn b/chromeos/BUILD.gn index 3ef6d63..4f2a4d4 100644 --- a/chromeos/BUILD.gn +++ b/chromeos/BUILD.gn
@@ -289,6 +289,7 @@ tast_disabled_tests = [ # crbug.com/1115622 "ui.ChromeLoginGAIA", + "inputs.VirtualKeyboardOOBE", # crbug.com/1097630 "security.OpenFDs",
diff --git a/chromeos/constants/chromeos_features.cc b/chromeos/constants/chromeos_features.cc index 35f7362..cb6b434b 100644 --- a/chromeos/constants/chromeos_features.cc +++ b/chromeos/constants/chromeos_features.cc
@@ -97,7 +97,7 @@ // Enables or disables entry point for child account sign in or creation. const base::Feature kChildSpecificSignin{"ChildSpecificSignin", - base::FEATURE_DISABLED_BY_DEFAULT}; + base::FEATURE_ENABLED_BY_DEFAULT}; // If enabled, options page for each input method will be opened in ChromeOS // settings. Otherwise it will be opened in a new web page in Chrome browser.
diff --git a/chromeos/profiles/airmont.afdo.newest.txt b/chromeos/profiles/airmont.afdo.newest.txt index 83834ffe..28b14e0 100644 --- a/chromeos/profiles/airmont.afdo.newest.txt +++ b/chromeos/profiles/airmont.afdo.newest.txt
@@ -1 +1 @@ -chromeos-chrome-amd64-airmont-86-4183.57-1597053344-benchmark-86.0.4232.0-r1-redacted.afdo.xz +chromeos-chrome-amd64-airmont-86-4183.59-1597659923-benchmark-86.0.4232.0-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/silvermont.afdo.newest.txt b/chromeos/profiles/silvermont.afdo.newest.txt index aaa77600..164a488 100644 --- a/chromeos/profiles/silvermont.afdo.newest.txt +++ b/chromeos/profiles/silvermont.afdo.newest.txt
@@ -1 +1 @@ -chromeos-chrome-amd64-silvermont-86-4183.57-1597055597-benchmark-86.0.4232.0-r1-redacted.afdo.xz +chromeos-chrome-amd64-silvermont-86-4183.59-1597657121-benchmark-86.0.4232.0-r1-redacted.afdo.xz
diff --git a/chromeos/services/cellular_setup/BUILD.gn b/chromeos/services/cellular_setup/BUILD.gn index 9b6255f..2700755 100644 --- a/chromeos/services/cellular_setup/BUILD.gn +++ b/chromeos/services/cellular_setup/BUILD.gn
@@ -26,6 +26,42 @@ ] } +static_library("esim_manager") { + sources = [ + "esim_manager.cc", + "esim_manager.h", + ] + + deps = [ + "//base", + "//chromeos/dbus/hermes", + "//chromeos/services/cellular_setup/public/mojom", + "//components/device_event_log", + "//dbus", + ] +} + +component("in_process_esim_manager") { + sources = [ + "in_process_esim_manager.cc", + "in_process_esim_manager.h", + ] + + defines = [ "IS_IN_PROCESS_ESIM_MANAGER_IMPL" ] + + public_deps = [ + "//chromeos/services/cellular_setup/public/mojom", + "//mojo/public/cpp/bindings", + ] + + deps = [ + ":esim_manager", + "//chromeos/services/cellular_setup/public/mojom", + "//dbus", + "//mojo/public/cpp/bindings", + ] +} + static_library("test_support") { testonly = true @@ -47,17 +83,21 @@ sources = [ "cellular_setup_impl_unittest.cc", "cellular_setup_service_unittest.cc", + "esim_manager_unittest.cc", "ota_activator_impl_unittest.cc", ] deps = [ ":cellular_setup", + ":esim_manager", ":test_support", "//base", "//base/test:test_support", + "//chromeos/dbus/hermes", "//chromeos/dbus/shill", "//chromeos/network:test_support", "//chromeos/services/cellular_setup/public/cpp:test_support", + "//dbus", "//testing/gmock", "//testing/gtest", ]
diff --git a/chromeos/services/cellular_setup/esim_manager.cc b/chromeos/services/cellular_setup/esim_manager.cc new file mode 100644 index 0000000..af4dfec --- /dev/null +++ b/chromeos/services/cellular_setup/esim_manager.cc
@@ -0,0 +1,580 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromeos/services/cellular_setup/esim_manager.h" + +#include "base/strings/utf_string_conversions.h" +#include "components/device_event_log/device_event_log.h" +#include "third_party/cros_system_api/dbus/hermes/dbus-constants.h" + +namespace chromeos { +namespace cellular_setup { + +namespace { +mojom::ProfileState ProfileStateToMojo(int32_t state) { + switch (state) { + case hermes::profile::State::kActive: + return mojom::ProfileState::kActive; + case hermes::profile::State::kInactive: + return mojom::ProfileState::kInactive; + default: + return mojom::ProfileState::kPending; + } +} + +mojom::ESimManager::ProfileInstallResult InstallResultFromStatus( + HermesResponseStatus status) { + switch (status) { + case HermesResponseStatus::kSuccess: + return ESimManager::ProfileInstallResult::kSuccess; + case HermesResponseStatus::kErrorNeedConfirmationCode: + return ESimManager::ProfileInstallResult::kErrorNeedsConfirmationCode; + case HermesResponseStatus::kErrorInvalidActivationCode: + return ESimManager::ProfileInstallResult::kErrorInvalidActivationCode; + default: + return ESimManager::ProfileInstallResult::kFailure; + } +} + +mojom::ESimManager::ESimOperationResult OperationResultFromStatus( + HermesResponseStatus status) { + switch (status) { + case HermesResponseStatus::kSuccess: + return ESimManager::ESimOperationResult::kSuccess; + default: + return ESimManager::ESimOperationResult::kFailure; + } +} + +} // namespace + +ESimManager::EuiccInfo::EuiccInfo(const dbus::ObjectPath& path, + HermesEuiccClient::Properties* properties) + : euicc_(mojom::Euicc::New()), path_(path) { + CopyProperties(properties); +} + +ESimManager::EuiccInfo::~EuiccInfo() = default; + +bool ESimManager::EuiccInfo::ContainsIccid(const std::string& iccid) { + return profile_iccids_.find(iccid) != profile_iccids_.end(); +} + +void ESimManager::EuiccInfo::CopyProperties( + HermesEuiccClient::Properties* properties) { + euicc_->eid = properties->eid().value(); + euicc_->is_active = properties->is_active().value(); +} + +ESimManager::ESimProfileInfo::ESimProfileInfo( + const dbus::ObjectPath& path, + const std::string& eid, + HermesProfileClient::Properties* properties) + : esim_profile_(mojom::ESimProfile::New()), path_(path) { + CopyProperties(properties); + esim_profile_->eid = eid; +} + +ESimManager::ESimProfileInfo::~ESimProfileInfo() = default; + +void ESimManager::ESimProfileInfo::CopyProperties( + HermesProfileClient::Properties* properties) { + esim_profile_->iccid = properties->iccid().value(); + esim_profile_->name = base::UTF8ToUTF16(properties->name().value()); + esim_profile_->nickname = base::UTF8ToUTF16(properties->nick_name().value()); + esim_profile_->service_provider = + base::UTF8ToUTF16(properties->service_provider().value()); + esim_profile_->state = ProfileStateToMojo(properties->state().value()); + esim_profile_->activation_code = properties->activation_code().value(); +} + +ESimManager::ESimManager() + : hermes_manager_client_(HermesManagerClient::Get()), + hermes_euicc_client_(HermesEuiccClient::Get()), + hermes_profile_client_(HermesProfileClient::Get()) { + hermes_manager_client_->AddObserver(this); + hermes_euicc_client_->AddObserver(this); + hermes_profile_client_->AddObserver(this); + UpdateAvailableEuiccs(); +} + +ESimManager::~ESimManager() { + hermes_manager_client_->RemoveObserver(this); + hermes_euicc_client_->RemoveObserver(this); + hermes_profile_client_->RemoveObserver(this); +} + +void ESimManager::BindReceiver( + mojo::PendingReceiver<mojom::ESimManager> receiver) { + NET_LOG(EVENT) << "ESimManager::BindReceiver()"; + receivers_.Add(this, std::move(receiver)); +} + +void ESimManager::AddObserver( + mojo::PendingRemote<mojom::ESimManagerObserver> observer) { + observers_.Add(std::move(observer)); +} + +void ESimManager::GetAvailableEuiccs(GetAvailableEuiccsCallback callback) { + std::vector<mojom::EuiccPtr> euicc_list; + for (auto const& eid : available_euicc_eids_) + euicc_list.push_back(eid_euicc_info_map_[eid]->euicc()->Clone()); + std::move(callback).Run(std::move(euicc_list)); +} + +void ESimManager::GetProfiles(const std::string& eid, + GetProfilesCallback callback) { + if (!eid_euicc_info_map_.count(eid)) { + std::move(callback).Run(base::nullopt); + return; + } + EuiccInfo* euicc_info = eid_euicc_info_map_[eid].get(); + std::vector<mojom::ESimProfilePtr> profile_list; + for (auto const& iccid : euicc_info->profile_iccids()) { + profile_list.push_back( + iccid_esim_profile_info_map_[iccid]->esim_profile()->Clone()); + } + std::move(callback).Run(std::move(profile_list)); +} + +void ESimManager::RequestPendingProfiles( + const std::string& eid, + RequestPendingProfilesCallback callback) { + if (!eid_euicc_info_map_.count(eid)) { + NET_LOG(ERROR) << "RequestPendingProfiles failed: Unknown eid."; + std::move(callback).Run(ESimOperationResult::kFailure); + return; + } + NET_LOG(EVENT) << "Requesting Pending profiles"; + hermes_euicc_client_->RequestPendingEvents( + eid_euicc_info_map_[eid]->path(), + base::BindOnce(&ESimManager::OnRequestPendingEventsResult, + weak_ptr_factory_.GetWeakPtr(), std::move(callback))); +} + +void ESimManager::InstallProfileFromActivationCode( + const std::string& eid, + const std::string& activation_code, + const std::string& confirmation_code, + InstallProfileFromActivationCodeCallback callback) { + ESimProfileInfo* profile_info = nullptr; + ProfileInstallResult status = GetPendingProfileInfoFromActivationCode( + activation_code, eid, &profile_info); + if (profile_info && + status != mojom::ESimManager::ProfileInstallResult::kSuccess) { + // Return early if profile was found but not in the correct state. + std::move(callback).Run(status, nullptr); + return; + } + + if (profile_info) { + CallInstallPendingProfile(profile_info, confirmation_code, + std::move(callback)); + return; + } + + // Try installing directly with activation code. + hermes_euicc_client_->InstallProfileFromActivationCode( + eid_euicc_info_map_[eid]->path(), activation_code, confirmation_code, + base::BindOnce(&ESimManager::OnProfileInstallResult, + weak_ptr_factory_.GetWeakPtr(), std::move(callback), eid)); +} + +void ESimManager::InstallProfile(const std::string& iccid, + const std::string& confirmation_code, + InstallProfileCallback callback) { + ESimProfileInfo* profile_info = GetPendingProfileInfoFromIccid(iccid); + if (!profile_info) { + std::move(callback).Run(ProfileInstallResult::kFailure, nullptr); + return; + } + + CallInstallPendingProfile(profile_info, confirmation_code, + std::move(callback)); +} + +void ESimManager::UninstallProfile(const std::string& iccid, + UninstallProfileCallback callback) { + ESimProfileInfo* profile_info = GetInstalledProfileInfoFromIccid(iccid); + if (!profile_info) { + std::move(callback).Run(ESimOperationResult::kFailure); + return; + } + + EuiccInfo* euicc_info = + eid_euicc_info_map_[profile_info->esim_profile()->eid].get(); + hermes_euicc_client_->UninstallProfile( + euicc_info->path(), profile_info->path(), + base::BindOnce(&ESimManager::OnESimOperationResult, + weak_ptr_factory_.GetWeakPtr(), std::move(callback))); +} + +void ESimManager::EnableProfile(const std::string& iccid, + EnableProfileCallback callback) { + ESimProfileInfo* profile_info = GetInstalledProfileInfoFromIccid(iccid); + if (!profile_info) { + std::move(callback).Run(ESimOperationResult::kFailure); + return; + } + + if (profile_info->esim_profile()->state == mojom::ProfileState::kActive) { + NET_LOG(ERROR) << "Profile enable failed: Profile already enabled"; + std::move(callback).Run(ESimOperationResult::kFailure); + return; + } + + hermes_profile_client_->EnableCarrierProfile( + profile_info->path(), + base::BindOnce(&ESimManager::OnESimOperationResult, + weak_ptr_factory_.GetWeakPtr(), std::move(callback))); +} + +void ESimManager::DisableProfile(const std::string& iccid, + DisableProfileCallback callback) { + ESimProfileInfo* profile_info = GetInstalledProfileInfoFromIccid(iccid); + if (!profile_info) { + std::move(callback).Run(ESimOperationResult::kFailure); + return; + } + + if (profile_info->esim_profile()->state == mojom::ProfileState::kInactive) { + NET_LOG(ERROR) << "Profile enable failed: Profile already disabled"; + std::move(callback).Run(ESimOperationResult::kFailure); + return; + } + + hermes_profile_client_->DisableCarrierProfile( + profile_info->path(), + base::BindOnce(&ESimManager::OnESimOperationResult, + weak_ptr_factory_.GetWeakPtr(), std::move(callback))); +} + +void ESimManager::SetProfileNickname(const std::string& iccid, + const base::string16& nickname, + SetProfileNicknameCallback callback) { + ESimProfileInfo* profile_info = GetInstalledProfileInfoFromIccid(iccid); + if (!profile_info) { + std::move(callback).Run(ESimOperationResult::kFailure); + return; + } + + HermesProfileClient::Properties* properties = + hermes_profile_client_->GetProperties(profile_info->path()); + properties->nick_name().Set( + base::UTF16ToUTF8(nickname), + base::BindOnce(&ESimManager::OnProfilePropertySet, + weak_ptr_factory_.GetWeakPtr(), std::move(callback))); +} + +void ESimManager::OnAvailableEuiccListChanged() { + UpdateAvailableEuiccs(); + for (auto& observer : observers_) + observer->OnAvailableEuiccListChanged(); +} + +void ESimManager::OnEuiccPropertyChanged(const dbus::ObjectPath& euicc_path, + const std::string& property_name) { + EuiccInfo* euicc_info = GetEuiccInfoFromPath(euicc_path); + // Skip notifying observers if the euicc object is not tracked. + if (!euicc_info) + return; + if (property_name == hermes::euicc::kPendingProfilesProperty || + property_name == hermes::euicc::kInstalledProfilesProperty) { + UpdateProfileList(euicc_info); + for (auto& observer : observers_) + observer->OnProfileListChanged(euicc_info->euicc()->eid); + } else { + HermesEuiccClient::Properties* properties = + hermes_euicc_client_->GetProperties(euicc_path); + euicc_info->CopyProperties(properties); + for (auto& observer : observers_) + observer->OnEuiccChanged(euicc_info->euicc()->Clone()); + } +} + +void ESimManager::OnCarrierProfilePropertyChanged( + const dbus::ObjectPath& carrier_profile_path, + const std::string& property_name) { + ESimProfileInfo* profile_info = GetProfileInfoFromPath(carrier_profile_path); + // Skip notifying observers if the carrier profile is not tracked. + if (!profile_info) + return; + + HermesProfileClient::Properties* properties = + hermes_profile_client_->GetProperties(carrier_profile_path); + profile_info->CopyProperties(properties); + for (auto& observer : observers_) + observer->OnProfileChanged(profile_info->esim_profile()->Clone()); +} + +void ESimManager::CallInstallPendingProfile( + ESimProfileInfo* profile_info, + const std::string& confirmation_code, + ProfileInstallResultCallback callback) { + mojom::ESimProfile* profile = profile_info->esim_profile(); + if (profile->state == mojom::ProfileState::kInstalling || + profile->state != mojom::ProfileState::kPending) { + NET_LOG(ERROR) << "Profile is already installed or in installing state."; + std::move(callback).Run(ProfileInstallResult::kFailure, nullptr); + return; + } + + profile->state = mojom::ProfileState::kInstalling; + for (auto& observer : observers_) + observer->OnProfileChanged(profile->Clone()); + + hermes_euicc_client_->InstallPendingProfile( + eid_euicc_info_map_[profile->eid]->path(), profile_info->path(), + confirmation_code, + base::BindOnce(&ESimManager::OnPendingProfileInstallResult, + weak_ptr_factory_.GetWeakPtr(), std::move(callback), + profile_info)); +} + +void ESimManager::OnProfileInstallResult(ProfileInstallResultCallback callback, + const std::string& eid, + HermesResponseStatus status, + const dbus::ObjectPath* object_path) { + if (status != HermesResponseStatus::kSuccess) { + NET_LOG(ERROR) << "Error Installing profile status=" + << static_cast<int>(status); + std::move(callback).Run(InstallResultFromStatus(status), nullptr); + return; + } + + HermesProfileClient::Properties* properties = + hermes_profile_client_->GetProperties(*object_path); + ESimProfileInfo* profile_info = + GetOrCreateESimProfileInfo(properties, *object_path, eid); + std::move(callback).Run(ProfileInstallResult::kSuccess, + profile_info->esim_profile()->Clone()); +} + +void ESimManager::OnPendingProfileInstallResult( + ProfileInstallResultCallback callback, + ESimProfileInfo* profile_info, + HermesResponseStatus status) { + if (status != HermesResponseStatus::kSuccess) { + NET_LOG(ERROR) << "Error Installing pending profile status=" + << static_cast<int>(status); + profile_info->esim_profile()->state = mojom::ProfileState::kPending; + for (auto& observer : observers_) + observer->OnProfileChanged(profile_info->esim_profile()->Clone()); + std::move(callback).Run(InstallResultFromStatus(status), nullptr); + return; + } + + std::move(callback).Run(ProfileInstallResult::kSuccess, + profile_info->esim_profile()->Clone()); +} + +void ESimManager::OnESimOperationResult(ESimOperationResultCallback callback, + HermesResponseStatus status) { + if (status != HermesResponseStatus::kSuccess) { + NET_LOG(ERROR) << "ESim operation error status=" + << static_cast<int>(status); + } + std::move(callback).Run(OperationResultFromStatus(status)); +} + +void ESimManager::OnProfilePropertySet(ESimOperationResultCallback callback, + bool success) { + if (!success) { + NET_LOG(ERROR) << "ESimProfile property set error."; + } + std::move(callback).Run( + success ? mojom::ESimManager::ESimOperationResult::kSuccess + : mojom::ESimManager::ESimOperationResult::kFailure); +} + +void ESimManager::OnRequestPendingEventsResult( + RequestPendingProfilesCallback callback, + HermesResponseStatus status) { + if (status != HermesResponseStatus::kSuccess) { + NET_LOG(ERROR) << "Request Pending events failed status=" + << static_cast<int>(status); + } + std::move(callback).Run( + status == HermesResponseStatus::kSuccess + ? mojom::ESimManager::ESimOperationResult::kSuccess + : mojom::ESimManager::ESimOperationResult::kFailure); +} + +void ESimManager::UpdateAvailableEuiccs() { + NET_LOG(EVENT) << "Updating available Euiccs"; + available_euicc_eids_.clear(); + for (auto& euicc_path : hermes_manager_client_->GetAvailableEuiccs()) { + HermesEuiccClient::Properties* properties = + hermes_euicc_client_->GetProperties(euicc_path); + EuiccInfo* euicc_info = GetOrCreateEuiccInfo(properties, euicc_path); + available_euicc_eids_.insert(properties->eid().value()); + UpdateProfileList(euicc_info); + } + RemoveUntrackedEuiccs(); +} + +void ESimManager::UpdateProfileList(EuiccInfo* euicc_info) { + HermesEuiccClient::Properties* euicc_properties = + hermes_euicc_client_->GetProperties(euicc_info->path()); + std::set<std::string> profile_iccids; + for (auto& path : euicc_properties->installed_carrier_profiles().value()) { + HermesProfileClient::Properties* profile_properties = + hermes_profile_client_->GetProperties(path); + GetOrCreateESimProfileInfo(profile_properties, path, + euicc_info->euicc()->eid); + profile_iccids.insert(profile_properties->iccid().value()); + } + for (auto& path : euicc_properties->pending_carrier_profiles().value()) { + HermesProfileClient::Properties* profile_properties = + hermes_profile_client_->GetProperties(path); + GetOrCreateESimProfileInfo(profile_properties, path, + euicc_info->euicc()->eid); + profile_iccids.insert(profile_properties->iccid().value()); + } + euicc_info->set_profile_iccids(profile_iccids); + RemoveUntrackedProfiles(euicc_info); +} + +void ESimManager::RemoveUntrackedEuiccs() { + for (auto euicc_it = eid_euicc_info_map_.begin(); + euicc_it != eid_euicc_info_map_.end();) { + const std::string& eid = euicc_it->first; + if (available_euicc_eids_.find(eid) != available_euicc_eids_.end()) { + euicc_it++; + continue; + } + + // Remove all profiles for this Euicc. + for (auto esim_profile_it = iccid_esim_profile_info_map_.begin(); + esim_profile_it != iccid_esim_profile_info_map_.end();) { + if (esim_profile_it->second->esim_profile()->eid == eid) + esim_profile_it = iccid_esim_profile_info_map_.erase(esim_profile_it); + else + esim_profile_it++; + } + euicc_it = eid_euicc_info_map_.erase(euicc_it); + } +} + +void ESimManager::RemoveUntrackedProfiles(EuiccInfo* euicc_info) { + for (auto it = iccid_esim_profile_info_map_.begin(); + it != iccid_esim_profile_info_map_.end();) { + ESimProfileInfo* profile_info = it->second.get(); + const std::string& iccid = it->first; + if (profile_info->esim_profile()->eid == euicc_info->euicc()->eid && + !euicc_info->ContainsIccid(iccid)) { + it = iccid_esim_profile_info_map_.erase(it); + } else { + it++; + } + } +} + +ESimManager::EuiccInfo* ESimManager::GetOrCreateEuiccInfo( + HermesEuiccClient::Properties* properties, + const dbus::ObjectPath& euicc_path) { + EuiccInfo* euicc_info = GetEuiccInfoFromPath(euicc_path); + if (euicc_info) + return euicc_info; + const std::string& eid = properties->eid().value(); + eid_euicc_info_map_[eid] = + std::make_unique<EuiccInfo>(euicc_path, properties); + return eid_euicc_info_map_[eid].get(); +} + +ESimManager::ESimProfileInfo* ESimManager::GetOrCreateESimProfileInfo( + HermesProfileClient::Properties* properties, + const dbus::ObjectPath& carrier_profile_path, + const std::string& eid) { + ESimProfileInfo* profile_info = GetProfileInfoFromPath(carrier_profile_path); + if (profile_info) + return profile_info; + const std::string& iccid = properties->iccid().value(); + iccid_esim_profile_info_map_[iccid] = + std::make_unique<ESimProfileInfo>(carrier_profile_path, eid, properties); + return iccid_esim_profile_info_map_[iccid].get(); +} + +ESimManager::EuiccInfo* ESimManager::GetEuiccInfoFromPath( + const dbus::ObjectPath& path) { + for (auto& pair : eid_euicc_info_map_) { + if (pair.second->path() == path) { + return eid_euicc_info_map_[pair.first].get(); + } + } + return nullptr; +} + +ESimManager::ESimProfileInfo* ESimManager::GetProfileInfoFromPath( + const dbus::ObjectPath& path) { + for (auto& pair : iccid_esim_profile_info_map_) { + if (pair.second->path() == path) { + return pair.second.get(); + } + } + return nullptr; +} + +mojom::ESimManager::ProfileInstallResult +ESimManager::GetPendingProfileInfoFromActivationCode( + const std::string& eid, + const std::string& activation_code, + ESimProfileInfo** profile_info) { + const auto iter = std::find_if( + iccid_esim_profile_info_map_.begin(), iccid_esim_profile_info_map_.end(), + [activation_code](const auto& pair) -> bool { + return pair.second->esim_profile()->activation_code == activation_code; + }); + if (iter == iccid_esim_profile_info_map_.end()) { + NET_LOG(EVENT) << "Get pending profile with activation failed: No profile " + "with activation_code."; + return ProfileInstallResult::kFailure; + } + *profile_info = iter->second.get(); + if (iter->second->esim_profile()->state != mojom::ProfileState::kPending || + iter->second->esim_profile()->eid != eid) { + NET_LOG(ERROR) << "Get pending profile with activation code failed: Profile" + "is not in pending state or EID does not match."; + return ProfileInstallResult::kFailure; + } + return ProfileInstallResult::kSuccess; +} + +ESimManager::ESimProfileInfo* ESimManager::GetPendingProfileInfoFromIccid( + const std::string& iccid) { + if (!iccid_esim_profile_info_map_.count(iccid)) { + NET_LOG(ERROR) << "Get pending profile with iccid failed: Unknown ICCID."; + return nullptr; + } + mojom::ESimProfile* profile = + iccid_esim_profile_info_map_[iccid]->esim_profile(); + if (profile->state != mojom::ProfileState::kPending) { + NET_LOG(ERROR) << "Get pending profile with iccid failed: Profile is " + "already installed or installing."; + return nullptr; + } + return iccid_esim_profile_info_map_[iccid].get(); +} + +ESimManager::ESimProfileInfo* ESimManager::GetInstalledProfileInfoFromIccid( + const std::string& iccid) { + if (!iccid_esim_profile_info_map_.count(iccid)) { + NET_LOG(ERROR) << "Get installed profile with iccid failed: Unknown iccid."; + return nullptr; + } + + mojom::ProfileState state = + iccid_esim_profile_info_map_[iccid]->esim_profile()->state; + if (state == mojom::ProfileState::kInstalling || + state == mojom::ProfileState::kPending) { + NET_LOG(ERROR) << "Get installed profile with iccid failed. Invalid state=" + << state; + return nullptr; + } + + return iccid_esim_profile_info_map_[iccid].get(); +} + +} // namespace cellular_setup +} // namespace chromeos
diff --git a/chromeos/services/cellular_setup/esim_manager.h b/chromeos/services/cellular_setup/esim_manager.h new file mode 100644 index 0000000..29a3d333 --- /dev/null +++ b/chromeos/services/cellular_setup/esim_manager.h
@@ -0,0 +1,177 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROMEOS_SERVICES_CELLULAR_SETUP_ESIM_MANAGER_H_ +#define CHROMEOS_SERVICES_CELLULAR_SETUP_ESIM_MANAGER_H_ + +#include "base/memory/weak_ptr.h" +#include "chromeos/dbus/hermes/hermes_euicc_client.h" +#include "chromeos/dbus/hermes/hermes_manager_client.h" +#include "chromeos/dbus/hermes/hermes_profile_client.h" +#include "chromeos/services/cellular_setup/public/mojom/esim_manager.mojom.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" +#include "mojo/public/cpp/bindings/pending_remote.h" +#include "mojo/public/cpp/bindings/receiver_set.h" +#include "mojo/public/cpp/bindings/remote_set.h" + +namespace chromeos { +namespace cellular_setup { + +// Implementation of mojom::ESimManager. This class uses the Hermes +// DBus clients to communicate with the Hermes daemon and provide +// eSIM management methods. ESimManager mojo interface is provided +// in WebUI for cellular settings and eSIM setup. +class ESimManager : public mojom::ESimManager, + HermesManagerClient::Observer, + HermesEuiccClient::Observer, + HermesProfileClient::Observer { + public: + ESimManager(); + ESimManager(const ESimManager&) = delete; + ESimManager& operator=(const ESimManager&) = delete; + ~ESimManager() override; + + void BindReceiver(mojo::PendingReceiver<mojom::ESimManager> receiver); + + // mojom::ESimManager + void AddObserver( + mojo::PendingRemote<mojom::ESimManagerObserver> observer) override; + void GetAvailableEuiccs(GetAvailableEuiccsCallback callback) override; + void GetProfiles(const std::string& eid, + GetProfilesCallback callback) override; + void RequestPendingProfiles(const std::string& eid, + RequestPendingProfilesCallback callback) override; + void InstallProfileFromActivationCode( + const std::string& eid, + const std::string& activation_code, + const std::string& confirmation_code, + InstallProfileFromActivationCodeCallback callback) override; + void InstallProfile(const std::string& iccid, + const std::string& confirmation_code, + InstallProfileCallback callback) override; + void UninstallProfile(const std::string& iccid, + UninstallProfileCallback callback) override; + void EnableProfile(const std::string& iccid, + EnableProfileCallback callback) override; + void DisableProfile(const std::string& iccid, + DisableProfileCallback callback) override; + void SetProfileNickname(const std::string& iccid, + const base::string16& nickname, + SetProfileNicknameCallback callback) override; + + // HermesManagerClient::Observer: + void OnAvailableEuiccListChanged() override; + + // HermesEuiccClient::Observer: + void OnEuiccPropertyChanged(const dbus::ObjectPath& euicc_path, + const std::string& property_name) override; + + // HermesProfileClient::Observer: + void OnCarrierProfilePropertyChanged( + const dbus::ObjectPath& carrier_profile_path, + const std::string& property_name) override; + + private: + // EuiccInfo object is used to track state of Hermes Euicc objects. + // It holds mojom::Euicc object along with other related values. + class EuiccInfo { + public: + EuiccInfo(const dbus::ObjectPath& path, + HermesEuiccClient::Properties* properties); + ~EuiccInfo(); + + // Returns a boolean indicating whether |iccid| exists + // in installed or pending profiles for this Euicc. + bool ContainsIccid(const std::string& iccid); + void CopyProperties(HermesEuiccClient::Properties* properties); + mojom::Euicc* euicc() { return euicc_.get(); } + const dbus::ObjectPath& path() { return path_; } + void set_profile_iccids(const std::set<std::string>& profile_iccids) { + profile_iccids_ = std::move(profile_iccids); + } + const std::set<std::string>& profile_iccids() { return profile_iccids_; } + + private: + mojom::EuiccPtr euicc_; + dbus::ObjectPath path_; + std::set<std::string> profile_iccids_; + }; + + // ESimProfileInfo is used to track state of Hermes Profile objects. + // It holds mojom::ESimProfile object along with other related values. + class ESimProfileInfo { + public: + ESimProfileInfo(const dbus::ObjectPath& path, + const std::string& eid, + HermesProfileClient::Properties* properties); + ~ESimProfileInfo(); + + void CopyProperties(HermesProfileClient::Properties* properties); + mojom::ESimProfile* esim_profile() { return esim_profile_.get(); } + const dbus::ObjectPath& path() { return path_; } + + private: + mojom::ESimProfilePtr esim_profile_; + dbus::ObjectPath path_; + }; + + // Type of callback for profile installation methods. + using ProfileInstallResultCallback = + base::OnceCallback<void(mojom::ESimManager::ProfileInstallResult, + mojom::ESimProfilePtr)>; + // Type of callback for other esim manager methods. + using ESimOperationResultCallback = + base::OnceCallback<void(mojom::ESimManager::ESimOperationResult)>; + + void CallInstallPendingProfile(ESimProfileInfo* profile_info, + const std::string& confirmation_code, + ProfileInstallResultCallback callback); + void OnRequestPendingEventsResult(RequestPendingProfilesCallback callback, + HermesResponseStatus status); + void OnPendingProfileInstallResult(ProfileInstallResultCallback callback, + ESimProfileInfo* profile_info, + HermesResponseStatus status); + void OnProfileInstallResult(ProfileInstallResultCallback callback, + const std::string& eid, + HermesResponseStatus status, + const dbus::ObjectPath* object_path); + void OnESimOperationResult(ESimOperationResultCallback callback, + HermesResponseStatus status); + void OnProfilePropertySet(ESimOperationResultCallback callback, bool success); + void UpdateAvailableEuiccs(); + void UpdateProfileList(EuiccInfo* euicc_info); + void RemoveUntrackedEuiccs(); + void RemoveUntrackedProfiles(EuiccInfo* euicc_info); + EuiccInfo* GetOrCreateEuiccInfo(HermesEuiccClient::Properties* properties, + const dbus::ObjectPath& euicc_path); + ESimProfileInfo* GetOrCreateESimProfileInfo( + HermesProfileClient::Properties* properties, + const dbus::ObjectPath& carrier_profile_path, + const std::string& eid); + EuiccInfo* GetEuiccInfoFromPath(const dbus::ObjectPath& path); + ESimProfileInfo* GetProfileInfoFromPath(const dbus::ObjectPath& path); + ProfileInstallResult GetPendingProfileInfoFromActivationCode( + const std::string& eid, + const std::string& activation_code, + ESimProfileInfo** profile_info); + ESimProfileInfo* GetPendingProfileInfoFromIccid(const std::string& iccid); + ESimProfileInfo* GetInstalledProfileInfoFromIccid(const std::string& iccid); + + HermesManagerClient* hermes_manager_client_; + HermesEuiccClient* hermes_euicc_client_; + HermesProfileClient* hermes_profile_client_; + std::set<std::string> available_euicc_eids_; + std::map<std::string, std::unique_ptr<EuiccInfo>> eid_euicc_info_map_; + std::map<std::string, std::unique_ptr<ESimProfileInfo>> + iccid_esim_profile_info_map_; + mojo::RemoteSet<mojom::ESimManagerObserver> observers_; + mojo::ReceiverSet<mojom::ESimManager> receivers_; + + base::WeakPtrFactory<ESimManager> weak_ptr_factory_{this}; +}; + +} // namespace cellular_setup +} // namespace chromeos + +#endif // CHROMEOS_SERVICES_CELLULAR_SETUP_ESIM_MANAGER_H_
diff --git a/chromeos/services/cellular_setup/esim_manager_unittest.cc b/chromeos/services/cellular_setup/esim_manager_unittest.cc new file mode 100644 index 0000000..557abe2 --- /dev/null +++ b/chromeos/services/cellular_setup/esim_manager_unittest.cc
@@ -0,0 +1,535 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromeos/services/cellular_setup/esim_manager.h" +#include "base/bind.h" +#include "base/strings/utf_string_conversions.h" +#include "base/test/task_environment.h" +#include "chromeos/dbus/hermes/hermes_clients.h" +#include "chromeos/dbus/hermes/hermes_manager_client.h" +#include "chromeos/dbus/shill/shill_clients.h" +#include "chromeos/dbus/shill/shill_manager_client.h" +#include "chromeos/services/cellular_setup/public/mojom/esim_manager.mojom.h" +#include "mojo/public/cpp/bindings/pending_remote.h" +#include "mojo/public/cpp/bindings/receiver.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/cros_system_api/dbus/hermes/dbus-constants.h" + +namespace chromeos { +namespace cellular_setup { + +namespace { +const char* kTestEuiccPath = "/org/chromium/Hermes/Euicc/0"; +const char* kTestEid = "12345678901234567890123456789012"; + +void CopyESimProfileList( + std::vector<mojom::ESimProfilePtr>* dest, + base::OnceClosure quit_closure, + base::Optional<std::vector<mojom::ESimProfilePtr>> esim_profiles) { + if (esim_profiles) { + for (auto& euicc : *esim_profiles) + dest->push_back(std::move(euicc)); + } + std::move(quit_closure).Run(); +} + +void CopyInstallResult(mojom::ESimManager::ProfileInstallResult* result_dest, + mojom::ESimProfilePtr* esim_profile_dest, + base::OnceClosure quit_closure, + mojom::ESimManager::ProfileInstallResult result, + mojom::ESimProfilePtr esim_profile) { + *result_dest = result; + *esim_profile_dest = std::move(esim_profile); + std::move(quit_closure).Run(); +} + +void CopyOperationResult(mojom::ESimManager::ESimOperationResult* result_dest, + base::OnceClosure quit_closure, + mojom::ESimManager::ESimOperationResult result) { + *result_dest = result; + std::move(quit_closure).Run(); +} + +} // namespace + +// Fake observer for testing ESimManager. +class ESimManagerTestObserver : public mojom::ESimManagerObserver { + public: + ESimManagerTestObserver() = default; + ESimManagerTestObserver(const ESimManagerTestObserver&) = delete; + ESimManagerTestObserver& operator=(const ESimManagerTestObserver&) = delete; + ~ESimManagerTestObserver() override = default; + + // mojom::ESimManagerObserver: + void OnAvailableEuiccListChanged() override { + available_euicc_list_change_count_++; + } + void OnProfileListChanged(const std::string& eid) override { + profile_list_change_calls_.push_back(eid); + } + void OnEuiccChanged(mojom::EuiccPtr euicc) override { + euicc_change_calls_.push_back(std::move(euicc)); + } + void OnProfileChanged(mojom::ESimProfilePtr esim_profile) override { + profile_change_calls_.push_back(std::move(esim_profile)); + } + + mojo::PendingRemote<mojom::ESimManagerObserver> GenerateRemote() { + return receiver_.BindNewPipeAndPassRemote(); + } + + void Reset() { + available_euicc_list_change_count_ = 0; + profile_list_change_calls_.clear(); + euicc_change_calls_.clear(); + profile_change_calls_.clear(); + } + + int available_euicc_list_change_count() { + return available_euicc_list_change_count_; + } + + const std::vector<std::string>& profile_list_change_calls() { + return profile_list_change_calls_; + } + + const std::vector<mojom::EuiccPtr>& euicc_change_calls() { + return euicc_change_calls_; + } + + const std::vector<mojom::ESimProfilePtr>& profile_change_calls() { + return profile_change_calls_; + } + + private: + int available_euicc_list_change_count_ = 0; + std::vector<std::string> profile_list_change_calls_; + std::vector<mojom::EuiccPtr> euicc_change_calls_; + std::vector<mojom::ESimProfilePtr> profile_change_calls_; + mojo::Receiver<mojom::ESimManagerObserver> receiver_{this}; +}; + +class ESimManagerTest : public testing::Test { + public: + using InstallResultPair = std::pair<mojom::ESimManager::ProfileInstallResult, + mojom::ESimProfilePtr>; + + ESimManagerTest() { + if (!ShillManagerClient::Get()) + shill_clients::InitializeFakes(); + if (!HermesManagerClient::Get()) + hermes_clients::InitializeFakes(); + } + ESimManagerTest(const ESimManagerTest&) = delete; + ESimManagerTest& operator=(const ESimManagerTest&) = delete; + ~ESimManagerTest() override = default; + + void SetUp() override { + HermesManagerClient::Get()->GetTestInterface()->ClearEuiccs(); + HermesEuiccClient::Get()->GetTestInterface()->SetInteractiveDelay( + base::TimeDelta::FromSeconds(0)); + esim_manager_ = std::make_unique<ESimManager>(); + observer_ = std::make_unique<ESimManagerTestObserver>(); + esim_manager_->AddObserver(observer_->GenerateRemote()); + } + + void TearDown() override { + esim_manager_.reset(); + observer_.reset(); + HermesEuiccClient::Get()->GetTestInterface()->ResetPendingEventsRequested(); + } + + void SetupEuicc() { + HermesManagerClient::Get()->GetTestInterface()->AddEuicc( + dbus::ObjectPath(kTestEuiccPath), kTestEid, true); + base::RunLoop().RunUntilIdle(); + } + + std::vector<mojom::EuiccPtr> GetAvailableEuiccs() { + std::vector<mojom::EuiccPtr> result; + base::RunLoop run_loop; + esim_manager_->GetAvailableEuiccs(base::BindOnce( + [](std::vector<mojom::EuiccPtr>* result, base::OnceClosure quit_closure, + std::vector<mojom::EuiccPtr> available_euiccs) { + for (auto& euicc : available_euiccs) + result->push_back(std::move(euicc)); + std::move(quit_closure).Run(); + }, + &result, run_loop.QuitClosure())); + run_loop.Run(); + return result; + } + + std::vector<mojom::ESimProfilePtr> GetProfiles(const std::string& eid) { + std::vector<mojom::ESimProfilePtr> result; + base::RunLoop run_loop; + esim_manager_->GetProfiles( + eid, + base::BindOnce(&CopyESimProfileList, &result, run_loop.QuitClosure())); + run_loop.Run(); + return result; + } + + mojom::ESimManager::ESimOperationResult RequestPendingProfiles( + const std::string& eid) { + mojom::ESimManager::ESimOperationResult result; + base::RunLoop run_loop; + esim_manager_->RequestPendingProfiles( + eid, base::BindOnce( + [](mojom::ESimManager::ESimOperationResult* result, + base::OnceClosure quit_closure, + mojom::ESimManager::ESimOperationResult status) { + *result = status; + std::move(quit_closure).Run(); + }, + &result, run_loop.QuitClosure())); + run_loop.Run(); + return result; + } + + InstallResultPair InstallProfileFromActivationCode( + const std::string& eid, + const std::string& activation_code, + const std::string& confirmation_code) { + base::RunLoop run_loop; + mojom::ESimManager::ProfileInstallResult result; + mojom::ESimProfilePtr esim_profile; + esim_manager_->InstallProfileFromActivationCode( + eid, activation_code, confirmation_code, + base::BindOnce(&CopyInstallResult, &result, &esim_profile, + run_loop.QuitClosure())); + run_loop.Run(); + return std::make_pair(result, std::move(esim_profile)); + } + + InstallResultPair InstallProfile(const std::string& iccid, + const std::string& confirmation_code) { + base::RunLoop run_loop; + mojom::ESimManager::ProfileInstallResult result; + mojom::ESimProfilePtr esim_profile; + esim_manager_->InstallProfile( + iccid, confirmation_code, + base::BindOnce(&CopyInstallResult, &result, &esim_profile, + run_loop.QuitClosure())); + run_loop.Run(); + return std::make_pair(result, std::move(esim_profile)); + } + + mojom::ESimManager::ESimOperationResult UninstallProfile( + const std::string& iccid) { + base::RunLoop run_loop; + mojom::ESimManager::ESimOperationResult result; + esim_manager_->UninstallProfile( + iccid, + base::BindOnce(&CopyOperationResult, &result, run_loop.QuitClosure())); + run_loop.Run(); + return result; + } + + mojom::ESimManager::ESimOperationResult EnableProfile( + const std::string& iccid) { + base::RunLoop run_loop; + mojom::ESimManager::ESimOperationResult result; + esim_manager_->EnableProfile( + iccid, + base::BindOnce(&CopyOperationResult, &result, run_loop.QuitClosure())); + run_loop.Run(); + return result; + } + + mojom::ESimManager::ESimOperationResult DisableProfile( + const std::string& iccid) { + base::RunLoop run_loop; + mojom::ESimManager::ESimOperationResult result; + esim_manager_->DisableProfile( + iccid, + base::BindOnce(&CopyOperationResult, &result, run_loop.QuitClosure())); + run_loop.Run(); + return result; + } + + mojom::ESimManager::ESimOperationResult SetProfileNickname( + const std::string& iccid, + const base::string16& nickname) { + base::RunLoop run_loop; + mojom::ESimManager::ESimOperationResult result; + esim_manager_->SetProfileNickname( + iccid, nickname, + base::BindOnce(&CopyOperationResult, &result, run_loop.QuitClosure())); + run_loop.Run(); + return result; + } + + ESimManager* esim_manager() { return esim_manager_.get(); } + ESimManagerTestObserver* observer() { return observer_.get(); } + + private: + base::test::SingleThreadTaskEnvironment task_environment_; + std::unique_ptr<ESimManager> esim_manager_; + std::unique_ptr<ESimManagerTestObserver> observer_; +}; + +TEST_F(ESimManagerTest, GetAvailableEuiccs) { + ASSERT_EQ(0u, GetAvailableEuiccs().size()); + // Verify that Euicc List change is notified to observer when a + // a new Euicc is setup. + SetupEuicc(); + EXPECT_EQ(1, observer()->available_euicc_list_change_count()); + // Verify that GetAvailableEuiccs call returns list of euiccs. + std::vector<mojom::EuiccPtr> available_euiccs = GetAvailableEuiccs(); + ASSERT_EQ(1u, available_euiccs.size()); + EXPECT_EQ(kTestEid, available_euiccs.front()->eid); +} + +TEST_F(ESimManagerTest, GetProfiles) { + SetupEuicc(); + HermesEuiccClient::TestInterface* euicc_test = + HermesEuiccClient::Get()->GetTestInterface(); + dbus::ObjectPath active_profile_path = euicc_test->AddFakeCarrierProfile( + dbus::ObjectPath(kTestEuiccPath), hermes::profile::State::kActive, ""); + dbus::ObjectPath pending_profile_path = euicc_test->AddFakeCarrierProfile( + dbus::ObjectPath(kTestEuiccPath), hermes::profile::State::kPending, ""); + base::RunLoop().RunUntilIdle(); + HermesProfileClient::Properties* active_profile_properties = + HermesProfileClient::Get()->GetProperties(active_profile_path); + HermesProfileClient::Properties* pending_profile_properties = + HermesProfileClient::Get()->GetProperties(pending_profile_path); + // Verify the profile list change is notified to observer. + ASSERT_EQ(2u, observer()->profile_list_change_calls().size()); + EXPECT_EQ(kTestEid, observer()->profile_list_change_calls().at(0)); + EXPECT_EQ(kTestEid, observer()->profile_list_change_calls().at(1)); + // Verify that the added profile is returned in installed list. + std::vector<mojom::ESimProfilePtr> profile_list = GetProfiles(kTestEid); + ASSERT_EQ(2u, profile_list.size()); + EXPECT_EQ(active_profile_properties->iccid().value(), + profile_list.at(0)->iccid); + EXPECT_EQ(pending_profile_properties->iccid().value(), + profile_list.at(1)->iccid); +} + +TEST_F(ESimManagerTest, RequestPendingProfiles) { + SetupEuicc(); + HermesEuiccClient::TestInterface* euicc_test = + HermesEuiccClient::Get()->GetTestInterface(); + // Verify that pending profile request errors are return properly. + euicc_test->QueueHermesErrorStatus(HermesResponseStatus::kErrorNoResponse); + mojom::ESimManager::ESimOperationResult result = + RequestPendingProfiles(kTestEid); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(mojom::ESimManager::ESimOperationResult::kFailure, result); + EXPECT_EQ(0u, observer()->profile_list_change_calls().size()); + + // Verify that successful request notifies observers and returns correct + // status code. + result = RequestPendingProfiles(kTestEid); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(mojom::ESimManager::ESimOperationResult::kSuccess, result); + EXPECT_EQ(kTestEid, observer()->profile_list_change_calls().front()); +} + +TEST_F(ESimManagerTest, InstallProfileFromActivationCode) { + SetupEuicc(); + HermesEuiccClient::TestInterface* euicc_test = + HermesEuiccClient::Get()->GetTestInterface(); + // Verify that install errors return error code properly. + euicc_test->QueueHermesErrorStatus( + HermesResponseStatus::kErrorInvalidActivationCode); + InstallResultPair result_pair = + InstallProfileFromActivationCode(kTestEid, "", ""); + EXPECT_EQ( + mojom::ESimManager::ProfileInstallResult::kErrorInvalidActivationCode, + result_pair.first); + EXPECT_EQ(nullptr, result_pair.second.get()); + + // Verify that installing a profile returns proper status code + // and profile object. + dbus::ObjectPath profile_path = euicc_test->AddFakeCarrierProfile( + dbus::ObjectPath(kTestEuiccPath), hermes::profile::State::kPending, ""); + base::RunLoop().RunUntilIdle(); + HermesProfileClient::Properties* properties = + HermesProfileClient::Get()->GetProperties(profile_path); + result_pair = InstallProfileFromActivationCode( + kTestEid, properties->activation_code().value(), ""); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(mojom::ESimManager::ProfileInstallResult::kSuccess, + result_pair.first); + ASSERT_NE(nullptr, result_pair.second.get()); + EXPECT_EQ(properties->iccid().value(), result_pair.second->iccid); + EXPECT_EQ(3u, observer()->profile_list_change_calls().size()); +} + +TEST_F(ESimManagerTest, InstallProfile) { + SetupEuicc(); + HermesEuiccClient::TestInterface* euicc_test = + HermesEuiccClient::Get()->GetTestInterface(); + dbus::ObjectPath profile_path = euicc_test->AddFakeCarrierProfile( + dbus::ObjectPath(kTestEuiccPath), hermes::profile::State::kPending, ""); + base::RunLoop().RunUntilIdle(); + HermesProfileClient::Properties* properties = + HermesProfileClient::Get()->GetProperties(profile_path); + + // Verify that install errors return error code properly. + euicc_test->QueueHermesErrorStatus( + HermesResponseStatus::kErrorNeedConfirmationCode); + InstallResultPair result_pair = + InstallProfile(properties->iccid().value(), ""); + EXPECT_EQ( + mojom::ESimManager::ProfileInstallResult::kErrorNeedsConfirmationCode, + result_pair.first); + EXPECT_EQ(nullptr, result_pair.second.get()); + + // Verify that installing pending profile returns proper results. + result_pair = InstallProfile(properties->iccid().value(), ""); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(mojom::ESimManager::ProfileInstallResult::kSuccess, + result_pair.first); + ASSERT_NE(nullptr, result_pair.second.get()); + ASSERT_EQ(properties->iccid().value(), result_pair.second->iccid); + EXPECT_EQ(3u, observer()->profile_list_change_calls().size()); +} + +TEST_F(ESimManagerTest, UninstallProfile) { + SetupEuicc(); + HermesEuiccClient::TestInterface* euicc_test = + HermesEuiccClient::Get()->GetTestInterface(); + dbus::ObjectPath active_profile_path = euicc_test->AddFakeCarrierProfile( + dbus::ObjectPath(kTestEuiccPath), hermes::profile::State::kActive, ""); + dbus::ObjectPath pending_profile_path = euicc_test->AddFakeCarrierProfile( + dbus::ObjectPath(kTestEuiccPath), hermes::profile::State::kPending, ""); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(2u, observer()->profile_list_change_calls().size()); + observer()->Reset(); + HermesProfileClient::Properties* pending_profile_properties = + HermesProfileClient::Get()->GetProperties(pending_profile_path); + HermesProfileClient::Properties* active_profile_properties = + HermesProfileClient::Get()->GetProperties(active_profile_path); + + // Verify that uninstall error codes are returned properly. + euicc_test->QueueHermesErrorStatus( + HermesResponseStatus::kErrorInvalidResponse); + mojom::ESimManager::ESimOperationResult result = + UninstallProfile(active_profile_properties->iccid().value()); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(mojom::ESimManager::ESimOperationResult::kFailure, result); + EXPECT_EQ(0u, observer()->profile_list_change_calls().size()); + + // Verify that pending profiles cannot be uninstalled + observer()->Reset(); + result = UninstallProfile(pending_profile_properties->iccid().value()); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(mojom::ESimManager::ESimOperationResult::kFailure, result); + EXPECT_EQ(0u, observer()->profile_list_change_calls().size()); + + // Verify that uninstall removes the profile and notifies observers properly. + observer()->Reset(); + result = UninstallProfile(active_profile_properties->iccid().value()); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(mojom::ESimManager::ESimOperationResult::kSuccess, result); + ASSERT_EQ(1u, observer()->profile_list_change_calls().size()); + EXPECT_EQ(kTestEid, observer()->profile_list_change_calls().front()); +} + +TEST_F(ESimManagerTest, EnableProfile) { + SetupEuicc(); + HermesEuiccClient::TestInterface* euicc_test = + HermesEuiccClient::Get()->GetTestInterface(); + dbus::ObjectPath inactive_profile_path = euicc_test->AddFakeCarrierProfile( + dbus::ObjectPath(kTestEuiccPath), hermes::profile::State::kInactive, ""); + dbus::ObjectPath pending_profile_path = euicc_test->AddFakeCarrierProfile( + dbus::ObjectPath(kTestEuiccPath), hermes::profile::State::kPending, ""); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(2u, observer()->profile_list_change_calls().size()); + observer()->Reset(); + HermesProfileClient::Properties* pending_profile_properties = + HermesProfileClient::Get()->GetProperties(pending_profile_path); + HermesProfileClient::Properties* inactive_profile_properties = + HermesProfileClient::Get()->GetProperties(inactive_profile_path); + + // Verify that pending profiles cannot be enabled. + mojom::ESimManager::ESimOperationResult result = + EnableProfile(pending_profile_properties->iccid().value()); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(mojom::ESimManager::ESimOperationResult::kFailure, result); + EXPECT_EQ(0u, observer()->profile_change_calls().size()); + + // Verify that enabling profile returns result properly. + result = EnableProfile(inactive_profile_properties->iccid().value()); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(mojom::ESimManager::ESimOperationResult::kSuccess, result); + EXPECT_EQ(inactive_profile_properties->iccid().value(), + observer()->profile_change_calls().front()->iccid); + EXPECT_EQ(mojom::ProfileState::kActive, + observer()->profile_change_calls().front()->state); +} + +TEST_F(ESimManagerTest, DisableProfile) { + SetupEuicc(); + HermesEuiccClient::TestInterface* euicc_test = + HermesEuiccClient::Get()->GetTestInterface(); + dbus::ObjectPath active_profile_path = euicc_test->AddFakeCarrierProfile( + dbus::ObjectPath(kTestEuiccPath), hermes::profile::State::kActive, ""); + dbus::ObjectPath pending_profile_path = euicc_test->AddFakeCarrierProfile( + dbus::ObjectPath(kTestEuiccPath), hermes::profile::State::kPending, ""); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(2u, observer()->profile_list_change_calls().size()); + observer()->Reset(); + HermesProfileClient::Properties* pending_profile_properties = + HermesProfileClient::Get()->GetProperties(pending_profile_path); + HermesProfileClient::Properties* active_profile_properties = + HermesProfileClient::Get()->GetProperties(active_profile_path); + + // Verify that pending profiles cannot be disabled. + mojom::ESimManager::ESimOperationResult result = + DisableProfile(pending_profile_properties->iccid().value()); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(mojom::ESimManager::ESimOperationResult::kFailure, result); + EXPECT_EQ(0u, observer()->profile_change_calls().size()); + + // Verify that disabling profile returns result properly. + result = DisableProfile(active_profile_properties->iccid().value()); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(mojom::ESimManager::ESimOperationResult::kSuccess, result); + EXPECT_EQ(active_profile_properties->iccid().value(), + observer()->profile_change_calls().front()->iccid); + EXPECT_EQ(mojom::ProfileState::kInactive, + observer()->profile_change_calls().front()->state); +} + +TEST_F(ESimManagerTest, SetProfileNickName) { + const base::string16 test_nickname = base::UTF8ToUTF16("Test nickname"); + SetupEuicc(); + HermesEuiccClient::TestInterface* euicc_test = + HermesEuiccClient::Get()->GetTestInterface(); + dbus::ObjectPath active_profile_path = euicc_test->AddFakeCarrierProfile( + dbus::ObjectPath(kTestEuiccPath), hermes::profile::State::kActive, ""); + dbus::ObjectPath pending_profile_path = euicc_test->AddFakeCarrierProfile( + dbus::ObjectPath(kTestEuiccPath), hermes::profile::State::kPending, ""); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(2u, observer()->profile_list_change_calls().size()); + observer()->Reset(); + HermesProfileClient::Properties* pending_profile_properties = + HermesProfileClient::Get()->GetProperties(pending_profile_path); + HermesProfileClient::Properties* active_profile_properties = + HermesProfileClient::Get()->GetProperties(active_profile_path); + + // Verify that pending profiles cannot be modified. + mojom::ESimManager::ESimOperationResult result = SetProfileNickname( + pending_profile_properties->iccid().value(), test_nickname); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(mojom::ESimManager::ESimOperationResult::kFailure, result); + EXPECT_EQ(0u, observer()->profile_change_calls().size()); + + // Verify that nickname can be set on active profiles. + result = SetProfileNickname(active_profile_properties->iccid().value(), + test_nickname); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(mojom::ESimManager::ESimOperationResult::kSuccess, result); + EXPECT_EQ(active_profile_properties->iccid().value(), + observer()->profile_change_calls().front()->iccid); + EXPECT_EQ(test_nickname, + observer()->profile_change_calls().front()->nickname); +} + +} // namespace cellular_setup +} // namespace chromeos
diff --git a/chromeos/services/cellular_setup/in_process_esim_manager.cc b/chromeos/services/cellular_setup/in_process_esim_manager.cc new file mode 100644 index 0000000..7782829 --- /dev/null +++ b/chromeos/services/cellular_setup/in_process_esim_manager.cc
@@ -0,0 +1,20 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromeos/services/cellular_setup/in_process_esim_manager.h" + +#include "base/no_destructor.h" +#include "chromeos/services/cellular_setup/esim_manager.h" + +namespace chromeos { +namespace cellular_setup { + +void BindToInProcessESimManager( + mojo::PendingReceiver<mojom::ESimManager> receiver) { + static base::NoDestructor<ESimManager> instance; + instance->BindReceiver(std::move(receiver)); +} + +} // namespace cellular_setup +} // namespace chromeos
diff --git a/chromeos/services/cellular_setup/in_process_esim_manager.h b/chromeos/services/cellular_setup/in_process_esim_manager.h new file mode 100644 index 0000000..b61cffd --- /dev/null +++ b/chromeos/services/cellular_setup/in_process_esim_manager.h
@@ -0,0 +1,22 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROMEOS_SERVICES_CELLULAR_SETUP_IN_PROCESS_ESIM_MANAGER_H_ +#define CHROMEOS_SERVICES_CELLULAR_SETUP_IN_PROCESS_ESIM_MANAGER_H_ + +#include "base/component_export.h" +#include "chromeos/services/cellular_setup/public/mojom/esim_manager.mojom.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" + +namespace chromeos { +namespace cellular_setup { + +COMPONENT_EXPORT(IN_PROCESS_ESIM_MANAGER) +void BindToInProcessESimManager( + mojo::PendingReceiver<mojom::ESimManager> receiver); + +} // namespace cellular_setup +} // namespace chromeos + +#endif // CHROMEOS_SERVICES_CELLULAR_SETUP_IN_PROCESS_ESIM_MANAGER_H_
diff --git a/chromeos/services/cellular_setup/public/mojom/BUILD.gn b/chromeos/services/cellular_setup/public/mojom/BUILD.gn index 25824e8..ff06cdb0 100644 --- a/chromeos/services/cellular_setup/public/mojom/BUILD.gn +++ b/chromeos/services/cellular_setup/public/mojom/BUILD.gn
@@ -5,7 +5,13 @@ import("//mojo/public/tools/bindings/mojom.gni") mojom("mojom") { - sources = [ "cellular_setup.mojom" ] + sources = [ + "cellular_setup.mojom", + "esim_manager.mojom", + ] - public_deps = [ "//url/mojom:url_mojom_gurl" ] + public_deps = [ + "//mojo/public/mojom/base", + "//url/mojom:url_mojom_gurl", + ] }
diff --git a/chromeos/services/cellular_setup/public/mojom/esim_manager.mojom b/chromeos/services/cellular_setup/public/mojom/esim_manager.mojom new file mode 100644 index 0000000..cd1f69a --- /dev/null +++ b/chromeos/services/cellular_setup/public/mojom/esim_manager.mojom
@@ -0,0 +1,133 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module chromeos.cellular_setup.mojom; + +import "mojo/public/mojom/base/string16.mojom"; + +// Represents the current state of an ESimProfile +enum ProfileState { + kPending, // Profile is not installed on the device. + kInstalling, // Profile is being installed. + kInactive, // Profile is installed but inactive. + kActive, // Profile is installed and active. +}; + +// Represents an EUICC (Embedded Universal Integrated Circuit Card) hardware +// available on the device. Each Euicc may have multiple ESimProfiles +// installed on it. +struct Euicc { + // A 32 digit unique id for the Euicc. + string eid; + // Boolean indicating whether the Euicc is active or not. + bool is_active; +}; + +// Represents an eSIM profile. +struct ESimProfile { + // EID of the Euicc in which this profile is installed or available for + // installation. + string eid; + // A 19-20 character long numeric id that uniquely identifies this profile. + string iccid; + // Service provider’s name for this profile. e.g. “Verizon Plan 1” + mojo_base.mojom.String16 name; + // A user configurable nickname for this profile. e.g. “My Personal SIM” + mojo_base.mojom.String16 nickname; + // Name of the service provider. e.g. “Verizon Wireless” + mojo_base.mojom.String16 service_provider; + // State of the profile + ProfileState state; + // An alphanumeric code that can be used to install this profile. + string activation_code; +}; + +// ESimManagerObserver is implemented by any module that +// needs to observe changes to the eSIM module. +interface ESimManagerObserver { + // Called when a new Euicc is added or removed from the system. + OnAvailableEuiccListChanged(); + + // Called when a new eSIM profile is added or removed to the + // Euicc with the given |eid|. + OnProfileListChanged(string eid); + + // Called when an Euicc object's active state changes. + OnEuiccChanged(Euicc euicc); + + // Called when an eSIM profile’s state or nickname changes. + OnProfileChanged(ESimProfile profile); +}; + +// ESimManager interface provides eSIM profile management methods. An instance +// of this interface is owned in the browser process in Ash. It will be +// accessed from WebUI or System UI code in the browser process. +interface ESimManager { + // Result codes for profile installation. + enum ProfileInstallResult { + kSuccess, // Installation succeeded. + kFailure, // Installation failed. + kErrorNeedsConfirmationCode, // Installation requires a valid + // confirmation code. + kErrorInvalidActivationCode, // Given activation code is invalid. + }; + + // Result code for ESimManager methods. + enum ESimOperationResult { + kSuccess, // Operation succeeded. + kFailure // Operation failed. + }; + + // Adds an observer for eSIM changes. + AddObserver(pending_remote<ESimManagerObserver> observer); + + // Returns a list of Euiccs available on the device. + GetAvailableEuiccs() => (array<Euicc> euiccs); + + // Returns a list of all profiles installed or pending on the Euicc + // with given |eid|. An empty list could be returned if there are + // no installed or pending profiles on the Euicc. + GetProfiles(string eid) => (array<ESimProfile>? profiles); + + // Starts a request for pending profiles for the Euicc with given |eid| + // from SMDS. Returns a status indicating result of the operation. This + // method updates the pending profiles list before succeeding. This method + // is used to allow the user to explicit trigger a request to check for + // new profiles that may have been pushed to SMDS. + RequestPendingProfiles(string eid) => (ESimOperationResult result); + + // Installs a profile with given |activation_code| on the Euicc with + // given |eid| and returns the ESimProfile that was just installed. A + // non-success result code is returned in case of errors. |activation_code| + // may be obtained from ESimProfiles retrieved with a previous call to + // GetPendingProfiles or directly from the user through a QR code. If + // |confirmation_code| is required but not supplied or if it’s invalid + // then a kErrorNeedsConfirmationCode result is returned. + InstallProfileFromActivationCode(string eid, string activation_code, + string confirmation_code) => + (ProfileInstallResult result, ESimProfile? profile); + + // Installs an eSIM profile given it’s |iccid| and returns the + // ESimProfile that was just installed. A non success result code + // is returned in case of errors. + InstallProfile(string iccid, string confirmation_code) => + (ProfileInstallResult result, ESimProfile? profile); + + // Uninstalls an eSIM profile given it’s |iccid|. Returns the result + // code for the operation. + UninstallProfile(string iccid) => (ESimOperationResult result); + + // Enables an eSIM profile with the given |iccid|. Returns the result + // code for the operation. + EnableProfile(string iccid) => (ESimOperationResult result); + + // Disables an eSIM profile with the given |iccid|. Returns the result + // code for the operation. + DisableProfile(string iccid) => (ESimOperationResult result); + + // Sets a nickname for an eSIM profile with given |iccid|. Returns the + // result code for the operation. + SetProfileNickname(string iccid, mojo_base.mojom.String16 nickname) => + (ESimOperationResult result); +};
diff --git a/components/BUILD.gn b/components/BUILD.gn index a346ea32..a62f7464 100644 --- a/components/BUILD.gn +++ b/components/BUILD.gn
@@ -236,6 +236,7 @@ "//components/content_settings/browser:unit_tests", "//components/contextual_search/core:unit_tests", "//components/data_use_measurement/core:unit_tests", + "//components/discardable_memory/client:unit_tests", "//components/discardable_memory/common:unit_tests", "//components/discardable_memory/service:unit_tests", "//components/dom_distiller/content/browser:unit_tests",
diff --git a/components/autofill/core/browser/data_model/autofill_profile.cc b/components/autofill/core/browser/data_model/autofill_profile.cc index 8c17a36..0a08f4b 100644 --- a/components/autofill/core/browser/data_model/autofill_profile.cc +++ b/components/autofill/core/browser/data_model/autofill_profile.cc
@@ -568,7 +568,18 @@ // values. std::string language_code_value = language_code(); std::string origin_value = origin(); - base::string16 name_full_value = GetRawInfo(NAME_FULL); + + // Structured names should not be simply overwritten but it should be + // attempted to merge the names. + bool use_structured_name = base::FeatureList::IsEnabled( + features::kAutofillEnableSupportForMoreStructureInNames); + bool is_structured_name_mergeable = false; + NameInfo name_info = GetNameInfo(); + if (use_structured_name) { + is_structured_name_mergeable = + name_info.IsStructuredNameMergeable(profile.GetNameInfo()); + name_info.MergeStructuredName(profile.GetNameInfo()); + } *this = profile; @@ -576,8 +587,23 @@ set_origin(origin_value); if (language_code().empty()) set_language_code(language_code_value); - if (!HasRawInfo(NAME_FULL)) - SetRawInfo(NAME_FULL, name_full_value); + + // For structured names, use the merged name if possible. + if (is_structured_name_mergeable) { + name_ = name_info; + return; + } + // For structured names, if the full name of |profile| is empty, maintain the + // complete name structure. Note, this should only happen if the complete name + // is empty. For the legacy implementation, set the full name if |profile| + // does not contain a full name. + if (!HasRawInfo(NAME_FULL)) { + if (use_structured_name) { + name_ = name_info; + } else { + SetRawInfo(NAME_FULL, name_info.GetRawInfo(NAME_FULL)); + } + } } bool AutofillProfile::MergeDataFrom(const AutofillProfile& profile, @@ -1209,31 +1235,53 @@ } std::ostream& operator<<(std::ostream& os, const AutofillProfile& profile) { - return os << (profile.record_type() == AutofillProfile::LOCAL_PROFILE - ? profile.guid() - : base::HexEncode(profile.server_id().data(), - profile.server_id().size())) - << " " << profile.origin() << " " - << UTF16ToUTF8(profile.GetRawInfo(NAME_FULL)) << " " - << UTF16ToUTF8(profile.GetRawInfo(NAME_FIRST)) << " " - << UTF16ToUTF8(profile.GetRawInfo(NAME_MIDDLE)) << " " - << UTF16ToUTF8(profile.GetRawInfo(NAME_LAST)) << " " - << UTF16ToUTF8(profile.GetRawInfo(EMAIL_ADDRESS)) << " " - << UTF16ToUTF8(profile.GetRawInfo(COMPANY_NAME)) << " " - << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE1)) << " " - << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE2)) << " " - << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE3)) << " " - << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY)) - << " " << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_CITY)) << " " - << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_STATE)) << " " - << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_ZIP)) << " " - << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_SORTING_CODE)) << " " - << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_COUNTRY)) << " " - << profile.language_code() << " " - << UTF16ToUTF8(profile.GetRawInfo(PHONE_HOME_WHOLE_NUMBER)) << " " - << profile.GetClientValidityBitfieldValue() << " " - << profile.has_converted() << " " << profile.use_count() << " " - << profile.use_date(); + return os + << (profile.record_type() == AutofillProfile::LOCAL_PROFILE + ? profile.guid() + : base::HexEncode(profile.server_id().data(), + profile.server_id().size())) + << " " << profile.origin() << " " + << UTF16ToUTF8(profile.GetRawInfo(NAME_FULL)) << " " + << "(" + << base::NumberToString(profile.GetVerificationStatusInt(NAME_FULL)) + << ") " << UTF16ToUTF8(profile.GetRawInfo(NAME_FIRST)) << " " + << "(" + << base::NumberToString(profile.GetVerificationStatusInt(NAME_FIRST)) + << ") " << UTF16ToUTF8(profile.GetRawInfo(NAME_MIDDLE)) << " " + << "(" + << base::NumberToString(profile.GetVerificationStatusInt(NAME_MIDDLE)) + << ") " << UTF16ToUTF8(profile.GetRawInfo(NAME_LAST)) << " " + << "(" + << base::NumberToString(profile.GetVerificationStatusInt(NAME_LAST)) + << ") " << UTF16ToUTF8(profile.GetRawInfo(NAME_LAST_FIRST)) << " " + << "(" + << base::NumberToString( + profile.GetVerificationStatusInt(NAME_LAST_FIRST)) + << ") " << UTF16ToUTF8(profile.GetRawInfo(NAME_LAST_CONJUNCTION)) + << " " + << "(" + << base::NumberToString( + profile.GetVerificationStatusInt(NAME_LAST_CONJUNCTION)) + << ") " << UTF16ToUTF8(profile.GetRawInfo(NAME_LAST_SECOND)) << " " + << "(" + << base::NumberToString( + profile.GetVerificationStatusInt(NAME_LAST_SECOND)) + << ") " << UTF16ToUTF8(profile.GetRawInfo(EMAIL_ADDRESS)) << " " + << UTF16ToUTF8(profile.GetRawInfo(COMPANY_NAME)) << " " + << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE1)) << " " + << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE2)) << " " + << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE3)) << " " + << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY)) + << " " << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_CITY)) << " " + << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_STATE)) << " " + << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_ZIP)) << " " + << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_SORTING_CODE)) << " " + << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_COUNTRY)) << " " + << profile.language_code() << " " + << UTF16ToUTF8(profile.GetRawInfo(PHONE_HOME_WHOLE_NUMBER)) << " " + << profile.GetClientValidityBitfieldValue() << " " + << profile.has_converted() << " " << profile.use_count() << " " + << profile.use_date(); } bool AutofillProfile::FinalizeAfterImport() {
diff --git a/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc b/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc index fa8e2d9..947d71e6 100644 --- a/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc +++ b/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc
@@ -11,6 +11,7 @@ #include "base/bind.h" #include "base/bind_helpers.h" +#include "base/feature_list.h" #include "base/files/scoped_temp_dir.h" #include "base/guid.h" #include "base/location.h" @@ -18,6 +19,7 @@ #include "base/run_loop.h" #include "base/strings/utf_string_conversions.h" #include "base/test/bind_test_util.h" +#include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" #include "base/time/time.h" #include "components/autofill/core/browser/autofill_profile_sync_util.h" @@ -28,6 +30,7 @@ #include "components/autofill/core/browser/webdata/autofill_table.h" #include "components/autofill/core/browser/webdata/mock_autofill_webdata_backend.h" #include "components/autofill/core/common/autofill_constants.h" +#include "components/autofill/core/common/autofill_features.h" #include "components/sync/base/client_tag_hash.h" #include "components/sync/model/data_batch.h" #include "components/sync/model/data_type_activation_request.h" @@ -259,10 +262,10 @@ } // namespace -class AutofillProfileSyncBridgeTest : public testing::Test { +class AutofillProfileSyncBridgeTestBase : public testing::Test { public: - AutofillProfileSyncBridgeTest() {} - ~AutofillProfileSyncBridgeTest() override {} + AutofillProfileSyncBridgeTestBase() = default; + ~AutofillProfileSyncBridgeTestBase() override = default; void SetUp() override { // Fix a time for implicitly constructed use_dates in AutofillProfile. @@ -374,10 +377,40 @@ std::unique_ptr<syncer::ClientTagBasedModelTypeProcessor> real_processor_; std::unique_ptr<AutofillProfileSyncBridge> bridge_; - DISALLOW_COPY_AND_ASSIGN(AutofillProfileSyncBridgeTest); + DISALLOW_COPY_AND_ASSIGN(AutofillProfileSyncBridgeTestBase); }; -TEST_F(AutofillProfileSyncBridgeTest, AutofillProfileChanged_Added) { +// This class performs the sync bridge test with and without structured names +// enabled. +class AutofillProfileSyncBridgeTest : public AutofillProfileSyncBridgeTestBase, + public testing::WithParamInterface<bool> { + public: + void SetUp() override { + InitializeFeatures(); + AutofillProfileSyncBridgeTestBase::SetUp(); + } + + void InitializeFeatures() { + bool structured_names_enabled = GetParam(); + if (structured_names_enabled) { + scoped_features_.InitAndEnableFeature( + features::kAutofillEnableSupportForMoreStructureInNames); + } else { + scoped_features_.InitAndDisableFeature( + features::kAutofillEnableSupportForMoreStructureInNames); + } + } + + bool UsingStructuredNames() const { + return base::FeatureList::IsEnabled( + features::kAutofillEnableSupportForMoreStructureInNames); + } + + private: + base::test::ScopedFeatureList scoped_features_; +}; + +TEST_P(AutofillProfileSyncBridgeTest, AutofillProfileChanged_Added) { StartSyncing({}); AutofillProfile local(kGuidA, kHttpsOrigin); @@ -395,7 +428,7 @@ } // Language code in autofill profiles should be synced to the server. -TEST_F(AutofillProfileSyncBridgeTest, +TEST_P(AutofillProfileSyncBridgeTest, AutofillProfileChanged_Added_LanguageCodePropagates) { StartSyncing({}); @@ -414,7 +447,7 @@ } // Validity state bitfield in autofill profiles should be synced to the server. -TEST_F(AutofillProfileSyncBridgeTest, +TEST_P(AutofillProfileSyncBridgeTest, AutofillProfileChanged_Added_LocalValidityBitfieldPropagates) { StartSyncing({}); @@ -433,7 +466,7 @@ } // Local updates should be properly propagated to the server. -TEST_F(AutofillProfileSyncBridgeTest, AutofillProfileChanged_Updated) { +TEST_P(AutofillProfileSyncBridgeTest, AutofillProfileChanged_Updated) { StartSyncing({}); AutofillProfile local(kGuidA, kHttpsOrigin); @@ -451,7 +484,7 @@ } // Usage stats should be updated by the client. -TEST_F(AutofillProfileSyncBridgeTest, +TEST_P(AutofillProfileSyncBridgeTest, AutofillProfileChanged_Updated_UsageStatsOverwrittenByClient) { // Remote data has a profile with usage stats. AutofillProfileSpecifics remote = @@ -482,7 +515,7 @@ } // Server profile updates should be ignored. -TEST_F(AutofillProfileSyncBridgeTest, +TEST_P(AutofillProfileSyncBridgeTest, AutofillProfileChanged_Updated_IgnoreServerProfiles) { StartSyncing({}); @@ -495,7 +528,7 @@ bridge()->AutofillProfileChanged(change); } -TEST_F(AutofillProfileSyncBridgeTest, AutofillProfileChanged_Deleted) { +TEST_P(AutofillProfileSyncBridgeTest, AutofillProfileChanged_Deleted) { StartSyncing({}); AutofillProfile local(kGuidB, kHttpsOrigin); @@ -510,7 +543,7 @@ } // Server profile updates should be ignored. -TEST_F(AutofillProfileSyncBridgeTest, +TEST_P(AutofillProfileSyncBridgeTest, AutofillProfileChanged_Deleted_IgnoreServerProfiles) { StartSyncing({}); @@ -523,7 +556,7 @@ bridge()->AutofillProfileChanged(change); } -TEST_F(AutofillProfileSyncBridgeTest, GetAllDataForDebugging) { +TEST_P(AutofillProfileSyncBridgeTest, GetAllDataForDebugging) { AutofillProfile local1 = AutofillProfile(kGuidA, kHttpsOrigin); local1.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John")); local1.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st")); @@ -535,7 +568,7 @@ EXPECT_THAT(GetAllLocalData(), UnorderedElementsAre(local1, local2)); } -TEST_F(AutofillProfileSyncBridgeTest, GetData) { +TEST_P(AutofillProfileSyncBridgeTest, GetData) { AutofillProfile local1 = AutofillProfile(kGuidA, kHttpsOrigin); local1.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John")); local1.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st")); @@ -558,25 +591,35 @@ EXPECT_THAT(data, ElementsAre(local1)); } -TEST_F(AutofillProfileSyncBridgeTest, MergeSyncData) { +TEST_P(AutofillProfileSyncBridgeTest, MergeSyncData) { AutofillProfile local1 = AutofillProfile(kGuidA, kHttpOrigin); local1.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John")); local1.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st")); + AutofillProfile local2 = AutofillProfile(kGuidB, std::string()); local2.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Tom")); local2.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("2 2nd st")); + AddAutofillProfilesToTable({local1, local2}); - AutofillProfileSpecifics remote1 = - CreateAutofillProfileSpecifics(kGuidC, kHttpsOrigin); - remote1.add_name_first("Jane"); - AutofillProfileSpecifics remote2 = - CreateAutofillProfileSpecifics(kGuidD, kSettingsOrigin); - remote2.add_name_first("Harry"); - // This one will have the name and origin updated. - AutofillProfileSpecifics remote3 = - CreateAutofillProfileSpecifics(kGuidB, kSettingsOrigin); - remote3.add_name_first("Tom Doe"); + AutofillProfile remote1 = AutofillProfile(kGuidC, kHttpOrigin); + remote1.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Jane")); + remote1.FinalizeAfterImport(); + + AutofillProfile remote2 = AutofillProfile(kGuidD, kSettingsOrigin); + remote2.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Harry")); + remote2.FinalizeAfterImport(); + + AutofillProfile remote3 = AutofillProfile(kGuidB, kSettingsOrigin); + remote3.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Tom Doe")); + remote3.FinalizeAfterImport(); + + AutofillProfileSpecifics remote1_specifics = + CreateAutofillProfileSpecifics(remote1); + AutofillProfileSpecifics remote2_specifics = + CreateAutofillProfileSpecifics(remote2); + AutofillProfileSpecifics remote3_specifics = + CreateAutofillProfileSpecifics(remote3); EXPECT_CALL( mock_processor(), @@ -584,17 +627,20 @@ EXPECT_CALL(mock_processor(), Delete(_, _)).Times(0); EXPECT_CALL(*backend(), CommitChanges()); - StartSyncing({remote1, remote2, remote3}); + StartSyncing({remote1_specifics, remote2_specifics, remote3_specifics}); - EXPECT_THAT(GetAllLocalData(), - UnorderedElementsAre(local1, CreateAutofillProfile(remote1), - CreateAutofillProfile(remote2), - CreateAutofillProfile(remote3))); + // Since |local2| and |remote3| have the same GUID, data from |remote3| is + // incorporated into the local profile which is mostly a replace operation. + EXPECT_THAT( + GetAllLocalData(), + UnorderedElementsAre(local1, CreateAutofillProfile(remote1_specifics), + CreateAutofillProfile(remote2_specifics), + CreateAutofillProfile(remote3_specifics))); } // Ensure that all profile fields are able to be synced up from the client to // the server. -TEST_F(AutofillProfileSyncBridgeTest, MergeSyncData_SyncAllFieldsToServer) { +TEST_P(AutofillProfileSyncBridgeTest, MergeSyncData_SyncAllFieldsToServer) { AutofillProfile local = ConstructCompleteProfile(); AddAutofillProfilesToTable({local}); @@ -611,7 +657,7 @@ // Ensure that all profile fields are able to be synced down from the server to // the client (and nothing gets uploaded back). -TEST_F(AutofillProfileSyncBridgeTest, MergeSyncData_SyncAllFieldsToClient) { +TEST_P(AutofillProfileSyncBridgeTest, MergeSyncData_SyncAllFieldsToClient) { EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); EXPECT_CALL(*backend(), CommitChanges()); StartSyncing({ConstructCompleteSpecifics()}); @@ -620,41 +666,50 @@ ElementsAre(WithUsageStats(ConstructCompleteProfile()))); } -TEST_F(AutofillProfileSyncBridgeTest, MergeSyncData_IdenticalProfiles) { +TEST_P(AutofillProfileSyncBridgeTest, MergeSyncData_IdenticalProfiles) { AutofillProfile local1 = AutofillProfile(kGuidA, kHttpOrigin); local1.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John")); local1.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st")); + AutofillProfile local2 = AutofillProfile(kGuidB, kSettingsOrigin); local2.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Tom")); local2.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("2 2nd st")); + AddAutofillProfilesToTable({local1, local2}); // The synced profiles are identical to the local ones, except that the guids // are different. - AutofillProfileSpecifics remote1 = - CreateAutofillProfileSpecifics(kGuidC, kHttpsOrigin); - remote1.add_name_first("John"); - remote1.set_address_home_street_address("1 1st st"); - AutofillProfileSpecifics remote2 = - CreateAutofillProfileSpecifics(kGuidD, kHttpsOrigin); - remote2.add_name_first("Tom"); - remote2.set_address_home_street_address("2 2nd st"); + + AutofillProfile remote1 = AutofillProfile(kGuidC, kHttpsOrigin); + remote1.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John")); + remote1.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st")); + remote1.FinalizeAfterImport(); + + AutofillProfile remote2 = AutofillProfile(kGuidD, kHttpsOrigin); + remote2.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Tom")); + remote2.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("2 2nd st")); + remote2.FinalizeAfterImport(); + + AutofillProfileSpecifics remote1_specifics = + CreateAutofillProfileSpecifics(remote1); + AutofillProfileSpecifics remote2_specifics = + CreateAutofillProfileSpecifics(remote2); // Both remote profiles win, only the verified origin is taken over for the // second profile. - AutofillProfileSpecifics merged2(remote2); + AutofillProfileSpecifics merged2(remote2_specifics); merged2.set_origin(kSettingsOrigin); EXPECT_CALL(mock_processor(), Put(kGuidD, HasSpecifics(merged2), _)); EXPECT_CALL(*backend(), CommitChanges()); - StartSyncing({remote1, remote2}); + StartSyncing({remote1_specifics, remote2_specifics}); EXPECT_THAT(GetAllLocalData(), - UnorderedElementsAre(CreateAutofillProfile(remote1), + UnorderedElementsAre(CreateAutofillProfile(remote1_specifics), CreateAutofillProfile(merged2))); } -TEST_F(AutofillProfileSyncBridgeTest, MergeSyncData_NonSimilarProfiles) { +TEST_P(AutofillProfileSyncBridgeTest, MergeSyncData_NonSimilarProfiles) { AutofillProfile local = ConstructCompleteProfile(); local.set_guid(kGuidA); local.SetRawInfo(NAME_FULL, ASCIIToUTF16("John K. Doe, Jr.")); @@ -687,39 +742,57 @@ UnorderedElementsAre(local, CreateAutofillProfile(remote))); } -TEST_F(AutofillProfileSyncBridgeTest, MergeSyncData_SimilarProfiles) { +TEST_P(AutofillProfileSyncBridgeTest, MergeSyncData_SimilarProfiles) { AutofillProfile local1 = AutofillProfile(kGuidA, kHttpOrigin); local1.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John")); local1.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st")); + local1.FinalizeAfterImport(); local1.set_use_count(27); + AutofillProfile local2 = AutofillProfile(kGuidB, kSettingsOrigin); local2.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Tom")); local2.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("2 2nd st")); + local2.FinalizeAfterImport(); AddAutofillProfilesToTable({local1, local2}); // The synced profiles are identical to the local ones, except that the guids // and use_count values are different. Remote ones have additional company // name which makes them not be identical. - AutofillProfileSpecifics remote1 = - CreateAutofillProfileSpecifics(kGuidC, kHttpsOrigin); - remote1.add_name_first("John"); - remote1.set_address_home_street_address("1 1st st"); - remote1.set_company_name("Frobbers, Inc."); + AutofillProfile remote1 = AutofillProfile(kGuidC, kHttpOrigin); + remote1.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John")); + remote1.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st")); + remote1.SetRawInfo(COMPANY_NAME, ASCIIToUTF16("Frobbers, Inc.")); + // Note, this populates the full name for structured profiles. + remote1.FinalizeAfterImport(); remote1.set_use_count(13); - AutofillProfileSpecifics remote2 = - CreateAutofillProfileSpecifics(kGuidD, kHttpsOrigin); - remote2.add_name_first("Tom"); - remote2.set_address_home_street_address("2 2nd st"); - remote2.set_company_name("Fizzbang, LLC."); + + AutofillProfile remote2 = AutofillProfile(kGuidD, kHttpOrigin); + remote2.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Tom")); + remote2.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("2 2nd st")); + remote2.SetRawInfo(COMPANY_NAME, ASCIIToUTF16("Fizzbang, LLC.")); + remote2.FinalizeAfterImport(); remote2.set_use_count(4); + AutofillProfileSpecifics remote1_specifics = + CreateAutofillProfileSpecifics(remote1); + AutofillProfileSpecifics remote2_specifics = + CreateAutofillProfileSpecifics(remote2); + // The first profile should have its origin updated. // The second profile should remain as-is, because an unverified profile // should never overwrite a verified one. - AutofillProfileSpecifics merged1(remote1); + AutofillProfileSpecifics merged1(remote1_specifics); merged1.set_origin(kHttpOrigin); - // When merging, full name gets populated. - merged1.add_name_full("John"); + // For the legacy implementation, the full name field gets popluated by the + // merging operation and must be added to the expectation. + // For structured names, the full name is already populated by calling + // |FinalizeAfterImport()|. + if (UsingStructuredNames()) { + ASSERT_GT(merged1.name_full_size(), 0); + ASSERT_EQ(merged1.name_full(0), "John"); + } else { + merged1.set_name_full(0, "John"); + } // Merging two profile takes their max use count. merged1.set_use_count(27); @@ -731,17 +804,17 @@ EXPECT_CALL(mock_processor(), Delete(_, _)).Times(0); EXPECT_CALL(*backend(), CommitChanges()); - StartSyncing({remote1, remote2}); + StartSyncing({remote1_specifics, remote2_specifics}); EXPECT_THAT(GetAllLocalData(), UnorderedElementsAre( WithUsageStats(CreateAutofillProfile(merged1)), local2, - WithUsageStats(CreateAutofillProfile(remote2)))); + WithUsageStats(CreateAutofillProfile(remote2_specifics)))); } // Tests that MergeSimilarProfiles keeps the most recent use date of the two // profiles being merged. -TEST_F(AutofillProfileSyncBridgeTest, +TEST_P(AutofillProfileSyncBridgeTest, MergeSyncData_SimilarProfiles_OlderUseDate) { // Different guids, same origin, difference in the phone number. AutofillProfile local(kGuidA, kHttpOrigin); @@ -766,7 +839,7 @@ // Tests that MergeSimilarProfiles keeps the most recent use date of the two // profiles being merged. -TEST_F(AutofillProfileSyncBridgeTest, +TEST_P(AutofillProfileSyncBridgeTest, MergeSyncData_SimilarProfiles_NewerUseDate) { // Different guids, same origin, difference in the phone number. AutofillProfile local(kGuidA, kHttpOrigin); @@ -790,7 +863,7 @@ // Tests that MergeSimilarProfiles saves the max of the use counts of the two // profiles in |remote|. -TEST_F(AutofillProfileSyncBridgeTest, +TEST_P(AutofillProfileSyncBridgeTest, MergeSyncData_SimilarProfiles_NonZeroUseCounts) { // Different guids, same origin, difference in the phone number. AutofillProfile local(kGuidA, kHttpOrigin); @@ -814,21 +887,23 @@ // Tests that when merging similar profiles for initial sync, we add the // additional information of |local| into |remote|. -TEST_F(AutofillProfileSyncBridgeTest, +TEST_P(AutofillProfileSyncBridgeTest, MergeSyncData_SimilarProfiles_LocalOriginPreserved) { AutofillProfile local(kGuidA, kHttpsOrigin); local.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("650234567")); AddAutofillProfilesToTable({local}); + AutofillProfile remote_profile = AutofillProfile(kGuidB, kHttpOrigin); + remote_profile.FinalizeAfterImport(); AutofillProfileSpecifics remote = - CreateAutofillProfileSpecifics(kGuidB, kHttpOrigin); + CreateAutofillProfileSpecifics(remote_profile); remote.set_address_home_language_code("en"); // Expect that the resulting merged profile is written back to sync and that // it has the phone number and origin from |local|. AutofillProfileSpecifics merged(remote); merged.set_origin(kHttpsOrigin); - merged.add_phone_home_whole_number("650234567"); + merged.set_phone_home_whole_number(0, "650234567"); // TODO(jkrcal): Is this expected that language code gets deleted? Not // explicitly covered by previous tests but happens. merged.set_address_home_language_code(""); @@ -840,7 +915,7 @@ // Sync data without origin should not overwrite existing origin in local // autofill profile. -TEST_F(AutofillProfileSyncBridgeTest, +TEST_P(AutofillProfileSyncBridgeTest, MergeSyncData_SimilarProfiles_LocalExistingOriginPreserved) { AutofillProfile local(kGuidA, kHttpsOrigin); AddAutofillProfilesToTable({local}); @@ -866,16 +941,19 @@ // Ensure that no Sync events are generated to fill in missing origins from Sync // with explicitly present empty ones. This ensures that the migration to add // origins to profiles does not generate lots of needless Sync updates. -TEST_F(AutofillProfileSyncBridgeTest, +TEST_P(AutofillProfileSyncBridgeTest, MergeSyncData_SimilarProfiles_LocalMissingOriginPreserved) { AutofillProfile local = AutofillProfile(kGuidA, std::string()); local.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John")); AddAutofillProfilesToTable({local}); // Create a Sync profile identical to |local|, except with no origin set. - AutofillProfileSpecifics remote = CreateAutofillProfileSpecifics(kGuidA, ""); + AutofillProfile remote_profile = AutofillProfile(kGuidA, ""); + remote_profile.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John")); + remote_profile.FinalizeAfterImport(); + AutofillProfileSpecifics remote = + CreateAutofillProfileSpecifics(remote_profile); remote.clear_origin(); - remote.add_name_first("John"); ASSERT_FALSE(remote.has_origin()); EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); @@ -884,15 +962,17 @@ EXPECT_THAT(GetAllLocalData(), ElementsAre(local)); } -TEST_F(AutofillProfileSyncBridgeTest, ApplySyncChanges) { +TEST_P(AutofillProfileSyncBridgeTest, ApplySyncChanges) { AutofillProfile local = AutofillProfile(kGuidA, kHttpsOrigin); AddAutofillProfilesToTable({local}); StartSyncing({}); + AutofillProfile remote_profile = AutofillProfile(kGuidB, kHttpOrigin); + remote_profile.SetRawInfo(NAME_FIRST, base::ASCIIToUTF16("Jane")); + remote_profile.FinalizeAfterImport(); AutofillProfileSpecifics remote = - CreateAutofillProfileSpecifics(kGuidB, kHttpOrigin); - remote.add_name_first("Jane"); + CreateAutofillProfileSpecifics(remote_profile); EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); EXPECT_CALL(mock_processor(), Delete(_, _)).Times(0); @@ -908,7 +988,7 @@ } // Ensure that entries with invalid specifics are ignored. -TEST_F(AutofillProfileSyncBridgeTest, ApplySyncChanges_OmitsInvalidSpecifics) { +TEST_P(AutofillProfileSyncBridgeTest, ApplySyncChanges_OmitsInvalidSpecifics) { StartSyncing({}); AutofillProfileSpecifics remote_valid = @@ -932,7 +1012,7 @@ // Verifies that setting the street address field also sets the (deprecated) // address line 1 and line 2 fields. -TEST_F(AutofillProfileSyncBridgeTest, StreetAddress_SplitAutomatically) { +TEST_P(AutofillProfileSyncBridgeTest, StreetAddress_SplitAutomatically) { AutofillProfile local; local.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("123 Example St.\n" "Apt. 42")); @@ -951,7 +1031,7 @@ // Verifies that setting the (deprecated) address line 1 and line 2 fields also // sets the street address. -TEST_F(AutofillProfileSyncBridgeTest, StreetAddress_JointAutomatically) { +TEST_P(AutofillProfileSyncBridgeTest, StreetAddress_JointAutomatically) { AutofillProfile local; local.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("123 Example St.")); local.SetRawInfo(ADDRESS_HOME_LINE2, ASCIIToUTF16("Apt. 42")); @@ -969,7 +1049,7 @@ // Ensure that the street address field takes precedence over the (deprecated) // address line 1 and line 2 fields, even though these are expected to always be // in sync in practice. -TEST_F(AutofillProfileSyncBridgeTest, +TEST_P(AutofillProfileSyncBridgeTest, RemoteWithSameGuid_StreetAddress_TakesPrecedenceOverAddressLines) { // Create remote entry with conflicting address data in the street address // field vs. the address line 1 and address line 2 fields. @@ -999,7 +1079,7 @@ // the line1 and line2 fields. This ensures that the migration to add the // street address field to profiles does not generate lots of needless Sync // updates. -TEST_F(AutofillProfileSyncBridgeTest, +TEST_P(AutofillProfileSyncBridgeTest, RemoteWithSameGuid_StreetAddress_NoUpdateToEmptyStreetAddressSyncedUp) { AutofillProfile local(kGuidA, kHttpsOrigin); local.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("123 Example St.\n" @@ -1021,7 +1101,7 @@ } // Missing language code field should not generate sync events. -TEST_F(AutofillProfileSyncBridgeTest, +TEST_P(AutofillProfileSyncBridgeTest, RemoteWithSameGuid_LanguageCode_MissingCodesNoSync) { AutofillProfile local(kGuidA, kHttpsOrigin); ASSERT_TRUE(local.language_code().empty()); @@ -1040,7 +1120,7 @@ } // Empty language code should be overwritten by sync. -TEST_F(AutofillProfileSyncBridgeTest, +TEST_P(AutofillProfileSyncBridgeTest, RemoteWithSameGuid_LanguageCode_ExistingRemoteWinsOverMissingLocal) { AutofillProfile local(kGuidA, kHttpsOrigin); ASSERT_TRUE(local.language_code().empty()); @@ -1059,7 +1139,7 @@ } // Local language code should be overwritten by remote one. -TEST_F(AutofillProfileSyncBridgeTest, +TEST_P(AutofillProfileSyncBridgeTest, RemoteWithSameGuid_LanguageCode_ExistingRemoteWinsOverExistingLocal) { AutofillProfile local(kGuidA, kHttpsOrigin); local.set_language_code("de"); @@ -1079,7 +1159,7 @@ // Sync data without language code should not overwrite existing language code // in local autofill profile. -TEST_F(AutofillProfileSyncBridgeTest, +TEST_P(AutofillProfileSyncBridgeTest, RemoteWithSameGuid_LanguageCode_ExistingLocalWinsOverMissingRemote) { // Local autofill profile has "en" language code. AutofillProfile local(kGuidA, kHttpsOrigin); @@ -1087,14 +1167,17 @@ AddAutofillProfilesToTable({local}); // Remote data does not have a language code value. + AutofillProfile remote_profile = AutofillProfile(kGuidA, kHttpsOrigin); + remote_profile.SetRawInfo(NAME_FIRST, base::ASCIIToUTF16("John")); + remote_profile.FinalizeAfterImport(); AutofillProfileSpecifics remote = - CreateAutofillProfileSpecifics(kGuidA, kHttpsOrigin); - remote.add_name_first("John"); - ASSERT_FALSE(remote.has_address_home_language_code()); + CreateAutofillProfileSpecifics(remote_profile); + ASSERT_TRUE(remote.address_home_language_code().empty()); // Expect local autofill profile to still have "en" language code after AutofillProfile merged(local); merged.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John")); + merged.FinalizeAfterImport(); // No update to sync, remote language code overwrites the local one. EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); @@ -1104,7 +1187,7 @@ } // Missing validity state bitifield should not generate sync events. -TEST_F(AutofillProfileSyncBridgeTest, +TEST_P(AutofillProfileSyncBridgeTest, RemoteWithSameGuid_ValidityState_DefaultValueNoSync) { AutofillProfile local(kGuidA, kHttpsOrigin); ASSERT_EQ(0, local.GetClientValidityBitfieldValue()); @@ -1125,7 +1208,7 @@ } // Default validity state bitfield should be overwritten by sync. -TEST_F(AutofillProfileSyncBridgeTest, +TEST_P(AutofillProfileSyncBridgeTest, RemoteWithSameGuid_ValidityState_ExistingRemoteWinsOverMissingLocal) { AutofillProfile local(kGuidA, kHttpsOrigin); ASSERT_EQ(0, local.GetClientValidityBitfieldValue()); @@ -1145,7 +1228,7 @@ } // Local validity state bitfield should be overwritten by sync. -TEST_F(AutofillProfileSyncBridgeTest, +TEST_P(AutofillProfileSyncBridgeTest, RemoteWithSameGuid_ValidityState_ExistingRemoteWinsOverExistingLocal) { AutofillProfile local(kGuidA, kHttpsOrigin); local.SetClientValidityFromBitfieldValue(kValidityStateBitfield + 1); @@ -1166,7 +1249,7 @@ // Sync data without a default validity state bitfield should not overwrite // an existing validity state bitfield in local autofill profile. -TEST_F(AutofillProfileSyncBridgeTest, +TEST_P(AutofillProfileSyncBridgeTest, RemoteWithSameGuid_ValidityState_ExistingLocalWinsOverMissingRemote) { AutofillProfile local(kGuidA, kHttpsOrigin); local.SetClientValidityFromBitfieldValue(kValidityStateBitfield); @@ -1190,7 +1273,7 @@ } // Missing full name field should not generate sync events. -TEST_F(AutofillProfileSyncBridgeTest, +TEST_P(AutofillProfileSyncBridgeTest, RemoteWithSameGuid_FullName_MissingValueNoSync) { // Local autofill profile has an empty full name. AutofillProfile local(kGuidA, kHttpsOrigin); @@ -1209,27 +1292,64 @@ EXPECT_THAT(GetAllLocalData(), ElementsAre(local)); } -TEST_F(AutofillProfileSyncBridgeTest, +// This test verifies that for the legacy implementation of names, the full name +// is maintained from the local profile. +// However, this is not a valid use case for structured names as name structures +// must be either merged or fully maintained. For structured names, this test +// verifies that the names are merged. +TEST_P(AutofillProfileSyncBridgeTest, RemoteWithSameGuid_FullName_ExistingLocalWinsOverMissingRemote) { // Local autofill profile has a full name. AutofillProfile local(kGuidA, kHttpsOrigin); - local.SetRawInfo(NAME_FULL, ASCIIToUTF16("John Jacob Smith, Jr")); + local.SetRawInfoWithVerificationStatus( + NAME_FULL, ASCIIToUTF16("John Jacob Smith"), + structured_address::VerificationStatus::kObserved); + local.FinalizeAfterImport(); AddAutofillProfilesToTable({local}); + if (UsingStructuredNames()) { + // After finalization, the first, middle and last name should have the + // status |kParsed|. + ASSERT_EQ(local.GetVerificationStatus(NAME_FIRST), + structured_address::VerificationStatus::kParsed); + ASSERT_EQ(local.GetVerificationStatus(NAME_MIDDLE), + structured_address::VerificationStatus::kParsed); + ASSERT_EQ(local.GetVerificationStatus(NAME_LAST), + structured_address::VerificationStatus::kParsed); + } + // Remote data does not have a full name value. + AutofillProfile remote_profile = AutofillProfile(kGuidA, kHttpsOrigin); + remote_profile.SetRawInfoWithVerificationStatus( + NAME_FIRST, base::ASCIIToUTF16("John"), + structured_address::VerificationStatus::kObserved); + remote_profile.SetRawInfoWithVerificationStatus( + NAME_MIDDLE, base::ASCIIToUTF16("Jacob"), + structured_address::VerificationStatus::kObserved); + remote_profile.SetRawInfoWithVerificationStatus( + NAME_LAST, base::ASCIIToUTF16("Smith"), + structured_address::VerificationStatus::kObserved); + remote_profile.FinalizeAfterImport(); AutofillProfileSpecifics remote = - CreateAutofillProfileSpecifics(kGuidA, kHttpsOrigin); - remote.add_name_first(std::string("John")); - remote.add_name_middle(std::string("Jacob")); - remote.add_name_last(std::string("Smith")); + CreateAutofillProfileSpecifics(remote_profile); // Expect local autofill profile to still have the same full name after. AutofillProfile merged(local); - merged.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John")); - merged.SetRawInfo(NAME_MIDDLE, ASCIIToUTF16("Jacob")); - merged.SetRawInfo(NAME_LAST, ASCIIToUTF16("Smith")); - // No update to sync, no change in local data. + // Note, for structured names, the verification status of those tokens is + // |kParsed| for local and becomes |kObserved| when merged with the remote + // profile. + merged.SetRawInfoWithVerificationStatus( + NAME_FIRST, base::ASCIIToUTF16("John"), + structured_address::VerificationStatus::kObserved); + merged.SetRawInfoWithVerificationStatus( + NAME_MIDDLE, base::ASCIIToUTF16("Jacob"), + structured_address::VerificationStatus::kObserved); + merged.SetRawInfoWithVerificationStatus( + NAME_LAST, base::ASCIIToUTF16("Smith"), + structured_address::VerificationStatus::kObserved); + + // No update to sync, merged changes in local data. EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0); EXPECT_CALL(*backend(), CommitChanges()); StartSyncing({remote}); @@ -1237,7 +1357,7 @@ } // Missing use_count/use_date fields should not generate sync events. -TEST_F(AutofillProfileSyncBridgeTest, +TEST_P(AutofillProfileSyncBridgeTest, RemoteWithSameGuid_UsageStats_MissingValueNoSync) { // Local autofill profile has 0 for use_count/use_date. AutofillProfile local(kGuidA, kHttpsOrigin); @@ -1270,7 +1390,7 @@ }; class AutofillProfileSyncBridgeUpdatesUsageStatsTest - : public AutofillProfileSyncBridgeTest, + : public AutofillProfileSyncBridgeTestBase, public testing::WithParamInterface<UpdatesUsageStatsTestCase> { public: AutofillProfileSyncBridgeUpdatesUsageStatsTest() {} @@ -1314,6 +1434,9 @@ EXPECT_THAT(GetAllLocalData(), ElementsAre(WithUsageStats(merged))); } +// Test the sync bridge with and without structured names. +INSTANTIATE_TEST_SUITE_P(, AutofillProfileSyncBridgeTest, testing::Bool()); + INSTANTIATE_TEST_SUITE_P( AutofillProfileSyncBridgeTest, AutofillProfileSyncBridgeUpdatesUsageStatsTest,
diff --git a/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker.cc b/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker.cc index 005c0d1..6718b8c 100644 --- a/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker.cc +++ b/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker.cc
@@ -48,12 +48,24 @@ return base::nullopt; } updated->OverwriteDataFrom(*remote); - // TODO(jkrcal): if |updated| deviates from |remote|, we should sync it back - // up. The only way |updated| can differ is having some extra fields - // compared to |remote|. Thus, this cannot lead to an infinite loop of - // commits from two clients as each commit decreases the set of empty + // TODO(crbug.com/1117022l): if |updated| deviates from |remote|, we should + // sync it back up. The only way |updated| can differ is having some extra + // fields compared to |remote|. Thus, this cannot lead to an infinite loop + // of commits from two clients as each commit decreases the set of empty // fields. This invariant depends on the implementation of // OverwriteDataFrom() and thus should be enforced by a DCHECK. + // + // With structured names the situation changes a bit, + // but maintains its character. + // If the name stored in |remote| is mergeable with the local |name|, the + // merge operation is performed. Otherwise the name structure of |local| is + // maintained iff |remote| contains an empty name. + // A merge operations manipulates the name towards a better total + // verification status of the stored tokens. Consequently, it is not + // possible to get into a merging loop of two competing clients. + // As in the legacy implementation, |OverwriteDataForm()| can change the + // profile in a deterministic way and a direct sync-back would be + // reasonable. if (!updated->EqualsForSyncPurposes(*local_with_same_storage_key)) { // We need to write back locally new changes in this entry.
diff --git a/components/autofill/ios/browser/autofill_agent.mm b/components/autofill/ios/browser/autofill_agent.mm index fafe880b..c1a3936 100644 --- a/components/autofill/ios/browser/autofill_agent.mm +++ b/components/autofill/ios/browser/autofill_agent.mm
@@ -540,7 +540,8 @@ suggestionWithValue:value displayDescription:displayDescription icon:base::SysUTF8ToNSString(popup_suggestion.icon) - identifier:popup_suggestion.frontend_id]; + identifier:popup_suggestion.frontend_id + requiresReauth:NO]; // Put "clear form" entry at the front of the suggestions. if (popup_suggestion.frontend_id == autofill::POPUP_ITEM_ID_CLEAR_FORM) {
diff --git a/components/autofill/ios/browser/form_suggestion.h b/components/autofill/ios/browser/form_suggestion.h index 8fb6689..eca359cf 100644 --- a/components/autofill/ios/browser/form_suggestion.h +++ b/components/autofill/ios/browser/form_suggestion.h
@@ -24,11 +24,16 @@ // than zero are profile or credit card identifiers. @property(assign, readonly, nonatomic) NSInteger identifier; +// Indicates if the user should re-authenticate with the device before applying +// the suggestion. +@property(assign, readonly, nonatomic) BOOL requiresReauth; + // Returns FormSuggestion (immutable) with given values. + (FormSuggestion*)suggestionWithValue:(NSString*)value displayDescription:(NSString*)displayDescription icon:(NSString*)icon - identifier:(NSInteger)identifier; + identifier:(NSInteger)identifier + requiresReauth:(BOOL)requiresReauth; @end
diff --git a/components/autofill/ios/browser/form_suggestion.mm b/components/autofill/ios/browser/form_suggestion.mm index 4074e8e..dc9f63f 100644 --- a/components/autofill/ios/browser/form_suggestion.mm +++ b/components/autofill/ios/browser/form_suggestion.mm
@@ -8,31 +8,20 @@ #error "This file requires ARC support." #endif -@interface FormSuggestion () -// Local initializer for a FormSuggestion. -- (instancetype)initWithValue:(NSString*)value - displayDescription:(NSString*)displayDescription - icon:(NSString*)icon - identifier:(NSInteger)identifier; -@end - @implementation FormSuggestion -@synthesize value = _value; -@synthesize displayDescription = _displayDescription; -@synthesize icon = _icon; -@synthesize identifier = _identifier; - - (instancetype)initWithValue:(NSString*)value displayDescription:(NSString*)displayDescription icon:(NSString*)icon - identifier:(NSInteger)identifier { + identifier:(NSInteger)identifier + requiresReauth:(BOOL)requiresReauth { self = [super init]; if (self) { _value = [value copy]; _displayDescription = [displayDescription copy]; _icon = [icon copy]; _identifier = identifier; + _requiresReauth = requiresReauth; } return self; } @@ -40,11 +29,13 @@ + (FormSuggestion*)suggestionWithValue:(NSString*)value displayDescription:(NSString*)displayDescription icon:(NSString*)icon - identifier:(NSInteger)identifier { + identifier:(NSInteger)identifier + requiresReauth:(BOOL)requiresReauth { return [[FormSuggestion alloc] initWithValue:value displayDescription:displayDescription icon:icon - identifier:identifier]; + identifier:identifier + requiresReauth:requiresReauth]; } @end
diff --git a/components/autofill_assistant/browser/website_login_manager_impl.cc b/components/autofill_assistant/browser/website_login_manager_impl.cc index 4adc36fd..6e21c380c 100644 --- a/components/autofill_assistant/browser/website_login_manager_impl.cc +++ b/components/autofill_assistant/browser/website_login_manager_impl.cc
@@ -196,7 +196,7 @@ } void CommitGeneratedPassword() { - password_save_manager_->Save(form_data_ /* observed_form */, + password_save_manager_->Save(&form_data_ /* observed_form */, password_form_); } @@ -206,7 +206,7 @@ metrics_recorder_, &votes_uploader_); password_save_manager_->PresaveGeneratedPassword(password_form_); password_save_manager_->CreatePendingCredentials( - password_form_, form_data_ /* observed_form */, + password_form_, &form_data_ /* observed_form */, form_data_ /* submitted_form */, false /* is_http_auth */, false /* is_credential_api_save */);
diff --git a/components/bookmarks/browser/bookmark_expanded_state_tracker_unittest.cc b/components/bookmarks/browser/bookmark_expanded_state_tracker_unittest.cc index de56654a..24405c4 100644 --- a/components/bookmarks/browser/bookmark_expanded_state_tracker_unittest.cc +++ b/components/bookmarks/browser/bookmark_expanded_state_tracker_unittest.cc
@@ -7,6 +7,7 @@ #include <memory> #include "base/files/file_path.h" +#include "base/files/scoped_temp_dir.h" #include "base/macros.h" #include "base/run_loop.h" #include "base/strings/utf_string_conversions.h" @@ -31,6 +32,7 @@ void SetUp() override; void TearDown() override; + base::ScopedTempDir scoped_temp_dir_; base::test::TaskEnvironment task_environment_; TestingPrefServiceSimple prefs_; std::unique_ptr<BookmarkModel> model_; @@ -38,15 +40,17 @@ DISALLOW_COPY_AND_ASSIGN(BookmarkExpandedStateTrackerTest); }; -BookmarkExpandedStateTrackerTest::BookmarkExpandedStateTrackerTest() {} +BookmarkExpandedStateTrackerTest::BookmarkExpandedStateTrackerTest() = default; -BookmarkExpandedStateTrackerTest::~BookmarkExpandedStateTrackerTest() {} +BookmarkExpandedStateTrackerTest::~BookmarkExpandedStateTrackerTest() = default; void BookmarkExpandedStateTrackerTest::SetUp() { + ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir()); prefs_.registry()->RegisterListPref(prefs::kBookmarkEditorExpandedNodes); prefs_.registry()->RegisterListPref(prefs::kManagedBookmarks); - model_.reset(new BookmarkModel(std::make_unique<TestBookmarkClient>())); - model_->Load(&prefs_, base::FilePath()); + model_ = + std::make_unique<BookmarkModel>(std::make_unique<TestBookmarkClient>()); + model_->Load(&prefs_, scoped_temp_dir_.GetPath()); test::WaitForBookmarkModelToLoad(model_.get()); }
diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/ContentSettingException.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/ContentSettingException.java index f440edf7..4e029f68 100644 --- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/ContentSettingException.java +++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/ContentSettingException.java
@@ -6,42 +6,17 @@ import static org.chromium.components.browser_ui.site_settings.WebsitePreferenceBridge.SITE_WILDCARD; -import androidx.annotation.IntDef; import androidx.annotation.Nullable; import org.chromium.components.content_settings.ContentSettingValues; -import org.chromium.components.content_settings.ContentSettingsType; import org.chromium.components.embedder_support.browser_context.BrowserContextHandle; import java.io.Serializable; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; /** * Exception information for a given origin. */ public class ContentSettingException implements Serializable { - @IntDef({Type.ADS, Type.AUTOMATIC_DOWNLOADS, Type.BACKGROUND_SYNC, Type.BLUETOOTH_SCANNING, - Type.COOKIE, Type.JAVASCRIPT, Type.POPUP, Type.SOUND}) - @Retention(RetentionPolicy.SOURCE) - public @interface Type { - // Values used to address array index - should be enumerated from 0 and can't have gaps. - // All updates here must also be reflected in {@link #getContentSettingsType(int) - // getContentSettingsType} and {@link SingleWebsiteSettings.PERMISSION_PREFERENCE_KEYS}. - int ADS = 0; - int AUTOMATIC_DOWNLOADS = 1; - int BACKGROUND_SYNC = 2; - int BLUETOOTH_SCANNING = 3; - int COOKIE = 4; - int JAVASCRIPT = 5; - int POPUP = 6; - int SOUND = 7; - /** - * Number of handled exceptions used for calculating array sizes. - */ - int NUM_ENTRIES = 8; - } - private final int mContentSettingType; private final String mPrimaryPattern; private final String mSecondaryPattern; @@ -97,33 +72,9 @@ /** * Sets the content setting value for this exception. */ - public void setContentSetting(BrowserContextHandle browserContextHandle, - @ContentSettingValues @Nullable Integer value) { + public void setContentSetting( + BrowserContextHandle browserContextHandle, @ContentSettingValues int value) { WebsitePreferenceBridge.setContentSettingForPattern(browserContextHandle, mContentSettingType, mPrimaryPattern, mSecondaryPattern, value); } - - public static @ContentSettingsType int getContentSettingsType(@Type int type) { - switch (type) { - case Type.ADS: - return ContentSettingsType.ADS; - case Type.AUTOMATIC_DOWNLOADS: - return ContentSettingsType.AUTOMATIC_DOWNLOADS; - case Type.BACKGROUND_SYNC: - return ContentSettingsType.BACKGROUND_SYNC; - case Type.BLUETOOTH_SCANNING: - return ContentSettingsType.BLUETOOTH_SCANNING; - case Type.COOKIE: - return ContentSettingsType.COOKIES; - case Type.JAVASCRIPT: - return ContentSettingsType.JAVASCRIPT; - case Type.POPUP: - return ContentSettingsType.POPUPS; - case Type.SOUND: - return ContentSettingsType.SOUND; - default: - assert false; - return ContentSettingsType.DEFAULT; - } - } }
diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleCategorySettings.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleCategorySettings.java index 6d49494..f66cb86 100644 --- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleCategorySettings.java +++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleCategorySettings.java
@@ -210,13 +210,11 @@ getSiteSettingsClient().getBrowserContextHandle(); for (@SiteSettingsCategory.Type int i = 0; i < SiteSettingsCategory.Type.NUM_ENTRIES; i++) { if (!mCategory.showSites(i)) continue; - for (@ContentSettingException.Type int j = 0; - j < ContentSettingException.Type.NUM_ENTRIES; j++) { - if (ContentSettingException.getContentSettingsType(j) - == SiteSettingsCategory.contentSettingsType(i)) { - return ContentSettingValues.BLOCK - == website.site().getContentSettingPermission(j); - } + @ContentSettingValues + Integer contentSettingPermission = website.site().getContentSettingPermission( + SiteSettingsCategory.contentSettingsType(i)); + if (contentSettingPermission != null) { + return ContentSettingValues.BLOCK == contentSettingPermission; } for (@PermissionInfo.Type int j = 0; j < PermissionInfo.Type.NUM_ENTRIES; j++) { if (PermissionInfo.getContentSettingsType(j)
diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java index 2fce3b4..a43f713 100644 --- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java +++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java
@@ -35,10 +35,9 @@ import org.chromium.components.embedder_support.browser_context.BrowserContextHandle; import org.chromium.components.embedder_support.util.Origin; -import java.util.Arrays; import java.util.Collection; -import java.util.HashSet; -import java.util.Set; +import java.util.HashMap; +import java.util.Map; /** * Shows the permissions and other settings for a particular website. @@ -71,19 +70,38 @@ // Buttons: public static final String PREF_RESET_SITE = "reset_site_button"; + /** + * Currently only implemented for ContentSettingsType that have a ContentSettingsException. + * TODO(crbug.com/1103597): Replace PermissionInfo.Type enum with ContentSettingsType. + * @param type ContentSettingsType + * @return The preference key of this type + */ + private static @Nullable String getPreferenceKey(@ContentSettingsType int type) { + switch (type) { + case ContentSettingsType.ADS: + return "ads_permission_list"; + case ContentSettingsType.AUTOMATIC_DOWNLOADS: + return "automatic_downloads_permission_list"; + case ContentSettingsType.BACKGROUND_SYNC: + return "background_sync_permission_list"; + case ContentSettingsType.BLUETOOTH_SCANNING: + return "bluetooth_scanning_permission_list"; + case ContentSettingsType.COOKIES: + return "cookies_permission_list"; + case ContentSettingsType.JAVASCRIPT: + return "javascript_permission_list"; + case ContentSettingsType.POPUPS: + return "popup_permission_list"; + case ContentSettingsType.SOUND: + return "sound_permission_list"; + default: + return null; + } + } + // Website permissions (if adding new, see hasPermissionsPreferences and resetSite below) // All permissions from the permissions preference category must be listed here. public static final String[] PERMISSION_PREFERENCE_KEYS = { - // Permission keys mapped for next {@link ContentSettingException.Type} values. - "ads_permission_list", // ContentSettingException.Type.ADS - "automatic_downloads_permission_list", - // ContentSettingException.Type.AUTOMATIC_DOWNLOADS - "background_sync_permission_list", // ContentSettingException.Type.BACKGROUND_SYNC - "bluetooth_scanning_permission_list", // ContentSettingException.Type.BLUETOOTH_SCANNING - "cookies_permission_list", // ContentSettingException.Type.COOKIE - "javascript_permission_list", // ContentSettingException.Type.JAVASCRIPT - "popup_permission_list", // ContentSettingException.Type.POPUP - "sound_permission_list", // ContentSettingException.Type.SOUND // Permission keys mapped for next {@link PermissionInfo.Type} values. "ar_permission_list", // PermissionInfo.Type.AUGMENTED_REALITY "camera_permission_list", // PermissionInfo.Type.CAMERA @@ -123,6 +141,8 @@ // The Preference key for chooser object permissions. private static final String CHOOSER_PERMISSION_PREFERENCE_KEY = "chooser_permission_list"; + // The maximum order of a permission preference. + private int mMaxPermissionOrder; // The number of user and policy chosen object permissions displayed. private int mObjectUserPermissionCount; private int mObjectPolicyPermissionCount; @@ -131,6 +151,9 @@ // revocation within the Android system permission activity. private @ContentSettingValues @Nullable Integer mPreviousNotificationPermission; + // Map from preference key to ContentSettingsType. + private Map<String, Integer> mPreferenceMap; + private class SingleWebsitePermissionsPopulator implements WebsitePermissionsFetcher.WebsitePermissionsCallback { private final WebsiteAddress mSiteAddress; @@ -260,11 +283,11 @@ // This loop looks expensive, but the amount of data is likely to be relatively small // because most sites have very few permissions. for (Website other : websites) { - if (merged.getContentSettingException(ContentSettingException.Type.ADS) == null - && other.getContentSettingException(ContentSettingException.Type.ADS) != null + if (merged.getContentSettingException(ContentSettingsType.ADS) == null + && other.getContentSettingException(ContentSettingsType.ADS) != null && other.compareByAddressTo(merged) == 0) { - merged.setContentSettingException(ContentSettingException.Type.ADS, - other.getContentSettingException(ContentSettingException.Type.ADS)); + merged.setContentSettingException(ContentSettingsType.ADS, + other.getContentSettingException(ContentSettingsType.ADS)); } for (@PermissionInfo.Type int type = 0; type < PermissionInfo.Type.NUM_ENTRIES; type++) { @@ -291,15 +314,13 @@ } } if (host.equals(other.getAddress().getHost())) { - for (@ContentSettingException.Type int type = 0; - type < ContentSettingException.Type.NUM_ENTRIES; type++) { - if (type == ContentSettingException.Type.ADS) { + for (ContentSettingException exception : other.getContentSettingExceptions()) { + int type = exception.getContentSettingType(); + if (type == ContentSettingsType.ADS) { continue; } - if (merged.getContentSettingException(type) == null - && other.getContentSettingException(type) != null) { - merged.setContentSettingException( - type, other.getContentSettingException(type)); + if (merged.getContentSettingException(type) == null) { + merged.setContentSettingException(type, exception); } } } @@ -329,22 +350,19 @@ } SettingsUtils.addPreferencesFromResource(this, R.xml.single_website_preferences); - Set<String> permissionPreferenceKeys = - new HashSet<>(Arrays.asList(PERMISSION_PREFERENCE_KEYS)); - int maxPermissionOrder = 0; + mMaxPermissionOrder = 0; PreferenceScreen preferenceScreen = getPreferenceScreen(); // Iterate over preferences in reverse order because some preferences will be removed during // this setup, causing indices of later preferences to change. for (int i = preferenceScreen.getPreferenceCount() - 1; i >= 0; i--) { Preference preference = preferenceScreen.getPreference(i); setUpPreference(preference); - // Keep track of the maximum 'order' value of permission preferences, to allow correct - // positioning of subsequent permission preferences. - if (permissionPreferenceKeys.contains(preference.getKey())) { - maxPermissionOrder = Math.max(maxPermissionOrder, preference.getOrder()); + if (getContentSettingsTypeFromPreferenceKey(preference.getKey()) + != ContentSettingsType.DEFAULT) { + mMaxPermissionOrder = Math.max(mMaxPermissionOrder, preference.getOrder()); } } - setUpChosenObjectPreferences(maxPermissionOrder); + setUpChosenObjectPreferences(mMaxPermissionOrder); setUpOsWarningPreferences(); setUpAdsInformationalBanner(); @@ -375,29 +393,9 @@ } else if (PREF_RESET_SITE.equals(preference.getKey())) { setupResetSitePreference(preference); } else { - assert PERMISSION_PREFERENCE_KEYS.length - == ContentSettingException.Type.NUM_ENTRIES + PermissionInfo.Type.NUM_ENTRIES; - for (@ContentSettingException.Type int i = 0; - i < ContentSettingException.Type.NUM_ENTRIES; i++) { - if (!PERMISSION_PREFERENCE_KEYS[i].equals(preference.getKey())) { - continue; - } - if (i == ContentSettingException.Type.ADS) { - setUpAdsPreference(preference); - } else if (i == ContentSettingException.Type.SOUND) { - setUpSoundPreference(preference); - } else if (i == ContentSettingException.Type.JAVASCRIPT) { - setUpJavascriptPreference(preference); - } else { - // ContentSettingException can not be embargoed. - setUpListPreference(preference, mSite.getContentSettingPermission(i), - false /* isEmbargoed */); - } - return; - } + assert PERMISSION_PREFERENCE_KEYS.length == PermissionInfo.Type.NUM_ENTRIES; for (@PermissionInfo.Type int i = 0; i < PermissionInfo.Type.NUM_ENTRIES; i++) { - if (!PERMISSION_PREFERENCE_KEYS[i + ContentSettingException.Type.NUM_ENTRIES] - .equals(preference.getKey())) { + if (!PERMISSION_PREFERENCE_KEYS[i].equals(preference.getKey())) { continue; } if (i == PermissionInfo.Type.GEOLOCATION) { @@ -413,6 +411,22 @@ } return; } + @ContentSettingsType + int type = getContentSettingsTypeFromPreferenceKey(preference.getKey()); + if (type != ContentSettingsType.DEFAULT) { + if (type == ContentSettingsType.ADS) { + setUpAdsPreference(preference); + } else if (type == ContentSettingsType.SOUND) { + setUpSoundPreference(preference); + } else if (type == ContentSettingsType.JAVASCRIPT) { + setUpJavascriptPreference(preference); + } else { + // ContentSettingException can not be embargoed. + setUpListPreference(preference, mSite.getContentSettingPermission(type), + false /* isEmbargoed */); + } + return; + } } } @@ -613,8 +627,7 @@ // User has navigated back from system channel settings on O+. Ensure notification // preference is up to date, since they might have toggled it from channel settings. Preference notificationsPreference = - findPreference(PERMISSION_PREFERENCE_KEYS[PermissionInfo.Type.NOTIFICATION - + ContentSettingException.Type.NUM_ENTRIES]); + findPreference(PERMISSION_PREFERENCE_KEYS[PermissionInfo.Type.NOTIFICATION]); if (notificationsPreference != null) { setUpNotificationsPreference(notificationsPreference, false /* isEmbargoed */); } @@ -722,8 +735,7 @@ && WebsitePreferenceBridge.getAdBlockingActivated( getSiteSettingsClient().getBrowserContextHandle(), mSite.getAddress().getOrigin()) - && findPreference(PERMISSION_PREFERENCE_KEYS[ContentSettingException.Type.ADS]) - != null; + && findPreference(getPreferenceKey(ContentSettingsType.ADS)) != null; if (!adBlockingActivated) { removePreferenceSafely(PREF_INTRUSIVE_ADS_INFO); @@ -767,10 +779,9 @@ for (int i = 0; i < PermissionInfo.Type.NUM_ENTRIES; i++) { if (PermissionInfo.getContentSettingsType(i) == SiteSettingsCategory.contentSettingsType(type)) { - return mSite.getPermission(browserContextHandle, i) == null - ? false - : SiteSettingsCategory.createFromType(browserContextHandle, type) - .showPermissionBlockedMessage(getActivity()); + return mSite.getPermission(browserContextHandle, i) != null + && SiteSettingsCategory.createFromType(browserContextHandle, type) + .showPermissionBlockedMessage(getActivity()); } } return false; @@ -784,9 +795,7 @@ private boolean hasPermissionsPreferences() { if (mObjectUserPermissionCount > 0 || mObjectPolicyPermissionCount > 0) return true; - for (String key : PERMISSION_PREFERENCE_KEYS) { - if (findPreference(key) != null) return true; - } + if (mMaxPermissionOrder > 0) return true; return false; } @@ -868,8 +877,7 @@ private void setUpSoundPreference(Preference preference) { @ContentSettingValues @Nullable - Integer currentValue = - mSite.getContentSettingPermission(ContentSettingException.Type.SOUND); + Integer currentValue = mSite.getContentSettingPermission(ContentSettingsType.SOUND); // In order to always show the sound permission, set it up with the default value if it // doesn't have a current value. if (currentValue == null) { @@ -886,8 +894,7 @@ private void setUpJavascriptPreference(Preference preference) { @ContentSettingValues @Nullable - Integer currentValue = - mSite.getContentSettingPermission(ContentSettingException.Type.JAVASCRIPT); + Integer currentValue = mSite.getContentSettingPermission(ContentSettingsType.JAVASCRIPT); // If Javascript is blocked by default, then always show a Javascript permission. // To do this, set it to the default value (blocked). if ((currentValue == null) @@ -919,7 +926,7 @@ getSiteSettingsClient().getBrowserContextHandle(), mSite.getAddress().getOrigin()); @ContentSettingValues @Nullable - Integer permission = mSite.getContentSettingPermission(ContentSettingException.Type.ADS); + Integer permission = mSite.getContentSettingPermission(ContentSettingsType.ADS); // If |permission| is null, there is no explicit (non-default) permission set for this site. // If the site is not considered a candidate for blocking, do the standard thing and remove @@ -972,16 +979,23 @@ }); } - public static int getContentSettingsTypeFromPreferenceKey(String preferenceKey) { - for (int i = 0; i < PERMISSION_PREFERENCE_KEYS.length; i++) { - if (PERMISSION_PREFERENCE_KEYS[i].equals(preferenceKey)) { - return i < ContentSettingException.Type.NUM_ENTRIES - ? ContentSettingException.getContentSettingsType(i) - : PermissionInfo.getContentSettingsType( - i - ContentSettingException.Type.NUM_ENTRIES); + public @ContentSettingsType int getContentSettingsTypeFromPreferenceKey(String preferenceKey) { + if (mPreferenceMap == null) { + mPreferenceMap = new HashMap<>(); + for (int i = 0; i < PERMISSION_PREFERENCE_KEYS.length; i++) { + mPreferenceMap.put( + PERMISSION_PREFERENCE_KEYS[i], PermissionInfo.getContentSettingsType(i)); + } + for (@ContentSettingsType int type = 0; type < ContentSettingsType.NUM_TYPES; type++) { + String key = getPreferenceKey(type); + if (key != null) { + mPreferenceMap.put(key, type); + } } } - return 0; + Integer type = mPreferenceMap.get(preferenceKey); + if (type != null) return type; + return ContentSettingsType.DEFAULT; } private void popBackIfNoSettings() { @@ -1001,16 +1015,16 @@ getSiteSettingsClient().getBrowserContextHandle(); for (int i = 0; i < PERMISSION_PREFERENCE_KEYS.length; i++) { if (PERMISSION_PREFERENCE_KEYS[i].equals(preference.getKey())) { - if (i < ContentSettingException.Type.NUM_ENTRIES) { - mSite.setContentSettingPermission( - getSiteSettingsClient().getBrowserContextHandle(), i, permission); - } else { - mSite.setPermission(browserContextHandle, - i - ContentSettingException.Type.NUM_ENTRIES, permission); - } + mSite.setPermission(browserContextHandle, i, permission); return true; } } + int type = getContentSettingsTypeFromPreferenceKey(preference.getKey()); + if (type != ContentSettingsType.DEFAULT) { + mSite.setContentSettingPermission( + getSiteSettingsClient().getBrowserContextHandle(), type, permission); + } + return true; } @@ -1045,6 +1059,12 @@ for (String key : PERMISSION_PREFERENCE_KEYS) { removePreferenceSafely(key); } + for (@ContentSettingsType int type = 0; type < ContentSettingsType.NUM_TYPES; type++) { + String key = getPreferenceKey(type); + if (key != null) { + removePreferenceSafely(key); + } + } // Clearing stored data implies popping back to parent menu if there is nothing left to // show. Therefore, we only need to explicitly close the activity if there's no stored data
diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteDataCleaner.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteDataCleaner.java index fcccd47..18cb047 100644 --- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteDataCleaner.java +++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteDataCleaner.java
@@ -24,10 +24,9 @@ WebsitePreferenceBridgeJni.get().clearMediaLicenses(browserContextHandle, origin); // Clear the permissions. - for (@ContentSettingException.Type int type = 0; - type < ContentSettingException.Type.NUM_ENTRIES; type++) { - site.setContentSettingPermission( - browserContextHandle, type, ContentSettingValues.DEFAULT); + for (ContentSettingException exception : site.getContentSettingExceptions()) { + site.setContentSettingPermission(browserContextHandle, + exception.getContentSettingType(), ContentSettingValues.DEFAULT); } for (@PermissionInfo.Type int type = 0; type < PermissionInfo.Type.NUM_ENTRIES; type++) { site.setPermission(browserContextHandle, type, ContentSettingValues.DEFAULT);
diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/Website.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/Website.java index 08fc2bc..ed57ec1 100644 --- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/Website.java +++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/Website.java
@@ -17,34 +17,30 @@ import java.io.Serializable; import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * Website is a class for storing information about a website and its associated permissions. */ -public class Website implements Serializable { - static final int INVALID_CAMERA_OR_MICROPHONE_ACCESS = 0; - static final int CAMERA_ACCESS_ALLOWED = 1; - static final int MICROPHONE_AND_CAMERA_ACCESS_ALLOWED = 2; - static final int MICROPHONE_ACCESS_ALLOWED = 3; - static final int CAMERA_ACCESS_DENIED = 4; - static final int MICROPHONE_AND_CAMERA_ACCESS_DENIED = 5; - static final int MICROPHONE_ACCESS_DENIED = 6; - +public final class Website implements Serializable { private final WebsiteAddress mOrigin; private final WebsiteAddress mEmbedder; /** - * Indexed by ContentSettingException.Type. + * Indexed by ContentSettingsType. */ - private ContentSettingException mContentSettingException[]; + private Map<Integer, ContentSettingException> mContentSettingExceptions = new HashMap<>(); + /** * Indexed by PermissionInfo.Type. */ private PermissionInfo[] mPermissionInfo; private LocalStorageInfo mLocalStorageInfo; - private final List<StorageInfo> mStorageInfo = new ArrayList<StorageInfo>(); + private final List<StorageInfo> mStorageInfo = new ArrayList<>(); private int mStorageInfoCallbacksLeft; // The collection of chooser-based permissions (e.g. USB device access) granted to this site. @@ -56,8 +52,6 @@ mOrigin = origin; mEmbedder = embedder; mPermissionInfo = new PermissionInfo[PermissionInfo.Type.NUM_ENTRIES]; - mContentSettingException = - new ContentSettingException[ContentSettingException.Type.NUM_ENTRIES]; } public WebsiteAddress getAddress() { @@ -164,29 +158,34 @@ } } + public Collection<ContentSettingException> getContentSettingExceptions() { + return mContentSettingExceptions.values(); + } + /** * Returns the exception info for this Website for specified type. */ - public ContentSettingException getContentSettingException( - @ContentSettingException.Type int type) { - return mContentSettingException[type]; + public ContentSettingException getContentSettingException(@ContentSettingsType int type) { + return mContentSettingExceptions.get(type); } /** * Sets the exception info for this Website for specified type. */ public void setContentSettingException( - @ContentSettingException.Type int type, ContentSettingException exception) { - mContentSettingException[type] = exception; + @ContentSettingsType int type, ContentSettingException exception) { + mContentSettingExceptions.put(type, exception); } /** * Returns what ContentSettingException governs the setting of specified type. */ public @ContentSettingValues @Nullable Integer getContentSettingPermission( - @ContentSettingException.Type int type) { - return mContentSettingException[type] != null - ? mContentSettingException[type].getContentSetting() + @ContentSettingsType int type) { + // TODO(crbug.com/1103597): Merge with getPermission() when both are keyed by + // ContentSettingsType. + return getContentSettingException(type) != null + ? getContentSettingException(type).getContentSetting() : null; } @@ -194,24 +193,28 @@ * Sets the permission. */ public void setContentSettingPermission(BrowserContextHandle browserContextHandle, - @ContentSettingException.Type int type, @ContentSettingValues int value) { - if (type == ContentSettingException.Type.ADS) { + @ContentSettingsType int type, @ContentSettingValues int value) { + // TODO(crbug.com/1103597): Merge with setPermission() when both are keyed by + // ContentSettingsType. + ContentSettingException exception = getContentSettingException(type); + if (type == ContentSettingsType.ADS) { // It is possible to set the permission without having an existing exception, // because we can show the BLOCK state even when this permission is set to the // default. In that case, just set an exception now to BLOCK to enable changing the // permission. - if (mContentSettingException[type] == null) { - mContentSettingException[type] = - new ContentSettingException(ContentSettingsType.ADS, - getAddress().getOrigin(), ContentSettingValues.BLOCK, ""); + if (exception == null) { + exception = new ContentSettingException(ContentSettingsType.ADS, + getAddress().getOrigin(), ContentSettingValues.BLOCK, ""); + setContentSettingException(type, exception); } - } else if (type == ContentSettingException.Type.JAVASCRIPT) { + } else if (type == ContentSettingsType.JAVASCRIPT) { // It is possible to set the permission without having an existing exception, // because we show the javascript permission in Site Settings if javascript // is blocked by default. - if (mContentSettingException[type] == null) { - mContentSettingException[type] = new ContentSettingException( + if (exception == null) { + exception = new ContentSettingException( ContentSettingsType.JAVASCRIPT, getAddress().getHost(), value, ""); + setContentSettingException(type, exception); } // It's possible for either action to be emitted. This code path is hit // regardless of whether there was an existing permission or not. @@ -220,12 +223,13 @@ } else { RecordUserAction.record("JavascriptContentSetting.DisableBy.SiteSettings"); } - } else if (type == ContentSettingException.Type.SOUND) { + } else if (type == ContentSettingsType.SOUND) { // It is possible to set the permission without having an existing exception, // because we always show the sound permission in Site Settings. - if (mContentSettingException[type] == null) { - mContentSettingException[type] = new ContentSettingException( + if (exception == null) { + exception = new ContentSettingException( ContentSettingsType.SOUND, getAddress().getHost(), value, ""); + setContentSettingException(type, exception); } if (value == ContentSettingValues.BLOCK) { RecordUserAction.record("SoundContentSetting.MuteBy.SiteSettings"); @@ -236,8 +240,8 @@ // We want to call setContentSetting even after explicitly setting // mContentSettingException above because this will trigger the actual change // on the PrefServiceBridge. - if (mContentSettingException[type] != null) { - mContentSettingException[type].setContentSetting(browserContextHandle, value); + if (exception != null) { + exception.setContentSetting(browserContextHandle, value); } }
diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/WebsitePermissionsFetcher.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/WebsitePermissionsFetcher.java index bddd75f..9c3be25 100644 --- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/WebsitePermissionsFetcher.java +++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/WebsitePermissionsFetcher.java
@@ -285,20 +285,6 @@ } private void setException(int contentSettingsType) { - @ContentSettingException.Type - int exceptionType; - for (exceptionType = 0; exceptionType < ContentSettingException.Type.NUM_ENTRIES; - exceptionType++) { - if (contentSettingsType - == ContentSettingException.getContentSettingsType(exceptionType)) { - break; - } - } - assert contentSettingsType - == ContentSettingException.getContentSettingsType(exceptionType) - : "Unexpected content setting type received: " - + contentSettingsType; - for (ContentSettingException exception : mWebsitePreferenceBridge.getContentSettingsExceptions( mBrowserContextHandle, contentSettingsType)) { @@ -309,7 +295,7 @@ continue; } Website site = findOrCreateSite(address, embedder); - site.setContentSettingException(exceptionType, exception); + site.setContentSettingException(contentSettingsType, exception); } }
diff --git a/components/discardable_memory/client/BUILD.gn b/components/discardable_memory/client/BUILD.gn index ea18c7d..e8e92b80 100644 --- a/components/discardable_memory/client/BUILD.gn +++ b/components/discardable_memory/client/BUILD.gn
@@ -21,3 +21,15 @@ "//components/discardable_memory/public/mojom", ] } + +source_set("unit_tests") { + testonly = true + + sources = [ "client_discardable_shared_memory_manager_unittest.cc" ] + + deps = [ + ":client", + "//base", + "//testing/gtest", + ] +}
diff --git a/components/discardable_memory/client/client_discardable_shared_memory_manager.cc b/components/discardable_memory/client/client_discardable_shared_memory_manager.cc index 49e37805..b6727fa 100644 --- a/components/discardable_memory/client/client_discardable_shared_memory_manager.cc +++ b/components/discardable_memory/client/client_discardable_shared_memory_manager.cc
@@ -4,14 +4,12 @@ #include "components/discardable_memory/client/client_discardable_shared_memory_manager.h" -#include <inttypes.h> - #include <algorithm> -#include <memory> #include <utility> #include "base/atomic_sequence_num.h" #include "base/bind.h" +#include "base/feature_list.h" #include "base/macros.h" #include "base/memory/discardable_memory.h" #include "base/memory/discardable_shared_memory.h" @@ -34,6 +32,13 @@ // Global atomic to generate unique discardable shared memory IDs. base::AtomicSequenceNumber g_next_discardable_shared_memory_id; +// This controls whether unlocked memory is released when |ReleaseFreeMemory| is +// called. Enabling this causes |ReleaseFreeMemory| to release all +// unlocked memory instances, as well as release all free memory (as opposed to +// merely releasing all free memory). +const base::Feature kPurgeUnlockedMemory{"PurgeUnlockedMemory", + base::FEATURE_DISABLED_BY_DEFAULT}; + size_t GetDefaultAllocationSize() { const size_t kOneMegabyteInBytes = 1024 * 1024; @@ -62,59 +67,6 @@ #endif } -class DiscardableMemoryImpl : public base::DiscardableMemory { - public: - DiscardableMemoryImpl(ClientDiscardableSharedMemoryManager* manager, - std::unique_ptr<DiscardableSharedMemoryHeap::Span> span) - : manager_(manager), span_(std::move(span)), is_locked_(true) {} - - ~DiscardableMemoryImpl() override { - if (is_locked_) - manager_->UnlockSpan(span_.get()); - - manager_->ReleaseSpan(std::move(span_)); - } - - // Overridden from base::DiscardableMemory: - bool Lock() override { - DCHECK(!is_locked_); - - if (!manager_->LockSpan(span_.get())) - return false; - - is_locked_ = true; - return true; - } - void Unlock() override { - DCHECK(is_locked_); - - manager_->UnlockSpan(span_.get()); - is_locked_ = false; - } - void* data() const override { - DCHECK(is_locked_); - return reinterpret_cast<void*>(span_->start() * base::GetPageSize()); - } - - void DiscardForTesting() override { - DCHECK(!is_locked_); - span_->shared_memory()->Purge(base::Time::Now()); - } - - base::trace_event::MemoryAllocatorDump* CreateMemoryAllocatorDump( - const char* name, - base::trace_event::ProcessMemoryDump* pmd) const override { - return manager_->CreateMemoryAllocatorDump(span_.get(), name, pmd); - } - - private: - ClientDiscardableSharedMemoryManager* const manager_; - std::unique_ptr<DiscardableSharedMemoryHeap::Span> span_; - bool is_locked_; - - DISALLOW_COPY_AND_ASSIGN(DiscardableMemoryImpl); -}; - void InitManagerMojoOnIO( mojo::Remote<mojom::DiscardableSharedMemoryManager>* manager_mojo, mojo::PendingRemote<mojom::DiscardableSharedMemoryManager> remote) { @@ -129,13 +81,94 @@ } // namespace +ClientDiscardableSharedMemoryManager::DiscardableMemoryImpl:: + DiscardableMemoryImpl( + ClientDiscardableSharedMemoryManager* manager, + std::unique_ptr<DiscardableSharedMemoryHeap::Span> span) + : manager_(manager), span_(std::move(span)), is_locked_(true) { + DCHECK_NE(manager, nullptr); +} + +ClientDiscardableSharedMemoryManager::DiscardableMemoryImpl:: + ~DiscardableMemoryImpl() { + base::AutoLock lock(manager_->GetLock()); + if (!span_) { + DCHECK(!is_locked_); + return; + } + if (is_locked_) + manager_->UnlockSpan(span_.get()); + + manager_->ReleaseMemory(this, std::move(span_)); +} + +bool ClientDiscardableSharedMemoryManager::DiscardableMemoryImpl::Lock() { + base::AutoLock lock(manager_->GetLock()); + DCHECK(!is_locked_); + + if (!span_) + return false; + + if (!manager_->LockSpan(span_.get())) + return false; + + is_locked_ = true; + return true; +} + +void ClientDiscardableSharedMemoryManager::DiscardableMemoryImpl::Unlock() { + base::AutoLock lock(manager_->GetLock()); + DCHECK(is_locked_); + DCHECK(span_); + + manager_->UnlockSpan(span_.get()); + is_locked_ = false; +} + +std::unique_ptr<DiscardableSharedMemoryHeap::Span> +ClientDiscardableSharedMemoryManager::DiscardableMemoryImpl::Purge() { + DCHECK(span_); + if (is_locked_) + return nullptr; + return std::move(span_); +} + +void* ClientDiscardableSharedMemoryManager::DiscardableMemoryImpl::data() + const { +#if DCHECK_IS_ON() + { + base::AutoLock lock(manager_->GetLock()); + DCHECK(is_locked_); + } +#endif + return reinterpret_cast<void*>(span_->start() * base::GetPageSize()); +} + +void ClientDiscardableSharedMemoryManager::DiscardableMemoryImpl:: + DiscardForTesting() { +#if DCHECK_IS_ON() + { + base::AutoLock lock(manager_->GetLock()); + DCHECK(!is_locked_); + } +#endif + span_->shared_memory()->Purge(base::Time::Now()); +} + +base::trace_event::MemoryAllocatorDump* ClientDiscardableSharedMemoryManager:: + DiscardableMemoryImpl::CreateMemoryAllocatorDump( + const char* name, + base::trace_event::ProcessMemoryDump* pmd) const { + return manager_->CreateMemoryAllocatorDump(span_.get(), name, pmd); +} + ClientDiscardableSharedMemoryManager::ClientDiscardableSharedMemoryManager( mojo::PendingRemote<mojom::DiscardableSharedMemoryManager> manager, scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) - : io_task_runner_(std::move(io_task_runner)), + : heap_(std::make_unique<DiscardableSharedMemoryHeap>()), + io_task_runner_(std::move(io_task_runner)), manager_mojo_(std::make_unique< - mojo::Remote<mojom::DiscardableSharedMemoryManager>>()), - heap_(std::make_unique<DiscardableSharedMemoryHeap>()) { + mojo::Remote<mojom::DiscardableSharedMemoryManager>>()) { base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( this, "ClientDiscardableSharedMemoryManager", base::ThreadTaskRunnerHandle::Get()); @@ -144,6 +177,11 @@ std::move(manager))); } +ClientDiscardableSharedMemoryManager::ClientDiscardableSharedMemoryManager( + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) + : heap_(std::make_unique<DiscardableSharedMemoryHeap>()), + io_task_runner_(std::move(io_task_runner)) {} + ClientDiscardableSharedMemoryManager::~ClientDiscardableSharedMemoryManager() { base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider( this); @@ -225,7 +263,10 @@ // at least one span from the free lists. MemoryUsageChanged(heap_->GetSize(), heap_->GetSizeOfFreeLists()); - return std::make_unique<DiscardableMemoryImpl>(this, std::move(free_span)); + auto discardable_memory = + std::make_unique<DiscardableMemoryImpl>(this, std::move(free_span)); + allocated_memory_.insert(discardable_memory.get()); + return std::move(discardable_memory); } // Release purged memory to free up the address space before we attempt to @@ -279,7 +320,10 @@ MemoryUsageChanged(heap_->GetSize(), heap_->GetSizeOfFreeLists()); - return std::make_unique<DiscardableMemoryImpl>(this, std::move(new_span)); + auto discardable_memory = + std::make_unique<DiscardableMemoryImpl>(this, std::move(new_span)); + allocated_memory_.insert(discardable_memory.get()); + return std::move(discardable_memory); } bool ClientDiscardableSharedMemoryManager::OnMemoryDump( @@ -294,11 +338,46 @@ return heap_->GetSize() - heap_->GetSizeOfFreeLists(); } +void ClientDiscardableSharedMemoryManager::PurgeUnlockedMemory() { + { + base::AutoLock lock(lock_); + + // Iterate this way in order to avoid invalidating the iterator while + // removing elements from |allocated_memory_| as we iterate over it. + for (auto it = allocated_memory_.begin(); it != allocated_memory_.end(); + /* nop */) { + auto prev = it++; + DiscardableMemoryImpl* mem = *prev; + + // This assert is only required because the static checker can't figure + // out that |mem->manager_->GetLock()| is the same as |this->lock_|, as + // verified by the DCHECK. + DCHECK_EQ(&lock_, &mem->manager_->GetLock()); + mem->manager_->GetLock().AssertAcquired(); + + auto span = mem->Purge(); + if (span) { + allocated_memory_.erase(prev); + ReleaseSpan(std::move(span)); + } + } + } + + ReleaseFreeMemoryImpl(); +} + void ClientDiscardableSharedMemoryManager::ReleaseFreeMemory() { + if (base::FeatureList::IsEnabled(kPurgeUnlockedMemory)) { + PurgeUnlockedMemory(); + } else { + ReleaseFreeMemoryImpl(); + } +} + +void ClientDiscardableSharedMemoryManager::ReleaseFreeMemoryImpl() { TRACE_EVENT0("blink", "ClientDiscardableSharedMemoryManager::ReleaseFreeMemory()"); base::AutoLock lock(lock_); - size_t heap_size_prior_to_releasing_memory = heap_->GetSize(); // Release both purged and free memory. @@ -311,8 +390,6 @@ bool ClientDiscardableSharedMemoryManager::LockSpan( DiscardableSharedMemoryHeap::Span* span) { - base::AutoLock lock(lock_); - if (!span->shared_memory()) return false; @@ -338,8 +415,6 @@ void ClientDiscardableSharedMemoryManager::UnlockSpan( DiscardableSharedMemoryHeap::Span* span) { - base::AutoLock lock(lock_); - DCHECK(span->shared_memory()); size_t offset = span->start() * base::GetPageSize() - reinterpret_cast<size_t>(span->shared_memory()->memory()); @@ -349,9 +424,18 @@ return span->shared_memory()->Unlock(offset, length); } +void ClientDiscardableSharedMemoryManager::ReleaseMemory( + DiscardableMemoryImpl* memory, + std::unique_ptr<DiscardableSharedMemoryHeap::Span> span) { + DCHECK(span); + auto removed = allocated_memory_.erase(memory); + DCHECK_EQ(removed, 1u); + ReleaseSpan(std::move(span)); +} + void ClientDiscardableSharedMemoryManager::ReleaseSpan( std::unique_ptr<DiscardableSharedMemoryHeap::Span> span) { - base::AutoLock lock(lock_); + DCHECK(span); // Delete span instead of merging it into free lists if memory is gone. if (!span->shared_memory()) @@ -380,6 +464,7 @@ "ClientDiscardableSharedMemoryManager::" "AllocateLockedDiscardableSharedMemory", "size", size, "id", id); + base::UnsafeSharedMemoryRegion region; base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, base::WaitableEvent::InitialState::NOT_SIGNALED); @@ -394,8 +479,8 @@ event.Wait(); // This is likely address space exhaustion in the the browser process. We - // don't want to crash the browser process for that, which is why the check is - // here, and not there. + // don't want to crash the browser process for that, which is why the check + // is here, and not there. if (!region.IsValid()) return nullptr;
diff --git a/components/discardable_memory/client/client_discardable_shared_memory_manager.h b/components/discardable_memory/client/client_discardable_shared_memory_manager.h index 47f7fdf..2bfe99c 100644 --- a/components/discardable_memory/client/client_discardable_shared_memory_manager.h +++ b/components/discardable_memory/client/client_discardable_shared_memory_manager.h
@@ -8,9 +8,8 @@ #include <stddef.h> #include <memory> +#include <set> -#include "base/callback_helpers.h" -#include "base/macros.h" #include "base/memory/discardable_memory_allocator.h" #include "base/memory/ref_counted.h" #include "base/memory/unsafe_shared_memory_region.h" @@ -47,12 +46,16 @@ bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args, base::trace_event::ProcessMemoryDump* pmd) override; + // Purge any unlocked memory that was allocated by this manager. + void PurgeUnlockedMemory(); + // Release memory and associated resources that have been purged. void ReleaseFreeMemory() override; - bool LockSpan(DiscardableSharedMemoryHeap::Span* span); - void UnlockSpan(DiscardableSharedMemoryHeap::Span* span); - void ReleaseSpan(std::unique_ptr<DiscardableSharedMemoryHeap::Span> span); + bool LockSpan(DiscardableSharedMemoryHeap::Span* span) + EXCLUSIVE_LOCKS_REQUIRED(GetLock()); + void UnlockSpan(DiscardableSharedMemoryHeap::Span* span) + EXCLUSIVE_LOCKS_REQUIRED(GetLock()); base::trace_event::MemoryAllocatorDump* CreateMemoryAllocatorDump( DiscardableSharedMemoryHeap::Span* span, @@ -70,8 +73,47 @@ bytes_allocated_limit_for_testing_ = limit; } + // We only have protected members for testing, everything else should be + // either public or private. + protected: + explicit ClientDiscardableSharedMemoryManager( + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner); + std::unique_ptr<DiscardableSharedMemoryHeap> heap_ GUARDED_BY(lock_); + mutable base::Lock lock_; + private: - std::unique_ptr<base::DiscardableSharedMemory> + class DiscardableMemoryImpl : public base::DiscardableMemory { + public: + DiscardableMemoryImpl( + ClientDiscardableSharedMemoryManager* manager, + std::unique_ptr<DiscardableSharedMemoryHeap::Span> span); + ~DiscardableMemoryImpl() override; + + DiscardableMemoryImpl(const DiscardableMemoryImpl&) = delete; + DiscardableMemoryImpl& operator=(const DiscardableMemoryImpl&) = delete; + + // Overridden from base::DiscardableMemory: + bool Lock() override; + void Unlock() override; + void* data() const override; + void DiscardForTesting() override; + base::trace_event::MemoryAllocatorDump* CreateMemoryAllocatorDump( + const char* name, + base::trace_event::ProcessMemoryDump* pmd) const override; + + // Returns |span_| if unlocked, otherwise nullptr. + std::unique_ptr<DiscardableSharedMemoryHeap::Span> Purge() + EXCLUSIVE_LOCKS_REQUIRED(manager_->GetLock()); + + private: + friend class ClientDiscardableSharedMemoryManager; + ClientDiscardableSharedMemoryManager* const manager_; + std::unique_ptr<DiscardableSharedMemoryHeap::Span> span_; + bool is_locked_ GUARDED_BY(manager_->GetLock()); + }; + + // This is only virtual for testing. + virtual std::unique_ptr<base::DiscardableSharedMemory> AllocateLockedDiscardableSharedMemory(size_t size, int32_t id); void AllocateOnIO(size_t size, int32_t id, @@ -81,18 +123,27 @@ base::ScopedClosureRunner closure_runner, base::UnsafeSharedMemoryRegion ret_region); - void DeletedDiscardableSharedMemory(int32_t id); + // This is only virtual for testing. + virtual void DeletedDiscardableSharedMemory(int32_t id); void MemoryUsageChanged(size_t new_bytes_allocated, size_t new_bytes_free) const; + void ReleaseFreeMemoryImpl(); + void ReleaseMemory(DiscardableMemoryImpl* memory, + std::unique_ptr<DiscardableSharedMemoryHeap::Span> span) + EXCLUSIVE_LOCKS_REQUIRED(lock_); + void ReleaseSpan(std::unique_ptr<DiscardableSharedMemoryHeap::Span> span) + EXCLUSIVE_LOCKS_REQUIRED(lock_); + base::Lock& GetLock() { return lock_; } + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; // TODO(penghuang): Switch to SharedRemote when it starts supporting // sync method call. std::unique_ptr<mojo::Remote<mojom::DiscardableSharedMemoryManager>> manager_mojo_; - mutable base::Lock lock_; - std::unique_ptr<DiscardableSharedMemoryHeap> heap_ GUARDED_BY(lock_); + // Holds all locked and unlocked instances which have not yet been purged. + std::set<DiscardableMemoryImpl*> allocated_memory_ GUARDED_BY(lock_); size_t bytes_allocated_limit_for_testing_ = 0; DISALLOW_COPY_AND_ASSIGN(ClientDiscardableSharedMemoryManager);
diff --git a/components/discardable_memory/client/client_discardable_shared_memory_manager_unittest.cc b/components/discardable_memory/client/client_discardable_shared_memory_manager_unittest.cc new file mode 100644 index 0000000..e48edb7 --- /dev/null +++ b/components/discardable_memory/client/client_discardable_shared_memory_manager_unittest.cc
@@ -0,0 +1,268 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/discardable_memory/client/client_discardable_shared_memory_manager.h" +#include "base/memory/discardable_memory.h" +#include "base/memory/discardable_shared_memory.h" +#include "base/process/process_metrics.h" +#include "base/synchronization/lock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace discardable_memory { +namespace { + +using base::Location; +using base::OnceClosure; +using base::TimeDelta; + +class TestSingleThreadTaskRunner : public base::SingleThreadTaskRunner { + ~TestSingleThreadTaskRunner() override = default; + bool PostTask(const Location& from_here, OnceClosure task) { return true; } + template <class T> + bool DeleteSoon(const Location& from_here, const T* object) { + return true; + } + bool PostDelayedTask(const Location& from_here, + OnceClosure task, + TimeDelta delay) override { + return true; + } + bool PostNonNestableDelayedTask(const Location& from_here, + OnceClosure task, + TimeDelta delay) override { + return true; + } + bool RunsTasksInCurrentSequence() const override { return true; } +}; + +class TestClientDiscardableSharedMemoryManager + : public ClientDiscardableSharedMemoryManager { + public: + TestClientDiscardableSharedMemoryManager() + : ClientDiscardableSharedMemoryManager( + base::MakeRefCounted<TestSingleThreadTaskRunner>()) {} + + ~TestClientDiscardableSharedMemoryManager() override = default; + + std::unique_ptr<base::DiscardableSharedMemory> + AllocateLockedDiscardableSharedMemory(size_t size, int32_t id) override { + auto shared_memory = std::make_unique<base::DiscardableSharedMemory>(); + shared_memory->CreateAndMap(size); + return shared_memory; + } + + void DeletedDiscardableSharedMemory(int32_t id) override {} + + size_t GetSize() const { + base::AutoLock lock(lock_); + return heap_->GetSize(); + } + + size_t GetSizeOfFreeLists() const { + base::AutoLock lock(lock_); + return heap_->GetSizeOfFreeLists(); + } +}; + +// This test allocates a single piece of memory, then verifies that calling +// |PurgeUnlockedMemory| only affects the memory when it is unlocked. +TEST(ClientDiscardableSharedMemoryManagerTest, Simple) { + const size_t page_size = base::GetPageSize(); + TestClientDiscardableSharedMemoryManager client; + + // Initially, we should have no memory allocated + ASSERT_EQ(client.GetBytesAllocated(), 0u); + ASSERT_EQ(client.GetSizeOfFreeLists(), 0u); + + auto mem = client.AllocateLockedDiscardableMemory(page_size); + + // After allocation, we should have allocated a single piece of memory. + EXPECT_EQ(client.GetBytesAllocated(), page_size); + + client.PurgeUnlockedMemory(); + + // All our memory is locked, so calling |PurgeUnlockedMemory| should have no + // effect. + EXPECT_EQ(client.GetBytesAllocated(), base::GetPageSize()); + + mem->Unlock(); + + // Unlocking has no effect on the amount of memory we have allocated. + EXPECT_EQ(client.GetBytesAllocated(), base::GetPageSize()); + + client.PurgeUnlockedMemory(); + + // Now that |mem| is unlocked, the call to |PurgeUnlockedMemory| will + // remove it. + EXPECT_EQ(client.GetBytesAllocated(), 0u); +} + +// This test allocates multiple pieces of memory, then unlocks them one by one, +// verifying that |PurgeUnlockedMemory| only affects the unlocked pieces of +// memory. +TEST(ClientDiscardableSharedMemoryManagerTest, MultipleOneByOne) { + const size_t page_size = base::GetPageSize(); + TestClientDiscardableSharedMemoryManager client; + + ASSERT_EQ(client.GetBytesAllocated(), 0u); + ASSERT_EQ(client.GetSizeOfFreeLists(), 0u); + + auto mem1 = client.AllocateLockedDiscardableMemory(page_size * 2.2); + auto mem2 = client.AllocateLockedDiscardableMemory(page_size * 1.1); + auto mem3 = client.AllocateLockedDiscardableMemory(page_size * 3.5); + auto mem4 = client.AllocateLockedDiscardableMemory(page_size * 0.2); + + EXPECT_EQ(client.GetBytesAllocated(), 10 * page_size); + + // Does nothing because everything is locked. + client.PurgeUnlockedMemory(); + + EXPECT_EQ(client.GetBytesAllocated(), 10 * page_size); + + mem1->Unlock(); + + // Does nothing, since we don't have any free memory, just unlocked memory. + client.ReleaseFreeMemory(); + + EXPECT_EQ(client.GetBytesAllocated(), 10 * page_size); + + // This gets rid of |mem1| (which is unlocked), but not the rest of the + // memory. + client.PurgeUnlockedMemory(); + + EXPECT_EQ(client.GetBytesAllocated(), 7 * page_size); + + // We do similar checks to above for the rest of the memory. + mem2->Unlock(); + + client.PurgeUnlockedMemory(); + + EXPECT_EQ(client.GetBytesAllocated(), 5 * page_size); + + mem3->Unlock(); + + client.PurgeUnlockedMemory(); + EXPECT_EQ(client.GetBytesAllocated(), 1 * page_size); + + mem4->Unlock(); + + client.PurgeUnlockedMemory(); + EXPECT_EQ(client.GetBytesAllocated(), 0 * page_size); +} + +// This test allocates multiple pieces of memory, then unlocks them all, +// verifying that |PurgeUnlockedMemory| only affects the unlocked pieces of +// memory. +TEST(ClientDiscardableSharedMemoryManagerTest, MultipleAtOnce) { + const size_t page_size = base::GetPageSize(); + TestClientDiscardableSharedMemoryManager client; + + ASSERT_EQ(client.GetBytesAllocated(), 0u); + ASSERT_EQ(client.GetSizeOfFreeLists(), 0u); + + auto mem1 = client.AllocateLockedDiscardableMemory(page_size * 2.2); + auto mem2 = client.AllocateLockedDiscardableMemory(page_size * 1.1); + auto mem3 = client.AllocateLockedDiscardableMemory(page_size * 3.5); + auto mem4 = client.AllocateLockedDiscardableMemory(page_size * 0.2); + + EXPECT_EQ(client.GetBytesAllocated(), 10 * page_size); + + // Does nothing because everything is locked. + client.PurgeUnlockedMemory(); + + EXPECT_EQ(client.GetBytesAllocated(), 10 * page_size); + + // Unlock all pieces of memory at once. + mem1->Unlock(); + mem2->Unlock(); + mem3->Unlock(); + mem4->Unlock(); + + client.PurgeUnlockedMemory(); + EXPECT_EQ(client.GetBytesAllocated(), 0 * page_size); +} + +// Tests that FreeLists are only released once all memory has been released. +TEST(ClientDiscardableSharedMemoryManagerTest, Release) { + const size_t page_size = base::GetPageSize(); + TestClientDiscardableSharedMemoryManager client; + + ASSERT_EQ(client.GetBytesAllocated(), 0u); + ASSERT_EQ(client.GetSizeOfFreeLists(), 0u); + + auto mem1 = client.AllocateLockedDiscardableMemory(page_size * 3); + auto mem2 = client.AllocateLockedDiscardableMemory(page_size * 2); + + size_t freelist_size = client.GetSizeOfFreeLists(); + EXPECT_EQ(client.GetBytesAllocated(), 5 * page_size); + + mem1 = nullptr; + + // Less memory is now allocated, but freelists are grown. + EXPECT_EQ(client.GetBytesAllocated(), page_size * 2); + EXPECT_EQ(client.GetSizeOfFreeLists(), freelist_size + page_size * 3); + + client.PurgeUnlockedMemory(); + + // Purging doesn't remove any memory since none is unlocked, also doesn't + // remove freelists since we still have some. + EXPECT_EQ(client.GetBytesAllocated(), page_size * 2); + EXPECT_EQ(client.GetSizeOfFreeLists(), freelist_size + page_size * 3); + + mem2 = nullptr; + + // No memory is allocated, but freelists are grown. + EXPECT_EQ(client.GetBytesAllocated(), 0u); + EXPECT_EQ(client.GetSizeOfFreeLists(), freelist_size + page_size * 5); + + client.PurgeUnlockedMemory(); + + // Purging now shrinks freelists as well. + EXPECT_EQ(client.GetBytesAllocated(), 0u); + EXPECT_EQ(client.GetSizeOfFreeLists(), 0u); +} + +// Similar to previous test, but makes sure that freelist still shrinks when +// last piece of memory was just unlocked instead of released. +TEST(ClientDiscardableSharedMemoryManagerTest, ReleaseUnlocked) { + const size_t page_size = base::GetPageSize(); + TestClientDiscardableSharedMemoryManager client; + + ASSERT_EQ(client.GetBytesAllocated(), 0u); + ASSERT_EQ(client.GetSizeOfFreeLists(), 0u); + + auto mem1 = client.AllocateLockedDiscardableMemory(page_size * 3); + auto mem2 = client.AllocateLockedDiscardableMemory(page_size * 2); + + size_t freelist_size = client.GetSizeOfFreeLists(); + EXPECT_EQ(client.GetBytesAllocated(), 5 * page_size); + + mem1 = nullptr; + + // Less memory is now allocated, but freelists are grown. + EXPECT_EQ(client.GetBytesAllocated(), page_size * 2); + EXPECT_EQ(client.GetSizeOfFreeLists(), freelist_size + page_size * 3); + + client.PurgeUnlockedMemory(); + + // Purging doesn't remove any memory since none is unlocked, also doesn't + // remove freelists since we still have some. + EXPECT_EQ(client.GetBytesAllocated(), page_size * 2); + EXPECT_EQ(client.GetSizeOfFreeLists(), freelist_size + page_size * 3); + + mem2->Unlock(); + + // No change in memory usage, since memory was only unlocked not released. + EXPECT_EQ(client.GetBytesAllocated(), page_size * 2); + EXPECT_EQ(client.GetSizeOfFreeLists(), freelist_size + page_size * 3); + + client.PurgeUnlockedMemory(); + + // Purging now shrinks freelists as well. + EXPECT_EQ(client.GetBytesAllocated(), 0u); + EXPECT_EQ(client.GetSizeOfFreeLists(), 0u); +} + +} // namespace +} // namespace discardable_memory
diff --git a/components/exo/mime_utils.cc b/components/exo/mime_utils.cc index 40ae71f4..dd8ebef 100644 --- a/components/exo/mime_utils.cc +++ b/components/exo/mime_utils.cc
@@ -17,7 +17,7 @@ namespace exo { std::string GetCharset(const std::string& mime_type) { - // We special case UTF8_STRING to provide minimal handling of X11 apps. + // We special case UTF-8 to provide minimal handling of X11 apps. if (mime_type == ui::kMimeTypeLinuxUtf8String) return std::string(kEncodingUTF8Charset);
diff --git a/components/favicon/core/favicon_backend.cc b/components/favicon/core/favicon_backend.cc index cd4c59c4..b1f49805 100644 --- a/components/favicon/core/favicon_backend.cc +++ b/components/favicon/core/favicon_backend.cc
@@ -204,47 +204,45 @@ return bitmap_results; } -std::vector<favicon_base::FaviconRawBitmapResult> -FaviconBackend::UpdateFaviconMappingsAndFetch( +UpdateFaviconMappingsResult FaviconBackend::UpdateFaviconMappingsAndFetch( const base::flat_set<GURL>& page_urls, const GURL& icon_url, favicon_base::IconType icon_type, const std::vector<int>& desired_sizes) { + UpdateFaviconMappingsResult result; const favicon_base::FaviconID favicon_id = db_->GetFaviconIDForFaviconURL(icon_url, icon_type); if (!favicon_id) - return {}; + return result; for (const GURL& page_url : page_urls) { bool mappings_updated = SetFaviconMappingsForPageAndRedirects(page_url, icon_type, favicon_id); - if (mappings_updated) { - delegate_->OnFaviconChangedForPageAndRedirects(page_url); - delegate_->ScheduleCommitForFavicons(); - } + if (mappings_updated) + result.updated_page_urls.insert(page_url); } - return GetFaviconBitmapResultsForBestMatch({favicon_id}, desired_sizes); + result.bitmap_results = + GetFaviconBitmapResultsForBestMatch({favicon_id}, desired_sizes); + return result; } -void FaviconBackend::DeleteFaviconMappings( +base::flat_set<GURL> FaviconBackend::DeleteFaviconMappings( const base::flat_set<GURL>& page_urls, favicon_base::IconType icon_type) { TRACE_EVENT0("browser", "FaviconBackend::DeleteFaviconMappings"); + base::flat_set<GURL> changed; for (const GURL& page_url : page_urls) { bool mapping_changed = SetFaviconMappingsForPageAndRedirects( page_url, icon_type, /*icon_id=*/0); - - if (mapping_changed) { - // Notify the UI that this function changed an icon mapping. - delegate_->OnFaviconChangedForPageAndRedirects(page_url); - delegate_->ScheduleCommitForFavicons(); - } + if (mapping_changed) + changed.insert(page_url); } + return changed; } -bool FaviconBackend::MergeFavicon( +MergeFaviconResult FaviconBackend::MergeFavicon( const GURL& page_url, const GURL& icon_url, favicon_base::IconType icon_type, @@ -382,15 +380,15 @@ } } + MergeFaviconResult result; // Update the favicon mappings such that only |icon_url| is mapped to // |page_url|. if (icon_mappings.size() != 1 || icon_mappings[0].icon_url != icon_url) { SetFaviconMappingsForPageAndRedirects(page_url, icon_type, favicon_id); - delegate_->OnFaviconChangedForPageAndRedirects(page_url); + result.did_page_to_icon_mapping_change = true; } - - delegate_->ScheduleCommitForFavicons(); - return !bitmap_identical || favicon_bitmaps_copied; + result.did_icon_change = !bitmap_identical || favicon_bitmaps_copied; + return result; } std::set<GURL> FaviconBackend::CloneFaviconMappingsForPages( @@ -430,9 +428,6 @@ changed_page_urls.insert(std::make_move_iterator(v.begin()), std::make_move_iterator(v.end())); } - - if (!changed_page_urls.empty()) - delegate_->ScheduleCommitForFavicons(); return changed_page_urls; } @@ -459,40 +454,42 @@ return true; } -bool FaviconBackend::SetOnDemandFavicons(const GURL& page_url, - favicon_base::IconType icon_type, - const GURL& icon_url, - const std::vector<SkBitmap>& bitmaps) { - return CanSetOnDemandFavicons(page_url, icon_type) && - SetFavicons({page_url}, icon_type, icon_url, bitmaps, +SetFaviconsResult FaviconBackend::SetOnDemandFavicons( + const GURL& page_url, + favicon_base::IconType icon_type, + const GURL& icon_url, + const std::vector<SkBitmap>& bitmaps) { + if (!CanSetOnDemandFavicons(page_url, icon_type)) + return {}; + return SetFavicons({page_url}, icon_type, icon_url, bitmaps, FaviconBitmapType::ON_DEMAND); } -void FaviconBackend::SetFaviconsOutOfDateForPage(const GURL& page_url) { +bool FaviconBackend::SetFaviconsOutOfDateForPage(const GURL& page_url) { TRACE_EVENT0("browser", "FaviconBackend::SetFaviconsOutOfDateForPage"); std::vector<IconMapping> icon_mappings; if (!db_->GetIconMappingsForPageURL(page_url, &icon_mappings)) - return; + return false; for (auto m = icon_mappings.begin(); m != icon_mappings.end(); ++m) db_->SetFaviconOutOfDate(m->icon_id); - delegate_->ScheduleCommitForFavicons(); + return true; } void FaviconBackend::TouchOnDemandFavicon(const GURL& icon_url) { TRACE_EVENT0("browser", "FaviconBackend::TouchOnDemandFavicon"); db_->TouchOnDemandFavicon(icon_url, base::Time::Now()); - delegate_->ScheduleCommitForFavicons(); } -bool FaviconBackend::SetFavicons(const base::flat_set<GURL>& page_urls, - favicon_base::IconType icon_type, - const GURL& icon_url, - const std::vector<SkBitmap>& bitmaps, - FaviconBitmapType bitmap_type) { +SetFaviconsResult FaviconBackend::SetFavicons( + const base::flat_set<GURL>& page_urls, + favicon_base::IconType icon_type, + const GURL& icon_url, + const std::vector<SkBitmap>& bitmaps, + FaviconBitmapType bitmap_type) { TRACE_EVENT0("browser", "FaviconBackend::SetFavicons"); DCHECK(!page_urls.empty()); @@ -512,22 +509,17 @@ favicon_created = true; } - bool favicon_data_modified = false; + SetFaviconsResult result; if (favicon_created || bitmap_type == FaviconBitmapType::ON_VISIT) - favicon_data_modified = SetFaviconBitmaps(icon_id, bitmaps, bitmap_type); + result.did_update_bitmap = SetFaviconBitmaps(icon_id, bitmaps, bitmap_type); for (const GURL& page_url : page_urls) { bool mapping_changed = SetFaviconMappingsForPageAndRedirects(page_url, icon_type, icon_id); - - if (mapping_changed) { - // Notify the UI that this function changed an icon mapping. - delegate_->OnFaviconChangedForPageAndRedirects(page_url); - } + if (mapping_changed) + result.updated_page_urls.insert(page_url); } - - delegate_->ScheduleCommitForFavicons(); - return favicon_data_modified; + return result; } FaviconBackend::FaviconBackend(std::unique_ptr<FaviconDatabase> db,
diff --git a/components/favicon/core/favicon_backend.h b/components/favicon/core/favicon_backend.h index ecc5534..1c9a755e 100644 --- a/components/favicon/core/favicon_backend.h +++ b/components/favicon/core/favicon_backend.h
@@ -77,32 +77,34 @@ // If there is a favicon stored in the database for |icon_url|, a mapping is // added to the database from each element in |page_urls| (and all redirects) // to |icon_url|. - std::vector<favicon_base::FaviconRawBitmapResult> - UpdateFaviconMappingsAndFetch(const base::flat_set<GURL>& page_urls, - const GURL& icon_url, - favicon_base::IconType icon_type, - const std::vector<int>& desired_sizes); + UpdateFaviconMappingsResult UpdateFaviconMappingsAndFetch( + const base::flat_set<GURL>& page_urls, + const GURL& icon_url, + favicon_base::IconType icon_type, + const std::vector<int>& desired_sizes); - void DeleteFaviconMappings(const base::flat_set<GURL>& page_urls, - favicon_base::IconType icon_type); + // Deletes the mappings for the specified page urls. Returns the set of + // page urls that changed. + base::flat_set<GURL> DeleteFaviconMappings( + const base::flat_set<GURL>& page_urls, + favicon_base::IconType icon_type); - // See function of same name in HistoryService for details. Returns true if - // the icon changed. - bool MergeFavicon(const GURL& page_url, - const GURL& icon_url, - favicon_base::IconType icon_type, - scoped_refptr<base::RefCountedMemory> bitmap_data, - const gfx::Size& pixel_size); + // See function of same name in HistoryService for details. + MergeFaviconResult MergeFavicon( + const GURL& page_url, + const GURL& icon_url, + favicon_base::IconType icon_type, + scoped_refptr<base::RefCountedMemory> bitmap_data, + const gfx::Size& pixel_size); // If |bitmap_type| is ON_DEMAND, the icon for |icon_url| will be modified // only if it's not present in the database. In that case, it will be - // initially set as expired. Returns whether the new bitmaps were actually - // written. |page_urls| must not be empty. - bool SetFavicons(const base::flat_set<GURL>& page_urls, - favicon_base::IconType icon_type, - const GURL& icon_url, - const std::vector<SkBitmap>& bitmaps, - FaviconBitmapType bitmap_type); + // initially set as expired. |page_urls| must not be empty. + SetFaviconsResult SetFavicons(const base::flat_set<GURL>& page_urls, + favicon_base::IconType icon_type, + const GURL& icon_url, + const std::vector<SkBitmap>& bitmaps, + FaviconBitmapType bitmap_type); // Causes each page in |page_urls_to_write| to be associated to the same // icon as the page |page_url_to_read| for icon types matching |icon_types|. @@ -114,17 +116,19 @@ const base::flat_set<GURL>& page_urls_to_write); // See function of same name in HistoryService for details. - bool SetOnDemandFavicons(const GURL& page_url, - favicon_base::IconType icon_type, - const GURL& icon_url, - const std::vector<SkBitmap>& bitmaps); + SetFaviconsResult SetOnDemandFavicons(const GURL& page_url, + favicon_base::IconType icon_type, + const GURL& icon_url, + const std::vector<SkBitmap>& bitmaps); // See function of same name in HistoryService for details. bool CanSetOnDemandFavicons(const GURL& page_url, favicon_base::IconType icon_type); - // See function of same name in HistoryService for details. - void SetFaviconsOutOfDateForPage(const GURL& page_url); + // See function of same name in HistoryService for details. Returns true + // if the mapping was updated, false if |page_url| has no icons associated + // with it. + bool SetFaviconsOutOfDateForPage(const GURL& page_url); // See function of same name in HistoryService for details. void TouchOnDemandFavicon(const GURL& icon_url);
diff --git a/components/favicon/core/favicon_backend_delegate.h b/components/favicon/core/favicon_backend_delegate.h index fb093a40..6304431 100644 --- a/components/favicon/core/favicon_backend_delegate.h +++ b/components/favicon/core/favicon_backend_delegate.h
@@ -15,17 +15,10 @@ public: FaviconBackendDelegate() = default; - // The delegate should schedule an asynchronous commit. - virtual void ScheduleCommitForFavicons() = 0; - // Returns the redirects for |page_url|. This should always return a // vector with at least one element (|page_url|). virtual std::vector<GURL> GetCachedRecentRedirectsForPage( const GURL& page_url) = 0; - - // Called when the favicon for a particular page changes. - virtual void OnFaviconChangedForPageAndRedirects(const GURL& page_url) = 0; - protected: virtual ~FaviconBackendDelegate() = default; };
diff --git a/components/favicon/core/favicon_backend_unittest.cc b/components/favicon/core/favicon_backend_unittest.cc index a2b7aab..2d708c4 100644 --- a/components/favicon/core/favicon_backend_unittest.cc +++ b/components/favicon/core/favicon_backend_unittest.cc
@@ -61,7 +61,6 @@ void TearDown() override { backend_.reset(); } // FaviconBackendDelegate: - void ScheduleCommitForFavicons() override {} std::vector<GURL> GetCachedRecentRedirectsForPage( const GURL& page_url) override { auto iter = recent_redirects_.Get(page_url); @@ -69,7 +68,6 @@ return iter->second; return {page_url}; } - void OnFaviconChangedForPageAndRedirects(const GURL& page_url) override {} protected: void SetFavicons(const base::flat_set<GURL>& page_urls, @@ -387,10 +385,8 @@ SetFavicons({page_url1}, IconType::kFavicon, icon_url, bitmaps); - std::vector<favicon_base::FaviconRawBitmapResult> bitmap_results = - backend_->UpdateFaviconMappingsAndFetch({page_url2}, icon_url, - IconType::kFavicon, - GetEdgeSizesSmallAndLarge()); + backend_->UpdateFaviconMappingsAndFetch( + {page_url2}, icon_url, IconType::kFavicon, GetEdgeSizesSmallAndLarge()); // Check that the same FaviconID is mapped to both page URLs. std::vector<IconMapping> icon_mappings; @@ -495,8 +491,10 @@ std::vector<SkBitmap> bitmaps; bitmaps.push_back(CreateBitmap(SK_ColorRED, kSmallEdgeSize)); - EXPECT_TRUE(backend_->SetOnDemandFavicons(page_url, IconType::kFavicon, - icon_url, bitmaps)); + EXPECT_TRUE( + backend_ + ->SetOnDemandFavicons(page_url, IconType::kFavicon, icon_url, bitmaps) + .did_update_bitmap); favicon_base::FaviconID favicon_id = backend_->db()->GetFaviconIDForFaviconURL(icon_url, IconType::kFavicon); @@ -534,8 +532,10 @@ // Call SetOnDemandFavicons() with a different icon URL and bitmap data. bitmaps[0] = CreateBitmap(SK_ColorWHITE, kSmallEdgeSize); - EXPECT_FALSE(backend_->SetOnDemandFavicons(page_url, IconType::kFavicon, - icon_url2, bitmaps)); + EXPECT_FALSE(backend_ + ->SetOnDemandFavicons(page_url, IconType::kFavicon, + icon_url2, bitmaps) + .did_update_bitmap); EXPECT_EQ(0, backend_->db()->GetFaviconIDForFaviconURL(icon_url2, IconType::kFavicon)); @@ -571,8 +571,10 @@ // Call SetOnDemandFavicons() with a different bitmap. bitmaps[0] = CreateBitmap(SK_ColorWHITE, kSmallEdgeSize); - EXPECT_FALSE(backend_->SetOnDemandFavicons(page_url, IconType::kFavicon, - icon_url, bitmaps)); + EXPECT_FALSE( + backend_ + ->SetOnDemandFavicons(page_url, IconType::kFavicon, icon_url, bitmaps) + .did_update_bitmap); EXPECT_EQ(original_favicon_id, backend_->db()->GetFaviconIDForFaviconURL( icon_url, IconType::kFavicon));
diff --git a/components/favicon/core/favicon_types.cc b/components/favicon/core/favicon_types.cc index 659fdd3..d994c2e 100644 --- a/components/favicon/core/favicon_types.cc +++ b/components/favicon/core/favicon_types.cc
@@ -40,4 +40,17 @@ FaviconBitmapIDSize::~FaviconBitmapIDSize() = default; +// UpdateFaviconMappingsResult ------------------------------------------------- + +UpdateFaviconMappingsResult::UpdateFaviconMappingsResult() = default; +UpdateFaviconMappingsResult::UpdateFaviconMappingsResult( + const UpdateFaviconMappingsResult& other) = default; +UpdateFaviconMappingsResult::~UpdateFaviconMappingsResult() = default; + +// SetFaviconsResult ----------------------------------------------------------- + +SetFaviconsResult::SetFaviconsResult() = default; +SetFaviconsResult::SetFaviconsResult(const SetFaviconsResult& other) = default; +SetFaviconsResult::~SetFaviconsResult() = default; + } // namespace favicon
diff --git a/components/favicon/core/favicon_types.h b/components/favicon/core/favicon_types.h index bcf7803..ff1bcfd14 100644 --- a/components/favicon/core/favicon_types.h +++ b/components/favicon/core/favicon_types.h
@@ -110,6 +110,41 @@ gfx::Size pixel_size; }; +struct UpdateFaviconMappingsResult { + UpdateFaviconMappingsResult(); + UpdateFaviconMappingsResult(const UpdateFaviconMappingsResult& other); + ~UpdateFaviconMappingsResult(); + + std::vector<favicon_base::FaviconRawBitmapResult> bitmap_results; + + // Contains the set of page urls that were updated. + base::flat_set<GURL> updated_page_urls; +}; + +struct MergeFaviconResult { + // If true, the mapping between the page and icon changed. + bool did_page_to_icon_mapping_change = false; + + // True if the icon itself changed. + bool did_icon_change = false; +}; + +struct SetFaviconsResult { + SetFaviconsResult(); + SetFaviconsResult(const SetFaviconsResult& other); + ~SetFaviconsResult(); + + bool did_change_database() const { + return did_update_bitmap || !updated_page_urls.empty(); + } + + // Set to true if the bitmap in the db was updated. + bool did_update_bitmap = false; + + // Set of page_urls whose mapping was updated. + base::flat_set<GURL> updated_page_urls; +}; + } // namespace favicon #endif // COMPONENTS_FAVICON_CORE_FAVICON_TYPES_H_
diff --git a/components/feed/core/v2/config.cc b/components/feed/core/v2/config.cc index a2a5207..753f275f 100644 --- a/components/feed/core/v2/config.cc +++ b/components/feed/core/v2/config.cc
@@ -4,7 +4,11 @@ #include "components/feed/core/v2/config.h" +#include "base/containers/flat_set.h" #include "base/metrics/field_trial_params.h" +#include "base/stl_util.h" +#include "base/strings/strcat.h" +#include "components/feed/core/proto/v2/wire/capability.pb.h" #include "components/feed/feed_feature_list.h" namespace feed { @@ -16,7 +20,12 @@ // plan is to send configuration down from the server, and store it in prefs. // The source of a config value would be the following, in order of preference: // finch, server, default-value. -Config g_config; + +bool CapabilityDisabled(feedwire::Capability capability) { + return !base::GetFieldTrialParamByFeatureAsBool( + kInterestFeedV2, + base::StrCat({"enable_", feedwire::Capability_Name(capability)}), true); +} // Override any parameters that may be provided by Finch. void OverrideWithFinch(Config* config) { @@ -66,24 +75,32 @@ base::GetFieldTrialParamByFeatureAsBool( kInterestFeedV2, "upload_actions_on_enter_background", config->upload_actions_on_enter_background); + + // Erase any capabilities with "enable_CAPABILITY = false" set. + base::EraseIf(config->experimental_capabilities, CapabilityDisabled); } } // namespace const Config& GetFeedConfig() { - static bool initialized = false; - if (!initialized) { - initialized = true; - OverrideWithFinch(&g_config); + static Config* s_config = nullptr; + if (!s_config) { + s_config = new Config; + OverrideWithFinch(s_config); } - return g_config; + return *s_config; } void SetFeedConfigForTesting(const Config& config) { - g_config = config; + const_cast<Config&>(GetFeedConfig()) = config; +} + +void OverrideConfigWithFinchForTesting() { + OverrideWithFinch(&const_cast<Config&>(GetFeedConfig())); } Config::Config() = default; Config::Config(const Config& other) = default; +Config::~Config() = default; } // namespace feed
diff --git a/components/feed/core/v2/config.h b/components/feed/core/v2/config.h index 297cc5c6..9ad1a39 100644 --- a/components/feed/core/v2/config.h +++ b/components/feed/core/v2/config.h
@@ -5,7 +5,9 @@ #ifndef COMPONENTS_FEED_CORE_V2_CONFIG_H_ #define COMPONENTS_FEED_CORE_V2_CONFIG_H_ +#include "base/containers/flat_set.h" #include "base/time/time.h" +#include "components/feed/core/proto/v2/wire/capability.pb.h" namespace feed { @@ -36,15 +38,28 @@ int load_more_trigger_lookahead = 5; // Whether to attempt uploading actions when Chrome is hidden. bool upload_actions_on_enter_background = true; + // Set of optional capabilities included in requests. See + // CreateFeedQueryRequest() for required capabilities. + base::flat_set<feedwire::Capability> experimental_capabilities = { + feedwire::Capability::REQUEST_SCHEDULE, + feedwire::Capability::OPEN_IN_TAB, + feedwire::Capability::DOWNLOAD_LINK, + feedwire::Capability::INFINITE_FEED, + feedwire::Capability::DISMISS_COMMAND, + feedwire::Capability::UI_THEME_V2, + feedwire::Capability::UNDO_FOR_DISMISS_COMMAND, + }; Config(); Config(const Config& other); + ~Config(); }; // Gets the current configuration. const Config& GetFeedConfig(); void SetFeedConfigForTesting(const Config& config); +void OverrideConfigWithFinchForTesting(); } // namespace feed
diff --git a/components/feed/core/v2/proto_util.cc b/components/feed/core/v2/proto_util.cc index ee8e0c4a..aa21f4a1 100644 --- a/components/feed/core/v2/proto_util.cc +++ b/components/feed/core/v2/proto_util.cc
@@ -15,6 +15,7 @@ #include "components/feed/core/proto/v2/wire/capability.pb.h" #include "components/feed/core/proto/v2/wire/feed_request.pb.h" #include "components/feed/core/proto/v2/wire/request.pb.h" +#include "components/feed/core/v2/config.h" #include "components/feed/core/v2/feed_stream.h" #if defined(OS_ANDROID) @@ -116,15 +117,9 @@ feedwire::FeedRequest& feed_request = *request.mutable_feed_request(); feed_request.add_client_capability(feedwire::Capability::BASE_UI); - feed_request.add_client_capability(feedwire::Capability::REQUEST_SCHEDULE); - feed_request.add_client_capability(feedwire::Capability::OPEN_IN_TAB); feed_request.add_client_capability(feedwire::Capability::CARD_MENU); - feed_request.add_client_capability(feedwire::Capability::DOWNLOAD_LINK); - feed_request.add_client_capability(feedwire::Capability::INFINITE_FEED); - feed_request.add_client_capability(feedwire::Capability::DISMISS_COMMAND); - feed_request.add_client_capability(feedwire::Capability::UI_THEME_V2); - feed_request.add_client_capability( - feedwire::Capability::UNDO_FOR_DISMISS_COMMAND); + for (auto capability : GetFeedConfig().experimental_capabilities) + feed_request.add_client_capability(capability); *feed_request.mutable_client_info() = CreateClientInfo(request_metadata); feedwire::FeedQuery& query = *feed_request.mutable_feed_query();
diff --git a/components/feed/core/v2/proto_util_unittest.cc b/components/feed/core/v2/proto_util_unittest.cc index e02772a..1c9eb37b 100644 --- a/components/feed/core/v2/proto_util_unittest.cc +++ b/components/feed/core/v2/proto_util_unittest.cc
@@ -4,15 +4,30 @@ #include "components/feed/core/v2/proto_util.h" +#include "base/test/scoped_feature_list.h" +#include "components/feed/core/proto/v2/wire/capability.pb.h" #include "components/feed/core/proto/v2/wire/client_info.pb.h" +#include "components/feed/core/proto/v2/wire/feed_request.pb.h" +#include "components/feed/core/proto/v2/wire/request.pb.h" +#include "components/feed/core/v2/config.h" #include "components/feed/core/v2/test/proto_printer.h" #include "components/feed/core/v2/types.h" +#include "components/feed/feed_feature_list.h" #include "components/version_info/channel.h" #include "testing/gtest/include/gtest/gtest.h" namespace feed { namespace { +bool HasCapability(const feedwire::FeedRequest& request, + feedwire::Capability wanted_capability) { + for (auto capability : request.client_capability()) { + if (wanted_capability == capability) + return true; + } + return false; +} + TEST(ProtoUtilTest, CreateClientInfo) { RequestMetadata request_metadata; request_metadata.chrome_info.version = base::Version({1, 2, 3, 4}); @@ -40,5 +55,56 @@ EXPECT_EQ("en-US", result.locale()); } +TEST(ProtoUtilTest, DefaultCapabilities) { + feedwire::FeedRequest request = + CreateFeedQueryRefreshRequest(feedwire::FeedQuery::MANUAL_REFRESH, + /*request_metadata=*/{}, + /*consistency_token=*/std::string()) + .feed_request(); + + ASSERT_EQ(9, request.client_capability_size()); + EXPECT_TRUE(HasCapability(request, feedwire::Capability::BASE_UI)); + EXPECT_TRUE(HasCapability(request, feedwire::Capability::REQUEST_SCHEDULE)); + EXPECT_TRUE(HasCapability(request, feedwire::Capability::OPEN_IN_TAB)); + EXPECT_TRUE(HasCapability(request, feedwire::Capability::CARD_MENU)); + EXPECT_TRUE(HasCapability(request, feedwire::Capability::DOWNLOAD_LINK)); + EXPECT_TRUE(HasCapability(request, feedwire::Capability::INFINITE_FEED)); + EXPECT_TRUE(HasCapability(request, feedwire::Capability::DISMISS_COMMAND)); + EXPECT_TRUE(HasCapability(request, feedwire::Capability::UI_THEME_V2)); + EXPECT_TRUE( + HasCapability(request, feedwire::Capability::UNDO_FOR_DISMISS_COMMAND)); +} + +TEST(ProtoUtilTest, DisableCapabilitiesWithFinch) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeatureWithParameters( + kInterestFeedV2, + {{"enable_BASE_UI", "false"}, {"enable_INFINITE_FEED", "false"}}); + OverrideConfigWithFinchForTesting(); + + feedwire::FeedRequest request = + CreateFeedQueryRefreshRequest(feedwire::FeedQuery::MANUAL_REFRESH, + /*request_metadata=*/{}, + /*consistency_token=*/std::string()) + .feed_request(); + + ASSERT_EQ(8, request.client_capability_size()); + + // Optional capabilities can be disabled. + EXPECT_FALSE(HasCapability(request, feedwire::Capability::INFINITE_FEED)); + + // Required capabilities can't be disabled. + EXPECT_TRUE(HasCapability(request, feedwire::Capability::BASE_UI)); + + EXPECT_TRUE(HasCapability(request, feedwire::Capability::REQUEST_SCHEDULE)); + EXPECT_TRUE(HasCapability(request, feedwire::Capability::OPEN_IN_TAB)); + EXPECT_TRUE(HasCapability(request, feedwire::Capability::CARD_MENU)); + EXPECT_TRUE(HasCapability(request, feedwire::Capability::DOWNLOAD_LINK)); + EXPECT_TRUE(HasCapability(request, feedwire::Capability::DISMISS_COMMAND)); + EXPECT_TRUE(HasCapability(request, feedwire::Capability::UI_THEME_V2)); + EXPECT_TRUE( + HasCapability(request, feedwire::Capability::UNDO_FOR_DISMISS_COMMAND)); +} + } // namespace } // namespace feed
diff --git a/components/history/core/browser/history_backend.cc b/components/history/core/browser/history_backend.cc index 580e9337f..e97173c 100644 --- a/components/history/core/browser/history_backend.cc +++ b/components/history/core/browser/history_backend.cc
@@ -1675,8 +1675,14 @@ const std::vector<int>& desired_sizes) { if (!favicon_backend_) return {}; - return favicon_backend_->UpdateFaviconMappingsAndFetch( + auto result = favicon_backend_->UpdateFaviconMappingsAndFetch( page_urls, icon_url, icon_type, desired_sizes); + if (!result.updated_page_urls.empty()) { + for (auto& page_url : result.updated_page_urls) + SendFaviconChangedNotificationForPageAndRedirects(page_url); + ScheduleCommit(); + } + return result.bitmap_results; } void HistoryBackend::DeleteFaviconMappings( @@ -1685,7 +1691,12 @@ if (!favicon_backend_ || !db_) return; - favicon_backend_->DeleteFaviconMappings(page_urls, icon_type); + auto deleted_page_urls = + favicon_backend_->DeleteFaviconMappings(page_urls, icon_type); + for (auto& deleted_page_url : deleted_page_urls) + SendFaviconChangedNotificationForPageAndRedirects(deleted_page_url); + if (!deleted_page_urls.empty()) + ScheduleCommit(); } void HistoryBackend::MergeFavicon( @@ -1694,22 +1705,29 @@ favicon_base::IconType icon_type, scoped_refptr<base::RefCountedMemory> bitmap_data, const gfx::Size& pixel_size) { - if (favicon_backend_ && db_ && - favicon_backend_->MergeFavicon(page_url, icon_url, icon_type, bitmap_data, - pixel_size)) { + if (!favicon_backend_ || !db_) + return; + + favicon::MergeFaviconResult result = favicon_backend_->MergeFavicon( + page_url, icon_url, icon_type, bitmap_data, pixel_size); + if (result.did_page_to_icon_mapping_change) + SendFaviconChangedNotificationForPageAndRedirects(page_url); + if (result.did_icon_change) SendFaviconChangedNotificationForIconURL(icon_url); - } + ScheduleCommit(); } void HistoryBackend::SetFavicons(const base::flat_set<GURL>& page_urls, favicon_base::IconType icon_type, const GURL& icon_url, const std::vector<SkBitmap>& bitmaps) { - if (favicon_backend_ && + if (!favicon_backend_) + return; + + ProcessSetFaviconsResult( favicon_backend_->SetFavicons(page_urls, icon_type, icon_url, bitmaps, - FaviconBitmapType::ON_VISIT)) { - SendFaviconChangedNotificationForIconURL(icon_url); - } + FaviconBitmapType::ON_VISIT), + icon_url); } void HistoryBackend::CloneFaviconMappingsForPages( @@ -1726,6 +1744,7 @@ if (changed_urls.empty()) return; + ScheduleCommit(); NotifyFaviconsChanged(changed_urls, GURL()); } @@ -1739,18 +1758,19 @@ favicon_base::IconType icon_type, const GURL& icon_url, const std::vector<SkBitmap>& bitmaps) { - if (favicon_backend_ && db_ && - favicon_backend_->SetOnDemandFavicons(page_url, icon_type, icon_url, - bitmaps)) { - SendFaviconChangedNotificationForIconURL(icon_url); - return true; - } - return false; + if (!favicon_backend_ || !db_) + return false; + + return ProcessSetFaviconsResult(favicon_backend_->SetOnDemandFavicons( + page_url, icon_type, icon_url, bitmaps), + icon_url); } void HistoryBackend::SetFaviconsOutOfDateForPage(const GURL& page_url) { - if (favicon_backend_) - favicon_backend_->SetFaviconsOutOfDateForPage(page_url); + if (favicon_backend_ && + favicon_backend_->SetFaviconsOutOfDateForPage(page_url)) { + ScheduleCommit(); + } } void HistoryBackend::TouchOnDemandFavicon(const GURL& icon_url) { @@ -1759,6 +1779,7 @@ if (!favicon_backend_) return; favicon_backend_->TouchOnDemandFavicon(icon_url); + ScheduleCommit(); } void HistoryBackend::SetImportedFavicons( @@ -2313,17 +2334,23 @@ return true; } -void HistoryBackend::ScheduleCommitForFavicons() { - ScheduleCommit(); -} - std::vector<GURL> HistoryBackend::GetCachedRecentRedirectsForPage( const GURL& page_url) { return GetCachedRecentRedirects(page_url); } -void HistoryBackend::OnFaviconChangedForPageAndRedirects(const GURL& page_url) { - SendFaviconChangedNotificationForPageAndRedirects(page_url); +bool HistoryBackend::ProcessSetFaviconsResult( + const favicon::SetFaviconsResult& result, + const GURL& icon_url) { + if (!result.did_change_database()) + return false; + + ScheduleCommit(); + if (result.did_update_bitmap) + SendFaviconChangedNotificationForIconURL(icon_url); + for (const GURL& page_url : result.updated_page_urls) + SendFaviconChangedNotificationForPageAndRedirects(page_url); + return true; } } // namespace history
diff --git a/components/history/core/browser/history_backend.h b/components/history/core/browser/history_backend.h index ca546be..ae6c474 100644 --- a/components/history/core/browser/history_backend.h +++ b/components/history/core/browser/history_backend.h
@@ -788,11 +788,11 @@ void DeleteFTSIndexDatabases(); // favicon::FaviconBackendDelegate - void ScheduleCommitForFavicons() override; std::vector<GURL> GetCachedRecentRedirectsForPage( const GURL& page_url) override; - void OnFaviconChangedForPageAndRedirects(const GURL& page_url) override; + bool ProcessSetFaviconsResult(const favicon::SetFaviconsResult& result, + const GURL& icon_url); // Data ---------------------------------------------------------------------- // Delegate. See the class definition above for more information. This will
diff --git a/components/invalidation/impl/invalidation_switches.cc b/components/invalidation/impl/invalidation_switches.cc index bad2851c..2147302 100644 --- a/components/invalidation/impl/invalidation_switches.cc +++ b/components/invalidation/impl/invalidation_switches.cc
@@ -36,8 +36,8 @@ const base::Feature kSyncInstanceIDTokenTTL { "SyncInstanceIDTokenTTL", -#if defined(OS_WIN) || defined(OS_MAC) || \ - (defined(OS_LINUX) && !defined(OS_CHROMEOS)) +#if defined(OS_WIN) || defined(OS_MAC) || defined(OS_LINUX) || \ + defined(OS_CHROMEOS) || defined(OS_IOS) base::FEATURE_ENABLED_BY_DEFAULT #else base::FEATURE_DISABLED_BY_DEFAULT
diff --git a/components/ntp_tiles/most_visited_sites_unittest.cc b/components/ntp_tiles/most_visited_sites_unittest.cc index a58b031..46b333c 100644 --- a/components/ntp_tiles/most_visited_sites_unittest.cc +++ b/components/ntp_tiles/most_visited_sites_unittest.cc
@@ -289,7 +289,7 @@ class PopularSitesFactoryForTest { public: - PopularSitesFactoryForTest( + explicit PopularSitesFactoryForTest( sync_preferences::TestingPrefServiceSyncable* pref_service) : prefs_(pref_service) { test_shared_loader_factory_ = @@ -393,27 +393,6 @@ scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_; }; -// CallbackList-like container without Subscription, mimicking the -// implementation in TopSites (which doesn't use base::CallbackList). -class TopSitesCallbackList { - public: - void Add(TopSites::GetMostVisitedURLsCallback callback) { - callbacks_.push_back(std::move(callback)); - } - - void ClearAndNotify(const MostVisitedURLList& list) { - std::vector<TopSites::GetMostVisitedURLsCallback> callbacks; - callbacks.swap(callbacks_); - for (auto& callback : callbacks) - std::move(callback).Run(list); - } - - bool empty() const { return callbacks_.empty(); } - - private: - std::vector<TopSites::GetMostVisitedURLsCallback> callbacks_; -}; - } // namespace // Param is a tuple with two components: @@ -423,10 +402,10 @@ class MostVisitedSitesTest : public ::testing::TestWithParam<std::tuple<bool, bool>> { protected: - MostVisitedSitesTest() - : is_custom_links_enabled_(false), - popular_sites_factory_(&pref_service_), - mock_top_sites_(new StrictMock<MockTopSites>()) { + using TopSitesCallbackList = + base::OnceCallbackList<TopSites::GetMostVisitedURLsCallback::RunType>; + + MostVisitedSitesTest() { MostVisitedSites::RegisterProfilePrefs(pref_service_.registry()); std::vector<base::Feature> enabled_features; @@ -548,7 +527,7 @@ void EnableCustomLinks() { is_custom_links_enabled_ = true; } - bool is_custom_links_enabled_; + bool is_custom_links_enabled_ = false; base::CallbackList<SuggestionsService::ResponseCallback::RunType> suggestions_service_callbacks_; TopSitesCallbackList top_sites_callbacks_; @@ -556,8 +535,9 @@ base::test::SingleThreadTaskEnvironment task_environment_; data_decoder::test::InProcessDataDecoder in_process_data_decoder_; sync_preferences::TestingPrefServiceSyncable pref_service_; - PopularSitesFactoryForTest popular_sites_factory_; - scoped_refptr<StrictMock<MockTopSites>> mock_top_sites_; + PopularSitesFactoryForTest popular_sites_factory_{&pref_service_}; + scoped_refptr<StrictMock<MockTopSites>> mock_top_sites_ = + base::MakeRefCounted<StrictMock<MockTopSites>>(); StrictMock<MockSuggestionsService> mock_suggestions_service_; StrictMock<MockMostVisitedSitesObserver> mock_observer_; std::unique_ptr<MostVisitedSites> most_visited_sites_; @@ -1247,8 +1227,8 @@ suggestions_service_callbacks_.Notify(SuggestionsProfile()); VerifyAndClearExpectations(); EXPECT_CALL(mock_observer_, OnURLsAvailable(_)).Times(0); - top_sites_callbacks_.ClearAndNotify( - {MakeMostVisitedURL("Site 2", "http://site2/")}); + top_sites_callbacks_.Notify( + MostVisitedURLList({MakeMostVisitedURL("Site 2", "http://site2/")})); base::RunLoop().RunUntilIdle(); } @@ -1837,7 +1817,8 @@ TEST_P(MostVisitedSitesWithCacheHitTest, ShouldSwitchToTopSitesIfEmptyUpdateBySuggestionsService) { EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_)) - .WillOnce(Invoke(&top_sites_callbacks_, &TopSitesCallbackList::Add)); + .WillOnce( + Invoke(&top_sites_callbacks_, &TopSitesCallbackList::AddUnsafe)); suggestions_service_callbacks_.Notify(SuggestionsProfile()); VerifyAndClearExpectations(); @@ -1851,11 +1832,11 @@ MatchesTile("Site 6", "http://site6/", TileSource::TOP_SITES), MatchesTile("Site 7", "http://site7/", TileSource::TOP_SITES)))))); - top_sites_callbacks_.ClearAndNotify( - {MakeMostVisitedURL("Site 4", "http://site4/"), - MakeMostVisitedURL("Site 5", "http://site5/"), - MakeMostVisitedURL("Site 6", "http://site6/"), - MakeMostVisitedURL("Site 7", "http://site7/")}); + top_sites_callbacks_.Notify( + MostVisitedURLList({MakeMostVisitedURL("Site 4", "http://site4/"), + MakeMostVisitedURL("Site 5", "http://site5/"), + MakeMostVisitedURL("Site 6", "http://site6/"), + MakeMostVisitedURL("Site 7", "http://site7/")})); base::RunLoop().RunUntilIdle(); } @@ -1889,7 +1870,8 @@ EXPECT_CALL(mock_suggestions_service_, GetSuggestionsDataFromCache()) .WillOnce(Return(SuggestionsProfile())); // Empty cache. EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_)) - .WillOnce(Invoke(&top_sites_callbacks_, &TopSitesCallbackList::Add)); + .WillOnce( + Invoke(&top_sites_callbacks_, &TopSitesCallbackList::AddUnsafe)); EXPECT_CALL(*mock_top_sites_, SyncWithHistory()); EXPECT_CALL(mock_suggestions_service_, FetchSuggestionsData()) .WillOnce(Return(true)); @@ -1953,8 +1935,8 @@ VerifyAndClearExpectations(); // Reply from top sites is ignored (i.e. not reported to observer). - top_sites_callbacks_.ClearAndNotify( - {MakeMostVisitedURL("Site 4", "http://site4/")}); + top_sites_callbacks_.Notify( + MostVisitedURLList({MakeMostVisitedURL("Site 4", "http://site4/")})); VerifyAndClearExpectations(); // Update by TopSites is also ignored. @@ -1979,10 +1961,10 @@ MatchesTile("Site 2", "http://site2/", TileSource::TOP_SITES), MatchesTile("Site 3", "http://site3/", TileSource::TOP_SITES)))))); - top_sites_callbacks_.ClearAndNotify( - {MakeMostVisitedURL("Site 1", "http://site1/"), - MakeMostVisitedURL("Site 2", "http://site2/"), - MakeMostVisitedURL("Site 3", "http://site3/")}); + top_sites_callbacks_.Notify( + MostVisitedURLList({MakeMostVisitedURL("Site 1", "http://site1/"), + MakeMostVisitedURL("Site 2", "http://site2/"), + MakeMostVisitedURL("Site 3", "http://site3/")})); base::RunLoop().RunUntilIdle(); } @@ -1998,10 +1980,10 @@ MatchesTile("Site 2", "http://site2/", TileSource::TOP_SITES), MatchesTile("Site 3", "http://site3/", TileSource::TOP_SITES)))))); - top_sites_callbacks_.ClearAndNotify( - {MakeMostVisitedURL("Site 1", "http://site1/"), - MakeMostVisitedURL("Site 2", "http://site2/"), - MakeMostVisitedURL("Site 3", "http://site3/")}); + top_sites_callbacks_.Notify( + MostVisitedURLList({MakeMostVisitedURL("Site 1", "http://site1/"), + MakeMostVisitedURL("Site 2", "http://site2/"), + MakeMostVisitedURL("Site 3", "http://site3/")})); VerifyAndClearExpectations(); // Reply from suggestions service overrides top sites. @@ -2034,10 +2016,10 @@ MatchesTile("Site 2", "http://site2/", TileSource::TOP_SITES), MatchesTile("Site 3", "http://site3/", TileSource::TOP_SITES)))))); - top_sites_callbacks_.ClearAndNotify( - {MakeMostVisitedURL("Site 1", "http://site1/"), - MakeMostVisitedURL("Site 2", "http://site2/"), - MakeMostVisitedURL("Site 3", "http://site3/")}); + top_sites_callbacks_.Notify( + MostVisitedURLList({MakeMostVisitedURL("Site 1", "http://site1/"), + MakeMostVisitedURL("Site 2", "http://site2/"), + MakeMostVisitedURL("Site 3", "http://site3/")})); VerifyAndClearExpectations(); // Reply from suggestions service is empty and thus ignored. @@ -2056,10 +2038,10 @@ MatchesTile("Site 2", "http://site2/", TileSource::TOP_SITES), MatchesTile("Site 3", "http://site3/", TileSource::TOP_SITES)))))); - top_sites_callbacks_.ClearAndNotify( - {MakeMostVisitedURL("Site 1", "http://site1/"), - MakeMostVisitedURL("Site 2", "http://site2/"), - MakeMostVisitedURL("Site 3", "http://site3/")}); + top_sites_callbacks_.Notify( + MostVisitedURLList({MakeMostVisitedURL("Site 1", "http://site1/"), + MakeMostVisitedURL("Site 2", "http://site2/"), + MakeMostVisitedURL("Site 3", "http://site3/")})); VerifyAndClearExpectations(); // Reply from suggestions service is empty and thus ignored. @@ -2105,7 +2087,7 @@ SectionType::PERSONALIZED, IsEmpty())))); } suggestions_service_callbacks_.Notify(SuggestionsProfile()); - top_sites_callbacks_.ClearAndNotify(MostVisitedURLList{}); + top_sites_callbacks_.Notify(MostVisitedURLList()); base::RunLoop().RunUntilIdle(); } @@ -2124,22 +2106,23 @@ suggestions_service_callbacks_.Notify(SuggestionsProfile()); - top_sites_callbacks_.ClearAndNotify( - {MakeMostVisitedURL("Site 1", "http://site1/"), - MakeMostVisitedURL("Site 2", "http://site2/"), - MakeMostVisitedURL("Site 3", "http://site3/")}); + top_sites_callbacks_.Notify( + MostVisitedURLList({MakeMostVisitedURL("Site 1", "http://site1/"), + MakeMostVisitedURL("Site 2", "http://site2/"), + MakeMostVisitedURL("Site 3", "http://site3/")})); base::RunLoop().RunUntilIdle(); for (int i = 0; i < 4; ++i) { EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_)) - .WillOnce(Invoke(&top_sites_callbacks_, &TopSitesCallbackList::Add)); + .WillOnce( + Invoke(&top_sites_callbacks_, &TopSitesCallbackList::AddUnsafe)); mock_top_sites_->NotifyTopSitesChanged( history::TopSitesObserver::ChangeReason::MOST_VISITED); EXPECT_FALSE(top_sites_callbacks_.empty()); - top_sites_callbacks_.ClearAndNotify( - {MakeMostVisitedURL("Site 1", "http://site1/"), - MakeMostVisitedURL("Site 2", "http://site2/"), - MakeMostVisitedURL("Site 3", "http://site3/")}); + top_sites_callbacks_.Notify( + MostVisitedURLList({MakeMostVisitedURL("Site 1", "http://site1/"), + MakeMostVisitedURL("Site 2", "http://site2/"), + MakeMostVisitedURL("Site 3", "http://site3/")})); base::RunLoop().RunUntilIdle(); } }
diff --git a/components/omnibox/browser/omnibox_event_global_tracker.cc b/components/omnibox/browser/omnibox_event_global_tracker.cc index 8f0752a..db4c7cd 100644 --- a/components/omnibox/browser/omnibox_event_global_tracker.cc +++ b/components/omnibox/browser/omnibox_event_global_tracker.cc
@@ -10,7 +10,8 @@ return base::Singleton<OmniboxEventGlobalTracker>::get(); } -std::unique_ptr<base::CallbackList<void(OmniboxLog*)>::Subscription> +std::unique_ptr< + OmniboxEventGlobalTracker::OnURLOpenedCallbackList::Subscription> OmniboxEventGlobalTracker::RegisterCallback(const OnURLOpenedCallback& cb) { return on_url_opened_callback_list_.Add(cb); }
diff --git a/components/omnibox/browser/omnibox_event_global_tracker.h b/components/omnibox/browser/omnibox_event_global_tracker.h index c4a87aff..858077b244 100644 --- a/components/omnibox/browser/omnibox_event_global_tracker.h +++ b/components/omnibox/browser/omnibox_event_global_tracker.h
@@ -24,14 +24,15 @@ // forwards the event to its registered observers. class OmniboxEventGlobalTracker { public: - typedef base::RepeatingCallback<void(OmniboxLog*)> OnURLOpenedCallback; + using OnURLOpenedCallbackList = base::CallbackList<void(OmniboxLog*)>; + using OnURLOpenedCallback = OnURLOpenedCallbackList::CallbackType; // Returns the instance of OmniboxEventGlobalTracker. static OmniboxEventGlobalTracker* GetInstance(); // Registers |cb| to be invoked when user open an URL from the omnibox. - std::unique_ptr<base::CallbackList<void(OmniboxLog*)>::Subscription> - RegisterCallback(const OnURLOpenedCallback& cb); + std::unique_ptr<OnURLOpenedCallbackList::Subscription> RegisterCallback( + const OnURLOpenedCallback& cb); // Called to notify all registered callbacks that an URL was opened from // the omnibox. @@ -46,7 +47,7 @@ OmniboxEventGlobalTracker& operator=(const OmniboxEventGlobalTracker&) = delete; - base::CallbackList<void(OmniboxLog*)> on_url_opened_callback_list_; + OnURLOpenedCallbackList on_url_opened_callback_list_; }; #endif // COMPONENTS_OMNIBOX_BROWSER_OMNIBOX_EVENT_GLOBAL_TRACKER_H_
diff --git a/components/omnibox/browser/omnibox_pedal_concepts.h b/components/omnibox/browser/omnibox_pedal_concepts.h index 0ea6abe..78956b2 100644 --- a/components/omnibox/browser/omnibox_pedal_concepts.h +++ b/components/omnibox/browser/omnibox_pedal_concepts.h
@@ -10,7 +10,7 @@ // This value is generated during Pedal concept data processing, and written // to all data files as well as the source code here to ensure synchrony. // The runtime loaded data must match this version exactly or it won't load. -constexpr int OMNIBOX_PEDAL_CONCEPTS_DATA_VERSION = 15462706; +constexpr int OMNIBOX_PEDAL_CONCEPTS_DATA_VERSION = 15468548; // Unique identifiers for Pedals, used to bind loaded data to implementations. enum class OmniboxPedalId {
diff --git a/components/omnibox/resources/omnibox_pedal_concepts.json b/components/omnibox/resources/omnibox_pedal_concepts.json index ad7c758..2a8fcac6 100644 --- a/components/omnibox/resources/omnibox_pedal_concepts.json +++ b/components/omnibox/resources/omnibox_pedal_concepts.json
@@ -1,7 +1,7 @@ { "schema": "pedals_translation_model", "schema_version": 1, - "time_generated": "2020-08-10T23:46:42.165601123+00:00", + "time_generated": "2020-08-15T01:08:48.941836349+00:00", "primary_language_code": "en", "locales": [ { @@ -229,6 +229,1604 @@ ] }, { + "language_code": "ar", + "tokenize_characters": " -", + "ignore_group": { + "required": false, + "single": false, + "synonyms": [ + "لي/الخاصة بي/التابعة/الخاص/التابع", + "ضمن/غضون/خلال", + "لـ/لمدة", + "إتمام", + "داخل", + "كيف", + "على", + "إلى", + "أنا", + "ال", + "في", + "an", + "a" + ] + }, + "pedals": [ + { + "name": "CLEAR_BROWSING_DATA", + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + "google chrome", + "متصفّح", + "تصفُّح", + "chrome" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "إزالة", + "حذف", + "مسح", + "محو", + "حجب" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "ذاكرة التخزين المؤقت", + "ملفات تعريف الارتباط", + "معلومات", + "معلومات", + "بيانات", + "سجلّ" + ] + } + ] + }, + { + "name": "MANAGE_PASSWORDS", + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + "google chrome", + "متصفّح", + "chrome" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "تعديل", + "إدارة", + "تحديث", + "تغيير", + "إظهار", + "مدير", + "حفظ", + "عرض" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "بيانات الاعتماد", + "كلمات المرور", + "كلمة مرور" + ] + } + ] + }, + { + "name": "UPDATE_CREDIT_CARD", + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + "google chrome", + "متصفّح", + "chrome" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "إدارة", + "تحديث", + "تعديل", + "تغيير", + "حفظ" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "معلومات بطاقة الائتمان", + "معلومات بطاقة الائتمان", + "بطاقات الائتمان", + "معلومات البطاقة", + "معلومات البطاقة", + "بطاقة ائتمان", + "طرق الدفع", + "الدفعات", + "بطاقات", + "الدفع" + ] + } + ] + }, + { + "name": "LAUNCH_INCOGNITO", + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + "google chrome", + "متصفّح", + "chrome" + ] + }, + { + "required": false, + "single": true, + "synonyms": [ + "تشغيل", + "إنشاء", + "دخول", + "بدء", + "فتح" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "علامة تبويب في وضع التصفّح المتخفي", + "نافذة التصفّح المتخفي", + "وضع التصفّح المتخفي", + "علامة تبويب خاصة", + "التصفح المتخفي", + "الوضع الخاص", + "نافذة خاصة" + ] + } + ] + }, + { + "name": "TRANSLATE", + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + "google chrome", + "متصفّح", + "chrome" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "تغيير اللغة", + "ترجمة" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "هذه الصفحة", + "صفحة", + "هذه" + ] + } + ] + }, + { + "name": "UPDATE_CHROME", + "groups": [ + { + "required": true, + "single": true, + "synonyms": [ + "google chrome", + "متصفّح", + "chrome" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "ترقية", + "تثبيت", + "تحديث" + ] + } + ] + } + ] + }, + { + "language_code": "bg", + "tokenize_characters": " -", + "ignore_group": { + "required": false, + "single": false, + "synonyms": [ + "как", + "да", + "се", + "от", + "на", + "за", + "си", + "ми", + "в" + ] + }, + "pedals": [ + { + "name": "CLEAR_BROWSING_DATA", + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + "сърфиране", + "браузване", + "браузъра", + "браузър", + "google chrome", + "chrome" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "премахване", + "изчистване", + "изтриване", + "премахни", + "премахна", + "премахва", + "изчиства", + "премахне", + "изчисти", + "изчистя", + "изтрива", + "изчисти", + "изтрий", + "изтрия", + "изтрие", + "трие" + ] + }, + { + "required": false, + "single": true, + "synonyms": [ + "информацията", + "бисквитките", + "информация", + "бисквитки", + "историята", + "история", + "данните", + "данни", + "кеша", + "кеш" + ] + } + ] + }, + { + "name": "MANAGE_PASSWORDS", + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + "браузъра", + "браузър", + "google chrome", + "chrome" + ] + }, + { + "required": false, + "single": true, + "synonyms": [ + "актуализиране", + "актуализирай", + "актуализация", + "актуализират", + "редактиране", + "управляване", + "актуализира", + "редактирай", + "редактират", + "редактирам", + "управление", + "управлявай", + "управляват", + "редактира", + "управлява", + "запазване", + "записване", + "запомняне", + "редакция", + "мениджър", + "променят", + "записват", + "запомнят", + "промяна", + "промени", + "променя", + "запазят", + "записва", + "запомни", + "запомня", + "покажат", + "сменят", + "запази", + "запазя", + "запиши", + "запиша", + "виждам", + "виждат", + "покажа", + "покажи", + "покаже", + "смени", + "смяна", + "сменя", + "запис", + "видя", + "види" + ] + }, + { + "required": false, + "single": true, + "synonyms": [ + "идентификацията", + "данните за вход", + "идентификация", + "данни за вход", + "паролите", + "паролата", + "пароли", + "парола" + ] + } + ] + }, + { + "name": "UPDATE_CREDIT_CARD", + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + "браузъра", + "браузър", + "google chrome", + "chrome" + ] + }, + { + "required": false, + "single": true, + "synonyms": [ + "актуализиране", + "актуализирай", + "актуализация", + "актуализират", + "редактиране", + "управляване", + "актуализира", + "редактирай", + "редактират", + "редактирам", + "управление", + "управлявай", + "управляват", + "редактира", + "управлява", + "запазване", + "записване", + "запомняне", + "редакция", + "променят", + "записват", + "запомнят", + "промяна", + "промени", + "променя", + "запазят", + "записва", + "запомни", + "запомня", + "запази", + "запазя", + "запиши", + "запиша", + "запис" + ] + }, + { + "required": false, + "single": true, + "synonyms": [ + "информацията кредитната карта", + "информация кредитната карта", + "информацията кредитна карта", + "информация кредитна карта", + "номер кредитната карта", + "данни кредитната карта", + "номер кредитна карта", + "данни кредитна карта", + "информация картата", + "кредитната карта", + "кредитните карти", + "информация карта", + "кредитна карта", + "кредитни карти", + "начини плащане", + "данни картата", + "данни карта", + "плащания", + "картите", + "плащане", + "карти" + ] + } + ] + }, + { + "name": "LAUNCH_INCOGNITO", + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + "браузъра", + "браузър", + "google chrome", + "chrome" + ] + }, + { + "required": false, + "single": true, + "synonyms": [ + "стартиране", + "създаване", + "стартирам", + "стартирай", + "отваряне", + "стартира", + "създавам", + "пускане", + "влизане", + "отварям", + "пускам", + "влизам", + "отворя", + "отваря", + "отвори", + "създам", + "създай", + "пуска", + "пусна", + "пусни", + "влиза", + "вляза", + "влез" + ] + }, + { + "required": false, + "single": true, + "synonyms": [ + "поверително сърфиране", + "прозорец инкогнито", + "инкогнито прозорец", + "поверителен раздел", + "поверителен режим", + "раздел инкогнито", + "инкогнито раздел", + "частно сърфиране", + "режим инкогнито", + "инкогнито режим", + "поверителен таб", + "таб инкогнито", + "инкогнито таб", + "частен раздел", + "частен режим", + "частен таб", + "инкогнито", + "частен" + ] + } + ] + }, + { + "name": "TRANSLATE", + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + "браузъра", + "браузър", + "google chrome", + "chrome" + ] + }, + { + "required": false, + "single": true, + "synonyms": [ + "промяна езика", + "промяна език", + "смяна езика", + "превеждане", + "смяна език", + "друг език", + "превежда", + "преведи", + "преведа", + "превод" + ] + }, + { + "required": false, + "single": true, + "synonyms": [ + "тази страница", + "страницата", + "страница", + "това" + ] + } + ] + }, + { + "name": "UPDATE_CHROME", + "groups": [ + { + "required": true, + "single": true, + "synonyms": [ + "браузъра", + "браузър", + "google chrome", + "chrome" + ] + }, + { + "required": false, + "single": true, + "synonyms": [ + "актуализиране", + "надстройване", + "актуализирам", + "актуализирай", + "инсталиране", + "актуализира", + "надстройва", + "инсталирам", + "инсталирай", + "обновяване", + "инсталира", + "ъпгрейдна", + "ъпгрейдни", + "надстроя", + "надстрой", + "ъпдейтна", + "ъпдейтва", + "ъпдейтни", + "ъпгрейд", + "обновя", + "обнови", + "ъпдейт" + ] + } + ] + } + ] + }, + { + "language_code": "bn", + "tokenize_characters": " -", + "ignore_group": { + "required": false, + "single": false, + "synonyms": [ + "এর মধ্যে", + "এর দিকে", + "কীভাবে", + "ভেতরে", + "মধ্যে", + "জন্য", + "একটি", + "আমার", + "উপরে", + "একটি", + "করা", + "আমি", + "the" + ] + }, + "pedals": [ + { + "name": "CLEAR_BROWSING_DATA", + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + "ব্রাউজ করা হচ্ছে", + "ব্রাউজার", + "google chrome", + "chrome" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "মিটিয়ে দিন", + "সরিয়ে দিন", + "মুছে দিন", + "মুছে দিন", + "মুছে দিন" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "ক্যাশে ফাইল", + "ইতিহাস", + "ডেটা", + "তথ্য", + "তথ্য", + "কুকি" + ] + } + ] + }, + { + "name": "MANAGE_PASSWORDS", + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + "ব্রাউজার", + "google chrome", + "chrome" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "পরিবর্তন করুন", + "ম্যানেজ করুন", + "আপডেট করুন", + "ম্যানেজার", + "এডিট করুন", + "সেভ করুন", + "দেখুন", + "দেখান" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "ক্রেডেনশিয়াল", + "পাসওয়ার্ড", + "পাসওয়ার্ড" + ] + } + ] + }, + { + "name": "UPDATE_CREDIT_CARD", + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + "ব্রাউজার", + "google chrome", + "chrome" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "পরিবর্তন করুন", + "ম্যানেজ করুন", + "আপডেট করুন", + "এডিট করুন", + "সেভ করুন" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "ক্রেডিট কার্ডের তথ্য", + "ক্রেডিট কার্ডের তথ্য", + "পেমেন্ট পদ্ধতি", + "ক্রেডিট কার্ড", + "ক্রেডিট কার্ড", + "কার্ডের তথ্য", + "কার্ডের তথ্য", + "পেমেন্ট", + "পেমেন্ট", + "কার্ড" + ] + } + ] + }, + { + "name": "LAUNCH_INCOGNITO", + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + "ব্রাউজার", + "google chrome", + "chrome" + ] + }, + { + "required": false, + "single": true, + "synonyms": [ + "এন্টার করুন", + "লঞ্চ করুন", + "শুরু করুন", + "তৈরি করুন", + "খুলুন" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "ব্যক্তিগত উইন্ডো", + "ছদ্মবেশী উইন্ডো", + "ব্যক্তিগত ট্যাব", + "ছদ্মবেশী ট্যাব", + "ব্যক্তিগত মোড", + "ছদ্মবেশী মোড", + "ছদ্মবেশী" + ] + } + ] + }, + { + "name": "TRANSLATE", + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + "ব্রাউজার", + "google chrome", + "chrome" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "ভাষা পরিবর্তন করুন", + "অনুবাদ করুন" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "এই পৃষ্ঠা", + "পৃষ্ঠা", + "এই" + ] + } + ] + }, + { + "name": "UPDATE_CHROME", + "groups": [ + { + "required": true, + "single": true, + "synonyms": [ + "ব্রাউজার", + "google chrome", + "chrome" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "আপগ্রেড করুন", + "ইনস্টল করুন", + "আপডেট করুন" + ] + } + ] + } + ] + }, + { + "language_code": "ca", + "tokenize_characters": " -", + "ignore_group": { + "required": false, + "single": false, + "synonyms": [ + "es pot", + "per a", + "meves", + "dins", + "meva", + "meus", + "com", + "puc", + "meu", + "per", + "una", + "els", + "les", + "en", + "el", + "un", + "la", + "de", + "a" + ] + }, + "pedals": [ + { + "name": "CLEAR_BROWSING_DATA", + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + "google chrome", + "navegació", + "navegador", + "chrome" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "suprimeix", + "suprimir", + "eliminar", + "esborrar", + "netejar", + "elimina", + "esborra", + "treure", + "neteja", + "treu" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "memòria cau", + "informació", + "historial", + "galetes", + "galeta", + "dades", + "info" + ] + } + ] + }, + { + "name": "MANAGE_PASSWORDS", + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + "google chrome", + "navegador", + "chrome" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "administrador", + "administrar", + "actualitzar", + "administra", + "actualitza", + "gestionar", + "modificar", + "gestiona", + "modifica", + "canviar", + "guardar", + "mostrar", + "editar", + "gestor", + "canvia", + "guarda", + "mostra", + "edita", + "desar", + "veure", + "desa" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "contrasenyes", + "contrasenya", + "credencials" + ] + } + ] + }, + { + "name": "UPDATE_CREDIT_CARD", + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + "google chrome", + "navegador", + "chrome" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "administrar", + "actualitzar", + "administra", + "actualitza", + "gestionar", + "modificar", + "gestiona", + "modifica", + "canviar", + "guardar", + "editar", + "canvia", + "guarda", + "edita", + "desar", + "desa" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "informació targeta crèdit", + "info targeta de crèdit", + "informació targeta", + "mètodes pagament", + "targetes crèdit", + "mètode pagament", + "targeta crèdit", + "formes pagament", + "forma pagament", + "info targeta", + "pagaments", + "targetes", + "pagament" + ] + } + ] + }, + { + "name": "LAUNCH_INCOGNITO", + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + "google chrome", + "navegador", + "chrome" + ] + }, + { + "required": false, + "single": true, + "synonyms": [ + "llançar", + "iniciar", + "llança", + "entrar", + "inicia", + "obrir", + "crear", + "entra", + "obre", + "crea" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "finestra d'incògnit", + "pestanya d'incògnit", + "finestra incògnit", + "pestanya incògnit", + "mode d'incògnit", + "finestra privada", + "pestanya privada", + "mode incògnit", + "mode privat", + "incògnit" + ] + } + ] + }, + { + "name": "TRANSLATE", + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + "google chrome", + "navegador", + "chrome" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "canviar l'idioma", + "canvia l'idioma", + "canviar idioma", + "canvia idioma", + "tradueix", + "traduir" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "aquesta pàgina", + "pàgina", + "això" + ] + } + ] + }, + { + "name": "UPDATE_CHROME", + "groups": [ + { + "required": true, + "single": true, + "synonyms": [ + "google chrome", + "navegador", + "chrome" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "actualitzar versió", + "actualitza versió", + "instal·lar", + "actualitzar", + "instal·la", + "actualitza" + ] + } + ] + } + ] + }, + { + "language_code": "cs", + "tokenize_characters": " -", + "ignore_group": { + "required": false, + "single": false, + "synonyms": [ + "uvnitř", + "pro", + "jak", + "v" + ] + }, + "pedals": [ + { + "name": "CLEAR_BROWSING_DATA", + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + "google chrome", + "prohlížení", + "prohlížeč", + "chrome" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "odstranit", + "vymazat", + "smazat" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "soubory cookie", + "mezipaměť", + "informace", + "historie", + "data", + "info" + ] + } + ] + }, + { + "name": "MANAGE_PASSWORDS", + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + "google chrome", + "prohlížeč", + "chrome" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "aktualizovat", + "spravovat", + "správce", + "zobrazit", + "upravit", + "změnit", + "uložit", + "ukázat" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "přihlašovací údaje", + "hesla", + "heslo" + ] + } + ] + }, + { + "name": "UPDATE_CREDIT_CARD", + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + "google chrome", + "prohlížeč", + "chrome" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "aktualizovat", + "spravovat", + "upravovat", + "změnit", + "uložit" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "informace o platební kartě", + "údaje o platební kartě", + "informace o kartě", + "platební metody", + "platební karty", + "platební karta", + "údaje o kartě", + "platba", + "platby", + "karty" + ] + } + ] + }, + { + "name": "LAUNCH_INCOGNITO", + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + "google chrome", + "prohlížeč", + "chrome" + ] + }, + { + "required": false, + "single": true, + "synonyms": [ + "otevřít", + "vytvořit", + "zahájit", + "vstoupit", + "spustit" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "anonymní režim", + "soukromý režim", + "anonymní karta", + "soukromá karta", + "anonymní okno", + "soukromé okno", + "anonymní" + ] + } + ] + }, + { + "name": "TRANSLATE", + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + "google chrome", + "prohlížeč", + "chrome" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "změnit jazyk", + "přeložit" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "tato stránka", + "stránka", + "toto" + ] + } + ] + }, + { + "name": "UPDATE_CHROME", + "groups": [ + { + "required": true, + "single": true, + "synonyms": [ + "google chrome", + "prohlížeč", + "chrome" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "nainstalovat", + "aktualizovat", + "upgradovat" + ] + } + ] + } + ] + }, + { + "language_code": "da", + "tokenize_characters": " -", + "ignore_group": { + "required": false, + "single": false, + "synonyms": [ + "mine", + "for", + "til", + "min", + "mit", + "på", + "jeg", + "en", + "et", + "i" + ] + }, + "pedals": [ + { + "name": "CLEAR_BROWSING_DATA", + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + "google chrome", + "browsing", + "browser", + "chrome" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "fjern", + "slet", + "ryd" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "browseroplysninger", + "browserhistorik", + "browsercookies", + "oplysninger", + "browserdata", + "historik", + "cookies", + "cache", + "data" + ] + } + ] + }, + { + "name": "MANAGE_PASSWORDS", + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + "google chrome", + "browser", + "chrome" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "administrator", + "administrer", + "rediger", + "opdater", + "skift", + "gem", + "vis", + "se" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "loginoplysninger", + "adgangskoder", + "adgangskode" + ] + } + ] + }, + { + "name": "UPDATE_CREDIT_CARD", + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + "google chrome", + "browser", + "chrome" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "administrer", + "opdater", + "rediger", + "skift", + "gem" + ] + }, + { + "required": false, + "single": true, + "synonyms": [ + "betalingskortoplysnigner", + "kreditkortoplysninger", + "betalingsmetoder", + "kortoplysninger", + "betalingskort", + "kreditkort", + "betalinger", + "betaling", + "kort" + ] + } + ] + }, + { + "name": "LAUNCH_INCOGNITO", + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + "google chrome", + "browser", + "chrome" + ] + }, + { + "required": false, + "single": true, + "synonyms": [ + "anvend", + "start", + "opret", + "åbn", + "brug" + ] + }, + { + "required": false, + "single": true, + "synonyms": [ + "inkognitotilstand", + "inkognitovindue", + "privat tilstand", + "privat vindue", + "inkognitofane", + "privat fane", + "inkognito" + ] + } + ] + }, + { + "name": "TRANSLATE", + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + "google chrome", + "browser", + "chrome" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "skift sprog", + "oversæt" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "denne side", + "dette", + "siden", + "side" + ] + } + ] + }, + { + "name": "UPDATE_CHROME", + "groups": [ + { + "required": true, + "single": true, + "synonyms": [ + "google chrome", + "browser", + "chrome" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "installer", + "opgrader", + "opdater" + ] + } + ] + } + ] + }, + { "language_code": "de", "tokenize_characters": " -", "ignore_group": { @@ -465,6 +2063,239 @@ ] }, { + "language_code": "el", + "tokenize_characters": " -", + "ignore_group": { + "required": false, + "single": false, + "synonyms": [ + "στον/στην/στο", + "στον/στην/στο", + "ένας/μια/ένα", + "τον/την/το", + "εντός", + "μέσα", + "κάνω", + "για", + "πώς", + "μου", + "ένα", + "εγώ", + "σε" + ] + }, + "pedals": [ + { + "name": "CLEAR_BROWSING_DATA", + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + "πρόγραμμα περιήγησης", + "περιήγηση", + "google chrome", + "chrome" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "εκκαθάριση", + "εκκαθάριση", + "κατάργηση", + "διαγραφή", + "διαγραφή" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "πληροφορίες", + "πληροφορίες", + "κρυφή μνήμη", + "ιστορικό", + "δεδομένα", + "cookie" + ] + } + ] + }, + { + "name": "MANAGE_PASSWORDS", + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + "πρόγραμμα περιήγησης", + "google chrome", + "chrome" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "διαχειριστής", + "επεξεργασία", + "διαχείριση", + "αποθήκευση", + "ενημέρωση", + "εμφάνιση", + "προβολή", + "αλλαγή" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "κωδικοί πρόσβασης", + "κωδικός πρόσβασης", + "διαπιστευτήρια" + ] + } + ] + }, + { + "name": "UPDATE_CREDIT_CARD", + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + "πρόγραμμα περιήγησης", + "google chrome", + "chrome" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "επεξεργασία", + "διαχείριση", + "αποθήκευση", + "ενημέρωση", + "αλλαγή" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "πληροφορίες πιστωτικής κάρτας", + "στοιχεία πιστωτικής κάρτας", + "πληροφορίες κάρτας", + "πιστωτικές κάρτες", + "πιστωτική κάρτα", + "τρόποι πληρωμής", + "στοιχεία κάρτας", + "πληρωμές", + "πληρωμή", + "κάρτες" + ] + } + ] + }, + { + "name": "LAUNCH_INCOGNITO", + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + "πρόγραμμα περιήγησης", + "google chrome", + "chrome" + ] + }, + { + "required": false, + "single": true, + "synonyms": [ + "δημιουργία", + "εκκίνηση", + "εισαγωγή", + "άνοιγμα", + "έναρξη" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "παράθυρο για ανώνυμη περιήγηση", + "καρτέλα ανώνυμης περιήγησης", + "ιδιωτική λειτουργία", + "ανώνυμη περιήγηση", + "ιδιωτικό παράθυρο", + "ιδιωτική καρτέλα", + "ανώνυμο" + ] + } + ] + }, + { + "name": "TRANSLATE", + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + "πρόγραμμα περιήγησης", + "google chrome", + "chrome" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "αλλαγή γλώσσας", + "μετάφραση" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "αυτή η σελίδα", + "σελίδα", + "αυτή" + ] + } + ] + }, + { + "name": "UPDATE_CHROME", + "groups": [ + { + "required": true, + "single": true, + "synonyms": [ + "πρόγραμμα περιήγησης", + "google chrome", + "chrome" + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + "εγκατάσταση", + "ενημέρωση", + "ενημέρωση" + ] + } + ] + } + ] + }, + { "language_code": "en", "tokenize_characters": " -", "ignore_group": {
diff --git a/components/omnibox/resources/omnibox_pedal_concepts_am.json b/components/omnibox/resources/omnibox_pedal_concepts_am.json index 6f917e7..25644fd7c 100644 --- a/components/omnibox/resources/omnibox_pedal_concepts_am.json +++ b/components/omnibox/resources/omnibox_pedal_concepts_am.json
@@ -1,7 +1,7 @@ { "schema": "pedal_concepts_runtime", "schema_version": 1, - "data_version": 15462706, + "data_version": 15468548, "tokenize_characters": " -", "dictionary": [ "chrome",
diff --git a/components/omnibox/resources/omnibox_pedal_concepts_ar.json b/components/omnibox/resources/omnibox_pedal_concepts_ar.json new file mode 100644 index 0000000..0bd0f3c --- /dev/null +++ b/components/omnibox/resources/omnibox_pedal_concepts_ar.json
@@ -0,0 +1,535 @@ +{ + "schema": "pedal_concepts_runtime", + "schema_version": 1, + "data_version": 15468548, + "tokenize_characters": " -", + "dictionary": [ + "a", + "an", + "chrome", + "google", + "أنا", + "إتمام", + "إدارة", + "إزالة", + "إظهار", + "إلى", + "إنشاء", + "ائتمان", + "ال", + "الائتمان", + "الارتباط", + "الاعتماد", + "البطاقة", + "التخزين", + "التصفح", + "التصفّح", + "الخاص", + "الدفع", + "الدفعات", + "الصفحة", + "اللغة", + "المؤقت", + "المتخفي", + "المرور", + "الوضع", + "بدء", + "بطاقات", + "بطاقة", + "بي/التابعة/الخاص/التابع", + "بيانات", + "تبويب", + "تثبيت", + "تحديث", + "ترجمة", + "ترقية", + "تشغيل", + "تصفُّح", + "تعديل", + "تعريف", + "تغيير", + "حجب", + "حذف", + "حفظ", + "خاصة", + "داخل", + "دخول", + "ذاكرة", + "سجلّ", + "صفحة", + "ضمن/غضون/خلال", + "طرق", + "عرض", + "علامة", + "على", + "فتح", + "في", + "كلمات", + "كلمة", + "كيف", + "لـ/لمدة", + "لي/الخاصة", + "متصفّح", + "محو", + "مدير", + "مرور", + "مسح", + "معلومات", + "ملفات", + "نافذة", + "هذه", + "وضع" + ], + "pedals": [ + { + "name": "CLEAR_BROWSING_DATA", + "id": 1, + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + [ + 3, + 2 + ], + [ + 65 + ], + [ + 40 + ], + [ + 2 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 7 + ], + [ + 45 + ], + [ + 69 + ], + [ + 66 + ], + [ + 44 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 50, + 17, + 25 + ], + [ + 71, + 42, + 14 + ], + [ + 70 + ], + [ + 70 + ], + [ + 33 + ], + [ + 51 + ] + ] + } + ] + }, + { + "name": "MANAGE_PASSWORDS", + "id": 2, + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + [ + 3, + 2 + ], + [ + 65 + ], + [ + 2 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 41 + ], + [ + 6 + ], + [ + 36 + ], + [ + 43 + ], + [ + 8 + ], + [ + 67 + ], + [ + 46 + ], + [ + 55 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 33, + 15 + ], + [ + 60, + 27 + ], + [ + 61, + 68 + ] + ] + } + ] + }, + { + "name": "UPDATE_CREDIT_CARD", + "id": 3, + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + [ + 3, + 2 + ], + [ + 65 + ], + [ + 2 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 6 + ], + [ + 36 + ], + [ + 41 + ], + [ + 43 + ], + [ + 46 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 70, + 31, + 13 + ], + [ + 70, + 31, + 13 + ], + [ + 30, + 13 + ], + [ + 70, + 16 + ], + [ + 70, + 16 + ], + [ + 31, + 11 + ], + [ + 54, + 21 + ], + [ + 22 + ], + [ + 30 + ], + [ + 21 + ] + ] + } + ] + }, + { + "name": "LAUNCH_INCOGNITO", + "id": 4, + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + [ + 3, + 2 + ], + [ + 65 + ], + [ + 2 + ] + ] + }, + { + "required": false, + "single": true, + "synonyms": [ + [ + 39 + ], + [ + 10 + ], + [ + 49 + ], + [ + 29 + ], + [ + 58 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 56, + 34, + 74, + 19, + 26 + ], + [ + 72, + 19, + 26 + ], + [ + 74, + 19, + 26 + ], + [ + 56, + 34, + 47 + ], + [ + 18, + 26 + ], + [ + 28, + 20 + ], + [ + 72, + 47 + ] + ] + } + ] + }, + { + "name": "TRANSLATE", + "id": 5, + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + [ + 3, + 2 + ], + [ + 65 + ], + [ + 2 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 43, + 24 + ], + [ + 37 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 73, + 23 + ], + [ + 52 + ], + [ + 73 + ] + ] + } + ] + }, + { + "name": "UPDATE_CHROME", + "id": 6, + "groups": [ + { + "required": true, + "single": true, + "synonyms": [ + [ + 3, + 2 + ], + [ + 65 + ], + [ + 2 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 38 + ], + [ + 35 + ], + [ + 36 + ] + ] + } + ] + } + ], + "ignore_group": { + "required": false, + "single": false, + "synonyms": [ + [ + 64, + 32 + ], + [ + 53 + ], + [ + 63 + ], + [ + 5 + ], + [ + 48 + ], + [ + 62 + ], + [ + 57 + ], + [ + 9 + ], + [ + 4 + ], + [ + 12 + ], + [ + 59 + ], + [ + 1 + ], + [ + 0 + ] + ] + }, + "max_tokens": 32 +} \ No newline at end of file
diff --git a/components/omnibox/resources/omnibox_pedal_concepts_bg.json b/components/omnibox/resources/omnibox_pedal_concepts_bg.json new file mode 100644 index 0000000..4564886 --- /dev/null +++ b/components/omnibox/resources/omnibox_pedal_concepts_bg.json
@@ -0,0 +1,1123 @@ +{ + "schema": "pedal_concepts_runtime", + "schema_version": 1, + "data_version": 15468548, + "tokenize_characters": " -", + "dictionary": [ + "chrome", + "google", + "актуализация", + "актуализира", + "актуализирай", + "актуализирам", + "актуализиране", + "актуализират", + "бисквитки", + "бисквитките", + "браузване", + "браузър", + "браузъра", + "в", + "види", + "видя", + "виждам", + "виждат", + "влез", + "влиза", + "влизам", + "влизане", + "вляза", + "вход", + "да", + "данни", + "данните", + "друг", + "език", + "езика", + "за", + "запазване", + "запази", + "запазя", + "запазят", + "запис", + "записва", + "записване", + "записват", + "запиша", + "запиши", + "запомни", + "запомня", + "запомняне", + "запомнят", + "идентификация", + "идентификацията", + "изтрива", + "изтриване", + "изтрие", + "изтрий", + "изтрия", + "изчиства", + "изчистване", + "изчисти", + "изчистя", + "инкогнито", + "инсталира", + "инсталирай", + "инсталирам", + "инсталиране", + "информация", + "информацията", + "история", + "историята", + "как", + "карта", + "картата", + "карти", + "картите", + "кеш", + "кеша", + "кредитна", + "кредитната", + "кредитни", + "кредитните", + "мениджър", + "ми", + "на", + "надстрой", + "надстройва", + "надстройване", + "надстроя", + "начини", + "номер", + "обнови", + "обновя", + "обновяване", + "от", + "отваря", + "отварям", + "отваряне", + "отвори", + "отворя", + "парола", + "паролата", + "пароли", + "паролите", + "плащане", + "плащания", + "поверителен", + "поверително", + "покажа", + "покажат", + "покаже", + "покажи", + "преведа", + "преведи", + "превежда", + "превеждане", + "превод", + "премахва", + "премахване", + "премахна", + "премахне", + "премахни", + "прозорец", + "промени", + "променя", + "променят", + "промяна", + "пуска", + "пускам", + "пускане", + "пусна", + "пусни", + "раздел", + "редактира", + "редактирай", + "редактирам", + "редактиране", + "редактират", + "редакция", + "режим", + "се", + "си", + "смени", + "сменя", + "сменят", + "смяна", + "стартира", + "стартирай", + "стартирам", + "стартиране", + "страница", + "страницата", + "създавам", + "създаване", + "създай", + "създам", + "сърфиране", + "таб", + "тази", + "това", + "трие", + "управление", + "управлява", + "управлявай", + "управляване", + "управляват", + "частен", + "частно", + "ъпгрейд", + "ъпгрейдна", + "ъпгрейдни", + "ъпдейт", + "ъпдейтва", + "ъпдейтна", + "ъпдейтни" + ], + "pedals": [ + { + "name": "CLEAR_BROWSING_DATA", + "id": 1, + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + [ + 1, + 0 + ], + [ + 150 + ], + [ + 10 + ], + [ + 12 + ], + [ + 11 + ], + [ + 0 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 112 + ], + [ + 53 + ], + [ + 48 + ], + [ + 115 + ], + [ + 113 + ], + [ + 111 + ], + [ + 52 + ], + [ + 114 + ], + [ + 54 + ], + [ + 55 + ], + [ + 47 + ], + [ + 54 + ], + [ + 50 + ], + [ + 51 + ], + [ + 49 + ], + [ + 154 + ] + ] + }, + { + "required": false, + "single": true, + "synonyms": [ + [ + 62 + ], + [ + 9 + ], + [ + 61 + ], + [ + 8 + ], + [ + 64 + ], + [ + 63 + ], + [ + 26 + ], + [ + 25 + ], + [ + 71 + ], + [ + 70 + ] + ] + } + ] + }, + { + "name": "MANAGE_PASSWORDS", + "id": 2, + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + [ + 1, + 0 + ], + [ + 12 + ], + [ + 11 + ], + [ + 0 + ] + ] + }, + { + "required": false, + "single": true, + "synonyms": [ + [ + 6 + ], + [ + 4 + ], + [ + 2 + ], + [ + 7 + ], + [ + 130 + ], + [ + 158 + ], + [ + 3 + ], + [ + 128 + ], + [ + 131 + ], + [ + 129 + ], + [ + 155 + ], + [ + 157 + ], + [ + 159 + ], + [ + 127 + ], + [ + 156 + ], + [ + 31 + ], + [ + 37 + ], + [ + 43 + ], + [ + 132 + ], + [ + 76 + ], + [ + 119 + ], + [ + 38 + ], + [ + 44 + ], + [ + 120 + ], + [ + 117 + ], + [ + 118 + ], + [ + 34 + ], + [ + 36 + ], + [ + 41 + ], + [ + 42 + ], + [ + 103 + ], + [ + 138 + ], + [ + 32 + ], + [ + 33 + ], + [ + 40 + ], + [ + 39 + ], + [ + 16 + ], + [ + 17 + ], + [ + 102 + ], + [ + 105 + ], + [ + 104 + ], + [ + 136 + ], + [ + 139 + ], + [ + 137 + ], + [ + 35 + ], + [ + 15 + ], + [ + 14 + ] + ] + }, + { + "required": false, + "single": true, + "synonyms": [ + [ + 26, + 23 + ], + [ + 25, + 23 + ], + [ + 46 + ], + [ + 45 + ], + [ + 97 + ], + [ + 95 + ], + [ + 96 + ], + [ + 94 + ] + ] + } + ] + }, + { + "name": "UPDATE_CREDIT_CARD", + "id": 3, + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + [ + 1, + 0 + ], + [ + 12 + ], + [ + 11 + ], + [ + 0 + ] + ] + }, + { + "required": false, + "single": true, + "synonyms": [ + [ + 6 + ], + [ + 4 + ], + [ + 2 + ], + [ + 7 + ], + [ + 130 + ], + [ + 158 + ], + [ + 3 + ], + [ + 128 + ], + [ + 131 + ], + [ + 129 + ], + [ + 155 + ], + [ + 157 + ], + [ + 159 + ], + [ + 127 + ], + [ + 156 + ], + [ + 31 + ], + [ + 37 + ], + [ + 43 + ], + [ + 132 + ], + [ + 119 + ], + [ + 38 + ], + [ + 44 + ], + [ + 120 + ], + [ + 117 + ], + [ + 118 + ], + [ + 34 + ], + [ + 36 + ], + [ + 41 + ], + [ + 42 + ], + [ + 32 + ], + [ + 33 + ], + [ + 40 + ], + [ + 39 + ], + [ + 35 + ] + ] + }, + { + "required": false, + "single": true, + "synonyms": [ + [ + 62, + 73, + 66 + ], + [ + 61, + 73, + 66 + ], + [ + 62, + 72, + 66 + ], + [ + 61, + 72, + 66 + ], + [ + 84, + 73, + 66 + ], + [ + 25, + 73, + 66 + ], + [ + 84, + 72, + 66 + ], + [ + 25, + 72, + 66 + ], + [ + 61, + 67 + ], + [ + 73, + 66 + ], + [ + 75, + 68 + ], + [ + 61, + 66 + ], + [ + 72, + 66 + ], + [ + 74, + 68 + ], + [ + 83, + 98 + ], + [ + 25, + 67 + ], + [ + 25, + 66 + ], + [ + 99 + ], + [ + 69 + ], + [ + 98 + ], + [ + 68 + ] + ] + } + ] + }, + { + "name": "LAUNCH_INCOGNITO", + "id": 4, + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + [ + 1, + 0 + ], + [ + 12 + ], + [ + 11 + ], + [ + 0 + ] + ] + }, + { + "required": false, + "single": true, + "synonyms": [ + [ + 143 + ], + [ + 147 + ], + [ + 142 + ], + [ + 141 + ], + [ + 91 + ], + [ + 140 + ], + [ + 146 + ], + [ + 123 + ], + [ + 21 + ], + [ + 90 + ], + [ + 122 + ], + [ + 20 + ], + [ + 93 + ], + [ + 89 + ], + [ + 92 + ], + [ + 149 + ], + [ + 148 + ], + [ + 121 + ], + [ + 124 + ], + [ + 125 + ], + [ + 19 + ], + [ + 22 + ], + [ + 18 + ] + ] + }, + { + "required": false, + "single": true, + "synonyms": [ + [ + 101, + 150 + ], + [ + 116, + 56 + ], + [ + 56, + 116 + ], + [ + 100, + 126 + ], + [ + 100, + 133 + ], + [ + 126, + 56 + ], + [ + 56, + 126 + ], + [ + 161, + 150 + ], + [ + 133, + 56 + ], + [ + 56, + 133 + ], + [ + 100, + 151 + ], + [ + 151, + 56 + ], + [ + 56, + 151 + ], + [ + 160, + 126 + ], + [ + 160, + 133 + ], + [ + 160, + 151 + ], + [ + 56 + ], + [ + 160 + ] + ] + } + ] + }, + { + "name": "TRANSLATE", + "id": 5, + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + [ + 1, + 0 + ], + [ + 12 + ], + [ + 11 + ], + [ + 0 + ] + ] + }, + { + "required": false, + "single": true, + "synonyms": [ + [ + 120, + 29 + ], + [ + 120, + 28 + ], + [ + 139, + 29 + ], + [ + 139, + 28 + ], + [ + 27, + 28 + ], + [ + 109 + ], + [ + 108 + ], + [ + 107 + ], + [ + 106 + ], + [ + 110 + ] + ] + }, + { + "required": false, + "single": true, + "synonyms": [ + [ + 152, + 144 + ], + [ + 145 + ], + [ + 144 + ], + [ + 153 + ] + ] + } + ] + }, + { + "name": "UPDATE_CHROME", + "id": 6, + "groups": [ + { + "required": true, + "single": true, + "synonyms": [ + [ + 1, + 0 + ], + [ + 12 + ], + [ + 11 + ], + [ + 0 + ] + ] + }, + { + "required": false, + "single": true, + "synonyms": [ + [ + 6 + ], + [ + 81 + ], + [ + 5 + ], + [ + 4 + ], + [ + 60 + ], + [ + 3 + ], + [ + 80 + ], + [ + 59 + ], + [ + 58 + ], + [ + 87 + ], + [ + 57 + ], + [ + 163 + ], + [ + 164 + ], + [ + 82 + ], + [ + 79 + ], + [ + 167 + ], + [ + 166 + ], + [ + 168 + ], + [ + 162 + ], + [ + 86 + ], + [ + 85 + ], + [ + 165 + ] + ] + } + ] + } + ], + "ignore_group": { + "required": false, + "single": false, + "synonyms": [ + [ + 65 + ], + [ + 24 + ], + [ + 134 + ], + [ + 88 + ], + [ + 78 + ], + [ + 30 + ], + [ + 135 + ], + [ + 77 + ], + [ + 13 + ] + ] + }, + "max_tokens": 32 +} \ No newline at end of file
diff --git a/components/omnibox/resources/omnibox_pedal_concepts_bn.json b/components/omnibox/resources/omnibox_pedal_concepts_bn.json new file mode 100644 index 0000000..8207fcb --- /dev/null +++ b/components/omnibox/resources/omnibox_pedal_concepts_bn.json
@@ -0,0 +1,532 @@ +{ + "schema": "pedal_concepts_runtime", + "schema_version": 1, + "data_version": 15468548, + "tokenize_characters": " -", + "dictionary": [ + "chrome", + "google", + "the", + "অনুবাদ", + "আপগ্রেড", + "আপডেট", + "আমার", + "আমি", + "ইতিহাস", + "ইনস্টল", + "উইন্ডো", + "উপরে", + "এই", + "একটি", + "এডিট", + "এন্টার", + "এর", + "করা", + "করুন", + "কার্ড", + "কার্ডের", + "কীভাবে", + "কুকি", + "ক্যাশে", + "ক্রেডিট", + "ক্রেডেনশিয়াল", + "খুলুন", + "ছদ্মবেশী", + "জন্য", + "ট্যাব", + "ডেটা", + "তথ্য", + "তৈরি", + "দিকে", + "দিন", + "দেখান", + "দেখুন", + "পদ্ধতি", + "পরিবর্তন", + "পাসওয়ার্ড", + "পৃষ্ঠা", + "পেমেন্ট", + "ফাইল", + "ব্যক্তিগত", + "ব্রাউজ", + "ব্রাউজার", + "ভাষা", + "ভেতরে", + "মধ্যে", + "মিটিয়ে", + "মুছে", + "মোড", + "ম্যানেজ", + "ম্যানেজার", + "লঞ্চ", + "শুরু", + "সরিয়ে", + "সেভ", + "হচ্ছে" + ], + "pedals": [ + { + "name": "CLEAR_BROWSING_DATA", + "id": 1, + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + [ + 44, + 58 + ], + [ + 1, + 0 + ], + [ + 45 + ], + [ + 0 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 49, + 34 + ], + [ + 56, + 34 + ], + [ + 50, + 34 + ], + [ + 50, + 34 + ], + [ + 50, + 34 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 23, + 42 + ], + [ + 8 + ], + [ + 30 + ], + [ + 31 + ], + [ + 31 + ], + [ + 22 + ] + ] + } + ] + }, + { + "name": "MANAGE_PASSWORDS", + "id": 2, + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + [ + 1, + 0 + ], + [ + 45 + ], + [ + 0 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 38, + 18 + ], + [ + 52, + 18 + ], + [ + 5, + 18 + ], + [ + 14, + 18 + ], + [ + 57, + 18 + ], + [ + 53 + ], + [ + 36 + ], + [ + 35 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 25 + ], + [ + 39 + ], + [ + 39 + ] + ] + } + ] + }, + { + "name": "UPDATE_CREDIT_CARD", + "id": 3, + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + [ + 1, + 0 + ], + [ + 45 + ], + [ + 0 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 38, + 18 + ], + [ + 52, + 18 + ], + [ + 5, + 18 + ], + [ + 14, + 18 + ], + [ + 57, + 18 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 24, + 20, + 31 + ], + [ + 24, + 20, + 31 + ], + [ + 41, + 37 + ], + [ + 24, + 19 + ], + [ + 24, + 19 + ], + [ + 20, + 31 + ], + [ + 20, + 31 + ], + [ + 41 + ], + [ + 41 + ], + [ + 19 + ] + ] + } + ] + }, + { + "name": "LAUNCH_INCOGNITO", + "id": 4, + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + [ + 1, + 0 + ], + [ + 45 + ], + [ + 0 + ] + ] + }, + { + "required": false, + "single": true, + "synonyms": [ + [ + 15, + 18 + ], + [ + 54, + 18 + ], + [ + 55, + 18 + ], + [ + 32, + 18 + ], + [ + 26 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 43, + 10 + ], + [ + 27, + 10 + ], + [ + 43, + 29 + ], + [ + 27, + 29 + ], + [ + 43, + 51 + ], + [ + 27, + 51 + ], + [ + 27 + ] + ] + } + ] + }, + { + "name": "TRANSLATE", + "id": 5, + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + [ + 1, + 0 + ], + [ + 45 + ], + [ + 0 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 46, + 38, + 18 + ], + [ + 3, + 18 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 12, + 40 + ], + [ + 40 + ], + [ + 12 + ] + ] + } + ] + }, + { + "name": "UPDATE_CHROME", + "id": 6, + "groups": [ + { + "required": true, + "single": true, + "synonyms": [ + [ + 1, + 0 + ], + [ + 45 + ], + [ + 0 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 4, + 18 + ], + [ + 9, + 18 + ], + [ + 5, + 18 + ] + ] + } + ] + } + ], + "ignore_group": { + "required": false, + "single": false, + "synonyms": [ + [ + 16, + 48 + ], + [ + 16, + 33 + ], + [ + 21 + ], + [ + 47 + ], + [ + 48 + ], + [ + 28 + ], + [ + 13 + ], + [ + 6 + ], + [ + 11 + ], + [ + 13 + ], + [ + 17 + ], + [ + 7 + ], + [ + 2 + ] + ] + }, + "max_tokens": 32 +} \ No newline at end of file
diff --git a/components/omnibox/resources/omnibox_pedal_concepts_ca.json b/components/omnibox/resources/omnibox_pedal_concepts_ca.json new file mode 100644 index 0000000..290188b --- /dev/null +++ b/components/omnibox/resources/omnibox_pedal_concepts_ca.json
@@ -0,0 +1,721 @@ +{ + "schema": "pedal_concepts_runtime", + "schema_version": 1, + "data_version": 15468548, + "tokenize_characters": " -", + "dictionary": [ + "a", + "actualitza", + "actualitzar", + "administra", + "administrador", + "administrar", + "això", + "aquesta", + "canvia", + "canviar", + "cau", + "chrome", + "com", + "contrasenya", + "contrasenyes", + "crea", + "crear", + "credencials", + "crèdit", + "d'incògnit", + "dades", + "de", + "desa", + "desar", + "dins", + "edita", + "editar", + "el", + "elimina", + "eliminar", + "els", + "en", + "entra", + "entrar", + "es", + "esborra", + "esborrar", + "finestra", + "forma", + "formes", + "galeta", + "galetes", + "gestiona", + "gestionar", + "gestor", + "google", + "google chrome", + "guarda", + "guardar", + "historial", + "idioma", + "incògnit", + "info", + "informació", + "inicia", + "iniciar", + "instal·la", + "instal·lar", + "l'idioma", + "la", + "les", + "llança", + "llançar", + "memòria", + "meu", + "meus", + "meva", + "meves", + "mode", + "modifica", + "modificar", + "mostra", + "mostrar", + "mètode", + "mètodes", + "navegació", + "navegador", + "neteja", + "netejar", + "obre", + "obrir", + "pagament", + "pagaments", + "per", + "pestanya", + "pot", + "privada", + "privat", + "puc", + "pàgina", + "suprimeix", + "suprimir", + "targeta", + "targetes", + "tradueix", + "traduir", + "treu", + "treure", + "un", + "una", + "versió", + "veure" + ], + "pedals": [ + { + "name": "CLEAR_BROWSING_DATA", + "id": 1, + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + [ + 46 + ], + [ + 75 + ], + [ + 76 + ], + [ + 11 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 90 + ], + [ + 91 + ], + [ + 29 + ], + [ + 36 + ], + [ + 78 + ], + [ + 28 + ], + [ + 35 + ], + [ + 97 + ], + [ + 77 + ], + [ + 96 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 63, + 10 + ], + [ + 53 + ], + [ + 49 + ], + [ + 41 + ], + [ + 40 + ], + [ + 20 + ], + [ + 52 + ] + ] + } + ] + }, + { + "name": "MANAGE_PASSWORDS", + "id": 2, + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + [ + 45, + 11 + ], + [ + 76 + ], + [ + 11 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 4 + ], + [ + 5 + ], + [ + 2 + ], + [ + 3 + ], + [ + 1 + ], + [ + 43 + ], + [ + 70 + ], + [ + 42 + ], + [ + 69 + ], + [ + 9 + ], + [ + 48 + ], + [ + 72 + ], + [ + 26 + ], + [ + 44 + ], + [ + 8 + ], + [ + 47 + ], + [ + 71 + ], + [ + 25 + ], + [ + 23 + ], + [ + 101 + ], + [ + 22 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 14 + ], + [ + 13 + ], + [ + 17 + ] + ] + } + ] + }, + { + "name": "UPDATE_CREDIT_CARD", + "id": 3, + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + [ + 45, + 11 + ], + [ + 76 + ], + [ + 11 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 5 + ], + [ + 2 + ], + [ + 3 + ], + [ + 1 + ], + [ + 43 + ], + [ + 70 + ], + [ + 42 + ], + [ + 69 + ], + [ + 9 + ], + [ + 48 + ], + [ + 26 + ], + [ + 8 + ], + [ + 47 + ], + [ + 25 + ], + [ + 23 + ], + [ + 22 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 52, + 92, + 18 + ], + [ + 53, + 92, + 18 + ], + [ + 53, + 92 + ], + [ + 74, + 81 + ], + [ + 93, + 18 + ], + [ + 73, + 81 + ], + [ + 92, + 18 + ], + [ + 39, + 81 + ], + [ + 38, + 81 + ], + [ + 52, + 92 + ], + [ + 82 + ], + [ + 93 + ], + [ + 81 + ] + ] + } + ] + }, + { + "name": "LAUNCH_INCOGNITO", + "id": 4, + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + [ + 45, + 11 + ], + [ + 76 + ], + [ + 11 + ] + ] + }, + { + "required": false, + "single": true, + "synonyms": [ + [ + 62 + ], + [ + 55 + ], + [ + 61 + ], + [ + 33 + ], + [ + 54 + ], + [ + 80 + ], + [ + 16 + ], + [ + 32 + ], + [ + 79 + ], + [ + 15 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 37, + 19 + ], + [ + 84, + 19 + ], + [ + 37, + 51 + ], + [ + 84, + 51 + ], + [ + 68, + 19 + ], + [ + 37, + 86 + ], + [ + 84, + 86 + ], + [ + 68, + 51 + ], + [ + 68, + 87 + ], + [ + 51 + ] + ] + } + ] + }, + { + "name": "TRANSLATE", + "id": 5, + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + [ + 45, + 11 + ], + [ + 76 + ], + [ + 11 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 9, + 58 + ], + [ + 8, + 58 + ], + [ + 9, + 50 + ], + [ + 8, + 50 + ], + [ + 94 + ], + [ + 95 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 7, + 89 + ], + [ + 89 + ], + [ + 6 + ] + ] + } + ] + }, + { + "name": "UPDATE_CHROME", + "id": 6, + "groups": [ + { + "required": true, + "single": true, + "synonyms": [ + [ + 46 + ], + [ + 76 + ], + [ + 11 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 2, + 100 + ], + [ + 1, + 100 + ], + [ + 57 + ], + [ + 2 + ], + [ + 56 + ], + [ + 1 + ] + ] + } + ] + } + ], + "ignore_group": { + "required": false, + "single": false, + "synonyms": [ + [ + 34, + 85 + ], + [ + 83, + 0 + ], + [ + 67 + ], + [ + 24 + ], + [ + 66 + ], + [ + 65 + ], + [ + 12 + ], + [ + 88 + ], + [ + 64 + ], + [ + 83 + ], + [ + 99 + ], + [ + 30 + ], + [ + 60 + ], + [ + 31 + ], + [ + 27 + ], + [ + 98 + ], + [ + 59 + ], + [ + 21 + ], + [ + 0 + ] + ] + }, + "max_tokens": 32 +} \ No newline at end of file
diff --git a/components/omnibox/resources/omnibox_pedal_concepts_cs.json b/components/omnibox/resources/omnibox_pedal_concepts_cs.json new file mode 100644 index 0000000..f5f6204 --- /dev/null +++ b/components/omnibox/resources/omnibox_pedal_concepts_cs.json
@@ -0,0 +1,475 @@ +{ + "schema": "pedal_concepts_runtime", + "schema_version": 1, + "data_version": 15468548, + "tokenize_characters": " -", + "dictionary": [ + "aktualizovat", + "anonymní", + "chrome", + "cookie", + "data", + "google", + "hesla", + "heslo", + "historie", + "info", + "informace", + "jak", + "jazyk", + "karta", + "karty", + "kartě", + "metody", + "mezipaměť", + "nainstalovat", + "o", + "odstranit", + "okno", + "otevřít", + "platba", + "platby", + "platební", + "pro", + "prohlížení", + "prohlížeč", + "přeložit", + "přihlašovací", + "režim", + "smazat", + "soubory", + "soukromá", + "soukromé", + "soukromý", + "spravovat", + "správce", + "spustit", + "stránka", + "tato", + "toto", + "ukázat", + "uložit", + "upgradovat", + "upravit", + "upravovat", + "uvnitř", + "v", + "vstoupit", + "vymazat", + "vytvořit", + "zahájit", + "změnit", + "zobrazit", + "údaje" + ], + "pedals": [ + { + "name": "CLEAR_BROWSING_DATA", + "id": 1, + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + [ + 5, + 2 + ], + [ + 27 + ], + [ + 28 + ], + [ + 2 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 20 + ], + [ + 51 + ], + [ + 32 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 33, + 3 + ], + [ + 17 + ], + [ + 10 + ], + [ + 8 + ], + [ + 4 + ], + [ + 9 + ] + ] + } + ] + }, + { + "name": "MANAGE_PASSWORDS", + "id": 2, + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + [ + 5, + 2 + ], + [ + 28 + ], + [ + 2 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 0 + ], + [ + 37 + ], + [ + 38 + ], + [ + 55 + ], + [ + 46 + ], + [ + 54 + ], + [ + 44 + ], + [ + 43 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 30, + 56 + ], + [ + 6 + ], + [ + 7 + ] + ] + } + ] + }, + { + "name": "UPDATE_CREDIT_CARD", + "id": 3, + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + [ + 5, + 2 + ], + [ + 28 + ], + [ + 2 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 0 + ], + [ + 37 + ], + [ + 47 + ], + [ + 54 + ], + [ + 44 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 10, + 19, + 25, + 15 + ], + [ + 56, + 19, + 25, + 15 + ], + [ + 10, + 19, + 15 + ], + [ + 56, + 19, + 15 + ], + [ + 25, + 16 + ], + [ + 25, + 14 + ], + [ + 25, + 13 + ], + [ + 23 + ], + [ + 24 + ], + [ + 14 + ] + ] + } + ] + }, + { + "name": "LAUNCH_INCOGNITO", + "id": 4, + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + [ + 5, + 2 + ], + [ + 28 + ], + [ + 2 + ] + ] + }, + { + "required": false, + "single": true, + "synonyms": [ + [ + 22 + ], + [ + 52 + ], + [ + 53 + ], + [ + 50 + ], + [ + 39 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 1, + 31 + ], + [ + 36, + 31 + ], + [ + 1, + 13 + ], + [ + 34, + 13 + ], + [ + 1, + 21 + ], + [ + 35, + 21 + ], + [ + 1 + ] + ] + } + ] + }, + { + "name": "TRANSLATE", + "id": 5, + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + [ + 5, + 2 + ], + [ + 28 + ], + [ + 2 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 54, + 12 + ], + [ + 29 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 41, + 40 + ], + [ + 40 + ], + [ + 42 + ] + ] + } + ] + }, + { + "name": "UPDATE_CHROME", + "id": 6, + "groups": [ + { + "required": true, + "single": true, + "synonyms": [ + [ + 5, + 2 + ], + [ + 28 + ], + [ + 2 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 18 + ], + [ + 0 + ], + [ + 45 + ] + ] + } + ] + } + ], + "ignore_group": { + "required": false, + "single": false, + "synonyms": [ + [ + 48 + ], + [ + 26 + ], + [ + 11 + ], + [ + 49 + ] + ] + }, + "max_tokens": 32 +} \ No newline at end of file
diff --git a/components/omnibox/resources/omnibox_pedal_concepts_da.json b/components/omnibox/resources/omnibox_pedal_concepts_da.json new file mode 100644 index 0000000..e71ebe3 --- /dev/null +++ b/components/omnibox/resources/omnibox_pedal_concepts_da.json
@@ -0,0 +1,494 @@ +{ + "schema": "pedal_concepts_runtime", + "schema_version": 1, + "data_version": 15468548, + "tokenize_characters": " -", + "dictionary": [ + "adgangskode", + "adgangskoder", + "administrator", + "administrer", + "anvend", + "betaling", + "betalinger", + "betalingskort", + "betalingskortoplysnigner", + "betalingsmetoder", + "browser", + "browsercookies", + "browserdata", + "browserhistorik", + "browseroplysninger", + "browsing", + "brug", + "cache", + "chrome", + "cookies", + "data", + "denne", + "dette", + "en", + "et", + "fane", + "fjern", + "for", + "gem", + "google", + "historik", + "i", + "inkognito", + "inkognitofane", + "inkognitotilstand", + "inkognitovindue", + "installer", + "jeg", + "kort", + "kortoplysninger", + "kreditkort", + "kreditkortoplysninger", + "loginoplysninger", + "min", + "mine", + "mit", + "opdater", + "opgrader", + "oplysninger", + "opret", + "oversæt", + "privat", + "på", + "rediger", + "ryd", + "se", + "side", + "siden", + "skift", + "slet", + "sprog", + "start", + "til", + "tilstand", + "vindue", + "vis", + "åbn" + ], + "pedals": [ + { + "name": "CLEAR_BROWSING_DATA", + "id": 1, + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + [ + 29, + 18 + ], + [ + 15 + ], + [ + 10 + ], + [ + 18 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 26 + ], + [ + 59 + ], + [ + 54 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 14 + ], + [ + 13 + ], + [ + 11 + ], + [ + 48 + ], + [ + 12 + ], + [ + 30 + ], + [ + 19 + ], + [ + 17 + ], + [ + 20 + ] + ] + } + ] + }, + { + "name": "MANAGE_PASSWORDS", + "id": 2, + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + [ + 29, + 18 + ], + [ + 10 + ], + [ + 18 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 2 + ], + [ + 3 + ], + [ + 53 + ], + [ + 46 + ], + [ + 58 + ], + [ + 28 + ], + [ + 65 + ], + [ + 55 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 42 + ], + [ + 1 + ], + [ + 0 + ] + ] + } + ] + }, + { + "name": "UPDATE_CREDIT_CARD", + "id": 3, + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + [ + 29, + 18 + ], + [ + 10 + ], + [ + 18 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 3 + ], + [ + 46 + ], + [ + 53 + ], + [ + 58 + ], + [ + 28 + ] + ] + }, + { + "required": false, + "single": true, + "synonyms": [ + [ + 8 + ], + [ + 41 + ], + [ + 9 + ], + [ + 39 + ], + [ + 7 + ], + [ + 40 + ], + [ + 6 + ], + [ + 5 + ], + [ + 38 + ] + ] + } + ] + }, + { + "name": "LAUNCH_INCOGNITO", + "id": 4, + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + [ + 29, + 18 + ], + [ + 10 + ], + [ + 18 + ] + ] + }, + { + "required": false, + "single": true, + "synonyms": [ + [ + 4 + ], + [ + 61 + ], + [ + 49 + ], + [ + 66 + ], + [ + 16 + ] + ] + }, + { + "required": false, + "single": true, + "synonyms": [ + [ + 51, + 63 + ], + [ + 51, + 64 + ], + [ + 51, + 25 + ], + [ + 34 + ], + [ + 35 + ], + [ + 33 + ], + [ + 32 + ] + ] + } + ] + }, + { + "name": "TRANSLATE", + "id": 5, + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + [ + 29, + 18 + ], + [ + 10 + ], + [ + 18 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 58, + 60 + ], + [ + 50 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 21, + 56 + ], + [ + 22 + ], + [ + 57 + ], + [ + 56 + ] + ] + } + ] + }, + { + "name": "UPDATE_CHROME", + "id": 6, + "groups": [ + { + "required": true, + "single": true, + "synonyms": [ + [ + 29, + 18 + ], + [ + 10 + ], + [ + 18 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 36 + ], + [ + 47 + ], + [ + 46 + ] + ] + } + ] + } + ], + "ignore_group": { + "required": false, + "single": false, + "synonyms": [ + [ + 44 + ], + [ + 27 + ], + [ + 62 + ], + [ + 43 + ], + [ + 45 + ], + [ + 52 + ], + [ + 37 + ], + [ + 23 + ], + [ + 24 + ], + [ + 31 + ] + ] + }, + "max_tokens": 32 +} \ No newline at end of file
diff --git a/components/omnibox/resources/omnibox_pedal_concepts_de.json b/components/omnibox/resources/omnibox_pedal_concepts_de.json index 4989f42..00d9e16 100644 --- a/components/omnibox/resources/omnibox_pedal_concepts_de.json +++ b/components/omnibox/resources/omnibox_pedal_concepts_de.json
@@ -1,7 +1,7 @@ { "schema": "pedal_concepts_runtime", "schema_version": 1, - "data_version": 15462706, + "data_version": 15468548, "tokenize_characters": " -", "dictionary": [ "aktualisieren",
diff --git a/components/omnibox/resources/omnibox_pedal_concepts_el.json b/components/omnibox/resources/omnibox_pedal_concepts_el.json new file mode 100644 index 0000000..eccf26d --- /dev/null +++ b/components/omnibox/resources/omnibox_pedal_concepts_el.json
@@ -0,0 +1,525 @@ +{ + "schema": "pedal_concepts_runtime", + "schema_version": 1, + "data_version": 15468548, + "tokenize_characters": " -", + "dictionary": [ + "chrome", + "cookie", + "google", + "άνοιγμα", + "ένα", + "έναρξη", + "ένας/μια/ένα", + "αλλαγή", + "ανώνυμη", + "ανώνυμης", + "ανώνυμο", + "αποθήκευση", + "αυτή", + "για", + "γλώσσας", + "δεδομένα", + "δημιουργία", + "διαγραφή", + "διαπιστευτήρια", + "διαχείριση", + "διαχειριστής", + "εγκατάσταση", + "εγώ", + "εισαγωγή", + "εκκίνηση", + "εκκαθάριση", + "εμφάνιση", + "ενημέρωση", + "εντός", + "επεξεργασία", + "η", + "ιδιωτική", + "ιδιωτικό", + "ιστορικό", + "κάνω", + "κάρτα", + "κάρτας", + "κάρτες", + "καρτέλα", + "κατάργηση", + "κρυφή", + "κωδικοί", + "κωδικός", + "λειτουργία", + "μέσα", + "μετάφραση", + "μνήμη", + "μου", + "παράθυρο", + "περιήγηση", + "περιήγησης", + "πιστωτικές", + "πιστωτική", + "πιστωτικής", + "πληροφορίες", + "πληρωμές", + "πληρωμή", + "πληρωμής", + "προβολή", + "πρόγραμμα", + "πρόσβασης", + "πώς", + "σε", + "σελίδα", + "στοιχεία", + "στον/στην/στο", + "τον/την/το", + "τρόποι" + ], + "pedals": [ + { + "name": "CLEAR_BROWSING_DATA", + "id": 1, + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + [ + 59, + 50 + ], + [ + 2, + 0 + ], + [ + 49 + ], + [ + 0 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 25 + ], + [ + 25 + ], + [ + 39 + ], + [ + 17 + ], + [ + 17 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 40, + 46 + ], + [ + 54 + ], + [ + 54 + ], + [ + 33 + ], + [ + 15 + ], + [ + 1 + ] + ] + } + ] + }, + { + "name": "MANAGE_PASSWORDS", + "id": 2, + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + [ + 59, + 50 + ], + [ + 2, + 0 + ], + [ + 0 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 20 + ], + [ + 29 + ], + [ + 19 + ], + [ + 11 + ], + [ + 27 + ], + [ + 26 + ], + [ + 58 + ], + [ + 7 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 41, + 60 + ], + [ + 42, + 60 + ], + [ + 18 + ] + ] + } + ] + }, + { + "name": "UPDATE_CREDIT_CARD", + "id": 3, + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + [ + 59, + 50 + ], + [ + 2, + 0 + ], + [ + 0 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 29 + ], + [ + 19 + ], + [ + 11 + ], + [ + 27 + ], + [ + 7 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 54, + 53, + 36 + ], + [ + 64, + 53, + 36 + ], + [ + 54, + 36 + ], + [ + 51, + 37 + ], + [ + 52, + 35 + ], + [ + 67, + 57 + ], + [ + 64, + 36 + ], + [ + 55 + ], + [ + 56 + ], + [ + 37 + ] + ] + } + ] + }, + { + "name": "LAUNCH_INCOGNITO", + "id": 4, + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + [ + 59, + 50 + ], + [ + 2, + 0 + ], + [ + 0 + ] + ] + }, + { + "required": false, + "single": true, + "synonyms": [ + [ + 16 + ], + [ + 24 + ], + [ + 23 + ], + [ + 3 + ], + [ + 5 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 48, + 8, + 49 + ], + [ + 38, + 9, + 50 + ], + [ + 31, + 43 + ], + [ + 8, + 49 + ], + [ + 32, + 48 + ], + [ + 31, + 38 + ], + [ + 10 + ] + ] + } + ] + }, + { + "name": "TRANSLATE", + "id": 5, + "groups": [ + { + "required": false, + "single": true, + "synonyms": [ + [ + 59, + 50 + ], + [ + 2, + 0 + ], + [ + 0 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 7, + 14 + ], + [ + 45 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 12, + 30, + 63 + ], + [ + 63 + ], + [ + 12 + ] + ] + } + ] + }, + { + "name": "UPDATE_CHROME", + "id": 6, + "groups": [ + { + "required": true, + "single": true, + "synonyms": [ + [ + 59, + 50 + ], + [ + 2, + 0 + ], + [ + 0 + ] + ] + }, + { + "required": true, + "single": true, + "synonyms": [ + [ + 21 + ], + [ + 27 + ], + [ + 27 + ] + ] + } + ] + } + ], + "ignore_group": { + "required": false, + "single": false, + "synonyms": [ + [ + 65 + ], + [ + 65 + ], + [ + 6 + ], + [ + 66 + ], + [ + 28 + ], + [ + 44 + ], + [ + 34 + ], + [ + 13 + ], + [ + 61 + ], + [ + 47 + ], + [ + 4 + ], + [ + 22 + ], + [ + 62 + ] + ] + }, + "max_tokens": 32 +} \ No newline at end of file
diff --git a/components/omnibox/resources/omnibox_pedal_concepts_en.json b/components/omnibox/resources/omnibox_pedal_concepts_en.json index e3d0207..7fb604fa 100644 --- a/components/omnibox/resources/omnibox_pedal_concepts_en.json +++ b/components/omnibox/resources/omnibox_pedal_concepts_en.json
@@ -1,7 +1,7 @@ { "schema": "pedal_concepts_runtime", "schema_version": 1, - "data_version": 15462706, + "data_version": 15468548, "tokenize_characters": " -", "dictionary": [ "a",
diff --git a/components/omnibox/resources/omnibox_pedal_concepts_fr.json b/components/omnibox/resources/omnibox_pedal_concepts_fr.json index 7a6fe34..995fe8b 100644 --- a/components/omnibox/resources/omnibox_pedal_concepts_fr.json +++ b/components/omnibox/resources/omnibox_pedal_concepts_fr.json
@@ -1,7 +1,7 @@ { "schema": "pedal_concepts_runtime", "schema_version": 1, - "data_version": 15462706, + "data_version": 15468548, "tokenize_characters": " -", "dictionary": [ "actualise",
diff --git a/components/omnibox/resources/omnibox_pedal_concepts_ja.json b/components/omnibox/resources/omnibox_pedal_concepts_ja.json index dfb4cbb9..f718a19 100644 --- a/components/omnibox/resources/omnibox_pedal_concepts_ja.json +++ b/components/omnibox/resources/omnibox_pedal_concepts_ja.json
@@ -1,7 +1,7 @@ { "schema": "pedal_concepts_runtime", "schema_version": 1, - "data_version": 15462706, + "data_version": 15468548, "tokenize_characters": "", "dictionary": [ " ",
diff --git a/components/omnibox/resources/omnibox_pedal_concepts_zh-CN.json b/components/omnibox/resources/omnibox_pedal_concepts_zh-CN.json index 5742028..76304c4c 100644 --- a/components/omnibox/resources/omnibox_pedal_concepts_zh-CN.json +++ b/components/omnibox/resources/omnibox_pedal_concepts_zh-CN.json
@@ -1,7 +1,7 @@ { "schema": "pedal_concepts_runtime", "schema_version": 1, - "data_version": 15462706, + "data_version": 15468548, "tokenize_characters": "", "dictionary": [ " ",
diff --git a/components/omnibox/resources/omnibox_resources.grd b/components/omnibox/resources/omnibox_resources.grd index ca7422d..e31b07b 100644 --- a/components/omnibox/resources/omnibox_resources.grd +++ b/components/omnibox/resources/omnibox_resources.grd
@@ -108,14 +108,36 @@ <output filename="omnibox_resources_zh-TW.pak" type="data_package" lang="zh-TW" /> </outputs> <release seq="1" allow_pseudo="false"> + <!-- This <includes> tag is generated by pedal_processor. --> <includes> <!-- These resources do not require translation or further processing because they are already handled by a separate localization process. --> <if expr="lang == 'am'"> <include name="IDR_OMNIBOX_PEDAL_CONCEPTS" file="omnibox_pedal_concepts_am.json" type="BINDATA" compress="gzip" /> </if> + <if expr="lang == 'ar'"> + <include name="IDR_OMNIBOX_PEDAL_CONCEPTS" file="omnibox_pedal_concepts_ar.json" type="BINDATA" compress="gzip" /> + </if> + <if expr="lang == 'bg'"> + <include name="IDR_OMNIBOX_PEDAL_CONCEPTS" file="omnibox_pedal_concepts_bg.json" type="BINDATA" compress="gzip" /> + </if> + <if expr="lang == 'bn'"> + <include name="IDR_OMNIBOX_PEDAL_CONCEPTS" file="omnibox_pedal_concepts_bn.json" type="BINDATA" compress="gzip" /> + </if> + <if expr="lang == 'ca'"> + <include name="IDR_OMNIBOX_PEDAL_CONCEPTS" file="omnibox_pedal_concepts_ca.json" type="BINDATA" compress="gzip" /> + </if> + <if expr="lang == 'cs'"> + <include name="IDR_OMNIBOX_PEDAL_CONCEPTS" file="omnibox_pedal_concepts_cs.json" type="BINDATA" compress="gzip" /> + </if> + <if expr="lang == 'da'"> + <include name="IDR_OMNIBOX_PEDAL_CONCEPTS" file="omnibox_pedal_concepts_da.json" type="BINDATA" compress="gzip" /> + </if> <if expr="lang == 'de'"> <include name="IDR_OMNIBOX_PEDAL_CONCEPTS" file="omnibox_pedal_concepts_de.json" type="BINDATA" compress="gzip" /> </if> + <if expr="lang == 'el'"> + <include name="IDR_OMNIBOX_PEDAL_CONCEPTS" file="omnibox_pedal_concepts_el.json" type="BINDATA" compress="gzip" /> + </if> <if expr="lang == 'en'"> <include name="IDR_OMNIBOX_PEDAL_CONCEPTS" file="omnibox_pedal_concepts_en.json" type="BINDATA" compress="gzip" /> </if> @@ -128,7 +150,7 @@ <if expr="lang == 'zh-CN'"> <include name="IDR_OMNIBOX_PEDAL_CONCEPTS" file="omnibox_pedal_concepts_zh-CN.json" type="BINDATA" compress="gzip" /> </if> - <if expr="lang not in ['am', 'de', 'en', 'fr', 'ja', 'zh-CN']"> + <if expr="lang not in ['am','ar','bg','bn','ca','cs','da','de','el','en','fr','ja','zh-CN',]"> <!-- Fall back to English for unsupported languages. --> <include name="IDR_OMNIBOX_PEDAL_CONCEPTS" file="omnibox_pedal_concepts_en.json" type="BINDATA" compress="gzip" /> </if>
diff --git a/components/omnibox_strings.grdp b/components/omnibox_strings.grdp index d080efd1c..58a016f1 100644 --- a/components/omnibox_strings.grdp +++ b/components/omnibox_strings.grdp
@@ -110,10 +110,10 @@ Clear your browsing history, cookies, cache, and more in Chrome settings </message> <message name="IDS_ACC_OMNIBOX_PEDAL_CLEAR_BROWSING_DATA_SUFFIX" desc="Suffix for spoken suggestion description with clear data pedal action to explain keystroke used to clear browsing data."> - <ph name="CLEAR_BROWSING_DATA_FOCUSED_FRIENDLY_MATCH_TEXT">$1<ex>The Chromium Projects http://www.chromium.org bookmark</ex></ph>, press Tab then Enter to clear Chrome's browsing history data + <ph name="CLEAR_BROWSING_DATA_FOCUSED_FRIENDLY_MATCH_TEXT">$1<ex>The Chromium Projects http://www.chromium.org bookmark</ex></ph>, press Tab then Enter to Clear your browsing history, cookies, cache, and more in Chrome settings </message> <message name="IDS_ACC_OMNIBOX_PEDAL_CLEAR_BROWSING_DATA" desc="Announcement when clear browsing data pedal button is focused."> - Clear Data button, press Enter to clear Chrome's browsing history data + Clear browsing data button, press Enter to clear your browsing history, cookies, cache, and more in Chrome settings </message> <message name="IDS_OMNIBOX_PEDAL_MANAGE_PASSWORDS_HINT" desc="The button text contents to suggest pedal action, manage passwords."> @@ -126,10 +126,10 @@ View and manage your passwords in Chrome settings </message> <message name="IDS_ACC_OMNIBOX_PEDAL_MANAGE_PASSWORDS_SUFFIX" desc="Suffix for spoken suggestion description with manage passwords pedal action to explain keystroke used to manage passwords."> - <ph name="MANAGE_PASSWORDS_FOCUSED_FRIENDLY_MATCH_TEXT">$1<ex>The Chromium Projects http://www.chromium.org bookmark</ex></ph>, press Tab then Enter to manage passwords in Chrome settings + <ph name="MANAGE_PASSWORDS_FOCUSED_FRIENDLY_MATCH_TEXT">$1<ex>The Chromium Projects http://www.chromium.org bookmark</ex></ph>, press Tab then Enter to view and manage your passwords in Chrome settings </message> <message name="IDS_ACC_OMNIBOX_PEDAL_MANAGE_PASSWORDS" desc="Announcement when manage passwords pedal button is focused."> - Manage Passwords button, press Enter to manage passwords in Chrome settings + Manage passwords button, press Enter to view and manage your passwords in Chrome settings </message> <message name="IDS_OMNIBOX_PEDAL_UPDATE_CREDIT_CARD_HINT" desc="The button text contents to suggest pedal action, update credit card."> @@ -141,11 +141,11 @@ <message name="IDS_OMNIBOX_PEDAL_UPDATE_CREDIT_CARD_SUGGESTION_CONTENTS" desc="The suggestion content text to suggest pedal action, update credit card."> Manage your payments and credit card info in Chrome settings </message> - <message name="IDS_ACC_OMNIBOX_PEDAL_UPDATE_CREDIT_CARD_SUFFIX" desc="Suffix for spoken suggestion description with update credit card pedal action to explain keystroke used to manage passwords."> - <ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT">$1<ex>The Chromium Projects http://www.chromium.org bookmark</ex></ph>, press Tab then Enter to update credit card autofill info in Chrome settings + <message name="IDS_ACC_OMNIBOX_PEDAL_UPDATE_CREDIT_CARD_SUFFIX" desc="Suffix for spoken suggestion description with update credit card pedal action to explain keystroke used to update credit card."> + <ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT">$1<ex>The Chromium Projects http://www.chromium.org bookmark</ex></ph>, press Tab then Enter to manage your payments and credit card info in Chrome settings </message> <message name="IDS_ACC_OMNIBOX_PEDAL_UPDATE_CREDIT_CARD" desc="Announcement when update credit card pedal button is focused."> - Update Credit Card button, press Enter to update credit card autofill info in Chrome settings + Manage payment methods button, press Enter to manage your payments and credit card info in Chrome settings </message> <message name="IDS_OMNIBOX_PEDAL_LAUNCH_INCOGNITO_HINT" desc="The button text contents to suggest pedal action, launch incognito."> @@ -157,11 +157,11 @@ <message name="IDS_OMNIBOX_PEDAL_LAUNCH_INCOGNITO_SUGGESTION_CONTENTS" desc="The suggestion content text to suggest pedal action, launch incognito."> Open a new Incognito window to browse privately </message> - <message name="IDS_ACC_OMNIBOX_PEDAL_LAUNCH_INCOGNITO_SUFFIX" desc="Suffix for spoken suggestion description with launch incognito pedal action to explain keystroke used to manage passwords."> - <ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT">$1<ex>The Chromium Projects http://www.chromium.org bookmark</ex></ph>, press Tab then Enter to open new Chrome incognito window + <message name="IDS_ACC_OMNIBOX_PEDAL_LAUNCH_INCOGNITO_SUFFIX" desc="Suffix for spoken suggestion description with launch incognito pedal action to explain keystroke used to launch incognito."> + <ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT">$1<ex>The Chromium Projects http://www.chromium.org bookmark</ex></ph>, press Tab then Enter to open a new Incognito window to browse privately </message> <message name="IDS_ACC_OMNIBOX_PEDAL_LAUNCH_INCOGNITO" desc="Announcement when launch incognito pedal button is focused."> - Open Incognito Window button, press Enter to open new Chrome incognito window + Open Incognito Window button, press Enter to open a new Incognito window to browse privately </message> <message name="IDS_OMNIBOX_PEDAL_TRANSLATE_HINT" desc="The button text contents to suggest pedal action, translate."> @@ -173,11 +173,11 @@ <message name="IDS_OMNIBOX_PEDAL_TRANSLATE_SUGGESTION_CONTENTS" desc="The suggestion content text to suggest pedal action, translate."> Translate this page with Google Translate </message> - <message name="IDS_ACC_OMNIBOX_PEDAL_TRANSLATE_SUFFIX" desc="Suffix for spoken suggestion description with translate pedal action to explain keystroke used to manage passwords."> - <ph name="TRANSLATE_FOCUSED_FRIENDLY_MATCH_TEXT">$1<ex>The Chromium Projects http://www.chromium.org bookmark</ex></ph>, press Tab then Enter to translate this page + <message name="IDS_ACC_OMNIBOX_PEDAL_TRANSLATE_SUFFIX" desc="Suffix for spoken suggestion description with translate pedal action to explain keystroke used to translate this page."> + <ph name="TRANSLATE_FOCUSED_FRIENDLY_MATCH_TEXT">$1<ex>The Chromium Projects http://www.chromium.org bookmark</ex></ph>, press Tab then Enter to translate this page with Google Translate </message> <message name="IDS_ACC_OMNIBOX_PEDAL_TRANSLATE" desc="Announcement when translate pedal button is focused."> - Translate Page button, press Enter to translate this page + Translate page button, press Enter to translate this page with Google Translate </message> <message name="IDS_OMNIBOX_PEDAL_UPDATE_CHROME_HINT" desc="The button text contents to suggest pedal action, update chrome."> @@ -189,11 +189,11 @@ <message name="IDS_OMNIBOX_PEDAL_UPDATE_CHROME_SUGGESTION_CONTENTS" desc="The suggestion content text to suggest pedal action, update chrome."> Update Chrome from your Chrome settings </message> - <message name="IDS_ACC_OMNIBOX_PEDAL_UPDATE_CHROME_SUFFIX" desc="Suffix for spoken suggestion description with update chrome pedal action to explain keystroke used to manage passwords."> - <ph name="UPDATE_CHROME_FOCUSED_FRIENDLY_MATCH_TEXT">$1<ex>The Chromium Projects http://www.chromium.org bookmark</ex></ph>, press Tab then Enter to update Chrome + <message name="IDS_ACC_OMNIBOX_PEDAL_UPDATE_CHROME_SUFFIX" desc="Suffix for spoken suggestion description with update chrome pedal action to explain keystroke used to update Chrome."> + <ph name="UPDATE_CHROME_FOCUSED_FRIENDLY_MATCH_TEXT">$1<ex>The Chromium Projects http://www.chromium.org bookmark</ex></ph>, press Tab then Enter to update Chrome from your Chrome settings </message> <message name="IDS_ACC_OMNIBOX_PEDAL_UPDATE_CHROME" desc="Announcement when update chrome pedal button is focused."> - Relaunch to Update button, press Enter to update Chrome + Update Chrome button, press Enter to update Chrome from your Chrome settings </message> <!-- Accessibility labels for autocomplete match types. @@ -255,7 +255,7 @@ <ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT">$1<ex>The Chromium Projects http://www.chromium.org bookmark</ex></ph>, press Tab then Enter to search </message> <message name="IDS_ACC_KEYWORD_BUTTON" desc="Announcement when keyword search button focused."> - Search button, press Enter to search <ph name="KEYWORD_SUFFIX">$1<ex>Search Youtube</ex></ph> + Search button, press Enter to search <ph name="KEYWORD_SUFFIX">$1<ex>Youtube</ex></ph> </message> <!-- Accessibility suffix for suggestions when the remove button is focused. -->
diff --git a/components/omnibox_strings_grdp/IDS_ACC_KEYWORD_BUTTON.png.sha1 b/components/omnibox_strings_grdp/IDS_ACC_KEYWORD_BUTTON.png.sha1 index 285a1fdb..c05dffa 100644 --- a/components/omnibox_strings_grdp/IDS_ACC_KEYWORD_BUTTON.png.sha1 +++ b/components/omnibox_strings_grdp/IDS_ACC_KEYWORD_BUTTON.png.sha1
@@ -1 +1 @@ -006b4c3d0255628f837e20c319c10676cef37109 \ No newline at end of file +4b945b3c8800a3170bb240e4d13df608aa7396c1 \ No newline at end of file
diff --git a/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_CLEAR_BROWSING_DATA.png.sha1 b/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_CLEAR_BROWSING_DATA.png.sha1 index 3894515..1b00e518 100644 --- a/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_CLEAR_BROWSING_DATA.png.sha1 +++ b/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_CLEAR_BROWSING_DATA.png.sha1
@@ -1 +1 @@ -4361ca28e97038007846b05a11ff6b4f669f6c20 \ No newline at end of file +8c0f2b9902dc6cf2e662f9ce3d55aa48a1115d83 \ No newline at end of file
diff --git a/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_CLEAR_BROWSING_DATA_SUFFIX.png.sha1 b/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_CLEAR_BROWSING_DATA_SUFFIX.png.sha1 index 1506c99..5d63e9b 100644 --- a/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_CLEAR_BROWSING_DATA_SUFFIX.png.sha1 +++ b/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_CLEAR_BROWSING_DATA_SUFFIX.png.sha1
@@ -1 +1 @@ -1de3f2f59c873f339459f3144c42a51fa61df8af \ No newline at end of file +11ca073f981682cc02b2e21a7f3c623a9c7663e1 \ No newline at end of file
diff --git a/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_LAUNCH_INCOGNITO.png.sha1 b/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_LAUNCH_INCOGNITO.png.sha1 index 32458ee5..772bbb0 100644 --- a/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_LAUNCH_INCOGNITO.png.sha1 +++ b/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_LAUNCH_INCOGNITO.png.sha1
@@ -1 +1 @@ -9271ad409aabe1ff88f4038500a0122a1d3b9920 \ No newline at end of file +2931c0e5ce9ed87dad962bffc0810d412704c3e8 \ No newline at end of file
diff --git a/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_LAUNCH_INCOGNITO_SUFFIX.png.sha1 b/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_LAUNCH_INCOGNITO_SUFFIX.png.sha1 index cfbc87fa..bcadacc 100644 --- a/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_LAUNCH_INCOGNITO_SUFFIX.png.sha1 +++ b/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_LAUNCH_INCOGNITO_SUFFIX.png.sha1
@@ -1 +1 @@ -1643cbffd07497fd70b09c01493aafdef0ec5ac0 \ No newline at end of file +7bff887520e6c71145db52556dc1157f7fe57d14 \ No newline at end of file
diff --git a/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_MANAGE_PASSWORDS.png.sha1 b/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_MANAGE_PASSWORDS.png.sha1 index 554b981..43f35875 100644 --- a/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_MANAGE_PASSWORDS.png.sha1 +++ b/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_MANAGE_PASSWORDS.png.sha1
@@ -1 +1 @@ -02dc80bf06286f288fe3afcd62ed6e470936946a \ No newline at end of file +76da67aa0644e383cf86ca3fffc13686b4a227d0 \ No newline at end of file
diff --git a/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_MANAGE_PASSWORDS_SUFFIX.png.sha1 b/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_MANAGE_PASSWORDS_SUFFIX.png.sha1 index 23cfb844..74c9d6d 100644 --- a/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_MANAGE_PASSWORDS_SUFFIX.png.sha1 +++ b/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_MANAGE_PASSWORDS_SUFFIX.png.sha1
@@ -1 +1 @@ -e39177ad8f4c1195f2f8397d62394110b77d62c1 \ No newline at end of file +ab3f0ffab5d607a5e827ccbf3215aae43e7ced90 \ No newline at end of file
diff --git a/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_TRANSLATE.png.sha1 b/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_TRANSLATE.png.sha1 index 08038db..98d6a2eb 100644 --- a/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_TRANSLATE.png.sha1 +++ b/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_TRANSLATE.png.sha1
@@ -1 +1 @@ -d35a775dc904ac5bb6c5de015eb8f824c8532616 \ No newline at end of file +96872a03dd36f7561a1f5fc84b93348d72dbe2f3 \ No newline at end of file
diff --git a/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_TRANSLATE_SUFFIX.png.sha1 b/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_TRANSLATE_SUFFIX.png.sha1 index ebb997f..7dc3ed3 100644 --- a/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_TRANSLATE_SUFFIX.png.sha1 +++ b/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_TRANSLATE_SUFFIX.png.sha1
@@ -1 +1 @@ -80917d536b163b57c1111331cdcfdb982167639c \ No newline at end of file +cc5e9c8884c4f47517d1d6ee1556fa4d1b1a64ac \ No newline at end of file
diff --git a/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_UPDATE_CHROME.png.sha1 b/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_UPDATE_CHROME.png.sha1 index b0fa2fe..8285036 100644 --- a/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_UPDATE_CHROME.png.sha1 +++ b/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_UPDATE_CHROME.png.sha1
@@ -1 +1 @@ -1d06b2efdb6b0314f979665c025ce1c1577d327c \ No newline at end of file +474bafabf0c2f6fd4d252cde895527af2c8769ce \ No newline at end of file
diff --git a/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_UPDATE_CHROME_SUFFIX.png.sha1 b/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_UPDATE_CHROME_SUFFIX.png.sha1 index d8a3101..c689018 100644 --- a/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_UPDATE_CHROME_SUFFIX.png.sha1 +++ b/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_UPDATE_CHROME_SUFFIX.png.sha1
@@ -1 +1 @@ -be0b21c471c6a17df3d466b7136f73796c77b4c4 \ No newline at end of file +204b6c2ca230f294eb27b189ee07221efedb644c \ No newline at end of file
diff --git a/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_UPDATE_CREDIT_CARD.png.sha1 b/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_UPDATE_CREDIT_CARD.png.sha1 index 14d7ca28..8a9fa11a 100644 --- a/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_UPDATE_CREDIT_CARD.png.sha1 +++ b/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_UPDATE_CREDIT_CARD.png.sha1
@@ -1 +1 @@ -f17c75e5b016def05c96fad398d44921f5d2242e \ No newline at end of file +ba1141cbfd254eb64beccfdb6679977b8e4e357c \ No newline at end of file
diff --git a/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_UPDATE_CREDIT_CARD_SUFFIX.png.sha1 b/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_UPDATE_CREDIT_CARD_SUFFIX.png.sha1 index a02f872..2278d84 100644 --- a/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_UPDATE_CREDIT_CARD_SUFFIX.png.sha1 +++ b/components/omnibox_strings_grdp/IDS_ACC_OMNIBOX_PEDAL_UPDATE_CREDIT_CARD_SUFFIX.png.sha1
@@ -1 +1 @@ -d8eefdbdef87e96900e627d107e8ca910dabb8eb \ No newline at end of file +72ef8eb60a081b86521be47728ae0681203f7351 \ No newline at end of file
diff --git a/components/page_load_metrics/browser/observers/use_counter/ukm_features.cc b/components/page_load_metrics/browser/observers/use_counter/ukm_features.cc index 8c4045c..cc60f8a 100644 --- a/components/page_load_metrics/browser/observers/use_counter/ukm_features.cc +++ b/components/page_load_metrics/browser/observers/use_counter/ukm_features.cc
@@ -173,6 +173,8 @@ WebFeature::kPerformanceObserverEntryTypesAndBuffered, WebFeature::kStorageAccessAPI_HasStorageAccess_Method, WebFeature::kStorageAccessAPI_requestStorageAccess_Method, + WebFeature::kThirdPartyCookieRead, + WebFeature::kThirdPartyCookieWrite, })); return *opt_in_features; }
diff --git a/components/paint_preview/browser/compositor_utils.cc b/components/paint_preview/browser/compositor_utils.cc index 120d243..ecbbe63 100644 --- a/components/paint_preview/browser/compositor_utils.cc +++ b/components/paint_preview/browser/compositor_utils.cc
@@ -9,6 +9,7 @@ #include "base/bind.h" #include "build/build_config.h" #include "components/discardable_memory/service/discardable_shared_memory_manager.h" +#include "components/paint_preview/browser/paint_preview_compositor_service_impl.h" #include "components/paint_preview/browser/service_sandbox_type.h" #include "components/services/paint_preview_compositor/public/mojom/paint_preview_compositor.mojom.h" #include "components/strings/grit/components_strings.h" @@ -31,6 +32,31 @@ } // namespace +std::unique_ptr<PaintPreviewCompositorService> StartCompositorService( + base::OnceClosure disconnect_handler) { + // Create a dedicated sequence for communicating with the compositor. This + // sequence will handle message serialization/deserialization of bitmaps so it + // affects user visible elements. This is an implementation detail and the + // caller should continue to communicate with the compositor via the sequence + // that called this. + auto compositor_task_runner = base::ThreadPool::CreateSequencedTaskRunner( + {base::TaskPriority::USER_VISIBLE, + base::ThreadPolicy::MUST_USE_FOREGROUND}); + + // The discardable memory manager isn't initialized here. This is handled in + // the constructor of PaintPreviewCompositorServiceImpl once the pending + // remote becomes bound. + mojo::PendingRemote<mojom::PaintPreviewCompositorCollection> pending_remote; + compositor_task_runner->PostTask( + FROM_HERE, + base::BindOnce(&CreateCompositorCollectionPending, + pending_remote.InitWithNewPipeAndPassReceiver())); + + return std::make_unique<PaintPreviewCompositorServiceImpl>( + std::move(pending_remote), compositor_task_runner, + std::move(disconnect_handler)); +} + mojo::Remote<mojom::PaintPreviewCompositorCollection> CreateCompositorCollection() { mojo::Remote<mojom::PaintPreviewCompositorCollection> collection;
diff --git a/components/paint_preview/browser/compositor_utils.h b/components/paint_preview/browser/compositor_utils.h index 8a2225c6..221db661 100644 --- a/components/paint_preview/browser/compositor_utils.h +++ b/components/paint_preview/browser/compositor_utils.h
@@ -5,11 +5,16 @@ #ifndef COMPONENTS_PAINT_PREVIEW_BROWSER_COMPOSITOR_UTILS_H_ #define COMPONENTS_PAINT_PREVIEW_BROWSER_COMPOSITOR_UTILS_H_ +#include "components/paint_preview/public/paint_preview_compositor_service.h" #include "components/services/paint_preview_compositor/public/mojom/paint_preview_compositor.mojom.h" #include "mojo/public/cpp/bindings/remote.h" namespace paint_preview { +// Starts the compositor service in a utility process. +std::unique_ptr<PaintPreviewCompositorService> StartCompositorService( + base::OnceClosure disconnect_handler); + // Creates a utility process via the service manager that is sandboxed and // running an instance of the PaintPreviewCompositorCollectionImpl. This can be // used to create compositor instances that composite Paint Previews into
diff --git a/components/paint_preview/browser/paint_preview_base_service.cc b/components/paint_preview/browser/paint_preview_base_service.cc index 14931a94..7ca3df9 100644 --- a/components/paint_preview/browser/paint_preview_base_service.cc +++ b/components/paint_preview/browser/paint_preview_base_service.cc
@@ -18,7 +18,6 @@ #include "components/keyed_service/core/keyed_service.h" #include "components/paint_preview/browser/compositor_utils.h" #include "components/paint_preview/browser/paint_preview_client.h" -#include "components/paint_preview/browser/paint_preview_compositor_service_impl.h" #include "components/paint_preview/common/mojom/paint_preview_recorder.mojom.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/web_contents.h" @@ -115,32 +114,6 @@ start_time, std::move(callback))); } -std::unique_ptr<PaintPreviewCompositorService> -PaintPreviewBaseService::StartCompositorService( - base::OnceClosure disconnect_handler) { - // Create a dedicated sequence for communicating with the compositor. This - // sequence will handle message serialization/deserialization of bitmaps so it - // affects user visible elements. This is an implementation detail and the - // caller should continue to communicate with the compositor via the sequence - // that called this. - auto compositor_task_runner = base::ThreadPool::CreateSequencedTaskRunner( - {base::TaskPriority::USER_VISIBLE, - base::ThreadPolicy::MUST_USE_FOREGROUND}); - - // The discardable memory manager isn't initialized here. This is handled in - // the constructor of PaintPreviewCompositorServiceImpl once the pending - // remote becomes bound. - mojo::PendingRemote<mojom::PaintPreviewCompositorCollection> pending_remote; - compositor_task_runner->PostTask( - FROM_HERE, - base::BindOnce(&CreateCompositorCollectionPending, - pending_remote.InitWithNewPipeAndPassReceiver())); - - return std::make_unique<PaintPreviewCompositorServiceImpl>( - std::move(pending_remote), compositor_task_runner, - std::move(disconnect_handler)); -} - void PaintPreviewBaseService::OnCaptured( int frame_tree_node_id, base::TimeTicks start_time,
diff --git a/components/paint_preview/browser/paint_preview_base_service.h b/components/paint_preview/browser/paint_preview_base_service.h index 1b0a705..6fea583 100644 --- a/components/paint_preview/browser/paint_preview_base_service.h +++ b/components/paint_preview/browser/paint_preview_base_service.h
@@ -24,7 +24,6 @@ #include "components/paint_preview/common/file_utils.h" #include "components/paint_preview/common/mojom/paint_preview_recorder.mojom.h" #include "components/paint_preview/common/proto/paint_preview.pb.h" -#include "components/paint_preview/public/paint_preview_compositor_service.h" #include "content/public/browser/web_contents.h" namespace paint_preview { @@ -128,10 +127,6 @@ size_t max_per_capture_size, OnCapturedCallback callback); - // Starts the compositor service in a utility process. - std::unique_ptr<PaintPreviewCompositorService> StartCompositorService( - base::OnceClosure disconnect_handler); - private: void OnCaptured(int frame_tree_node_id, base::TimeTicks start_time,
diff --git a/components/paint_preview/player/player_compositor_delegate.cc b/components/paint_preview/player/player_compositor_delegate.cc index 83ca5d6e..95cc660 100644 --- a/components/paint_preview/player/player_compositor_delegate.cc +++ b/components/paint_preview/player/player_compositor_delegate.cc
@@ -113,10 +113,9 @@ TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("paint_preview", "PlayerCompositorDelegate CreateCompositor", TRACE_ID_LOCAL(this)); - paint_preview_compositor_service_ = - paint_preview_service_->StartCompositorService(base::BindOnce( - &PlayerCompositorDelegate::OnCompositorServiceDisconnected, - weak_factory_.GetWeakPtr())); + paint_preview_compositor_service_ = StartCompositorService( + base::BindOnce(&PlayerCompositorDelegate::OnCompositorServiceDisconnected, + weak_factory_.GetWeakPtr())); paint_preview_compositor_client_ = paint_preview_compositor_service_->CreateCompositor(
diff --git a/components/password_manager/core/browser/credential_manager_pending_request_task.cc b/components/password_manager/core/browser/credential_manager_pending_request_task.cc index 271bbd3..baeed3e 100644 --- a/components/password_manager/core/browser/credential_manager_pending_request_task.cc +++ b/components/password_manager/core/browser/credential_manager_pending_request_task.cc
@@ -56,7 +56,11 @@ // Remove duplicates in |forms| before displaying them in the account chooser. void FilterDuplicates( std::vector<std::unique_ptr<autofill::PasswordForm>>* forms) { - std::vector<std::unique_ptr<autofill::PasswordForm>> federated_forms; + auto federated_forms_with_unique_username = + MakeFlatSet(/*key_getter=*/[](const auto& form) { + return std::make_pair(form->username_value, form->federation_origin); + }); + // The key is [username, signon_realm, store]. signon_realm is used only for // PSL matches because those entries have it in the UI. auto credentials = MakeFlatSet(/*key_getter=*/[](const auto& form) { @@ -67,7 +71,13 @@ }); for (auto& form : *forms) { if (!form->federation_origin.opaque()) { - federated_forms.push_back(std::move(form)); + // |forms| contains credentials from both the profile and account stores. + // Therefore, it could potentially contains duplicate federated + // credentials. In case of duplicates, favor the account store version. + auto result = + federated_forms_with_unique_username.insert(std::move(form)); + if (!result.second && form->IsUsingAccountStore()) + *result.first = std::move(form); } else { auto result = credentials.insert(std::move(form)); if (!result.second && IsBetterMatch(*form, **result.first)) @@ -93,6 +103,9 @@ *result.first = std::move(form); } *forms = std::move(credentials_with_unique_passwords).extract(); + + std::vector<std::unique_ptr<autofill::PasswordForm>> federated_forms = + std::move(federated_forms_with_unique_username).extract(); std::move(federated_forms.begin(), federated_forms.end(), std::back_inserter(*forms)); }
diff --git a/components/password_manager/core/browser/credential_manager_pending_request_task_unittest.cc b/components/password_manager/core/browser/credential_manager_pending_request_task_unittest.cc index ecafe67..849d4f26 100644 --- a/components/password_manager/core/browser/credential_manager_pending_request_task_unittest.cc +++ b/components/password_manager/core/browser/credential_manager_pending_request_task_unittest.cc
@@ -202,4 +202,36 @@ EXPECT_TRUE(client()->forms_passed_to_ui()[0]->IsUsingAccountStore()); } +TEST_F(CredentialManagerPendingRequestTaskTest, + SameFederatedCredentialsInBothStores) { + // This is testing that when two federated credentials have the same username + // for the same origin, the account store version is passed to the UI. + GURL federation_url("https://google.com/"); + CredentialManagerPendingRequestTask task( + &delegate_mock_, /*callback=*/base::DoNothing(), + CredentialMediationRequirement::kOptional, /*include_passwords=*/false, + {federation_url}, StoresToQuery::kProfileAndAccountStores); + + form_.federation_origin = url::Origin::Create(federation_url); + form_.password_value = base::string16(); + form_.signon_realm = "federation://example.com/google.com"; + + autofill::PasswordForm profile_form = form_; + profile_form.in_store = autofill::PasswordForm::Store::kProfileStore; + std::vector<std::unique_ptr<autofill::PasswordForm>> profile_forms; + profile_forms.push_back( + std::make_unique<autofill::PasswordForm>(profile_form)); + + autofill::PasswordForm account_form = form_; + account_form.in_store = autofill::PasswordForm::Store::kAccountStore; + std::vector<std::unique_ptr<autofill::PasswordForm>> account_forms; + account_forms.push_back( + std::make_unique<autofill::PasswordForm>(account_form)); + + task.OnGetPasswordStoreResultsFrom(profile_store_, std::move(profile_forms)); + task.OnGetPasswordStoreResultsFrom(account_store_, std::move(account_forms)); + ASSERT_EQ(1U, client()->forms_passed_to_ui().size()); + EXPECT_TRUE(client()->forms_passed_to_ui()[0]->IsUsingAccountStore()); +} + } // namespace password_manager
diff --git a/components/password_manager/core/browser/multi_store_password_save_manager_unittest.cc b/components/password_manager/core/browser/multi_store_password_save_manager_unittest.cc index 9a9bc080c..9f85879 100644 --- a/components/password_manager/core/browser/multi_store_password_save_manager_unittest.cc +++ b/components/password_manager/core/browser/multi_store_password_save_manager_unittest.cc
@@ -238,7 +238,7 @@ SetDefaultPasswordStore(PasswordForm::Store::kAccountStore); password_save_manager()->CreatePendingCredentials( - parsed_submitted_form_, observed_form_, submitted_form_, + parsed_submitted_form_, &observed_form_, submitted_form_, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -247,7 +247,7 @@ EXPECT_CALL(*mock_profile_form_saver(), Save(_, _, _)).Times(0); EXPECT_CALL(*mock_account_form_saver(), Save(_, _, _)); - password_save_manager()->Save(observed_form_, parsed_submitted_form_); + password_save_manager()->Save(&observed_form_, parsed_submitted_form_); } TEST_F(MultiStorePasswordSaveManagerTest, @@ -259,7 +259,7 @@ SetDefaultPasswordStore(PasswordForm::Store::kAccountStore); password_save_manager()->CreatePendingCredentials( - parsed_submitted_form_, observed_form_, submitted_form_, + parsed_submitted_form_, &observed_form_, submitted_form_, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -268,7 +268,7 @@ EXPECT_CALL(*mock_profile_form_saver(), Save(_, _, _)).Times(0); EXPECT_CALL(*mock_account_form_saver(), Save(_, _, _)).Times(0); - password_save_manager()->Save(observed_form_, parsed_submitted_form_); + password_save_manager()->Save(&observed_form_, parsed_submitted_form_); } TEST_F(MultiStorePasswordSaveManagerTest, SaveInProfileStore) { @@ -279,7 +279,7 @@ SetDefaultPasswordStore(PasswordForm::Store::kProfileStore); password_save_manager()->CreatePendingCredentials( - parsed_submitted_form_, observed_form_, submitted_form_, + parsed_submitted_form_, &observed_form_, submitted_form_, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -288,7 +288,7 @@ EXPECT_CALL(*mock_profile_form_saver(), Save(_, _, _)); EXPECT_CALL(*mock_account_form_saver(), Save(_, _, _)).Times(0); - password_save_manager()->Save(observed_form_, parsed_submitted_form_); + password_save_manager()->Save(&observed_form_, parsed_submitted_form_); } TEST_F(MultiStorePasswordSaveManagerTest, UpdateInAccountStoreOnly) { @@ -301,7 +301,7 @@ SetNonFederatedAndNotifyFetchCompleted({&saved_match_in_account_store}); password_save_manager()->CreatePendingCredentials( - parsed_submitted_form_, observed_form_, submitted_form_, + parsed_submitted_form_, &observed_form_, submitted_form_, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -312,7 +312,7 @@ EXPECT_CALL(*mock_profile_form_saver(), Update(_, _, _)).Times(0); EXPECT_CALL(*mock_account_form_saver(), Update(_, _, _)); - password_save_manager()->Save(observed_form_, parsed_submitted_form_); + password_save_manager()->Save(&observed_form_, parsed_submitted_form_); } TEST_F(MultiStorePasswordSaveManagerTest, UpdateInProfileStoreOnly) { @@ -325,7 +325,7 @@ SetNonFederatedAndNotifyFetchCompleted({&saved_match_in_profile_store}); password_save_manager()->CreatePendingCredentials( - parsed_submitted_form_, observed_form_, submitted_form_, + parsed_submitted_form_, &observed_form_, submitted_form_, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -336,7 +336,7 @@ EXPECT_CALL(*mock_profile_form_saver(), Update(_, _, _)); EXPECT_CALL(*mock_account_form_saver(), Update(_, _, _)).Times(0); - password_save_manager()->Save(observed_form_, parsed_submitted_form_); + password_save_manager()->Save(&observed_form_, parsed_submitted_form_); } TEST_F(MultiStorePasswordSaveManagerTest, UpdateInBothStores) { @@ -363,7 +363,7 @@ {&saved_match_in_profile_store, &saved_match_in_account_store}); password_save_manager()->CreatePendingCredentials( - parsed_submitted_form_, observed_form_, submitted_form_, + parsed_submitted_form_, &observed_form_, submitted_form_, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -400,7 +400,7 @@ EXPECT_CALL(*mock_account_form_saver(), Update(expected_account_updated_form, _, _)); - password_save_manager()->Save(observed_form_, parsed_submitted_form_); + password_save_manager()->Save(&observed_form_, parsed_submitted_form_); } TEST_F(MultiStorePasswordSaveManagerTest, AutomaticSaveInBothStores) { @@ -431,7 +431,7 @@ {&saved_match_in_profile_store, &saved_match_in_account_store}); password_save_manager()->CreatePendingCredentials( - parsed_submitted_form_, observed_form_, submitted_form_, + parsed_submitted_form_, &observed_form_, submitted_form_, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -461,7 +461,7 @@ EXPECT_CALL(*mock_account_form_saver(), Update(expected_account_update_form, _, _)); - password_save_manager()->Save(observed_form_, parsed_submitted_form_); + password_save_manager()->Save(&observed_form_, parsed_submitted_form_); } // Since conflicts in the profile store should not be taken into account during @@ -619,14 +619,14 @@ SetNonFederatedAndNotifyFetchCompleted({&psl_saved_match}); password_save_manager()->CreatePendingCredentials( - parsed_submitted_form_, observed_form_, submitted_form_, + parsed_submitted_form_, &observed_form_, submitted_form_, /*is_http_auth=*/false, /*is_credential_api_save=*/false); EXPECT_CALL(*mock_profile_form_saver(), Save(_, _, _)).Times(0); EXPECT_CALL(*mock_account_form_saver(), Save(_, _, _)); - password_save_manager()->Save(observed_form_, parsed_submitted_form_); + password_save_manager()->Save(&observed_form_, parsed_submitted_form_); } TEST_F(MultiStorePasswordSaveManagerTest, @@ -640,14 +640,14 @@ SetNonFederatedAndNotifyFetchCompleted({&psl_saved_match}); password_save_manager()->CreatePendingCredentials( - parsed_submitted_form_, observed_form_, submitted_form_, + parsed_submitted_form_, &observed_form_, submitted_form_, /*is_http_auth=*/false, /*is_credential_api_save=*/false); EXPECT_CALL(*mock_profile_form_saver(), Save(_, _, _)); EXPECT_CALL(*mock_account_form_saver(), Save(_, _, _)).Times(0); - password_save_manager()->Save(observed_form_, parsed_submitted_form_); + password_save_manager()->Save(&observed_form_, parsed_submitted_form_); } TEST_F(MultiStorePasswordSaveManagerTest, @@ -672,14 +672,14 @@ {&profile_psl_saved_match, &account_psl_saved_match}); password_save_manager()->CreatePendingCredentials( - parsed_submitted_form_, observed_form_, submitted_form_, + parsed_submitted_form_, &observed_form_, submitted_form_, /*is_http_auth=*/false, /*is_credential_api_save=*/false); EXPECT_CALL(*mock_profile_form_saver(), Save(_, _, _)); EXPECT_CALL(*mock_account_form_saver(), Save(_, _, _)); - password_save_manager()->Save(observed_form_, parsed_submitted_form_); + password_save_manager()->Save(&observed_form_, parsed_submitted_form_); } TEST_F(MultiStorePasswordSaveManagerTest, UpdateVsPSLMatch) { @@ -701,7 +701,7 @@ {&profile_saved_match, &account_psl_saved_match}); password_save_manager()->CreatePendingCredentials( - parsed_submitted_form_, observed_form_, submitted_form_, + parsed_submitted_form_, &observed_form_, submitted_form_, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -711,7 +711,7 @@ EXPECT_CALL(*mock_profile_form_saver(), Update(_, _, _)); EXPECT_CALL(*mock_account_form_saver(), Save(_, _, _)); - password_save_manager()->Save(observed_form_, parsed_submitted_form_); + password_save_manager()->Save(&observed_form_, parsed_submitted_form_); } TEST_F(MultiStorePasswordSaveManagerTest, UnblacklistInBothStores) { @@ -771,7 +771,7 @@ SetNonFederatedAndNotifyFetchCompleted({&saved_match_in_profile_store}); password_save_manager()->CreatePendingCredentials( - saved_match_in_profile_store, observed_form_, submitted_form_, + saved_match_in_profile_store, &observed_form_, submitted_form_, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -799,7 +799,7 @@ SetNonFederatedAndNotifyFetchCompleted({&saved_match_in_profile_store}); password_save_manager()->CreatePendingCredentials( - saved_match_in_profile_store, observed_form_, submitted_form_, + saved_match_in_profile_store, &observed_form_, submitted_form_, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -824,7 +824,7 @@ credentials_with_diffrent_username.username_value = ASCIIToUTF16("different_username"); password_save_manager()->CreatePendingCredentials( - credentials_with_diffrent_username, observed_form_, submitted_form_, + credentials_with_diffrent_username, &observed_form_, submitted_form_, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -848,7 +848,7 @@ {&saved_match_in_profile_store, &psl_saved_match_in_profile_store}); password_save_manager()->CreatePendingCredentials( - saved_match_in_profile_store, observed_form_, submitted_form_, + saved_match_in_profile_store, &observed_form_, submitted_form_, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -872,7 +872,7 @@ SetFederatedAndNotifyFetchCompleted({&federated_match_in_profile_store}); password_save_manager()->CreatePendingCredentials( - federated_match_in_profile_store, observed_form_, submitted_form_, + federated_match_in_profile_store, &observed_form_, submitted_form_, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -895,7 +895,7 @@ {&saved_match_in_profile_store, &saved_match_in_account_store}); password_save_manager()->CreatePendingCredentials( - saved_match_in_profile_store, observed_form_, submitted_form_, + saved_match_in_profile_store, &observed_form_, submitted_form_, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -923,7 +923,7 @@ &psl_saved_match_in_account_store}); password_save_manager()->CreatePendingCredentials( - saved_match_in_profile_store, observed_form_, submitted_form_, + saved_match_in_profile_store, &observed_form_, submitted_form_, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -951,7 +951,7 @@ SetNonFederatedAndNotifyFetchCompleted({&profile_saved_match}); password_save_manager()->CreatePendingCredentials( - parsed_submitted_form_, observed_form_, submitted_form_, + parsed_submitted_form_, &observed_form_, submitted_form_, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -984,7 +984,7 @@ SetNonFederatedAndNotifyFetchCompleted({&profile_saved_match}); password_save_manager()->CreatePendingCredentials( - parsed_submitted_form_, observed_form_, submitted_form_, + parsed_submitted_form_, &observed_form_, submitted_form_, /*is_http_auth=*/false, /*is_credential_api_save=*/false);
diff --git a/components/password_manager/core/browser/password_form_manager.cc b/components/password_manager/core/browser/password_form_manager.cc index ac3cde41..690257a 100644 --- a/components/password_manager/core/browser/password_form_manager.cc +++ b/components/password_manager/core/browser/password_form_manager.cc
@@ -312,7 +312,7 @@ newly_blacklisted_ = false; } - password_save_manager_->Save(observed_form_, *parsed_submitted_form_); + password_save_manager_->Save(&observed_form_, *parsed_submitted_form_); client_->UpdateFormManagers(); } @@ -323,7 +323,7 @@ metrics_recorder_->SetSubmissionIndicatorEvent( parsed_submitted_form_->submission_event); - password_save_manager_->Update(credentials_to_update, observed_form_, + password_save_manager_->Update(credentials_to_update, &observed_form_, *parsed_submitted_form_); client_->UpdateFormManagers(); @@ -685,7 +685,7 @@ return; password_save_manager_->CreatePendingCredentials( - *parsed_submitted_form_, observed_form_, submitted_form_, IsHttpAuth(), + *parsed_submitted_form_, &observed_form_, submitted_form_, IsHttpAuth(), IsCredentialAPISave()); }
diff --git a/components/password_manager/core/browser/password_form_manager_unittest.cc b/components/password_manager/core/browser/password_form_manager_unittest.cc index 758b6233..c2c1159 100644 --- a/components/password_manager/core/browser/password_form_manager_unittest.cc +++ b/components/password_manager/core/browser/password_form_manager_unittest.cc
@@ -105,8 +105,8 @@ return arg.new_password_value == password_value; } -MATCHER_P(FormDataEqualTo, form_data, "") { - return autofill::FormDataEqualForTesting(arg, form_data); +MATCHER_P(FormDataPointeeEqualTo, form_data, "") { + return autofill::FormDataEqualForTesting(*arg, form_data); } class MockPasswordManagerDriver : public StubPasswordManagerDriver { @@ -2380,16 +2380,16 @@ MOCK_CONST_METHOD0(GetFormSaver, FormSaver*()); MOCK_METHOD5(CreatePendingCredentials, void(const autofill::PasswordForm&, - const autofill::FormData&, + const autofill::FormData*, const autofill::FormData&, bool, bool)); MOCK_METHOD0(ResetPendingCredentials, void()); MOCK_METHOD2(Save, - void(const autofill::FormData&, const autofill::PasswordForm&)); + void(const autofill::FormData*, const autofill::PasswordForm&)); MOCK_METHOD3(Update, void(const autofill::PasswordForm&, - const autofill::FormData&, + const autofill::FormData*, const autofill::PasswordForm&)); MOCK_METHOD1(PermanentlyBlacklist, void(const PasswordStore::FormDigest&)); MOCK_METHOD1(Unblacklist, void(const PasswordStore::FormDigest&)); @@ -2475,7 +2475,7 @@ form_manager_->ProvisionallySave(submitted_form, &driver_, nullptr)); PasswordForm updated_form; EXPECT_CALL(*mock_password_save_manager(), - Save(FormDataEqualTo(observed_form_), _)) + Save(FormDataPointeeEqualTo(observed_form_), _)) .WillOnce(SaveArg<1>(&updated_form)); EXPECT_CALL(client_, UpdateFormManagers()); form_manager_->Save(); @@ -2692,7 +2692,7 @@ EXPECT_TRUE( form_manager_->ProvisionallySave(submitted_form_, &driver_, nullptr)); EXPECT_CALL(*mock_password_save_manager(), - Save(FormDataEqualTo(submitted_form_), _)) + Save(FormDataPointeeEqualTo(submitted_form_), _)) .WillOnce(SaveArg<1>(&updated_form)); form_manager_->Save(); EXPECT_EQ(submitted_form_.fields[kUsernameFieldIndex].value,
diff --git a/components/password_manager/core/browser/password_save_manager.h b/components/password_manager/core/browser/password_save_manager.h index cf7c1b5..e8e5158 100644 --- a/components/password_manager/core/browser/password_save_manager.h +++ b/components/password_manager/core/browser/password_save_manager.h
@@ -50,22 +50,28 @@ virtual FormSaver* GetFormSaver() const = 0; - // Create pending credentials from |parsed_submitted_form| and - // |parsed_observed_form| and |submitted_form|. + // Create pending credentials from |parsed_submitted_form| and |observed_form| + // and |submitted_form|. In the case of HTTP or proxy auth no |observed_form| + // exists, so this parameter is optional. virtual void CreatePendingCredentials( const autofill::PasswordForm& parsed_submitted_form, - const autofill::FormData& observed_form, + const autofill::FormData* observed_form, const autofill::FormData& submitted_form, bool is_http_auth, bool is_credential_api_save) = 0; virtual void ResetPendingCredentials() = 0; - virtual void Save(const autofill::FormData& observed_form, + // Saves `parsed_submitted_form` to the store. An optional `observed_form` is + // passed along to be able to send votes. This is null for HTTP or proxy auth. + virtual void Save(const autofill::FormData* observed_form, const autofill::PasswordForm& parsed_submitted_form) = 0; + // Replaces `credentials_to_update` with `parsed_submitted_form` in the store. + // An optional `observed_form` is passed along to be able to send votes. This + // is null for HTTP or proxy auth. virtual void Update(const autofill::PasswordForm& credentials_to_update, - const autofill::FormData& observed_form, + const autofill::FormData* observed_form, const autofill::PasswordForm& parsed_submitted_form) = 0; virtual void PermanentlyBlacklist(
diff --git a/components/password_manager/core/browser/password_save_manager_impl.cc b/components/password_manager/core/browser/password_save_manager_impl.cc index 8f23543..e92d331 100644 --- a/components/password_manager/core/browser/password_save_manager_impl.cc +++ b/components/password_manager/core/browser/password_save_manager_impl.cc
@@ -41,7 +41,7 @@ PasswordForm PendingCredentialsForNewCredentials( const PasswordForm& parsed_submitted_form, - const FormData& observed_form, + const FormData* observed_form, const base::string16& password_element, bool is_http_auth, bool is_credential_api_save) { @@ -49,7 +49,8 @@ return parsed_submitted_form; PasswordForm pending_credentials = parsed_submitted_form; - pending_credentials.form_data = observed_form; + if (observed_form) + pending_credentials.form_data = *observed_form; // The password value will be filled in later, remove any garbage for now. pending_credentials.password_value.clear(); // The password element should be determined earlier in |PasswordToSave|. @@ -156,7 +157,7 @@ void PasswordSaveManagerImpl::CreatePendingCredentials( const PasswordForm& parsed_submitted_form, - const FormData& observed_form, + const FormData* observed_form, const FormData& submitted_form, bool is_http_auth, bool is_credential_api_save) { @@ -214,7 +215,7 @@ pending_credentials_state_ = PendingCredentialsState::NONE; } -void PasswordSaveManagerImpl::Save(const FormData& observed_form, +void PasswordSaveManagerImpl::Save(const FormData* observed_form, const PasswordForm& parsed_submitted_form) { if (IsPasswordUpdate() && pending_credentials_.type == PasswordForm::Type::kGenerated && @@ -241,7 +242,7 @@ void PasswordSaveManagerImpl::Update( const PasswordForm& credentials_to_update, - const FormData& observed_form, + const FormData* observed_form, const PasswordForm& parsed_submitted_form) { base::string16 password_to_save = pending_credentials_.password_value; bool skip_zero_click = pending_credentials_.skip_zero_click; @@ -375,7 +376,7 @@ PasswordForm PasswordSaveManagerImpl::BuildPendingCredentials( PendingCredentialsState pending_credentials_state, const PasswordForm& parsed_submitted_form, - const FormData& observed_form, + const FormData* observed_form, const FormData& submitted_form, const base::Optional<base::string16>& generated_password, bool is_http_auth, @@ -458,7 +459,7 @@ } void PasswordSaveManagerImpl::SavePendingToStore( - const FormData& observed_form, + const FormData* observed_form, const PasswordForm& parsed_submitted_form) { UploadVotesAndMetrics(observed_form, parsed_submitted_form); @@ -494,16 +495,19 @@ } void PasswordSaveManagerImpl::UploadVotesAndMetrics( - const FormData& observed_form, + const FormData* observed_form, const PasswordForm& parsed_submitted_form) { if (IsNewLogin()) { metrics_util::LogNewlySavedPasswordIsGenerated( pending_credentials_.type == PasswordForm::Type::kGenerated, client_->GetPasswordFeatureManager() ->ComputePasswordAccountStorageUsageLevel()); - votes_uploader_->SendVotesOnSave(observed_form, parsed_submitted_form, - form_fetcher_->GetBestMatches(), - &pending_credentials_); + // Don't send votes if there was no observed form. + if (observed_form) { + votes_uploader_->SendVotesOnSave(*observed_form, parsed_submitted_form, + form_fetcher_->GetBestMatches(), + &pending_credentials_); + } return; } @@ -521,11 +525,12 @@ base::UserMetricsAction("PasswordManager_LoginFollowingAutofill")); // Check to see if this form is a candidate for password generation. - // Do not send votes on change password forms, since they were already sent - // in Update() method. - if (!parsed_submitted_form.IsPossibleChangePasswordForm()) { + // Do not send votes if there was no observed form. Furthermore, don't send + // votes on change password forms, since they were already sent in Update() + // method. + if (observed_form && !parsed_submitted_form.IsPossibleChangePasswordForm()) { votes_uploader_->SendVoteOnCredentialsReuse( - observed_form, parsed_submitted_form, &pending_credentials_); + *observed_form, parsed_submitted_form, &pending_credentials_); } if (IsPasswordUpdate()) { votes_uploader_->UploadPasswordVote(
diff --git a/components/password_manager/core/browser/password_save_manager_impl.h b/components/password_manager/core/browser/password_save_manager_impl.h index b89a5666..a4c5fa26 100644 --- a/components/password_manager/core/browser/password_save_manager_impl.h +++ b/components/password_manager/core/browser/password_save_manager_impl.h
@@ -43,18 +43,18 @@ // and |submitted_form|. void CreatePendingCredentials( const autofill::PasswordForm& parsed_submitted_form, - const autofill::FormData& observed_form, + const autofill::FormData* observed_form, const autofill::FormData& submitted_form, bool is_http_auth, bool is_credential_api_save) override; void ResetPendingCredentials() override; - void Save(const autofill::FormData& observed_form, + void Save(const autofill::FormData* observed_form, const autofill::PasswordForm& parsed_submitted_form) override; void Update(const autofill::PasswordForm& credentials_to_update, - const autofill::FormData& observed_form, + const autofill::FormData* observed_form, const autofill::PasswordForm& parsed_submitted_form) override; void PermanentlyBlacklist( @@ -95,7 +95,7 @@ static autofill::PasswordForm BuildPendingCredentials( PendingCredentialsState pending_credentials_state, const autofill::PasswordForm& parsed_submitted_form, - const autofill::FormData& observed_form, + const autofill::FormData* observed_form, const autofill::FormData& submitted_form, const base::Optional<base::string16>& generated_password, bool is_http_auth, @@ -149,13 +149,13 @@ const autofill::PasswordForm& parsed_submitted_form); // Save/update |pending_credentials_| to the password store. - void SavePendingToStore(const autofill::FormData& observed_form, + void SavePendingToStore(const autofill::FormData* observed_form, const autofill::PasswordForm& parsed_submitted_form); // This sends needed signals to the autofill server, and also triggers some // UMA reporting. void UploadVotesAndMetrics( - const autofill::FormData& observed_form, + const autofill::FormData* observed_form, const autofill::PasswordForm& parsed_submitted_form); // Handles the user flows related to the generation.
diff --git a/components/password_manager/core/browser/password_save_manager_impl_unittest.cc b/components/password_manager/core/browser/password_save_manager_impl_unittest.cc index c71afbc4..6290d491 100644 --- a/components/password_manager/core/browser/password_save_manager_impl_unittest.cc +++ b/components/password_manager/core/browser/password_save_manager_impl_unittest.cc
@@ -403,7 +403,7 @@ const base::Time kNow = base::Time::Now(); password_save_manager_impl()->CreatePendingCredentials( - Parse(submitted_form_), observed_form_, submitted_form_, + Parse(submitted_form_), &observed_form_, submitted_form_, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -418,7 +418,7 @@ TEST_P(PasswordSaveManagerImplTest, CreatePendingCredentialsNewCredentials) { SetNonFederatedAndNotifyFetchCompleted({&saved_match_}); password_save_manager_impl()->CreatePendingCredentials( - Parse(submitted_form_), observed_form_, submitted_form_, + Parse(submitted_form_), &observed_form_, submitted_form_, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -438,7 +438,7 @@ saved_match_.password_value; password_save_manager_impl()->CreatePendingCredentials( - Parse(submitted_form_), observed_form_, submitted_form_, + Parse(submitted_form_), &observed_form_, submitted_form_, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -463,7 +463,7 @@ saved_match_.password_value; password_save_manager_impl()->CreatePendingCredentials( - Parse(submitted_form_), observed_form_, submitted_form_, + Parse(submitted_form_), &observed_form_, submitted_form_, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -484,7 +484,7 @@ submitted_form_.fields[kPasswordFieldIndex].value = expected.password_value; password_save_manager_impl()->CreatePendingCredentials( - Parse(submitted_form_), observed_form_, submitted_form_, + Parse(submitted_form_), &observed_form_, submitted_form_, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -505,7 +505,7 @@ expected.password_value = ASCIIToUTF16("verystrongpassword"); password_save_manager_impl()->CreatePendingCredentials( - Parse(submitted_form), observed_form_, submitted_form, + Parse(submitted_form), &observed_form_, submitted_form, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -528,7 +528,7 @@ PasswordForm expected = saved_match_; expected.password_value = ASCIIToUTF16("verystrongpassword"); password_save_manager_impl()->CreatePendingCredentials( - Parse(submitted_form), observed_form_, submitted_form, + Parse(submitted_form), &observed_form_, submitted_form, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -547,7 +547,7 @@ anonymous_signup.fields[2].autocomplete_attribute = "new-password"; password_save_manager_impl()->CreatePendingCredentials( - Parse(anonymous_signup), observed_form_, anonymous_signup, + Parse(anonymous_signup), &observed_form_, anonymous_signup, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -561,7 +561,7 @@ fetcher()->NotifyFetchCompleted(); password_save_manager_impl()->CreatePendingCredentials( - Parse(submitted_form_), observed_form_, submitted_form_, + Parse(submitted_form_), &observed_form_, submitted_form_, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -587,7 +587,7 @@ submitted_form.fields[kPasswordFieldIndex].value = new_password; password_save_manager_impl()->CreatePendingCredentials( - Parse(submitted_form), observed_form_, submitted_form, + Parse(submitted_form), &observed_form_, submitted_form, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -598,7 +598,7 @@ EXPECT_CALL(*mock_form_saver(), Save(_, _, _)) .WillOnce(DoAll(SaveArg<0>(&saved_form), SaveArg<1>(&best_matches))); - password_save_manager_impl()->Save(observed_form_, Parse(submitted_form)); + password_save_manager_impl()->Save(&observed_form_, Parse(submitted_form)); std::string expected_signon_realm = submitted_form.url.GetOrigin().spec(); EXPECT_EQ(submitted_form.url, saved_form.url); @@ -635,7 +635,7 @@ psl_saved_match_.password_value; password_save_manager_impl()->CreatePendingCredentials( - Parse(submitted_form), observed_form_, submitted_form, + Parse(submitted_form), &observed_form_, submitted_form, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -649,7 +649,7 @@ EXPECT_CALL(*mock_form_saver(), Save(_, _, _)) .WillOnce(DoAll(SaveArg<0>(&saved_form), SaveArg<1>(&best_matches))); - password_save_manager_impl()->Save(observed_form_, Parse(submitted_form)); + password_save_manager_impl()->Save(&observed_form_, Parse(submitted_form)); EXPECT_EQ(submitted_form.url, saved_form.url); EXPECT_EQ(GetSignonRealm(submitted_form.url), saved_form.signon_realm); @@ -673,7 +673,7 @@ submitted_form.fields[kPasswordFieldIndex].value = new_password; password_save_manager_impl()->CreatePendingCredentials( - Parse(submitted_form), observed_form_, submitted_form, + Parse(submitted_form), &observed_form_, submitted_form, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -685,7 +685,7 @@ saved_match_.password_value)) .WillOnce(SaveArg<0>(&updated_form)); - password_save_manager_impl()->Save(observed_form_, Parse(submitted_form)); + password_save_manager_impl()->Save(&observed_form_, Parse(submitted_form)); EXPECT_TRUE(ArePasswordFormUniqueKeysEqual(saved_match_, updated_form)); EXPECT_EQ(new_password, updated_form.password_value); @@ -707,7 +707,7 @@ submitted_form.fields[1].value = new_password; password_save_manager_impl()->CreatePendingCredentials( - Parse(submitted_form), observed_form_only_password_fields_, + Parse(submitted_form), &observed_form_only_password_fields_, submitted_form, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -724,7 +724,7 @@ saved_match_.password_value)) .WillOnce(SaveArg<0>(&updated_form)); - password_save_manager_impl()->Save(observed_form_only_password_fields_, + password_save_manager_impl()->Save(&observed_form_only_password_fields_, Parse(submitted_form)); EXPECT_TRUE(ArePasswordFormUniqueKeysEqual(saved_match_, updated_form)); @@ -742,7 +742,7 @@ submitted_form_.fields[1].value = automatically_chosen_username; PasswordForm parsed_submitted_form = Parse(submitted_form_); password_save_manager_impl()->CreatePendingCredentials( - parsed_submitted_form, observed_form_only_password_fields_, + parsed_submitted_form, &observed_form_only_password_fields_, submitted_form_, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -754,7 +754,7 @@ parsed_submitted_form.username_value = user_chosen_username; parsed_submitted_form.username_element.clear(); password_save_manager_impl()->CreatePendingCredentials( - parsed_submitted_form, observed_form_only_password_fields_, + parsed_submitted_form, &observed_form_only_password_fields_, submitted_form_, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -768,7 +768,7 @@ SetNonFederatedAndNotifyFetchCompleted({&saved_match_}); PasswordForm parsed_submitted_form = Parse(submitted_form_); password_save_manager_impl()->CreatePendingCredentials( - parsed_submitted_form, observed_form_, submitted_form_, + parsed_submitted_form, &observed_form_, submitted_form_, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -781,7 +781,7 @@ parsed_submitted_form.username_value = new_username; parsed_submitted_form.username_element.clear(); password_save_manager_impl()->CreatePendingCredentials( - parsed_submitted_form, observed_form_, submitted_form_, + parsed_submitted_form, &observed_form_, submitted_form_, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -796,7 +796,7 @@ PasswordForm parsed_submitted_form = Parse(submitted_form_); password_save_manager_impl()->CreatePendingCredentials( - parsed_submitted_form, observed_form_, submitted_form_, + parsed_submitted_form, &observed_form_, submitted_form_, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -813,7 +813,7 @@ parsed_submitted_form.new_password_element.clear(); password_save_manager_impl()->CreatePendingCredentials( - parsed_submitted_form, observed_form_, submitted_form_, + parsed_submitted_form, &observed_form_, submitted_form_, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -826,7 +826,7 @@ EXPECT_CALL(*mock_autofill_download_manager(), StartUploadRequest(_, _, _, _, _, _)) .Times(1); - password_save_manager_impl()->Save(observed_form_, parsed_submitted_form); + password_save_manager_impl()->Save(&observed_form_, parsed_submitted_form); } TEST_P(PasswordSaveManagerImplTest, UpdatePasswordValueToAlreadyExisting) { @@ -838,7 +838,7 @@ PasswordForm parsed_submitted_form = Parse(submitted_form_); password_save_manager_impl()->CreatePendingCredentials( - parsed_submitted_form, observed_form_, submitted_form_, + parsed_submitted_form, &observed_form_, submitted_form_, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -849,7 +849,7 @@ parsed_submitted_form.new_password_element.clear(); password_save_manager_impl()->CreatePendingCredentials( - parsed_submitted_form, observed_form_, submitted_form_, + parsed_submitted_form, &observed_form_, submitted_form_, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -871,7 +871,7 @@ PasswordForm parsed_submitted_form = Parse(submitted_form); password_save_manager_impl()->CreatePendingCredentials( - parsed_submitted_form, observed_form_, submitted_form, + parsed_submitted_form, &observed_form_, submitted_form, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -892,7 +892,7 @@ parsed_submitted_form.new_password_element.clear(); password_save_manager_impl()->CreatePendingCredentials( - parsed_submitted_form, observed_form_, submitted_form, + parsed_submitted_form, &observed_form_, submitted_form, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -915,7 +915,7 @@ EXPECT_CALL(*mock_form_saver(), Save(_, _, _)) .WillOnce(SaveArg<0>(&saved_form)); - password_save_manager_impl()->Save(observed_form_, parsed_submitted_form); + password_save_manager_impl()->Save(&observed_form_, parsed_submitted_form); CheckPendingCredentials(expected, saved_form); } @@ -1096,7 +1096,7 @@ submitted_form.fields[kPasswordFieldIndex].value = new_password; password_save_manager_impl()->CreatePendingCredentials( - Parse(submitted_form), observed_form_, submitted_form, + Parse(submitted_form), &observed_form_, submitted_form, /*is_http_auth=*/false, /*is_credential_api_save=*/false); @@ -1111,7 +1111,7 @@ const base::Time kNow = base::Time::Now(); - password_save_manager_impl()->Update(saved_match_, observed_form_, + password_save_manager_impl()->Update(saved_match_, &observed_form_, Parse(submitted_form)); EXPECT_TRUE(ArePasswordFormUniqueKeysEqual(saved_match_, updated_form)); @@ -1139,7 +1139,7 @@ submitted_http_auth_form.password_value = new_password; password_save_manager_impl()->CreatePendingCredentials( - submitted_http_auth_form, observed_form_, submitted_form_, + submitted_http_auth_form, &observed_form_, submitted_form_, /*is_http_auth=*/true, /*is_credential_api_save=*/false); @@ -1152,7 +1152,7 @@ Update(_, ElementsAre(Pointee(saved_http_auth_form)), password)) .WillOnce(SaveArg<0>(&updated_form)); - password_save_manager_impl()->Save(observed_form_, submitted_http_auth_form); + password_save_manager_impl()->Save(&observed_form_, submitted_http_auth_form); EXPECT_TRUE( ArePasswordFormUniqueKeysEqual(saved_http_auth_form, updated_form));
diff --git a/components/password_manager/core/browser/well_known_change_password_state_unittest.cc b/components/password_manager/core/browser/well_known_change_password_state_unittest.cc index fcb0c4e..ecc902a 100644 --- a/components/password_manager/core/browser/well_known_change_password_state_unittest.cc +++ b/components/password_manager/core/browser/well_known_change_password_state_unittest.cc
@@ -156,4 +156,4 @@ WellKnownChangePasswordStateTest, ::testing::ValuesIn(kDelayParams)); -} // namespace password_manager +} // namespace password_manager \ No newline at end of file
diff --git a/components/password_manager/ios/password_suggestion_helper.mm b/components/password_manager/ios/password_suggestion_helper.mm index f7feca5..1d133e0 100644 --- a/components/password_manager/ios/password_suggestion_helper.mm +++ b/components/password_manager/ios/password_suggestion_helper.mm
@@ -75,7 +75,8 @@ [results addObject:[FormSuggestion suggestionWithValue:username displayDescription:realm icon:nil - identifier:0]]; + identifier:0 + requiresReauth:YES]]; } }
diff --git a/components/password_manager/ios/shared_password_controller.mm b/components/password_manager/ios/shared_password_controller.mm index 05b50af8..5de3b94 100644 --- a/components/password_manager/ios/shared_password_controller.mm +++ b/components/password_manager/ios/shared_password_controller.mm
@@ -327,14 +327,18 @@ ![rawSuggestion.value hasPrefix:formQuery.typedValue])) { continue; } - [suggestions - addObject:[FormSuggestion - suggestionWithValue: - [rawSuggestion.value - stringByAppendingString:kSuggestionSuffix] - displayDescription:rawSuggestion.displayDescription - icon:nil - identifier:0]]; + DCHECK(self.delegate.passwordManagerClient); + BOOL requiresReauth = + self.delegate.passwordManagerClient->RequiresReauthToFill(); + NSString* value = + [rawSuggestion.value stringByAppendingString:kSuggestionSuffix]; + FormSuggestion* suggestion = + [FormSuggestion suggestionWithValue:value + displayDescription:rawSuggestion.displayDescription + icon:nil + identifier:0 + requiresReauth:requiresReauth]; + [suggestions addObject:suggestion]; } base::Optional<PasswordDropdownState> suggestion_state; if (suggestions.count) { @@ -346,14 +350,14 @@ fieldType:formQuery.fieldType]) { // Add "Suggest Password...". NSString* suggestPassword = GetNSString(IDS_IOS_SUGGEST_PASSWORD); - [suggestions - addObject: - [FormSuggestion - suggestionWithValue:suggestPassword - displayDescription:nil - icon:nil - identifier:autofill:: - POPUP_ITEM_ID_GENERATE_PASSWORD_ENTRY]]; + FormSuggestion* suggestion = [FormSuggestion + suggestionWithValue:suggestPassword + displayDescription:nil + icon:nil + identifier:autofill::POPUP_ITEM_ID_GENERATE_PASSWORD_ENTRY + requiresReauth:NO]; + + [suggestions addObject:suggestion]; suggestion_state = PasswordDropdownState::kStandardGenerate; }
diff --git a/components/password_manager/ios/shared_password_controller_unittest.mm b/components/password_manager/ios/shared_password_controller_unittest.mm index 1232ba7..bfcbe26 100644 --- a/components/password_manager/ios/shared_password_controller_unittest.mm +++ b/components/password_manager/ios/shared_password_controller_unittest.mm
@@ -274,7 +274,8 @@ [FormSuggestion suggestionWithValue:@"value" displayDescription:@"display-description" icon:@"icon" - identifier:0]; + identifier:0 + requiresReauth:NO]; [[[suggestion_helper_ expect] andReturn:@[ suggestion ]] retrieveSuggestionsWithFormID:form_query.uniqueFormID fieldIdentifier:form_query.uniqueFieldID @@ -347,7 +348,8 @@ suggestionWithValue:@"test-value" displayDescription:@"test-description" icon:nil - identifier:autofill::POPUP_ITEM_ID_GENERATE_PASSWORD_ENTRY]; + identifier:autofill::POPUP_ITEM_ID_GENERATE_PASSWORD_ENTRY + requiresReauth:NO]; [[delegate_ expect] sharedPasswordController:controller_ showGeneratedPotentialPassword:[OCMArg isNotNil] @@ -376,7 +378,8 @@ suggestionWithValue:@"test-value" displayDescription:@"test-description" icon:nil - identifier:autofill::POPUP_ITEM_ID_GENERATE_PASSWORD_ENTRY]; + identifier:autofill::POPUP_ITEM_ID_GENERATE_PASSWORD_ENTRY + requiresReauth:NO]; id decision_handler_arg = [OCMArg checkWithBlock:^(void (^decision_handler)(BOOL)) {
diff --git a/components/payments/content/android_app_communication.h b/components/payments/content/android_app_communication.h index 8ee2de2..d4707c8 100644 --- a/components/payments/content/android_app_communication.h +++ b/components/payments/content/android_app_communication.h
@@ -83,9 +83,14 @@ const std::string& payment_request_id, InvokePaymentAppCallback callback) = 0; - // Enables the testing mode. + // Allows usage of a test browser context. virtual void SetForTesting() = 0; + // Simulates having this payment app. + virtual void SetAppForTesting(const std::string& package_name, + const std::string& method, + const std::string& response) = 0; + protected: explicit AndroidAppCommunication(content::BrowserContext* context);
diff --git a/components/payments/content/android_app_communication_chrome_os.cc b/components/payments/content/android_app_communication_chrome_os.cc index ee184f4..1012d35 100644 --- a/components/payments/content/android_app_communication_chrome_os.cc +++ b/components/payments/content/android_app_communication_chrome_os.cc
@@ -56,12 +56,6 @@ return; } - if (response->get_valid()->service_names.size() > 1U) { - std::move(callback).Run(errors::kMoreThanOneService, - /*app_descriptions=*/{}); - return; - } - auto activity = std::make_unique<AndroidActivityDescription>(); activity->name = response->get_valid()->activity_names.front(); @@ -176,6 +170,20 @@ return parameters; } +std::vector<std::unique_ptr<AndroidAppDescription>> CreateAppForTesting( + const std::string& package_name, + const std::string& method_name) { + auto activity = std::make_unique<AndroidActivityDescription>(); + activity->name = package_name + ".Activity"; + activity->default_payment_method = method_name; + auto app = std::make_unique<AndroidAppDescription>(); + app->package = package_name; + app->activities.emplace_back(std::move(activity)); + std::vector<std::unique_ptr<AndroidAppDescription>> app_descriptions; + app_descriptions.emplace_back(std::move(app)); + return app_descriptions; +} + // Invokes the TWA Android app in Android subsystem on Chrome OS. class AndroidAppCommunicationChromeOS : public AndroidAppCommunication { public: @@ -205,6 +213,13 @@ return; } + if (!package_name_for_testing_.empty()) { + std::move(callback).Run( + /*error_message=*/base::nullopt, + CreateAppForTesting(package_name_for_testing_, method_for_testing_)); + return; + } + auto* payment_app_service = get_app_service_.Run(context()); if (!payment_app_service) { std::move(callback).Run(errors::kUnableToInvokeAndroidPaymentApps, @@ -258,6 +273,15 @@ const std::string& payment_request_id, InvokePaymentAppCallback callback) override { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + base::Optional<std::string> error_message; + if (package_name_for_testing_ == package_name) { + std::move(callback).Run(error_message, + /*is_activity_result_ok=*/true, + method_for_testing_, response_for_testing_); + return; + } + auto* payment_app_service = get_app_service_.Run(context()); if (!payment_app_service) { std::move(callback).Run(errors::kUnableToInvokeAndroidPaymentApps, @@ -267,7 +291,6 @@ return; } - base::Optional<std::string> error_message; auto parameters = CreatePaymentParameters( package_name, activity_name, stringified_method_data, top_level_origin, payment_request_origin, payment_request_id, &error_message); @@ -284,14 +307,27 @@ base::BindOnce(&OnPaymentAppResponse, std::move(callback))); } - // AndroidAppCommunication implementation: + // AndroidAppCommunication implementation. void SetForTesting() override { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); get_app_service_ = base::BindRepeating( &arc::ArcPaymentAppBridge::GetForBrowserContextForTesting); } + // AndroidAppCommunication implementation. + void SetAppForTesting(const std::string& package_name, + const std::string& method, + const std::string& response) override { + package_name_for_testing_ = package_name; + method_for_testing_ = method; + response_for_testing_ = response; + } + private: + std::string package_name_for_testing_; + std::string method_for_testing_; + std::string response_for_testing_; + base::RepeatingCallback<arc::ArcPaymentAppBridge*(content::BrowserContext*)> get_app_service_; };
diff --git a/components/payments/content/android_app_communication_stub.cc b/components/payments/content/android_app_communication_stub.cc index 99a7758..b03ab06 100644 --- a/components/payments/content/android_app_communication_stub.cc +++ b/components/payments/content/android_app_communication_stub.cc
@@ -57,6 +57,11 @@ // AndroidAppCommunication implementation. void SetForTesting() override {} + + // AndroidAppCommunication implementation. + void SetAppForTesting(const std::string& package_name, + const std::string& method, + const std::string& response) override {} }; } // namespace
diff --git a/components/payments/content/android_app_communication_unittest.cc b/components/payments/content/android_app_communication_unittest.cc index a681c10..552e46b3 100644 --- a/components/payments/content/android_app_communication_unittest.cc +++ b/components/payments/content/android_app_communication_unittest.cc
@@ -175,17 +175,28 @@ base::BindOnce(&AndroidAppCommunicationTest::OnGetAppDescriptionsResponse, base::Unretained(this))); + EXPECT_FALSE(error_.has_value()); if (support_->AreAndroidAppsSupportedOnThisPlatform()) { - ASSERT_TRUE(error_.has_value()); - EXPECT_EQ( - "Found more than one IS_READY_TO_PAY service in the Trusted Web " - "Activity, but at most one service is supported.", - error_.value()); - } else { - EXPECT_FALSE(error_.has_value()); - } + ASSERT_EQ(1u, apps_.size()); + ASSERT_NE(nullptr, apps_.front().get()); + EXPECT_EQ("com.example.app", apps_.front()->package); - EXPECT_TRUE(apps_.empty()); + // The logic for checking for multiple services is cross-platform in + // android_payment_app_factory.cc, so the platform-specific implementations + // of android_app_communication.h do not check for this error condition. + std::vector<std::string> expected_service_names = { + "com.example.app.ServiceOne", "com.example.app.ServiceTwo"}; + EXPECT_EQ(expected_service_names, apps_.front()->service_names); + + ASSERT_EQ(1u, apps_.front()->activities.size()); + ASSERT_NE(nullptr, apps_.front()->activities.front().get()); + EXPECT_EQ("com.example.app.Activity", + apps_.front()->activities.front()->name); + EXPECT_EQ("https://play.google.com/billing", + apps_.front()->activities.front()->default_payment_method); + } else { + EXPECT_TRUE(apps_.empty()); + } } TEST_F(AndroidAppCommunicationTest, ActivityAndService) {
diff --git a/components/payments/content/android_payment_app.cc b/components/payments/content/android_payment_app.cc index 64b3720..6871e68 100644 --- a/components/payments/content/android_payment_app.cc +++ b/components/payments/content/android_payment_app.cc
@@ -6,6 +6,8 @@ #include <utility> +#include "base/check.h" +#include "components/payments/core/method_strings.h" #include "components/payments/core/native_error_strings.h" #include "components/payments/core/payer_data.h" @@ -13,27 +15,26 @@ AndroidPaymentApp::AndroidPaymentApp( const std::set<std::string>& payment_method_names, - const std::map<std::string, std::set<std::string>>& stringified_method_data, + std::unique_ptr<std::map<std::string, std::set<std::string>>> + stringified_method_data, const GURL& top_level_origin, const GURL& payment_request_origin, const std::string& payment_request_id, std::unique_ptr<AndroidAppDescription> description, base::WeakPtr<AndroidAppCommunication> communication) : PaymentApp(/*icon_resource_id=*/0, PaymentApp::Type::NATIVE_MOBILE_APP), - stringified_method_data_(stringified_method_data), + stringified_method_data_(std::move(stringified_method_data)), top_level_origin_(top_level_origin), payment_request_origin_(payment_request_origin), payment_request_id_(payment_request_id), description_(std::move(description)), communication_(communication) { DCHECK(!payment_method_names.empty()); - DCHECK_EQ(payment_method_names.size(), stringified_method_data_.size()); + DCHECK_EQ(payment_method_names.size(), stringified_method_data_->size()); DCHECK_EQ(*payment_method_names.begin(), - stringified_method_data_.begin()->first); + stringified_method_data_->begin()->first); DCHECK(description_); DCHECK(!description_->package.empty()); - DCHECK_EQ(1U, description_->service_names.size()); - DCHECK(!description_->service_names.front().empty()); DCHECK_EQ(1U, description_->activities.size()); DCHECK(!description_->activities.front()->name.empty()); @@ -49,7 +50,7 @@ communication_->InvokePaymentApp( description_->package, description_->activities.front()->name, - stringified_method_data_, top_level_origin_, payment_request_origin_, + *stringified_method_data_, top_level_origin_, payment_request_origin_, payment_request_id_, base::BindOnce(&AndroidPaymentApp::OnPaymentAppResponse, weak_ptr_factory_.GetWeakPtr(), delegate)); @@ -141,6 +142,19 @@ void AndroidPaymentApp::OnPaymentDetailsNotUpdated() {} +bool AndroidPaymentApp::IsPreferred() const { + // This class used only on Chrome OS, where the only Android payment app + // available is the trusted web application (TWA) that launched this instance + // of Chrome with a TWA specific payment method, so this app should be + // preferred. +#if !defined(OS_CHROMEOS) + NOTREACHED(); +#endif // OS_CHROMEOS + DCHECK_EQ(1U, GetAppMethodNames().size()); + DCHECK_EQ(methods::kGooglePlayBilling, *GetAppMethodNames().begin()); + return true; +} + void AndroidPaymentApp::OnPaymentAppResponse( Delegate* delegate, const base::Optional<std::string>& error_message,
diff --git a/components/payments/content/android_payment_app.h b/components/payments/content/android_payment_app.h index a4b8cc7a..0e826e0e 100644 --- a/components/payments/content/android_payment_app.h +++ b/components/payments/content/android_payment_app.h
@@ -32,14 +32,15 @@ // merchant. The set of keys should match exactly the |payment_method_names|. // It is the responsibility of the creator of AndroidPaymentApp to filter out // the data from merchant that is not in |payment_method_names|. - AndroidPaymentApp(const std::set<std::string>& payment_method_names, - const std::map<std::string, std::set<std::string>>& - stringified_method_data, - const GURL& top_level_origin, - const GURL& payment_request_origin, - const std::string& payment_request_id, - std::unique_ptr<AndroidAppDescription> description, - base::WeakPtr<AndroidAppCommunication> communication); + AndroidPaymentApp( + const std::set<std::string>& payment_method_names, + std::unique_ptr<std::map<std::string, std::set<std::string>>> + stringified_method_data, + const GURL& top_level_origin, + const GURL& payment_request_origin, + const std::string& payment_request_id, + std::unique_ptr<AndroidAppDescription> description, + base::WeakPtr<AndroidAppCommunication> communication); ~AndroidPaymentApp() override; AndroidPaymentApp(const AndroidPaymentApp& other) = delete; @@ -71,6 +72,7 @@ void UpdateWith( mojom::PaymentRequestDetailsUpdatePtr details_update) override; void OnPaymentDetailsNotUpdated() override; + bool IsPreferred() const override; private: void OnPaymentAppResponse(Delegate* delegate, @@ -79,7 +81,8 @@ const std::string& payment_method_identifier, const std::string& stringified_details); - const std::map<std::string, std::set<std::string>> stringified_method_data_; + const std::unique_ptr<std::map<std::string, std::set<std::string>>> + stringified_method_data_; const GURL top_level_origin_; const GURL payment_request_origin_; const std::string payment_request_id_;
diff --git a/components/payments/content/android_payment_app_factory.cc b/components/payments/content/android_payment_app_factory.cc index f0888a01..7774e78 100644 --- a/components/payments/content/android_payment_app_factory.cc +++ b/components/payments/content/android_payment_app_factory.cc
@@ -55,6 +55,7 @@ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_EQ(nullptr, delegate_.get()); DCHECK_NE(nullptr, delegate.get()); + DCHECK_EQ(0U, number_of_pending_is_ready_to_pay_queries_); DCHECK_EQ(nullptr, communication_.get()); DCHECK_NE(nullptr, communication.get()); DCHECK(delegate->GetSpec()->details().id.has_value()); @@ -98,31 +99,101 @@ std::vector<std::unique_ptr<AndroidAppDescription>> single_activity_apps; for (size_t i = 0; i < app_descriptions.size(); ++i) { auto app = std::move(app_descriptions[i]); + if (app->service_names.size() > 1U) { + delegate_->OnPaymentAppCreationError(errors::kMoreThanOneService); + continue; + } + + // Move each activity in the given |app| to its own AndroidAppDescription + // in |single_activity_apps|, so the code can treat each PAY intent as its + // own payment app. This allows Android apps to implement PAY intent in + // multiple activities with different names and icons for different use + // cases. SplitPotentiallyMultipleActivities(std::move(app), &single_activity_apps); } + number_of_pending_is_ready_to_pay_queries_ = single_activity_apps.size(); + if (number_of_pending_is_ready_to_pay_queries_ == 0U) { + OnDoneCreatingPaymentApps(); + return; + } + for (size_t i = 0; i < single_activity_apps.size(); ++i) { - auto app = std::move(single_activity_apps[i]); + std::unique_ptr<AndroidAppDescription> single_activity_app = + std::move(single_activity_apps[i]); const std::string& default_method = - app->activities.front()->default_payment_method; + single_activity_app->activities.front()->default_payment_method; DCHECK_EQ(methods::kGooglePlayBilling, default_method); std::set<std::string> supported_payment_methods = {default_method}; - - delegate_->OnPaymentAppCreated(std::make_unique<AndroidPaymentApp>( + std::set<std::string> payment_method_names = base::STLSetIntersection<std::set<std::string>>( delegate_->GetSpec()->payment_method_identifiers_set(), - supported_payment_methods), - data_util::FilterStringifiedMethodData( + supported_payment_methods); + + std::unique_ptr<std::map<std::string, std::set<std::string>>> + stringified_method_data = data_util::FilterStringifiedMethodData( delegate_->GetSpec()->stringified_method_data(), - supported_payment_methods), - delegate_->GetTopOrigin(), delegate_->GetFrameOrigin(), - delegate_->GetSpec()->details().id.value(), std::move(app), - communication_)); + supported_payment_methods); + + // TODO(crbug.com/1022512): Download the web app manifest for + // |default_payment_method_name| to verify Android app signature. + + // Skip querying IS_READY_TO_PAY service when Chrome is off-the-record or + // when the app does not implement the IS_READY_TO_PAY service. + if (delegate_->IsOffTheRecord() || + single_activity_app->service_names.empty()) { + OnIsReadyToPay(std::move(single_activity_app), payment_method_names, + std::move(stringified_method_data), + /*error_message=*/base::nullopt, + /*is_ready_to_pay=*/true); + continue; + } + + std::map<std::string, std::set<std::string>> + stringified_method_data_copy = *stringified_method_data; + communication_->IsReadyToPay( + single_activity_app->package, + single_activity_app->service_names.front(), + stringified_method_data_copy, delegate_->GetTopOrigin(), + delegate_->GetFrameOrigin(), + delegate_->GetSpec()->details().id.value(), + base::BindOnce(&AppFinder::OnIsReadyToPay, + weak_ptr_factory_.GetWeakPtr(), + std::move(single_activity_app), payment_method_names, + std::move(stringified_method_data))); + } + } + + void OnIsReadyToPay( + std::unique_ptr<AndroidAppDescription> app_description, + const std::set<std::string>& payment_method_names, + std::unique_ptr<std::map<std::string, std::set<std::string>>> + stringified_method_data, + const base::Optional<std::string>& error_message, + bool is_ready_to_pay) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + DCHECK_LT(0U, number_of_pending_is_ready_to_pay_queries_); + + // The browser could be shutting down. + if (!communication_ || !delegate_) { + OnDoneCreatingPaymentApps(); + return; } - OnDoneCreatingPaymentApps(); + if (error_message.has_value()) { + delegate_->OnPaymentAppCreationError(error_message.value()); + } else if (is_ready_to_pay) { + delegate_->OnPaymentAppCreated(std::make_unique<AndroidPaymentApp>( + payment_method_names, std::move(stringified_method_data), + delegate_->GetTopOrigin(), delegate_->GetFrameOrigin(), + delegate_->GetSpec()->details().id.value(), + std::move(app_description), communication_)); + } + + if (--number_of_pending_is_ready_to_pay_queries_ == 0) + OnDoneCreatingPaymentApps(); } void OnDoneCreatingPaymentApps() { @@ -134,6 +205,7 @@ base::SupportsUserData* owner_; base::WeakPtr<PaymentAppFactory::Delegate> delegate_; + size_t number_of_pending_is_ready_to_pay_queries_ = 0; base::WeakPtr<AndroidAppCommunication> communication_; base::WeakPtrFactory<AppFinder> weak_ptr_factory_{this};
diff --git a/components/payments/content/android_payment_app_factory_unittest.cc b/components/payments/content/android_payment_app_factory_unittest.cc index 70223e18..404bbc0 100644 --- a/components/payments/content/android_payment_app_factory_unittest.cc +++ b/components/payments/content/android_payment_app_factory_unittest.cc
@@ -54,6 +54,8 @@ /*observer=*/nullptr, /*app_locale=*/"en-US"); } + void set_is_off_the_record() { is_off_the_record_ = true; } + // PaymentAppFactory::Delegate implementation: content::WebContents* GetWebContents() override { return web_contents_; } const GURL& GetTopOrigin() override { return top_origin_; } @@ -65,7 +67,7 @@ MOCK_CONST_METHOD0(GetPaymentManifestWebDataService, scoped_refptr<PaymentManifestWebDataService>()); MOCK_METHOD0(MayCrawlForInstallablePaymentApps, bool()); - MOCK_CONST_METHOD0(IsOffTheRecord, bool()); + bool IsOffTheRecord() const override { return is_off_the_record_; } PaymentRequestSpec* GetSpec() const override { return spec_.get(); } MOCK_CONST_METHOD0(GetTwaPackageName, std::string()); MOCK_METHOD0(ShowProcessingSpinner, void()); @@ -90,6 +92,7 @@ GURL top_origin_; GURL frame_origin_; std::unique_ptr<PaymentRequestSpec> spec_; + bool is_off_the_record_ = false; base::WeakPtrFactory<PaymentAppFactory::Delegate> weak_ptr_factory_{this}; }; @@ -129,6 +132,7 @@ .Times(support_->AreAndroidAppsSupportedOnThisPlatform() ? 1 : 0); EXPECT_CALL(delegate_, OnPaymentAppCreated(testing::_)).Times(0); support_->ExpectNoListOfPaymentAppsQuery(); + support_->ExpectNoIsReadyToPayQuery(); factory_.Create(delegate_.GetWeakPtr()); } @@ -146,6 +150,7 @@ EXPECT_CALL(delegate_, OnPaymentAppCreationError(testing::_)).Times(0); EXPECT_CALL(delegate_, OnPaymentAppCreated(testing::_)).Times(0); support_->ExpectQueryListOfPaymentAppsAndRespond({}); + support_->ExpectNoIsReadyToPayQuery(); factory_.Create(delegate_.GetWeakPtr()); } @@ -157,8 +162,83 @@ } // The payment app factory should return the TWA payment app when running in TWA -// mode. -TEST_F(AndroidPaymentAppFactoryTest, FindTheTwaPaymentAppInTwaMode) { +// mode, even when it does not have an IS_READY_TO_PAY service. +TEST_F(AndroidPaymentAppFactoryTest, FindAppsThatDoNotHaveReadyToPayService) { + // Enable invoking Android payment apps on those platforms that support it. + auto scoped_initialization_ = support_->CreateScopedInitialization(); + + EXPECT_CALL(delegate_, GetTwaPackageName()) + .WillRepeatedly(testing::Return("com.example.app")); + EXPECT_CALL(delegate_, OnDoneCreatingPaymentApps()); + + EXPECT_CALL(delegate_, OnPaymentAppCreationError(testing::_)).Times(0); + + EXPECT_CALL(delegate_, + OnPaymentAppCreated(PaymentAppMatches( + PaymentApp::Type::NATIVE_MOBILE_APP, "com.example.app", + "https://play.google.com/billing"))) + .Times(support_->AreAndroidAppsSupportedOnThisPlatform() ? 1 : 0); + + // This app does not have an IS_READY_TO_PAY service. + std::vector<std::unique_ptr<AndroidAppDescription>> apps; + apps.emplace_back(std::make_unique<AndroidAppDescription>()); + apps.back()->package = "com.example.app"; + apps.back()->activities.emplace_back( + std::make_unique<AndroidActivityDescription>()); + apps.back()->activities.back()->name = "com.example.app.Activity"; + apps.back()->activities.back()->default_payment_method = + "https://play.google.com/billing"; + support_->ExpectQueryListOfPaymentAppsAndRespond(std::move(apps)); + + // There is no IS_READY_TO_PAY service to invoke. + support_->ExpectNoIsReadyToPayQuery(); + + factory_.Create(delegate_.GetWeakPtr()); +} + +// The payment app factory should return one payment app and should not query +// the IS_READY_TO_PAY service, because of being off the record. +TEST_F(AndroidPaymentAppFactoryTest, + DoNotQueryReadyToPaySericeWhenOffTheRecord) { + // Enable invoking Android payment apps on those platforms that support it. + auto scoped_initialization_ = support_->CreateScopedInitialization(); + + // Simulate being off the record. + delegate_.set_is_off_the_record(); + + EXPECT_CALL(delegate_, GetTwaPackageName()) + .WillRepeatedly(testing::Return("com.example.app")); + EXPECT_CALL(delegate_, OnDoneCreatingPaymentApps()); + + EXPECT_CALL(delegate_, OnPaymentAppCreationError(testing::_)).Times(0); + + EXPECT_CALL(delegate_, + OnPaymentAppCreated(PaymentAppMatches( + PaymentApp::Type::NATIVE_MOBILE_APP, "com.example.app", + "https://play.google.com/billing"))) + .Times(support_->AreAndroidAppsSupportedOnThisPlatform() ? 1 : 0); + + std::vector<std::unique_ptr<AndroidAppDescription>> apps; + apps.emplace_back(std::make_unique<AndroidAppDescription>()); + apps.back()->package = "com.example.app"; + apps.back()->service_names.push_back("com.example.app.Service"); + apps.back()->activities.emplace_back( + std::make_unique<AndroidActivityDescription>()); + apps.back()->activities.back()->name = "com.example.app.Activity"; + apps.back()->activities.back()->default_payment_method = + "https://play.google.com/billing"; + support_->ExpectQueryListOfPaymentAppsAndRespond(std::move(apps)); + + // The IS_READY_TO_PAY service should not be invoked when off the record. + support_->ExpectNoIsReadyToPayQuery(); + + factory_.Create(delegate_.GetWeakPtr()); +} + +// The payment app factory should return the TWA payment app that returns true +// from IS_READY_TO_PAY service when running in TWA mode. +TEST_F(AndroidPaymentAppFactoryTest, + FindTheTwaPaymentAppThatIsReadyToPayInTwaMode) { // Enable invoking Android payment apps on those platforms that support it. auto scoped_initialization_ = support_->CreateScopedInitialization(); @@ -183,6 +263,34 @@ apps.back()->activities.back()->default_payment_method = "https://play.google.com/billing"; support_->ExpectQueryListOfPaymentAppsAndRespond(std::move(apps)); + support_->ExpectQueryIsReadyToPayAndRespond(/*is_ready_to_pay=*/true); + + factory_.Create(delegate_.GetWeakPtr()); +} + +// The payment app factory should return no payment apps when IS_READY_TO_PAY +// service returns false. +TEST_F(AndroidPaymentAppFactoryTest, IgnoreAppsThatAreNotReadyToPay) { + // Enable invoking Android payment apps on those platforms that support it. + auto scoped_initialization_ = support_->CreateScopedInitialization(); + + EXPECT_CALL(delegate_, GetTwaPackageName()) + .WillRepeatedly(testing::Return("com.example.app")); + EXPECT_CALL(delegate_, OnDoneCreatingPaymentApps()); + EXPECT_CALL(delegate_, OnPaymentAppCreationError(testing::_)).Times(0); + EXPECT_CALL(delegate_, OnPaymentAppCreated(testing::_)).Times(0); + + std::vector<std::unique_ptr<AndroidAppDescription>> apps; + apps.emplace_back(std::make_unique<AndroidAppDescription>()); + apps.back()->package = "com.example.app"; + apps.back()->service_names.push_back("com.example.app.Service"); + apps.back()->activities.emplace_back( + std::make_unique<AndroidActivityDescription>()); + apps.back()->activities.back()->name = "com.example.app.Activity"; + apps.back()->activities.back()->default_payment_method = + "https://play.google.com/billing"; + support_->ExpectQueryListOfPaymentAppsAndRespond(std::move(apps)); + support_->ExpectQueryIsReadyToPayAndRespond(/*is_ready_to_pay=*/false); factory_.Create(delegate_.GetWeakPtr()); } @@ -230,6 +338,7 @@ "https://play.google.com/billing"; support_->ExpectQueryListOfPaymentAppsAndRespond(std::move(apps)); + support_->ExpectQueryIsReadyToPayAndRespond(/*is_ready_to_pay=*/true); factory_.Create(delegate_.GetWeakPtr()); } @@ -256,6 +365,7 @@ apps.back()->activities.back()->default_payment_method = "https://play.google.com/billing"; support_->ExpectQueryListOfPaymentAppsAndRespond(std::move(apps)); + support_->ExpectNoIsReadyToPayQuery(); factory_.Create(delegate_.GetWeakPtr()); } @@ -290,6 +400,7 @@ EXPECT_CALL(delegate_, OnPaymentAppCreationError(testing::_)).Times(0); EXPECT_CALL(delegate_, OnPaymentAppCreated(testing::_)).Times(0); support_->ExpectNoListOfPaymentAppsQuery(); + support_->ExpectNoIsReadyToPayQuery(); factory_.Create(delegate_.GetWeakPtr()); } @@ -316,6 +427,7 @@ apps.back()->activities.back()->default_payment_method = "https://example.test"; support_->ExpectQueryListOfPaymentAppsAndRespond(std::move(apps)); + support_->ExpectNoIsReadyToPayQuery(); factory_.Create(delegate_.GetWeakPtr()); } @@ -359,6 +471,42 @@ "https://example.test"; support_->ExpectQueryListOfPaymentAppsAndRespond(std::move(apps)); + support_->ExpectQueryIsReadyToPayAndRespond(/*is_ready_to_pay=*/true); + + factory_.Create(delegate_.GetWeakPtr()); +} + +// At most one IS_READY_TO_PAY service is allowed in an Android payment app. +TEST_F(AndroidPaymentAppFactoryTest, ReturnErrorWhenMoreThanOneServiceInApp) { + // Enable invoking Android payment apps on those platforms that support it. + auto scoped_initialization_ = support_->CreateScopedInitialization(); + + EXPECT_CALL(delegate_, GetTwaPackageName()) + .WillRepeatedly(testing::Return("com.example.app")); + EXPECT_CALL(delegate_, OnDoneCreatingPaymentApps()); + + EXPECT_CALL(delegate_, OnPaymentAppCreationError( + "Found more than one IS_READY_TO_PAY service, but " + "at most one service is supported.")) + .Times(support_->AreAndroidAppsSupportedOnThisPlatform() ? 1 : 0); + + EXPECT_CALL(delegate_, OnPaymentAppCreated(testing::_)).Times(0); + + std::vector<std::unique_ptr<AndroidAppDescription>> apps; + apps.emplace_back(std::make_unique<AndroidAppDescription>()); + apps.back()->package = "com.example.app"; + + // Two IS_READY_TO_PAY services: + apps.back()->service_names.push_back("com.example.app.ServiceOne"); + apps.back()->service_names.push_back("com.example.app.ServiceTwo"); + + apps.back()->activities.emplace_back( + std::make_unique<AndroidActivityDescription>()); + apps.back()->activities.back()->name = "com.example.app.Activity"; + apps.back()->activities.back()->default_payment_method = + "https://play.google.com/billing"; + support_->ExpectQueryListOfPaymentAppsAndRespond(std::move(apps)); + support_->ExpectNoIsReadyToPayQuery(); factory_.Create(delegate_.GetWeakPtr()); }
diff --git a/components/payments/content/android_payment_app_unittest.cc b/components/payments/content/android_payment_app_unittest.cc index 0b1f445..cb515a0 100644 --- a/components/payments/content/android_payment_app_unittest.cc +++ b/components/payments/content/android_payment_app_unittest.cc
@@ -31,8 +31,9 @@ base::WeakPtr<AndroidAppCommunication> communication) { std::set<std::string> payment_method_names; payment_method_names.insert(methods::kGooglePlayBilling); - std::map<std::string, std::set<std::string>> stringified_method_data; - stringified_method_data[methods::kGooglePlayBilling].insert("{}"); + auto stringified_method_data = + std::make_unique<std::map<std::string, std::set<std::string>>>(); + stringified_method_data->insert({methods::kGooglePlayBilling, {"{}"}}); auto description = std::make_unique<AndroidAppDescription>(); description->package = "com.example.app"; description->service_names.push_back("com.example.app.Service"); @@ -43,7 +44,7 @@ methods::kGooglePlayBilling; return std::make_unique<AndroidPaymentApp>( - payment_method_names, stringified_method_data, + payment_method_names, std::move(stringified_method_data), GURL("https://top-level-origin.com"), GURL("https://payment-request-origin.com"), "payment-request-id", std::move(description), communication);
diff --git a/components/payments/content/payment_app.h b/components/payments/content/payment_app.h index 16bd277..5bb070f 100644 --- a/components/payments/content/payment_app.h +++ b/components/payments/content/payment_app.h
@@ -187,7 +187,7 @@ // Whether this app should be chosen over other available payment apps. For // example, when the Play Billing payment app is available in a TWA. - bool IsPreferred() const; + virtual bool IsPreferred() const; protected: PaymentApp(int icon_resource_id, Type type);
diff --git a/components/payments/content/payment_request.cc b/components/payments/content/payment_request.cc index ae4ae73..7c2f63a0 100644 --- a/components/payments/content/payment_request.cc +++ b/components/payments/content/payment_request.cc
@@ -661,7 +661,9 @@ case PaymentApp::Type::AUTOFILL: selected_event = JourneyLogger::Event::EVENT_SELECTED_CREDIT_CARD; break; - case PaymentApp::Type::SERVICE_WORKER_APP: { + case PaymentApp::Type::SERVICE_WORKER_APP: + // Intentionally fall through. + case PaymentApp::Type::NATIVE_MOBILE_APP: { selected_event = IsGooglePaymentMethod(response->method_name) ? JourneyLogger::Event::EVENT_SELECTED_GOOGLE : JourneyLogger::Event::EVENT_SELECTED_OTHER; @@ -669,8 +671,6 @@ } case PaymentApp::Type::UNDEFINED: // Intentionally fall through. - case PaymentApp::Type::NATIVE_MOBILE_APP: - // Intentionally fall through. case PaymentApp::Type::INTERNAL: NOTREACHED(); break;
diff --git a/components/payments/core/android_app_description.h b/components/payments/core/android_app_description.h index e7f70dfc..4274dba9 100644 --- a/components/payments/core/android_app_description.h +++ b/components/payments/core/android_app_description.h
@@ -5,6 +5,7 @@ #ifndef COMPONENTS_PAYMENTS_CORE_ANDROID_APP_DESCRIPTION_H_ #define COMPONENTS_PAYMENTS_CORE_ANDROID_APP_DESCRIPTION_H_ +#include <memory> #include <string> #include <vector>
diff --git a/components/payments/core/chrome_os_error_strings.cc b/components/payments/core/chrome_os_error_strings.cc index efdc6559..27bdd8c 100644 --- a/components/payments/core/chrome_os_error_strings.cc +++ b/components/payments/core/chrome_os_error_strings.cc
@@ -15,10 +15,6 @@ "Found more than one PAY activity in the Trusted Web Activity, but at most " "one activity is supported."; -const char kMoreThanOneService[] = - "Found more than one IS_READY_TO_PAY service in the Trusted Web Activity, " - "but at most one service is supported."; - const char kMoreThanOneMethodData[] = "At most one payment method specific data is supported.";
diff --git a/components/payments/core/chrome_os_error_strings.h b/components/payments/core/chrome_os_error_strings.h index 45d3252..13c4be4 100644 --- a/components/payments/core/chrome_os_error_strings.h +++ b/components/payments/core/chrome_os_error_strings.h
@@ -20,9 +20,6 @@ // Used when the TWA declares more than one PAY activity. extern const char kMoreThanOneActivity[]; -// Used when the TWA declares more than one IS_READY_TO_PAY service. -extern const char kMoreThanOneService[]; - // Used when the merchant invokes the Trusted Web Activity with more than set of // payment method specific data. extern const char kMoreThanOneMethodData[];
diff --git a/components/payments/core/native_error_strings.cc b/components/payments/core/native_error_strings.cc index ae977250..45991e1 100644 --- a/components/payments/core/native_error_strings.cc +++ b/components/payments/core/native_error_strings.cc
@@ -206,5 +206,9 @@ const char kUserClosedPaymentApp[] = "User closed the payment app."; +const char kMoreThanOneService[] = + "Found more than one IS_READY_TO_PAY service, but at most one service is " + "supported."; + } // namespace errors } // namespace payments
diff --git a/components/payments/core/native_error_strings.h b/components/payments/core/native_error_strings.h index 6f90334..61ede42ec 100644 --- a/components/payments/core/native_error_strings.h +++ b/components/payments/core/native_error_strings.h
@@ -234,6 +234,9 @@ // indicates this by returning Activity.RESULT_CANCELED. extern const char kUserClosedPaymentApp[]; +// Used when an Android app declares more than one IS_READY_TO_PAY service. +extern const char kMoreThanOneService[]; + } // namespace errors } // namespace payments
diff --git a/components/payments/core/payment_request_data_util.cc b/components/payments/core/payment_request_data_util.cc index 5d5049533..b3f8785 100644 --- a/components/payments/core/payment_request_data_util.cc +++ b/components/payments/core/payment_request_data_util.cc
@@ -4,7 +4,7 @@ #include "components/payments/core/payment_request_data_util.h" -#include <memory> +#include <utility> #include "base/stl_util.h" #include "base/strings/string_split.h" @@ -166,13 +166,15 @@ return number; } -std::map<std::string, std::set<std::string>> FilterStringifiedMethodData( +std::unique_ptr<std::map<std::string, std::set<std::string>>> +FilterStringifiedMethodData( const std::map<std::string, std::set<std::string>>& stringified_method_data, const std::set<std::string>& supported_payment_method_names) { - std::map<std::string, std::set<std::string>> result; + auto result = + std::make_unique<std::map<std::string, std::set<std::string>>>(); for (const auto& pair : stringified_method_data) { if (base::Contains(supported_payment_method_names, pair.first)) { - result[pair.first] = pair.second; + result->insert({pair.first, pair.second}); } } return result;
diff --git a/components/payments/core/payment_request_data_util.h b/components/payments/core/payment_request_data_util.h index f8d3c18..bdaaaae2 100644 --- a/components/payments/core/payment_request_data_util.h +++ b/components/payments/core/payment_request_data_util.h
@@ -5,6 +5,7 @@ #ifndef COMPONENTS_PAYMENTS_CORE_PAYMENT_REQUEST_DATA_UTIL_H_ #define COMPONENTS_PAYMENTS_CORE_PAYMENT_REQUEST_DATA_UTIL_H_ +#include <memory> #include <set> #include <string> #include <vector> @@ -77,7 +78,8 @@ // Value: The set of all payment method specific parameters for the given // payment method identifier, each one serialized into a JSON string, // e.g., '{"key": "value"}'. -std::map<std::string, std::set<std::string>> FilterStringifiedMethodData( +std::unique_ptr<std::map<std::string, std::set<std::string>>> +FilterStringifiedMethodData( const std::map<std::string, std::set<std::string>>& stringified_method_data, const std::set<std::string>& supported_payment_method_names);
diff --git a/components/payments/core/payment_request_data_util_unittest.cc b/components/payments/core/payment_request_data_util_unittest.cc index 4ed42179..19f2578 100644 --- a/components/payments/core/payment_request_data_util_unittest.cc +++ b/components/payments/core/payment_request_data_util_unittest.cc
@@ -280,21 +280,21 @@ TEST(PaymentRequestDataUtil, FilterStringifiedMethodData) { std::map<std::string, std::set<std::string>> requested; std::set<std::string> supported; - EXPECT_TRUE(FilterStringifiedMethodData(requested, supported).empty()); + EXPECT_TRUE(FilterStringifiedMethodData(requested, supported)->empty()); requested["a"].insert("{\"b\": \"c\"}"); - EXPECT_TRUE(FilterStringifiedMethodData(requested, supported).empty()); + EXPECT_TRUE(FilterStringifiedMethodData(requested, supported)->empty()); requested["x"].insert("{\"y\": \"z\"}"); - EXPECT_TRUE(FilterStringifiedMethodData(requested, supported).empty()); + EXPECT_TRUE(FilterStringifiedMethodData(requested, supported)->empty()); supported.insert("x"); std::map<std::string, std::set<std::string>> expected; expected["x"].insert("{\"y\": \"z\"}"); - EXPECT_EQ(expected, FilterStringifiedMethodData(requested, supported)); + EXPECT_EQ(expected, *FilterStringifiedMethodData(requested, supported)); supported.insert("g"); - EXPECT_EQ(expected, FilterStringifiedMethodData(requested, supported)); + EXPECT_EQ(expected, *FilterStringifiedMethodData(requested, supported)); } } // namespace data_util
diff --git a/components/performance_manager/v8_memory/v8_per_frame_memory_decorator.cc b/components/performance_manager/v8_memory/v8_per_frame_memory_decorator.cc index 9e44e53..a6a1e6fc 100644 --- a/components/performance_manager/v8_memory/v8_per_frame_memory_decorator.cc +++ b/components/performance_manager/v8_memory/v8_per_frame_memory_decorator.cc
@@ -4,12 +4,13 @@ #include "components/performance_manager/public/v8_memory/v8_per_frame_memory_decorator.h" +#include <algorithm> +#include <iterator> #include <utility> #include <vector> #include "base/bind.h" #include "base/check.h" -#include "base/containers/flat_map.h" #include "base/containers/flat_set.h" #include "base/memory/weak_ptr.h" #include "base/stl_util.h" @@ -47,6 +48,35 @@ namespace { +using PerFrameUsagePtr = blink::mojom::PerFrameV8MemoryUsageDataPtr; + +// Comparator that generates a strict total order of PerFrameUsagePtr's when +// compared by their frame tokens. +struct SortByToken { + constexpr bool operator()(const PerFrameUsagePtr& a, + const PerFrameUsagePtr& b) { + return a->frame_token < b->frame_token; + } + + constexpr bool operator()(const PerFrameUsagePtr& a, + const blink::LocalFrameToken& b) { + return a->frame_token < b.value(); + } +}; + +// Returns the memory used by the main world in a frame. +uint64_t GetMainWorldBytesUsed(const PerFrameUsagePtr& per_frame) { + for (const auto& entry : per_frame->associated_bytes) { + if (entry->world_id == + blink::mojom::V8IsolatedWorldMemoryUsage::kMainWorldId) { + return entry->bytes_used; + } + } + NOTREACHED() << "There should always be data for the main isolated world for " + "each frame."; + return 0ULL; +} + // Forwards the pending receiver to the RenderProcessHost and binds it on the // UI thread. void BindReceiverOnUIThread( @@ -254,53 +284,44 @@ // existing frame is likewise accured to unassociated usage. uint64_t unassociated_v8_bytes_used = result->unassociated_bytes_used; - // Create a mapping from token to per-frame usage for the merge below. - std::vector<std::pair<blink::LocalFrameToken, - blink::mojom::PerFrameV8MemoryUsageDataPtr>> - tmp; - for (auto& entry : result->associated_memory) { - tmp.emplace_back(std::make_pair(blink::LocalFrameToken(entry->frame_token), - std::move(entry))); - } - DCHECK_EQ(tmp.size(), result->associated_memory.size()); - - base::flat_map<blink::LocalFrameToken, - blink::mojom::PerFrameV8MemoryUsageDataPtr> - associated_memory(std::move(tmp)); - // Validate that the frame tokens were all unique. If there are duplicates, - // the map will arbirarily drop all but one record per unique token. - DCHECK_EQ(associated_memory.size(), result->associated_memory.size()); - + // Use a sorted vector (O(NlogN)) + lower_bound (O(logN)) for O(NlogN) + // lookups. + std::sort(result->associated_memory.begin(), result->associated_memory.end(), + SortByToken()); base::flat_set<const FrameNode*> frame_nodes = process_node_->GetFrameNodes(); for (const FrameNode* frame_node : frame_nodes) { - auto it = associated_memory.find(frame_node->GetFrameToken()); - if (it == associated_memory.end()) { + const blink::LocalFrameToken& frame_token = frame_node->GetFrameToken(); + auto it = std::lower_bound(result->associated_memory.begin(), + result->associated_memory.end(), frame_token, + SortByToken()); + if (it == result->associated_memory.end() || + (*it)->frame_token != frame_token.value()) { // No data for this node, clear any data associated with it. NodeAttachedFrameData::Destroy(frame_node); } else { - bool found_main_world = false; + DCHECK(std::next(it) == result->associated_memory.end() || + (*std::next(it))->frame_token != (*it)->frame_token) + << "Duplicate frame tokens found"; + + // TODO(crbug.com/1080672): Where to stash the non-main-world data? NodeAttachedFrameData* frame_data = NodeAttachedFrameData::GetOrCreate(frame_node); - for (const auto& entry : it->second->associated_bytes) { - if (entry->world_id == - blink::mojom::V8IsolatedWorldMemoryUsage::kMainWorldId) { - frame_data->data_available_ = true; - frame_data->data_.set_v8_bytes_used(entry->bytes_used); - found_main_world = true; - } else { - // TODO(crbug.com/1080672): Where to stash the rest of the data? - } - } - // There should always be data for the main isolated world for each frame. - DCHECK(found_main_world); - // Clear this datum as its usage has been consumed. - associated_memory.erase(it); + frame_data->data_available_ = true; + frame_data->data_.set_v8_bytes_used(GetMainWorldBytesUsed(*it)); + + // Zero out this datum as its usage has been consumed. + (*it)->associated_bytes.clear(); } } - for (const auto& it : associated_memory) { + for (const PerFrameUsagePtr& per_frame : result->associated_memory) { + if (per_frame->associated_bytes.empty()) { + // Frame was already consumed. + continue; + } // Accrue the data for non-existent frames to unassociated bytes. - unassociated_v8_bytes_used += it.second->associated_bytes[0]->bytes_used; + // TODO(crbug.com/1080672): Where to stash the non-main-world data? + unassociated_v8_bytes_used += GetMainWorldBytesUsed(per_frame); } data_available_ = true;
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json index fa11993..022d688 100644 --- a/components/policy/resources/policy_templates.json +++ b/components/policy/resources/policy_templates.json
@@ -1706,11 +1706,9 @@ 'id': 11, 'caption': '''Disable saving browser history''', 'tags': [], - 'desc': '''Disables saving browser history in <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> and prevents users from changing this setting. + 'desc': '''Setting the policy to Enabled means browsing history is not saved, tab syncing is off and, and users can't change this setting. - If this setting is enabled, browsing history is not saved. This setting also disables tab syncing. - - If this setting is disabled or not set, browsing history is saved.''', + Setting the policy to Disabled or leaving it unset saves browsing history.''', }, { 'name': 'AllowDeletingBrowserHistory', @@ -2942,23 +2940,17 @@ 'id': 14, 'caption': '''Enable Safe Browsing''', 'tags': ['system-security'], - 'desc': '''This policy is deprecated in M83, please use SafeBrowsingProtectionLevel instead. + 'desc': '''This policy is deprecated in <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> 83, please use <ph name="SAFE_BROWSING_PROTECTION_LEVEL_POLICY_NAME">SafeBrowsingProtectionLevel</ph> instead. - Enables <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph>'s Safe Browsing feature and prevents users from changing this setting. + Setting the policy to Enabled keeps Chrome's Safe Browsing feature on. Setting the policy to Disabled keeps Safe Browsing off. - If you enable this setting, Safe Browsing is always active. + If you set this policy, users can't change it or override the "Enable phishing and malware protection" setting in Chrome. If not set, "Enable phishing and malware protection" is set to True, but the user can change it. - If you disable this setting, Safe Browsing is never active. + See more about Safe Browsing ( https://developers.google.com/safe-browsing ). - If you enable or disable this setting, users cannot change or override the "Enable phishing and malware protection" setting in <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph>. + If the policy <ph name="SAFE_BROWSING_PROTECTION_LEVEL_POLICY_NAME">SafeBrowsingProtectionLevel</ph> is set, the value of the policy <ph name="SAFE_BROWSING_ENABLED_POLICY_NAME">SafeBrowsingEnabled</ph> is ignored. - If this policy is left not set, this will be enabled but the user will be able to change it. - - See https://developers.google.com/safe-browsing for more info on Safe Browsing. - - If the policy SafeBrowsingProtectionLevel is set, the value of the policy SafeBrowsingEnabled is ignored. - - This policy is available only on Windows instances that are joined to a <ph name="MS_AD_NAME">Microsoft® Active Directory®</ph> domain. or Windows 10 Pro or Enterprise instances that enrolled for device management and macOS instances that are that are managed via MDM or joined to a domain via MCX.''', + On <ph name="MS_WIN_NAME">Microsoft® Windows®</ph>, this functionality is only available on instances that are joined to a <ph name="MS_AD_NAME">Microsoft® Active Directory®</ph> domain, running on Windows 10 Pro, or enrolled in <ph name="CHROME_BROWSER_CLOUSE_MANAGEMENT_NAME">Chrome Browser Cloud Management</ph>. On <ph name="MAC_OS_NAME">macOS</ph>, this functionality is only available on instances that are managed via MDM, or joined to a domain via MCX.''', }, { 'name': 'SafeBrowsingProtectionLevel', @@ -3741,15 +3733,13 @@ 'id': 375, 'caption': '''Enable Safe Browsing for trusted sources''', 'tags': ['local-data-access'], - 'desc': '''Identify if <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> can allow download without Safe Browsing checks when it's from a trusted source. + 'desc': '''Setting the policy to Enabled or leaving it unset means downloaded files are sent to be analyzed by Safe Browsing, even when it's from a trusted source. - When False, downloaded files will not be sent to be analyzed by Safe Browsing when it's from a trusted source. + Setting the policy to Disabled means downloaded files won't be sent to be analyzed by Safe Browsing when it's from a trusted source. - When not set (or set to True), downloaded files are sent to be analyzed by Safe Browsing, even when it's from a trusted source. + These restrictions apply to downloads triggered from webpage content, as well as the Download link menu option. These restrictions don't apply to the save or download of the currently displayed page or to saving as PDF from the printing options. - Note that these restrictions apply to downloads triggered from web page content, as well as the 'download link...' context menu option. These restrictions do not apply to the save / download of the currently displayed page, nor does it apply to saving as PDF from the printing options. - - This policy is available only on Windows instances that are joined to a <ph name="MS_AD_NAME">Microsoft® Active Directory®</ph> domain. or Windows 10 Pro or Enterprise instances that enrolled for device management and macOS instances that are that are managed via MDM or joined to a domain via MCX.''', + On <ph name="MS_WIN_NAME">Microsoft® Windows®</ph>, this functionality is only available on instances that are joined to a <ph name="MS_AD_NAME">Microsoft® Active Directory®</ph> domain, running on Windows 10 Pro, or enrolled in <ph name="CHROME_BROWSER_CLOUSE_MANAGEMENT_NAME">Chrome Browser Cloud Management</ph>. On <ph name="MAC_OS_NAME">macOS</ph>, this functionality is only available on instances that are managed via MDM, or joined to a domain via MCX.''', 'label': '''Safe Browsing enable state for trusted sources''', }, { @@ -4455,7 +4445,7 @@ On <ph name="MS_WIN_NAME">Microsoft® Windows®</ph> instances, apps and extensions from outside the Chrome Web Store can only be forced installed if the instance is joined to a <ph name="MS_AD_NAME">Microsoft® Active Directory®</ph> domain, running on Windows 10 Pro, or enrolled in Chrome Browser Cloud Management. - On <ph name="MAC_OS_NAME">macOS</ph> instances, apps and extensions from outside the Chrome Web Store can only can only be force installed if the instance is managed via MDM, or joined to a domain via MCX. + On <ph name="MAC_OS_NAME">macOS</ph> instances, apps and extensions from outside the Chrome Web Store can only be force installed if the instance is managed via MDM, or joined to a domain via MCX. The source code of any extension may be altered by users through developer tools, potentially rendering the extension dysfunctional. If this is a concern, set the <ph name="DEVELOPER_TOOLS_DISABLED_POLICY_NAME">DeveloperToolsDisabled</ph> policy. @@ -17184,14 +17174,19 @@ 'id': 411, 'caption': '''Password protection warning trigger''', 'tags': [], - 'desc': '''Allows you to control the triggering of password protection warning. Password protection alerts users when they reuse their protected password on potentially suspicious sites. + 'desc': '''Setting the policy lets you control the triggering of password protection warning. Password protection alerts users when they reuse their protected password on potentially suspicious sites. - You can use 'PasswordProtectionLoginURLs' and 'PasswordProtectionChangePasswordURL' policies to configure which password to protect. + Use <ph name="PASSWORD_PROTECTION_LOGIN_URLS_POLICY_NAME">PasswordProtectionLoginURLs</ph> and <ph name="PASSWORD_PROTECTION_CHANGE_PASSWORD_URL_POLICY_NAME">PasswordProtectionChangePasswordURL</ph> to set which password to protect. - If this policy is set to 'PasswordProtectionWarningOff', no password protection warning will be shown. - If this policy is set to 'PasswordProtectionWarningOnPasswordReuse', password protection warning will be shown when the user reuses their protected password on a non-whitelisted site. - If this policy is set to 'PasswordProtectionWarningOnPhishingReuse', password protection warning will be shown when the user reuses their protected password on a phishing site. - If this policy is left unset, password protection service will only protect Google passwords but the user will be able to change this setting.''', + If this policy is set to: + + * PasswordProtectionWarningOff, no password protection warning will be shown. + + * PasswordProtectionWarningOnPasswordReuse, password protection warning will be shown when the user reuses their protected password on a non-whitelisted site. + + * PasswordProtectionWarningOnPhishingReuse, password protection warning will be shown when the user reuses their protected password on a phishing site. + + Leaving the policy unset has the password protection service only protect Google passwords, but users can change this setting.''', }, { 'id': 419, @@ -17529,15 +17524,11 @@ 'tags': [], 'desc': '''This policy is deprecated, please use <ph name="SAFE_BROWSING_ALLOWLIST_DOMAINS_POLICY_NAME">SafeBrowsingAllowlistDomains</ph> instead. - Configure the list of domains which Safe Browsing will trust. This means: - Safe Browsing will not check for dangerous resources (e.g. phishing, malware, or unwanted software) if their URLs match these domains. - Safe Browsing's download protection service will not check downloads hosted on these domains. - Safe Browsing's password protection service will not check for password reuse if the page URL matches these domains. + Setting the policy to Enabled means Safe Browsing will trust the domains you designate. It won't check them for dangerous resources such as phishing, malware, or unwanted software. Safe Browsing's download protection service won't check downloads hosted on these domains. Its password protection service won't check for password reuse. - If this setting is enabled, then Safe Browsing will trust these domains. - If this setting is disabled or not set, then default Safe Browsing protection is applied to all resources. + Setting the policy to Disabled or leaving it unset means default Safe Browsing protection applies to all resources. - This policy is available only on Windows instances that are joined to a <ph name="MS_AD_NAME">Microsoft® Active Directory®</ph> domain. or Windows 10 Pro or Enterprise instances that enrolled for device management and macOS instances that are that are managed via MDM or joined to a domain via MCX.''', + On <ph name="MS_WIN_NAME">Microsoft® Windows®</ph>, this functionality is only available on instances that are joined to a <ph name="MS_AD_NAME">Microsoft® Active Directory®</ph> domain, running on Windows 10 Pro, or enrolled in <ph name="CHROME_BROWSER_CLOUSE_MANAGEMENT_NAME">Chrome Browser Cloud Management</ph>. On <ph name="MAC_OS_NAME">macOS</ph>, this functionality is only available on instances that are managed via MDM, or joined to a domain via MCX.''', }, { 'name': 'SafeBrowsingAllowlistDomains', @@ -17556,15 +17547,11 @@ 'id': 732, 'caption': '''Configure the list of domains on which Safe Browsing will not trigger warnings.''', 'tags': [], - 'desc': '''Configure the list of domains which Safe Browsing will trust. This means: - Safe Browsing will not check for dangerous resources (e.g. phishing, malware, or unwanted software) if their URLs match these domains. - Safe Browsing's download protection service will not check downloads hosted on these domains. - Safe Browsing's password protection service will not check for password reuse if the page URL matches these domains. + 'desc': '''Setting the policy to Enabled means Safe Browsing will trust the domains you designate. It won't check them for dangerous resources such as phishing, malware, or unwanted software. Safe Browsing's download protection service won't check downloads hosted on these domains. Its password protection service won't check for password reuse. - If this setting is enabled, then Safe Browsing will trust these domains. - If this setting is disabled or not set, then default Safe Browsing protection is applied to all resources. + Setting the policy to Disabled or leaving it unset means default Safe Browsing protection applies to all resources. - On <ph name="MS_WIN_NAME">Microsoft® Windows®</ph>, this functionality is only available on instances that are joined to a <ph name="MS_AD_NAME">Microsoft® Active Directory®</ph> domain, running on Windows 10 Pro, or enrolled in Chrome Browser Cloud Management. On <ph name="MAC_OS_NAME">macOS</ph>, this functionality is only available on instances that are managed via MDM, or joined to a domain via MCX.''', + On <ph name="MS_WIN_NAME">Microsoft® Windows®</ph>, this functionality is only available on instances that are joined to a <ph name="MS_AD_NAME">Microsoft® Active Directory®</ph> domain, running on Windows 10 Pro, or enrolled in <ph name="CHROME_BROWSER_CLOUSE_MANAGEMENT_NAME">Chrome Browser Cloud Management</ph>. On <ph name="MAC_OS_NAME">macOS</ph>, this functionality is only available on instances that are managed via MDM, or joined to a domain via MCX.''', }, { 'name': 'PasswordProtectionLoginURLs', @@ -17583,13 +17570,11 @@ 'id': 423, 'caption': '''Configure the list of enterprise login URLs where password protection service should capture salted hashes of passwords.''', 'tags': [], - 'desc': '''Configure the list of enterprise login URLs (HTTP and HTTPS schemes only). Password protection service will capture salted hashes of passwords on these URLs and use them for password reuse detection. - In order for <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> to correctly capture password salted hashes, please make sure your login pages follow the guidelines on https://www.chromium.org/developers/design-documents/create-amazing-password-forms. + 'desc': '''Setting the policy sets the list of enterprise login URLs (HTTP and HTTPS protocols only). Password protection service will capture salted hashes of passwords on these URLs and use them for password reuse detection. For <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> to correctly capture password salted hashes, ensure your sign-in pages follow these guidelines ( https://www.chromium.org/developers/design-documents/create-amazing-password-forms ). - If this setting is enabled, then password protection service will capture salted hashes of password on these URLs for password reuse detection purpose. - If this setting is disabled or not set, then password protection service will only capture password salted hashes on https://accounts.google.com. + Turning this setting off or leaving it unset means the password protection service only captures the password salted hashes on https://accounts.google.com. - This policy is available only on Windows instances that are joined to a <ph name="MS_AD_NAME">Microsoft® Active Directory®</ph> domain. or Windows 10 Pro or Enterprise instances that enrolled for device management and macOS instances that are that are managed via MDM or joined to a domain via MCX.''', + On <ph name="MS_WIN_NAME">Microsoft® Windows®</ph>, this functionality is only available on instances that are joined to a <ph name="MS_AD_NAME">Microsoft® Active Directory®</ph> domain, running on Windows 10 Pro, or enrolled in <ph name="CHROME_BROWSER_CLOUSE_MANAGEMENT_NAME">Chrome Browser Cloud Management</ph>. On <ph name="MAC_OS_NAME">macOS</ph>, this functionality is only available on instances that are managed via MDM, or joined to a domain via MCX.''', }, { 'name': 'PasswordProtectionChangePasswordURL', @@ -17605,13 +17590,11 @@ 'id': 424, 'caption': '''Configure the change password URL.''', 'tags': [], - 'desc': '''Configure the change password URL (HTTP and HTTPS schemes only). Password protection service will send users to this URL to change their password after seeing a warning in the browser. - In order for <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> to correctly capture the salted hash of the new password on this change password page, please make sure your change password page follows the guidelines on https://www.chromium.org/developers/design-documents/create-amazing-password-forms. + 'desc': '''Setting the policy sets the URL for users to change their password after seeing a warning in the browser. The password protection service sends users to the URL (HTTP and HTTPS protocols only) you designate through this policy. For <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> to correctly capture the salted hash of the new password on this change password page, make sure your change password page follows these guidelines ( https://www.chromium.org/developers/design-documents/create-amazing-password-forms ). - If this setting is enabled, then password protection service will send users to this URL to change their password after seeing a warning in the browser. - If this setting is disabled or not set, then password protection service will send users to https://myaccount.google.com to change their password. + Turning the policy off or leaving it unset means the service sends users to https://myaccount.google.com to change their password. - This policy is available only on Windows instances that are joined to a <ph name="MS_AD_NAME">Microsoft® Active Directory®</ph> domain. or Windows 10 Pro or Enterprise instances that enrolled for device management and macOS instances that are that are managed via MDM or joined to a domain via MCX.''', + On <ph name="MS_WIN_NAME">Microsoft® Windows®</ph>, this functionality is only available on instances that are joined to a <ph name="MS_AD_NAME">Microsoft® Active Directory®</ph> domain, running on Windows 10 Pro, or enrolled in <ph name="CHROME_BROWSER_CLOUSE_MANAGEMENT_NAME">Chrome Browser Cloud Management</ph>. On <ph name="MAC_OS_NAME">macOS</ph>, this functionality is only available on instances that are managed via MDM, or joined to a domain via MCX.''', }, { 'name': 'SafeBrowsingExtendedReportingEnabled', @@ -17627,19 +17610,13 @@ 'id': 429, 'tags': ['google-sharing'], 'caption': '''Enable Safe Browsing Extended Reporting''', - 'desc': '''Enables <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph>'s Safe Browsing Extended Reporting and prevents users from changing this setting. + 'desc': '''Setting the policy to Enabled turns on <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph>'s Safe Browsing Extended Reporting, which sends some system information and page content to Google servers to help detect dangerous apps and sites. - Extended Reporting sends some system information and page content to Google servers to help detect dangerous apps and sites. + Setting the policy to Disabled means reports are never sent. - If the setting is set to true, then reports will be created and sent whenever necessary (such as when a security interstitial is shown). + If you set this policy, users can't change it. If not set, users can decide whether to send reports or not. - If the setting is set to false, reports will never be sent. - - If this policy is set to true or false, the user will not be able to modify the setting. - - If this policy is left unset, the user will be able to change the setting and decide whether to send reports or not. - - See https://developers.google.com/safe-browsing for more info on Safe Browsing.''', + See more about Safe Browsing ( https://developers.google.com/safe-browsing ).''', }, { 'name': 'MachineLevelUserCloudPolicyEnrollmentToken', @@ -18419,12 +18396,13 @@ 'caption': '''Control SafeSites adult content filtering.''', 'tags': ['filtering', 'google-sharing'], 'desc': - '''This policy controls the application of the SafeSites URL filter. - This filter uses the Google Safe Search API to classify URLs as pornographic or not. + '''Setting the policy controls the SafeSites URL filter, which uses the Google Safe Search API to classify URLs as pornographic or not. - When this policy is not configured or set to "Do not filter sites for adult content", sites will not be filtered. + When this policy is set to: - When this policy is set to "Filter top level sites for adult content", sites classified as pornographic will be filtered.''', + * Do not filter sites for adult content, or not set, sites aren't filtered + + * Filter top level sites for adult content, pornographic sites are filtered''', }, { 'name': 'OverrideSecurityRestrictionsOnInsecureOrigin', @@ -18444,28 +18422,11 @@ 'caption': '''Origins or hostname patterns for which restrictions on insecure origins should not apply''', 'tags': ['system-security'], - 'desc': ''' - The policy specifies a list of origins (URLs) or hostname patterns (such - as "*.example.com") for which security restrictions on insecure origins - will not apply. + 'desc': '''Setting the policy specifies a list of origins (URLs) or hostname patterns (such as *.example.com) for which security restrictions on insecure origins won't apply. Organizations can set whitelist origins for legacy applications that can't deploy TLS or set up a staging server for internal web development, so developers can test out features requiring secure contexts without having to deploy TLS on the staging server. This policy also prevents the origin from being labeled "Not Secure" in the address bar. - The intent is to allow organizations to set whitelist origins for legacy - applications that cannot deploy TLS, or to set up a staging server for - internal web development so that their developers can test out features - requiring secure contexts without having to deploy TLS on the staging - server. This policy will also prevent the origin from being labeled - "Not Secure" in the omnibox. + Setting a list of URLs in this policy amounts to setting the command-line flag --unsafely-treat-insecure-origin-as-secure to a comma-separated list of the same URLs. The policy overrides the command-line flag and UnsafelyTreatInsecureOriginAsSecure, if present. - Setting a list of URLs in this policy has the same effect as setting the - command-line flag '--unsafely-treat-insecure-origin-as-secure' to a - comma-separated list of the same URLs. If the policy is set, it will - override the command-line flag. - - This policy will override UnsafelyTreatInsecureOriginAsSecure, if present. - - For more information on secure contexts, see - https://www.w3.org/TR/secure-contexts/. - ''' + For more information on secure contexts, see Secure Contexts ( https://www.w3.org/TR/secure-contexts ).''' }, { 'name': 'DeviceUpdateStagingSchedule',
diff --git a/components/policy/tools/template_writers/writers/ios_app_config_writer.py b/components/policy/tools/template_writers/writers/ios_app_config_writer.py index f82ee54..2018c7aa 100755 --- a/components/policy/tools/template_writers/writers/ios_app_config_writer.py +++ b/components/policy/tools/template_writers/writers/ios_app_config_writer.py
@@ -19,6 +19,10 @@ '''Simple writer that writes app_config.xml files. ''' + def IsFuturePolicySupported(self, policy): + # For now, include all future policies in appconfig.xml. + return True + def CreateDocument(self): dom_impl = minidom.getDOMImplementation('') return dom_impl.createDocument('http://www.w3.org/2001/XMLSchema-instance', @@ -41,7 +45,13 @@ def WritePolicy(self, policy): element_type = self.policy_type_to_xml_tag[policy['type']] if element_type: - self.AddElement(self._policies, element_type, {'keyName': policy['name']}) + attributes = {'keyName': policy['name']} + # Add a "future=true" attribute for future policies. + if 'future_on' in policy: + for config in policy['future_on']: + if config['platform'] == 'ios': + attributes['future'] = 'true' + self.AddElement(self._policies, element_type, attributes) def Init(self): self._doc = self.CreateDocument()
diff --git a/components/policy/tools/template_writers/writers/ios_app_config_writer_unittest.py b/components/policy/tools/template_writers/writers/ios_app_config_writer_unittest.py index df741e3..d609a347 100755 --- a/components/policy/tools/template_writers/writers/ios_app_config_writer_unittest.py +++ b/components/policy/tools/template_writers/writers/ios_app_config_writer_unittest.py
@@ -16,14 +16,20 @@ class IOSAppConfigWriterUnitTests(writer_unittest_common.WriterUnittestCommon): '''Unit tests for IOSAppConfigWriter.''' - def _GetTestPolicyTemplate(self, policy_name, policy_type): + def _GetTestPolicyTemplate(self, policy_name, policy_type, future=False): + supported_or_future = '' + if future: + supported_or_future = ''''future_on':['ios']''' + else: + supported_or_future = ''''supported_on':['ios:80-']''' + return ''' { 'policy_definitions': [ { 'name': '%s', 'type': '%s', - 'supported_on':['ios:80-'], + %s, 'caption': '', 'desc': '', 'items': [{ @@ -37,7 +43,7 @@ 'placeholders': [], 'messages': {}, } -''' % (policy_name, policy_type) +''' % (policy_name, policy_type, supported_or_future) def _GetExpectedOutput(self, version, tag): if tag: @@ -135,6 +141,30 @@ }, 'ios_app_config') self.assertEquals(output.strip(), expected.strip()) + def testFuturePolicy(self): + policy_json = self._GetTestPolicyTemplate('FuturePolicy', + 'string', + future=True) + expected = self._GetExpectedOutput( + '83.0.4089.0', '<string future="true" keyName="FuturePolicy"/>') + output = self.GetOutput(policy_json, { + '_google_chrome': '1', + 'version': '83.0.4089.0' + }, 'ios_app_config') + self.assertEquals(output.strip(), expected.strip()) + + def testNonFuturePolicy(self): + policy_json = self._GetTestPolicyTemplate('NonFuturePolicy', + 'string', + future=False) + expected = self._GetExpectedOutput('83.0.4089.0', + '<string keyName="NonFuturePolicy"/>') + output = self.GetOutput(policy_json, { + '_google_chrome': '1', + 'version': '83.0.4089.0' + }, 'ios_app_config') + self.assertEquals(output.strip(), expected.strip()) + if __name__ == '__main__': unittest.main()
diff --git a/components/signin/OWNERS b/components/signin/OWNERS index 837b6f4..26af5a6 100644 --- a/components/signin/OWNERS +++ b/components/signin/OWNERS
@@ -4,5 +4,8 @@ msarda@chromium.org sdefresne@chromium.org +# For android related change +per-file *android*=aliceywang@chromium.org + # TEAM: chrome-signin@chromium.org # COMPONENT: Services>SignIn
diff --git a/components/signin/public/identity_manager/identity_test_utils.cc b/components/signin/public/identity_manager/identity_test_utils.cc index f179eea..69867756 100644 --- a/components/signin/public/identity_manager/identity_test_utils.cc +++ b/components/signin/public/identity_manager/identity_test_utils.cc
@@ -304,11 +304,8 @@ identity_manager->GetChromeOSAccountManager(), #endif identity_manager, account_id, - // TODO(crbug.com/1115075): set the same token_value on all platforms. token_value.empty() ? "refresh_token_for_" + account_id.ToString() -#if defined(OS_CHROMEOS) + "_" + base::GenerateGUID() -#endif : token_value); }
diff --git a/components/sync/BUILD.gn b/components/sync/BUILD.gn index 46b56488..abbe13b 100644 --- a/components/sync/BUILD.gn +++ b/components/sync/BUILD.gn
@@ -521,6 +521,7 @@ "protocol/proto_enum_conversions_unittest.cc", "protocol/proto_value_conversions_unittest.cc", "trusted_vault/securebox_unittest.cc", + "trusted_vault/standalone_trusted_vault_backend_unittest.cc", "trusted_vault/standalone_trusted_vault_client_unittest.cc", ]
diff --git a/components/sync/driver/sync_driver_switches.cc b/components/sync/driver/sync_driver_switches.cc index 5d3d3ed..b5e2c18 100644 --- a/components/sync/driver/sync_driver_switches.cc +++ b/components/sync/driver/sync_driver_switches.cc
@@ -61,4 +61,9 @@ const base::Feature kDecoupleSyncFromAndroidMasterSync{ "DecoupleSyncFromAndroidMasterSync", base::FEATURE_DISABLED_BY_DEFAULT}; +// Allows trusted vault implementation to follow key rotation (including device +// registration). +const base::Feature kFollowTrustedVaultKeyRotation{ + "FollowTrustedVaultKeyRotation", base::FEATURE_DISABLED_BY_DEFAULT}; + } // namespace switches
diff --git a/components/sync/driver/sync_driver_switches.h b/components/sync/driver/sync_driver_switches.h index 9fd873b4..0c572e6 100644 --- a/components/sync/driver/sync_driver_switches.h +++ b/components/sync/driver/sync_driver_switches.h
@@ -31,6 +31,7 @@ extern const base::Feature kSyncWifiConfigurations; extern const base::Feature kSyncDeviceInfoInTransportMode; extern const base::Feature kDecoupleSyncFromAndroidMasterSync; +extern const base::Feature kFollowTrustedVaultKeyRotation; } // namespace switches
diff --git a/components/sync/protocol/local_trusted_vault.proto b/components/sync/protocol/local_trusted_vault.proto index a4b4473..11fda3af 100644 --- a/components/sync/protocol/local_trusted_vault.proto +++ b/components/sync/protocol/local_trusted_vault.proto
@@ -13,15 +13,32 @@ optional bytes key_material = 1; } +message LocalDeviceRegistrationInfo { + // Private SecureBox key. + optional bytes private_key_material = 1; + + // Indicates whether device is registered, i.e. whether its public key is + // successfully submitted to the server. + optional bool device_registered = 2; +} + message LocalTrustedVaultPerUser { // User identifier. optional bytes gaia_id = 1; // All keys known for a user. - repeated LocalTrustedVaultKey key = 2; + repeated LocalTrustedVaultKey vault_key = 2; - // The version corresponding to the last element in |key|. - optional int32 last_key_version = 3; + // The version corresponding to the last element in |vault_key|. + optional int32 last_vault_key_version = 3; + + // Indicates whether |vault_key| is stale, i.e. that the latest locally + // available key isn't the latest key in the vault. New keys need to be + // fetched through key retrieval procedure or by following key rotation. + optional bool keys_are_stale = 4; + + // Device key and corresponding registration metadata. + optional LocalDeviceRegistrationInfo local_device_registration_info = 5; } message LocalTrustedVault {
diff --git a/components/sync/trusted_vault/BUILD.gn b/components/sync/trusted_vault/BUILD.gn index dba1ba7..439dd59e 100644 --- a/components/sync/trusted_vault/BUILD.gn +++ b/components/sync/trusted_vault/BUILD.gn
@@ -10,6 +10,10 @@ "standalone_trusted_vault_backend.h", "standalone_trusted_vault_client.cc", "standalone_trusted_vault_client.h", + "trusted_vault_access_token_fetcher.h", + "trusted_vault_connection.h", + "trusted_vault_connection_impl.cc", + "trusted_vault_connection_impl.h", ] public_deps = [ "//base", @@ -20,6 +24,7 @@ "//components/signin/public/identity_manager", "//components/sync/protocol", "//crypto", + "//services/network/public/cpp:cpp", "//third_party/boringssl", ] }
diff --git a/components/sync/trusted_vault/DEPS b/components/sync/trusted_vault/DEPS index dd50494..02411ed6 100644 --- a/components/sync/trusted_vault/DEPS +++ b/components/sync/trusted_vault/DEPS
@@ -4,5 +4,6 @@ "+components/sync/driver", "+components/sync/protocol", "+crypto", + "+services/network/public", "+third_party/boringssl", ] \ No newline at end of file
diff --git a/components/sync/trusted_vault/standalone_trusted_vault_backend.cc b/components/sync/trusted_vault/standalone_trusted_vault_backend.cc index 17000c58c..86410f2 100644 --- a/components/sync/trusted_vault/standalone_trusted_vault_backend.cc +++ b/components/sync/trusted_vault/standalone_trusted_vault_backend.cc
@@ -4,12 +4,17 @@ #include "components/sync/trusted_vault/standalone_trusted_vault_backend.h" +#include <memory> +#include <utility> + +#include "base/containers/span.h" #include "base/files/file_util.h" #include "base/files/important_file_writer.h" #include "base/logging.h" #include "base/sequence_checker.h" #include "components/os_crypt/os_crypt.h" -#include "components/signin/public/identity_manager/account_info.h" +#include "components/sync/driver/sync_driver_switches.h" +#include "components/sync/trusted_vault/securebox.h" namespace syncer { @@ -44,8 +49,11 @@ } // namespace StandaloneTrustedVaultBackend::StandaloneTrustedVaultBackend( - const base::FilePath& file_path) - : file_path_(file_path) {} + const base::FilePath& file_path, + std::unique_ptr<TrustedVaultConnection> connection) + : file_path_(file_path), connection_(std::move(connection)) {} + +StandaloneTrustedVaultBackend::~StandaloneTrustedVaultBackend() = default; void StandaloneTrustedVaultBackend::ReadDataFromDisk() { data_ = ReadEncryptedFile(file_path_); @@ -58,7 +66,8 @@ std::vector<std::vector<uint8_t>> keys; if (per_user_vault) { - for (const sync_pb::LocalTrustedVaultKey& key : per_user_vault->key()) { + for (const sync_pb::LocalTrustedVaultKey& key : + per_user_vault->vault_key()) { const std::string& key_material = key.key_material(); keys.emplace_back(key_material.begin(), key_material.end()); } @@ -79,18 +88,133 @@ } // Replace all keys. - per_user_vault->set_last_key_version(last_key_version); - per_user_vault->clear_key(); + per_user_vault->set_last_vault_key_version(last_key_version); + per_user_vault->set_keys_are_stale(false); + per_user_vault->clear_vault_key(); for (const std::vector<uint8_t>& key : keys) { - per_user_vault->add_key()->set_key_material(key.data(), key.size()); + per_user_vault->add_vault_key()->set_key_material(key.data(), key.size()); } WriteToDisk(data_, file_path_); + MaybeRegisterDevice(gaia_id); } void StandaloneTrustedVaultBackend::RemoveAllStoredKeys() { base::DeleteFile(file_path_); data_.Clear(); + weak_factory_for_connection_.InvalidateWeakPtrs(); +} + +void StandaloneTrustedVaultBackend::SetSyncingAccount( + const base::Optional<CoreAccountInfo>& syncing_account) { + if (syncing_account == syncing_account_) { + return; + } + syncing_account_ = syncing_account; + weak_factory_for_connection_.InvalidateWeakPtrs(); + if (syncing_account_.has_value()) { + MaybeRegisterDevice(syncing_account_->gaia); + } +} + +sync_pb::LocalDeviceRegistrationInfo +StandaloneTrustedVaultBackend::GetDeviceRegistrationInfoForTesting( + const std::string& gaia_id) { + sync_pb::LocalTrustedVaultPerUser* per_user_vault = FindUserVault(gaia_id); + if (!per_user_vault) { + return sync_pb::LocalDeviceRegistrationInfo(); + } + return per_user_vault->local_device_registration_info(); +} + +void StandaloneTrustedVaultBackend::MaybeRegisterDevice( + const std::string& gaia_id) { + if (!base::FeatureList::IsEnabled(switches::kFollowTrustedVaultKeyRotation)) { + return; + } + if (!syncing_account_.has_value() || syncing_account_->gaia != gaia_id) { + // Device registration is supported only for |syncing_account_|. + return; + } + sync_pb::LocalTrustedVaultPerUser* per_user_vault = FindUserVault(gaia_id); + if (!per_user_vault || per_user_vault->vault_key_size() == 0 || + per_user_vault->keys_are_stale()) { + // Fresh vault key is required to register the device. + return; + } + if (per_user_vault->local_device_registration_info().device_registered()) { + // Device is already registered. + return; + } + // TODO(crbug.com/1102340): add throttling mechanism. + + std::unique_ptr<SecureBoxKeyPair> key_pair; + if (per_user_vault->has_local_device_registration_info()) { + key_pair = SecureBoxKeyPair::CreateByPrivateKeyImport(base::as_bytes( + base::make_span(per_user_vault->local_device_registration_info() + .private_key_material()))); + if (!key_pair) { + // Device key is corrupted. + // TODO(crbug.com/1102340): consider generation of new key in this case. + return; + } + } else { + key_pair = SecureBoxKeyPair::GenerateRandom(); + // It's possible that device will be successfully registered, but the client + // won't persist this state (for example response doesn't reach the client + // or registration callback is cancelled). To avoid duplicated registrations + // device key is stored before sending the registration request, so the same + // key will be used for future registration attempts. + std::vector<uint8_t> serialized_private_key = + key_pair->private_key().ExportToBytes(); + per_user_vault->mutable_local_device_registration_info() + ->set_private_key_material(serialized_private_key.data(), + serialized_private_key.size()); + WriteToDisk(data_, file_path_); + } + + std::string last_key = per_user_vault->vault_key() + .at(per_user_vault->vault_key_size() - 1) + .key_material(); + std::vector<uint8_t> last_key_bytes(last_key.begin(), last_key.end()); + + // Cancel existing callbacks passed to |connection_| to ensure there is only + // one ongoing request. + weak_factory_for_connection_.InvalidateWeakPtrs(); + connection_->RegisterDevice( + *syncing_account_, last_key_bytes, + per_user_vault->last_vault_key_version(), key_pair->public_key(), + base::BindOnce(&StandaloneTrustedVaultBackend::OnDeviceRegistered, + weak_factory_for_connection_.GetWeakPtr(), gaia_id)); +} + +void StandaloneTrustedVaultBackend::OnDeviceRegistered( + const std::string& gaia_id, + TrustedVaultRequestStatus status) { + // If |syncing_account_| was changed meanwhile, this callback must be + // cancelled. + DCHECK(syncing_account_ && syncing_account_->gaia == gaia_id); + + sync_pb::LocalTrustedVaultPerUser* per_user_vault = FindUserVault(gaia_id); + DCHECK(per_user_vault); + + switch (status) { + case TrustedVaultRequestStatus::kSuccess: + // TODO(crbug.com/1102340): we may want to immediately fetch fresh keys + // (in case they were marked as stale while the request was in flight). + per_user_vault->mutable_local_device_registration_info() + ->set_device_registered(true); + WriteToDisk(data_, file_path_); + return; + case TrustedVaultRequestStatus::kLocalDataObsolete: + per_user_vault->set_keys_are_stale(true); + return; + case TrustedVaultRequestStatus::kOtherError: + // TODO(crbug.com/1102340): prevent future queries until browser restart? + // TODO(crbug.com/1102340): introduce throttling mechanism across browser + // restarts? + return; + } } sync_pb::LocalTrustedVaultPerUser* StandaloneTrustedVaultBackend::FindUserVault(
diff --git a/components/sync/trusted_vault/standalone_trusted_vault_backend.h b/components/sync/trusted_vault/standalone_trusted_vault_backend.h index ddbd4e5c..1922022 100644 --- a/components/sync/trusted_vault/standalone_trusted_vault_backend.h +++ b/components/sync/trusted_vault/standalone_trusted_vault_backend.h
@@ -6,14 +6,17 @@ #define COMPONENTS_SYNC_TRUSTED_VAULT_STANDALONE_TRUSTED_VAULT_BACKEND_H_ #include <cstdint> +#include <map> +#include <memory> #include <string> #include <vector> #include "base/files/file_path.h" #include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" +#include "components/signin/public/identity_manager/account_info.h" #include "components/sync/protocol/local_trusted_vault.pb.h" - -struct CoreAccountInfo; +#include "components/sync/trusted_vault/trusted_vault_connection.h" namespace syncer { @@ -24,7 +27,9 @@ class StandaloneTrustedVaultBackend : public base::RefCountedThreadSafe<StandaloneTrustedVaultBackend> { public: - explicit StandaloneTrustedVaultBackend(const base::FilePath& file_path); + StandaloneTrustedVaultBackend( + const base::FilePath& file_path, + std::unique_ptr<TrustedVaultConnection> connection); StandaloneTrustedVaultBackend(const StandaloneTrustedVaultBackend& other) = delete; StandaloneTrustedVaultBackend& operator=( @@ -46,18 +51,45 @@ // Removes all keys for all accounts from both memory and |file_path_|. void RemoveAllStoredKeys(); + // Sets/resets |syncing_account_|. + void SetSyncingAccount( + const base::Optional<CoreAccountInfo>& syncing_account); + + sync_pb::LocalDeviceRegistrationInfo GetDeviceRegistrationInfoForTesting( + const std::string& gaia_id); + private: friend class base::RefCountedThreadSafe<StandaloneTrustedVaultBackend>; - ~StandaloneTrustedVaultBackend() = default; + ~StandaloneTrustedVaultBackend(); // Finds the per-user vault in |data_| for |gaia_id|. Returns null if not // found. sync_pb::LocalTrustedVaultPerUser* FindUserVault(const std::string& gaia_id); + // Attempts to register device in case it's not yet registered and currently + // available local data is sufficient to do it. + void MaybeRegisterDevice(const std::string& gaia_id); + + // Called when device registration for |gaia_id| is completed (either + // successfully or not). + void OnDeviceRegistered(const std::string& gaia_id, + TrustedVaultRequestStatus status); + const base::FilePath file_path_; sync_pb::LocalTrustedVault data_; + + // Only current |syncing_account_| can be used for communication with trusted + // vault server. + base::Optional<CoreAccountInfo> syncing_account_; + + // Used for communication with trusted vault server. + std::unique_ptr<TrustedVaultConnection> connection_; + + // Used for cancellation of callbacks passed to |connection_|. + base::WeakPtrFactory<StandaloneTrustedVaultBackend> + weak_factory_for_connection_{this}; }; } // namespace syncer
diff --git a/components/sync/trusted_vault/standalone_trusted_vault_backend_unittest.cc b/components/sync/trusted_vault/standalone_trusted_vault_backend_unittest.cc new file mode 100644 index 0000000..2a609931 --- /dev/null +++ b/components/sync/trusted_vault/standalone_trusted_vault_backend_unittest.cc
@@ -0,0 +1,130 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/sync/trusted_vault/standalone_trusted_vault_backend.h" + +#include <memory> +#include <string> +#include <utility> +#include <vector> + +#include "base/files/file_util.h" +#include "base/files/scoped_temp_dir.h" +#include "base/test/scoped_feature_list.h" +#include "components/os_crypt/os_crypt_mocker.h" +#include "components/sync/driver/sync_driver_switches.h" +#include "components/sync/trusted_vault/securebox.h" +#include "components/sync/trusted_vault/trusted_vault_connection.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace syncer { + +namespace { + +using testing::_; +using testing::Eq; + +base::FilePath CreateUniqueTempDir(base::ScopedTempDir* temp_dir) { + EXPECT_TRUE(temp_dir->CreateUniqueTempDir()); + return temp_dir->GetPath(); +} + +class MockTrustedVaultConnection : public TrustedVaultConnection { + public: + MockTrustedVaultConnection() = default; + ~MockTrustedVaultConnection() override = default; + + MOCK_METHOD5(RegisterDevice, + void(const CoreAccountInfo&, + const std::vector<uint8_t>&, + int, + const SecureBoxPublicKey&, + RegisterDeviceCallback)); + MOCK_METHOD5(DownloadKeys, + void(const CoreAccountInfo&, + const std::vector<uint8_t>&, + int, + std::unique_ptr<SecureBoxKeyPair>, + DownloadKeysCallback)); +}; + +class StandaloneTrustedVaultBackendTest : public testing::Test { + public: + StandaloneTrustedVaultBackendTest() + : file_path_( + CreateUniqueTempDir(&temp_dir_) + .Append(base::FilePath(FILE_PATH_LITERAL("some_file")))) { + override_features.InitAndEnableFeature( + switches::kFollowTrustedVaultKeyRotation); + auto connection = + std::make_unique<testing::NiceMock<MockTrustedVaultConnection>>(); + connection_ = connection.get(); + backend_ = base::MakeRefCounted<StandaloneTrustedVaultBackend>( + file_path_, std::move(connection)); + } + + ~StandaloneTrustedVaultBackendTest() override = default; + + void SetUp() override { OSCryptMocker::SetUp(); } + + void TearDown() override { OSCryptMocker::TearDown(); } + + MockTrustedVaultConnection* connection() { return connection_; } + + StandaloneTrustedVaultBackend* backend() { return backend_.get(); } + + private: + base::test::ScopedFeatureList override_features; + + base::ScopedTempDir temp_dir_; + const base::FilePath file_path_; + testing::NiceMock<MockTrustedVaultConnection>* connection_; + scoped_refptr<StandaloneTrustedVaultBackend> backend_; +}; + +TEST_F(StandaloneTrustedVaultBackendTest, ShouldRegisterDevice) { + CoreAccountInfo account_info; + account_info.gaia = "user"; + + const std::vector<uint8_t> kVaultKey = {{1, 2, 3}}; + const int kLastKeyVersion = 0; + + backend()->StoreKeys(account_info.gaia, {kVaultKey}, kLastKeyVersion); + + TrustedVaultConnection::RegisterDeviceCallback device_registration_callback; + std::vector<uint8_t> serialized_public_device_key; + EXPECT_CALL(*connection(), RegisterDevice(Eq(account_info), Eq(kVaultKey), + Eq(kLastKeyVersion), _, _)) + .WillOnce([&](const CoreAccountInfo&, const std::vector<uint8_t>&, int, + const SecureBoxPublicKey& device_public_key, + TrustedVaultConnection::RegisterDeviceCallback callback) { + serialized_public_device_key = device_public_key.ExportToBytes(); + device_registration_callback = std::move(callback); + }); + + // Setting the syncing account will trigger device registration. + backend()->SetSyncingAccount(account_info); + ASSERT_FALSE(device_registration_callback.is_null()); + + // Pretend that the registration completed successfully. + std::move(device_registration_callback) + .Run(TrustedVaultRequestStatus::kSuccess); + + // Now the device should be registered. + sync_pb::LocalDeviceRegistrationInfo registration_info = + backend()->GetDeviceRegistrationInfoForTesting(account_info.gaia); + EXPECT_TRUE(registration_info.device_registered()); + EXPECT_TRUE(registration_info.has_private_key_material()); + + std::unique_ptr<SecureBoxKeyPair> key_pair = + SecureBoxKeyPair::CreateByPrivateKeyImport(base::as_bytes( + base::make_span(registration_info.private_key_material()))); + EXPECT_THAT(key_pair->public_key().ExportToBytes(), + Eq(serialized_public_device_key)); +} + +} // namespace + +} // namespace syncer
diff --git a/components/sync/trusted_vault/standalone_trusted_vault_client.cc b/components/sync/trusted_vault/standalone_trusted_vault_client.cc index d43c554a..d4f73e7 100644 --- a/components/sync/trusted_vault/standalone_trusted_vault_client.cc +++ b/components/sync/trusted_vault/standalone_trusted_vault_client.cc
@@ -14,6 +14,9 @@ #include "base/task_runner_util.h" #include "components/signin/public/identity_manager/account_info.h" #include "components/sync/trusted_vault/standalone_trusted_vault_backend.h" +#include "components/sync/trusted_vault/trusted_vault_access_token_fetcher.h" +#include "components/sync/trusted_vault/trusted_vault_connection_impl.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" namespace syncer { @@ -96,11 +99,22 @@ return; } - backend_ = base::MakeRefCounted<StandaloneTrustedVaultBackend>(file_path_); + // TODO(crbug.com/1113597): populate TrustedVaultAccessTokenFetcher into + // TrustedVaultConnectionImpl ctor. + // TODO(crbug.com/1113598): populate URLLoaderFactory into + // TrustedVaultConnectionImpl ctor. + // TODO(crbug.com/1102340): allow setting custom TrustedVaultConnection for + // testing. + backend_ = base::MakeRefCounted<StandaloneTrustedVaultBackend>( + file_path_, + std::make_unique<TrustedVaultConnectionImpl>( + /*url_loader_factory=*/nullptr, /*access_token_fetcher=*/nullptr)); backend_task_runner_->PostTask( FROM_HERE, base::BindOnce(&StandaloneTrustedVaultBackend::ReadDataFromDisk, backend_)); + // TODO(crbug.com/1113597): populate current syncing account to |backend_| + // here and upon syncing account change. } bool StandaloneTrustedVaultClient::IsInitializationTriggeredForTesting() const {
diff --git a/components/sync/trusted_vault/standalone_trusted_vault_client.h b/components/sync/trusted_vault/standalone_trusted_vault_client.h index ef4cc3e1..78ffa18 100644 --- a/components/sync/trusted_vault/standalone_trusted_vault_client.h +++ b/components/sync/trusted_vault/standalone_trusted_vault_client.h
@@ -28,6 +28,7 @@ // Reading of the file is done lazily. class StandaloneTrustedVaultClient : public TrustedVaultClient { public: + // TODO(crbug.com/1113597): plumb IdentityManager into ctor. explicit StandaloneTrustedVaultClient(const base::FilePath& file_path); StandaloneTrustedVaultClient(const StandaloneTrustedVaultClient& other) = delete;
diff --git a/components/sync/trusted_vault/standalone_trusted_vault_client_unittest.cc b/components/sync/trusted_vault/standalone_trusted_vault_client_unittest.cc index 2c16e1d..7608eb8 100644 --- a/components/sync/trusted_vault/standalone_trusted_vault_client_unittest.cc +++ b/components/sync/trusted_vault/standalone_trusted_vault_client_unittest.cc
@@ -114,9 +114,9 @@ sync_pb::LocalTrustedVaultPerUser* user_data2 = initial_data.add_user(); user_data1->set_gaia_id(kGaiaId1); user_data2->set_gaia_id(kGaiaId2); - user_data1->add_key()->set_key_material(kKey1.data(), kKey1.size()); - user_data2->add_key()->set_key_material(kKey2.data(), kKey2.size()); - user_data2->add_key()->set_key_material(kKey3.data(), kKey3.size()); + user_data1->add_vault_key()->set_key_material(kKey1.data(), kKey1.size()); + user_data2->add_vault_key()->set_key_material(kKey2.data(), kKey2.size()); + user_data2->add_vault_key()->set_key_material(kKey3.data(), kKey3.size()); std::string encrypted_data; ASSERT_TRUE(OSCrypt::EncryptString(initial_data.SerializeAsString(), @@ -154,11 +154,11 @@ EXPECT_TRUE(OSCrypt::DecryptString(ciphertext, &decrypted_content)); EXPECT_TRUE(proto.ParseFromString(decrypted_content)); ASSERT_THAT(proto.user_size(), Eq(2)); - EXPECT_THAT(proto.user(0).key(), ElementsAre(KeyMaterialEq(kKey1))); - EXPECT_THAT(proto.user(0).last_key_version(), Eq(7)); - EXPECT_THAT(proto.user(1).key(), + EXPECT_THAT(proto.user(0).vault_key(), ElementsAre(KeyMaterialEq(kKey1))); + EXPECT_THAT(proto.user(0).last_vault_key_version(), Eq(7)); + EXPECT_THAT(proto.user(1).vault_key(), ElementsAre(KeyMaterialEq(kKey3), KeyMaterialEq(kKey4))); - EXPECT_THAT(proto.user(1).last_key_version(), Eq(9)); + EXPECT_THAT(proto.user(1).last_vault_key_version(), Eq(9)); } TEST_F(StandaloneTrustedVaultClientTest, ShouldFetchPreviouslyStoredKeys) {
diff --git a/components/sync/trusted_vault/trusted_vault_access_token_fetcher.h b/components/sync/trusted_vault/trusted_vault_access_token_fetcher.h new file mode 100644 index 0000000..53c767d --- /dev/null +++ b/components/sync/trusted_vault/trusted_vault_access_token_fetcher.h
@@ -0,0 +1,45 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_SYNC_TRUSTED_VAULT_TRUSTED_VAULT_ACCESS_TOKEN_FETCHER_H_ +#define COMPONENTS_SYNC_TRUSTED_VAULT_TRUSTED_VAULT_ACCESS_TOKEN_FETCHER_H_ + +#include <string> + +#include "base/callback.h" + +struct CoreAccountId; +class GoogleServiceAuthError; + +namespace signin { +struct AccessTokenInfo; +} // namespace signin + +namespace syncer { + +// Allows asynchronous OAuth2 access token fetching from sequences other than +// the UI thread. +class TrustedVaultAccessTokenFetcher { + public: + using TokenCallback = + base::OnceCallback<void(GoogleServiceAuthError error, + signin::AccessTokenInfo access_token_info)>; + + TrustedVaultAccessTokenFetcher() = default; + TrustedVaultAccessTokenFetcher(const TrustedVaultAccessTokenFetcher& other) = + delete; + TrustedVaultAccessTokenFetcher& operator=( + const TrustedVaultAccessTokenFetcher& other) = delete; + virtual ~TrustedVaultAccessTokenFetcher() = default; + + // Asynchronously fetches vault service access token for |account_id|. May be + // called from arbitrary sequence that owns |this|. |callback| will be called + // on the caller sequence. + virtual void FetchAccessToken(const CoreAccountId& account_id, + TokenCallback callback) = 0; +}; + +} // namespace syncer + +#endif // COMPONENTS_SYNC_TRUSTED_VAULT_TRUSTED_VAULT_ACCESS_TOKEN_FETCHER_H_
diff --git a/components/sync/trusted_vault/trusted_vault_connection.h b/components/sync/trusted_vault/trusted_vault_connection.h new file mode 100644 index 0000000..629208aa --- /dev/null +++ b/components/sync/trusted_vault/trusted_vault_connection.h
@@ -0,0 +1,67 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_SYNC_TRUSTED_VAULT_TRUSTED_VAULT_CONNECTION_H_ +#define COMPONENTS_SYNC_TRUSTED_VAULT_TRUSTED_VAULT_CONNECTION_H_ + +#include <memory> +#include <string> +#include <vector> + +#include "base/callback.h" + +struct CoreAccountInfo; + +namespace syncer { + +class SecureBoxKeyPair; +class SecureBoxPublicKey; + +enum class TrustedVaultRequestStatus { + kSuccess, + // Used when trusted vault request can't be completed successfully due to + // vault key being outdated or device key being not registered. + kLocalDataObsolete, + // Used for all network, http and protocol errors. + kOtherError +}; + +// Supports interaction with vault service, all methods must called on trusted +// vault backend sequence. +class TrustedVaultConnection { + public: + using RegisterDeviceCallback = + base::OnceCallback<void(TrustedVaultRequestStatus)>; + using DownloadKeysCallback = + base::OnceCallback<void(TrustedVaultRequestStatus, + const std::vector<std::vector<uint8_t>>& /*keys*/, + int /*last_key_version*/)>; + + TrustedVaultConnection() = default; + TrustedVaultConnection(const TrustedVaultConnection& other) = delete; + TrustedVaultConnection& operator=(const TrustedVaultConnection& other) = + delete; + virtual ~TrustedVaultConnection() = default; + + // Asynchronously attempts to register the device on the trusted vault server + // to allow further DownloadKeys(). Calls |callback| upon completion. + virtual void RegisterDevice( + const CoreAccountInfo& account_info, + const std::vector<uint8_t>& last_trusted_vault_key, + int last_trusted_vault_key_version, + const SecureBoxPublicKey& device_public_key, + RegisterDeviceCallback callback) = 0; + + // Asynchronously attempts to download new vault keys from the trusted vault + // server. + virtual void DownloadKeys(const CoreAccountInfo& account_info, + const std::vector<uint8_t>& last_trusted_vault_key, + int last_trusted_vault_key_version, + std::unique_ptr<SecureBoxKeyPair> device_key_pair, + DownloadKeysCallback callback) = 0; +}; + +} // namespace syncer + +#endif // COMPONENTS_SYNC_TRUSTED_VAULT_TRUSTED_VAULT_CONNECTION_H_
diff --git a/components/sync/trusted_vault/trusted_vault_connection_impl.cc b/components/sync/trusted_vault/trusted_vault_connection_impl.cc new file mode 100644 index 0000000..3909261c --- /dev/null +++ b/components/sync/trusted_vault/trusted_vault_connection_impl.cc
@@ -0,0 +1,37 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/sync/trusted_vault/trusted_vault_connection_impl.h" + +#include "components/sync/trusted_vault/securebox.h" +#include "components/sync/trusted_vault/trusted_vault_access_token_fetcher.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" + +namespace syncer { + +TrustedVaultConnectionImpl::TrustedVaultConnectionImpl( + std::unique_ptr<network::PendingSharedURLLoaderFactory> url_loader_factory, + std::unique_ptr<TrustedVaultAccessTokenFetcher> access_token_fetcher) { + NOTIMPLEMENTED(); +} + +void TrustedVaultConnectionImpl::RegisterDevice( + const CoreAccountInfo& account_info, + const std::vector<uint8_t>& last_trusted_vault_key, + int last_trusted_vault_key_version, + const SecureBoxPublicKey& device_key_pair, + RegisterDeviceCallback callback) { + NOTIMPLEMENTED(); +} + +void TrustedVaultConnectionImpl::DownloadKeys( + const CoreAccountInfo& account_info, + const std::vector<uint8_t>& last_trusted_vault_key, + int last_trusted_vault_key_version, + std::unique_ptr<SecureBoxKeyPair> device_key_pair, + DownloadKeysCallback callback) { + NOTIMPLEMENTED(); +} + +} // namespace syncer
diff --git a/components/sync/trusted_vault/trusted_vault_connection_impl.h b/components/sync/trusted_vault/trusted_vault_connection_impl.h new file mode 100644 index 0000000..2af1964 --- /dev/null +++ b/components/sync/trusted_vault/trusted_vault_connection_impl.h
@@ -0,0 +1,50 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_SYNC_TRUSTED_VAULT_TRUSTED_VAULT_CONNECTION_IMPL_H_ +#define COMPONENTS_SYNC_TRUSTED_VAULT_TRUSTED_VAULT_CONNECTION_IMPL_H_ + +#include <memory> +#include <string> +#include <vector> + +#include "components/sync/trusted_vault/trusted_vault_access_token_fetcher.h" +#include "components/sync/trusted_vault/trusted_vault_connection.h" + +namespace network { +class PendingSharedURLLoaderFactory; +} // namespace network + +namespace syncer { + +// This class is created on UI thread and used/destroyed on trusted vault +// backend thread. +class TrustedVaultConnectionImpl : public TrustedVaultConnection { + public: + TrustedVaultConnectionImpl( + std::unique_ptr<network::PendingSharedURLLoaderFactory> + url_loader_factory, + std::unique_ptr<TrustedVaultAccessTokenFetcher> access_token_fetcher); + + TrustedVaultConnectionImpl(const TrustedVaultConnectionImpl& other) = delete; + TrustedVaultConnectionImpl& operator=( + const TrustedVaultConnectionImpl& other) = delete; + ~TrustedVaultConnectionImpl() override = default; + + void RegisterDevice(const CoreAccountInfo& account_info, + const std::vector<uint8_t>& last_trusted_vault_key, + int last_trusted_vault_key_version, + const SecureBoxPublicKey& device_key_pair, + RegisterDeviceCallback callback) override; + + void DownloadKeys(const CoreAccountInfo& account_info, + const std::vector<uint8_t>& last_trusted_vault_key, + int last_trusted_vault_key_version, + std::unique_ptr<SecureBoxKeyPair> device_key_pair, + DownloadKeysCallback callback) override; +}; + +} // namespace syncer + +#endif // COMPONENTS_SYNC_TRUSTED_VAULT_TRUSTED_VAULT_CONNECTION_IMPL_H_
diff --git a/components/test/data/payments/payment_handler_status.js b/components/test/data/payments/payment_handler_status.js index 4be77fc..b8b0803 100644 --- a/components/test/data/payments/payment_handler_status.js +++ b/components/test/data/payments/payment_handler_status.js
@@ -5,14 +5,39 @@ */ /** - * Returns the status field from the payment handler's response. + * Returns the status field from the payment handler's response for the given + * payment method identifier. * @param {string} method - The payment method identifier to use. * @return {string} - The status field or error message. */ async function getStatus(method) { // eslint-disable-line no-unused-vars + return getStatusInternal([{supportedMethods: method}]); +} + +/** + * Returns the status field from the payment handler's response for the given + * list of payment method identifiers. + * @param {array<string>} methods - The list of payment methods to use. + * @return {string} - The status field or error message. + */ +async function getStatusList(methods) { // eslint-disable-line no-unused-vars + const methodData = []; + for (let method of methods) { + methodData.push({supportedMethods: method}); + } + return getStatusInternal(methodData); +} + +/** + * Returns the status field from the payment handler's response for given + * payment method data. + * @param {array<PaymentMethodData>} methodData - The method data to use. + * @return {string} - The status field or error message. + */ +async function getStatusInternal(methodData) { try { const request = new PaymentRequest( - [{supportedMethods: method}], + methodData, {total: {label: 'TEST', amount: {currency: 'USD', value: '0.01'}}}); const response = await request.show(); await response.complete();
diff --git a/components/translate/core/browser/translate_language_list.h b/components/translate/core/browser/translate_language_list.h index 77e6025a..7dc7195c 100644 --- a/components/translate/core/browser/translate_language_list.h +++ b/components/translate/core/browser/translate_language_list.h
@@ -55,10 +55,9 @@ // pending request. void SetResourceRequestsAllowed(bool allowed); - typedef base::RepeatingCallback<void(const TranslateEventDetails&)> - EventCallback; - typedef base::CallbackList<void(const TranslateEventDetails&)> - EventCallbackList; + using EventCallbackList = + base::CallbackList<void(const TranslateEventDetails&)>; + using EventCallback = EventCallbackList::CallbackType; // Registers a callback for translate events related to the language list, // such as updates and download errors.
diff --git a/components/translate/core/browser/translate_manager.h b/components/translate/core/browser/translate_manager.h index 425feca..13780bbf 100644 --- a/components/translate/core/browser/translate_manager.h +++ b/components/translate/core/browser/translate_manager.h
@@ -139,16 +139,14 @@ void ReportLanguageDetectionError(); // Callback types for translate errors. - typedef base::RepeatingCallback<void(const TranslateErrorDetails&)> - TranslateErrorCallback; - typedef base::CallbackList<void(const TranslateErrorDetails&)> - TranslateErrorCallbackList; + using TranslateErrorCallbackList = + base::CallbackList<void(const TranslateErrorDetails&)>; + using TranslateErrorCallback = TranslateErrorCallbackList::CallbackType; // Callback types for translate initialization. - typedef base::RepeatingCallback<void(const TranslateInitDetails&)> - TranslateInitCallback; - typedef base::CallbackList<void(const TranslateInitDetails&)> - TranslateInitCallbackList; + using TranslateInitCallbackList = + base::CallbackList<void(const TranslateInitDetails&)>; + using TranslateInitCallback = TranslateInitCallbackList::CallbackType; // Registers a callback for translate errors. static std::unique_ptr<TranslateErrorCallbackList::Subscription>
diff --git a/components/translate/core/browser/translate_script.cc b/components/translate/core/browser/translate_script.cc index bc59e97..3cacd36 100644 --- a/components/translate/core/browser/translate_script.cc +++ b/components/translate/core/browser/translate_script.cc
@@ -60,7 +60,7 @@ script_fetch_start_time_ = base::Time::Now().ToJsTime(); DCHECK(data_.empty()) << "Do not fetch the script if it is already fetched"; - callback_list_.push_back(std::move(callback)); + callback_list_.AddUnsafe(std::move(callback)); if (fetcher_) { // If there is already a request in progress, do nothing. |callback| will be @@ -177,9 +177,7 @@ expiration_delay_); } - for (auto& callback : callback_list_) - std::move(callback).Run(success, data); - callback_list_.clear(); + callback_list_.Notify(success, data); } } // namespace translate
diff --git a/components/translate/core/browser/translate_script.h b/components/translate/core/browser/translate_script.h index 2e96746..7396733b 100644 --- a/components/translate/core/browser/translate_script.h +++ b/components/translate/core/browser/translate_script.h
@@ -10,6 +10,7 @@ #include <vector> #include "base/callback_forward.h" +#include "base/callback_list.h" #include "base/gtest_prod_util.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" @@ -93,7 +94,7 @@ base::TimeDelta expiration_delay_; // The callbacks called when the server sends a response. - typedef std::vector<RequestCallback> RequestCallbackList; + using RequestCallbackList = base::OnceCallbackList<RequestCallback::RunType>; RequestCallbackList callback_list_; base::WeakPtrFactory<TranslateScript> weak_method_factory_{this};
diff --git a/components/viz/service/display/direct_renderer.cc b/components/viz/service/display/direct_renderer.cc index 07fcea12..15170075 100644 --- a/components/viz/service/display/direct_renderer.cc +++ b/components/viz/service/display/direct_renderer.cc
@@ -953,4 +953,10 @@ delegated_ink_point_renderer_->SetDelegatedInkMetadata(std::move(metadata)); } +bool DirectRenderer::CompositeTimeTracingEnabled() { + return false; +} + +void DirectRenderer::AddCompositeTimeTraces(base::TimeTicks ready_timestamp) {} + } // namespace viz
diff --git a/components/viz/service/display/direct_renderer.h b/components/viz/service/display/direct_renderer.h index 07c87be7..7e43e8a 100644 --- a/components/viz/service/display/direct_renderer.h +++ b/components/viz/service/display/direct_renderer.h
@@ -140,6 +140,13 @@ DelegatedInkPointRendererBase* GetDelegatedInkPointRenderer(); void SetDelegatedInkMetadata(std::unique_ptr<DelegatedInkMetadata> metadata); + // Returns true if composite time tracing is enabled. This measures a detailed + // trace log for draw time spent per quad. + virtual bool CompositeTimeTracingEnabled(); + + // Puts the draw time wall in trace file relative to the |ready_timestamp|. + virtual void AddCompositeTimeTraces(base::TimeTicks ready_timestamp); + protected: friend class BspWalkActionDrawPolygon; FRIEND_TEST_ALL_PREFIXES(DisplayTest, SkiaDelegatedInkRenderer);
diff --git a/components/viz/service/display/display.cc b/components/viz/service/display/display.cc index 0cb2b75..a6a96c8c 100644 --- a/components/viz/service/display/display.cc +++ b/components/viz/service/display/display.cc
@@ -977,6 +977,15 @@ TRACE_EVENT_INSTANT_WITH_TIMESTAMP0( "benchmark,viz", "Display::FrameDisplayed", TRACE_EVENT_SCOPE_THREAD, copy_feedback.timestamp); + + if (renderer_->CompositeTimeTracingEnabled()) { + if (copy_feedback.ready_timestamp.is_null()) { + LOG(WARNING) << "Ready Timestamp unavailable"; + } else { + renderer_->AddCompositeTimeTraces(copy_feedback.ready_timestamp); + } + } + presentation_group_timing.OnPresent(copy_feedback); pending_presentation_group_timings_.pop_front(); }
diff --git a/components/viz/service/display/gl_renderer.cc b/components/viz/service/display/gl_renderer.cc index 3dc5c652..d7b2f17 100644 --- a/components/viz/service/display/gl_renderer.cc +++ b/components/viz/service/display/gl_renderer.cc
@@ -12,8 +12,6 @@ #include <memory> #include <numeric> #include <set> -#include <string> -#include <utility> #include <vector> #include "base/bind.h" @@ -192,9 +190,43 @@ } } +// Adds a timer query that spans all GL calls in its scope. |viz.composite_time| +// trace category must be enabled for this to work. +// Note:: Multiple timer queries cannot be nested. +class ScopedTimerQuery { + public: + ScopedTimerQuery(bool tracing_enabled, + gpu::gles2::GLES2Interface* gl, + base::queue<std::pair<unsigned, std::string>>* timer_queries, + const std::string& quad_type_str) + : gl_(gl) { + if (!tracing_enabled) { + gl_ = nullptr; + return; + } + unsigned timer_query; + gl_->GenQueriesEXT(1, &timer_query); + gl_->BeginQueryEXT(GL_TIME_ELAPSED_EXT, timer_query); + timer_queries->emplace(timer_query, quad_type_str); + } + + ~ScopedTimerQuery() { + if (gl_) + gl_->EndQueryEXT(GL_TIME_ELAPSED_EXT); + } + + private: + gpu::gles2::GLES2Interface* gl_; +}; + // Smallest unit that impact anti-aliasing output. We use this to // determine when anti-aliasing is unnecessary. const float kAntiAliasingEpsilon = 1.0f / 1024.0f; + +// A dummy timer query ID used to identify the beginning of a frame in the queue +// of timer queries. +const unsigned kTimerQueryDummy = 0; + } // anonymous namespace static GLint GetActiveTextureUnit(GLES2Interface* gl) { @@ -384,6 +416,7 @@ use_blend_equation_advanced_coherent_ = context_caps.blend_equation_advanced_coherent; use_occlusion_query_ = context_caps.occlusion_query; + use_timer_query_ = context_caps.timer_queries; use_swap_with_bounds_ = context_caps.swap_buffers_with_bounds; prefer_draw_to_copy_ = output_surface_->context_provider() ->GetGpuFeatureInfo() @@ -535,6 +568,11 @@ // TODO(enne): Do we need to reinitialize all of this state per frame? ReinitializeGLState(); + // Add a dummy timer query as a fence to identify the beginning of a frame in + // the circular queue. + if (CompositeTimeTracingEnabled()) + timer_queries_.emplace(kTimerQueryDummy, ""); + num_triangles_drawn_ = 0; } @@ -1189,6 +1227,8 @@ params.window_matrix = current_frame()->window_matrix; params.projection_matrix = current_frame()->projection_matrix; params.tex_coord_rect = quad->tex_coord_rect; + ScopedTimerQuery scoped_timer_query(CompositeTimeTracingEnabled(), gl_, + &timer_queries_, "kRenderPassDrawQuad"); if (bypass != render_pass_bypass_quads_.end()) { DCHECK(bypass->second->material == DrawQuad::Material::kTiledContent); const TileDrawQuad* tile_quad = TileDrawQuad::MaterialCast(bypass->second); @@ -2036,6 +2076,10 @@ use_aa = ShouldAntialiasQuad(device_layer_quad, clipped, force_aa); } + ScopedTimerQuery scoped_timer_query(CompositeTimeTracingEnabled(), gl_, + &timer_queries_, + use_aa ? "kSolidColorAA" : "kSolidColor"); + float edge[24]; const gfx::QuadF* aa_quad = use_aa ? &device_layer_quad : nullptr; SetupQuadForClippingAndAntialiasing(device_transform, quad, aa_quad, @@ -2129,6 +2173,9 @@ if (!device_transform.IsInvertible()) return; + ScopedTimerQuery scoped_timer_query(CompositeTimeTracingEnabled(), gl_, + &timer_queries_, "kTiledContentAA"); + gfx::Rect tile_rect = quad->visible_rect; gfx::RectF tex_coord_rect = cc::MathUtil::ScaleRectProportional( @@ -2243,6 +2290,9 @@ float tex_to_geom_scale_y = quad->rect.height() / quad->tex_coord_rect.height(); + ScopedTimerQuery scoped_timer_query(CompositeTimeTracingEnabled(), gl_, + &timer_queries_, "kTiledContent"); + bool scaled = (tex_to_geom_scale_x != 1.f || tex_to_geom_scale_y != 1.f); GLenum filter = (scaled || !quad->shared_quad_state->quad_to_target_transform .IsIdentityOrIntegerTranslation()) && @@ -2366,6 +2416,15 @@ void GLRenderer::DrawYUVVideoQuad(const YUVVideoDrawQuad* quad, const gfx::QuadF* clip_region) { + std::string gpu_composite_time_string; + if (!clip_region && quad->rect == quad->visible_rect) + gpu_composite_time_string = "kYuvVideoContent"; + else + gpu_composite_time_string = "kYuvVideoContentClipped"; + ScopedTimerQuery scoped_timer_query(CompositeTimeTracingEnabled(), gl_, + &timer_queries_, + gpu_composite_time_string); + SetBlendEnabled(quad->ShouldDrawWithBlending()); TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired( @@ -2548,6 +2607,15 @@ void GLRenderer::DrawStreamVideoQuad(const StreamVideoDrawQuad* quad, const gfx::QuadF* clip_region) { + std::string gpu_composite_time_string; + if (!clip_region && quad->rect == quad->visible_rect) { + gpu_composite_time_string = "kStreamVideoContent"; + } else { + gpu_composite_time_string = "kStreamVideoContentClipped"; + } + ScopedTimerQuery scoped_timer_query(CompositeTimeTracingEnabled(), gl_, + &timer_queries_, + gpu_composite_time_string); SetBlendEnabled(quad->ShouldDrawWithBlending()); DCHECK(output_surface_->context_provider() @@ -2616,6 +2684,8 @@ // Check to see if we have anything to draw. if (draw_cache_.is_empty) return; + ScopedTimerQuery scoped_timer_query(CompositeTimeTracingEnabled(), gl_, + &timer_queries_, "kTextureContentFlush"); PrepareGeometry(flush_binding); @@ -2685,6 +2755,7 @@ DCHECK_LE(draw_cache_.matrix_data.size(), static_cast<size_t>(std::numeric_limits<int>::max()) / 6u); + // Draw the quads! gl_->DrawElements(GL_TRIANGLES, 6 * static_cast<int>(draw_cache_.matrix_data.size()), @@ -2882,6 +2953,74 @@ current_frame()->root_render_pass; } +bool GLRenderer::CompositeTimeTracingEnabled() { + bool tracing_enabled; + TRACE_EVENT_CATEGORY_GROUP_ENABLED( + TRACE_DISABLED_BY_DEFAULT("viz.gpu_composite_time"), &tracing_enabled); + + return tracing_enabled && use_timer_query_; +} + +void GLRenderer::AddCompositeTimeTraces(base::TimeTicks ready_timestamp) { + DCHECK(CompositeTimeTracingEnabled()); + DCHECK_EQ(timer_queries_.front().first, kTimerQueryDummy); + + std::size_t count = 0; + uint64_t duration = 0; + + // List of queries to delete after their results are retrieved. + std::vector<unsigned> queries_to_delete; + + // Queue of durations per draw call. The |second| in the pair represents the + // draw call type as string. + base::queue<std::pair<uint64_t, std::string>> durations; + + // Pop the fence query as it does not represent a timer query. + timer_queries_.pop(); + + // Initialize |start_time_ticks| as the end timestamp and walk backwards to + // find the actual timestamp. + base::TimeTicks start_time_ticks = ready_timestamp; + + while (timer_queries_.size() && + timer_queries_.front().first != kTimerQueryDummy) { + count++; + gl_->GetQueryObjectui64vEXT(timer_queries_.front().first, + GL_QUERY_RESULT_EXT, &duration); + durations.emplace(duration, timer_queries_.front().second); + queries_to_delete.push_back(timer_queries_.front().first); + timer_queries_.pop(); + start_time_ticks -= base::TimeDelta::FromNanoseconds(duration); + } + + // Delete all timer queries for which results have been retrieved. + gl_->DeleteQueriesEXT(count, queries_to_delete.data()); + + TRACE_EVENT_ASYNC_BEGIN_WITH_TIMESTAMP0( + TRACE_DISABLED_BY_DEFAULT("viz.gpu_composite_time"), "Composite Time", + this, start_time_ticks); + + while (!durations.empty()) { + duration = durations.front().first; + + // |duration| may be set to 0 if the timer query result was unavailable in + // |GetQueryObjectui64vEXT| function call. + if (!duration) { + durations.pop(); + continue; + } + TRACE_EVENT_ASYNC_STEP_INTO_WITH_TIMESTAMP0( + TRACE_DISABLED_BY_DEFAULT("viz.gpu_composite_time"), "Composite Time", + this, durations.front().second.c_str(), start_time_ticks); + start_time_ticks += base::TimeDelta::FromNanoseconds(duration); + durations.pop(); + } + + TRACE_EVENT_ASYNC_END_WITH_TIMESTAMP0( + TRACE_DISABLED_BY_DEFAULT("viz.gpu_composite_time"), "Composite Time", + this, ready_timestamp); +} + void GLRenderer::FinishDrawingQuadList() { FlushTextureQuadCache(SHARED_BINDING); if (occlusion_query_) {
diff --git a/components/viz/service/display/gl_renderer.h b/components/viz/service/display/gl_renderer.h index f3ab1ae..e5d03f4 100644 --- a/components/viz/service/display/gl_renderer.h +++ b/components/viz/service/display/gl_renderer.h
@@ -7,11 +7,14 @@ #include <map> #include <memory> +#include <string> #include <unordered_map> +#include <utility> #include <vector> #include "base/cancelable_callback.h" #include "base/containers/circular_deque.h" +#include "base/containers/queue.h" #include "base/macros.h" #include "build/build_config.h" #include "components/viz/common/gpu/context_cache_controller.h" @@ -359,6 +362,9 @@ unsigned query); bool OverdrawTracingEnabled(); + bool CompositeTimeTracingEnabled() override; + void AddCompositeTimeTraces(base::TimeTicks ready_timestamp) override; + ResourceFormat CurrentRenderPassResourceFormat() const; // A map from RenderPass id to the texture used to draw the RenderPass from. @@ -438,6 +444,7 @@ bool use_sync_query_ = false; bool use_blend_equation_advanced_ = false; bool use_blend_equation_advanced_coherent_ = false; + bool use_timer_query_ = false; bool use_occlusion_query_ = false; bool use_swap_with_bounds_ = false; @@ -459,6 +466,10 @@ unsigned num_triangles_drawn_ = 0; bool prefer_draw_to_copy_ = false; + // A circular queue of to keep track of timer queries and their associated + // quad type as string. + base::queue<std::pair<unsigned, std::string>> timer_queries_; + // This may be null if the compositor is run on a thread without a // MessageLoop. scoped_refptr<base::SingleThreadTaskRunner> current_task_runner_;
diff --git a/components/viz/service/display/surface_aggregator.cc b/components/viz/service/display/surface_aggregator.cc index 905e733..398c9db9 100644 --- a/components/viz/service/display/surface_aggregator.cc +++ b/components/viz/service/display/surface_aggregator.cc
@@ -1183,15 +1183,12 @@ pass_id_remapper_.Remap(source.id, surface->surface_id()); gfx::Rect output_rect = source.output_rect; - gfx::Rect damage_rect = source.output_rect; gfx::Transform transform_to_root_target = source.transform_to_root_target; if (apply_surface_transform_to_root_pass) { // If we don't need an additional render pass to apply the surface // transform, adjust the root pass's rects to account for it. output_rect = cc::MathUtil::MapEnclosedRectWith2dAxisAlignedTransform( surface_transform, output_rect); - damage_rect = cc::MathUtil::MapEnclosedRectWith2dAxisAlignedTransform( - surface_transform, damage_rect); } else { // For the non-root render passes, the transform to root target needs to // be adjusted to include the root surface transform. This is also true if @@ -1202,7 +1199,7 @@ } copy_pass->SetAll( - remapped_pass_id, output_rect, damage_rect, transform_to_root_target, + remapped_pass_id, output_rect, output_rect, transform_to_root_target, source.filters, source.backdrop_filters, source.backdrop_filter_bounds, root_content_color_usage_, source.has_transparent_background, source.cache_render_pass, source.has_damage_from_contributing_content,
diff --git a/components/viz/service/main/viz_main_impl.cc b/components/viz/service/main/viz_main_impl.cc index f74b6cd..5203eca 100644 --- a/components/viz/service/main/viz_main_impl.cc +++ b/components/viz/service/main/viz_main_impl.cc
@@ -10,9 +10,13 @@ #include "base/bind.h" #include "base/feature_list.h" #include "base/message_loop/message_pump_type.h" +#include "base/no_destructor.h" #include "base/power_monitor/power_monitor.h" #include "base/power_monitor/power_monitor_source.h" #include "base/single_thread_task_runner.h" +#include "base/synchronization/lock.h" +#include "base/task/thread_pool.h" +#include "base/time/time.h" #include "base/trace_event/memory_dump_manager.h" #include "build/build_config.h" #include "components/ui_devtools/buildflags.h" @@ -21,12 +25,81 @@ #include "gpu/ipc/service/gpu_init.h" #include "gpu/ipc/service/gpu_watchdog_thread.h" #include "media/gpu/buildflags.h" +#include "mojo/public/cpp/bindings/scoped_message_error_crash_key.h" +#include "mojo/public/cpp/system/functions.h" #include "services/metrics/public/cpp/delegating_ukm_recorder.h" #include "services/metrics/public/cpp/mojo_ukm_recorder.h" #include "third_party/skia/include/core/SkFontLCDConfig.h" namespace { +// Singleton class to store error strings from global mojo error handler. It +// will store error strings for kTimeout seconds and can be used to set a crash +// key if the GPU process is going to crash due to a deserialization error. +// TODO(kylechar): This can be removed after tracking down all outstanding +// deserialization errors in messages sent from the browser to GPU on the viz +// message pipe. +class MojoErrorTracker { + public: + static constexpr base::TimeDelta kTimeout = base::TimeDelta::FromSeconds(5); + + static MojoErrorTracker& Get() { + static base::NoDestructor<MojoErrorTracker> tracker; + return *tracker; + } + + void OnError(const std::string& error) { + { + base::AutoLock locked(lock_); + error_ = error; + error_time_ = base::TimeTicks::Now(); + } + + // Once the error is old enough we will no longer use it in a crash key we + // can reset the string storage. + base::ThreadPool::PostDelayedTask( + FROM_HERE, + base::BindOnce(&MojoErrorTracker::Reset, base::Unretained(this)), + kTimeout); + } + + // This will initialize the scoped crash key in |key| with the last mojo + // error message if the last mojo error happened within kTimeout seconds. + void MaybeSetCrashKeyWithRecentError( + base::Optional<mojo::debug::ScopedMessageErrorCrashKey>& key) { + base::AutoLock locked(lock_); + if (!HasErrorTimedOut()) + key.emplace(error_); + } + + private: + friend class base::NoDestructor<MojoErrorTracker>; + MojoErrorTracker() = default; + + bool HasErrorTimedOut() const EXCLUSIVE_LOCKS_REQUIRED(lock_) { + return base::TimeTicks::Now() - error_time_ > kTimeout; + } + + void Reset() { + base::AutoLock locked(lock_); + + // If another mojo error happened since this task was scheduled we shouldn't + // reset the error string yet. + if (!HasErrorTimedOut()) + return; + + error_.clear(); + error_.shrink_to_fit(); + } + + base::Lock lock_; + std::string error_ GUARDED_BY(lock_); + base::TimeTicks error_time_ GUARDED_BY(lock_); +}; + +// static +constexpr base::TimeDelta MojoErrorTracker::kTimeout; + std::unique_ptr<base::Thread> CreateAndStartIOThread() { // TODO(sad): We do not need the IO thread once gpu has a separate process. // It should be possible to use |main_task_runner_| for doing IO tasks. @@ -63,6 +136,12 @@ gpu_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()) { DCHECK(gpu_init_); + if (!gpu_init_->gpu_info().in_process_gpu) { + mojo::SetDefaultProcessErrorHandler( + base::BindRepeating(&MojoErrorTracker::OnError, + base::Unretained(&MojoErrorTracker::Get()))); + } + // TODO(crbug.com/609317): Remove this when Mus Window Server and GPU are // split into separate processes. Until then this is necessary to be able to // run Mushrome (chrome with mus) with Mus running in the browser process. @@ -238,7 +317,16 @@ // FrameSinkManagerImpl, so just do a hard CHECK rather than crashing down the // road so that all crash reports caused by this issue look the same and have // the same signature. https://crbug.com/928845 - CHECK(!task_executor_); + if (task_executor_) { + // If the global mojo error handler callback ran recently, we've cached the + // error string and will initialize |crash_key| to contain it before + // intentionally crashing. The deserialization error that caused the mojo + // error handler to run was probably, but not 100% guaranteed, the error + // that caused the main viz browser-to-GPU message pipe close. + base::Optional<mojo::debug::ScopedMessageErrorCrashKey> crash_key; + MojoErrorTracker::Get().MaybeSetCrashKeyWithRecentError(crash_key); + CHECK(!task_executor_); + } task_executor_ = std::make_unique<gpu::GpuInProcessThreadService>( this, gpu_thread_task_runner_, gpu_service_->GetGpuScheduler(), gpu_service_->sync_point_manager(), gpu_service_->mailbox_manager(),
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc index dba5ff9..ef0f1e49 100644 --- a/content/browser/frame_host/render_frame_host_impl.cc +++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -1356,6 +1356,13 @@ return it == portals_.end() ? nullptr : it->get(); } +std::vector<Portal*> RenderFrameHostImpl::GetPortals() const { + std::vector<Portal*> result; + for (const auto& portal : portals_) + result.push_back(portal.get()); + return result; +} + void RenderFrameHostImpl::DestroyPortal(Portal* portal) { auto it = portals_.find(portal); CHECK(it != portals_.end());
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h index 714cd99..7b812202f 100644 --- a/content/browser/frame_host/render_frame_host_impl.h +++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -1191,6 +1191,9 @@ // Look up a portal by its token (as received from the renderer process). Portal* FindPortalByToken(const blink::PortalToken& portal_token); + // Return portals owned by |this|. + std::vector<Portal*> GetPortals() const; + // Called when a Portal needs to be destroyed. void DestroyPortal(Portal* portal);
diff --git a/content/browser/portal/portal.cc b/content/browser/portal/portal.cc index f93eb98..8375598 100644 --- a/content/browser/portal/portal.cc +++ b/content/browser/portal/portal.cc
@@ -308,169 +308,34 @@ void Portal::Activate(blink::TransferableMessage data, base::TimeTicks activation_time, ActivateCallback callback) { - WebContentsImpl* outer_contents = GetPortalHostContents(); - - if (outer_contents->portal()) { + if (GetPortalHostContents()->portal()) { mojo::ReportBadMessage("Portal::Activate called on nested portal"); - DestroySelf(); // Also deletes |this|. + DestroySelf(); return; } - DCHECK(owner_render_frame_host_->IsCurrent()) - << "The binding should have been closed when the portal's outer " - "FrameTreeNode was deleted due to swap out."; - - DCHECK(portal_contents_); - NavigationControllerImpl& portal_controller = - portal_contents_->GetController(); - NavigationControllerImpl& predecessor_controller = - outer_contents->GetController(); - - // If no navigation has yet committed in the portal, it cannot be activated as - // this would lead to an empty tab contents (without even an about:blank). - if (portal_controller.GetLastCommittedEntryIndex() < 0) { - std::move(callback).Run( - blink::mojom::PortalActivateResult::kRejectedDueToPortalNotReady); - return; - } - DCHECK(predecessor_controller.GetLastCommittedEntry()); - - // Error pages and interstitials may not host portals due to the HTTP(S) - // restriction. - DCHECK_EQ(PAGE_TYPE_NORMAL, - predecessor_controller.GetLastCommittedEntry()->GetPageType()); - - // If the portal is crashed or is showing an error page, reject activation. - if (portal_contents_->IsCrashed() || - portal_controller.GetLastCommittedEntry()->GetPageType() != - PAGE_TYPE_NORMAL) { - std::move(callback).Run( - blink::mojom::PortalActivateResult::kRejectedDueToErrorInPortal); + if (is_activating_) { + mojo::ReportBadMessage("Portal::Activate called twice on the same portal"); + DestroySelf(); return; } - // If a navigation in the main frame is occurring, stop it if possible and - // reject the activation if it's too late or if an ongoing navigation takes - // precedence. There are a few cases here: - // - a different RenderFrameHost has been assigned to the FrameTreeNode - // - the same RenderFrameHost is being used, but it is committing a navigation - // - the FrameTreeNode holds a navigation request that can't turn back but has - // not yet been handed off to a RenderFrameHost - FrameTreeNode* outer_root_node = owner_render_frame_host_->frame_tree_node(); - NavigationRequest* outer_navigation = outer_root_node->navigation_request(); - const bool has_user_gesture = - owner_render_frame_host_->HasTransientUserActivation(); - - // WILL_PROCESS_RESPONSE is slightly early: it happens - // immediately before READY_TO_COMMIT (unless it's deferred), but - // WILL_PROCESS_RESPONSE is easier to hook for tests using a - // NavigationThrottle. - if (owner_render_frame_host_->HasPendingCommitNavigation() || - (outer_navigation && - outer_navigation->state() >= NavigationRequest::WILL_PROCESS_RESPONSE) || - Navigator::ShouldIgnoreIncomingRendererRequest(outer_navigation, - has_user_gesture)) { - std::move(callback).Run(blink::mojom::PortalActivateResult:: - kRejectedDueToPredecessorNavigation); - return; - } - outer_root_node->navigator().CancelNavigation(outer_root_node); - - DCHECK(!is_closing_) << "Portal should not be shutting down when contents " - "ownership is yielded"; - - WebContentsDelegate* delegate = outer_contents->GetDelegate(); - std::unique_ptr<WebContents> successor_contents; - - if (portal_contents_->GetOuterWebContents()) { - FrameTreeNode* outer_frame_tree_node = FrameTreeNode::GloballyFindByID( - portal_contents_->GetOuterDelegateFrameTreeNodeId()); - outer_frame_tree_node->RemoveObserver(this); - successor_contents = portal_contents_->DetachFromOuterWebContents(); - owner_render_frame_host_->RemoveChild(outer_frame_tree_node); - } else { - // Portals created for predecessor pages during activation may not be - // attached to an outer WebContents, and may not have an outer frame tree - // node created (i.e. CreateProxyAndAttachPortal isn't called). In this - // case, we can skip a few of the detachment steps above. - for (auto& render_view_host : - portal_contents_->GetFrameTree()->render_view_hosts()) { - CreatePortalRenderWidgetHostView(portal_contents_.get(), - render_view_host.second); + for (Portal* portal : owner_render_frame_host()->GetPortals()) { + if (portal != this && portal->is_activating_) { + mojo::ReportBadMessage( + "Portal::Activate called on portal whose owner RenderFrameHost has " + "another portal that is activating"); + DestroySelf(); + return; } - successor_contents = portal_contents_.ReleaseOwnership(); - } - DCHECK(!portal_contents_.OwnsContents()); - - // This assumes that the delegate keeps the new contents alive long enough to - // notify it of activation, at least. - WebContentsImpl* successor_contents_raw = - static_cast<WebContentsImpl*>(successor_contents.get()); - - auto* outer_contents_main_frame_view = static_cast<RenderWidgetHostViewBase*>( - outer_contents->GetMainFrame()->GetView()); - DCHECK(!outer_contents->GetPendingMainFrame()); - auto* portal_contents_main_frame_view = - static_cast<RenderWidgetHostViewBase*>( - successor_contents_raw->GetMainFrame()->GetView()); - - std::vector<std::unique_ptr<ui::TouchEvent>> touch_events; - - if (outer_contents_main_frame_view) { - // Take fallback contents from previous WebContents so that the activation - // is smooth without flashes. - portal_contents_main_frame_view->TakeFallbackContentFrom( - outer_contents_main_frame_view); - touch_events = - outer_contents_main_frame_view->ExtractAndCancelActiveTouches(); - FlushTouchEventQueues(outer_contents_main_frame_view->host()); } - TakeHistoryForActivation(successor_contents_raw, outer_contents); - - devtools_instrumentation::PortalActivated(outer_contents->GetMainFrame()); - successor_contents_raw->set_portal(nullptr); - - std::unique_ptr<WebContents> predecessor_web_contents = - delegate->ActivatePortalWebContents(outer_contents, - std::move(successor_contents)); - DCHECK_EQ(predecessor_web_contents.get(), outer_contents); - - if (outer_contents_main_frame_view) { - portal_contents_main_frame_view->TransferTouches(touch_events); - // Takes ownership of SyntheticGestureController from the predecessor's - // RenderWidgetHost. This allows the controller to continue sending events - // to the new RenderWidgetHostView. - portal_contents_main_frame_view->host()->TakeSyntheticGestureController( - outer_contents_main_frame_view->host()); - outer_contents_main_frame_view->Destroy(); - } - - // These pointers are cleared so that they don't dangle in the event this - // object isn't immediately deleted. It isn't done sooner because - // ActivatePortalWebContents misbehaves if the WebContents doesn't appear to - // be a portal at that time. - portal_contents_.Clear(); - - mojo::PendingAssociatedRemote<blink::mojom::Portal> pending_portal; - auto portal_receiver = pending_portal.InitWithNewEndpointAndPassReceiver(); - mojo::PendingAssociatedRemote<blink::mojom::PortalClient> pending_client; - auto client_receiver = pending_client.InitWithNewEndpointAndPassReceiver(); - - RenderFrameHostImpl* successor_main_frame = - successor_contents_raw->GetMainFrame(); - auto predecessor = std::make_unique<Portal>( - successor_main_frame, std::move(predecessor_web_contents)); - predecessor->Bind(std::move(portal_receiver), std::move(pending_client)); - successor_main_frame->OnPortalActivated( - std::move(predecessor), std::move(pending_portal), - std::move(client_receiver), std::move(data), std::move(callback)); - - // Notifying of activation happens later than ActivatePortalWebContents so - // that it is observed after predecessor_web_contents has been moved into a - // portal. - DCHECK(outer_contents->IsPortal()); - successor_contents_raw->DidActivatePortal(outer_contents, activation_time); + is_activating_ = true; + WebContentsImpl* outer_contents = GetPortalHostContents(); + outer_contents->GetDelegate()->UpdateInspectedWebContentsIfNecessary( + outer_contents, portal_contents_.get(), + base::BindOnce(&Portal::ActivateImpl, weak_factory_.GetWeakPtr(), + std::move(data), activation_time, std::move(callback))); } void Portal::PostMessageToGuest( @@ -583,6 +448,186 @@ WebContents::FromRenderFrameHost(owner_render_frame_host_)); } +std::pair<bool, blink::mojom::PortalActivateResult> Portal::CanActivate() { + WebContentsImpl* outer_contents = GetPortalHostContents(); + + DCHECK(owner_render_frame_host_->IsCurrent()) + << "The binding should have been closed when the portal's outer " + "FrameTreeNode was deleted due to swap out."; + + DCHECK(portal_contents_); + NavigationControllerImpl& portal_controller = + portal_contents_->GetController(); + NavigationControllerImpl& predecessor_controller = + outer_contents->GetController(); + + // If no navigation has yet committed in the portal, it cannot be activated as + // this would lead to an empty tab contents (without even an about:blank). + if (portal_controller.GetLastCommittedEntryIndex() < 0) { + return std::make_pair( + false, + blink::mojom::PortalActivateResult::kRejectedDueToPortalNotReady); + } + DCHECK(predecessor_controller.GetLastCommittedEntry()); + + // Error pages and interstitials may not host portals due to the HTTP(S) + // restriction. + DCHECK_EQ(PAGE_TYPE_NORMAL, + predecessor_controller.GetLastCommittedEntry()->GetPageType()); + + // If the portal is crashed or is showing an error page, reject activation. + if (portal_contents_->IsCrashed() || + portal_controller.GetLastCommittedEntry()->GetPageType() != + PAGE_TYPE_NORMAL) { + return std::make_pair( + false, blink::mojom::PortalActivateResult::kRejectedDueToErrorInPortal); + } + + // If a navigation in the main frame is occurring, stop it if possible and + // reject the activation if it's too late or if an ongoing navigation takes + // precedence. There are a few cases here: + // - a different RenderFrameHost has been assigned to the FrameTreeNode + // - the same RenderFrameHost is being used, but it is committing a navigation + // - the FrameTreeNode holds a navigation request that can't turn back but has + // not yet been handed off to a RenderFrameHost + FrameTreeNode* outer_root_node = owner_render_frame_host_->frame_tree_node(); + NavigationRequest* outer_navigation = outer_root_node->navigation_request(); + const bool has_user_gesture = + owner_render_frame_host_->HasTransientUserActivation(); + + // WILL_PROCESS_RESPONSE is slightly early: it happens + // immediately before READY_TO_COMMIT (unless it's deferred), but + // WILL_PROCESS_RESPONSE is easier to hook for tests using a + // NavigationThrottle. + if (owner_render_frame_host_->HasPendingCommitNavigation() || + (outer_navigation && + outer_navigation->state() >= NavigationRequest::WILL_PROCESS_RESPONSE) || + Navigator::ShouldIgnoreIncomingRendererRequest(outer_navigation, + has_user_gesture)) { + return std::make_pair(false, blink::mojom::PortalActivateResult:: + kRejectedDueToPredecessorNavigation); + } + return std::make_pair(true, + blink::mojom::PortalActivateResult::kAbortedDueToBug); +} + +void Portal::ActivateImpl(blink::TransferableMessage data, + base::TimeTicks activation_time, + ActivateCallback callback) { + WebContentsImpl* outer_contents = GetPortalHostContents(); + WebContentsDelegate* delegate = outer_contents->GetDelegate(); + + is_activating_ = false; + + bool can_activate; + blink::mojom::PortalActivateResult activate_error; + std::tie(can_activate, activate_error) = CanActivate(); + if (!can_activate) { + outer_contents->GetDelegate()->UpdateInspectedWebContentsIfNecessary( + portal_contents_.get(), outer_contents, base::DoNothing()); + std::move(callback).Run(activate_error); + return; + } + + FrameTreeNode* outer_root_node = owner_render_frame_host_->frame_tree_node(); + outer_root_node->navigator().CancelNavigation(outer_root_node); + + DCHECK(!is_closing_) << "Portal should not be shutting down when contents " + "ownership is yielded"; + + std::unique_ptr<WebContents> successor_contents; + + if (portal_contents_->GetOuterWebContents()) { + FrameTreeNode* outer_frame_tree_node = FrameTreeNode::GloballyFindByID( + portal_contents_->GetOuterDelegateFrameTreeNodeId()); + outer_frame_tree_node->RemoveObserver(this); + successor_contents = portal_contents_->DetachFromOuterWebContents(); + owner_render_frame_host_->RemoveChild(outer_frame_tree_node); + } else { + // Portals created for predecessor pages during activation may not be + // attached to an outer WebContents, and may not have an outer frame tree + // node created (i.e. CreateProxyAndAttachPortal isn't called). In this + // case, we can skip a few of the detachment steps above. + for (auto& render_view_host : + portal_contents_->GetFrameTree()->render_view_hosts()) { + CreatePortalRenderWidgetHostView(portal_contents_.get(), + render_view_host.second); + } + successor_contents = portal_contents_.ReleaseOwnership(); + } + DCHECK(!portal_contents_.OwnsContents()); + + // This assumes that the delegate keeps the new contents alive long enough to + // notify it of activation, at least. + WebContentsImpl* successor_contents_raw = + static_cast<WebContentsImpl*>(successor_contents.get()); + + auto* outer_contents_main_frame_view = static_cast<RenderWidgetHostViewBase*>( + outer_contents->GetMainFrame()->GetView()); + DCHECK(!outer_contents->GetPendingMainFrame()); + auto* portal_contents_main_frame_view = + static_cast<RenderWidgetHostViewBase*>( + successor_contents_raw->GetMainFrame()->GetView()); + + std::vector<std::unique_ptr<ui::TouchEvent>> touch_events; + + if (outer_contents_main_frame_view) { + // Take fallback contents from previous WebContents so that the activation + // is smooth without flashes. + portal_contents_main_frame_view->TakeFallbackContentFrom( + outer_contents_main_frame_view); + touch_events = + outer_contents_main_frame_view->ExtractAndCancelActiveTouches(); + FlushTouchEventQueues(outer_contents_main_frame_view->host()); + } + + TakeHistoryForActivation(successor_contents_raw, outer_contents); + + devtools_instrumentation::PortalActivated(outer_contents->GetMainFrame()); + successor_contents_raw->set_portal(nullptr); + + std::unique_ptr<WebContents> predecessor_web_contents = + delegate->ActivatePortalWebContents(outer_contents, + std::move(successor_contents)); + DCHECK_EQ(predecessor_web_contents.get(), outer_contents); + + if (outer_contents_main_frame_view) { + portal_contents_main_frame_view->TransferTouches(touch_events); + // Takes ownership of SyntheticGestureController from the predecessor's + // RenderWidgetHost. This allows the controller to continue sending events + // to the new RenderWidgetHostView. + portal_contents_main_frame_view->host()->TakeSyntheticGestureController( + outer_contents_main_frame_view->host()); + outer_contents_main_frame_view->Destroy(); + } + + // These pointers are cleared so that they don't dangle in the event this + // object isn't immediately deleted. It isn't done sooner because + // ActivatePortalWebContents misbehaves if the WebContents doesn't appear to + // be a portal at that time. + portal_contents_.Clear(); + + mojo::PendingAssociatedRemote<blink::mojom::Portal> pending_portal; + auto portal_receiver = pending_portal.InitWithNewEndpointAndPassReceiver(); + mojo::PendingAssociatedRemote<blink::mojom::PortalClient> pending_client; + auto client_receiver = pending_client.InitWithNewEndpointAndPassReceiver(); + + RenderFrameHostImpl* successor_main_frame = + successor_contents_raw->GetMainFrame(); + auto predecessor = std::make_unique<Portal>( + successor_main_frame, std::move(predecessor_web_contents)); + predecessor->Bind(std::move(portal_receiver), std::move(pending_client)); + successor_main_frame->OnPortalActivated( + std::move(predecessor), std::move(pending_portal), + std::move(client_receiver), std::move(data), std::move(callback)); + + // Notifying of activation happens later than ActivatePortalWebContents so + // that it is observed after predecessor_web_contents has been moved into a + // portal. + DCHECK(outer_contents->IsPortal()); + successor_contents_raw->DidActivatePortal(outer_contents, activation_time); +} + Portal::WebContentsHolder::WebContentsHolder(Portal* portal) : portal_(portal) {}
diff --git a/content/browser/portal/portal.h b/content/browser/portal/portal.h index a5fbaa6..f6192f4 100644 --- a/content/browser/portal/portal.h +++ b/content/browser/portal/portal.h
@@ -191,6 +191,11 @@ void SetPortalContents(std::unique_ptr<WebContents> web_contents); + std::pair<bool, blink::mojom::PortalActivateResult> CanActivate(); + void ActivateImpl(blink::TransferableMessage data, + base::TimeTicks activation_time, + ActivateCallback callback); + RenderFrameHostImpl* owner_render_frame_host_; // Uniquely identifies the portal, this token is used by the browser process @@ -214,9 +219,14 @@ // Set when |Close| is called. Destruction will occur shortly thereafter. bool is_closing_ = false; + // Set when portal is activating. + bool is_activating_ = false; + // Another implementation of blink::mojom::Portal to bind instead. // For use in testing only. std::unique_ptr<blink::mojom::Portal> interceptor_; + + base::WeakPtrFactory<Portal> weak_factory_{this}; }; } // namespace content
diff --git a/content/browser/portal/portal_browsertest.cc b/content/browser/portal/portal_browsertest.cc index aa58c907..8f387e2 100644 --- a/content/browser/portal/portal_browsertest.cc +++ b/content/browser/portal/portal_browsertest.cc
@@ -2172,6 +2172,80 @@ EXPECT_FALSE(download_observer.AwaitDownload()); } +// The following tests check code paths that won't be hit on Android as we +// do not create DevTools windows on Android. +#if !defined(OS_ANDROID) +IN_PROC_BROWSER_TEST_F(PortalBrowserTest, CallActivateOnTwoPortals) { + EXPECT_TRUE(NavigateToURL( + shell(), embedded_test_server()->GetURL("portal.test", "/title1.html"))); + WebContentsImpl* web_contents_impl = + static_cast<WebContentsImpl*>(shell()->web_contents()); + RenderFrameHostImpl* main_frame = web_contents_impl->GetMainFrame(); + shell()->ShowDevTools(); + + GURL url_a = embedded_test_server()->GetURL("a.com", "/title1.html"); + Portal* portal_a = CreatePortalToUrl(web_contents_impl, url_a); + GURL url_b = embedded_test_server()->GetURL("b.com", "/title1.html"); + Portal* portal_b = CreatePortalToUrl(web_contents_impl, url_b); + + PortalInterceptorForTesting* portal_interceptor = + PortalInterceptorForTesting::From(portal_a); + // Hijacks navigate request and calls Activate on both portals. + portal_interceptor->SetNavigateCallback(base::BindRepeating( + [](Portal* portal_a, Portal* portal_b, const GURL&, + blink::mojom::ReferrerPtr, + blink::mojom::Portal::NavigateCallback callback) { + portal_a->Activate(blink::TransferableMessage(), base::TimeTicks::Now(), + base::DoNothing()); + portal_b->Activate(blink::TransferableMessage(), base::TimeTicks::Now(), + base::DoNothing()); + std::move(callback).Run(); + }, + portal_a, portal_b)); + + RenderProcessHostBadIpcMessageWaiter rph_kill_waiter( + main_frame->GetProcess()); + GURL dummy_url = embedded_test_server()->GetURL("c.com", "/title1.html"); + ExecuteScriptAsync( + main_frame, + JsReplace("document.querySelector('portal').src = $1", dummy_url)); + EXPECT_EQ(bad_message::RPH_MOJO_PROCESS_ERROR, rph_kill_waiter.Wait()); +} + +IN_PROC_BROWSER_TEST_F(PortalBrowserTest, CallActivateTwice) { + EXPECT_TRUE(NavigateToURL( + shell(), embedded_test_server()->GetURL("portal.test", "/title1.html"))); + WebContentsImpl* web_contents_impl = + static_cast<WebContentsImpl*>(shell()->web_contents()); + RenderFrameHostImpl* main_frame = web_contents_impl->GetMainFrame(); + shell()->ShowDevTools(); + + GURL url = embedded_test_server()->GetURL("a.com", "/title1.html"); + Portal* portal = CreatePortalToUrl(web_contents_impl, url); + PortalInterceptorForTesting* portal_interceptor = + PortalInterceptorForTesting::From(portal); + // Hijacks navigate request and calls Activate twice instead. + portal_interceptor->SetNavigateCallback(base::BindRepeating( + [](Portal* portal, const GURL&, blink::mojom::ReferrerPtr, + blink::mojom::Portal::NavigateCallback callback) { + portal->Activate(blink::TransferableMessage(), base::TimeTicks::Now(), + base::DoNothing()); + portal->Activate(blink::TransferableMessage(), base::TimeTicks::Now(), + base::DoNothing()); + std::move(callback).Run(); + }, + portal)); + + RenderProcessHostBadIpcMessageWaiter rph_kill_waiter( + main_frame->GetProcess()); + GURL dummy_url = embedded_test_server()->GetURL("b.com", "/title1.html"); + ExecuteScriptAsync( + main_frame, + JsReplace("document.querySelector('portal').src = $1", dummy_url)); + EXPECT_EQ(bad_message::RPH_MOJO_PROCESS_ERROR, rph_kill_waiter.Wait()); +} +#endif + namespace { static constexpr struct {
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc index 7dcc21f6..c0b7c26 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -1897,7 +1897,8 @@ void RenderWidgetHostImpl::ShowContextMenuAtPoint( const gfx::Point& point, const ui::MenuSourceType source_type) { - GetAssociatedFrameWidget()->ShowContextMenu(source_type, point); + if (blink_frame_widget_) + blink_frame_widget_->ShowContextMenu(source_type, point); } RenderProcessHost::Priority RenderWidgetHostImpl::GetPriority() {
diff --git a/content/public/browser/web_contents_delegate.cc b/content/public/browser/web_contents_delegate.cc index 5631ce9..3c009a7 100644 --- a/content/public/browser/web_contents_delegate.cc +++ b/content/public/browser/web_contents_delegate.cc
@@ -341,6 +341,13 @@ return portal_contents; } +void WebContentsDelegate::UpdateInspectedWebContentsIfNecessary( + WebContents* old_contents, + WebContents* new_contents, + base::OnceCallback<void()> callback) { + std::move(callback).Run(); +} + bool WebContentsDelegate::ShouldShowStaleContentOnEviction( WebContents* source) { return false;
diff --git a/content/public/browser/web_contents_delegate.h b/content/public/browser/web_contents_delegate.h index 61ed37a5..61f786b 100644 --- a/content/public/browser/web_contents_delegate.h +++ b/content/public/browser/web_contents_delegate.h
@@ -712,6 +712,15 @@ WebContents* predecessor_contents, std::unique_ptr<WebContents> portal_contents); + // If |old_contents| is being inspected by a DevTools window, it updates the + // window to inspect |new_contents| instead and calls |callback| after it + // finishes asynchronously. If no window is present, or no update is + // necessary, |callback| is run synchronously (immediately on the same stack). + virtual void UpdateInspectedWebContentsIfNecessary( + WebContents* old_contents, + WebContents* new_contents, + base::OnceCallback<void()> callback); + // Returns true if the widget's frame content needs to be stored before // eviction and displayed until a new frame is generated. If false, a white // solid color is displayed instead.
diff --git a/content/shell/browser/shell.cc b/content/shell/browser/shell.cc index b2ea0f0..88fa09bd 100644 --- a/content/shell/browser/shell.cc +++ b/content/shell/browser/shell.cc
@@ -600,11 +600,6 @@ DCHECK_EQ(predecessor_contents, web_contents_.get()); portal_contents->SetDelegate(this); web_contents_->SetDelegate(nullptr); - for (auto* shell_devtools_bindings : - ShellDevToolsBindings::GetInstancesForWebContents( - predecessor_contents)) { - shell_devtools_bindings->UpdateInspectedWebContents(portal_contents.get()); - } std::swap(web_contents_, portal_contents); g_platform->SetContents(this); g_platform->SetAddressBarURL(this, web_contents_->GetVisibleURL()); @@ -612,6 +607,34 @@ return portal_contents; } +namespace { +class PendingCallback : public base::RefCounted<PendingCallback> { + public: + explicit PendingCallback(base::OnceCallback<void()> cb) + : callback_(std::move(cb)) {} + + private: + friend class base::RefCounted<PendingCallback>; + ~PendingCallback() { std::move(callback_).Run(); } + base::OnceCallback<void()> callback_; +}; +} // namespace + +void Shell::UpdateInspectedWebContentsIfNecessary( + content::WebContents* old_contents, + content::WebContents* new_contents, + base::OnceCallback<void()> callback) { + scoped_refptr<PendingCallback> pending_callback = + base::MakeRefCounted<PendingCallback>(std::move(callback)); + for (auto* shell_devtools_bindings : + ShellDevToolsBindings::GetInstancesForWebContents(old_contents)) { + shell_devtools_bindings->UpdateInspectedWebContents( + new_contents, + base::BindOnce(base::DoNothing::Once<scoped_refptr<PendingCallback>>(), + pending_callback)); + } +} + bool Shell::ShouldAllowRunningInsecureContent(WebContents* web_contents, bool allowed_per_prefs, const url::Origin& origin,
diff --git a/content/shell/browser/shell.h b/content/shell/browser/shell.h index 1c0ce7d5..871f642f 100644 --- a/content/shell/browser/shell.h +++ b/content/shell/browser/shell.h
@@ -161,9 +161,14 @@ RenderWidgetHost* render_widget_host, base::RepeatingClosure hang_monitor_restarter) override; void ActivateContents(WebContents* contents) override; + std::unique_ptr<content::WebContents> ActivatePortalWebContents( content::WebContents* predecessor_contents, std::unique_ptr<content::WebContents> portal_contents) override; + void UpdateInspectedWebContentsIfNecessary( + content::WebContents* old_contents, + content::WebContents* new_contents, + base::OnceCallback<void()> callback) override; bool ShouldAllowRunningInsecureContent(content::WebContents* web_contents, bool allowed_per_prefs, const url::Origin& origin,
diff --git a/content/shell/browser/shell_devtools_bindings.cc b/content/shell/browser/shell_devtools_bindings.cc index e52411eb..d939f35 100644 --- a/content/shell/browser/shell_devtools_bindings.cc +++ b/content/shell/browser/shell_devtools_bindings.cc
@@ -234,13 +234,17 @@ } void ShellDevToolsBindings::UpdateInspectedWebContents( - WebContents* new_contents) { + WebContents* new_contents, + base::OnceCallback<void()> callback) { inspected_contents_ = new_contents; if (!agent_host_) return; AttachInternal(); - CallClientFunction("DevToolsAPI.reattachMainTarget", nullptr, nullptr, - nullptr); + CallClientFunction( + "DevToolsAPI.reattachMainTarget", nullptr, nullptr, nullptr, + base::BindOnce([](base::OnceCallback<void()> callback, + base::Value) { std::move(callback).Run(); }, + std::move(callback))); } void ShellDevToolsBindings::WebContentsDestroyed() { @@ -405,10 +409,12 @@ } } -void ShellDevToolsBindings::CallClientFunction(const std::string& function_name, - const base::Value* arg1, - const base::Value* arg2, - const base::Value* arg3) { +void ShellDevToolsBindings::CallClientFunction( + const std::string& function_name, + const base::Value* arg1, + const base::Value* arg2, + const base::Value* arg3, + base::OnceCallback<void(base::Value)> cb) { std::string javascript = function_name + "("; if (arg1) { std::string json; @@ -425,7 +431,7 @@ } javascript.append(");"); web_contents()->GetMainFrame()->ExecuteJavaScriptForTests( - base::UTF8ToUTF16(javascript), base::NullCallback()); + base::UTF8ToUTF16(javascript), std::move(cb)); } void ShellDevToolsBindings::SendMessageAck(int request_id,
diff --git a/content/shell/browser/shell_devtools_bindings.h b/content/shell/browser/shell_devtools_bindings.h index 09c3b6f..6d9c5394 100644 --- a/content/shell/browser/shell_devtools_bindings.h +++ b/content/shell/browser/shell_devtools_bindings.h
@@ -51,12 +51,15 @@ void InspectElementAt(int x, int y); virtual void Attach(); - void UpdateInspectedWebContents(WebContents* new_contents); + void UpdateInspectedWebContents(WebContents* new_contents, + base::OnceCallback<void()> callback); - void CallClientFunction(const std::string& function_name, - const base::Value* arg1, - const base::Value* arg2, - const base::Value* arg3); + void CallClientFunction( + const std::string& function_name, + const base::Value* arg1, + const base::Value* arg2, + const base::Value* arg3, + base::OnceCallback<void(base::Value)> cb = base::NullCallback()); ~ShellDevToolsBindings() override; WebContents* inspected_contents() { return inspected_contents_; }
diff --git a/crypto/nss_util_chromeos.cc b/crypto/nss_util_chromeos.cc index d6ddeb7..1b52f16 100644 --- a/crypto/nss_util_chromeos.cc +++ b/crypto/nss_util_chromeos.cc
@@ -16,9 +16,9 @@ #include <map> #include <memory> #include <utility> -#include <vector> #include "base/bind.h" +#include "base/callback_list.h" #include "base/debug/stack_trace.h" #include "base/files/file_path.h" #include "base/files/file_util.h" @@ -49,9 +49,11 @@ class ChromeOSUserData { public: + using SlotReadyCallback = base::OnceCallback<void(ScopedPK11Slot)>; + explicit ChromeOSUserData(ScopedPK11Slot public_slot) - : public_slot_(std::move(public_slot)), - private_slot_initialization_started_(false) {} + : public_slot_(std::move(public_slot)) {} + ~ChromeOSUserData() { if (public_slot_) { SECStatus status = SECMOD_CloseUserDB(public_slot_.get()); @@ -65,26 +67,28 @@ : nullptr); } - ScopedPK11Slot GetPrivateSlot( - base::OnceCallback<void(ScopedPK11Slot)> callback) { + ScopedPK11Slot GetPrivateSlot(SlotReadyCallback callback) { if (private_slot_) return ScopedPK11Slot(PK11_ReferenceSlot(private_slot_.get())); - if (!callback.is_null()) - tpm_ready_callback_list_.push_back(std::move(callback)); + if (!callback.is_null()) { + // Callback lists cannot hold callbacks that take move-only args, since + // Notify()ing such a list would move the arg into the first callback, + // leaving it null or unspecified for remaining callbacks. Instead, adapt + // the provided callbacks to accept a raw pointer, which can be copied, + // and then wrap in a separate scoping object for each callback. + tpm_ready_callback_list_.AddUnsafe(base::BindOnce( + [](SlotReadyCallback callback, PK11SlotInfo* info) { + std::move(callback).Run(ScopedPK11Slot(PK11_ReferenceSlot(info))); + }, + std::move(callback))); + } return ScopedPK11Slot(); } void SetPrivateSlot(ScopedPK11Slot private_slot) { DCHECK(!private_slot_); private_slot_ = std::move(private_slot); - - SlotReadyCallbackList callback_list; - callback_list.swap(tpm_ready_callback_list_); - for (SlotReadyCallbackList::iterator i = callback_list.begin(); - i != callback_list.end(); ++i) { - std::move(*i).Run( - ScopedPK11Slot(PK11_ReferenceSlot(private_slot_.get()))); - } + tpm_ready_callback_list_.Notify(private_slot_.get()); } bool private_slot_initialization_started() const { @@ -96,13 +100,13 @@ } private: + using SlotReadyCallbackList = base::OnceCallbackList<void(PK11SlotInfo*)>; + ScopedPK11Slot public_slot_; ScopedPK11Slot private_slot_; - bool private_slot_initialization_started_; + bool private_slot_initialization_started_ = false; - typedef std::vector<base::OnceCallback<void(ScopedPK11Slot)>> - SlotReadyCallbackList; SlotReadyCallbackList tpm_ready_callback_list_; }; @@ -271,14 +275,7 @@ std::move(callback).Run(!!tpm_slot_); } - void RunAndClearTPMReadyCallbackList() { - TPMReadyCallbackList callback_list; - callback_list.swap(tpm_ready_callback_list_); - for (TPMReadyCallbackList::iterator i = callback_list.begin(); - i != callback_list.end(); ++i) { - std::move(*i).Run(); - } - } + void RunAndClearTPMReadyCallbackList() { tpm_ready_callback_list_.Notify(); } bool IsTPMTokenReady(base::OnceClosure callback) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); @@ -286,7 +283,7 @@ return true; if (!callback.is_null()) - tpm_ready_callback_list_.push_back(std::move(callback)); + tpm_ready_callback_list_.AddUnsafe(std::move(callback)); return false; } @@ -515,7 +512,7 @@ bool tpm_token_enabled_for_nss_ = false; bool initializing_tpm_token_ = false; - using TPMReadyCallbackList = std::vector<base::OnceClosure>; + using TPMReadyCallbackList = base::OnceClosureList; TPMReadyCallbackList tpm_ready_callback_list_; SECMODModule* chaps_module_ = nullptr; crypto::ScopedPK11Slot tpm_slot_;
diff --git a/docs/enterprise/description_guidelines.md b/docs/enterprise/description_guidelines.md index 575dbdb..8e14c0f8 100644 --- a/docs/enterprise/description_guidelines.md +++ b/docs/enterprise/description_guidelines.md
@@ -3,6 +3,7 @@ * Chrome: `<ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph>` * Chrome OS: `<ph name="PRODUCT_OS_NAME">$2<ex>Google Chrome OS</ex></ph>` +* Chrome Browser Cloud Management: `<ph name="CHROME_BROWSER_CLOUSE_MANAGEMENT_NAME">Chrome Browser Cloud Management</ph>` * Linux: `<ph name="LINUX_OS_NAME">Linux</ph>` * Internet Explorer: `<ph name="IE_PRODUCT_NAME">Internet® Explorer®</ph>` * Google Cast: `<ph name="PRODUCT_NAME">Google Cast</ph>`
diff --git a/extensions/browser/api/web_request/web_request_time_tracker.cc b/extensions/browser/api/web_request/web_request_time_tracker.cc index 298a509..1ab7771 100644 --- a/extensions/browser/api/web_request/web_request_time_tracker.cc +++ b/extensions/browser/api/web_request/web_request_time_tracker.cc
@@ -5,6 +5,7 @@ #include "extensions/browser/api/web_request/web_request_time_tracker.h" #include "base/metrics/histogram_macros.h" +#include "base/numerics/safe_conversions.h" ExtensionWebRequestTimeTracker::RequestTimeLog::RequestTimeLog() = default; ExtensionWebRequestTimeTracker::RequestTimeLog::~RequestTimeLog() = default; @@ -65,9 +66,9 @@ // extra delay the extension adds is likely to be noise. constexpr auto kMinRequestTimeToCare = base::TimeDelta::FromMilliseconds(10); if (request_duration >= kMinRequestTimeToCare) { - double percentage = log.block_duration / request_duration; - UMA_HISTOGRAM_PERCENTAGE("Extensions.NetworkDelayPercentage", - static_cast<int>(100 * percentage)); + const int percentage = + base::ClampRound(log.block_duration / request_duration * 100); + UMA_HISTOGRAM_PERCENTAGE("Extensions.NetworkDelayPercentage", percentage); } }
diff --git a/extensions/renderer/extension_throttle_simulation_unittest.cc b/extensions/renderer/extension_throttle_simulation_unittest.cc index 5d46854..ad4caff 100644 --- a/extensions/renderer/extension_throttle_simulation_unittest.cc +++ b/extensions/renderer/extension_throttle_simulation_unittest.cc
@@ -393,14 +393,10 @@ } void PerformAction() override { - TimeDelta effective_delay = time_between_requests_; - TimeDelta current_jitter = TimeDelta::FromMilliseconds( - request_jitter_.InMilliseconds() * base::RandDouble()); - if (base::RandInt(0, 1)) { - effective_delay -= current_jitter; - } else { - effective_delay += current_jitter; - } + const TimeDelta current_jitter = request_jitter_ * base::RandDouble(); + const TimeDelta effective_delay = + time_between_requests_ + + (base::RandInt(0, 1) ? -current_jitter : current_jitter); if (throttler_entry_->ImplGetTimeNow() - time_of_last_attempt_ > effective_delay) {
diff --git a/gin/v8_platform.cc b/gin/v8_platform.cc index 7094260..1d5158d 100644 --- a/gin/v8_platform.cc +++ b/gin/v8_platform.cc
@@ -283,6 +283,7 @@ void NotifyConcurrencyIncrease() override { delegate_->NotifyConcurrencyIncrease(); } + uint8_t GetTaskId() override { return delegate_->GetTaskId(); } private: base::JobDelegate* delegate_; @@ -303,7 +304,7 @@ } void Join() override { handle_.Join(); } void Cancel() override { handle_.Cancel(); } - + bool IsCompleted() override { return handle_.IsCompleted(); } bool IsRunning() override { return !!handle_; } private: @@ -507,8 +508,8 @@ }, base::Unretained(job_task.get())), base::BindRepeating( - [](v8::JobTask* job_task, size_t /*worker_count*/) { - return job_task->GetMaxConcurrency(); + [](v8::JobTask* job_task, size_t worker_count) { + return job_task->GetMaxConcurrency(worker_count); }, base::Unretained(job_task.get())));
diff --git a/infra/config/generated/cr-buildbucket.cfg b/infra/config/generated/cr-buildbucket.cfg index 8905ba3..a90bf88 100644 --- a/infra/config/generated/cr-buildbucket.cfg +++ b/infra/config/generated/cr-buildbucket.cfg
@@ -918,35 +918,6 @@ } } builders { - name: "Android WebView P Blink-CORS FYI (rel)" - swarming_host: "chromium-swarm.appspot.com" - swarming_tags: "vpython:native-python-wrapper" - dimensions: "builderless:1" - dimensions: "cores:8" - dimensions: "cpu:x86-64" - dimensions: "os:Ubuntu-16.04" - dimensions: "pool:luci.chromium.ci" - dimensions: "ssd:0" - exe { - cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" - cipd_version: "refs/heads/master" - cmd: "recipes" - } - properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.android.fyi\",\"recipe\":\"chromium\"}" - execution_timeout_secs: 10800 - build_numbers: YES - service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com" - resultdb { - enable: true - bq_exports { - project: "luci-resultdb" - dataset: "chromium" - table: "ci_test_results" - test_results {} - } - } - } - builders { name: "Android WebView P FYI (rel)" swarming_host: "chromium-swarm.appspot.com" swarming_tags: "vpython:native-python-wrapper" @@ -10299,35 +10270,6 @@ } } builders { - name: "linux-blink-cors-rel" - swarming_host: "chromium-swarm.appspot.com" - swarming_tags: "vpython:native-python-wrapper" - dimensions: "builderless:1" - dimensions: "cores:8" - dimensions: "cpu:x86-64" - dimensions: "os:Ubuntu-16.04" - dimensions: "pool:luci.chromium.ci" - dimensions: "ssd:0" - exe { - cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" - cipd_version: "refs/heads/master" - cmd: "recipes" - } - properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.linux\",\"recipe\":\"chromium\"}" - execution_timeout_secs: 10800 - build_numbers: YES - service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com" - resultdb { - enable: true - bq_exports { - project: "luci-resultdb" - dataset: "chromium" - table: "ci_test_results" - test_results {} - } - } - } - builders { name: "linux-blink-heap-concurrent-marking-tsan-rel" swarming_host: "chromium-swarm.appspot.com" swarming_tags: "vpython:native-python-wrapper"
diff --git a/infra/config/generated/luci-milo.cfg b/infra/config/generated/luci-milo.cfg index 358ef2ae..b224dfa4 100644 --- a/infra/config/generated/luci-milo.cfg +++ b/infra/config/generated/luci-milo.cfg
@@ -231,11 +231,6 @@ short_name: "gcc" } builders { - name: "buildbucket/luci.chromium.ci/linux-blink-cors-rel" - category: "chromium.linux|release" - short_name: "crs" - } - builders { name: "buildbucket/luci.chromium.ci/Deterministic Linux" category: "chromium.linux|release" short_name: "det" @@ -6105,11 +6100,6 @@ short_name: "p-x86-rel" } builders { - name: "buildbucket/luci.chromium.ci/Android WebView P Blink-CORS FYI (rel)" - category: "webview" - short_name: "cors" - } - builders { name: "buildbucket/luci.chromium.ci/Android WebView P FYI (rel)" category: "webview" short_name: "p-rel" @@ -10063,21 +10053,11 @@ short_name: "bfc" } builders { - name: "buildbucket/luci.chromium.ci/linux-blink-cors-rel" - category: "week15a|linux" - short_name: "oorcors" - } - builders { name: "buildbucket/luci.chromium.ci/linux-fieldtrial-rel" category: "week15a|linux" short_name: "field" } builders { - name: "buildbucket/luci.chromium.ci/Android WebView P Blink-CORS FYI (rel)" - category: "week15b|android|webview p" - short_name: "oorcors" - } - builders { name: "buildbucket/luci.chromium.ci/android-archive-rel" category: "week15b|android|archive" short_name: "rel" @@ -11835,11 +11815,6 @@ short_name: "gcc" } builders { - name: "buildbucket/luci.chromium.ci/linux-blink-cors-rel" - category: "release" - short_name: "crs" - } - builders { name: "buildbucket/luci.chromium.ci/Deterministic Linux" category: "release" short_name: "det"
diff --git a/infra/config/generated/luci-notify.cfg b/infra/config/generated/luci-notify.cfg index b26e2ed..a5d64e08 100644 --- a/infra/config/generated/luci-notify.cfg +++ b/infra/config/generated/luci-notify.cfg
@@ -2819,32 +2819,6 @@ } notifiers { notifications { - on_occurrence: FAILURE - failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update" - email { - rotation_urls: "https://chrome-ops-rotation-proxy.appspot.com/current/oncallator:chrome-build-sheriff" - } - template: "tree_closure_email_template" - } - notifications { - on_occurrence: FAILURE - failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update" - email { - recipients: "thomasanderson@chromium.org" - } - } - builders { - bucket: "ci" - name: "linux-blink-cors-rel" - repository: "https://chromium.googlesource.com/chromium/src" - } - tree_closers { - tree_status_host: "chromium-status.appspot.com" - failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update" - } -} -notifiers { - notifications { on_new_status: FAILURE email { recipients: "mlippautz+fyi-bots@chromium.org"
diff --git a/infra/config/generated/luci-scheduler.cfg b/infra/config/generated/luci-scheduler.cfg index 325de7a..c61438a 100644 --- a/infra/config/generated/luci-scheduler.cfg +++ b/infra/config/generated/luci-scheduler.cfg
@@ -367,16 +367,6 @@ } } job { - id: "Android WebView P Blink-CORS FYI (rel)" - realm: "ci" - acl_sets: "ci" - buildbucket { - server: "cr-buildbucket.appspot.com" - bucket: "luci.chromium.ci" - builder: "Android WebView P Blink-CORS FYI (rel)" - } -} -job { id: "Android WebView P FYI (rel)" realm: "ci" acl_sets: "ci" @@ -5063,16 +5053,6 @@ } } job { - id: "ci-Android WebView P Blink-CORS FYI (rel)" - realm: "ci" - acl_sets: "ci" - buildbucket { - server: "cr-buildbucket.appspot.com" - bucket: "luci.chromium.ci" - builder: "Android WebView P Blink-CORS FYI (rel)" - } -} -job { id: "ci-Android WebView P FYI (rel)" realm: "ci" acl_sets: "ci" @@ -8783,16 +8763,6 @@ } } job { - id: "ci-linux-blink-cors-rel" - realm: "ci" - acl_sets: "ci" - buildbucket { - server: "cr-buildbucket.appspot.com" - bucket: "luci.chromium.ci" - builder: "linux-blink-cors-rel" - } -} -job { id: "ci-linux-blink-heap-concurrent-marking-tsan-rel" realm: "ci" acl_sets: "ci" @@ -11819,16 +11789,6 @@ } } job { - id: "linux-blink-cors-rel" - realm: "ci" - acl_sets: "ci" - buildbucket { - server: "cr-buildbucket.appspot.com" - bucket: "luci.chromium.ci" - builder: "linux-blink-cors-rel" - } -} -job { id: "linux-blink-heap-concurrent-marking-tsan-rel" realm: "ci" acl_sets: "ci" @@ -12849,7 +12809,6 @@ triggers: "Android FYI dEQP Release (Nexus 5X)" triggers: "ci-Android Release (Nexus 5X)" triggers: "Android WebLayer P FYI (rel)" - triggers: "Android WebView P Blink-CORS FYI (rel)" triggers: "Android WebView P FYI (rel)" triggers: "ci-Android arm Builder (dbg)" triggers: "ci-Android arm64 Builder (dbg)" @@ -13059,7 +13018,6 @@ triggers: "linux-ash-chromium-builder-fyi-rel" triggers: "linux-bfcache-rel" triggers: "linux-blink-animation-use-time-delta" - triggers: "linux-blink-cors-rel" triggers: "linux-blink-heap-concurrent-marking-tsan-rel" triggers: "linux-blink-heap-verification" triggers: "ci-linux-chromeos-dbg"
diff --git a/infra/config/subprojects/chromium/master-only/ci.star b/infra/config/subprojects/chromium/master-only/ci.star index d64dea2..ef5a5bbc 100644 --- a/infra/config/subprojects/chromium/master-only/ci.star +++ b/infra/config/subprojects/chromium/master-only/ci.star
@@ -362,14 +362,6 @@ ) ci.android_fyi_builder( - name = "Android WebView P Blink-CORS FYI (rel)", - console_view_entry = ci.console_view_entry( - category = "webview", - short_name = "cors", - ), -) - -ci.android_fyi_builder( name = "Android WebView P FYI (rel)", console_view_entry = ci.console_view_entry( category = "webview", @@ -2922,16 +2914,6 @@ ) ci.linux_builder( - name = "linux-blink-cors-rel", - console_view_entry = ci.console_view_entry( - category = "release", - short_name = "crs", - ), - goma_jobs = None, - main_console_view = "main", -) - -ci.linux_builder( name = "linux-gcc-rel", console_view_entry = ci.console_view_entry( category = "release",
diff --git a/infra/config/subprojects/goma/consoles/chromium.goma.migration.star b/infra/config/subprojects/goma/consoles/chromium.goma.migration.star index b5031da841..9e48043 100644 --- a/infra/config/subprojects/goma/consoles/chromium.goma.migration.star +++ b/infra/config/subprojects/goma/consoles/chromium.goma.migration.star
@@ -711,21 +711,11 @@ short_name = "bfc", ), luci.console_view_entry( - builder = "ci/linux-blink-cors-rel", - category = "week15a|linux", - short_name = "oorcors", - ), - luci.console_view_entry( builder = "ci/linux-fieldtrial-rel", category = "week15a|linux", short_name = "field", ), luci.console_view_entry( - builder = "ci/Android WebView P Blink-CORS FYI (rel)", - category = "week15b|android|webview p", - short_name = "oorcors", - ), - luci.console_view_entry( builder = "ci/android-archive-rel", category = "week15b|android|archive", short_name = "rel",
diff --git a/ios/chrome/app/strings/ios_chromium_strings.grd b/ios/chrome/app/strings/ios_chromium_strings.grd index 7e8a11c5..456eefe1 100644 --- a/ios/chrome/app/strings/ios_chromium_strings.grd +++ b/ios/chrome/app/strings/ios_chromium_strings.grd
@@ -347,7 +347,7 @@ Chromium couldn't check all passwords. Try again tomorrow or <ph name="BEGIN_LINK">BEGIN_LINK</ph>check passwords in your Google Account.<ph name="END_LINK">END_LINK</ph> </message> <message name="IDS_IOS_PASSWORD_CHECK_ERROR_OTHER" desc="Text inside popover which is shown when the user wants to see detailed information about the error. [iOS only]" meaning="Password check failed due to specific reason (out of memory)."> - Chromium couldn't check all passwords. Try again. + Chromium couldn't check all passwords. Try again later. </message> <message name="IDS_IOS_CHANGE_COMPROMISED_PASSWORD_DESCRIPTION" desc="Text inside Password Details screen shown when password was compromised. [iOS only]" meaning="Text which explains the user that current password is compromised and it should be changed."> Your password was exposed in a data breach. Chromium recommends changing the password now.
diff --git a/ios/chrome/app/strings/ios_chromium_strings_grd/IDS_IOS_PASSWORD_CHECK_ERROR_OTHER.png.sha1 b/ios/chrome/app/strings/ios_chromium_strings_grd/IDS_IOS_PASSWORD_CHECK_ERROR_OTHER.png.sha1 index 23ae499c..e9256c15 100644 --- a/ios/chrome/app/strings/ios_chromium_strings_grd/IDS_IOS_PASSWORD_CHECK_ERROR_OTHER.png.sha1 +++ b/ios/chrome/app/strings/ios_chromium_strings_grd/IDS_IOS_PASSWORD_CHECK_ERROR_OTHER.png.sha1
@@ -1 +1 @@ -9f6db2c8b50b1ba8bb3a2ad70a2fdea2504d076e \ No newline at end of file +bfb0f0e85c3f699f1d75c9ff1d0a1a3b0acb304c \ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_google_chrome_strings.grd b/ios/chrome/app/strings/ios_google_chrome_strings.grd index fc0c231..3268b48e 100644 --- a/ios/chrome/app/strings/ios_google_chrome_strings.grd +++ b/ios/chrome/app/strings/ios_google_chrome_strings.grd
@@ -347,7 +347,7 @@ Chrome couldn't check all passwords. Try again tomorrow or <ph name="BEGIN_LINK">BEGIN_LINK</ph>check passwords in your Google Account.<ph name="END_LINK">END_LINK</ph> </message> <message name="IDS_IOS_PASSWORD_CHECK_ERROR_OTHER" desc="Text inside popover which is shown when the user wants to see detailed information about the error. [iOS only]" meaning="Password check failed due to specific reason (out of memory)."> - Chrome couldn't check all passwords. Try again. + Chrome couldn't check all passwords. Try again later. </message> <message name="IDS_IOS_CHANGE_COMPROMISED_PASSWORD_DESCRIPTION" desc="Text inside Password Details screen shown when password was compromised. [iOS only]" meaning="Text which explains the user that current password is compromised and it should be changed."> Your password was exposed in a data breach. Chrome recommends changing the password now.
diff --git a/ios/chrome/app/strings/ios_google_chrome_strings_grd/IDS_IOS_PASSWORD_CHECK_ERROR_OTHER.png.sha1 b/ios/chrome/app/strings/ios_google_chrome_strings_grd/IDS_IOS_PASSWORD_CHECK_ERROR_OTHER.png.sha1 index 557d3d8..dd032d3 100644 --- a/ios/chrome/app/strings/ios_google_chrome_strings_grd/IDS_IOS_PASSWORD_CHECK_ERROR_OTHER.png.sha1 +++ b/ios/chrome/app/strings/ios_google_chrome_strings_grd/IDS_IOS_PASSWORD_CHECK_ERROR_OTHER.png.sha1
@@ -1 +1 @@ -0ca0465f6571937f552166f15a26652f03be4e84 \ No newline at end of file +0bccc30dd7da0333087b7218153a3c202fbca7a9 \ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd index e8bc22e5..775757bb 100644 --- a/ios/chrome/app/strings/ios_strings.grd +++ b/ios/chrome/app/strings/ios_strings.grd
@@ -1932,7 +1932,7 @@ Cancel </message> <message name="IDS_IOS_CONFIRM_PASSWORD_DELETION" desc="Label of a confirmation dialogue button which allows the user to confirm deletion of a stored password. [Length: one line] [iOS only]"> - Delete + Delete Password </message> <message name="IDS_IOS_COOKIES_ALLOW_ALL" desc="Label that informs the user that no cookies are blocked"> Allow All
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_CONFIRM_PASSWORD_DELETION.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_CONFIRM_PASSWORD_DELETION.png.sha1 new file mode 100644 index 0000000..2e0c7dcc --- /dev/null +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_CONFIRM_PASSWORD_DELETION.png.sha1
@@ -0,0 +1 @@ +6e921ad4389bf3bf08fa6664f39c6f63ddf690be \ No newline at end of file
diff --git a/ios/chrome/browser/autofill/autofill_controller_unittest.mm b/ios/chrome/browser/autofill/autofill_controller_unittest.mm index e00b91d..651c6f5 100644 --- a/ios/chrome/browser/autofill/autofill_controller_unittest.mm +++ b/ios/chrome/browser/autofill/autofill_controller_unittest.mm
@@ -286,7 +286,9 @@ webStateList:NULL personalDataManager:NULL passwordStore:nullptr - appState:nil]; + appState:nil + securityAlertHandler:nil + reauthenticationModule:nil]; [accessory_mediator_ injectWebState:web_state()]; [accessory_mediator_ injectProvider:suggestion_controller_];
diff --git a/ios/chrome/browser/autofill/form_suggestion_controller_unittest.mm b/ios/chrome/browser/autofill/form_suggestion_controller_unittest.mm index d23dda6..f80c3d5 100644 --- a/ios/chrome/browser/autofill/form_suggestion_controller_unittest.mm +++ b/ios/chrome/browser/autofill/form_suggestion_controller_unittest.mm
@@ -74,11 +74,13 @@ [FormSuggestion suggestionWithValue:@"foo" displayDescription:nil icon:@"" - identifier:0], + identifier:0 + requiresReauth:NO], [FormSuggestion suggestionWithValue:@"bar" displayDescription:nil icon:@"" - identifier:1] + identifier:1 + requiresReauth:NO] ]; return [[TestSuggestionProvider alloc] initWithSuggestions:suggestions]; } @@ -185,8 +187,7 @@ received_suggestions_ = suggestions; }; [[[mock_consumer stub] andDo:mockShow] - showAccessorySuggestions:[OCMArg any] - suggestionClient:[OCMArg any]]; + showAccessorySuggestions:[OCMArg any]]; // Mock restore keyboard to verify cleanup. void (^mockRestore)(NSInvocation*) = ^(NSInvocation* invocation) { @@ -210,7 +211,9 @@ webStateList:NULL personalDataManager:NULL passwordStore:nullptr - appState:mock_app_state]; + appState:mock_app_state + securityAlertHandler:nil + reauthenticationModule:nil]; [accessory_mediator_ injectWebState:&test_web_state_]; [accessory_mediator_ injectProvider:suggestion_controller_]; @@ -377,11 +380,13 @@ [FormSuggestion suggestionWithValue:@"foo" displayDescription:nil icon:@"" - identifier:0], + identifier:0 + requiresReauth:NO], [FormSuggestion suggestionWithValue:@"bar" displayDescription:nil icon:@"" - identifier:1] + identifier:1 + requiresReauth:NO] ]; TestSuggestionProvider* provider1 = [[TestSuggestionProvider alloc] initWithSuggestions:suggestions]; @@ -424,7 +429,8 @@ [FormSuggestion suggestionWithValue:@"foo" displayDescription:nil icon:@"" - identifier:0], + identifier:0 + requiresReauth:NO], ]; TestSuggestionProvider* provider = [[TestSuggestionProvider alloc] initWithSuggestions:suggestions];
diff --git a/ios/chrome/browser/autofill/form_suggestion_label.h b/ios/chrome/browser/autofill/form_suggestion_label.h index 6b7d0e4..1f3ace1e 100644 --- a/ios/chrome/browser/autofill/form_suggestion_label.h +++ b/ios/chrome/browser/autofill/form_suggestion_label.h
@@ -5,19 +5,29 @@ #ifndef IOS_CHROME_BROWSER_AUTOFILL_FORM_SUGGESTION_LABEL_H_ #define IOS_CHROME_BROWSER_AUTOFILL_FORM_SUGGESTION_LABEL_H_ +// TODO(crbug.com/1115980): Move Autofill ui code to i/c/b/ui/autofill. + #import <UIKit/UIKit.h> @class FormSuggestion; -@protocol FormSuggestionClient; +@class FormSuggestionLabel; + +// Delegate for actions happening in FormSuggestionLabel. +@protocol FormSuggestionLabelDelegate + +// User tapped on the suggestion. +- (void)didTapFormSuggestionLabel:(FormSuggestionLabel*)formSuggestionLabel; + +@end // Class for Autofill suggestion in the customized keyboard. @interface FormSuggestionLabel : UIView -// Designated initializer. Initializes with |client| for |suggestion|. +// Designated initializer. Initializes with |delegate| for |suggestion|. - (instancetype)initWithSuggestion:(FormSuggestion*)suggestion index:(NSUInteger)index numSuggestions:(NSUInteger)numSuggestions - client:(id<FormSuggestionClient>)client + delegate:(id<FormSuggestionLabelDelegate>)delegate NS_DESIGNATED_INITIALIZER; - (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE;
diff --git a/ios/chrome/browser/autofill/form_suggestion_label.mm b/ios/chrome/browser/autofill/form_suggestion_label.mm index b1ca7b3..9ca2dba 100644 --- a/ios/chrome/browser/autofill/form_suggestion_label.mm +++ b/ios/chrome/browser/autofill/form_suggestion_label.mm
@@ -15,7 +15,6 @@ #include "components/autofill/core/browser/autofill_data_util.h" #include "components/autofill/core/browser/data_model/credit_card.h" #import "components/autofill/ios/browser/form_suggestion.h" -#import "ios/chrome/browser/autofill/form_suggestion_client.h" #import "ios/chrome/browser/autofill/form_suggestion_constants.h" #include "ios/chrome/browser/ui/util/ui_util.h" #import "ios/chrome/browser/ui/util/uikit_ui_util.h" @@ -63,18 +62,18 @@ @implementation FormSuggestionLabel { // Client of this view. - __weak id<FormSuggestionClient> _client; + __weak id<FormSuggestionLabelDelegate> _delegate; FormSuggestion* _suggestion; } - (id)initWithSuggestion:(FormSuggestion*)suggestion - index:(NSUInteger)index - numSuggestions:(NSUInteger)numSuggestions - client:(id<FormSuggestionClient>)client { + index:(NSUInteger)index + numSuggestions:(NSUInteger)numSuggestions + delegate:(id<FormSuggestionLabelDelegate>)delegate { self = [super initWithFrame:CGRectZero]; if (self) { _suggestion = suggestion; - _client = client; + _delegate = delegate; UIStackView* stackView = [[UIStackView alloc] initWithArrangedSubviews:@[]]; stackView.axis = UILayoutConstraintAxisHorizontal; @@ -131,20 +130,28 @@ self.layer.cornerRadius = self.bounds.size.height / 2.0; } -#pragma mark - -#pragma mark UIResponder +#pragma mark - UIResponder -- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event { +- (void)touchesBegan:(NSSet<UITouch*>*)touches withEvent:(UIEvent*)event { [self setBackgroundColor:[UIColor colorNamed:kGrey300Color]]; } -- (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event { +- (void)touchesMoved:(NSSet<UITouch*>*)touches withEvent:(UIEvent*)event { + // No op. This method implementation is needed per the UIResponder docs. +} + +- (void)touchesCancelled:(NSSet<UITouch*>*)touches withEvent:(UIEvent*)event { [self setBackgroundColor:[UIColor colorNamed:kGrey100Color]]; } -- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event { +- (void)touchesEnded:(NSSet<UITouch*>*)touches withEvent:(UIEvent*)event { [self setBackgroundColor:[UIColor colorNamed:kGrey100Color]]; - [_client didSelectSuggestion:_suggestion]; + + // Don't count touches ending outside the view as as taps. + CGPoint locationInView = [touches.anyObject locationInView:self]; + if (CGRectContainsPoint(self.bounds, locationInView)) { + [_delegate didTapFormSuggestionLabel:self]; + } } @end
diff --git a/ios/chrome/browser/autofill/form_suggestion_view.h b/ios/chrome/browser/autofill/form_suggestion_view.h index 5d81dd5..b09a4e9 100644 --- a/ios/chrome/browser/autofill/form_suggestion_view.h +++ b/ios/chrome/browser/autofill/form_suggestion_view.h
@@ -13,6 +13,10 @@ @protocol FormSuggestionViewDelegate <NSObject> +// User accepted a suggestion from FormSuggestionView. +- (void)formSuggestionView:(FormSuggestionView*)formSuggestionView + didAcceptSuggestion:(FormSuggestion*)suggestion; + // The view received a long pull in the content direction. The delegate should // probably unlock the trailing view and reset to a clean state. - (void)formSuggestionViewShouldResetFromPull: @@ -33,9 +37,8 @@ // A view added at the end of the current suggestions. @property(nonatomic, strong) UIView* trailingView; -// Updates with |client| and |suggestions|. -- (void)updateClient:(id<FormSuggestionClient>)client - suggestions:(NSArray<FormSuggestion*>*)suggestions; +// Updates with |suggestions|. +- (void)updateSuggestions:(NSArray<FormSuggestion*>*)suggestions; // Reset content insets back to zero and sets the delegate to nil. Used to stop // hearing for the pull gesture to reset and unlock the trailing view.
diff --git a/ios/chrome/browser/autofill/form_suggestion_view.mm b/ios/chrome/browser/autofill/form_suggestion_view.mm index 4fd32082..7d564a8 100644 --- a/ios/chrome/browser/autofill/form_suggestion_view.mm +++ b/ios/chrome/browser/autofill/form_suggestion_view.mm
@@ -4,6 +4,7 @@ #import "ios/chrome/browser/autofill/form_suggestion_view.h" +#include "base/check.h" #include "base/i18n/rtl.h" #include "components/autofill/core/browser/ui/popup_item_ids.h" #import "components/autofill/ios/browser/form_suggestion.h" @@ -29,7 +30,8 @@ } // namespace -@interface FormSuggestionView () <UIScrollViewDelegate> +@interface FormSuggestionView () <FormSuggestionLabelDelegate, + UIScrollViewDelegate> // The FormSuggestions that are displayed by this view. @property(nonatomic) NSArray<FormSuggestion*>* suggestions; @@ -37,22 +39,16 @@ // The stack view with the suggestions. @property(nonatomic) UIStackView* stackView; -// Handles user interactions. -@property(nonatomic, weak) id<FormSuggestionClient> client; - @end @implementation FormSuggestionView #pragma mark - Public -- (void)updateClient:(id<FormSuggestionClient>)client - suggestions:(NSArray<FormSuggestion*>*)suggestions { - if ([self.suggestions isEqualToArray:suggestions] && - (self.client == client || !suggestions.count)) { +- (void)updateSuggestions:(NSArray<FormSuggestion*>*)suggestions { + if ([self.suggestions isEqualToArray:suggestions] && !suggestions.count) { return; } - self.client = client; self.suggestions = [suggestions copy]; if (self.stackView) { @@ -102,6 +98,17 @@ [super willMoveToSuperview:newSuperview]; } +#pragma mark - FormSuggestionLabelDelegate + +- (void)didTapFormSuggestionLabel:(FormSuggestionLabel*)formSuggestionLabel { + NSUInteger index = + [self.stackView.arrangedSubviews indexOfObject:formSuggestionLabel]; + DCHECK(index != NSNotFound); + FormSuggestion* suggestion = [self.suggestions objectAtIndex:index]; + [self.formSuggestionViewDelegate formSuggestionView:self + didAcceptSuggestion:suggestion]; +} + #pragma mark - Helper methods // Creates and adds subviews. @@ -142,7 +149,7 @@ [[FormSuggestionLabel alloc] initWithSuggestion:suggestion index:idx numSuggestions:[self.suggestions count] - client:self.client]; + delegate:self]; [self.stackView addArrangedSubview:label]; }; [self.suggestions enumerateObjectsUsingBlock:setupBlock];
diff --git a/ios/chrome/browser/browser_state/browser_state_keyed_service_factories.mm b/ios/chrome/browser/browser_state/browser_state_keyed_service_factories.mm index 8c00728..b075d9b 100644 --- a/ios/chrome/browser/browser_state/browser_state_keyed_service_factories.mm +++ b/ios/chrome/browser/browser_state/browser_state_keyed_service_factories.mm
@@ -13,7 +13,6 @@ #import "ios/chrome/browser/bookmarks/managed_bookmark_service_factory.h" #include "ios/chrome/browser/browsing_data/browsing_data_remover_factory.h" #include "ios/chrome/browser/content_settings/cookie_settings_factory.h" -#include "ios/chrome/browser/content_settings/ios_cookie_blocker_factory.h" #include "ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager_keyed_service_factory.h" #include "ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_persistent_storage_keyed_service_factory.h" #include "ios/chrome/browser/credential_provider/credential_provider_service_factory.h" @@ -112,7 +111,6 @@ DiscoverFeedServiceFactory::GetInstance(); GoogleLogoServiceFactory::GetInstance(); IdentityManagerFactory::GetInstance(); - IOSCookieBlockerFactory::GetInstance(); IOSChromeContentSuggestionsServiceFactory::GetInstance(); IOSChromeFaviconLoaderFactory::GetInstance(); IOSChromeGCMProfileServiceFactory::GetInstance();
diff --git a/ios/chrome/browser/content_settings/BUILD.gn b/ios/chrome/browser/content_settings/BUILD.gn index 10ce926..fb8e502 100644 --- a/ios/chrome/browser/content_settings/BUILD.gn +++ b/ios/chrome/browser/content_settings/BUILD.gn
@@ -8,39 +8,15 @@ "cookie_settings_factory.h", "host_content_settings_map_factory.cc", "host_content_settings_map_factory.h", - "ios_cookie_blocker.h", - "ios_cookie_blocker.mm", - "ios_cookie_blocker_factory.h", - "ios_cookie_blocker_factory.mm", ] deps = [ "//base", "//components/content_settings/core/browser", - "//components/keyed_service/core", "//components/keyed_service/ios", "//components/prefs", "//ios/chrome/browser", "//ios/chrome/browser/browser_state", - "//ios/chrome/browser/main:public", - "//ios/chrome/browser/web_state_list", - "//ios/chrome/browser/web_state_list/web_usage_enabler", ] configs += [ "//build/config/compiler:enable_arc" ] } - -source_set("unit_tests") { - configs += [ "//build/config/compiler:enable_arc" ] - testonly = true - sources = [ "ios_cookie_blocker_unittest.mm" ] - deps = [ - ":content_settings", - "//base/test:test_support", - "//components/content_settings/core/browser", - "//components/prefs", - "//components/sync_preferences:test_support", - "//ios/chrome/browser/browser_state:test_support", - "//ios/web/public/test", - "//testing/gtest", - ] -}
diff --git a/ios/chrome/browser/content_settings/ios_cookie_blocker.h b/ios/chrome/browser/content_settings/ios_cookie_blocker.h deleted file mode 100644 index 250e18b6..0000000 --- a/ios/chrome/browser/content_settings/ios_cookie_blocker.h +++ /dev/null
@@ -1,53 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_CONTENT_SETTINGS_IOS_COOKIE_BLOCKER_H_ -#define IOS_CHROME_BROWSER_CONTENT_SETTINGS_IOS_COOKIE_BLOCKER_H_ - -#import <WebKit/WebKit.h> - -#include "base/gtest_prod_util.h" -#include "base/memory/weak_ptr.h" -#include "components/content_settings/core/browser/cookie_settings.h" -#include "components/keyed_service/core/keyed_service.h" - -class ChromeBrowserState; -namespace web { -enum class CookieBlockingMode; -} - -// Class for translating Chrome-wide cookie settings into //ios/web cookie -// blocking updates. -class IOSCookieBlocker : public content_settings::CookieSettings::Observer, - public KeyedService { - public: - IOSCookieBlocker( - ChromeBrowserState* browser_state, - scoped_refptr<content_settings::CookieSettings> cookie_settings); - IOSCookieBlocker(const IOSCookieBlocker&) = delete; - IOSCookieBlocker& operator=(const IOSCookieBlocker&) = delete; - - ~IOSCookieBlocker() override; - - private: - // Gets the current cookie blocking mode based on the - // data stored on the attached |CookieSettings|. - web::CookieBlockingMode GetCurrentCookieBlockingMode(); - // Updates the cookie blocking mode of the attached |BrowserState| - // to the correct mode from |CookieSettings|. - void UpdateBrowserStateCookieBlockingMode(); - - // content_settings::CookieSettings::Observer - void OnThirdPartyCookieBlockingChanged( - bool block_third_party_cookies) override; - void OnCookieSettingChanged() override; - - // KeyedService - void Shutdown() override; - - ChromeBrowserState* browser_state_ = nullptr; - scoped_refptr<content_settings::CookieSettings> cookie_settings_ = nullptr; -}; - -#endif // IOS_CHROME_BROWSER_CONTENT_SETTINGS_IOS_COOKIE_BLOCKER_H_
diff --git a/ios/chrome/browser/content_settings/ios_cookie_blocker.mm b/ios/chrome/browser/content_settings/ios_cookie_blocker.mm deleted file mode 100644 index 7a32818..0000000 --- a/ios/chrome/browser/content_settings/ios_cookie_blocker.mm +++ /dev/null
@@ -1,69 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "ios/chrome/browser/content_settings/ios_cookie_blocker.h" - -#import "ios/chrome/browser/browser_state/chrome_browser_state.h" -#import "ios/chrome/browser/main/browser.h" -#include "ios/chrome/browser/main/browser_list.h" -#include "ios/chrome/browser/main/browser_list_factory.h" -#include "ios/chrome/browser/web_state_list/web_state_list.h" -#import "ios/chrome/browser/web_state_list/web_usage_enabler/web_usage_enabler_browser_agent.h" -#import "ios/web/public/browsing_data/cookie_blocking_mode.h" -#import "ios/web/public/navigation/navigation_manager.h" -#import "ios/web/public/web_state.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -IOSCookieBlocker::IOSCookieBlocker( - ChromeBrowserState* browser_state, - scoped_refptr<content_settings::CookieSettings> cookie_settings) - : browser_state_(browser_state), cookie_settings_(cookie_settings) { - cookie_settings_->AddObserver(this); - UpdateBrowserStateCookieBlockingMode(); -} - -void IOSCookieBlocker::Shutdown() { - cookie_settings_->RemoveObserver(this); - cookie_settings_.reset(); -} - -IOSCookieBlocker::~IOSCookieBlocker() = default; - -web::CookieBlockingMode IOSCookieBlocker::GetCurrentCookieBlockingMode() { - if (cookie_settings_->GetDefaultCookieSetting(/*provider_id=*/nullptr) == - CONTENT_SETTING_BLOCK) { - return web::CookieBlockingMode::kBlock; - } - if (cookie_settings_->ShouldBlockThirdPartyCookies()) { - return web::CookieBlockingMode::kBlockThirdParty; - } - return web::CookieBlockingMode::kAllow; -} - -void IOSCookieBlocker::UpdateBrowserStateCookieBlockingMode() { - web::CookieBlockingMode blocking_mode = GetCurrentCookieBlockingMode(); - if (blocking_mode != browser_state_->GetCookieBlockingMode()) { - // This assumes that call to |SetCookieBlockingMode| will almost always be - // synchronous. This is true because cookie blocking only has 3 modes, no - // exceptions, so any async setup work can be done once for each mode at - // initialization time. If cookie blocking ever changes to require async - // work done here, when the blocking mode is set (e.g. compiling a new - // ContentRuleList based on per-site exceptions), this should be re-examined - // to see if something should be done to alert the user when the update - // is finished. - browser_state_->SetCookieBlockingMode(blocking_mode, base::DoNothing()); - } -} - -void IOSCookieBlocker::OnThirdPartyCookieBlockingChanged( - bool block_third_party_cookies) { - UpdateBrowserStateCookieBlockingMode(); -} - -void IOSCookieBlocker::OnCookieSettingChanged() { - UpdateBrowserStateCookieBlockingMode(); -}
diff --git a/ios/chrome/browser/content_settings/ios_cookie_blocker_factory.h b/ios/chrome/browser/content_settings/ios_cookie_blocker_factory.h deleted file mode 100644 index ea1a2ba..0000000 --- a/ios/chrome/browser/content_settings/ios_cookie_blocker_factory.h +++ /dev/null
@@ -1,38 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_CONTENT_SETTINGS_IOS_COOKIE_BLOCKER_FACTORY_H_ -#define IOS_CHROME_BROWSER_CONTENT_SETTINGS_IOS_COOKIE_BLOCKER_FACTORY_H_ - -#include "base/memory/ref_counted.h" -#include "base/no_destructor.h" -#include "components/keyed_service/ios/browser_state_keyed_service_factory.h" - -class ChromeBrowserState; -class IOSCookieBlocker; - -class IOSCookieBlockerFactory : public BrowserStateKeyedServiceFactory { - public: - static IOSCookieBlocker* GetForBrowserState( - ChromeBrowserState* browser_state); - static IOSCookieBlockerFactory* GetInstance(); - - IOSCookieBlockerFactory(const IOSCookieBlockerFactory&) = delete; - IOSCookieBlockerFactory& operator=(const IOSCookieBlockerFactory&) = delete; - - private: - friend class base::NoDestructor<IOSCookieBlockerFactory>; - - IOSCookieBlockerFactory(); - ~IOSCookieBlockerFactory() override; - - // BrowserStateKeyedServiceFactory implementation. - web::BrowserState* GetBrowserStateToUse( - web::BrowserState* context) const override; - std::unique_ptr<KeyedService> BuildServiceInstanceFor( - web::BrowserState* context) const override; - bool ServiceIsCreatedWithBrowserState() const override; -}; - -#endif // IOS_CHROME_BROWSER_CONTENT_SETTINGS_IOS_COOKIE_BLOCKER_FACTORY_H_
diff --git a/ios/chrome/browser/content_settings/ios_cookie_blocker_factory.mm b/ios/chrome/browser/content_settings/ios_cookie_blocker_factory.mm deleted file mode 100644 index 70c37b4..0000000 --- a/ios/chrome/browser/content_settings/ios_cookie_blocker_factory.mm +++ /dev/null
@@ -1,61 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "ios/chrome/browser/content_settings/ios_cookie_blocker_factory.h" - -#include "base/feature_list.h" -#include "base/no_destructor.h" -#include "components/content_settings/core/common/features.h" -#include "components/keyed_service/ios/browser_state_dependency_manager.h" -#include "ios/chrome/browser/browser_state/browser_state_otr_helper.h" -#include "ios/chrome/browser/browser_state/chrome_browser_state.h" -#include "ios/chrome/browser/content_settings/cookie_settings_factory.h" -#import "ios/chrome/browser/content_settings/ios_cookie_blocker.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -// static -IOSCookieBlocker* IOSCookieBlockerFactory::GetForBrowserState( - ChromeBrowserState* browser_state) { - return static_cast<IOSCookieBlocker*>( - GetInstance()->GetServiceForBrowserState(browser_state, true)); -} - -// static -IOSCookieBlockerFactory* IOSCookieBlockerFactory::GetInstance() { - static base::NoDestructor<IOSCookieBlockerFactory> instance; - return instance.get(); -} - -IOSCookieBlockerFactory::IOSCookieBlockerFactory() - : BrowserStateKeyedServiceFactory( - "IOSCookieBlocker", - BrowserStateDependencyManager::GetInstance()) { - DependsOn(ios::CookieSettingsFactory::GetInstance()); -} - -IOSCookieBlockerFactory::~IOSCookieBlockerFactory() {} - -web::BrowserState* IOSCookieBlockerFactory::GetBrowserStateToUse( - web::BrowserState* context) const { - // The incognito browser state has its own CookieSettings map. Therefore, it - // should get its own IOSCookieBlocker. - return GetBrowserStateOwnInstanceInIncognito(context); -} - -std::unique_ptr<KeyedService> IOSCookieBlockerFactory::BuildServiceInstanceFor( - web::BrowserState* context) const { - ChromeBrowserState* browser_state = - ChromeBrowserState::FromBrowserState(context); - return std::make_unique<IOSCookieBlocker>( - browser_state, - ios::CookieSettingsFactory::GetForBrowserState(browser_state)); -} - -bool IOSCookieBlockerFactory::ServiceIsCreatedWithBrowserState() const { - return base::FeatureList::IsEnabled( - content_settings::kImprovedCookieControls); -}
diff --git a/ios/chrome/browser/content_settings/ios_cookie_blocker_unittest.mm b/ios/chrome/browser/content_settings/ios_cookie_blocker_unittest.mm deleted file mode 100644 index 7682a5a9..0000000 --- a/ios/chrome/browser/content_settings/ios_cookie_blocker_unittest.mm +++ /dev/null
@@ -1,86 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "ios/chrome/browser/content_settings/ios_cookie_blocker.h" - -#include "base/test/scoped_feature_list.h" -#include "components/content_settings/core/browser/content_settings_registry.h" -#include "components/content_settings/core/common/features.h" -#include "components/content_settings/core/common/pref_names.h" -#include "components/prefs/pref_service.h" -#include "components/sync_preferences/testing_pref_service_syncable.h" -#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h" -#include "ios/chrome/browser/content_settings/cookie_settings_factory.h" -#import "ios/web/public/browsing_data/cookie_blocking_mode.h" -#include "ios/web/public/test/web_task_environment.h" -#import "testing/gtest_mac.h" -#include "testing/platform_test.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -class IOSCookieBlockerTest : public PlatformTest { - public: - IOSCookieBlockerTest() { - feature_list_.InitAndEnableFeature( - content_settings::kImprovedCookieControls); - - TestChromeBrowserState::Builder builder; - chrome_browser_state_ = builder.Build(); - } - - void SetUp() override { - PlatformTest::SetUp(); - - content_settings::ContentSettingsRegistry::GetInstance()->ResetForTest(); - content_settings::CookieSettings::RegisterProfilePrefs(prefs_.registry()); - HostContentSettingsMap::RegisterProfilePrefs(prefs_.registry()); - scoped_refptr<HostContentSettingsMap> settings_map = - new HostContentSettingsMap( - &prefs_, false /* is_off_the_record */, - false /* store_last_modified */, - false /* migrate_requesting_and_top_level_origin_settings */, - false /* restore_session */); - cookie_settings_ = new content_settings::CookieSettings( - settings_map.get(), &prefs_, false, "chrome-extension"); - - cookie_blocker_ = - new IOSCookieBlocker(chrome_browser_state_.get(), cookie_settings_); - } - - web::WebTaskEnvironment task_environment_; - base::test::ScopedFeatureList feature_list_; - - sync_preferences::TestingPrefServiceSyncable prefs_; - scoped_refptr<content_settings::CookieSettings> cookie_settings_; - std::unique_ptr<TestChromeBrowserState> chrome_browser_state_; - IOSCookieBlocker* cookie_blocker_; -}; - -// Test that CredentialProviderService can be created. -TEST_F(IOSCookieBlockerTest, CorrectBlockingMode) { - EXPECT_EQ(web::CookieBlockingMode::kAllow, - chrome_browser_state_->GetCookieBlockingMode()); - - // Turn on third party cookie blocking preference. - prefs_.SetInteger( - prefs::kCookieControlsMode, - static_cast<int>(content_settings::CookieControlsMode::kBlockThirdParty)); - EXPECT_EQ(web::CookieBlockingMode::kBlockThirdParty, - chrome_browser_state_->GetCookieBlockingMode()); - - // Disable cookies altogether. - cookie_settings_->SetDefaultCookieSetting(CONTENT_SETTING_BLOCK); - EXPECT_EQ(web::CookieBlockingMode::kBlock, - chrome_browser_state_->GetCookieBlockingMode()); - - // Undo settings, to verify that state goes back to allow. - prefs_.SetInteger( - prefs::kCookieControlsMode, - static_cast<int>(content_settings::CookieControlsMode::kOff)); - cookie_settings_->SetDefaultCookieSetting(CONTENT_SETTING_ALLOW); - EXPECT_EQ(web::CookieBlockingMode::kAllow, - chrome_browser_state_->GetCookieBlockingMode()); -}
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm index 37e15e36..0ff599dc 100644 --- a/ios/chrome/browser/flags/about_flags.mm +++ b/ios/chrome/browser/flags/about_flags.mm
@@ -529,10 +529,6 @@ {"reload-sad-tab", flag_descriptions::kReloadSadTabName, flag_descriptions::kReloadSadTabDescription, flags_ui::kOsIos, FEATURE_VALUE_TYPE(web::kReloadSadTab)}, - {"improved-cookie-controls", - flag_descriptions::kImprovedCookieControlsDescription, - flag_descriptions::kImprovedCookieControlsDescription, flags_ui::kOsIos, - FEATURE_VALUE_TYPE(content_settings::kImprovedCookieControls)}, {"page-info-refactoring", flag_descriptions::kPageInfoRefactoringName, flag_descriptions::kPageInfoRefactoringDescription, flags_ui::kOsIos, FEATURE_VALUE_TYPE(kPageInfoRefactoring)},
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc index ac18e50..e6cbaee6 100644 --- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc +++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -377,10 +377,6 @@ "the tools menu or after pressing the 'Open in downloads' button invoked " "by pressing 'Open In...' after download completes."; -const char kImprovedCookieControlsName[] = "Third-party cookie blocking UI"; -const char kImprovedCookieControlsDescription[] = - "Allows user to manage third-party cookie blocking."; - const char kPasswordCheckName[] = "Bulk Password Check"; const char kPasswordCheckDescription[] = "Enables the Bulk Password Check feature for signed-in users.";
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h index e4bab0b..a851d10 100644 --- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h +++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -321,11 +321,6 @@ extern const char kOpenDownloadsInFilesAppName[]; extern const char kOpenDownloadsInFilesAppDescription[]; -// Title and description for the flag to provide user with improved settings -// relating to cookies. -extern const char kImprovedCookieControlsName[]; -extern const char kImprovedCookieControlsDescription[]; - // Title and description for the flag to provide user with Password Check // feature in Settings. extern const char kPasswordCheckName[];
diff --git a/ios/chrome/browser/passwords/ios_chrome_password_check_manager.h b/ios/chrome/browser/passwords/ios_chrome_password_check_manager.h index af23921d..3297f69 100644 --- a/ios/chrome/browser/passwords/ios_chrome_password_check_manager.h +++ b/ios/chrome/browser/passwords/ios_chrome_password_check_manager.h
@@ -142,6 +142,10 @@ // delegate is initialized. bool start_check_on_init_ = false; + // Time when password check was started. Used to calculate delay in case + // when password check run less than 3 seconds. + base::Time start_time_; + // A scoped observer for |saved_passwords_presenter_|. ScopedObserver<password_manager::SavedPasswordsPresenter, password_manager::SavedPasswordsPresenter::Observer> @@ -159,6 +163,8 @@ // Observers to listen to password check changes. base::ObserverList<Observer> observers_; + + base::WeakPtrFactory<IOSChromePasswordCheckManager> weak_ptr_factory_{this}; }; #endif // IOS_CHROME_BROWSER_PASSWORDS_IOS_CHROME_PASSWORD_CHECK_MANAGER_H_
diff --git a/ios/chrome/browser/passwords/ios_chrome_password_check_manager.mm b/ios/chrome/browser/passwords/ios_chrome_password_check_manager.mm index 03cff996..371f141 100644 --- a/ios/chrome/browser/passwords/ios_chrome_password_check_manager.mm +++ b/ios/chrome/browser/passwords/ios_chrome_password_check_manager.mm
@@ -26,6 +26,8 @@ // Key used to attach UserData to a LeakCheckCredential. constexpr char kPasswordCheckDataKey[] = "password-check-manager-data-key"; +// Minimum time the check should be running. +constexpr base::TimeDelta kDelay = base::TimeDelta::FromSeconds(3); // Class which ensures that IOSChromePasswordCheckManager will stay alive // until password check is completed even if class what initially created @@ -120,6 +122,7 @@ bulk_leak_check_service_adapter_.StartBulkLeakCheck(kPasswordCheckDataKey, &data); is_check_running_ = true; + start_time_ = base::Time::Now(); } else { start_check_on_init_ = true; } @@ -207,6 +210,20 @@ base::Time::Now().ToDoubleT()); } if (state != State::kRunning) { + // If check was running + if (is_check_running_) { + const base::TimeDelta elapsed = base::Time::Now() - start_time_; + if (elapsed < kDelay) { + base::SequencedTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, + base::BindOnce(&IOSChromePasswordCheckManager:: + NotifyPasswordCheckStatusChanged, + weak_ptr_factory_.GetWeakPtr()), + kDelay - elapsed); + is_check_running_ = false; + return; + } + } is_check_running_ = false; } NotifyPasswordCheckStatusChanged();
diff --git a/ios/chrome/browser/passwords/ios_chrome_password_check_manager_unittest.mm b/ios/chrome/browser/passwords/ios_chrome_password_check_manager_unittest.mm index 1f1454f..88bcfcb 100644 --- a/ios/chrome/browser/passwords/ios_chrome_password_check_manager_unittest.mm +++ b/ios/chrome/browser/passwords/ios_chrome_password_check_manager_unittest.mm
@@ -157,6 +157,8 @@ void RunUntilIdle() { task_env_.RunUntilIdle(); } + void FastForwardBy(base::TimeDelta time) { task_env_.FastForwardBy(time); } + ChromeBrowserState* browser_state() { return browser_state_.get(); } TestPasswordStore& store() { return *store_; } MockBulkLeakCheckService* service() { return bulk_leak_check_service_; } @@ -389,3 +391,28 @@ EXPECT_EQ(base::UTF8ToUTF16(kPassword2), store().stored_passwords().at(kExampleCom).at(0).password_value); } + +// Tests expected delay is being added. +TEST_F(IOSChromePasswordCheckManagerTest, CheckFinishedWithDelay) { + store().AddLogin(MakeSavedPassword(kExampleCom, kUsername1)); + + RunUntilIdle(); + StrictMock<MockPasswordCheckManagerObserver> observer; + manager().AddObserver(&observer); + manager().StartPasswordCheck(); + RunUntilIdle(); + + EXPECT_CALL(observer, PasswordCheckStatusChanged(PasswordCheckState::kIdle)) + .Times(0); + static_cast<BulkLeakCheckServiceInterface::Observer*>(&manager()) + ->OnStateChanged(BulkLeakCheckServiceInterface::State::kIdle); + FastForwardBy(base::TimeDelta::FromSeconds(1)); + + EXPECT_CALL(observer, PasswordCheckStatusChanged(PasswordCheckState::kIdle)) + .Times(0); + FastForwardBy(base::TimeDelta::FromSeconds(1)); + + EXPECT_CALL(observer, PasswordCheckStatusChanged(PasswordCheckState::kIdle)) + .Times(1); + FastForwardBy(base::TimeDelta::FromSeconds(1)); +}
diff --git a/ios/chrome/browser/passwords/password_check_observer_bridge.mm b/ios/chrome/browser/passwords/password_check_observer_bridge.mm index 25bbb4f..eb401a0 100644 --- a/ios/chrome/browser/passwords/password_check_observer_bridge.mm +++ b/ios/chrome/browser/passwords/password_check_observer_bridge.mm
@@ -20,7 +20,11 @@ void PasswordCheckObserverBridge::PasswordCheckStatusChanged( PasswordCheckState status) { - [delegate_ passwordCheckStateDidChange:status]; + // Since password check state update can be called with delay from the + // background thread, dispatch aync should be used to update main UI thread. + dispatch_async(dispatch_get_main_queue(), ^{ + [delegate_ passwordCheckStateDidChange:status]; + }); } void PasswordCheckObserverBridge::CompromisedCredentialsChanged(
diff --git a/ios/chrome/browser/passwords/password_controller_unittest.mm b/ios/chrome/browser/passwords/password_controller_unittest.mm index e41a07f..3568c45 100644 --- a/ios/chrome/browser/passwords/password_controller_unittest.mm +++ b/ios/chrome/browser/passwords/password_controller_unittest.mm
@@ -312,7 +312,9 @@ webStateList:nullptr personalDataManager:nullptr passwordStore:nullptr - appState:nil]; + appState:nil + securityAlertHandler:nil + reauthenticationModule:nil]; [accessoryMediator_ injectWebState:web_state()]; [accessoryMediator_ injectProvider:suggestionController_]; } @@ -1163,7 +1165,8 @@ [FormSuggestion suggestionWithValue:@"abc ••••••••" displayDescription:nil icon:nil - identifier:0]; + identifier:0 + requiresReauth:NO]; block_was_called = NO; SuggestionHandledCompletion completion = ^{
diff --git a/ios/chrome/browser/passwords/well_known_change_password_tab_helper.h b/ios/chrome/browser/passwords/well_known_change_password_tab_helper.h index 310504a..b22a1a0 100644 --- a/ios/chrome/browser/passwords/well_known_change_password_tab_helper.h +++ b/ios/chrome/browser/passwords/well_known_change_password_tab_helper.h
@@ -4,6 +4,7 @@ #ifndef IOS_CHROME_BROWSER_PASSWORDS_WELL_KNOWN_CHANGE_PASSWORD_TAB_HELPER_H_ #define IOS_CHROME_BROWSER_PASSWORDS_WELL_KNOWN_CHANGE_PASSWORD_TAB_HELPER_H_ +#include "components/password_manager/core/browser/well_known_change_password_state.h" #include "ios/web/public/navigation/web_state_policy_decider.h" #include "ios/web/public/web_state_observer.h" #import "ios/web/public/web_state_user_data.h" @@ -17,30 +18,65 @@ // the change-password url. If the site does not support the change password // url, the user gets redirected to the base path '/'. If the sites supports the // standard, the request is allowed and the navigation is not changed. +// The TabHelper only intercepts the navigation if .well-known/change-password +// is opened in a new tab. class WellKnownChangePasswordTabHelper - : public web::WebStatePolicyDecider, + : public password_manager::WellKnownChangePasswordStateDelegate, public web::WebStateObserver, + public web::WebStatePolicyDecider, public web::WebStateUserData<WellKnownChangePasswordTabHelper> { public: ~WellKnownChangePasswordTabHelper() override; + // web::WebStatePolicyDecider: PolicyDecision ShouldAllowRequest(NSURLRequest* request, const RequestInfo& request_info) override; void ShouldAllowResponse( NSURLResponse* response, bool for_main_frame, web::WebStatePolicyDecider::PolicyDecisionCallback callback) override; - void DidRedirectNavigation( - web::WebState* web_state, - web::NavigationContext* navigation_context) override; void WebStateDestroyed() override; + + // web::WebStateObserver: + void DidStartNavigation(web::WebState* web_state, + web::NavigationContext* navigation_context) override; + void RenderProcessGone(web::WebState* web_state) override; void WebStateDestroyed(web::WebState* web_state) override; private: - explicit WellKnownChangePasswordTabHelper(web::WebState* web_state); - friend class web::WebStateUserData<WellKnownChangePasswordTabHelper>; - web::WebState* web_state_ = nullptr; + // Describes the progress and state of the .well-known processing. + enum ProcessingState { + // The TabHelper only checks the first request. This state signals if the + // current request is the first. + kWaitingForFirstRequest = 0, + // When the first request is for .well-known/change-password, the TabHelper + // is waiting for the response. + kWaitingForResponse, + // When the Response arrived the TabHelper waits for the + // well_known_change_password_state_ to notify is the .well-known is + // supported. + kResponesReceived, + // When the first request is not to .well-known/change-password, or another + // navigation is started the TabHelper stops any custom processing. + kInactive, + }; + explicit WellKnownChangePasswordTabHelper(web::WebState* web_state); + // WellKnownChangePasswordStateDelegate: + void OnProcessingFinished(bool is_supported) override; + // Redirects to a given URL in the same tab. + void Redirect(const GURL& url); + + web::WebState* web_state_ = nullptr; + ProcessingState processing_state_ = kWaitingForFirstRequest; + // Stores the request_url if the first navigation was to + // .well-known/change-password. It is later used to redirect to the origin. + GURL request_url_; + // Stored callback from ShouldAllowResponse when the response is from + // .well-known/change-password. + web::WebStatePolicyDecider::PolicyDecisionCallback response_policy_callback_; + password_manager::WellKnownChangePasswordState + well_known_change_password_state_{this}; WEB_STATE_USER_DATA_KEY_DECL(); };
diff --git a/ios/chrome/browser/passwords/well_known_change_password_tab_helper.mm b/ios/chrome/browser/passwords/well_known_change_password_tab_helper.mm index 339c62e..aa69232 100644 --- a/ios/chrome/browser/passwords/well_known_change_password_tab_helper.mm +++ b/ios/chrome/browser/passwords/well_known_change_password_tab_helper.mm
@@ -12,14 +12,13 @@ #include "ios/chrome/browser/browser_state/chrome_browser_state.h" #import "ios/web/public/navigation/navigation_context.h" #import "net/base/mac/url_conversions.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." #endif -namespace { using password_manager::WellKnownChangePasswordTabHelper; -} WellKnownChangePasswordTabHelper::WellKnownChangePasswordTabHelper( web::WebState* web_state) @@ -29,26 +28,46 @@ WellKnownChangePasswordTabHelper::~WellKnownChangePasswordTabHelper() = default; -void WellKnownChangePasswordTabHelper::DidRedirectNavigation( +void WellKnownChangePasswordTabHelper::DidStartNavigation( web::WebState* web_state, web::NavigationContext* navigation_context) { - // TODO(crbug.com/927473): handle redirects + // |request_url_| is set when the first request goes to + // .well-known-change-password. If the navigation url and |request_url_| are + // equal, DidStartNavigation() is called for the .well-known/change-password + // navigation. Otherwise a different navigation was started. + if (!(request_url_.is_valid() && + request_url_ == navigation_context->GetUrl())) { + processing_state_ = kInactive; + } } web::WebStatePolicyDecider::PolicyDecision WellKnownChangePasswordTabHelper::ShouldAllowRequest( NSURLRequest* request, const RequestInfo& request_info) { - const GURL& request_url = net::GURLWithNSURL(request.URL); - // Boolean order important. First url then feature flag. Otherwise it messes - // with usage statistics of control and experimental group (UMA). - if (request_info.target_frame_is_main && - IsWellKnownChangePasswordUrl(request_url) && - base::FeatureList::IsEnabled( - password_manager::features::kWellKnownChangePassword)) { - // TODO(crbug.com/927473): Make request to non existing resource and check - // if well-known/change-password is supported. + GURL request_url = net::GURLWithNSURL(request.URL); + // The custom behaviour is only used if the .well-known/change-password + // request if the request is the main frame opened in a new tab. + if (processing_state_ == kWaitingForFirstRequest) { + // Boolean order important, feature flag last. Otherwise it messes + // with usage statistics of control and experimental group (UMA). + if (request_info.target_frame_is_main && + web_state_->GetLastCommittedURL().is_empty() && // empty tab history + IsWellKnownChangePasswordUrl(request_url) && + base::FeatureList::IsEnabled( + password_manager::features::kWellKnownChangePassword)) { + request_url_ = request_url; + + auto url_loader_factory = + web_state_->GetBrowserState()->GetSharedURLLoaderFactory(); + well_known_change_password_state_.FetchNonExistingResource( + url_loader_factory.get(), request_url); + processing_state_ = kWaitingForResponse; + } else { + processing_state_ = kInactive; + } } + return web::WebStatePolicyDecider::PolicyDecision::Allow(); } @@ -56,21 +75,31 @@ NSURLResponse* response, bool for_main_frame, web::WebStatePolicyDecider::PolicyDecisionCallback callback) { - const GURL& url = net::GURLWithNSURL(response.URL); - // Boolean order important, feature flag check last. Otherwise it messes - // with usage statistics. - // We only want to handle main_frame requests to keep consistency with the - // NavigationThrottle implementation. - if (!for_main_frame || !IsWellKnownChangePasswordUrl(url) || - !base::FeatureList::IsEnabled( + GURL url = net::GURLWithNSURL(response.URL); + // True if the TabHelper expects the response from .well-known/change-password + // and only that navigation was started. + if (processing_state_ == kWaitingForResponse && + [response isKindOfClass:[NSHTTPURLResponse class]] && + base::FeatureList::IsEnabled( password_manager::features::kWellKnownChangePassword)) { - // TODO(crbug.com/927473): Handle .well-known/change-passord response. + processing_state_ = kResponesReceived; + DCHECK(url.SchemeIsHTTPOrHTTPS()); + response_policy_callback_ = std::move(callback); + + well_known_change_password_state_.SetChangePasswordResponseCode( + static_cast<NSHTTPURLResponse*>(response).statusCode); + } else { std::move(callback).Run( web::WebStatePolicyDecider::PolicyDecision::Allow()); - return; } - // TODO(crbug.com/927473): Handle Response - std::move(callback).Run(web::WebStatePolicyDecider::PolicyDecision::Allow()); +} + +void WellKnownChangePasswordTabHelper::RenderProcessGone( + web::WebState* web_state) { + if (!response_policy_callback_) + return; + std::move(response_policy_callback_) + .Run(web::WebStatePolicyDecider::PolicyDecision::Cancel()); } void WellKnownChangePasswordTabHelper::WebStateDestroyed() {} @@ -78,6 +107,33 @@ void WellKnownChangePasswordTabHelper::WebStateDestroyed( web::WebState* web_state) { web_state->RemoveObserver(this); + if (!response_policy_callback_) + return; + std::move(response_policy_callback_) + .Run(web::WebStatePolicyDecider::PolicyDecision::Cancel()); +} + +void WellKnownChangePasswordTabHelper::OnProcessingFinished(bool is_supported) { + if (!response_policy_callback_) + return; + if (is_supported) { + std::move(response_policy_callback_) + .Run(web::WebStatePolicyDecider::PolicyDecision::Allow()); + } else { + std::move(response_policy_callback_) + .Run(web::WebStatePolicyDecider::PolicyDecision::Cancel()); + Redirect(request_url_.GetOrigin()); + } +} + +void WellKnownChangePasswordTabHelper::Redirect(const GURL& url) { + // Making sure there was no other navigation started we could override. + if (processing_state_ == kResponesReceived) { + web::WebState::OpenURLParams params(url, web::Referrer(), + WindowOpenDisposition::CURRENT_TAB, + ui::PAGE_TRANSITION_LINK, false); + web_state_->OpenURL(params); + } } WEB_STATE_USER_DATA_KEY_IMPL(WellKnownChangePasswordTabHelper)
diff --git a/ios/chrome/browser/passwords/well_known_change_password_tab_helper_unittest.mm b/ios/chrome/browser/passwords/well_known_change_password_tab_helper_unittest.mm index 1951671b..756ba3fe 100644 --- a/ios/chrome/browser/passwords/well_known_change_password_tab_helper_unittest.mm +++ b/ios/chrome/browser/passwords/well_known_change_password_tab_helper_unittest.mm
@@ -1,9 +1,206 @@ // Copyright 2020 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. - #import "ios/chrome/browser/passwords/well_known_change_password_tab_helper.h" +#import <Foundation/Foundation.h> + +#include "base/run_loop.h" +#import "base/test/ios/wait_util.h" +#include "base/test/scoped_feature_list.h" +#include "components/password_manager/core/browser/well_known_change_password_util.h" +#include "components/password_manager/core/common/password_manager_features.h" +#import "ios/web/public/navigation/navigation_manager.h" +#import "ios/web/public/test/fakes/test_web_client.h" +#import "ios/web/public/test/fakes/test_web_state_delegate.h" +#import "ios/web/public/test/navigation_test_util.h" +#include "ios/web/public/test/web_task_environment.h" +#include "ios/web/public/test/web_test.h" +#include "ios/web/public/test/web_test_with_web_state.h" +#import "ios/web/public/test/web_view_content_test_util.h" +#include "net/cert/x509_certificate.h" +#include "net/http/http_status_code.h" +#include "net/test/embedded_test_server/embedded_test_server.h" +#include "net/test/embedded_test_server/http_request.h" +#include "net/test/embedded_test_server/http_response.h" +#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" +#include "services/network/test/test_url_loader_factory.h" + #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." #endif + +namespace { + +using base::test::ios::WaitUntilConditionOrTimeout; +using net::test_server::BasicHttpResponse; +using net::test_server::EmbeddedTestServer; +using net::test_server::EmbeddedTestServerHandle; +using net::test_server::HttpRequest; +using net::test_server::HttpResponse; +using password_manager::kWellKnownChangePasswordPath; +using password_manager::kWellKnownNotExistingResourcePath; + +// ServerResponse describes how a server should respond to a given path. +struct ServerResponse { + net::HttpStatusCode status_code; + std::vector<std::pair<std::string, std::string>> headers; +}; + +} // namespace + +// This test uses a mockserver to simulate different response. To handle the +// url_loader requests we also mock the response for the url_loader_factory. +class WellKnownChangePasswordTabHelperTest : public web::TestWebClient, + public web::WebTestWithWebState { + public: + WellKnownChangePasswordTabHelperTest() { + feature_list_.InitAndEnableFeature( + password_manager::features::kWellKnownChangePassword); + test_server_->RegisterRequestHandler(base::BindRepeating( + &WellKnownChangePasswordTabHelperTest::HandleRequest, + base::Unretained(this))); + } + + void SetUp() override { + web::WebTestWithWebState::SetUp(); + EXPECT_TRUE(test_server_->InitializeAndListen()); + test_server_->StartAcceptingConnections(); + + web_state()->SetDelegate(&delegate_); + password_manager::WellKnownChangePasswordTabHelper::CreateForWebState( + web_state()); + SetSharedURLLoaderFactory( + base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( + &test_url_loader_factory_)); + } + + // Sets a response for the |test_url_loader_factory_| with the |test_server_| + // as the host. + void SetUrlLoaderResponse(const std::string& path, + net::HttpStatusCode status_code) { + test_url_loader_factory_.AddResponse(test_server_->GetURL(path).spec(), "", + status_code); + } + // Waits until the navigation is complete and waits for backgroundtasks to + // complete. Returns false when timed out. + bool WaitUntilLoaded(); + // Returns the url after the navigation is complete. + GURL GetNavigatedUrl() const; + + // Maps a path to a ServerResponse config object. + base::flat_map<std::string, ServerResponse> path_response_map_; + std::unique_ptr<EmbeddedTestServer> test_server_ = + std::make_unique<EmbeddedTestServer>(); + + private: + // Returns a response for the given request. Uses |path_response_map_| to + // construct the response. Returns nullptr when the path is not defined in + // |path_response_map_|. + std::unique_ptr<HttpResponse> HandleRequest(const HttpRequest& request); + + base::test::ScopedFeatureList feature_list_; + network::TestURLLoaderFactory test_url_loader_factory_; + web::TestWebStateDelegate delegate_; +}; + +GURL WellKnownChangePasswordTabHelperTest::GetNavigatedUrl() const { + web::URLVerificationTrustLevel trust_level = + web::URLVerificationTrustLevel::kAbsolute; + GURL url = web_state()->GetCurrentURL(&trust_level); + // When redirecting with WebState::OpenURL() |web_state_| is not + // updated, we only see the registered request in + // TestWebStateDelegate::last_open_url_request(). + if (delegate_.last_open_url_request()) { + url = delegate_.last_open_url_request()->params.url; + } + return url; +} + +bool WellKnownChangePasswordTabHelperTest::WaitUntilLoaded() { + return WaitUntilConditionOrTimeout(base::test::ios::kWaitForPageLoadTimeout, + ^{ + WaitForBackgroundTasks(); + return !web_state()->IsLoading(); + }); +} + +std::unique_ptr<HttpResponse> +WellKnownChangePasswordTabHelperTest::HandleRequest( + const HttpRequest& request) { + GURL absolute_url = test_server_->GetURL(request.relative_url); + std::string path = absolute_url.path(); + auto it = path_response_map_.find(absolute_url.path_piece()); + if (it == path_response_map_.end()) + return nullptr; + + const ServerResponse& config = it->second; + auto http_response = std::make_unique<BasicHttpResponse>(); + http_response->set_code(config.status_code); + http_response->set_content_type("text/plain"); + for (auto header_pair : config.headers) { + http_response->AddCustomHeader(header_pair.first, header_pair.second); + } + return http_response; +} + +TEST_F(WellKnownChangePasswordTabHelperTest, SupportForChangePassword) { + path_response_map_[kWellKnownChangePasswordPath] = {net::HTTP_OK, {}}; + + SetUrlLoaderResponse(kWellKnownNotExistingResourcePath, net::HTTP_NOT_FOUND); + + web::test::LoadUrl(web_state(), + test_server_->GetURL(kWellKnownChangePasswordPath)); + ASSERT_TRUE(WaitUntilLoaded()); + EXPECT_EQ(GetNavigatedUrl().path(), kWellKnownChangePasswordPath); +} + +TEST_F(WellKnownChangePasswordTabHelperTest, + SupportForChangePassword_WithRedirect) { + path_response_map_[kWellKnownChangePasswordPath] = { + net::HTTP_PERMANENT_REDIRECT, + {std::make_pair("Location", "/change-password")}}; + path_response_map_["/change-password"] = {net::HTTP_OK, {}}; + + SetUrlLoaderResponse(kWellKnownNotExistingResourcePath, net::HTTP_NOT_FOUND); + + web::test::LoadUrl(web_state(), + test_server_->GetURL(kWellKnownChangePasswordPath)); + ASSERT_TRUE(WaitUntilLoaded()); + EXPECT_EQ(GetNavigatedUrl().path(), "/change-password"); +} + +TEST_F(WellKnownChangePasswordTabHelperTest, + NoSupportForChangePassword_NotFound) { + path_response_map_[kWellKnownChangePasswordPath] = {net::HTTP_NOT_FOUND, {}}; + path_response_map_["/"] = {net::HTTP_OK, {}}; + SetUrlLoaderResponse(kWellKnownNotExistingResourcePath, net::HTTP_NOT_FOUND); + + web::test::LoadUrl(web_state(), + test_server_->GetURL(kWellKnownChangePasswordPath)); + ASSERT_TRUE(WaitUntilLoaded()); + EXPECT_EQ(GetNavigatedUrl().path(), "/"); +} + +TEST_F(WellKnownChangePasswordTabHelperTest, NoSupportForChangePassword_Ok) { + path_response_map_[kWellKnownChangePasswordPath] = {net::HTTP_OK, {}}; + path_response_map_["/"] = {net::HTTP_OK, {}}; + SetUrlLoaderResponse(kWellKnownNotExistingResourcePath, net::HTTP_OK); + + web::test::LoadUrl(web_state(), + test_server_->GetURL(kWellKnownChangePasswordPath)); + ASSERT_TRUE(WaitUntilLoaded()); + EXPECT_EQ(GetNavigatedUrl().path(), "/"); +} + +TEST_F(WellKnownChangePasswordTabHelperTest, + NoSupportForChangePassword_WithRedirect) { + path_response_map_[kWellKnownChangePasswordPath] = { + net::HTTP_PERMANENT_REDIRECT, {std::make_pair("Location", "/not-found")}}; + path_response_map_["/not-found"] = {net::HTTP_NOT_FOUND, {}}; + SetUrlLoaderResponse(kWellKnownNotExistingResourcePath, net::HTTP_OK); + web::test::LoadUrl(web_state(), + test_server_->GetURL(kWellKnownChangePasswordPath)); + ASSERT_TRUE(WaitUntilLoaded()); + EXPECT_EQ(GetNavigatedUrl().path(), "/"); +}
diff --git a/ios/chrome/browser/ui/authentication/BUILD.gn b/ios/chrome/browser/ui/authentication/BUILD.gn index 49ff4e43..03f0169 100644 --- a/ios/chrome/browser/ui/authentication/BUILD.gn +++ b/ios/chrome/browser/ui/authentication/BUILD.gn
@@ -196,6 +196,7 @@ "//ios/chrome/test/earl_grey:eg_test_support+eg2", "//ios/public/provider/chrome/browser/signin", "//ios/public/provider/chrome/browser/signin:fake_chrome_identity", + "//ios/public/provider/chrome/browser/signin:test_support", "//ios/testing/earl_grey:eg_test_support+eg2", "//ios/third_party/earl_grey2:test_lib", "//ui/base",
diff --git a/ios/chrome/browser/ui/authentication/signin/signin_coordinator_egtest.mm b/ios/chrome/browser/ui/authentication/signin/signin_coordinator_egtest.mm index e561194a..d904ebd 100644 --- a/ios/chrome/browser/ui/authentication/signin/signin_coordinator_egtest.mm +++ b/ios/chrome/browser/ui/authentication/signin/signin_coordinator_egtest.mm
@@ -82,8 +82,7 @@ // Sign in to |fakeIdentity1|. [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity1]; - [SigninEarlGreyUI - signOutWithSignOutConfirmation:SignOutConfirmationNonManagedUser]; + [SigninEarlGreyUI signOut]; // Sign in with |fakeIdentity2|. [ChromeEarlGreyUI openSettingsMenu]; @@ -128,8 +127,6 @@ - (void)testSignInOneUser { // Set up a fake identity. FakeChromeIdentity* fakeIdentity = [SigninEarlGrey fakeIdentity1]; - [SigninEarlGrey addFakeIdentity:fakeIdentity]; - [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity]; // Check |fakeIdentity| is signed-in. @@ -151,30 +148,21 @@ // Tests that signing out from the Settings works correctly. - (void)testSignInDisconnectFromChrome { FakeChromeIdentity* fakeIdentity = [SigninEarlGrey fakeIdentity1]; - [SigninEarlGrey addFakeIdentity:fakeIdentity]; - - // Sign in to |fakeIdentity|. [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity]; // Sign out. - [SigninEarlGreyUI - signOutWithSignOutConfirmation:SignOutConfirmationNonManagedUser]; + [SigninEarlGreyUI signOut]; } // Tests that signing out of a managed account from the Settings works // correctly. - (void)testSignInDisconnectFromChromeManaged { - FakeChromeIdentity* fakeIdentity = [SigninEarlGrey fakeManagedIdentity]; - // Sign-in with a managed account. - [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity isManagedAccount:YES]; + FakeChromeIdentity* fakeIdentity = [SigninEarlGrey fakeManagedIdentity]; + [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity]; // Sign out. - [SigninEarlGreyUI - signOutWithSignOutConfirmation:SignOutConfirmationManagedUser]; - - // Check that there is no signed in user. - [SigninEarlGrey verifySignedOut]; + [SigninEarlGreyUI signOutAndClearDataFromDevice]; } // Tests that signing in, tapping the Settings link on the confirmation screen @@ -253,8 +241,7 @@ [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity2]; // Sign out. - [SigninEarlGreyUI - signOutWithSignOutConfirmation:SignOutConfirmationNonManagedUser]; + [SigninEarlGreyUI signOut]; // Sign in with |fakeIdentity1|. [ChromeEarlGreyUI openSettingsMenu]; [[EarlGrey selectElementWithMatcher:SecondarySignInButton()]
diff --git a/ios/chrome/browser/ui/authentication/signin_earl_grey_app_interface.h b/ios/chrome/browser/ui/authentication/signin_earl_grey_app_interface.h index b7403cb..01d14189 100644 --- a/ios/chrome/browser/ui/authentication/signin_earl_grey_app_interface.h +++ b/ios/chrome/browser/ui/authentication/signin_earl_grey_app_interface.h
@@ -32,8 +32,13 @@ + (void)forgetFakeIdentity:(FakeChromeIdentity*)fakeIdentity; // Returns the gaia ID of the signed-in account. +// If there is no signed-in account returns an empty string. + (NSString*)primaryAccountGaiaID; +// Returns the email of the signed-in account. +// If there is no signed-in account returns an empty string. ++ (NSString*)primaryAccountEmail; + // Checks that no identity is signed in. + (BOOL)isSignedOut;
diff --git a/ios/chrome/browser/ui/authentication/signin_earl_grey_app_interface.mm b/ios/chrome/browser/ui/authentication/signin_earl_grey_app_interface.mm index e4e22e66..87f89c7 100644 --- a/ios/chrome/browser/ui/authentication/signin_earl_grey_app_interface.mm +++ b/ios/chrome/browser/ui/authentication/signin_earl_grey_app_interface.mm
@@ -41,7 +41,7 @@ } + (FakeChromeIdentity*)fakeManagedIdentity { - return [FakeChromeIdentity identityWithEmail:@"foo@managed.com" + return [FakeChromeIdentity identityWithEmail:@"foo@google.com" gaiaID:@"fooManagedID" name:@"Fake Managed"]; } @@ -57,20 +57,30 @@ } + (NSString*)primaryAccountGaiaID { - ChromeBrowserState* browser_state = + ChromeBrowserState* browserState = chrome_test_util::GetOriginalBrowserState(); CoreAccountInfo info = - IdentityManagerFactory::GetForBrowserState(browser_state) + IdentityManagerFactory::GetForBrowserState(browserState) ->GetPrimaryAccountInfo(); return base::SysUTF8ToNSString(info.gaia); } ++ (NSString*)primaryAccountEmail { + ChromeBrowserState* browserState = + chrome_test_util::GetOriginalBrowserState(); + CoreAccountInfo info = + IdentityManagerFactory::GetForBrowserState(browserState) + ->GetPrimaryAccountInfo(); + + return base::SysUTF8ToNSString(info.email); +} + + (BOOL)isSignedOut { - ChromeBrowserState* browser_state = + ChromeBrowserState* browserState = chrome_test_util::GetOriginalBrowserState(); - return !IdentityManagerFactory::GetForBrowserState(browser_state) + return !IdentityManagerFactory::GetForBrowserState(browserState) ->HasPrimaryAccount(); } @@ -81,18 +91,18 @@ } + (BOOL)isAuthenticated { - ChromeBrowserState* browser_state = + ChromeBrowserState* browserState = chrome_test_util::GetOriginalBrowserState(); AuthenticationService* authentication_service = - AuthenticationServiceFactory::GetForBrowserState(browser_state); + AuthenticationServiceFactory::GetForBrowserState(browserState); return authentication_service->IsAuthenticated(); } + (void)signOut { - ChromeBrowserState* browser_state = + ChromeBrowserState* browserState = chrome_test_util::GetOriginalBrowserState(); AuthenticationService* authentication_service = - AuthenticationServiceFactory::GetForBrowserState(browser_state); + AuthenticationServiceFactory::GetForBrowserState(browserState); authentication_service->SignOut(signin_metrics::SIGNOUT_TEST, /*force_clear_browsing_data=*/false, nil); }
diff --git a/ios/chrome/browser/ui/authentication/signin_earl_grey_ui.h b/ios/chrome/browser/ui/authentication/signin_earl_grey_ui.h index 90bedff..1e9890c 100644 --- a/ios/chrome/browser/ui/authentication/signin_earl_grey_ui.h +++ b/ios/chrome/browser/ui/authentication/signin_earl_grey_ui.h
@@ -17,18 +17,25 @@ SignOutConfirmationNonManagedUserWithClearedData, }; -// Methods used for the EarlGrey tests, related to UI. +// Test methods that perform sign in actions on Chrome UI. @interface SigninEarlGreyUI : NSObject -// Calls [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity -// isManagedAccount:NO]. +// Signs the account for |fakeIdentity| into Chrome through the Settings screen. +// There will be a GREYAssert if the tools menus is open when calling this +// method or if the account is not successfully signed in. + (void)signinWithFakeIdentity:(FakeChromeIdentity*)fakeIdentity; -// Adds the identity (if not already added), and perform a sign-in. if -// |isManagedAccount| is true, |fakeIdentity| needs to be a managed account and -// the managed dialog is expected while signing in. -+ (void)signinWithFakeIdentity:(FakeChromeIdentity*)fakeIdentity - isManagedAccount:(BOOL)isManagedAccount; +// Signs the primary account out of Chrome through the accounts list screen. +// Taps the "Sign Out" button to begin flow. Note that managed accounts cannot +// go through this flow. There will be a GREYAssert if the tools menus is open +// when calling this method or if the account is not successfully signed out. ++ (void)signOut; + +// Signs the primary account out of Chrome through the accounts list screen. +// Taps the "Sign out and clear data from this device" button to begin flow. +// There will be a GREYAssert if the tools menus is open when calling this +// method or if the account is not successfully signed out. ++ (void)signOutAndClearDataFromDevice; // Taps on the settings link in the sign-in view. The sign-in view has to be // opened before calling this method. @@ -38,9 +45,6 @@ // is confirmed, but it doesn't validated the user consent page. + (void)selectIdentityWithEmail:(NSString*)userEmail; -// Confirms the managed account dialog with signing in. -+ (void)confirmSigninWithManagedAccount; - // Confirms the sign in confirmation page, scrolls first to make the OK button // visible on short devices (e.g. iPhone 5s). + (void)confirmSigninConfirmationDialog;
diff --git a/ios/chrome/browser/ui/authentication/signin_earl_grey_ui.mm b/ios/chrome/browser/ui/authentication/signin_earl_grey_ui.mm index 830242a..0d32a63 100644 --- a/ios/chrome/browser/ui/authentication/signin_earl_grey_ui.mm +++ b/ios/chrome/browser/ui/authentication/signin_earl_grey_ui.mm
@@ -17,6 +17,7 @@ #import "ios/chrome/test/earl_grey/chrome_matchers_app_interface.h" #import "ios/chrome/test/scoped_eg_synchronization_disabler.h" #import "ios/public/provider/chrome/browser/signin/fake_chrome_identity.h" +#import "ios/public/provider/chrome/browser/signin/fake_chrome_identity_service.h" #import "ios/testing/earl_grey/earl_grey_test.h" #include "ui/base/l10n/l10n_util_mac.h" @@ -34,18 +35,13 @@ @implementation SigninEarlGreyUI + (void)signinWithFakeIdentity:(FakeChromeIdentity*)fakeIdentity { - [self signinWithFakeIdentity:fakeIdentity isManagedAccount:NO]; -} - -+ (void)signinWithFakeIdentity:(FakeChromeIdentity*)fakeIdentity - isManagedAccount:(BOOL)isManagedAccount { [SigninEarlGrey addFakeIdentity:fakeIdentity]; [ChromeEarlGreyUI openSettingsMenu]; [ChromeEarlGreyUI tapSettingsMenuButton:chrome_test_util::SecondarySignInButton()]; [self selectIdentityWithEmail:fakeIdentity.userEmail]; [self confirmSigninConfirmationDialog]; - if (isManagedAccount) { + if ([fakeIdentity.userEmail hasSuffix:ios::kManagedIdentityEmailSuffix]) { [self confirmSigninWithManagedAccount]; } [[EarlGrey selectElementWithMatcher:SettingsDoneButton()] @@ -53,6 +49,22 @@ [SigninEarlGrey verifySignedInWithFakeIdentity:fakeIdentity]; } ++ (void)signOut { + NSString* primaryAccountEmail = + [SigninEarlGreyAppInterface primaryAccountEmail]; + GREYAssert(![primaryAccountEmail hasSuffix:ios::kManagedIdentityEmailSuffix], + @"Managed account must clear data on signout"); + [self signOutWithButton:SignOutAccountsButton() + confirmationLabelID:IDS_IOS_DISCONNECT_DIALOG_CONTINUE_BUTTON_MOBILE]; +} + ++ (void)signOutAndClearDataFromDevice { + [self signOutWithButton: + grey_accessibilityID( + kSettingsAccountsTableViewSignoutAndClearDataCellId) + confirmationLabelID:IDS_IOS_DISCONNECT_DIALOG_CONTINUE_AND_CLEAR_MOBILE]; +} + + (void)selectIdentityWithEmail:(NSString*)userEmail { // Assumes that the identity chooser is visible. [[EarlGrey @@ -213,19 +225,6 @@ break; } } - - [ChromeEarlGreyUI tapAccountsMenuButton:signOutButtonMatcher]; - id<GREYMatcher> confirmationButtonMatcher = [ChromeMatchersAppInterface - buttonWithAccessibilityLabelID:confirmationLabelID]; - [[EarlGrey - selectElementWithMatcher:grey_allOf(confirmationButtonMatcher, - grey_not(signOutButtonMatcher), nil)] - performAction:grey_tap()]; - // Wait until the user is signed out. - [ChromeEarlGreyUI waitForAppToIdle]; - [[EarlGrey selectElementWithMatcher:SettingsDoneButton()] - performAction:grey_tap()]; - [SigninEarlGrey verifySignedOut]; } + (void)tapRemoveAccountFromDeviceWithFakeIdentity: @@ -246,4 +245,24 @@ [ChromeEarlGreyUI waitForAppToIdle]; } +#pragma mark - Private + ++ (void)signOutWithButton:(id<GREYMatcher>)buttonMatcher + confirmationLabelID:(int)confirmationLabelID { + [ChromeEarlGreyUI openSettingsMenu]; + [ChromeEarlGreyUI tapSettingsMenuButton:SettingsAccountButton()]; + + [ChromeEarlGreyUI tapAccountsMenuButton:buttonMatcher]; + id<GREYMatcher> confirmationButtonMatcher = [ChromeMatchersAppInterface + buttonWithAccessibilityLabelID:confirmationLabelID]; + [[EarlGrey selectElementWithMatcher:grey_allOf(confirmationButtonMatcher, + grey_not(buttonMatcher), nil)] + performAction:grey_tap()]; + // Wait until the user is signed out. + [ChromeEarlGreyUI waitForAppToIdle]; + [[EarlGrey selectElementWithMatcher:SettingsDoneButton()] + performAction:grey_tap()]; + [SigninEarlGrey verifySignedOut]; +} + @end
diff --git a/ios/chrome/browser/ui/autofill/form_input_accessory/BUILD.gn b/ios/chrome/browser/ui/autofill/form_input_accessory/BUILD.gn index e9dc16bf..2d494ef 100644 --- a/ios/chrome/browser/ui/autofill/form_input_accessory/BUILD.gn +++ b/ios/chrome/browser/ui/autofill/form_input_accessory/BUILD.gn
@@ -21,6 +21,7 @@ "//components/autofill/ios/form_util", "//components/keyed_service/core", "//components/password_manager/core/browser", + "//components/strings:components_strings_grit", "//ios/chrome/app/application_delegate:app_state_header", "//ios/chrome/app/strings:ios_strings_grit", "//ios/chrome/browser/autofill:autofill", @@ -29,12 +30,15 @@ "//ios/chrome/browser/browser_state", "//ios/chrome/browser/main", "//ios/chrome/browser/passwords", + "//ios/chrome/browser/ui:feature_flags", "//ios/chrome/browser/ui/autofill/manual_fill", "//ios/chrome/browser/ui/autofill/manual_fill:manual_fill_ui", + "//ios/chrome/browser/ui/commands", "//ios/chrome/browser/ui/coordinators:chrome_coordinators", "//ios/chrome/browser/ui/main:scene_state_header", "//ios/chrome/browser/ui/util", "//ios/chrome/browser/web_state_list", + "//ios/chrome/common/ui/reauthentication", "//ios/chrome/common/ui/util", "//ios/web/common", "//ios/web/public",
diff --git a/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_consumer.h b/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_consumer.h index 87913ea..16a4e0a8 100644 --- a/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_consumer.h +++ b/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_consumer.h
@@ -11,7 +11,6 @@ @class FormSuggestion; @protocol FormInputAccessoryViewDelegate; -@protocol FormSuggestionClient; @protocol FormInputAccessoryConsumer <NSObject> @@ -55,8 +54,7 @@ // Replace the keyboard accessory view with one showing the passed suggestions. // And form navigation buttons if not an iPad (which already includes those). -- (void)showAccessorySuggestions:(NSArray<FormSuggestion*>*)suggestions - suggestionClient:(id<FormSuggestionClient>)suggestionClient; +- (void)showAccessorySuggestions:(NSArray<FormSuggestion*>*)suggestions; // Indicates that the keyboard state changed. - (void)keyboardWillChangeToState:(KeyboardState)keyboardState;
diff --git a/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_coordinator.h b/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_coordinator.h index 7c12a095..5e20d43 100644 --- a/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_coordinator.h +++ b/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_coordinator.h
@@ -8,6 +8,7 @@ #import "ios/chrome/browser/ui/coordinators/chrome_coordinator.h" @class ManualFillInjectionHandler; +@class ReauthenticationModule; // Delegate for the coordinator actions. @protocol FormInputAccessoryCoordinatorNavigator <NSObject> @@ -21,9 +22,6 @@ // Opens the credit cards settings. - (void)openCreditCardSettings; -// Opens the all passwords picker, used for manual fallback. -- (void)openAllPasswordsPicker; - @end // Creates and manages a custom input accessory view while the user is @@ -38,8 +36,6 @@ // a |webStateList|. - (instancetype)initWithBaseViewController:(UIViewController*)viewController browser:(Browser*)browser - injectionHandler: - (ManualFillInjectionHandler*)injectionHandler NS_DESIGNATED_INITIALIZER; - (instancetype)initWithBaseViewController:(UIViewController*)viewController
diff --git a/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_coordinator.mm b/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_coordinator.mm index 7236a44..efa0ba0 100644 --- a/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_coordinator.mm +++ b/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_coordinator.mm
@@ -12,6 +12,7 @@ #include "components/autofill/core/common/autofill_features.h" #import "components/autofill/ios/browser/js_suggestion_manager.h" #include "components/keyed_service/core/service_access_type.h" +#include "components/strings/grit/components_strings.h" #include "ios/chrome/browser/autofill/personal_data_manager_factory.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" #import "ios/chrome/browser/main/browser.h" @@ -22,12 +23,19 @@ #import "ios/chrome/browser/ui/autofill/manual_fill/card_coordinator.h" #import "ios/chrome/browser/ui/autofill/manual_fill/fallback_view_controller.h" #import "ios/chrome/browser/ui/autofill/manual_fill/manual_fill_accessory_view_controller.h" +#import "ios/chrome/browser/ui/autofill/manual_fill/manual_fill_all_password_coordinator.h" #import "ios/chrome/browser/ui/autofill/manual_fill/manual_fill_injection_handler.h" #import "ios/chrome/browser/ui/autofill/manual_fill/manual_fill_password_coordinator.h" +#import "ios/chrome/browser/ui/commands/application_commands.h" +#import "ios/chrome/browser/ui/commands/command_dispatcher.h" +#import "ios/chrome/browser/ui/commands/open_new_tab_command.h" +#import "ios/chrome/browser/ui/commands/security_alert_commands.h" #import "ios/chrome/browser/ui/main/scene_state.h" #import "ios/chrome/browser/ui/main/scene_state_browser_agent.h" #include "ios/chrome/browser/ui/util/ui_util.h" #import "ios/chrome/browser/web_state_list/web_state_list.h" +#import "ios/chrome/common/ui/reauthentication/reauthentication_module.h" +#include "ios/chrome/grit/ios_strings.h" #import "ios/web/public/web_state.h" #include "ui/base/l10n/l10n_util_mac.h" @@ -40,7 +48,12 @@ CardCoordinatorDelegate, FormInputAccessoryMediatorDelegate, ManualFillAccessoryViewControllerDelegate, - PasswordCoordinatorDelegate> + PasswordCoordinatorDelegate, + SecurityAlertCommands> + +// Coordinator in charge of the presenting password autofill options as a modal. +@property(nonatomic, strong) + ManualFillAllPasswordCoordinator* allPasswordCoordinator; // The Mediator for the input accessory view controller. @property(nonatomic, strong) @@ -54,24 +67,35 @@ // in the forms. @property(nonatomic, strong) ManualFillInjectionHandler* injectionHandler; +// Reauthentication Module used for re-authentication. +@property(nonatomic, strong) ReauthenticationModule* reauthenticationModule; + @end @implementation FormInputAccessoryCoordinator - (instancetype)initWithBaseViewController:(UIViewController*)viewController - browser:(Browser*)browser - injectionHandler: - (ManualFillInjectionHandler*)injectionHandler { + browser:(Browser*)browser { self = [super initWithBaseViewController:viewController browser:browser]; if (self) { - _injectionHandler = injectionHandler; + CommandDispatcher* dispatcher = browser->GetCommandDispatcher(); + [dispatcher startDispatchingToTarget:self + forProtocol:@protocol(SecurityAlertCommands)]; + __weak id<SecurityAlertCommands> securityAlertHandler = + HandlerForProtocol(dispatcher, SecurityAlertCommands); + _reauthenticationModule = [[ReauthenticationModule alloc] init]; + _injectionHandler = [[ManualFillInjectionHandler alloc] + initWithWebStateList:browser->GetWebStateList() + securityAlertHandler:securityAlertHandler + reauthenticationModule:_reauthenticationModule]; } return self; } - (void)start { - _formInputAccessoryViewController = [[FormInputAccessoryViewController alloc] - initWithManualFillAccessoryViewControllerDelegate:self]; + self.formInputAccessoryViewController = + [[FormInputAccessoryViewController alloc] + initWithManualFillAccessoryViewControllerDelegate:self]; auto passwordStore = IOSChromePasswordStoreFactory::GetForBrowserState( self.browser->GetBrowserState(), ServiceAccessType::EXPLICIT_ACCESS); @@ -85,13 +109,19 @@ AppState* appState = SceneStateBrowserAgent::FromBrowser(self.browser) ->GetSceneState() .appState; - _formInputAccessoryMediator = [[FormInputAccessoryMediator alloc] - initWithConsumer:self.formInputAccessoryViewController - delegate:self - webStateList:self.browser->GetWebStateList() - personalDataManager:personalDataManager - passwordStore:passwordStore - appState:appState]; + __weak id<SecurityAlertCommands> securityAlertHandler = HandlerForProtocol( + self.browser->GetCommandDispatcher(), SecurityAlertCommands); + self.formInputAccessoryMediator = [[FormInputAccessoryMediator alloc] + initWithConsumer:self.formInputAccessoryViewController + delegate:self + webStateList:self.browser->GetWebStateList() + personalDataManager:personalDataManager + passwordStore:passwordStore + appState:appState + securityAlertHandler:securityAlertHandler + reauthenticationModule:self.reauthenticationModule]; + self.formInputAccessoryViewController.formSuggestionClient = + self.formInputAccessoryMediator; } - (void)stop { @@ -102,6 +132,9 @@ [self.formInputAccessoryMediator disconnect]; self.formInputAccessoryMediator = nil; + + [self.allPasswordCoordinator stop]; + self.allPasswordCoordinator = nil; } - (void)reset { @@ -177,6 +210,7 @@ - (void)mediatorDidDetectKeyboardHide:(FormInputAccessoryMediator*)mediator { // On iOS 13, beta 3, the popover is not dismissed when the keyboard hides. // This explicitly dismiss any popover. + // TODO(crbug.com/1116037): Verify if this workaround is still needed. if (base::ios::IsRunningOnIOS13OrLater() && IsIPadIdiom()) { [self reset]; } @@ -230,7 +264,11 @@ - (void)openAllPasswordsPicker { [self reset]; - [self.navigator openAllPasswordsPicker]; + self.allPasswordCoordinator = [[ManualFillAllPasswordCoordinator alloc] + initWithBaseViewController:self.baseViewController + browser:self.browser + injectionHandler:self.injectionHandler]; + [self.allPasswordCoordinator start]; } #pragma mark - CardCoordinatorDelegate @@ -247,4 +285,63 @@ [self.navigator openAddressSettings]; } +#pragma mark - SecurityAlertCommands + +- (void)presentSecurityWarningAlertWithText:(NSString*)body { + NSString* alertTitle = + l10n_util::GetNSString(IDS_IOS_MANUAL_FALLBACK_NOT_SECURE_TITLE); + NSString* defaultActionTitle = + l10n_util::GetNSString(IDS_IOS_MANUAL_FALLBACK_NOT_SECURE_OK_BUTTON); + + UIAlertController* alert = + [UIAlertController alertControllerWithTitle:alertTitle + message:body + preferredStyle:UIAlertControllerStyleAlert]; + UIAlertAction* defaultAction = + [UIAlertAction actionWithTitle:defaultActionTitle + style:UIAlertActionStyleDefault + handler:^(UIAlertAction* action){ + }]; + [alert addAction:defaultAction]; + UIViewController* presenter = self.baseViewController; + while (presenter.presentedViewController) { + presenter = presenter.presentedViewController; + } + [presenter presentViewController:alert animated:YES completion:nil]; +} + +- (void)showSetPasscodeDialog { + UIAlertController* alertController = [UIAlertController + alertControllerWithTitle:l10n_util::GetNSString( + IDS_IOS_SETTINGS_SET_UP_SCREENLOCK_TITLE) + message:l10n_util::GetNSString( + IDS_IOS_AUTOFILL_SET_UP_SCREENLOCK_CONTENT) + preferredStyle:UIAlertControllerStyleAlert]; + + __weak id<ApplicationCommands> applicationCommandsHandler = + HandlerForProtocol(self.browser->GetCommandDispatcher(), + ApplicationCommands); + OpenNewTabCommand* command = + [OpenNewTabCommand commandWithURLFromChrome:GURL(kPasscodeArticleURL)]; + + UIAlertAction* learnAction = [UIAlertAction + actionWithTitle:l10n_util::GetNSString( + IDS_IOS_SETTINGS_SET_UP_SCREENLOCK_LEARN_HOW) + style:UIAlertActionStyleDefault + handler:^(UIAlertAction*) { + [applicationCommandsHandler openURLInNewTab:command]; + }]; + [alertController addAction:learnAction]; + UIAlertAction* okAction = + [UIAlertAction actionWithTitle:l10n_util::GetNSString(IDS_OK) + style:UIAlertActionStyleDefault + handler:nil]; + [alertController addAction:okAction]; + alertController.preferredAction = okAction; + + [self.baseViewController presentViewController:alertController + animated:YES + completion:nil]; +} + @end
diff --git a/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_mediator.h b/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_mediator.h index 6dbc880..63bbcbf 100644 --- a/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_mediator.h +++ b/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_mediator.h
@@ -9,6 +9,7 @@ #include "components/password_manager/core/browser/password_store.h" #import "ios/chrome/browser/autofill/form_input_navigator.h" +#import "ios/chrome/browser/autofill/form_suggestion_client.h" #import "ios/chrome/browser/web_state_list/web_state_list_observer_bridge.h" #import "ios/web/public/web_state_observer_bridge.h" @@ -18,6 +19,8 @@ @class FormInputAccessoryMediator; @protocol FormInputSuggestionsProvider; @class JsSuggestionManager; +@class ReauthenticationModule; +@protocol SecurityAlertCommands; namespace autofill { class PersonalDataManager; @@ -46,18 +49,20 @@ // This class contains all the logic to get and provide keyboard input accessory // views to its consumer. As well as telling the consumer when the default // accessory view shoeuld be restored to the system default. -@interface FormInputAccessoryMediator : NSObject +@interface FormInputAccessoryMediator : NSObject <FormSuggestionClient> // Returns a mediator observing the passed `WebStateList` and associated with // the passed consumer. `webSateList` can be nullptr and `consumer` can be nil. - (instancetype) - initWithConsumer:(id<FormInputAccessoryConsumer>)consumer - delegate:(id<FormInputAccessoryMediatorDelegate>)delegate - webStateList:(WebStateList*)webStateList - personalDataManager:(autofill::PersonalDataManager*)personalDataManager - passwordStore: - (scoped_refptr<password_manager::PasswordStore>)passwordStore - appState:(AppState*)appState; + initWithConsumer:(id<FormInputAccessoryConsumer>)consumer + delegate:(id<FormInputAccessoryMediatorDelegate>)delegate + webStateList:(WebStateList*)webStateList + personalDataManager:(autofill::PersonalDataManager*)personalDataManager + passwordStore: + (scoped_refptr<password_manager::PasswordStore>)passwordStore + appState:(AppState*)appState + securityAlertHandler:(id<SecurityAlertCommands>)securityAlertHandler + reauthenticationModule:(ReauthenticationModule*)reauthenticationModule; // Unavailable, use initWithConsumer:webStateList: instead. - (instancetype)init NS_UNAVAILABLE;
diff --git a/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_mediator.mm b/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_mediator.mm index a46cf5f..da6f2c9d 100644 --- a/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_mediator.mm +++ b/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_mediator.mm
@@ -7,9 +7,11 @@ #include "base/ios/block_types.h" #include "base/ios/ios_util.h" #include "base/mac/foundation_util.h" +#include "base/metrics/histogram_functions.h" #import "base/strings/sys_string_conversions.h" #include "components/autofill/core/browser/personal_data_manager.h" #include "components/autofill/core/common/autofill_features.h" +#import "components/autofill/ios/browser/form_suggestion.h" #import "components/autofill/ios/browser/js_suggestion_manager.h" #import "components/autofill/ios/browser/personal_data_manager_observer_bridge.h" #import "components/autofill/ios/form_util/form_activity_observer_bridge.h" @@ -23,21 +25,29 @@ #import "ios/chrome/browser/passwords/password_generation_utils.h" #import "ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_consumer.h" #import "ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_view.h" +#import "ios/chrome/browser/ui/commands/security_alert_commands.h" #import "ios/chrome/browser/ui/coordinators/chrome_coordinator.h" +#import "ios/chrome/browser/ui/ui_feature_flags.h" #import "ios/chrome/browser/ui/util/keyboard_observer_helper.h" #import "ios/chrome/browser/ui/util/ui_util.h" #import "ios/chrome/browser/ui/util/uikit_ui_util.h" #import "ios/chrome/browser/web_state_list/web_state_list.h" +#include "ios/chrome/common/ui/reauthentication/reauthentication_event.h" +#import "ios/chrome/common/ui/reauthentication/reauthentication_module.h" +#include "ios/chrome/grit/ios_strings.h" #import "ios/web/common/url_scheme_util.h" #import "ios/web/public/deprecated/crw_js_injection_receiver.h" #include "ios/web/public/js_messaging/web_frame.h" #include "ios/web/public/js_messaging/web_frames_manager.h" #import "ios/web/public/web_state.h" +#include "ui/base/l10n/l10n_util_mac.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." #endif +using base::UmaHistogramEnumeration; + @interface FormInputAccessoryMediator () <AppStateObserver, FormActivityObserver, FormInputAccessoryViewDelegate, @@ -90,6 +100,12 @@ // that was tapped. @property(nonatomic, weak) AppState* appState; +// Reauthentication Module used for re-authentication. +@property(nonatomic, strong) ReauthenticationModule* reauthenticationModule; + +// Used to present alerts. +@property(nonatomic, weak) id<SecurityAlertCommands> securityAlertHandler; + @end @implementation FormInputAccessoryMediator { @@ -126,13 +142,15 @@ } - (instancetype) - initWithConsumer:(id<FormInputAccessoryConsumer>)consumer - delegate:(id<FormInputAccessoryMediatorDelegate>)delegate - webStateList:(WebStateList*)webStateList - personalDataManager:(autofill::PersonalDataManager*)personalDataManager - passwordStore: - (scoped_refptr<password_manager::PasswordStore>)passwordStore - appState:(AppState*)appState { + initWithConsumer:(id<FormInputAccessoryConsumer>)consumer + delegate:(id<FormInputAccessoryMediatorDelegate>)delegate + webStateList:(WebStateList*)webStateList + personalDataManager:(autofill::PersonalDataManager*)personalDataManager + passwordStore: + (scoped_refptr<password_manager::PasswordStore>)passwordStore + appState:(AppState*)appState + securityAlertHandler:(id<SecurityAlertCommands>)securityAlertHandler + reauthenticationModule:(ReauthenticationModule*)reauthenticationModule { self = [super init]; if (self) { _consumer = consumer; @@ -220,6 +238,8 @@ if (!base::ios::IsRunningOnIOS14OrLater()) { [_appState addObserver:self]; } + _reauthenticationModule = reauthenticationModule; + _securityAlertHandler = securityAlertHandler; } return self; } @@ -530,8 +550,7 @@ // If suggestions are enabled update |currentProvider|. self.currentProvider = provider; // Post it to the consumer. - [self.consumer showAccessorySuggestions:suggestions - suggestionClient:provider]; + [self.consumer showAccessorySuggestions:suggestions]; } } @@ -608,6 +627,44 @@ [self verifyFirstResponderAndUpdateCustomKeyboardView]; } +#pragma mark - FormSuggestionClient + +- (void)didSelectSuggestion:(FormSuggestion*)formSuggestion { + UmaHistogramEnumeration("IOS.Reauth.Password.Autofill", + ReauthenticationEvent::kAttempt); + + if (!base::FeatureList::IsEnabled(kEnableAutofillPasswordReauthIOS) || + !formSuggestion.requiresReauth) { + UmaHistogramEnumeration("IOS.Reauth.Password.Autofill", + ReauthenticationEvent::kSuccess); + [self.currentProvider didSelectSuggestion:formSuggestion]; + return; + } + if ([self.reauthenticationModule canAttemptReauth]) { + NSString* reason = l10n_util::GetNSString(IDS_IOS_AUTOFILL_REAUTH_REASON); + __weak __typeof(self) weakSelf = self; + auto completionHandler = ^(ReauthenticationResult result) { + if (result != ReauthenticationResult::kFailure) { + UmaHistogramEnumeration("IOS.Reauth.Password.Autofill", + ReauthenticationEvent::kSuccess); + [weakSelf.currentProvider didSelectSuggestion:formSuggestion]; + } else { + UmaHistogramEnumeration("IOS.Reauth.Password.Autofill", + ReauthenticationEvent::kFailure); + } + }; + + [self.reauthenticationModule + attemptReauthWithLocalizedReason:reason + canReusePreviousAuth:YES + handler:completionHandler]; + } else { + UmaHistogramEnumeration("IOS.Reauth.Password.Autofill", + ReauthenticationEvent::kMissingPasscode); + [self.securityAlertHandler showSetPasscodeDialog]; + } +} + #pragma mark - PasswordFetcherDelegate - (void)passwordFetcher:(PasswordFetcher*)passwordFetcher
diff --git a/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_view_controller.h b/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_view_controller.h index 3d3822c..7e009185 100644 --- a/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_view_controller.h +++ b/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_view_controller.h
@@ -9,6 +9,7 @@ #import "ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_consumer.h" +@protocol FormSuggestionClient; @class ManualFillAccessoryViewController; @protocol ManualFillAccessoryViewControllerDelegate; @@ -19,6 +20,9 @@ @interface FormInputAccessoryViewController : NSObject <FormInputAccessoryConsumer> +// Client in charge of handling actions in suggestions. +@property(nonatomic, weak) id<FormSuggestionClient> formSuggestionClient; + // Presents a view above the keyboard. - (void)presentView:(UIView*)view;
diff --git a/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_view_controller.mm b/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_view_controller.mm index ff04cd3..a55ef573 100644 --- a/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_view_controller.mm +++ b/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_view_controller.mm
@@ -8,6 +8,7 @@ #include "base/metrics/histogram_macros.h" #include "base/metrics/user_metrics.h" #include "components/autofill/core/common/autofill_features.h" +#import "ios/chrome/browser/autofill/form_suggestion_client.h" #import "ios/chrome/browser/autofill/form_suggestion_view.h" #import "ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_view.h" #import "ios/chrome/browser/ui/autofill/manual_fill/manual_fill_accessory_view_controller.h" @@ -189,11 +190,9 @@ } } -- (void)showAccessorySuggestions:(NSArray<FormSuggestion*>*)suggestions - suggestionClient:(id<FormSuggestionClient>)suggestionClient { +- (void)showAccessorySuggestions:(NSArray<FormSuggestion*>*)suggestions { [self createFormSuggestionViewIfNeeded]; - [self.formSuggestionView updateClient:suggestionClient - suggestions:suggestions]; + [self.formSuggestionView updateSuggestions:suggestions]; [self addInputAccessoryViewIfNeeded]; } @@ -362,6 +361,11 @@ #pragma mark - FormSuggestionViewDelegate +- (void)formSuggestionView:(FormSuggestionView*)formSuggestionView + didAcceptSuggestion:(FormSuggestion*)suggestion { + [self.formSuggestionClient didSelectSuggestion:suggestion]; +} + - (void)formSuggestionViewShouldResetFromPull: (FormSuggestionView*)formSuggestionView { base::RecordAction(base::UserMetricsAction("ManualFallback_ClosePull"));
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_injection_handler.h b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_injection_handler.h index 689bf398..0aa8396 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_injection_handler.h +++ b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_injection_handler.h
@@ -9,33 +9,20 @@ #import "ios/chrome/browser/ui/autofill/manual_fill/manual_fill_content_injector.h" -@protocol AutofillSecurityAlertPresenter<NSObject> - -// Presents an alert with the passed body. And a title indicating something is -// not secure. Credit card numbers and passwords cannot be filled over HTTP, and -// passwords can only be filled in a password field; when a user attempts to -// autofill these a warning is displayed using the security alert presenter -- (void)presentSecurityWarningAlertWithText:(NSString*)body; - -// Request the presented a dialog informing the user that a password must be set -// to use the feature. -- (void)showSetPasscodeDialog; - -@end - @class ReauthenticationModule; +@protocol SecurityAlertCommands; class WebStateList; // Handler with the common logic for injecting data from manual fill. +// TODO(crbug.com/1116980): Convert ManualFillInjectionHandler to browser agent. @interface ManualFillInjectionHandler : NSObject <ManualFillContentInjector> // Returns a handler using the |WebStateList| to inject JS to the active web // state and |securityAlertPresenter| to present alerts. -- (instancetype)initWithWebStateList:(WebStateList*)webStateList - securityAlertPresenter: - (id<AutofillSecurityAlertPresenter>)securityAlertPresenter - reauthenticationModule: - (ReauthenticationModule*)reauthenticationModule; +- (instancetype) + initWithWebStateList:(WebStateList*)webStateList + securityAlertHandler:(id<SecurityAlertCommands>)securityAlertHandler + reauthenticationModule:(ReauthenticationModule*)reauthenticationModule; @end
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_injection_handler.mm b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_injection_handler.mm index 4404e8b9..7ea8bc2e 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_injection_handler.mm +++ b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_injection_handler.mm
@@ -11,6 +11,7 @@ #include "base/bind.h" #include "base/json/string_escape.h" #include "base/mac/foundation_util.h" +#include "base/metrics/histogram_functions.h" #include "base/strings/sys_string_conversions.h" #include "base/values.h" #import "components/autofill/ios/browser/autofill_util.h" @@ -20,8 +21,10 @@ #import "ios/chrome/browser/autofill/form_input_accessory_view_handler.h" #import "ios/chrome/browser/passwords/password_tab_helper.h" #import "ios/chrome/browser/ui/autofill/manual_fill/form_observer_helper.h" +#import "ios/chrome/browser/ui/commands/security_alert_commands.h" #import "ios/chrome/browser/ui/ui_feature_flags.h" #import "ios/chrome/browser/web_state_list/web_state_list.h" +#include "ios/chrome/common/ui/reauthentication/reauthentication_event.h" #import "ios/chrome/common/ui/reauthentication/reauthentication_module.h" #include "ios/chrome/grit/ios_strings.h" #import "ios/web/public/deprecated/crw_js_injection_receiver.h" @@ -36,6 +39,8 @@ #error "This file requires ARC support." #endif +using base::UmaHistogramEnumeration; + namespace { // The timeout for any JavaScript call in this file. const int64_t kJavaScriptExecutionTimeoutInSeconds = 1; @@ -75,21 +80,20 @@ @property(nonatomic, assign) std::string lastFocusedElementIdentifier; // Used to present alerts. -@property(nonatomic, weak) id<AutofillSecurityAlertPresenter> alertPresenter; +@property(nonatomic, weak) id<SecurityAlertCommands> securityAlertHandler; @end @implementation ManualFillInjectionHandler -- (instancetype)initWithWebStateList:(WebStateList*)webStateList - securityAlertPresenter: - (id<AutofillSecurityAlertPresenter>)securityAlertPresenter - reauthenticationModule: - (ReauthenticationModule*)reauthenticationModule { +- (instancetype) + initWithWebStateList:(WebStateList*)webStateList + securityAlertHandler:(id<SecurityAlertCommands>)securityAlertHandler + reauthenticationModule:(ReauthenticationModule*)reauthenticationModule { self = [super init]; if (self) { _webStateList = webStateList; - _alertPresenter = securityAlertPresenter; + _securityAlertHandler = securityAlertHandler; _formHelper = [[FormObserverHelper alloc] initWithWebStateList:webStateList]; _formHelper.delegate = self; @@ -105,13 +109,13 @@ if (passwordField && ![self isLastFocusedElementPasswordField]) { NSString* alertBody = l10n_util::GetNSString( IDS_IOS_MANUAL_FALLBACK_NOT_SECURE_PASSWORD_BODY); - [self.alertPresenter presentSecurityWarningAlertWithText:alertBody]; + [self.securityAlertHandler presentSecurityWarningAlertWithText:alertBody]; return NO; } if (requiresHTTPS && ![self isLastFocusedElementSecure]) { NSString* alertBody = l10n_util::GetNSString(IDS_IOS_MANUAL_FALLBACK_NOT_SECURE_GENERIC_BODY); - [self.alertPresenter presentSecurityWarningAlertWithText:alertBody]; + [self.securityAlertHandler presentSecurityWarningAlertWithText:alertBody]; return NO; } return YES; @@ -120,10 +124,19 @@ - (void)userDidPickContent:(NSString*)content passwordField:(BOOL)passwordField requiresHTTPS:(BOOL)requiresHTTPS { + if (passwordField) { + UmaHistogramEnumeration("IOS.Reauth.Password.ManualFallback", + ReauthenticationEvent::kAttempt); + } + if ([self canUserInjectInPasswordField:passwordField requiresHTTPS:requiresHTTPS]) { if (!base::FeatureList::IsEnabled(kEnableAutofillPasswordReauthIOS)) { [self fillLastSelectedFieldWithString:content]; + if (passwordField) { + UmaHistogramEnumeration("IOS.Reauth.Password.ManualFallback", + ReauthenticationEvent::kSuccess); + } } else { if (!passwordField) { [self fillLastSelectedFieldWithString:content]; @@ -136,7 +149,12 @@ __weak __typeof(self) weakSelf = self; auto completionHandler = ^(ReauthenticationResult result) { if (result != ReauthenticationResult::kFailure) { + UmaHistogramEnumeration("IOS.Reauth.Password.ManualFallback", + ReauthenticationEvent::kSuccess); [weakSelf fillLastSelectedFieldWithString:content]; + } else { + UmaHistogramEnumeration("IOS.Reauth.Password.ManualFallback", + ReauthenticationEvent::kFailure); } }; @@ -145,7 +163,9 @@ canReusePreviousAuth:YES handler:completionHandler]; } else { - [self.alertPresenter showSetPasscodeDialog]; + UmaHistogramEnumeration("IOS.Reauth.Password.ManualFallback", + ReauthenticationEvent::kMissingPasscode); + [self.securityAlertHandler showSetPasscodeDialog]; } } }
diff --git a/ios/chrome/browser/ui/browser_view/BUILD.gn b/ios/chrome/browser/ui/browser_view/BUILD.gn index 0895551..cc31afc 100644 --- a/ios/chrome/browser/ui/browser_view/BUILD.gn +++ b/ios/chrome/browser/ui/browser_view/BUILD.gn
@@ -79,8 +79,6 @@ "//ios/chrome/browser/ui/authentication", "//ios/chrome/browser/ui/autofill:autofill", "//ios/chrome/browser/ui/autofill/form_input_accessory", - "//ios/chrome/browser/ui/autofill/manual_fill", - "//ios/chrome/browser/ui/autofill/manual_fill:manual_fill_ui", "//ios/chrome/browser/ui/badges:badges_popup_menu", "//ios/chrome/browser/ui/bookmarks", "//ios/chrome/browser/ui/browser_container",
diff --git a/ios/chrome/browser/ui/browser_view/browser_coordinator.mm b/ios/chrome/browser/ui/browser_view/browser_coordinator.mm index c3f0228..284ed1d 100644 --- a/ios/chrome/browser/ui/browser_view/browser_coordinator.mm +++ b/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
@@ -7,8 +7,6 @@ #include <memory> #include "base/scoped_observer.h" -#include "base/strings/sys_string_conversions.h" -#include "components/strings/grit/components_strings.h" #import "ios/chrome/browser/app_launcher/app_launcher_abuse_detector.h" #import "ios/chrome/browser/app_launcher/app_launcher_tab_helper.h" #import "ios/chrome/browser/autofill/autofill_tab_helper.h" @@ -26,8 +24,6 @@ #import "ios/chrome/browser/ui/activity_services/requirements/activity_service_positioner.h" #import "ios/chrome/browser/ui/alert_coordinator/repost_form_coordinator.h" #import "ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_coordinator.h" -#import "ios/chrome/browser/ui/autofill/manual_fill/manual_fill_all_password_coordinator.h" -#import "ios/chrome/browser/ui/autofill/manual_fill/manual_fill_injection_handler.h" #import "ios/chrome/browser/ui/badges/badge_popup_menu_coordinator.h" #import "ios/chrome/browser/ui/browser_container/browser_container_coordinator.h" #import "ios/chrome/browser/ui/browser_view/browser_view_controller+private.h" @@ -77,8 +73,6 @@ #import "ios/chrome/browser/web/repost_form_tab_helper_delegate.h" #include "ios/chrome/browser/web_state_list/web_state_list.h" #import "ios/chrome/browser/web_state_list/web_state_list_observer_bridge.h" -#import "ios/chrome/common/ui/reauthentication/reauthentication_module.h" -#include "ios/chrome/grit/ios_strings.h" #include "ui/base/l10n/l10n_util_mac.h" #if !defined(__has_feature) || !__has_feature(objc_arc) @@ -86,7 +80,6 @@ #endif @interface BrowserCoordinator () <ActivityServiceCommands, - AutofillSecurityAlertPresenter, BrowserCoordinatorCommands, FormInputAccessoryCoordinatorNavigator, PageInfoCommands, @@ -109,9 +102,6 @@ // Mediator between OpenIn TabHelper and OpenIn UI. @property(nonatomic, strong) OpenInMediator* openInMediator; -// Reauthentication Module used for re-authentication. -@property(nonatomic, strong) ReauthenticationModule* reauthenticationModule; - // ================================================= // Child Coordinators, listed in alphabetical order. // ================================================= @@ -135,14 +125,6 @@ @property(nonatomic, strong) FormInputAccessoryCoordinator* formInputAccessoryCoordinator; -// The object in charge of interacting with the web view. Used to fill the data -// in the forms. -@property(nonatomic, strong) ManualFillInjectionHandler* injectionHandler; - -// Coordinator in charge of the presenting password autofill options as a modal. -@property(nonatomic, strong) - ManualFillAllPasswordCoordinator* allPasswordCoordinator; - // Weak reference for the next coordinator to be displayed over the toolbar. @property(nonatomic, weak) ChromeCoordinator* nextToolbarCoordinator; @@ -346,14 +328,9 @@ browser:self.browser]; [self.ARQuickLookCoordinator start]; - self.injectionHandler = [[ManualFillInjectionHandler alloc] - initWithWebStateList:self.browser->GetWebStateList() - securityAlertPresenter:self - reauthenticationModule:self.reauthenticationModule]; self.formInputAccessoryCoordinator = [[FormInputAccessoryCoordinator alloc] initWithBaseViewController:self.viewController - browser:self.browser - injectionHandler:self.injectionHandler]; + browser:self.browser]; self.formInputAccessoryCoordinator.navigator = self; [self.formInputAccessoryCoordinator start]; @@ -420,9 +397,6 @@ // Stops child coordinators. - (void)stopChildCoordinators { - [self.allPasswordCoordinator stop]; - self.allPasswordCoordinator = nil; - [self.ARQuickLookCoordinator stop]; self.ARQuickLookCoordinator = nil; @@ -431,7 +405,6 @@ [self.formInputAccessoryCoordinator stop]; self.formInputAccessoryCoordinator = nil; - self.injectionHandler = nil; [self.pageInfoCoordinator stop]; self.pageInfoCoordinator = nil; @@ -481,73 +454,6 @@ self.infobarModalOverlayContainerCoordinator = nil; } -#pragma mark - Properties - -- (ReauthenticationModule*)reauthenticationModule { - if (!_reauthenticationModule) { - _reauthenticationModule = [[ReauthenticationModule alloc] init]; - } - return _reauthenticationModule; -} - -#pragma mark - AutofillSecurityAlertPresenter - -- (void)presentSecurityWarningAlertWithText:(NSString*)body { - NSString* alertTitle = - l10n_util::GetNSString(IDS_IOS_MANUAL_FALLBACK_NOT_SECURE_TITLE); - NSString* defaultActionTitle = - l10n_util::GetNSString(IDS_IOS_MANUAL_FALLBACK_NOT_SECURE_OK_BUTTON); - - UIAlertController* alert = - [UIAlertController alertControllerWithTitle:alertTitle - message:body - preferredStyle:UIAlertControllerStyleAlert]; - UIAlertAction* defaultAction = - [UIAlertAction actionWithTitle:defaultActionTitle - style:UIAlertActionStyleDefault - handler:^(UIAlertAction* action){ - }]; - [alert addAction:defaultAction]; - UIViewController* presenter = self.viewController; - while (presenter.presentedViewController) { - presenter = presenter.presentedViewController; - } - [presenter presentViewController:alert animated:YES completion:nil]; -} - -- (void)showSetPasscodeDialog { - UIAlertController* alertController = [UIAlertController - alertControllerWithTitle:l10n_util::GetNSString( - IDS_IOS_SETTINGS_SET_UP_SCREENLOCK_TITLE) - message:l10n_util::GetNSString( - IDS_IOS_AUTOFILL_SET_UP_SCREENLOCK_CONTENT) - preferredStyle:UIAlertControllerStyleAlert]; - - __weak id<ApplicationCommands> applicationCommandsHandler = - HandlerForProtocol(self.dispatcher, ApplicationCommands); - OpenNewTabCommand* command = - [OpenNewTabCommand commandWithURLFromChrome:GURL(kPasscodeArticleURL)]; - - UIAlertAction* learnAction = [UIAlertAction - actionWithTitle:l10n_util::GetNSString( - IDS_IOS_SETTINGS_SET_UP_SCREENLOCK_LEARN_HOW) - style:UIAlertActionStyleDefault - handler:^(UIAlertAction*) { - [applicationCommandsHandler openURLInNewTab:command]; - }]; - [alertController addAction:learnAction]; - UIAlertAction* okAction = - [UIAlertAction actionWithTitle:l10n_util::GetNSString(IDS_OK) - style:UIAlertActionStyleDefault - handler:nil]; - [alertController addAction:okAction]; - alertController.preferredAction = okAction; - - [self.viewController presentViewController:alertController - animated:YES - completion:nil]; -} - #pragma mark - ActivityServiceCommands - (void)sharePage { @@ -785,14 +691,6 @@ showCreditCardSettingsFromViewController:self.viewController]; } -- (void)openAllPasswordsPicker { - self.allPasswordCoordinator = [[ManualFillAllPasswordCoordinator alloc] - initWithBaseViewController:self.viewController - browser:self.browser - injectionHandler:self.injectionHandler]; - [self.allPasswordCoordinator start]; -} - #pragma mark - RepostFormTabHelperDelegate - (void)repostFormTabHelper:(RepostFormTabHelper*)helper
diff --git a/ios/chrome/browser/ui/commands/BUILD.gn b/ios/chrome/browser/ui/commands/BUILD.gn index 555579f..0e138ac 100644 --- a/ios/chrome/browser/ui/commands/BUILD.gn +++ b/ios/chrome/browser/ui/commands/BUILD.gn
@@ -30,6 +30,7 @@ "qr_scanner_commands.h", "reading_list_add_command.h", "reading_list_add_command.mm", + "security_alert_commands.h", "show_signin_command.h", "show_signin_command.mm", "snackbar_commands.h",
diff --git a/ios/chrome/browser/ui/commands/application_commands.h b/ios/chrome/browser/ui/commands/application_commands.h index b8e2881..2b60a529 100644 --- a/ios/chrome/browser/ui/commands/application_commands.h +++ b/ios/chrome/browser/ui/commands/application_commands.h
@@ -115,6 +115,13 @@ - (void)showReportAnIssueFromViewController: (UIViewController*)baseViewController; +// Shows the Report an Issue UI, presenting from |baseViewController|, using +// |specificProductData| for additional product data to be sent in the report. +- (void) + showReportAnIssueFromViewController:(UIViewController*)baseViewController + specificProductData:(NSDictionary<NSString*, NSString*>*) + specificProductData; + // Opens the |command| URL in a new tab. // TODO(crbug.com/907527): Check if it is possible to merge it with the // URLLoader methods.
diff --git a/ios/chrome/browser/ui/commands/security_alert_commands.h b/ios/chrome/browser/ui/commands/security_alert_commands.h new file mode 100644 index 0000000..c86204e3 --- /dev/null +++ b/ios/chrome/browser/ui/commands/security_alert_commands.h
@@ -0,0 +1,22 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_UI_COMMANDS_SECURITY_ALERT_COMMANDS_H_ +#define IOS_CHROME_BROWSER_UI_COMMANDS_SECURITY_ALERT_COMMANDS_H_ + +@protocol SecurityAlertCommands <NSObject> + +// Presents an alert with the passed body. And a title indicating something is +// not secure. Credit card numbers and passwords cannot be filled over HTTP, and +// passwords can only be filled in a password field; when a user attempts to +// autofill these a warning is displayed using the security alert presenter +- (void)presentSecurityWarningAlertWithText:(NSString*)body; + +// Request the presenter to inform the user that a password must be set to use +// the feature. +- (void)showSetPasscodeDialog; + +@end + +#endif // IOS_CHROME_BROWSER_UI_COMMANDS_SECURITY_ALERT_COMMANDS_H_
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm index a46a8b5b..00b2c1a 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm
@@ -775,7 +775,16 @@ DCHECK(_discoverFeed != discoverFeed); _discoverFeed = discoverFeed; _discoverItem.discoverFeed = _discoverFeed; - [self.dataSink reloadAllData]; + // The UICollectionView -reloadData method is a no-op if it is called at the + // same time as other collection updates. This full refresh command can come + // at the same time as other collection update commands. To make sure that it + // is taken into account, dispatch it with a delay. See + // http://crbug.com/945726. + dispatch_after( + dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), + dispatch_get_main_queue(), ^{ + [self reloadAllData]; + }); } #pragma mark - PrefObserverDelegate
diff --git a/ios/chrome/browser/ui/main/scene_controller.mm b/ios/chrome/browser/ui/main/scene_controller.mm index b1e8bde7..c805547 100644 --- a/ios/chrome/browser/ui/main/scene_controller.mm +++ b/ios/chrome/browser/ui/main/scene_controller.mm
@@ -198,6 +198,11 @@ // time it is accessed. @property(nonatomic, strong) SigninCoordinator* signinCoordinator; +// Additional product specific data used by UserFeedbackDataSource. +// TODO(crbug.com/1117041): Move this into a UserFeedback config object. +@property(nonatomic, strong) + NSDictionary<NSString*, NSString*>* specificProductData; + @end @implementation SceneController { @@ -845,7 +850,16 @@ - (void)showReportAnIssueFromViewController: (UIViewController*)baseViewController { + [self showReportAnIssueFromViewController:baseViewController + specificProductData:nil]; +} + +- (void) + showReportAnIssueFromViewController:(UIViewController*)baseViewController + specificProductData:(NSDictionary<NSString*, NSString*>*) + specificProductData { DCHECK(baseViewController); + self.specificProductData = specificProductData; // This dispatch is necessary to give enough time for the tools menu to // disappear before taking a screenshot. dispatch_async(dispatch_get_main_queue(), ^{ @@ -1216,6 +1230,10 @@ return username.empty() ? nil : base::SysUTF8ToNSString(username); } +- (NSDictionary<NSString*, NSString*>*)specificProductData { + return _specificProductData; +} + #pragma mark - SettingsNavigationControllerDelegate - (void)closeSettings {
diff --git a/ios/chrome/browser/ui/ntp/BUILD.gn b/ios/chrome/browser/ui/ntp/BUILD.gn index e3c24b6..f16e6b5 100644 --- a/ios/chrome/browser/ui/ntp/BUILD.gn +++ b/ios/chrome/browser/ui/ntp/BUILD.gn
@@ -22,12 +22,9 @@ ":ntp", ":ntp_internal", "//ios/chrome/browser/browser_state", - "//ios/chrome/browser/content_settings", "//ios/chrome/browser/main:public", - "//ios/chrome/browser/ui:feature_flags", "//ios/chrome/browser/ui/content_suggestions", "//ios/chrome/browser/ui/coordinators:chrome_coordinators", - "//ios/chrome/browser/ui/settings/privacy", "//ios/chrome/browser/url_loading", "//ios/chrome/browser/web_state_list", "//ios/public/provider/chrome/browser/voice", @@ -51,8 +48,6 @@ source_set("ntp_internal") { configs += [ "//build/config/compiler:enable_arc" ] sources = [ - "incognito_cookies_view.h", - "incognito_cookies_view.mm", "incognito_view.h", "incognito_view.mm", "incognito_view_controller.h", @@ -113,7 +108,6 @@ "//ios/chrome/browser/ui/overscroll_actions", "//ios/chrome/browser/ui/page_info:features", "//ios/chrome/browser/ui/settings/cells", - "//ios/chrome/browser/ui/settings/privacy:privacy_ui", "//ios/chrome/browser/ui/toolbar/buttons", "//ios/chrome/browser/ui/toolbar/public", "//ios/chrome/browser/ui/util",
diff --git a/ios/chrome/browser/ui/ntp/incognito_cookies_view.h b/ios/chrome/browser/ui/ntp/incognito_cookies_view.h deleted file mode 100644 index 0b003261..0000000 --- a/ios/chrome/browser/ui/ntp/incognito_cookies_view.h +++ /dev/null
@@ -1,22 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_UI_NTP_INCOGNITO_COOKIES_VIEW_H_ -#define IOS_CHROME_BROWSER_UI_NTP_INCOGNITO_COOKIES_VIEW_H_ - -#import <UIKit/UIKit.h> - -// View for displaying the controls for cookies. -@interface IncognitoCookiesView : UIView - -- (instancetype)init NS_DESIGNATED_INITIALIZER; -- (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE; -- (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE; - -// Switch to manage cookies blocking. -@property(nonatomic, strong, readonly) UISwitch* cookiesBlockedSwitch; - -@end - -#endif // IOS_CHROME_BROWSER_UI_NTP_INCOGNITO_COOKIES_VIEW_H_
diff --git a/ios/chrome/browser/ui/ntp/incognito_cookies_view.mm b/ios/chrome/browser/ui/ntp/incognito_cookies_view.mm deleted file mode 100644 index 3476008..0000000 --- a/ios/chrome/browser/ui/ntp/incognito_cookies_view.mm +++ /dev/null
@@ -1,112 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "ios/chrome/browser/ui/ntp/incognito_cookies_view.h" - -#include "components/strings/grit/components_strings.h" -#import "ios/chrome/browser/ui/util/uikit_ui_util.h" -#import "ios/chrome/common/ui/colors/UIColor+cr_semantic_colors.h" -#import "ios/chrome/common/ui/colors/dynamic_color_util.h" -#import "ios/chrome/common/ui/colors/semantic_color_names.h" -#import "ios/chrome/common/ui/util/constraints_ui_util.h" -#include "ios/chrome/grit/ios_strings.h" -#include "ui/base/l10n/l10n_util.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -namespace { - -const CGFloat kHorizontalSpacing = 14.0f; - -const CGFloat kVerticalSpacing = 16.0f; - -const CGFloat kVerticalLabelMargin = 6.0f; - -} // namespace - -@implementation IncognitoCookiesView - -#pragma mark - UIView - -- (instancetype)init { - self = [super initWithFrame:CGRectZero]; - if (self) { - UIColor* bodyTextColor = color::DarkModeDynamicColor( - [UIColor colorNamed:kTextSecondaryColor], true, - [UIColor colorNamed:kTextSecondaryDarkColor]); - self.layer.borderWidth = 1; - self.layer.borderColor = bodyTextColor.CGColor; - self.layer.cornerRadius = 10; - - // Cookies title. - UILabel* titleLabel = [[UILabel alloc] init]; - titleLabel.textColor = UIColor.whiteColor; - titleLabel.adjustsFontForContentSizeCategory = YES; - titleLabel.numberOfLines = 0; - titleLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleCallout]; - titleLabel.translatesAutoresizingMaskIntoConstraints = NO; - titleLabel.text = - l10n_util::GetNSString(IDS_NEW_TAB_OTR_THIRD_PARTY_COOKIE); - - [self addSubview:titleLabel]; - - // Cookies description. - UILabel* descriptionLabel = [[UILabel alloc] init]; - descriptionLabel.textColor = bodyTextColor; - descriptionLabel.adjustsFontForContentSizeCategory = YES; - descriptionLabel.numberOfLines = 0; - descriptionLabel.font = - [UIFont preferredFontForTextStyle:UIFontTextStyleFootnote]; - descriptionLabel.translatesAutoresizingMaskIntoConstraints = NO; - descriptionLabel.text = - l10n_util::GetNSString(IDS_NEW_TAB_OTR_THIRD_PARTY_COOKIE_SUBLABEL); - - [self addSubview:descriptionLabel]; - - // Cookies switch. - _cookiesBlockedSwitch = [[UISwitch alloc] init]; - _cookiesBlockedSwitch.translatesAutoresizingMaskIntoConstraints = NO; - [self addSubview:_cookiesBlockedSwitch]; - [_cookiesBlockedSwitch - setContentCompressionResistancePriority:UILayoutPriorityDefaultHigh + 1 - forAxis: - UILayoutConstraintAxisHorizontal]; - - NSArray* constraints = @[ - // titleLabel constraints. - [titleLabel.leadingAnchor constraintEqualToAnchor:self.leadingAnchor - constant:kHorizontalSpacing], - [titleLabel.trailingAnchor - constraintEqualToAnchor:_cookiesBlockedSwitch.leadingAnchor - constant:-kHorizontalSpacing], - [titleLabel.trailingAnchor - constraintEqualToAnchor:descriptionLabel.trailingAnchor], - [titleLabel.topAnchor constraintEqualToAnchor:self.topAnchor - constant:kVerticalSpacing], - - // descriptionLabel constraints. - [descriptionLabel.leadingAnchor - constraintEqualToAnchor:self.leadingAnchor - constant:kHorizontalSpacing], - [descriptionLabel.topAnchor - constraintEqualToAnchor:titleLabel.bottomAnchor - constant:kVerticalLabelMargin], - [descriptionLabel.bottomAnchor constraintEqualToAnchor:self.bottomAnchor - constant:-kVerticalSpacing], - - // cookiesBlockedSwitch constraints. - [_cookiesBlockedSwitch.trailingAnchor - constraintEqualToAnchor:self.trailingAnchor - constant:-kHorizontalSpacing], - [_cookiesBlockedSwitch.centerYAnchor - constraintEqualToAnchor:self.centerYAnchor], - ]; - [NSLayoutConstraint activateConstraints:constraints]; - } - return self; -} - -@end
diff --git a/ios/chrome/browser/ui/ntp/incognito_view.h b/ios/chrome/browser/ui/ntp/incognito_view.h index 994b194..32133e2 100644 --- a/ios/chrome/browser/ui/ntp/incognito_view.h +++ b/ios/chrome/browser/ui/ntp/incognito_view.h
@@ -16,9 +16,6 @@ - (instancetype)initWithFrame:(CGRect)frame URLLoader:(UrlLoadingBrowserAgent*)URLLoader; -// Switch to manage cookies blocking. -@property(nonatomic, readonly) UISwitch* cookiesBlockedSwitch; - @end #endif // IOS_CHROME_BROWSER_UI_NTP_INCOGNITO_VIEW_H_
diff --git a/ios/chrome/browser/ui/ntp/incognito_view.mm b/ios/chrome/browser/ui/ntp/incognito_view.mm index 8e6f268..7159248 100644 --- a/ios/chrome/browser/ui/ntp/incognito_view.mm +++ b/ios/chrome/browser/ui/ntp/incognito_view.mm
@@ -11,7 +11,6 @@ #include "ios/chrome/browser/application_context.h" #include "ios/chrome/browser/drag_and_drop/drag_and_drop_flag.h" #import "ios/chrome/browser/drag_and_drop/url_drag_drop_handler.h" -#import "ios/chrome/browser/ui/ntp/incognito_cookies_view.h" #import "ios/chrome/browser/ui/page_info/features.h" #import "ios/chrome/browser/ui/toolbar/public/toolbar_constants.h" #import "ios/chrome/browser/ui/toolbar/public/toolbar_utils.h" @@ -125,8 +124,6 @@ @interface IncognitoView () <URLDropDelegate> -@property(nonatomic, strong) IncognitoCookiesView* cookiesView; - @end @implementation IncognitoView { @@ -201,9 +198,6 @@ [self addTextSections]; - if (base::FeatureList::IsEnabled(content_settings::kImprovedCookieControls)) - [self addCookiesViewController]; - // |topGuide| and |bottomGuide| exist to vertically position the stackview // inside the container scrollview. UILayoutGuide* topGuide = [[UILayoutGuide alloc] init]; @@ -297,12 +291,6 @@ return self; } -#pragma mark - Properties - -- (UISwitch*)cookiesBlockedSwitch { - return self.cookiesView.cookiesBlockedSwitch; -} - #pragma mark - UIView overrides - (void)didMoveToSuperview { @@ -496,9 +484,4 @@ object:nil]; } -- (void)addCookiesViewController { - self.cookiesView = [[IncognitoCookiesView alloc] init]; - [_stackView addArrangedSubview:self.cookiesView]; -} - @end
diff --git a/ios/chrome/browser/ui/ntp/incognito_view_controller.h b/ios/chrome/browser/ui/ntp/incognito_view_controller.h index 23df9699..61564ae 100644 --- a/ios/chrome/browser/ui/ntp/incognito_view_controller.h +++ b/ios/chrome/browser/ui/ntp/incognito_view_controller.h
@@ -7,21 +7,17 @@ #import <UIKit/UIKit.h> -#import "ios/chrome/browser/ui/settings/privacy/cookies_consumer.h" @protocol NewTabPageControllerDelegate; @protocol PrivacyCookiesCommands; class UrlLoadingBrowserAgent; -@interface IncognitoViewController : UIViewController <PrivacyCookiesConsumer> +@interface IncognitoViewController : UIViewController // Init with the given loader object. |loader| may be nil, but isn't // retained so it must outlive this controller. - (instancetype)initWithUrlLoader:(UrlLoadingBrowserAgent*)URLLoader; -// Handler used to update Cookies settings. -@property(nonatomic, weak) id<PrivacyCookiesCommands> handler; - @end #endif // IOS_CHROME_BROWSER_UI_NTP_INCOGNITO_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/ntp/incognito_view_controller.mm b/ios/chrome/browser/ui/ntp/incognito_view_controller.mm index e115fd3db..a41de24 100644 --- a/ios/chrome/browser/ui/ntp/incognito_view_controller.mm +++ b/ios/chrome/browser/ui/ntp/incognito_view_controller.mm
@@ -10,7 +10,6 @@ #include "ios/chrome/browser/browser_state/chrome_browser_state.h" #import "ios/chrome/browser/ui/commands/browser_commands.h" #import "ios/chrome/browser/ui/ntp/incognito_view.h" -#import "ios/chrome/browser/ui/settings/privacy/cookies_commands.h" #include "ios/chrome/browser/ui/ui_feature_flags.h" #import "ios/chrome/browser/ui/util/uikit_ui_util.h" #import "ios/chrome/browser/url_loading/url_loading_browser_agent.h" @@ -26,8 +25,6 @@ // The scrollview containing the actual views. @property(nonatomic, strong) IncognitoView* incognitoView; -@property(nonatomic, assign) CookiesSettingType cookiesSettingSelected; - @end @implementation IncognitoViewController { @@ -57,60 +54,10 @@ [UIColor colorNamed:kBackgroundDarkColor]); self.incognitoView.backgroundColor = backgroundColor; [self.view addSubview:self.incognitoView]; - - if (self.incognitoView.cookiesBlockedSwitch) { - [self.incognitoView.cookiesBlockedSwitch - addTarget:self - action:@selector(onCookieSwitchToggled:) - forControlEvents:UIControlEventValueChanged]; - - // The mediator may have updated the cookies switch before before it's - // returned. - [self cookiesSettingsOptionSelected:self.cookiesSettingSelected]; - } else { - // cookiesBlockedSwitch must exists if kImprovedCookieControls - // feature is enabled. - DCHECK(!base::FeatureList::IsEnabled( - content_settings::kImprovedCookieControls)); - } } - (void)dealloc { [_incognitoView setDelegate:nil]; } -#pragma mark - Private - -// Called when the cookies switch is toogled. -- (void)onCookieSwitchToggled:(UISwitch*)cookiesBlockedSwitch { - [self.handler selectedCookiesSettingType: - self.incognitoView.cookiesBlockedSwitch.isOn - ? SettingTypeBlockThirdPartyCookiesIncognito - : SettingTypeAllowCookies]; -} - -#pragma mark - PrivacyCookiesConsumer - -- (void)cookiesSettingsOptionSelected:(CookiesSettingType)settingType { - self.cookiesSettingSelected = settingType; - switch (settingType) { - case SettingTypeBlockThirdPartyCookiesIncognito: - self.incognitoView.cookiesBlockedSwitch.enabled = YES; - [self.incognitoView.cookiesBlockedSwitch setOn:YES animated:YES]; - break; - case SettingTypeBlockThirdPartyCookies: - self.incognitoView.cookiesBlockedSwitch.enabled = NO; - [self.incognitoView.cookiesBlockedSwitch setOn:YES animated:YES]; - break; - case SettingTypeBlockAllCookies: - self.incognitoView.cookiesBlockedSwitch.enabled = NO; - [self.incognitoView.cookiesBlockedSwitch setOn:YES animated:YES]; - break; - case SettingTypeAllowCookies: - self.incognitoView.cookiesBlockedSwitch.enabled = YES; - [self.incognitoView.cookiesBlockedSwitch setOn:NO animated:YES]; - break; - } -} - @end
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm b/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm index a691a20..9628a6b 100644 --- a/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm +++ b/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm
@@ -6,15 +6,11 @@ #include "base/metrics/user_metrics.h" #include "base/metrics/user_metrics_action.h" -#include "components/content_settings/core/common/features.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" -#include "ios/chrome/browser/content_settings/host_content_settings_map_factory.h" #import "ios/chrome/browser/main/browser.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.h" #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.h" #import "ios/chrome/browser/ui/ntp/incognito_view_controller.h" -#import "ios/chrome/browser/ui/settings/privacy/cookies_mediator.h" -#include "ios/chrome/browser/ui/ui_feature_flags.h" #import "ios/chrome/browser/url_loading/url_loading_browser_agent.h" #import "ios/web/public/navigation/navigation_context.h" #import "ios/web/public/navigation/navigation_item.h" @@ -33,7 +29,6 @@ // View controller for incognito. @property(nonatomic, strong) IncognitoViewController* incognitoViewController; -@property(nonatomic, strong) PrivacyCookiesMediator* mediator; @end @@ -59,17 +54,6 @@ UrlLoadingBrowserAgent::FromBrowser(self.browser); self.incognitoViewController = [[IncognitoViewController alloc] initWithUrlLoader:URLLoader]; - if (base::FeatureList::IsEnabled( - content_settings::kImprovedCookieControls)) { - ChromeBrowserState* originalBrowser = - self.browser->GetBrowserState()->GetOriginalChromeBrowserState(); - self.mediator = [[PrivacyCookiesMediator alloc] - initWithPrefService:originalBrowser->GetPrefs() - settingsMap:ios::HostContentSettingsMapFactory:: - GetForBrowserState(originalBrowser)]; - self.mediator.consumer = self.incognitoViewController; - self.incognitoViewController.handler = self.mediator; - } } else { DCHECK(!self.contentSuggestionsCoordinator); self.contentSuggestionsCoordinator = [[ContentSuggestionsCoordinator alloc] @@ -81,6 +65,7 @@ [self.contentSuggestionsCoordinator start]; base::RecordAction(base::UserMetricsAction("MobileNTPShowMostVisited")); } + self.started = YES; } @@ -90,7 +75,6 @@ [self.contentSuggestionsCoordinator stop]; self.contentSuggestionsCoordinator = nil; self.incognitoViewController = nil; - self.mediator = nil; self.started = NO; }
diff --git a/ios/chrome/browser/ui/page_info/BUILD.gn b/ios/chrome/browser/ui/page_info/BUILD.gn index fe38db0..268c0790 100644 --- a/ios/chrome/browser/ui/page_info/BUILD.gn +++ b/ios/chrome/browser/ui/page_info/BUILD.gn
@@ -7,14 +7,12 @@ sources = [ "legacy_page_info_view_controller.h", "legacy_page_info_view_controller.mm", - "page_info_cookies_commands.h", "page_info_site_security_description.h", "page_info_site_security_description.mm", "page_info_view_controller.h", "page_info_view_controller.mm", ] deps = [ - "resources:cookies_icon", "resources:security_icon_dangerous", "resources:security_icon_not_secure", "resources:security_icon_secure",
diff --git a/ios/chrome/browser/ui/page_info/page_info_cookies_commands.h b/ios/chrome/browser/ui/page_info/page_info_cookies_commands.h deleted file mode 100644 index 3eec13c9..0000000 --- a/ios/chrome/browser/ui/page_info/page_info_cookies_commands.h +++ /dev/null
@@ -1,16 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_UI_PAGE_INFO_PAGE_INFO_COOKIES_COMMANDS_H_ -#define IOS_CHROME_BROWSER_UI_PAGE_INFO_PAGE_INFO_COOKIES_COMMANDS_H_ - -// Commands related to the UI of the Page Info Cookies section. -@protocol PageInfoCookiesCommands - -// Shows the Cookies settings screen. -- (void)showCookiesSettingsPage; - -@end - -#endif // IOS_CHROME_BROWSER_UI_PAGE_INFO_PAGE_INFO_COOKIES_COMMANDS_H_
diff --git a/ios/chrome/browser/ui/page_info/page_info_coordinator.mm b/ios/chrome/browser/ui/page_info/page_info_coordinator.mm index 01b1136..3cc0cdf 100644 --- a/ios/chrome/browser/ui/page_info/page_info_coordinator.mm +++ b/ios/chrome/browser/ui/page_info/page_info_coordinator.mm
@@ -4,21 +4,16 @@ #import "ios/chrome/browser/ui/page_info/page_info_coordinator.h" -#include "components/content_settings/core/common/features.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" #include "ios/chrome/browser/content_settings/host_content_settings_map_factory.h" #include "ios/chrome/browser/main/browser.h" #import "ios/chrome/browser/reading_list/offline_page_tab_helper.h" #include "ios/chrome/browser/ui/commands/browser_commands.h" #import "ios/chrome/browser/ui/commands/command_dispatcher.h" -#import "ios/chrome/browser/ui/page_info/page_info_cookies_commands.h" #import "ios/chrome/browser/ui/page_info/page_info_site_security_description.h" #import "ios/chrome/browser/ui/page_info/page_info_site_security_mediator.h" #import "ios/chrome/browser/ui/page_info/page_info_view_controller.h" -#import "ios/chrome/browser/ui/settings/privacy/cookies_coordinator.h" -#import "ios/chrome/browser/ui/settings/privacy/cookies_status_mediator.h" #import "ios/chrome/browser/ui/table_view/table_view_navigation_controller.h" -#include "ios/chrome/browser/ui/ui_feature_flags.h" #import "ios/chrome/browser/web_state_list/web_state_list.h" #include "ios/web/public/navigation/navigation_item.h" #include "ios/web/public/navigation/navigation_manager.h" @@ -28,15 +23,12 @@ #error "This file requires ARC support." #endif -@interface PageInfoCoordinator () <PageInfoCookiesCommands, - PrivacyCookiesCoordinatorDelegate> +@interface PageInfoCoordinator () @property(nonatomic, strong) TableViewNavigationController* navigationController; @property(nonatomic, strong) CommandDispatcher* dispatcher; @property(nonatomic, strong) PageInfoViewController* viewController; -@property(nonatomic, strong) PrivacyCookiesCoordinator* cookiesCoordinator; -@property(nonatomic, strong) CookiesStatusMediator* cookiesMediator; @end @@ -47,9 +39,6 @@ #pragma mark - ChromeCoordinator - (void)start { - self.dispatcher = self.browser->GetCommandDispatcher(); - [self.dispatcher startDispatchingToTarget:self - forProtocol:@protocol(PageInfoCookiesCommands)]; web::WebState* webState = self.browser->GetWebStateList()->GetActiveWebState(); web::NavigationItem* navItem = @@ -62,20 +51,9 @@ [PageInfoSiteSecurityMediator configurationForURL:navItem->GetURL() SSLStatus:navItem->GetSSL() offlinePage:offlinePage]; - if (!siteSecurityDescription.isEmpty && - base::FeatureList::IsEnabled(content_settings::kImprovedCookieControls)) { - self.cookiesMediator = [[CookiesStatusMediator alloc] - initWithPrefService:self.browser->GetBrowserState()->GetPrefs() - settingsMap:ios::HostContentSettingsMapFactory:: - GetForBrowserState( - self.browser->GetBrowserState())]; - } - self.viewController = [[PageInfoViewController alloc] - initWithSiteSecurityDescription:siteSecurityDescription - cookiesDescription:[self.cookiesMediator - cookiesDescription]]; - self.cookiesMediator.consumer = self.viewController; + self.viewController = [[PageInfoViewController alloc] + initWithSiteSecurityDescription:siteSecurityDescription]; self.navigationController = [[TableViewNavigationController alloc] initWithTable:self.viewController]; @@ -84,8 +62,7 @@ self.dispatcher = self.browser->GetCommandDispatcher(); self.viewController.handler = - static_cast<id<BrowserCommands, PageInfoCookiesCommands>>( - self.dispatcher); + static_cast<id<BrowserCommands>>(self.browser->GetCommandDispatcher()); [self.baseViewController presentViewController:self.navigationController animated:YES @@ -99,31 +76,6 @@ [self.dispatcher stopDispatchingToTarget:self]; self.navigationController = nil; self.viewController = nil; - self.cookiesMediator = nil; - self.cookiesCoordinator = nil; -} - -#pragma mark - PageInfoCookiesCommands - -- (void)showCookiesSettingsPage { - self.cookiesCoordinator = [[PrivacyCookiesCoordinator alloc] - initWithBaseViewController:self.navigationController - browser:self.browser]; - self.cookiesCoordinator.delegate = self; - [self.cookiesCoordinator start]; -} - -#pragma mark - PrivacyCookiesCoordinatorDelegate - -- (void)dismissPrivacyCookiesCoordinatorViewController: - (PrivacyCookiesCoordinator*)coordinator { - DCHECK(self.cookiesCoordinator); - DCHECK(self.cookiesCoordinator == coordinator); - [self.baseViewController.presentedViewController - dismissViewControllerAnimated:YES - completion:nil]; - [coordinator stop]; - self.cookiesCoordinator = nil; } @end
diff --git a/ios/chrome/browser/ui/page_info/page_info_view_controller.h b/ios/chrome/browser/ui/page_info/page_info_view_controller.h index ec77fca9..ab8f99e7 100644 --- a/ios/chrome/browser/ui/page_info/page_info_view_controller.h +++ b/ios/chrome/browser/ui/page_info/page_info_view_controller.h
@@ -8,28 +8,22 @@ #import <UIKit/UIKit.h> #import "ios/chrome/browser/ui/page_info/page_info_site_security_description.h" -#import "ios/chrome/browser/ui/settings/privacy/cookies_status_consumer.h" -#import "ios/chrome/browser/ui/settings/privacy/cookies_status_description.h" #import "ios/chrome/browser/ui/table_view/chrome_table_view_controller.h" @protocol BrowserCommands; -@protocol PageInfoCookiesCommands; // View Controller for displaying the page info. -@interface PageInfoViewController - : ChromeTableViewController <CookiesStatusConsumer> +@interface PageInfoViewController : ChromeTableViewController // Designated initializer. - (instancetype)initWithSiteSecurityDescription: (PageInfoSiteSecurityDescription*)siteSecurityDescription - cookiesDescription: - (CookiesStatusDescription*)cookiesDescription NS_DESIGNATED_INITIALIZER; - (instancetype)initWithStyle:(UITableViewStyle)style NS_UNAVAILABLE; // Handler used to navigate outside the page info. -@property(nonatomic, weak) id<BrowserCommands, PageInfoCookiesCommands> handler; +@property(nonatomic, weak) id<BrowserCommands> handler; @end
diff --git a/ios/chrome/browser/ui/page_info/page_info_view_controller.mm b/ios/chrome/browser/ui/page_info/page_info_view_controller.mm index 9799dec..09edd59 100644 --- a/ios/chrome/browser/ui/page_info/page_info_view_controller.mm +++ b/ios/chrome/browser/ui/page_info/page_info_view_controller.mm
@@ -5,12 +5,10 @@ #import "ios/chrome/browser/ui/page_info/page_info_view_controller.h" #include "base/mac/foundation_util.h" -#include "components/content_settings/core/common/features.h" #include "ios/chrome/browser/chrome_url_constants.h" #include "ios/chrome/browser/ui/commands/browser_commands.h" #import "ios/chrome/browser/ui/page_info/features.h" #import "ios/chrome/browser/ui/page_info/page_info_constants.h" -#import "ios/chrome/browser/ui/page_info/page_info_cookies_commands.h" #import "ios/chrome/browser/ui/settings/cells/settings_switch_cell.h" #import "ios/chrome/browser/ui/settings/cells/settings_switch_item.h" #import "ios/chrome/browser/ui/table_view/cells/table_view_detail_icon_item.h" @@ -18,7 +16,6 @@ #import "ios/chrome/browser/ui/table_view/cells/table_view_text_header_footer_item.h" #import "ios/chrome/browser/ui/table_view/cells/table_view_text_item.h" #import "ios/chrome/browser/ui/table_view/cells/table_view_text_link_item.h" -#include "ios/chrome/browser/ui/ui_feature_flags.h" #import "ios/chrome/common/ui/colors/semantic_color_names.h" #include "ios/chrome/grit/ios_strings.h" #include "ui/base/l10n/l10n_util.h" @@ -32,20 +29,15 @@ typedef NS_ENUM(NSInteger, SectionIdentifier) { SectionIdentifierSecurityContent = kSectionIdentifierEnumZero, - SectionIdentifierCookiesContent }; typedef NS_ENUM(NSInteger, ItemType) { ItemTypeSecurityHeader = kItemTypeEnumZero, ItemTypeSecurityDescription, - ItemTypeCookiesHeader, - ITemTypeCookiesFooter, }; // The vertical padding between the navigation bar and the Security header. float kPaddingSecurityHeader = 28.0f; -// The vertical padding between the Security section and the Cookies section. -float kPaddingCookiesHeader = 0.0f; } // namespace @@ -53,7 +45,6 @@ @property(nonatomic, strong) PageInfoSiteSecurityDescription* pageInfoSecurityDescription; -@property(nonatomic, strong) CookiesStatusDescription* cookiesDescription; @end @@ -62,13 +53,10 @@ #pragma mark - UIViewController - (instancetype)initWithSiteSecurityDescription: - (PageInfoSiteSecurityDescription*)siteSecurityDescription - cookiesDescription: - (CookiesStatusDescription*)cookiesDescription { + (PageInfoSiteSecurityDescription*)siteSecurityDescription { self = [super initWithStyle:UITableViewStylePlain]; if (self) { _pageInfoSecurityDescription = siteSecurityDescription; - _cookiesDescription = cookiesDescription; } return self; } @@ -106,8 +94,6 @@ [self.tableViewModel addSectionWithIdentifier:SectionIdentifierSecurityContent]; - [self.tableViewModel - addSectionWithIdentifier:SectionIdentifierCookiesContent]; TableViewDetailIconItem* securityHeader = [[TableViewDetailIconItem alloc] initWithType:ItemTypeSecurityHeader]; @@ -123,39 +109,13 @@ securityDescription.linkURL = GURL(kPageInfoHelpCenterURL); [self.tableViewModel addItem:securityDescription toSectionWithIdentifier:SectionIdentifierSecurityContent]; - - if (base::FeatureList::IsEnabled(content_settings::kImprovedCookieControls)) - [self loadCookiesModel]; -} - -#pragma mark - Private - -// Adds Items to the tableView related to Cookies Settings. -- (void)loadCookiesModel { - TableViewDetailIconItem* cookiesHeader = - [[TableViewDetailIconItem alloc] initWithType:ItemTypeCookiesHeader]; - cookiesHeader.text = l10n_util::GetNSString(IDS_IOS_PAGE_INFO_COOKIES_HEADER); - cookiesHeader.detailText = self.cookiesDescription.headerDescription; - cookiesHeader.iconImageName = @"cookies_icon"; - [self.tableViewModel addItem:cookiesHeader - toSectionWithIdentifier:SectionIdentifierCookiesContent]; - - TableViewTextLinkItem* cookiesFooter = - [[TableViewTextLinkItem alloc] initWithType:ITemTypeCookiesFooter]; - cookiesFooter.text = self.cookiesDescription.footerDescription; - cookiesFooter.linkURL = GURL(kChromeUICookiesSettingsURL); - [self.tableViewModel addItem:cookiesFooter - toSectionWithIdentifier:SectionIdentifierCookiesContent]; } #pragma mark - UITableViewDelegate - (CGFloat)tableView:(UITableView*)tableView heightForHeaderInSection:(NSInteger)section { - if ([self.tableViewModel sectionIdentifierForSection:section] == - SectionIdentifierSecurityContent) - return kPaddingSecurityHeader; - return kPaddingCookiesHeader; + return kPaddingSecurityHeader; } #pragma mark - UITableViewDataSource @@ -166,8 +126,7 @@ cellForRowAtIndexPath:indexPath]; TableViewItem* item = [self.tableViewModel itemAtIndexPath:indexPath]; - if (item.type == ItemTypeSecurityDescription || - item.type == ITemTypeCookiesFooter) { + if (item.type == ItemTypeSecurityDescription) { TableViewTextLinkCell* tableViewTextLinkCell = base::mac::ObjCCastStrict<TableViewTextLinkCell>(cellToReturn); tableViewTextLinkCell.delegate = self; @@ -180,35 +139,8 @@ - (void)tableViewTextLinkCell:(TableViewTextLinkCell*)cell didRequestOpenURL:(const GURL&)URL { - if (URL == GURL(kPageInfoHelpCenterURL)) - [self.handler showSecurityHelpPage]; - if (URL == GURL(kChromeUICookiesSettingsURL)) - [self.handler showCookiesSettingsPage]; -} - -#pragma mark - PageInfoCookiesConsumer - -- (void)cookiesOptionChangedToDescription: - (CookiesStatusDescription*)description { - // Update the Cookies Header. - NSIndexPath* headerPath = [self.tableViewModel - indexPathForItemType:ItemTypeCookiesHeader - sectionIdentifier:SectionIdentifierCookiesContent]; - TableViewDetailIconItem* cookiesHeader = - base::mac::ObjCCastStrict<TableViewDetailIconItem>( - [self.tableViewModel itemAtIndexPath:headerPath]); - cookiesHeader.detailText = description.headerDescription; - - // Update the Cookies footer. - NSIndexPath* footerPath = [self.tableViewModel - indexPathForItemType:ITemTypeCookiesFooter - sectionIdentifier:SectionIdentifierCookiesContent]; - TableViewTextLinkItem* cookiesFooter = - base::mac::ObjCCastStrict<TableViewTextLinkItem>( - [self.tableViewModel itemAtIndexPath:footerPath]); - cookiesFooter.text = description.footerDescription; - - [self reconfigureCellsForItems:@[ cookiesHeader, cookiesFooter ]]; + DCHECK(URL == GURL(kPageInfoHelpCenterURL)); + [self.handler showSecurityHelpPage]; } @end
diff --git a/ios/chrome/browser/ui/recent_tabs/BUILD.gn b/ios/chrome/browser/ui/recent_tabs/BUILD.gn index 51c8c46..81cdc08 100644 --- a/ios/chrome/browser/ui/recent_tabs/BUILD.gn +++ b/ios/chrome/browser/ui/recent_tabs/BUILD.gn
@@ -11,6 +11,8 @@ "recent_tabs_coordinator.mm", "recent_tabs_mediator.h", "recent_tabs_mediator.mm", + "recent_tabs_menu_helper.h", + "recent_tabs_menu_helper.mm", "synced_sessions_bridge.h", "synced_sessions_bridge.mm", ]
diff --git a/ios/chrome/browser/ui/recent_tabs/recent_tabs_coordinator.mm b/ios/chrome/browser/ui/recent_tabs/recent_tabs_coordinator.mm index 5a73ee43..2a1e919c 100644 --- a/ios/chrome/browser/ui/recent_tabs/recent_tabs_coordinator.mm +++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_coordinator.mm
@@ -6,7 +6,6 @@ #include "base/ios/block_types.h" #include "base/metrics/histogram_functions.h" -#include "base/metrics/histogram_macros.h" #include "base/metrics/user_metrics.h" #include "base/metrics/user_metrics_action.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" @@ -17,6 +16,7 @@ #import "ios/chrome/browser/ui/menu/action_factory.h" #import "ios/chrome/browser/ui/menu/menu_histograms.h" #import "ios/chrome/browser/ui/recent_tabs/recent_tabs_mediator.h" +#import "ios/chrome/browser/ui/recent_tabs/recent_tabs_menu_helper.h" #import "ios/chrome/browser/ui/recent_tabs/recent_tabs_menu_provider.h" #import "ios/chrome/browser/ui/recent_tabs/recent_tabs_presentation_delegate.h" #import "ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.h" @@ -27,18 +27,14 @@ #import "ios/chrome/browser/ui/table_view/feature_flags.h" #import "ios/chrome/browser/ui/table_view/table_view_navigation_controller.h" #import "ios/chrome/browser/ui/table_view/table_view_navigation_controller_constants.h" -#import "ios/chrome/browser/ui/util/multi_window_support.h" #import "ios/chrome/browser/url_loading/url_loading_browser_agent.h" #import "ios/chrome/browser/url_loading/url_loading_params.h" -#include "ios/chrome/grit/ios_strings.h" -#include "ui/base/l10n/l10n_util.h" -#include "url/gurl.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." #endif -@interface RecentTabsCoordinator () <RecentTabsMenuProvider, +@interface RecentTabsCoordinator () <RecentTabsContextMenuDelegate, RecentTabsPresentationDelegate> // Completion block called once the recentTabsViewController is dismissed. @property(nonatomic, copy) ProceduralBlock completion; @@ -51,9 +47,9 @@ RecentTabsTransitioningDelegate* recentTabsTransitioningDelegate; @property(nonatomic, strong) RecentTabsTableViewController* recentTabsTableViewController; - @property(nonatomic, strong) SharingCoordinator* sharingCoordinator; - +@property(nonatomic, strong) + RecentTabsContextMenuHelper* recentTabsContextMenuHelper; @end @implementation RecentTabsCoordinator @@ -75,7 +71,12 @@ self.recentTabsTableViewController.presentationDelegate = self; if (@available(iOS 13.0, *)) { - self.recentTabsTableViewController.menuProvider = self; + self.recentTabsContextMenuHelper = + [[RecentTabsContextMenuHelper alloc] initWithBrowser:self.browser + recentTabsPresentationDelegate:self + recentTabsContextMenuDelegate:self]; + self.recentTabsTableViewController.menuProvider = + self.recentTabsContextMenuHelper; } // Adds the "Done" button and hooks it up to |stop|. @@ -145,6 +146,9 @@ dismissViewControllerAnimated:YES completion:self.completion]; self.recentTabsNavigationController = nil; + self.recentTabsContextMenuHelper = nil; + [self.sharingCoordinator stop]; + self.sharingCoordinator = nil; self.recentTabsTransitioningDelegate = nil; [self.mediator disconnect]; } @@ -154,33 +158,6 @@ [self stop]; } -#pragma mark - Private - -// Opens all tabs from the given |sectionIdentifier|. -- (void)openAllTabsFromSessionSectionIdentitifer:(NSInteger)sectionIdentifier { - synced_sessions::DistantSession const* session = - [self.recentTabsTableViewController - sessionForSectionIdentifier:sectionIdentifier]; - [self openAllTabsFromSession:session]; -} - -// Triggers the URL sharing flow for the given |URL| and |title|, with the -// origin |view| representing the UI component for that URL. -- (void)shareURL:(const GURL&)URL - title:(NSString*)title - fromView:(UIView*)view { - ActivityParams* params = - [[ActivityParams alloc] initWithURL:URL - title:title - scenario:ActivityScenario::RecentTabsEntry]; - self.sharingCoordinator = [[SharingCoordinator alloc] - initWithBaseViewController:self.recentTabsTableViewController - browser:self.browser - params:params - originView:view]; - [self.sharingCoordinator start]; -} - #pragma mark - RecentTabsPresentationDelegate - (void)openAllTabsFromSession:(const synced_sessions::DistantSession*)session { @@ -226,120 +203,32 @@ [self stop]; } -#pragma mark - RecentTabsMenuProvider +#pragma mark - RecentTabsContextMenuDelegate -- (UIContextMenuConfiguration*)contextMenuConfigurationForItem: - (TableViewURLItem*)item - fromView:(UIView*)view - API_AVAILABLE(ios(13.0)) { - __weak __typeof(self) weakSelf = self; - - UIContextMenuActionProvider actionProvider = ^( - NSArray<UIMenuElement*>* suggestedActions) { - if (!weakSelf) { - // Return an empty menu. - return [UIMenu menuWithTitle:@"" children:@[]]; - } - - RecentTabsCoordinator* strongSelf = weakSelf; - - // Record that this context menu was shown to the user. - RecordMenuShown(MenuScenario::kRecentTabsEntry); - - ActionFactory* actionFactory = - [[ActionFactory alloc] initWithBrowser:strongSelf.browser - scenario:MenuScenario::kRecentTabsEntry]; - - NSMutableArray<UIMenuElement*>* menuElements = - [[NSMutableArray alloc] init]; - - [menuElements addObject:[actionFactory actionToOpenInNewTabWithURL:item.URL - completion:^{ - [strongSelf stop]; - }]]; - - [menuElements - addObject:[actionFactory actionToOpenInNewIncognitoTabWithURL:item.URL - completion:^{ - [strongSelf stop]; - }]]; - - if (IsMultipleScenesSupported()) { - [menuElements - addObject: - [actionFactory - actionToOpenInNewWindowWithURL:item.URL - activityOrigin:WindowActivityRecentTabsOrigin - completion:^{ - [strongSelf stop]; - }]]; - } - - [menuElements addObject:[actionFactory actionToCopyURL:item.URL]]; - - [menuElements addObject:[actionFactory actionToShareWithBlock:^{ - [strongSelf shareURL:item.URL - title:item.title - fromView:view]; - }]]; - - return [UIMenu menuWithTitle:@"" children:menuElements]; - }; - - return - [UIContextMenuConfiguration configurationWithIdentifier:nil - previewProvider:nil - actionProvider:actionProvider]; +- (void)shareURL:(const GURL&)URL + title:(NSString*)title + fromView:(UIView*)view { + ActivityParams* params = + [[ActivityParams alloc] initWithURL:URL + title:title + scenario:ActivityScenario::RecentTabsEntry]; + self.sharingCoordinator = [[SharingCoordinator alloc] + initWithBaseViewController:self.recentTabsTableViewController + browser:self.browser + params:params + originView:view]; + [self.sharingCoordinator start]; } -- (UIContextMenuConfiguration*) - contextMenuConfigurationForHeaderWithSectionIdentifier: - (NSInteger)sectionIdentifier API_AVAILABLE(ios(13.0)) { - __weak __typeof(self) weakSelf = self; +- (void)removeSessionAtSessionSectionIdentifier:(NSInteger)sectionIdentifier { + [self.recentTabsTableViewController + removeSessionAtSessionSectionIdentifier:sectionIdentifier]; +} - UIContextMenuActionProvider actionProvider = - ^(NSArray<UIMenuElement*>* suggestedActions) { - if (!weakSelf || ![weakSelf.recentTabsTableViewController - isSessionSectionIdentifier:sectionIdentifier]) { - // Return an empty menu. - return [UIMenu menuWithTitle:@"" children:@[]]; - } - - // Record that this context menu was shown to the user. - RecordMenuShown(MenuScenario::kRecentTabsHeader); - - ActionFactory* actionFactory = [[ActionFactory alloc] - initWithBrowser:weakSelf.browser - scenario:MenuScenario::kRecentTabsHeader]; - - NSMutableArray<UIMenuElement*>* menuElements = - [[NSMutableArray alloc] init]; - - synced_sessions::DistantSession const* session = - [weakSelf.recentTabsTableViewController - sessionForSectionIdentifier:sectionIdentifier]; - - if (!session->tabs.empty()) { - [menuElements - addObject:[actionFactory actionToOpenAllTabsWithBlock:^{ - [weakSelf - openAllTabsFromSessionSectionIdentitifer:sectionIdentifier]; - }]]; - } - - [menuElements - addObject:[actionFactory actionToHideWithBlock:^{ - [weakSelf.recentTabsTableViewController - removeSessionAtSessionSectionIdentifier:sectionIdentifier]; - }]]; - - return [UIMenu menuWithTitle:@"" children:menuElements]; - }; - - return - [UIContextMenuConfiguration configurationWithIdentifier:nil - previewProvider:nil - actionProvider:actionProvider]; +- (synced_sessions::DistantSession const*)sessionForSectionIdentifier: + (NSInteger)sectionIdentifier { + return [self.recentTabsTableViewController + sessionForSectionIdentifier:sectionIdentifier]; } @end
diff --git a/ios/chrome/browser/ui/recent_tabs/recent_tabs_menu_helper.h b/ios/chrome/browser/ui/recent_tabs/recent_tabs_menu_helper.h new file mode 100644 index 0000000..f27f8a30 --- /dev/null +++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_menu_helper.h
@@ -0,0 +1,52 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_UI_RECENT_TABS_RECENT_TABS_MENU_HELPER_H_ +#define IOS_CHROME_BROWSER_UI_RECENT_TABS_RECENT_TABS_MENU_HELPER_H_ + +#import <UIKit/UIKit.h> + +#import "ios/chrome/browser/ui/recent_tabs/recent_tabs_menu_provider.h" + +class Browser; +class GURL; +@class RecentTabsTableViewController; +@protocol RecentTabsPresentationDelegate; + +namespace synced_sessions { +class DistantSession; +} + +// Commands used to create context menu actions. +@protocol RecentTabsContextMenuDelegate + +// Triggers the URL sharing flow for the given |URL| and |title|, with the +// origin |view| representing the UI component for that URL. +- (void)shareURL:(const GURL&)URL title:(NSString*)title fromView:(UIView*)view; + +// Hides Sessions corresponding to the given |sectionIdentifier|. +- (void)removeSessionAtSessionSectionIdentifier:(NSInteger)sectionIdentifier; + +// Returns Sessions corresponding to the given |sectionIdentifier|. +- (synced_sessions::DistantSession const*)sessionForSectionIdentifier: + (NSInteger)sectionIdentifier; + +@end + +// RecentTabsContextMenuHelper controls the creation of context menus, +// based on the given |browser|, |RecentTabsPresentationDelegate| and +// |RecentTabsTableViewController|. +@interface RecentTabsContextMenuHelper : NSObject <RecentTabsMenuProvider> +- (instancetype)initWithBrowser:(Browser*)browser + recentTabsPresentationDelegate: + (id<RecentTabsPresentationDelegate>)recentTabsPresentationDelegate + recentTabsContextMenuDelegate: + (id<RecentTabsContextMenuDelegate>)recentTabsContextMenuDelegate + NS_DESIGNATED_INITIALIZER; + +- (instancetype)init NS_UNAVAILABLE; + +@end + +#endif // IOS_CHROME_BROWSER_UI_RECENT_TABS_RECENT_TABS_MENU_HELPER_H_
diff --git a/ios/chrome/browser/ui/recent_tabs/recent_tabs_menu_helper.mm b/ios/chrome/browser/ui/recent_tabs/recent_tabs_menu_helper.mm new file mode 100644 index 0000000..222db27 --- /dev/null +++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_menu_helper.mm
@@ -0,0 +1,172 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/ui/recent_tabs/recent_tabs_menu_helper.h" + +#include "base/metrics/histogram_functions.h" +#include "base/metrics/histogram_macros.h" +#import "ios/chrome/browser/ui/coordinators/chrome_coordinator.h" +#import "ios/chrome/browser/ui/menu/action_factory.h" +#import "ios/chrome/browser/ui/menu/menu_histograms.h" +#import "ios/chrome/browser/ui/recent_tabs/recent_tabs_menu_provider.h" +#import "ios/chrome/browser/ui/recent_tabs/recent_tabs_presentation_delegate.h" +#include "ios/chrome/browser/ui/recent_tabs/synced_sessions.h" +#import "ios/chrome/browser/ui/table_view/cells/table_view_url_item.h" +#import "ios/chrome/browser/ui/util/multi_window_support.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +@interface RecentTabsContextMenuHelper () <RecentTabsMenuProvider> + +@property(nonatomic, assign) Browser* browser; + +@property(nonatomic, weak) id<RecentTabsPresentationDelegate> + recentTabsPresentationDelegate; + +@property(nonatomic, weak) id<RecentTabsContextMenuDelegate> + recentTabsContextMenuDelegate; + +@end + +@implementation RecentTabsContextMenuHelper + +- (instancetype)initWithBrowser:(Browser*)browser + recentTabsPresentationDelegate: + (id<RecentTabsPresentationDelegate>)recentTabsPresentationDelegate + recentTabsContextMenuDelegate: + (id<RecentTabsContextMenuDelegate>)recentTabsContextMenuDelegate { + self = [super init]; + if (self) { + _browser = browser; + _recentTabsPresentationDelegate = recentTabsPresentationDelegate; + _recentTabsContextMenuDelegate = recentTabsContextMenuDelegate; + } + return self; +} + +#pragma mark - RecentTabsMenuProvider + +- (UIContextMenuConfiguration*)contextMenuConfigurationForItem: + (TableViewURLItem*)item + fromView:(UIView*)view + API_AVAILABLE(ios(13.0)) { + __weak __typeof(self) weakSelf = self; + + UIContextMenuActionProvider actionProvider = ^( + NSArray<UIMenuElement*>* suggestedActions) { + if (!weakSelf) { + // Return an empty menu. + return [UIMenu menuWithTitle:@"" children:@[]]; + } + + RecentTabsContextMenuHelper* strongSelf = weakSelf; + + // Record that this context menu was shown to the user. + RecordMenuShown(MenuScenario::kRecentTabsEntry); + + ActionFactory* actionFactory = + [[ActionFactory alloc] initWithBrowser:strongSelf.browser + scenario:MenuScenario::kRecentTabsEntry]; + + NSMutableArray<UIMenuElement*>* menuElements = + [[NSMutableArray alloc] init]; + + [menuElements + addObject:[actionFactory + actionToOpenInNewTabWithURL:item.URL + completion:^{ + [self.recentTabsPresentationDelegate + dismissRecentTabs]; + }]]; + + [menuElements + addObject: + [actionFactory + actionToOpenInNewIncognitoTabWithURL:item.URL + completion:^{ + [self.recentTabsPresentationDelegate + dismissRecentTabs]; + }]]; + + if (IsMultipleScenesSupported()) { + [menuElements + addObject: + [actionFactory + actionToOpenInNewWindowWithURL:item.URL + activityOrigin:WindowActivityRecentTabsOrigin + completion:^{ + [self.recentTabsPresentationDelegate + dismissRecentTabs]; + }]]; + } + + [menuElements addObject:[actionFactory actionToCopyURL:item.URL]]; + + [menuElements addObject:[actionFactory actionToShareWithBlock:^{ + [strongSelf.recentTabsContextMenuDelegate + shareURL:item.URL + title:item.title + fromView:view]; + }]]; + + return [UIMenu menuWithTitle:@"" children:menuElements]; + }; + + return + [UIContextMenuConfiguration configurationWithIdentifier:nil + previewProvider:nil + actionProvider:actionProvider]; +} + +- (UIContextMenuConfiguration*) + contextMenuConfigurationForHeaderWithSectionIdentifier: + (NSInteger)sectionIdentifier API_AVAILABLE(ios(13.0)) { + __weak __typeof(self) weakSelf = self; + + UIContextMenuActionProvider actionProvider = + ^(NSArray<UIMenuElement*>* suggestedActions) { + if (!weakSelf) { + // Return an empty menu. + return [UIMenu menuWithTitle:@"" children:@[]]; + } + + // Record that this context menu was shown to the user. + RecordMenuShown(MenuScenario::kRecentTabsHeader); + + ActionFactory* actionFactory = [[ActionFactory alloc] + initWithBrowser:self.browser + scenario:MenuScenario::kRecentTabsHeader]; + + NSMutableArray<UIMenuElement*>* menuElements = + [[NSMutableArray alloc] init]; + + synced_sessions::DistantSession const* session = + [weakSelf.recentTabsContextMenuDelegate + sessionForSectionIdentifier:sectionIdentifier]; + + if (!session->tabs.empty()) { + [menuElements addObject:[actionFactory actionToOpenAllTabsWithBlock:^{ + [self.recentTabsPresentationDelegate + openAllTabsFromSession:session]; + }]]; + } + + [menuElements + addObject:[actionFactory actionToHideWithBlock:^{ + [weakSelf.recentTabsContextMenuDelegate + removeSessionAtSessionSectionIdentifier:sectionIdentifier]; + }]]; + + return [UIMenu menuWithTitle:@"" children:menuElements]; + }; + + return + [UIContextMenuConfiguration configurationWithIdentifier:nil + previewProvider:nil + actionProvider:actionProvider]; +} + +@end
diff --git a/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.h b/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.h index c90665b16..a69e78647 100644 --- a/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.h +++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.h
@@ -55,9 +55,6 @@ - (instancetype)init NS_DESIGNATED_INITIALIZER; - (instancetype)initWithStyle:(UITableViewStyle)style NS_UNAVAILABLE; -// Returns YES if |sectionIdentifier| is a Sessions sectionIdentifier. -- (BOOL)isSessionSectionIdentifier:(NSInteger)sectionIdentifier; - // Returns Sessions corresponding to the given |sectionIdentifier|. - (synced_sessions::DistantSession const*)sessionForSectionIdentifier: (NSInteger)sectionIdentifer;
diff --git a/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm b/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm index b5e49cb2f..4c5d005 100644 --- a/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm +++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm
@@ -647,12 +647,6 @@ #pragma mark - Public -- (BOOL)isSessionSectionIdentifier:(NSInteger)sectionIdentifier { - NSArray* sessionSectionIdentifiers = [self allSessionSectionIdentifiers]; - NSNumber* sectionIdentifierObject = @(sectionIdentifier); - return [sessionSectionIdentifiers containsObject:sectionIdentifierObject]; -} - - (synced_sessions::DistantSession const*)sessionForSectionIdentifier: (NSInteger)sectionIdentifer { NSInteger section = @@ -690,6 +684,15 @@ }]; } +#pragma mark - Private + +// Returns YES if |sectionIdentifier| is a Sessions sectionIdentifier. +- (BOOL)isSessionSectionIdentifier:(NSInteger)sectionIdentifier { + NSArray* sessionSectionIdentifiers = [self allSessionSectionIdentifiers]; + NSNumber* sectionIdentifierObject = @(sectionIdentifier); + return [sessionSectionIdentifiers containsObject:sectionIdentifierObject]; +} + #pragma mark - Consumer Protocol - (void)refreshUserState:(SessionsSyncUserState)newSessionState { @@ -944,6 +947,9 @@ UIView* header = [interaction view]; NSInteger tappedHeaderSectionIdentifier = header.tag; + if (![self isSessionSectionIdentifier:tappedHeaderSectionIdentifier]) + return [[UIContextMenuConfiguration alloc] init]; + return [self.menuProvider contextMenuConfigurationForHeaderWithSectionIdentifier: tappedHeaderSectionIdentifier];
diff --git a/ios/chrome/browser/ui/settings/google_services/accounts_table_egtest.mm b/ios/chrome/browser/ui/settings/google_services/accounts_table_egtest.mm index 2999a8c..f179714 100644 --- a/ios/chrome/browser/ui/settings/google_services/accounts_table_egtest.mm +++ b/ios/chrome/browser/ui/settings/google_services/accounts_table_egtest.mm
@@ -197,8 +197,7 @@ [BookmarkEarlGrey setupStandardBookmarks]; // Sign out. - [SigninEarlGreyUI - signOutWithSignOutConfirmation:SignOutConfirmationNonManagedUser]; + [SigninEarlGreyUI signOut]; // Open the Bookmarks screen on the Tools menu. [BookmarkEarlGreyUI openBookmarks]; @@ -223,8 +222,7 @@ [BookmarkEarlGrey setupStandardBookmarks]; // Sign out. - [SigninEarlGreyUI signOutWithSignOutConfirmation: - SignOutConfirmationNonManagedUserWithClearedData]; + [SigninEarlGreyUI signOutAndClearDataFromDevice]; // Open the Bookmarks screen on the Tools menu. [BookmarkEarlGreyUI openBookmarks]; @@ -237,10 +235,9 @@ // Tests that signing out from a managed user account clears the user's data. - (void)testsSignOutFromManagedAccount { - FakeChromeIdentity* fakeIdentity = [SigninEarlGrey fakeManagedIdentity]; - - // Sign In |fakeIdentity|. - [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity isManagedAccount:YES]; + // Sign In |fakeManagedIdentity|. + [SigninEarlGreyUI + signinWithFakeIdentity:[SigninEarlGrey fakeManagedIdentity]]; // Add a bookmark after sync is initialized. [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:kSyncOperationTimeout]; @@ -248,8 +245,7 @@ [BookmarkEarlGrey setupStandardBookmarks]; // Sign out. - [SigninEarlGreyUI - signOutWithSignOutConfirmation:SignOutConfirmationManagedUser]; + [SigninEarlGreyUI signOutAndClearDataFromDevice]; // Open the Bookmarks screen on the Tools menu. [BookmarkEarlGreyUI openBookmarks];
diff --git a/ios/chrome/browser/ui/settings/password/password_details/BUILD.gn b/ios/chrome/browser/ui/settings/password/password_details/BUILD.gn index 27c7271..0da1203 100644 --- a/ios/chrome/browser/ui/settings/password/password_details/BUILD.gn +++ b/ios/chrome/browser/ui/settings/password/password_details/BUILD.gn
@@ -50,7 +50,9 @@ deps = [ "//base", "//components/autofill/core/common", + "//components/password_manager/core/browser:affiliation", "//components/password_manager/core/browser:browser", + "//components/password_manager/core/common", "//components/strings", "//ios/chrome/app/strings:ios_chromium_strings_grit", "//ios/chrome/app/strings:ios_strings_grit",
diff --git a/ios/chrome/browser/ui/settings/password/password_details/password_details.h b/ios/chrome/browser/ui/settings/password/password_details/password_details.h index a3fe92a..e3a81a5 100644 --- a/ios/chrome/browser/ui/settings/password/password_details/password_details.h +++ b/ios/chrome/browser/ui/settings/password/password_details/password_details.h
@@ -7,6 +7,8 @@ #import <Foundation/Foundation.h> +#include "url/gurl.h" + namespace autofill { struct PasswordForm; } @@ -16,20 +18,23 @@ @interface PasswordDetails : NSObject // Short version of website. -@property(nonatomic, strong, readonly) NSString* origin; +@property(nonatomic, copy, readonly) NSString* origin; // Associated website. -@property(nonatomic, strong, readonly) NSString* website; +@property(nonatomic, copy, readonly) NSString* website; // Associated username. -@property(nonatomic, strong, readonly) NSString* username; +@property(nonatomic, copy, readonly) NSString* username; // Associated password. -@property(nonatomic, strong) NSString* password; +@property(nonatomic, copy) NSString* password; // Whether password is compromised or not. @property(nonatomic, assign, getter=isCompromised) BOOL compromised; +// URL which allows to change the password of compromised credential. +@property(nonatomic, readonly) GURL changePasswordURL; + - (instancetype)initWithPasswordForm:(const autofill::PasswordForm&)form NS_DESIGNATED_INITIALIZER;
diff --git a/ios/chrome/browser/ui/settings/password/password_details/password_details.mm b/ios/chrome/browser/ui/settings/password/password_details/password_details.mm index 3e6855e..4cda8c26 100644 --- a/ios/chrome/browser/ui/settings/password/password_details/password_details.mm +++ b/ios/chrome/browser/ui/settings/password/password_details/password_details.mm
@@ -6,7 +6,10 @@ #include "base/strings/sys_string_conversions.h" #include "components/autofill/core/common/password_form.h" +#include "components/password_manager/core/browser/android_affiliation/affiliation_utils.h" #include "components/password_manager/core/browser/password_ui_utils.h" +#include "components/password_manager/core/browser/well_known_change_password_util.h" +#include "components/password_manager/core/common/password_manager_features.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -17,13 +20,38 @@ - (instancetype)initWithPasswordForm:(const autofill::PasswordForm&)form { self = [super init]; if (self) { - auto nameWithLink = password_manager::GetShownOriginAndLinkUrl(form); - _origin = base::SysUTF8ToNSString(nameWithLink.first); - _website = base::SysUTF8ToNSString(nameWithLink.second.spec()); + auto facetUri = password_manager::FacetURI::FromPotentiallyInvalidSpec( + form.signon_realm); + if (facetUri.IsValidAndroidFacetURI()) { + if (!form.app_display_name.empty()) { + _changePasswordURL = + [self changePasswordUrlFor:GURL(form.affiliated_web_realm)]; + _origin = base::SysUTF8ToNSString(form.app_display_name); + _website = base::SysUTF8ToNSString(form.app_display_name); + } else { + _origin = base::SysUTF8ToNSString(facetUri.android_package_name()); + _website = base::SysUTF8ToNSString(facetUri.android_package_name()); + } + } else { + auto nameWithLink = password_manager::GetShownOriginAndLinkUrl(form); + _origin = base::SysUTF8ToNSString(nameWithLink.first); + _website = base::SysUTF8ToNSString(nameWithLink.second.spec()); + _changePasswordURL = [self changePasswordUrlFor:form.url]; + } _username = base::SysUTF16ToNSString(form.username_value); _password = base::SysUTF16ToNSString(form.password_value); } return self; } +- (GURL)changePasswordUrlFor:(const GURL&)url { + if (!base::FeatureList::IsEnabled( + password_manager::features::kWellKnownChangePassword)) { + return url.GetOrigin(); + } + + return password_manager::CreateWellKnownNonExistingResourceURL( + url.GetOrigin()); +} + @end
diff --git a/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller.mm b/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller.mm index 73753ab..6b7d9d1 100644 --- a/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller.mm +++ b/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller.mm
@@ -138,8 +138,10 @@ if (self.password.isCompromised) { [model addSectionWithIdentifier:SectionIdentifierCompromisedInfo]; - [model addItem:[self changePasswordItem] - toSectionWithIdentifier:SectionIdentifierCompromisedInfo]; + if (self.password.changePasswordURL.is_valid()) { + [model addItem:[self changePasswordItem] + toSectionWithIdentifier:SectionIdentifierCompromisedInfo]; + } [model addItem:[self changePasswordRecommendationItem] toSectionWithIdentifier:SectionIdentifierCompromisedInfo]; @@ -237,10 +239,9 @@ case ItemTypeChangePasswordButton: if (!self.tableView.editing) { DCHECK(self.commandsDispatcher); - GURL URL(base::SysNSStringToUTF8(self.password.website)); - DCHECK(URL.is_valid()); - OpenNewTabCommand* command = - [OpenNewTabCommand commandWithURLFromChrome:URL]; + DCHECK(self.password.changePasswordURL.is_valid()); + OpenNewTabCommand* command = [OpenNewTabCommand + commandWithURLFromChrome:self.password.changePasswordURL]; [self.commandsDispatcher closeSettingsUIAndOpenURL:command]; } break;
diff --git a/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller_unittest.mm index 7ed767f..2583360 100644 --- a/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller_unittest.mm +++ b/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller_unittest.mm
@@ -32,6 +32,13 @@ #error "This file requires ARC support." #endif +namespace { +constexpr char kExampleCom[] = "http://www.example.com/"; +constexpr char kAndroid[] = "android://hash@com.example.my.app"; +constexpr char kUsername[] = "test@egmail.com"; +constexpr char kPassword[] = "test"; +} + // Test class that conforms to PasswordDetailsHanler in order to test the // presenter methods are called correctly. @interface FakePasswordDetailsHandler : NSObject <PasswordDetailsHandler> @@ -100,24 +107,26 @@ return controller; } - void SetPassword(bool isCompromised = false) { + void SetPassword(std::string website = kExampleCom, + std::string username = kUsername, + std::string password = kPassword, + bool isCompromised = false) { auto form = autofill::PasswordForm(); - form.url = GURL("http://www.example.com/"); - form.action = GURL("http://www.example.com/accounts/Login"); - form.username_element = base::ASCIIToUTF16("Email"); - form.username_value = base::ASCIIToUTF16("test@egmail.com"); - form.password_element = base::ASCIIToUTF16("Passwd"); - form.password_value = base::ASCIIToUTF16("test"); - form.submit_element = base::ASCIIToUTF16("signIn"); - form.signon_realm = "http://www.example.com/"; + form.signon_realm = website; + form.username_value = base::ASCIIToUTF16(username); + form.password_value = base::ASCIIToUTF16(password); + form.url = GURL(website); + form.action = GURL(website + "/action"); + form.username_element = base::ASCIIToUTF16("email"); form.scheme = autofill::PasswordForm::Scheme::kHtml; - PasswordDetails* password = + + PasswordDetails* passwordDetails = [[PasswordDetails alloc] initWithPasswordForm:form]; - password.compromised = isCompromised; + passwordDetails.compromised = isCompromised; PasswordDetailsTableViewController* passwords_controller = static_cast<PasswordDetailsTableViewController*>(controller()); - [passwords_controller setPassword:password]; + [passwords_controller setPassword:passwordDetails]; } void CheckEditCellText(NSString* expected_text, int section, int item) { @@ -169,7 +178,7 @@ // Tests that compromised password is displayed properly. TEST_F(PasswordDetailsTableViewControllerTest, TestCompromisedPassword) { - SetPassword(true); + SetPassword(kExampleCom, kUsername, kPassword, true); EXPECT_EQ(2, NumberOfSections()); EXPECT_EQ(3, NumberOfItemsInSection(0)); EXPECT_EQ(2, NumberOfItemsInSection(1)); @@ -300,7 +309,7 @@ EXPECT_FALSE(passwordDetails.tableView.editing); } -// Tests password editing. User cancelled this action. +// Tests password editing. User cancelled this action. TEST_F(PasswordDetailsTableViewControllerTest, TestEditPasswordCancel) { SetPassword(); @@ -319,3 +328,20 @@ EXPECT_FALSE(delegate().password); EXPECT_TRUE(passwordDetails.tableView.editing); } + +// Tests android compromised credential is displayed without change password +// button. +TEST_F(PasswordDetailsTableViewControllerTest, + TestAndroidCompromisedCredential) { + SetPassword(kAndroid, kUsername, kPassword, true); + EXPECT_EQ(2, NumberOfSections()); + EXPECT_EQ(3, NumberOfItemsInSection(0)); + EXPECT_EQ(1, NumberOfItemsInSection(1)); + + CheckEditCellText(@"com.example.my.app", 0, 0); + CheckEditCellText(@"test@egmail.com", 0, 1); + CheckEditCellText(kMaskedPassword, 0, 2); + + CheckDetailItemTextWithId(IDS_IOS_CHANGE_COMPROMISED_PASSWORD_DESCRIPTION, 1, + 0); +}
diff --git a/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.mm b/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.mm index 6a84b78..e7c5866 100644 --- a/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.mm +++ b/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.mm
@@ -1369,8 +1369,7 @@ } break; case ItemTypeCheckForProblemsButton: - if (_passwordCheck->GetPasswordCheckState() != - PasswordCheckState::kNoPasswords) { + if (self.passwordCheckState != PasswordCheckStateRunning) { _passwordCheck->StartPasswordCheck(); } break;
diff --git a/ios/chrome/browser/ui/settings/privacy/BUILD.gn b/ios/chrome/browser/ui/settings/privacy/BUILD.gn index 4e60901..f399603 100644 --- a/ios/chrome/browser/ui/settings/privacy/BUILD.gn +++ b/ios/chrome/browser/ui/settings/privacy/BUILD.gn
@@ -5,13 +5,6 @@ source_set("privacy_ui") { configs += [ "//build/config/compiler:enable_arc" ] sources = [ - "cookies_commands.h", - "cookies_consumer.h", - "cookies_status_consumer.h", - "cookies_status_description.h", - "cookies_status_description.mm", - "cookies_view_controller.h", - "cookies_view_controller.mm", "handoff_table_view_controller.h", "handoff_table_view_controller.mm", "privacy_navigation_commands.h", @@ -55,12 +48,6 @@ source_set("privacy") { configs += [ "//build/config/compiler:enable_arc" ] sources = [ - "cookies_coordinator.h", - "cookies_coordinator.mm", - "cookies_mediator.h", - "cookies_mediator.mm", - "cookies_status_mediator.h", - "cookies_status_mediator.mm", "privacy_coordinator.h", "privacy_coordinator.mm", ] @@ -73,7 +60,6 @@ "//ios/chrome/browser/browser_state", "//ios/chrome/browser/content_settings", "//ios/chrome/browser/main:public", - "//ios/chrome/browser/ui:feature_flags", "//ios/chrome/browser/ui/commands", "//ios/chrome/browser/ui/coordinators:chrome_coordinators", "//ios/chrome/browser/ui/settings:settings_root",
diff --git a/ios/chrome/browser/ui/settings/privacy/cookies_commands.h b/ios/chrome/browser/ui/settings/privacy/cookies_commands.h deleted file mode 100644 index 4c85b85..0000000 --- a/ios/chrome/browser/ui/settings/privacy/cookies_commands.h +++ /dev/null
@@ -1,20 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_UI_SETTINGS_PRIVACY_COOKIES_COMMANDS_H_ -#define IOS_CHROME_BROWSER_UI_SETTINGS_PRIVACY_COOKIES_COMMANDS_H_ - -#import "ios/chrome/browser/ui/settings/privacy/cookies_consumer.h" - -@class TableViewItem; - -// Commands related to the Cookies state. -@protocol PrivacyCookiesCommands - -// Updates Cookies settings with the given item type. -- (void)selectedCookiesSettingType:(CookiesSettingType)settingType; - -@end - -#endif // IOS_CHROME_BROWSER_UI_SETTINGS_PRIVACY_COOKIES_COMMANDS_H_
diff --git a/ios/chrome/browser/ui/settings/privacy/cookies_consumer.h b/ios/chrome/browser/ui/settings/privacy/cookies_consumer.h deleted file mode 100644 index 0b7b9c7..0000000 --- a/ios/chrome/browser/ui/settings/privacy/cookies_consumer.h +++ /dev/null
@@ -1,27 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_UI_SETTINGS_PRIVACY_COOKIES_CONSUMER_H_ -#define IOS_CHROME_BROWSER_UI_SETTINGS_PRIVACY_COOKIES_CONSUMER_H_ - -#import "ios/chrome/browser/ui/list_model/list_model.h" - -typedef NS_ENUM(NSInteger, CookiesSettingType) { - SettingTypeAllowCookies, - SettingTypeBlockThirdPartyCookiesIncognito, - SettingTypeBlockThirdPartyCookies, - SettingTypeBlockAllCookies, -}; - -@class TableViewItem; - -// A consumer for Cookies settings changes. -@protocol PrivacyCookiesConsumer - -// Called when a cookie setting option was selected. -- (void)cookiesSettingsOptionSelected:(CookiesSettingType)settingType; - -@end - -#endif // IOS_CHROME_BROWSER_UI_SETTINGS_PRIVACY_COOKIES_CONSUMER_H_
diff --git a/ios/chrome/browser/ui/settings/privacy/cookies_coordinator.h b/ios/chrome/browser/ui/settings/privacy/cookies_coordinator.h deleted file mode 100644 index 05784546..0000000 --- a/ios/chrome/browser/ui/settings/privacy/cookies_coordinator.h +++ /dev/null
@@ -1,38 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_UI_SETTINGS_PRIVACY_COOKIES_COORDINATOR_H_ -#define IOS_CHROME_BROWSER_UI_SETTINGS_PRIVACY_COOKIES_COORDINATOR_H_ - -#import <Foundation/Foundation.h> - -#import "ios/chrome/browser/ui/coordinators/chrome_coordinator.h" - -@class PrivacyCookiesCoordinator; - -// Delegate that allows to dereference the PrivacyCookiesCoordinator. -@protocol PrivacyCookiesCoordinatorDelegate - -@optional -// Called when the view controller is removed from navigation controller. -- (void)privacyCookiesCoordinatorViewControllerWasRemoved: - (PrivacyCookiesCoordinator*)coordinator; - -// Called when the view controller should be dismissed. -- (void)dismissPrivacyCookiesCoordinatorViewController: - (PrivacyCookiesCoordinator*)coordinator; - -@end -// The coordinator for the Cookies screen. -@interface PrivacyCookiesCoordinator : ChromeCoordinator - -@property(nonatomic, weak) id<PrivacyCookiesCoordinatorDelegate> delegate; - -- (instancetype)initWithBaseNavigationController: - (UINavigationController*)navigationController - browser:(Browser*)browser; - -@end - -#endif // IOS_CHROME_BROWSER_UI_SETTINGS_PRIVACY_COOKIES_COORDINATOR_H_
diff --git a/ios/chrome/browser/ui/settings/privacy/cookies_coordinator.mm b/ios/chrome/browser/ui/settings/privacy/cookies_coordinator.mm deleted file mode 100644 index df1a817..0000000 --- a/ios/chrome/browser/ui/settings/privacy/cookies_coordinator.mm +++ /dev/null
@@ -1,101 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "ios/chrome/browser/ui/settings/privacy/cookies_coordinator.h" - -#include "base/check_op.h" -#include "ios/chrome/browser/browser_state/chrome_browser_state.h" -#include "ios/chrome/browser/content_settings/host_content_settings_map_factory.h" -#include "ios/chrome/browser/main/browser.h" -#import "ios/chrome/browser/ui/commands/browser_commands.h" -#import "ios/chrome/browser/ui/commands/command_dispatcher.h" -#import "ios/chrome/browser/ui/settings/privacy/cookies_commands.h" -#import "ios/chrome/browser/ui/settings/privacy/cookies_mediator.h" -#import "ios/chrome/browser/ui/settings/privacy/cookies_view_controller.h" -#import "ios/chrome/browser/ui/table_view/table_view_navigation_controller.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -@interface PrivacyCookiesCoordinator () < - PrivacyCookiesViewControllerPresentationDelegate> - -@property(nonatomic, strong) PrivacyCookiesViewController* viewController; -@property(nonatomic, strong) PrivacyCookiesMediator* mediator; - -@end - -@implementation PrivacyCookiesCoordinator - -@synthesize baseNavigationController = _baseNavigationController; - -- (instancetype)initWithBaseNavigationController: - (UINavigationController*)navigationController - browser:(Browser*)browser { - if ([super initWithBaseViewController:navigationController browser:browser]) { - _baseNavigationController = navigationController; - } - return self; -} - -#pragma mark - ChromeCoordinator - -- (void)start { - self.viewController = [[PrivacyCookiesViewController alloc] - initWithStyle:UITableViewStylePlain]; - - if (!self.baseNavigationController) { - self.viewController.navigationItem.rightBarButtonItem = - [[UIBarButtonItem alloc] - initWithBarButtonSystemItem:UIBarButtonSystemItemDone - target:self - action:@selector(hideCookiesSettings)]; - - TableViewNavigationController* navigationController = - [[TableViewNavigationController alloc] - initWithTable:self.viewController]; - navigationController.modalPresentationStyle = UIModalPresentationFormSheet; - - [self.baseViewController presentViewController:navigationController - animated:YES - completion:nil]; - } else { - [self.baseNavigationController pushViewController:self.viewController - animated:YES]; - } - - self.viewController.presentationDelegate = self; - - self.mediator = [[PrivacyCookiesMediator alloc] - initWithPrefService:self.browser->GetBrowserState()->GetPrefs() - settingsMap:ios::HostContentSettingsMapFactory:: - GetForBrowserState( - self.browser->GetBrowserState())]; - self.mediator.consumer = self.viewController; - self.viewController.handler = self.mediator; -} - -- (void)stop { - self.viewController = nil; - self.mediator = nil; -} - -#pragma mark - PrivacyCookiesViewControllerPresentationDelegate - -- (void)privacyCookiesViewControllerWasRemoved: - (PrivacyCookiesViewController*)controller { - DCHECK_EQ(self.viewController, controller); - [self.delegate privacyCookiesCoordinatorViewControllerWasRemoved:self]; -} - -#pragma mark - Private - -// Called when the view controller is displayed from the page info and the -// user pressed 'Done'. -- (void)hideCookiesSettings { - [self.delegate dismissPrivacyCookiesCoordinatorViewController:self]; -} - -@end
diff --git a/ios/chrome/browser/ui/settings/privacy/cookies_mediator.h b/ios/chrome/browser/ui/settings/privacy/cookies_mediator.h deleted file mode 100644 index 17d6287..0000000 --- a/ios/chrome/browser/ui/settings/privacy/cookies_mediator.h +++ /dev/null
@@ -1,31 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_UI_SETTINGS_PRIVACY_COOKIES_MEDIATOR_H_ -#define IOS_CHROME_BROWSER_UI_SETTINGS_PRIVACY_COOKIES_MEDIATOR_H_ - -#import <Foundation/Foundation.h> - -#import "ios/chrome/browser/ui/settings/privacy/cookies_commands.h" - -class HostContentSettingsMap; -class PrefService; - -@protocol PrivacyCookiesConsumer; - -// The mediator is pushing the data for the root of the Cookies screen to the -// consumer. -@interface PrivacyCookiesMediator : NSObject <PrivacyCookiesCommands> - -- (instancetype)init NS_UNAVAILABLE; -- (instancetype)initWithPrefService:(PrefService*)prefService - settingsMap:(HostContentSettingsMap*)settingsMap - NS_DESIGNATED_INITIALIZER; - -// The consumer for this mediator. -@property(nonatomic, weak) id<PrivacyCookiesConsumer> consumer; - -@end - -#endif // IOS_CHROME_BROWSER_UI_SETTINGS_PRIVACY_COOKIES_MEDIATOR_H_
diff --git a/ios/chrome/browser/ui/settings/privacy/cookies_mediator.mm b/ios/chrome/browser/ui/settings/privacy/cookies_mediator.mm deleted file mode 100644 index 9526e94..0000000 --- a/ios/chrome/browser/ui/settings/privacy/cookies_mediator.mm +++ /dev/null
@@ -1,131 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "ios/chrome/browser/ui/settings/privacy/cookies_mediator.h" - -#import "base/logging.h" -#include "components/content_settings/core/browser/cookie_settings.h" -#include "components/content_settings/core/browser/host_content_settings_map.h" -#include "components/content_settings/core/common/content_settings.h" -#include "components/content_settings/core/common/content_settings_pattern.h" -#include "components/content_settings/core/common/pref_names.h" -#include "components/prefs/pref_member.h" -#include "components/prefs/pref_service.h" -#include "ios/chrome/browser/content_settings/host_content_settings_map_factory.h" -#import "ios/chrome/browser/ui/settings/privacy/cookies_consumer.h" -#import "ios/chrome/browser/ui/settings/utils/content_setting_backed_boolean.h" -#import "ios/chrome/browser/ui/settings/utils/pref_backed_boolean.h" -#import "ios/chrome/browser/ui/table_view/cells/table_view_url_item.h" -#include "url/gurl.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -@interface PrivacyCookiesMediator () <BooleanObserver> { - // The preference that decides when the cookie controls UI is enabled. - IntegerPrefMember _prefsCookieControlsMode; -} - -// The observable boolean that binds to the "Enable cookie controls" setting -// state. -@property(nonatomic, strong) - ContentSettingBackedBoolean* prefsContentSettingCookieControl; - -@end - -@implementation PrivacyCookiesMediator - -- (instancetype)initWithPrefService:(PrefService*)prefService - settingsMap:(HostContentSettingsMap*)settingsMap { - self = [super init]; - if (self) { - __weak PrivacyCookiesMediator* weakSelf = self; - _prefsCookieControlsMode.Init(prefs::kCookieControlsMode, prefService, - base::BindRepeating(^() { - [weakSelf updateConsumer]; - })); - - _prefsContentSettingCookieControl = [[ContentSettingBackedBoolean alloc] - initWithHostContentSettingsMap:settingsMap - settingID:ContentSettingsType::COOKIES - inverted:NO]; - [_prefsContentSettingCookieControl setObserver:self]; - } - return self; -} - -- (void)setConsumer:(id<PrivacyCookiesConsumer>)consumer { - if (_consumer == consumer) - return; - - _consumer = consumer; - [self updateConsumer]; -} - -#pragma mark - PrivacyCookiesCommands - -- (void)selectedCookiesSettingType:(CookiesSettingType)settingType { - switch (settingType) { - case SettingTypeAllowCookies: - [self.prefsContentSettingCookieControl setValue:YES]; - _prefsCookieControlsMode.SetValue( - static_cast<int>(content_settings::CookieControlsMode::kOff)); - break; - - case SettingTypeBlockThirdPartyCookiesIncognito: - [self.prefsContentSettingCookieControl setValue:YES]; - _prefsCookieControlsMode.SetValue(static_cast<int>( - content_settings::CookieControlsMode::kIncognitoOnly)); - break; - - case SettingTypeBlockThirdPartyCookies: - [self.prefsContentSettingCookieControl setValue:YES]; - _prefsCookieControlsMode.SetValue(static_cast<int>( - content_settings::CookieControlsMode::kBlockThirdParty)); - break; - - case SettingTypeBlockAllCookies: - [self.prefsContentSettingCookieControl setValue:NO]; - _prefsCookieControlsMode.SetValue(static_cast<int>( - content_settings::CookieControlsMode::kBlockThirdParty)); - break; - default: - NOTREACHED(); - break; - } - [self updateConsumer]; -} - -#pragma mark - Private - -// Returns the cookiesSettingType according to preferences. -- (CookiesSettingType)cookiesSettingType { - if (![self.prefsContentSettingCookieControl value]) - return SettingTypeBlockAllCookies; - - if (self.prefsContentSettingCookieControl.value && - _prefsCookieControlsMode.GetValue() == - static_cast<int>( - content_settings::CookieControlsMode::kBlockThirdParty)) - return SettingTypeBlockThirdPartyCookies; - - if (_prefsCookieControlsMode.GetValue() == - static_cast<int>(content_settings::CookieControlsMode::kIncognitoOnly)) - return SettingTypeBlockThirdPartyCookiesIncognito; - - return SettingTypeAllowCookies; -} - -- (void)updateConsumer { - [self.consumer cookiesSettingsOptionSelected:[self cookiesSettingType]]; -} - -#pragma mark - BooleanObserver - -- (void)booleanDidChange:(id<ObservableBoolean>)observableBoolean { - [self updateConsumer]; -} - -@end
diff --git a/ios/chrome/browser/ui/settings/privacy/cookies_status_consumer.h b/ios/chrome/browser/ui/settings/privacy/cookies_status_consumer.h deleted file mode 100644 index fdf50ef..0000000 --- a/ios/chrome/browser/ui/settings/privacy/cookies_status_consumer.h +++ /dev/null
@@ -1,21 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_UI_SETTINGS_PRIVACY_COOKIES_STATUS_CONSUMER_H_ -#define IOS_CHROME_BROWSER_UI_SETTINGS_PRIVACY_COOKIES_STATUS_CONSUMER_H_ - -#import <Foundation/Foundation.h> - -@class CookiesStatusDescription; - -// Consumer for Cookies status. -@protocol CookiesStatusConsumer - -// Called when Cookies option has changed. -- (void)cookiesOptionChangedToDescription: - (CookiesStatusDescription*)description; - -@end - -#endif // IOS_CHROME_BROWSER_UI_SETTINGS_PRIVACY_COOKIES_STATUS_CONSUMER_H_
diff --git a/ios/chrome/browser/ui/settings/privacy/cookies_status_description.h b/ios/chrome/browser/ui/settings/privacy/cookies_status_description.h deleted file mode 100644 index 5ae1d78..0000000 --- a/ios/chrome/browser/ui/settings/privacy/cookies_status_description.h +++ /dev/null
@@ -1,18 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_UI_SETTINGS_PRIVACY_COOKIES_STATUS_DESCRIPTION_H_ -#define IOS_CHROME_BROWSER_UI_SETTINGS_PRIVACY_COOKIES_STATUS_DESCRIPTION_H_ - -#import <Foundation/Foundation.h> - -// Config to display Cookies status. -@interface CookiesStatusDescription : NSObject - -@property(nonatomic, copy) NSString* headerDescription; -@property(nonatomic, copy) NSString* footerDescription; - -@end - -#endif // IOS_CHROME_BROWSER_UI_SETTINGS_PRIVACY_COOKIES_STATUS_DESCRIPTION_H_
diff --git a/ios/chrome/browser/ui/settings/privacy/cookies_status_description.mm b/ios/chrome/browser/ui/settings/privacy/cookies_status_description.mm deleted file mode 100644 index dd227be..0000000 --- a/ios/chrome/browser/ui/settings/privacy/cookies_status_description.mm +++ /dev/null
@@ -1,13 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "ios/chrome/browser/ui/settings/privacy/cookies_status_description.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -@implementation CookiesStatusDescription - -@end
diff --git a/ios/chrome/browser/ui/settings/privacy/cookies_status_mediator.h b/ios/chrome/browser/ui/settings/privacy/cookies_status_mediator.h deleted file mode 100644 index 191bdfe..0000000 --- a/ios/chrome/browser/ui/settings/privacy/cookies_status_mediator.h +++ /dev/null
@@ -1,34 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_UI_SETTINGS_PRIVACY_COOKIES_STATUS_MEDIATOR_H_ -#define IOS_CHROME_BROWSER_UI_SETTINGS_PRIVACY_COOKIES_STATUS_MEDIATOR_H_ - -#import <Foundation/Foundation.h> - -@protocol CookiesStatusConsumer; -@class CookiesStatusDescription; -class HostContentSettingsMap; -class PrefService; - -// The mediator is pushing the data for Cookies related views to the -// consumer. -@interface CookiesStatusMediator : NSObject - -- (instancetype)init NS_UNAVAILABLE; - -// Designated initializer. -- (instancetype)initWithPrefService:(PrefService*)prefService - settingsMap:(HostContentSettingsMap*)settingsMap - NS_DESIGNATED_INITIALIZER; - -// The consumer for this mediator. -@property(nonatomic, weak) id<CookiesStatusConsumer> consumer; - -// Returns a configuration for Cookies related views to the coordinator. -- (CookiesStatusDescription*)cookiesDescription; - -@end - -#endif // IOS_CHROME_BROWSER_UI_SETTINGS_PRIVACY_COOKIES_STATUS_MEDIATOR_H_
diff --git a/ios/chrome/browser/ui/settings/privacy/cookies_status_mediator.mm b/ios/chrome/browser/ui/settings/privacy/cookies_status_mediator.mm deleted file mode 100644 index d0c5ff4..0000000 --- a/ios/chrome/browser/ui/settings/privacy/cookies_status_mediator.mm +++ /dev/null
@@ -1,120 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "ios/chrome/browser/ui/settings/privacy/cookies_status_mediator.h" - -#import "base/logging.h" -#include "components/content_settings/core/browser/cookie_settings.h" -#include "components/content_settings/core/browser/host_content_settings_map.h" -#include "components/content_settings/core/common/pref_names.h" -#include "components/prefs/pref_member.h" -#include "components/prefs/pref_service.h" -#include "ios/chrome/browser/content_settings/host_content_settings_map_factory.h" -#import "ios/chrome/browser/ui/settings/privacy/cookies_status_consumer.h" -#import "ios/chrome/browser/ui/settings/privacy/cookies_status_description.h" -#import "ios/chrome/browser/ui/settings/utils/content_setting_backed_boolean.h" -#import "ios/chrome/browser/ui/settings/utils/pref_backed_boolean.h" -#include "ios/chrome/grit/ios_strings.h" -#include "ui/base/l10n/l10n_util.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -namespace { - -typedef NS_ENUM(NSInteger, CookiesSettingType) { - SettingTypeAllowCookies, - SettingTypeBlockThirdPartyCookiesIncognito, - SettingTypeBlockThirdPartyCookies, - SettingTypeBlockAllCookies, -}; - -} // namespace - -@interface CookiesStatusMediator () <BooleanObserver> { - // The preference that decides when the cookie controls UI is enabled. - IntegerPrefMember _prefsCookieControlsMode; -} - -// The observable boolean that binds to the "Enable cookie controls" setting -// state. -@property(nonatomic, strong) - ContentSettingBackedBoolean* prefsContentSettingCookieControl; - -@end - -@implementation CookiesStatusMediator - -- (instancetype)initWithPrefService:(PrefService*)prefService - settingsMap:(HostContentSettingsMap*)settingsMap { - self = [super init]; - if (self) { - __weak CookiesStatusMediator* weakSelf = self; - _prefsCookieControlsMode.Init(prefs::kCookieControlsMode, prefService, - base::BindRepeating(^() { - [weakSelf updateConsumer]; - })); - - _prefsContentSettingCookieControl = [[ContentSettingBackedBoolean alloc] - initWithHostContentSettingsMap:settingsMap - settingID:ContentSettingsType::COOKIES - inverted:NO]; - [_prefsContentSettingCookieControl setObserver:self]; - } - return self; -} - -#pragma mark - Public - -- (CookiesStatusDescription*)cookiesDescription { - CookiesStatusDescription* dataHolder = - [[CookiesStatusDescription alloc] init]; - dataHolder.headerDescription = [self cookiesStatus]; - dataHolder.footerDescription = [self cookiesFooterDescription]; - return dataHolder; -} - -#pragma mark - Private - -// Updates consumer. -- (void)updateConsumer { - [self.consumer cookiesOptionChangedToDescription:[self cookiesDescription]]; -} - -// Returns the status of Cookies according to preferences. -- (NSString*)cookiesStatus { - if (![self.prefsContentSettingCookieControl value]) - return l10n_util::GetNSString(IDS_IOS_COOKIES_BLOCK_ALL); - - if (self.prefsContentSettingCookieControl.value && - _prefsCookieControlsMode.GetValue() == - static_cast<int>( - content_settings::CookieControlsMode::kBlockThirdParty)) - return l10n_util::GetNSString(IDS_IOS_COOKIES_BLOCK_THIRD_PARTY); - - if (_prefsCookieControlsMode.GetValue() == - static_cast<int>(content_settings::CookieControlsMode::kIncognitoOnly)) - return l10n_util::GetNSString(IDS_IOS_COOKIES_BLOCK_THIRD_PARTY_INCOGNITO); - - return l10n_util::GetNSString(IDS_IOS_COOKIES_ALLOW_ALL); -} - -// Returns the footer description of Cookies according to preferences. -- (NSString*)cookiesFooterDescription { - if (_prefsCookieControlsMode.GetValue() == - static_cast<int>(content_settings::CookieControlsMode::kOff)) - return l10n_util::GetNSString( - IDS_IOS_PAGE_INFO_COOKIES_SETTINGS_LINK_LABEL_ALLOW_ALL); - return l10n_util::GetNSString( - IDS_IOS_PAGE_INFO_COOKIES_SETTINGS_LINK_LABEL_BLOCK); -} - -#pragma mark - BooleanObserver - -- (void)booleanDidChange:(id<ObservableBoolean>)observableBoolean { - [self updateConsumer]; -} - -@end
diff --git a/ios/chrome/browser/ui/settings/privacy/cookies_view_controller.h b/ios/chrome/browser/ui/settings/privacy/cookies_view_controller.h deleted file mode 100644 index cd67051..0000000 --- a/ios/chrome/browser/ui/settings/privacy/cookies_view_controller.h +++ /dev/null
@@ -1,41 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_UI_SETTINGS_PRIVACY_COOKIES_VIEW_CONTROLLER_H_ -#define IOS_CHROME_BROWSER_UI_SETTINGS_PRIVACY_COOKIES_VIEW_CONTROLLER_H_ - -#import <UIKit/UIKit.h> - -#import "ios/chrome/browser/ui/settings/settings_root_table_view_controller.h" - -#import "ios/chrome/browser/ui/settings/privacy/cookies_consumer.h" - -@class PrivacyCookiesViewController; - -@protocol PrivacyCookiesCommands; - -// Delegate for presentation events related to -// PrivacyCookiesViewController. -@protocol PrivacyCookiesViewControllerPresentationDelegate - -// Called when the view controller is removed from its parent. -- (void)privacyCookiesViewControllerWasRemoved: - (PrivacyCookiesViewController*)controller; - -@end - -// View Controller for displaying the Cookies screen. -@interface PrivacyCookiesViewController - : SettingsRootTableViewController <PrivacyCookiesConsumer> - -// Presentation delegate. -@property(nonatomic, weak) id<PrivacyCookiesViewControllerPresentationDelegate> - presentationDelegate; - -// Handler used to update Cookies settings. -@property(nonatomic, weak) id<PrivacyCookiesCommands> handler; - -@end - -#endif // IOS_CHROME_BROWSER_UI_SETTINGS_PRIVACY_COOKIES_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/settings/privacy/cookies_view_controller.mm b/ios/chrome/browser/ui/settings/privacy/cookies_view_controller.mm deleted file mode 100644 index 6d0164b..0000000 --- a/ios/chrome/browser/ui/settings/privacy/cookies_view_controller.mm +++ /dev/null
@@ -1,290 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "ios/chrome/browser/ui/settings/privacy/cookies_view_controller.h" - -#include "base/mac/foundation_util.h" -#import "ios/chrome/browser/ui/list_model/list_item+Controller.h" -#import "ios/chrome/browser/ui/settings/privacy/cookies_commands.h" -#import "ios/chrome/browser/ui/settings/settings_navigation_controller.h" -#import "ios/chrome/browser/ui/table_view/cells/table_view_info_button_cell.h" -#import "ios/chrome/browser/ui/table_view/cells/table_view_info_button_item.h" -#import "ios/chrome/browser/ui/table_view/cells/table_view_text_item.h" -#import "ios/chrome/browser/ui/table_view/cells/table_view_text_link_item.h" -#import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h" -#include "ios/chrome/browser/ui/ui_feature_flags.h" -#import "ios/chrome/common/ui/colors/UIColor+cr_semantic_colors.h" -#import "ios/chrome/common/ui/colors/semantic_color_names.h" -#import "ios/chrome/common/ui/elements/popover_label_view_controller.h" -#include "ios/chrome/grit/ios_strings.h" -#include "ui/base/l10n/l10n_util.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -namespace { - -typedef NS_ENUM(NSInteger, ItemType) { - ItemTypeAllowCookies = kItemTypeEnumZero, - ItemTypeBlockThirdPartyCookiesIncognito, - ItemTypeBlockThirdPartyCookies, - ItemTypeBlockAllCookies, - ItemTypeCookiesDescriptionFooter, -}; - -typedef NS_ENUM(NSInteger, SectionIdentifier) { - SectionIdentifierCookiesContent = kSectionIdentifierEnumZero, -}; - -} // namespace - -@interface PrivacyCookiesViewController () - -@property(nonatomic, strong) TableViewItem* selectedCookiesItem; -@property(nonatomic, assign) ItemType selectedSetting; - -@end - -@implementation PrivacyCookiesViewController - -#pragma mark - UIViewController - -- (void)viewDidLoad { - [super viewDidLoad]; - - self.title = l10n_util::GetNSString(IDS_IOS_OPTIONS_PRIVACY_COOKIES); - self.styler.cellBackgroundColor = UIColor.cr_systemBackgroundColor; - self.styler.tableViewBackgroundColor = UIColor.cr_systemBackgroundColor; - self.tableView.backgroundColor = self.styler.tableViewBackgroundColor; - - if (!base::FeatureList::IsEnabled(kSettingsRefresh)) - [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; - - if (!self.tableViewModel) - [self loadModel]; - - NSIndexPath* indexPath = - [self.tableViewModel indexPathForItemType:self.selectedSetting]; - [self updateSelectedCookiesItemWithIndexPath:indexPath]; -} - -- (void)didMoveToParentViewController:(UIViewController*)parent { - [super didMoveToParentViewController:parent]; - if (!parent) { - [self.presentationDelegate privacyCookiesViewControllerWasRemoved:self]; - } -} - -#pragma mark - ChromeTableViewController - -- (void)loadModel { - [super loadModel]; - [self.tableViewModel - addSectionWithIdentifier:SectionIdentifierCookiesContent]; - - TableViewInfoButtonItem* allowCookies = - [[TableViewInfoButtonItem alloc] initWithType:ItemTypeAllowCookies]; - allowCookies.text = l10n_util::GetNSString( - IDS_IOS_OPTIONS_PRIVACY_COOKIES_ALLOW_COOKIES_TITLE); - allowCookies.detailText = l10n_util::GetNSString( - IDS_IOS_OPTIONS_PRIVACY_COOKIES_ALLOW_COOKIES_DETAIL); - allowCookies.useCustomSeparator = YES; - allowCookies.iconImageName = @"accessory_no_checkmark"; - [self.tableViewModel addItem:allowCookies - toSectionWithIdentifier:SectionIdentifierCookiesContent]; - - TableViewInfoButtonItem* blockThirdPartyCookiesIncognito = - [[TableViewInfoButtonItem alloc] - initWithType:ItemTypeBlockThirdPartyCookiesIncognito]; - blockThirdPartyCookiesIncognito.text = l10n_util::GetNSString( - IDS_IOS_OPTIONS_PRIVACY_COOKIES_BLOCK_THIRD_PARTY_COOKIES_INCOGNITO_TITLE); - blockThirdPartyCookiesIncognito.detailText = l10n_util::GetNSString( - IDS_IOS_OPTIONS_PRIVACY_COOKIES_BLOCK_THIRD_PARTY_COOKIES_DETAIL); - blockThirdPartyCookiesIncognito.useCustomSeparator = YES; - blockThirdPartyCookiesIncognito.iconImageName = @"accessory_no_checkmark"; - [self.tableViewModel addItem:blockThirdPartyCookiesIncognito - toSectionWithIdentifier:SectionIdentifierCookiesContent]; - - TableViewInfoButtonItem* blockThirdPartyCookies = - [[TableViewInfoButtonItem alloc] - initWithType:ItemTypeBlockThirdPartyCookies]; - blockThirdPartyCookies.text = l10n_util::GetNSString( - IDS_IOS_OPTIONS_PRIVACY_COOKIES_BLOCK_THIRD_PARTY_COOKIES_TITLE); - blockThirdPartyCookies.detailText = l10n_util::GetNSString( - IDS_IOS_OPTIONS_PRIVACY_COOKIES_BLOCK_THIRD_PARTY_COOKIES_DETAIL); - blockThirdPartyCookies.useCustomSeparator = YES; - blockThirdPartyCookies.iconImageName = @"accessory_no_checkmark"; - [self.tableViewModel addItem:blockThirdPartyCookies - toSectionWithIdentifier:SectionIdentifierCookiesContent]; - - TableViewInfoButtonItem* blockAllCookies = - [[TableViewInfoButtonItem alloc] initWithType:ItemTypeBlockAllCookies]; - blockAllCookies.text = l10n_util::GetNSString( - IDS_IOS_OPTIONS_PRIVACY_COOKIES_BLOCK_ALL_COOKIES_TITLE); - blockAllCookies.detailText = l10n_util::GetNSString( - IDS_IOS_OPTIONS_PRIVACY_COOKIES_BLOCK_ALL_COOKIES_DETAIL); - blockAllCookies.useCustomSeparator = YES; - blockAllCookies.iconImageName = @"accessory_no_checkmark"; - [self.tableViewModel addItem:blockAllCookies - toSectionWithIdentifier:SectionIdentifierCookiesContent]; - - TableViewTextLinkItem* cookiesDescriptionFooter = - [[TableViewTextLinkItem alloc] - initWithType:ItemTypeCookiesDescriptionFooter]; - cookiesDescriptionFooter.text = - l10n_util::GetNSString(IDS_IOS_OPTIONS_PRIVACY_COOKIES_FOOTER); - [self.tableViewModel addItem:cookiesDescriptionFooter - toSectionWithIdentifier:SectionIdentifierCookiesContent]; -} - -#pragma mark - Private - -// Adds Checkmark icon to the selected item. -// Removes the checkmark icon of the prevous selected option item. -- (void)updateSelectedCookiesItemWithIndexPath:(NSIndexPath*)indexPath { - // TODO(crbug.com/1095579): Tint this. - TableViewItem* previousSelectedCookiesItem; - if (self.selectedCookiesItem) { - previousSelectedCookiesItem = self.selectedCookiesItem; - static_cast<TableViewInfoButtonItem*>(previousSelectedCookiesItem) - .iconImageName = @"accessory_no_checkmark"; - } - self.selectedCookiesItem = [self.tableViewModel itemAtIndexPath:indexPath]; - TableViewInfoButtonItem* selectedItem = - static_cast<TableViewInfoButtonItem*>(self.selectedCookiesItem); - selectedItem.iconImageName = @"accessory_checkmark"; - selectedItem.tintColor = [UIColor colorNamed:kBlueColor]; - - if (previousSelectedCookiesItem) - [self reconfigureCellsForItems:@[ - previousSelectedCookiesItem, self.selectedCookiesItem - ]]; -} - -// Returns the ItemType associated with the CookiesSettingType. -- (ItemType)itemTypeForCookiesSettingType:(CookiesSettingType)settingType { - switch (settingType) { - case SettingTypeBlockThirdPartyCookiesIncognito: - return ItemTypeBlockThirdPartyCookiesIncognito; - case SettingTypeBlockThirdPartyCookies: - return ItemTypeBlockThirdPartyCookies; - case SettingTypeBlockAllCookies: - return ItemTypeBlockAllCookies; - case SettingTypeAllowCookies: - return ItemTypeAllowCookies; - } -} - -#pragma mark - Actions - -// Called when the user clicks on the information button. -- (void)didTapInfoIcon:(UIButton*)button { - NSString* message; - switch (button.tag) { - case ItemTypeAllowCookies: - message = l10n_util::GetNSString( - IDS_IOS_OPTIONS_PRIVACY_COOKIES_ALLOW_COOKIES_DESCRIPTION); - break; - case ItemTypeBlockThirdPartyCookiesIncognito: - message = l10n_util::GetNSString( - IDS_IOS_OPTIONS_PRIVACY_COOKIES_BLOCK_THIRD_PARTY_COOKIES_INCOGNITO_DESCRIPTION); - break; - case ItemTypeBlockThirdPartyCookies: - message = l10n_util::GetNSString( - IDS_IOS_OPTIONS_PRIVACY_COOKIES_BLOCK_THIRD_PARTY_COOKIES_DESCRIPTION); - break; - case ItemTypeBlockAllCookies: - message = l10n_util::GetNSString( - IDS_IOS_OPTIONS_PRIVACY_COOKIES_BLOCK_ALL_COOKIES_DESCRIPTION); - break; - default: - return; - } - - PopoverLabelViewController* bubbleViewController = - [[PopoverLabelViewController alloc] initWithMessage:message]; - [self presentViewController:bubbleViewController animated:YES completion:nil]; - - // Set the anchor and arrow direction of the bubble. - bubbleViewController.popoverPresentationController.sourceView = button; - bubbleViewController.popoverPresentationController.sourceRect = button.bounds; - bubbleViewController.popoverPresentationController.permittedArrowDirections = - UIPopoverArrowDirectionUp; -} - -#pragma mark - UITableViewDelegate - -- (void)tableView:(UITableView*)tableView - didSelectRowAtIndexPath:(NSIndexPath*)indexPath { - [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; - ItemType itemType = - (ItemType)[self.tableViewModel itemTypeForIndexPath:indexPath]; - CookiesSettingType settingType; - switch (itemType) { - case ItemTypeAllowCookies: - settingType = SettingTypeAllowCookies; - break; - case ItemTypeBlockThirdPartyCookiesIncognito: - settingType = SettingTypeBlockThirdPartyCookiesIncognito; - break; - case ItemTypeBlockThirdPartyCookies: - settingType = SettingTypeBlockThirdPartyCookies; - break; - case ItemTypeBlockAllCookies: - settingType = SettingTypeBlockAllCookies; - break; - default: - return; - } - [self.handler selectedCookiesSettingType:settingType]; -} - -#pragma mark - UITableViewDataSource - -- (UITableViewCell*)tableView:(UITableView*)tableView - cellForRowAtIndexPath:(NSIndexPath*)indexPath { - UITableViewCell* cell = [super tableView:tableView - cellForRowAtIndexPath:indexPath]; - if ([self.tableViewModel itemTypeForIndexPath:indexPath] == - ItemTypeCookiesDescriptionFooter) - return cell; - - TableViewInfoButtonCell* managedCell = - base::mac::ObjCCastStrict<TableViewInfoButtonCell>(cell); - [managedCell.trailingButton addTarget:self - action:@selector(didTapInfoIcon:) - forControlEvents:UIControlEventTouchUpInside]; - switch ([self.tableViewModel itemTypeForIndexPath:indexPath]) { - case ItemTypeAllowCookies: { - managedCell.trailingButton.tag = ItemTypeAllowCookies; - break; - } - case ItemTypeBlockThirdPartyCookiesIncognito: { - managedCell.trailingButton.tag = ItemTypeBlockThirdPartyCookiesIncognito; - break; - } - case ItemTypeBlockThirdPartyCookies: { - managedCell.trailingButton.tag = ItemTypeBlockThirdPartyCookies; - break; - } - - case ItemTypeBlockAllCookies: { - managedCell.trailingButton.tag = ItemTypeBlockAllCookies; - break; - } - } - return cell; -} - -#pragma mark - PrivacyCookiesConsumer - -- (void)cookiesSettingsOptionSelected:(CookiesSettingType)settingType { - self.selectedSetting = [self itemTypeForCookiesSettingType:settingType]; - NSIndexPath* indexPath = [self.tableViewModel - indexPathForItemType:[self itemTypeForCookiesSettingType:settingType]]; - [self updateSelectedCookiesItemWithIndexPath:indexPath]; -} - -@end
diff --git a/ios/chrome/browser/ui/settings/privacy/privacy_coordinator.mm b/ios/chrome/browser/ui/settings/privacy/privacy_coordinator.mm index 2073a4b..d7b476b 100644 --- a/ios/chrome/browser/ui/settings/privacy/privacy_coordinator.mm +++ b/ios/chrome/browser/ui/settings/privacy/privacy_coordinator.mm
@@ -5,22 +5,17 @@ #import "ios/chrome/browser/ui/settings/privacy/privacy_coordinator.h" #import "base/mac/foundation_util.h" -#include "components/content_settings/core/common/features.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" -#include "ios/chrome/browser/content_settings/host_content_settings_map_factory.h" #include "ios/chrome/browser/main/browser.h" #import "ios/chrome/browser/ui/commands/browser_commands.h" #import "ios/chrome/browser/ui/commands/command_dispatcher.h" #import "ios/chrome/browser/ui/commands/open_new_tab_command.h" #import "ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_table_view_controller.h" #import "ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_ui_delegate.h" -#import "ios/chrome/browser/ui/settings/privacy/cookies_coordinator.h" -#import "ios/chrome/browser/ui/settings/privacy/cookies_status_mediator.h" #import "ios/chrome/browser/ui/settings/privacy/handoff_table_view_controller.h" #import "ios/chrome/browser/ui/settings/privacy/privacy_navigation_commands.h" #import "ios/chrome/browser/ui/settings/privacy/privacy_table_view_controller.h" #import "ios/chrome/browser/ui/settings/settings_navigation_controller.h" -#include "ios/chrome/browser/ui/ui_feature_flags.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -28,14 +23,11 @@ @interface PrivacyCoordinator () < ClearBrowsingDataUIDelegate, - PrivacyCookiesCoordinatorDelegate, PrivacyNavigationCommands, PrivacyTableViewControllerPresentationDelegate> @property(nonatomic, strong) id<ApplicationCommands> handler; @property(nonatomic, strong) PrivacyTableViewController* viewController; -@property(nonatomic, strong) PrivacyCookiesCoordinator* cookiesCoordinator; -@property(nonatomic, strong) CookiesStatusMediator* cookiesStatusMediator; @end @@ -58,19 +50,8 @@ self.handler = HandlerForProtocol(self.browser->GetCommandDispatcher(), ApplicationCommands); - if (base::FeatureList::IsEnabled(content_settings::kImprovedCookieControls)) { - self.cookiesStatusMediator = [[CookiesStatusMediator alloc] - initWithPrefService:self.browser->GetBrowserState()->GetPrefs() - settingsMap:ios::HostContentSettingsMapFactory:: - GetForBrowserState( - self.browser->GetBrowserState())]; - } - - self.viewController = [[PrivacyTableViewController alloc] - initWithBrowser:self.browser - cookiesDescription:[self.cookiesStatusMediator cookiesDescription]]; - - self.cookiesStatusMediator.consumer = self.viewController; + self.viewController = + [[PrivacyTableViewController alloc] initWithBrowser:self.browser]; DCHECK(self.baseNavigationController); self.viewController.handler = self; @@ -84,9 +65,6 @@ - (void)stop { self.viewController = nil; - [self.cookiesCoordinator stop]; - self.cookiesCoordinator = nil; - self.cookiesStatusMediator = nil; } #pragma mark - PrivacyTableViewControllerPresentationDelegate @@ -97,15 +75,6 @@ [self.delegate privacyCoordinatorViewControllerWasRemoved:self]; } -#pragma mark - PrivacyCookiesCoordinatorDelegate - -- (void)privacyCookiesCoordinatorViewControllerWasRemoved: - (PrivacyCookiesCoordinator*)coordinator { - DCHECK(self.cookiesCoordinator); - [coordinator stop]; - coordinator = nil; -} - #pragma mark - PrivacyNavigationCommands - (void)showHandoff { @@ -127,14 +96,6 @@ animated:YES]; } -- (void)showCookies { - self.cookiesCoordinator = [[PrivacyCookiesCoordinator alloc] - initWithBaseNavigationController:self.baseNavigationController - browser:self.browser]; - self.cookiesCoordinator.delegate = self; - [self.cookiesCoordinator start]; -} - #pragma mark - ClearBrowsingDataUIDelegate - (void)openURL:(const GURL&)URL {
diff --git a/ios/chrome/browser/ui/settings/privacy/privacy_navigation_commands.h b/ios/chrome/browser/ui/settings/privacy/privacy_navigation_commands.h index 6c20130..a107e606 100644 --- a/ios/chrome/browser/ui/settings/privacy/privacy_navigation_commands.h +++ b/ios/chrome/browser/ui/settings/privacy/privacy_navigation_commands.h
@@ -15,9 +15,6 @@ // Shows ClearBrowsingData screen. - (void)showClearBrowsingData; -// Shows Cookies screen. -- (void)showCookies; - @end #endif // IOS_CHROME_BROWSER_UI_SETTINGS_PRIVACY_PRIVACY_NAVIGATION_COMMANDS_H_
diff --git a/ios/chrome/browser/ui/settings/privacy/privacy_table_view_controller.h b/ios/chrome/browser/ui/settings/privacy/privacy_table_view_controller.h index 6602c4f..3b900bd 100644 --- a/ios/chrome/browser/ui/settings/privacy/privacy_table_view_controller.h +++ b/ios/chrome/browser/ui/settings/privacy/privacy_table_view_controller.h
@@ -5,8 +5,6 @@ #ifndef IOS_CHROME_BROWSER_UI_SETTINGS_PRIVACY_PRIVACY_TABLE_VIEW_CONTROLLER_H_ #define IOS_CHROME_BROWSER_UI_SETTINGS_PRIVACY_PRIVACY_TABLE_VIEW_CONTROLLER_H_ -#import "ios/chrome/browser/ui/settings/privacy/cookies_status_consumer.h" -#import "ios/chrome/browser/ui/settings/privacy/cookies_status_description.h" #import "ios/chrome/browser/ui/settings/settings_controller_protocol.h" #import "ios/chrome/browser/ui/settings/settings_root_table_view_controller.h" @@ -29,8 +27,7 @@ @end @interface PrivacyTableViewController - : SettingsRootTableViewController <CookiesStatusConsumer, - SettingsControllerProtocol> + : SettingsRootTableViewController <SettingsControllerProtocol> // Presentation delegate. @property(nonatomic, weak) id<PrivacyTableViewControllerPresentationDelegate> @@ -38,7 +35,6 @@ // |browserState| cannot be nil - (instancetype)initWithBrowser:(Browser*)browser - cookiesDescription:(CookiesStatusDescription*)cookiesDescription NS_DESIGNATED_INITIALIZER; - (instancetype)initWithStyle:(UITableViewStyle)style NS_UNAVAILABLE;
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 2f9318e..2c49fe4 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
@@ -22,7 +22,6 @@ #import "ios/chrome/browser/ui/page_info/features.h" #import "ios/chrome/browser/ui/settings/cells/settings_switch_cell.h" #import "ios/chrome/browser/ui/settings/cells/settings_switch_item.h" -#import "ios/chrome/browser/ui/settings/privacy/cookies_status_description.h" #import "ios/chrome/browser/ui/settings/privacy/privacy_navigation_commands.h" #import "ios/chrome/browser/ui/settings/settings_navigation_controller.h" #import "ios/chrome/browser/ui/settings/settings_table_view_controller_constants.h" @@ -51,7 +50,6 @@ typedef NS_ENUM(NSInteger, ItemType) { ItemTypeClearBrowsingDataClear = kItemTypeEnumZero, - ItemTypeCookies, // Footer to suggest the user to open Sync and Google services settings. ItemTypePrivacyFooter, ItemTypeOtherDevicesHandoff, @@ -77,7 +75,6 @@ // Browser. @property(nonatomic, readonly) Browser* browser; -@property(nonatomic, strong) CookiesStatusDescription* cookiesDescription; @end @@ -85,8 +82,7 @@ #pragma mark - Initialization -- (instancetype)initWithBrowser:(Browser*)browser - cookiesDescription:(CookiesStatusDescription*)cookiesDescription { +- (instancetype)initWithBrowser:(Browser*)browser { DCHECK(browser); UITableViewStyle style = base::FeatureList::IsEnabled(kSettingsRefresh) ? UITableViewStylePlain @@ -95,7 +91,6 @@ if (self) { _browser = browser; _browserState = browser->GetBrowserState(); - _cookiesDescription = cookiesDescription; self.title = l10n_util::GetNSString(IDS_OPTIONS_ADVANCED_SECTION_TITLE_PRIVACY); @@ -140,12 +135,6 @@ [model addItem:[self clearBrowsingDetailItem] toSectionWithIdentifier:SectionIdentifierPrivacyContent]; - if (base::FeatureList::IsEnabled(content_settings::kImprovedCookieControls)) { - // Cookies item. - [model addItem:[self cookiesItemWithDetailText:self.cookiesDescription - .headerDescription] - toSectionWithIdentifier:SectionIdentifierPrivacyContent]; - } [model setFooter:[self showPrivacyFooterItem] forSectionWithIdentifier:SectionIdentifierPrivacyContent]; @@ -183,14 +172,6 @@ return showPrivacyFooterItem; } -// Returns TableViewHeaderFooterItem instance to open Cookies screen. -- (TableViewItem*)cookiesItemWithDetailText:(NSString*)detailText { - return [self detailItemWithType:ItemTypeCookies - titleId:IDS_IOS_OPTIONS_PRIVACY_COOKIES - detailText:detailText - accessibilityIdentifier:kSettingsCookiesCellId]; -} - - (TableViewItem*)clearBrowsingDetailItem { return [self detailItemWithType:ItemTypeClearBrowsingDataClear titleId:IDS_IOS_CLEAR_BROWSING_DATA_TITLE @@ -249,9 +230,6 @@ case ItemTypeClearBrowsingDataClear: [self.handler showClearBrowsingData]; break; - case ItemTypeCookies: - [self.handler showCookies]; - break; default: break; } @@ -284,20 +262,4 @@ } } -#pragma mark - CookiesStatusConsumer - -- (void)cookiesOptionChangedToDescription: - (CookiesStatusDescription*)description { - // Update the Cookies Header. - NSIndexPath* indexPath = [self.tableViewModel - indexPathForItemType:ItemTypeCookies - sectionIdentifier:SectionIdentifierPrivacyContent]; - TableViewDetailIconItem* cookiesHeader = - base::mac::ObjCCastStrict<TableViewDetailIconItem>( - [self.tableViewModel itemAtIndexPath:indexPath]); - cookiesHeader.detailText = description.headerDescription; - - [self reconfigureCellsForItems:@[ cookiesHeader ]]; -} - @end
diff --git a/ios/chrome/browser/ui/settings/privacy/privacy_table_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/privacy/privacy_table_view_controller_unittest.mm index 5a5f03b..032117c 100644 --- a/ios/chrome/browser/ui/settings/privacy/privacy_table_view_controller_unittest.mm +++ b/ios/chrome/browser/ui/settings/privacy/privacy_table_view_controller_unittest.mm
@@ -75,8 +75,7 @@ } ChromeTableViewController* InstantiateController() override { - return [[PrivacyTableViewController alloc] initWithBrowser:browser_.get() - cookiesDescription:nil]; + return [[PrivacyTableViewController alloc] initWithBrowser:browser_.get()]; } web::WebTaskEnvironment task_environment_; @@ -93,16 +92,9 @@ EXPECT_EQ(2, NumberOfSections()); // Sections[0]. - if (base::FeatureList::IsEnabled(content_settings::kImprovedCookieControls)) { - EXPECT_EQ(2, NumberOfItemsInSection(0)); - CheckTextCellTextAndDetailText( - l10n_util::GetNSString(IDS_IOS_OPTIONS_PRIVACY_COOKIES), nil, 0, 1); - - } else { - EXPECT_EQ(1, NumberOfItemsInSection(0)); - CheckTextCellTextAndDetailText( - l10n_util::GetNSString(IDS_IOS_CLEAR_BROWSING_DATA_TITLE), nil, 0, 0); - } + EXPECT_EQ(1, NumberOfItemsInSection(0)); + CheckTextCellTextAndDetailText( + l10n_util::GetNSString(IDS_IOS_CLEAR_BROWSING_DATA_TITLE), nil, 0, 0); // Sections[1]. EXPECT_EQ(1, NumberOfItemsInSection(1));
diff --git a/ios/chrome/browser/ui/tab_grid/BUILD.gn b/ios/chrome/browser/ui/tab_grid/BUILD.gn index b21d9f9..1fec54f 100644 --- a/ios/chrome/browser/ui/tab_grid/BUILD.gn +++ b/ios/chrome/browser/ui/tab_grid/BUILD.gn
@@ -31,6 +31,7 @@ "//ios/chrome/browser/snapshots", "//ios/chrome/browser/tabs", "//ios/chrome/browser/ui:feature_flags", + "//ios/chrome/browser/ui/activity_services", "//ios/chrome/browser/ui/commands", "//ios/chrome/browser/ui/coordinators:chrome_coordinators", "//ios/chrome/browser/ui/history", @@ -38,6 +39,7 @@ "//ios/chrome/browser/ui/main", "//ios/chrome/browser/ui/recent_tabs", "//ios/chrome/browser/ui/recent_tabs:recent_tabs_ui", + "//ios/chrome/browser/ui/sharing", "//ios/chrome/browser/ui/tab_grid/transitions", "//ios/chrome/browser/ui/util", "//ios/chrome/browser/url_loading",
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm index a4f1c22b..30e4aa8a 100644 --- a/ios/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm +++ b/ios/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm
@@ -6,11 +6,14 @@ #include "base/mac/bundle_locations.h" #include "base/mac/foundation_util.h" +#include "base/metrics/histogram_functions.h" #include "base/metrics/user_metrics.h" #include "base/metrics/user_metrics_action.h" +#include "ios/chrome/browser/browser_state/chrome_browser_state.h" #include "ios/chrome/browser/chrome_url_constants.h" #include "ios/chrome/browser/main/browser.h" #include "ios/chrome/browser/sessions/ios_chrome_tab_restore_service_factory.h" +#import "ios/chrome/browser/ui/activity_services/activity_params.h" #import "ios/chrome/browser/ui/commands/application_commands.h" #import "ios/chrome/browser/ui/commands/browser_commands.h" #import "ios/chrome/browser/ui/commands/browsing_data_commands.h" @@ -20,8 +23,11 @@ #import "ios/chrome/browser/ui/history/public/history_presentation_delegate.h" #import "ios/chrome/browser/ui/main/bvc_container_view_controller.h" #import "ios/chrome/browser/ui/recent_tabs/recent_tabs_mediator.h" +#import "ios/chrome/browser/ui/recent_tabs/recent_tabs_menu_helper.h" #import "ios/chrome/browser/ui/recent_tabs/recent_tabs_presentation_delegate.h" #import "ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.h" +#include "ios/chrome/browser/ui/recent_tabs/synced_sessions.h" +#import "ios/chrome/browser/ui/sharing/sharing_coordinator.h" #import "ios/chrome/browser/ui/tab_grid/tab_grid_coordinator_delegate.h" #import "ios/chrome/browser/ui/tab_grid/tab_grid_mediator.h" #import "ios/chrome/browser/ui/tab_grid/tab_grid_paging.h" @@ -29,6 +35,7 @@ #import "ios/chrome/browser/ui/tab_grid/transitions/tab_grid_transition_handler.h" #include "ios/chrome/browser/ui/ui_feature_flags.h" #import "ios/chrome/browser/ui/util/uikit_ui_util.h" +#import "ios/chrome/browser/url_loading/url_loading_browser_agent.h" #import "ios/chrome/browser/url_loading/url_loading_params.h" #import "ios/chrome/browser/web_state_list/web_state_list.h" @@ -38,6 +45,7 @@ @interface TabGridCoordinator () <TabPresentationDelegate, HistoryPresentationDelegate, + RecentTabsContextMenuDelegate, RecentTabsPresentationDelegate> { // Use an explicit ivar instead of synthesizing as the setter isn't using the // ivar. @@ -64,6 +72,10 @@ @property(nonatomic, strong) HistoryCoordinator* historyCoordinator; // YES if the TabViewController has never been shown yet. @property(nonatomic, assign) BOOL firstPresentation; +@property(nonatomic, strong) SharingCoordinator* sharingCoordinator; +@property(nonatomic, strong) + RecentTabsContextMenuHelper* recentTabsContextMenuHelper; + @end @implementation TabGridCoordinator @@ -268,6 +280,15 @@ baseViewController.regularTabsImageDataSource = self.regularTabsMediator; baseViewController.incognitoTabsImageDataSource = self.incognitoTabsMediator; + if (@available(iOS 13.0, *)) { + self.recentTabsContextMenuHelper = + [[RecentTabsContextMenuHelper alloc] initWithBrowser:self.regularBrowser + recentTabsPresentationDelegate:self + recentTabsContextMenuDelegate:self]; + self.baseViewController.remoteTabsViewController.menuProvider = + self.recentTabsContextMenuHelper; + } + // TODO(crbug.com/845192) : Remove RecentTabsTableViewController dependency on // ChromeBrowserState so that we don't need to expose the view controller. baseViewController.remoteTabsViewController.browser = self.regularBrowser; @@ -314,6 +335,9 @@ // handler after this coordinator has stopped; make this action a no-op by // setting the handler to nil. self.baseViewController.handler = nil; + self.recentTabsContextMenuHelper = nil; + [self.sharingCoordinator stop]; + self.sharingCoordinator = nil; [self.dispatcher stopDispatchingForProtocol:@protocol(ApplicationCommands)]; [self.dispatcher stopDispatchingForProtocol:@protocol(ApplicationSettingsCommands)]; @@ -399,7 +423,53 @@ - (void)openAllTabsFromSession:(const synced_sessions::DistantSession*)session { - // TODO(crbug.com/1093302) : Implement this. + base::RecordAction(base::UserMetricsAction( + "MobileRecentTabManagerOpenAllTabsFromOtherDevice")); + base::UmaHistogramCounts100( + "Mobile.RecentTabsManager.TotalTabsFromOtherDevicesOpenAll", + session->tabs.size()); + + for (auto const& tab : session->tabs) { + UrlLoadParams params = UrlLoadParams::InNewTab(tab->virtual_url); + params.SetInBackground(YES); + params.web_params.transition_type = ui::PAGE_TRANSITION_AUTO_BOOKMARK; + params.load_strategy = + self.baseViewController.remoteTabsViewController.loadStrategy; + params.in_incognito = + self.regularBrowser->GetBrowserState()->IsOffTheRecord(); + UrlLoadingBrowserAgent::FromBrowser(self.regularBrowser)->Load(params); + } + + [self showActiveRegularTabFromRecentTabs]; +} + +#pragma mark - RecentTabsContextMenuDelegate + +- (void)shareURL:(const GURL&)URL + title:(NSString*)title + fromView:(UIView*)view { + ActivityParams* params = + [[ActivityParams alloc] initWithURL:URL + title:title + scenario:ActivityScenario::RecentTabsEntry]; + self.sharingCoordinator = [[SharingCoordinator alloc] + initWithBaseViewController:self.baseViewController + .remoteTabsViewController + browser:self.regularBrowser + params:params + originView:view]; + [self.sharingCoordinator start]; +} + +- (void)removeSessionAtSessionSectionIdentifier:(NSInteger)sectionIdentifier { + [self.baseViewController.remoteTabsViewController + removeSessionAtSessionSectionIdentifier:sectionIdentifier]; +} + +- (synced_sessions::DistantSession const*)sessionForSectionIdentifier: + (NSInteger)sectionIdentifier { + return [self.baseViewController.remoteTabsViewController + sessionForSectionIdentifier:sectionIdentifier]; } @end
diff --git a/ios/chrome/common/ui/elements/popover_label_view_controller.mm b/ios/chrome/common/ui/elements/popover_label_view_controller.mm index 40299a2..2366d4c 100644 --- a/ios/chrome/common/ui/elements/popover_label_view_controller.mm +++ b/ios/chrome/common/ui/elements/popover_label_view_controller.mm
@@ -113,24 +113,69 @@ [_scrollView addSubview:textView]; - UITextView* secondaryTextView = [[UITextView alloc] init]; - secondaryTextView.scrollEnabled = NO; - secondaryTextView.editable = NO; - secondaryTextView.delegate = self; - secondaryTextView.backgroundColor = [UIColor clearColor]; - secondaryTextView.font = - [UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline]; - secondaryTextView.adjustsFontForContentSizeCategory = YES; - secondaryTextView.translatesAutoresizingMaskIntoConstraints = NO; - secondaryTextView.textColor = [UIColor colorNamed:kTextSecondaryColor]; - secondaryTextView.linkTextAttributes = - @{NSForegroundColorAttributeName : [UIColor colorNamed:kBlueColor]}; - - if (self.secondaryAttributedString) { + // Only create secondary TextView when |secondaryAttributedString| is not nil. + // Set the constraint accordingly. + if (self.secondaryAttributedString && + !self.secondaryAttributedString.length) { + UITextView* secondaryTextView = [[UITextView alloc] init]; + secondaryTextView.scrollEnabled = NO; + secondaryTextView.editable = NO; + secondaryTextView.delegate = self; + secondaryTextView.backgroundColor = [UIColor clearColor]; + secondaryTextView.font = + [UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline]; + secondaryTextView.adjustsFontForContentSizeCategory = YES; + secondaryTextView.translatesAutoresizingMaskIntoConstraints = NO; + secondaryTextView.textColor = [UIColor colorNamed:kTextSecondaryColor]; + secondaryTextView.linkTextAttributes = + @{NSForegroundColorAttributeName : [UIColor colorNamed:kBlueColor]}; secondaryTextView.attributedText = self.secondaryAttributedString; - } - [_scrollView addSubview:secondaryTextView]; + [_scrollView addSubview:secondaryTextView]; + + [NSLayoutConstraint activateConstraints:@[ + [textContainerView.widthAnchor + constraintEqualToAnchor:_scrollView.widthAnchor], + [textContainerView.leadingAnchor + constraintEqualToAnchor:textView.leadingAnchor + constant:-kHorizontalInsetValue], + [textContainerView.leadingAnchor + constraintEqualToAnchor:secondaryTextView.leadingAnchor + constant:-kHorizontalInsetValue], + [textContainerView.trailingAnchor + constraintEqualToAnchor:textView.trailingAnchor + constant:kHorizontalInsetValue], + [textContainerView.trailingAnchor + constraintEqualToAnchor:secondaryTextView.trailingAnchor + constant:kHorizontalInsetValue], + [textView.bottomAnchor constraintEqualToAnchor:secondaryTextView.topAnchor + constant:-kVerticalDistance], + [textContainerView.topAnchor + constraintEqualToAnchor:textView.topAnchor + constant:-kVerticalInsetValue], + [textContainerView.bottomAnchor + constraintEqualToAnchor:secondaryTextView.bottomAnchor + constant:kVerticalInsetValue], + ]]; + } else { + // Constraints used when only have primary TextView. + [NSLayoutConstraint activateConstraints:@[ + [textContainerView.widthAnchor + constraintEqualToAnchor:_scrollView.widthAnchor], + [textContainerView.leadingAnchor + constraintEqualToAnchor:textView.leadingAnchor + constant:-kHorizontalInsetValue], + [textContainerView.trailingAnchor + constraintEqualToAnchor:textView.trailingAnchor + constant:kHorizontalInsetValue], + [textContainerView.topAnchor + constraintEqualToAnchor:textView.topAnchor + constant:-kVerticalInsetValue], + [textContainerView.bottomAnchor + constraintEqualToAnchor:textView.bottomAnchor + constant:kVerticalInsetValue], + ]]; + } NSLayoutConstraint* heightConstraint = [_scrollView.heightAnchor constraintEqualToAnchor:_scrollView.contentLayoutGuide.heightAnchor @@ -141,35 +186,6 @@ // scroll view. heightConstraint.priority = UILayoutPriorityDefaultHigh - 1; heightConstraint.active = YES; - - CGFloat verticalOffset = - (secondaryTextView.attributedText) ? -kVerticalDistance : 0; - NSLayoutConstraint* verticalConstraint = - [textView.bottomAnchor constraintEqualToAnchor:secondaryTextView.topAnchor - constant:verticalOffset]; - - [NSLayoutConstraint activateConstraints:@[ - [textContainerView.widthAnchor - constraintEqualToAnchor:_scrollView.widthAnchor], - [textContainerView.leadingAnchor - constraintEqualToAnchor:textView.leadingAnchor - constant:-kHorizontalInsetValue], - [textContainerView.leadingAnchor - constraintEqualToAnchor:secondaryTextView.leadingAnchor - constant:-kHorizontalInsetValue], - [textContainerView.trailingAnchor - constraintEqualToAnchor:textView.trailingAnchor - constant:kHorizontalInsetValue], - [textContainerView.trailingAnchor - constraintEqualToAnchor:secondaryTextView.trailingAnchor - constant:kHorizontalInsetValue], - verticalConstraint, - [textContainerView.topAnchor constraintEqualToAnchor:textView.topAnchor - constant:-kVerticalInsetValue], - [textContainerView.bottomAnchor - constraintEqualToAnchor:secondaryTextView.bottomAnchor - constant:kVerticalInsetValue], - ]]; } - (void)viewWillAppear:(BOOL)animated {
diff --git a/ios/chrome/common/ui/reauthentication/BUILD.gn b/ios/chrome/common/ui/reauthentication/BUILD.gn index f87ff97f..26c5f71 100644 --- a/ios/chrome/common/ui/reauthentication/BUILD.gn +++ b/ios/chrome/common/ui/reauthentication/BUILD.gn
@@ -5,6 +5,7 @@ source_set("reauthentication") { configs += [ "//build/config/compiler:enable_arc" ] sources = [ + "reauthentication_event.h", "reauthentication_module.h", "reauthentication_module.mm", "reauthentication_protocol.h",
diff --git a/ios/chrome/common/ui/reauthentication/reauthentication_event.h b/ios/chrome/common/ui/reauthentication/reauthentication_event.h new file mode 100644 index 0000000..6aad039 --- /dev/null +++ b/ios/chrome/common/ui/reauthentication/reauthentication_event.h
@@ -0,0 +1,20 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_COMMON_UI_REAUTHENTICATION_REAUTHENTICATION_EVENT_H_ +#define IOS_CHROME_COMMON_UI_REAUTHENTICATION_REAUTHENTICATION_EVENT_H_ + +// These values are persisted to logs. Entries should not be renumbered and +// numeric values should never be reused. +// Must be in sync with ReauthenticationEvent enum in +// tools/metrics/histograms/enums.xml. +enum class ReauthenticationEvent { + kAttempt = 0, + kSuccess = 1, + kFailure = 2, + kMissingPasscode = 3, + kMaxValue = kMissingPasscode, +}; + +#endif // IOS_CHROME_COMMON_UI_REAUTHENTICATION_REAUTHENTICATION_EVENT_H_
diff --git a/ios/chrome/common/ui/reauthentication/reauthentication_module.h b/ios/chrome/common/ui/reauthentication/reauthentication_module.h index f00d7dbb..50d151a 100644 --- a/ios/chrome/common/ui/reauthentication/reauthentication_module.h +++ b/ios/chrome/common/ui/reauthentication/reauthentication_module.h
@@ -27,6 +27,8 @@ * This is used by |PasswordsDetailsCollectionViewController| and * |PasswordExporter|to re-authenticate the user before displaying the password * in plain text, allowing it to be copied, or exporting passwords. + * TODO(crbug.com/1116979): Convert reauthentication module to model object + * (keyed service or browser agent). */ @interface ReauthenticationModule : NSObject <ReauthenticationProtocol>
diff --git a/ios/chrome/test/BUILD.gn b/ios/chrome/test/BUILD.gn index 4d6300a..520761a 100644 --- a/ios/chrome/test/BUILD.gn +++ b/ios/chrome/test/BUILD.gn
@@ -173,7 +173,6 @@ "//ios/chrome/browser/browser_state:unit_tests", "//ios/chrome/browser/browsing_data:unit_tests", "//ios/chrome/browser/complex_tasks:unit_tests", - "//ios/chrome/browser/content_settings:unit_tests", "//ios/chrome/browser/crash_report:unit_tests", "//ios/chrome/browser/crash_report/breadcrumbs:unit_tests", "//ios/chrome/browser/credential_provider:unit_tests",
diff --git a/ios/public/provider/chrome/browser/user_feedback/user_feedback_provider.h b/ios/public/provider/chrome/browser/user_feedback/user_feedback_provider.h index 3d3f5da..4aef79b 100644 --- a/ios/public/provider/chrome/browser/user_feedback/user_feedback_provider.h +++ b/ios/public/provider/chrome/browser/user_feedback/user_feedback_provider.h
@@ -13,14 +13,18 @@ // This data source object is used to obtain initial data to populate the fields // on the User Feedback form. +// TODO(crbug.com/1117041): Rename this protocol to something more specific to +// currentPageScreenshot since that might be the only method remaining. @protocol UserFeedbackDataSource<NSObject> // Returns whether user was viewing a tab in Incognito mode. +// TODO(crbug.com/1117041): Move this into a UserFeedback config object. - (BOOL)currentPageIsIncognito; // Returns a formatted string representation of the URL that the user was // viewing. May return nil if the tab viewed does not have a valid URL to be // shown (e.g. user was viewing stack view controller). +// TODO(crbug.com/1117041): Move this into a UserFeedback config object. - (NSString*)currentPageDisplayURL; // Returns a screenshot of the application suitable for attaching to problem @@ -30,8 +34,14 @@ // Returns the username of the account being synced. // Returns nil if sync is not enabled or user is in incognito mode. +// TODO(crbug.com/1117041): Move this into a UserFeedback config object. - (NSString*)currentPageSyncedUserName; +// Returns the additional product specific data to be sent in the Send Feedback +// report. +// TODO(crbug.com/1117041): Move this into a UserFeedback config object. +- (NSDictionary<NSString*, NSString*>*)specificProductData; + @end // UserFeedbackProvider allows embedders to provide functionality to collect @@ -46,6 +56,8 @@ // |data_source| provides the information to initialize the view controller // and |dispatcher| is an object from the embedder that can perform operations // on behalf of the UserFeedbackProvider. + // TODO(crbug.com/1117041): Send a configuration object instead of these + // parameters. virtual UIViewController* CreateViewController( id<UserFeedbackDataSource> data_source, id<ApplicationCommands> handler);
diff --git a/ios/web_view/internal/autofill/cwv_autofill_controller_unittest.mm b/ios/web_view/internal/autofill/cwv_autofill_controller_unittest.mm index d237b5a..2923208e 100644 --- a/ios/web_view/internal/autofill/cwv_autofill_controller_unittest.mm +++ b/ios/web_view/internal/autofill/cwv_autofill_controller_unittest.mm
@@ -161,7 +161,8 @@ [FormSuggestion suggestionWithValue:kTestFieldValue displayDescription:kTestDisplayDescription icon:nil - identifier:0]; + identifier:0 + requiresReauth:NO]; [autofill_agent_ addSuggestion:suggestion forFormName:kTestFormName fieldIdentifier:kTestFieldIdentifier @@ -207,7 +208,8 @@ [FormSuggestion suggestionWithValue:kTestFieldValue displayDescription:nil icon:nil - identifier:0]; + identifier:0 + requiresReauth:NO]; OCMExpect([password_controller_ checkIfSuggestionsAvailableForForm:[OCMArg any] isMainFrame:NO @@ -256,7 +258,8 @@ [FormSuggestion suggestionWithValue:kTestFieldValue displayDescription:nil icon:nil - identifier:0]; + identifier:0 + requiresReauth:NO]; CWVAutofillSuggestion* suggestion = [[CWVAutofillSuggestion alloc] initWithFormSuggestion:form_suggestion formName:kTestFormName
diff --git a/ios/web_view/internal/autofill/cwv_autofill_suggestion_unittest.mm b/ios/web_view/internal/autofill/cwv_autofill_suggestion_unittest.mm index eb9e0424..9a65f15 100644 --- a/ios/web_view/internal/autofill/cwv_autofill_suggestion_unittest.mm +++ b/ios/web_view/internal/autofill/cwv_autofill_suggestion_unittest.mm
@@ -28,7 +28,8 @@ [FormSuggestion suggestionWithValue:@"TestValue" displayDescription:@"TestDisplayDescription" icon:@"TestIcon" - identifier:1337]; + identifier:1337 + requiresReauth:NO]; CWVAutofillSuggestion* suggestion = [[CWVAutofillSuggestion alloc] initWithFormSuggestion:formSuggestion formName:formName
diff --git a/media/DEPS b/media/DEPS index dd77d6b7..2c54e647 100644 --- a/media/DEPS +++ b/media/DEPS
@@ -20,6 +20,7 @@ "+third_party/libyuv", "+third_party/opus", "+third_party/skia", + "+ui/base/ui_base_features.h", "+ui/display", "+ui/events", "+ui/gfx",
diff --git a/media/base/BUILD.gn b/media/base/BUILD.gn index 325a678..8d281dd 100644 --- a/media/base/BUILD.gn +++ b/media/base/BUILD.gn
@@ -383,6 +383,7 @@ if (use_x11) { sources += [ "user_input_monitor_linux.cc" ] deps += [ + "//ui/base:features", "//ui/events:events_base", "//ui/events/devices/x11", "//ui/gfx/x",
diff --git a/media/base/user_input_monitor_linux.cc b/media/base/user_input_monitor_linux.cc index 2484b834..397bae2 100644 --- a/media/base/user_input_monitor_linux.cc +++ b/media/base/user_input_monitor_linux.cc
@@ -21,6 +21,7 @@ #include "base/task/current_thread.h" #include "media/base/keyboard_event_counter.h" #include "third_party/skia/include/core/SkPoint.h" +#include "ui/base/ui_base_features.h" #include "ui/events/devices/x11/xinput_util.h" #include "ui/events/keycodes/keyboard_code_conversion_x.h" #include "ui/gfx/x/x11.h" @@ -139,6 +140,14 @@ void UserInputMonitorLinuxCore::StartMonitor() { DCHECK(io_task_runner_->BelongsToCurrentThread()); + // TODO(https://crbug.com/1116414): support UserInputMonitorLinux on + // Ozone/Linux. + if (features::IsUsingOzonePlatform()) { + NOTIMPLEMENTED_LOG_ONCE(); + StopMonitor(); + return; + } + if (!connection_) { // TODO(jamiewalch): We should pass the connection in. if (auto* connection = x11::Connection::Get()) {
diff --git a/mojo/public/tools/bindings/generators/cpp_tracing_support.py b/mojo/public/tools/bindings/generators/cpp_tracing_support.py index 9ce7b5de..75acc489 100644 --- a/mojo/public/tools/bindings/generators/cpp_tracing_support.py +++ b/mojo/public/tools/bindings/generators/cpp_tracing_support.py
@@ -362,6 +362,15 @@ for line in _WrapIfNullable(loop_generator): yield line return + if (mojom.IsAnyHandleOrInterfaceKind(kind) + and not mojom.IsAssociatedInterfaceRequestKind(kind)): + yield output_context.AddSingleValue('Boolean', + cpp_parameter_name + '.is_valid()') + return + if mojom.IsAssociatedInterfaceRequestKind(kind): + yield output_context.AddSingleValue('Boolean', + cpp_parameter_name + '.is_pending()') + return yield output_context.AddSingleValue('String', _TraceEventToString())
diff --git a/services/network/public/cpp/http_request_headers_mojom_traits.cc b/services/network/public/cpp/http_request_headers_mojom_traits.cc index 66bedc183..1fb302c 100644 --- a/services/network/public/cpp/http_request_headers_mojom_traits.cc +++ b/services/network/public/cpp/http_request_headers_mojom_traits.cc
@@ -4,12 +4,25 @@ #include "services/network/public/cpp/http_request_headers_mojom_traits.h" +#include "base/debug/dump_without_crashing.h" #include "net/http/http_util.h" #include "services/network/public/cpp/crash_keys.h" namespace mojo { // static +const std::string& +StructTraits<network::mojom::HttpRequestHeaderKeyValuePairDataView, + net::HttpRequestHeaders::HeaderKeyValuePair>:: + key(const net::HttpRequestHeaders::HeaderKeyValuePair& item) { + if (!net::HttpUtil::IsValidHeaderName(item.key)) { + // TODO(crbug.com/1028189): Adding temporarily to debug crbug.com/1028189. + base::debug::DumpWithoutCrashing(); + } + return item.key; +} + +// static bool StructTraits<network::mojom::HttpRequestHeaderKeyValuePairDataView, net::HttpRequestHeaders::HeaderKeyValuePair>:: Read(network::mojom::HttpRequestHeaderKeyValuePairDataView data,
diff --git a/services/network/public/cpp/http_request_headers_mojom_traits.h b/services/network/public/cpp/http_request_headers_mojom_traits.h index 1bb267f4..fe643a3 100644 --- a/services/network/public/cpp/http_request_headers_mojom_traits.h +++ b/services/network/public/cpp/http_request_headers_mojom_traits.h
@@ -16,9 +16,7 @@ StructTraits<network::mojom::HttpRequestHeaderKeyValuePairDataView, net::HttpRequestHeaders::HeaderKeyValuePair> { static const std::string& key( - const net::HttpRequestHeaders::HeaderKeyValuePair& item) { - return item.key; - } + const net::HttpRequestHeaders::HeaderKeyValuePair& item); static const std::string& value( const net::HttpRequestHeaders::HeaderKeyValuePair& item) { return item.value;
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json index 33b74d3..fcf9097 100644 --- a/testing/buildbot/chromium.android.fyi.json +++ b/testing/buildbot/chromium.android.fyi.json
@@ -33,377 +33,6 @@ } ] }, - "Android WebView P Blink-CORS FYI (rel)": { - "gtest_tests": [ - { - "args": [ - "--disable-features=OutOfBlinkCors", - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "android_webview_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "device_os": "PQ3A.190801.002", - "device_os_flavor": "google", - "device_os_type": "userdebug", - "device_type": "walleye", - "os": "Android" - } - ], - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "android_webview_unittests", - "test_id_prefix": "ninja://android_webview/test:android_webview_unittests/" - }, - { - "args": [ - "--disable-features=OutOfBlinkCors", - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "system_webview_shell_layout_test_apk" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "device_os": "PQ3A.190801.002", - "device_os_flavor": "google", - "device_os_type": "userdebug", - "device_type": "walleye", - "os": "Android" - } - ], - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "system_webview_shell_layout_test_apk", - "test_id_prefix": "ninja://android_webview/tools/system_webview_shell:system_webview_shell_layout_test_apk/" - }, - { - "args": [ - "--disable-features=OutOfBlinkCors", - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "webview_cts_tests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "chromium/android_webview/tools/cts_archive", - "location": "android_webview/tools/cts_archive", - "revision": "Zmi8uHgTaLXGm9f8Fu_0U-Xa6BljyNjsyL0Nq7VouKoC" - }, - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "device_os": "PQ3A.190801.002", - "device_os_flavor": "google", - "device_os_type": "userdebug", - "device_type": "walleye", - "os": "Android" - } - ], - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 2 - }, - "test": "webview_cts_tests", - "test_id_prefix": "ninja://android_webview/test:webview_cts_tests/" - }, - { - "args": [ - "--disable-field-trial-config", - "--disable-features=OutOfBlinkCors", - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "webview_cts_tests_no_field_trial" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "webview_cts_tests_no_field_trial", - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "chromium/android_webview/tools/cts_archive", - "location": "android_webview/tools/cts_archive", - "revision": "Zmi8uHgTaLXGm9f8Fu_0U-Xa6BljyNjsyL0Nq7VouKoC" - }, - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "device_os": "PQ3A.190801.002", - "device_os_flavor": "google", - "device_os_type": "userdebug", - "device_type": "walleye", - "os": "Android" - } - ], - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 2 - }, - "test": "webview_cts_tests", - "test_id_prefix": "ninja://android_webview/test:webview_cts_tests/" - }, - { - "args": [ - "--disable-features=OutOfBlinkCors", - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "webview_instrumentation_test_apk" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "device_os": "PQ3A.190801.002", - "device_os_flavor": "google", - "device_os_type": "userdebug", - "device_type": "walleye", - "os": "Android" - } - ], - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 12 - }, - "test": "webview_instrumentation_test_apk", - "test_id_prefix": "ninja://android_webview/test:webview_instrumentation_test_apk/" - }, - { - "args": [ - "--disable-features=OutOfBlinkCors", - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "webview_ui_test_app_test_apk" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "device_os": "PQ3A.190801.002", - "device_os_flavor": "google", - "device_os_type": "userdebug", - "device_type": "walleye", - "os": "Android" - } - ], - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "webview_ui_test_app_test_apk", - "test_id_prefix": "ninja://android_webview/tools/automated_ui_tests:webview_ui_test_app_test_apk/" - } - ], - "isolated_scripts": [ - { - "args": [ - "--disable-features=OutOfBlinkCors" - ], - "isolate_name": "chrome_public_wpt", - "merge": { - "args": [ - "--verbose" - ], - "script": "//third_party/blink/tools/merge_web_test_results.py" - }, - "name": "chrome_public_wpt", - "results_handler": "layout tests", - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "device_os": "PQ3A.190801.002", - "device_os_flavor": "google", - "device_os_type": "userdebug", - "device_type": "walleye", - "os": "Android" - } - ], - "expiration": 18000, - "hard_timeout": 14400, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 15 - }, - "test_id_prefix": "ninja://chrome/android:chrome_public_wpt/" - }, - { - "args": [ - "--disable-features=OutOfBlinkCors" - ], - "isolate_name": "system_webview_wpt", - "merge": { - "args": [ - "--verbose" - ], - "script": "//third_party/blink/tools/merge_web_test_results.py" - }, - "name": "system_webview_wpt", - "results_handler": "layout tests", - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "device_os": "PQ3A.190801.002", - "device_os_flavor": "google", - "device_os_type": "userdebug", - "device_type": "walleye", - "os": "Android" - } - ], - "expiration": 18000, - "hard_timeout": 14400, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 15 - }, - "test_id_prefix": "ninja://android_webview/test:system_webview_wpt/" - } - ] - }, "Android WebView P FYI (rel)": { "gtest_tests": [ {
diff --git a/testing/buildbot/chromium.ci.json b/testing/buildbot/chromium.ci.json index 564332e..de9105a8 100644 --- a/testing/buildbot/chromium.ci.json +++ b/testing/buildbot/chromium.ci.json
@@ -12788,377 +12788,6 @@ } ] }, - "Android WebView P Blink-CORS FYI (rel)": { - "gtest_tests": [ - { - "args": [ - "--disable-features=OutOfBlinkCors", - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "android_webview_unittests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "device_os": "PQ3A.190801.002", - "device_os_flavor": "google", - "device_os_type": "userdebug", - "device_type": "walleye", - "os": "Android" - } - ], - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "android_webview_unittests", - "test_id_prefix": "ninja://android_webview/test:android_webview_unittests/" - }, - { - "args": [ - "--disable-features=OutOfBlinkCors", - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "system_webview_shell_layout_test_apk" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "device_os": "PQ3A.190801.002", - "device_os_flavor": "google", - "device_os_type": "userdebug", - "device_type": "walleye", - "os": "Android" - } - ], - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "system_webview_shell_layout_test_apk", - "test_id_prefix": "ninja://android_webview/tools/system_webview_shell:system_webview_shell_layout_test_apk/" - }, - { - "args": [ - "--disable-features=OutOfBlinkCors", - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "webview_cts_tests" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "chromium/android_webview/tools/cts_archive", - "location": "android_webview/tools/cts_archive", - "revision": "Zmi8uHgTaLXGm9f8Fu_0U-Xa6BljyNjsyL0Nq7VouKoC" - }, - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "device_os": "PQ3A.190801.002", - "device_os_flavor": "google", - "device_os_type": "userdebug", - "device_type": "walleye", - "os": "Android" - } - ], - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 2 - }, - "test": "webview_cts_tests", - "test_id_prefix": "ninja://android_webview/test:webview_cts_tests/" - }, - { - "args": [ - "--disable-field-trial-config", - "--disable-features=OutOfBlinkCors", - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "webview_cts_tests_no_field_trial" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "webview_cts_tests_no_field_trial", - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "chromium/android_webview/tools/cts_archive", - "location": "android_webview/tools/cts_archive", - "revision": "Zmi8uHgTaLXGm9f8Fu_0U-Xa6BljyNjsyL0Nq7VouKoC" - }, - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "device_os": "PQ3A.190801.002", - "device_os_flavor": "google", - "device_os_type": "userdebug", - "device_type": "walleye", - "os": "Android" - } - ], - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 2 - }, - "test": "webview_cts_tests", - "test_id_prefix": "ninja://android_webview/test:webview_cts_tests/" - }, - { - "args": [ - "--disable-features=OutOfBlinkCors", - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "webview_instrumentation_test_apk" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "device_os": "PQ3A.190801.002", - "device_os_flavor": "google", - "device_os_type": "userdebug", - "device_type": "walleye", - "os": "Android" - } - ], - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 12 - }, - "test": "webview_instrumentation_test_apk", - "test_id_prefix": "ninja://android_webview/test:webview_instrumentation_test_apk/" - }, - { - "args": [ - "--disable-features=OutOfBlinkCors", - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "webview_ui_test_app_test_apk" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "device_os": "PQ3A.190801.002", - "device_os_flavor": "google", - "device_os_type": "userdebug", - "device_type": "walleye", - "os": "Android" - } - ], - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "webview_ui_test_app_test_apk", - "test_id_prefix": "ninja://android_webview/tools/automated_ui_tests:webview_ui_test_app_test_apk/" - } - ], - "isolated_scripts": [ - { - "args": [ - "--disable-features=OutOfBlinkCors" - ], - "isolate_name": "chrome_public_wpt", - "merge": { - "args": [ - "--verbose" - ], - "script": "//third_party/blink/tools/merge_web_test_results.py" - }, - "name": "chrome_public_wpt", - "results_handler": "layout tests", - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "device_os": "PQ3A.190801.002", - "device_os_flavor": "google", - "device_os_type": "userdebug", - "device_type": "walleye", - "os": "Android" - } - ], - "expiration": 18000, - "hard_timeout": 14400, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 15 - }, - "test_id_prefix": "ninja://chrome/android:chrome_public_wpt/" - }, - { - "args": [ - "--disable-features=OutOfBlinkCors" - ], - "isolate_name": "system_webview_wpt", - "merge": { - "args": [ - "--verbose" - ], - "script": "//third_party/blink/tools/merge_web_test_results.py" - }, - "name": "system_webview_wpt", - "results_handler": "layout tests", - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "device_os": "PQ3A.190801.002", - "device_os_flavor": "google", - "device_os_type": "userdebug", - "device_type": "walleye", - "os": "Android" - } - ], - "expiration": 18000, - "hard_timeout": 14400, - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 15 - }, - "test_id_prefix": "ninja://android_webview/test:system_webview_wpt/" - } - ] - }, "Android WebView P FYI (rel)": { "gtest_tests": [ { @@ -243245,187 +242874,6 @@ } ] }, - "linux-blink-cors-rel": { - "gtest_tests": [ - { - "args": [ - "--disable-features=OutOfBlinkCors" - ], - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" - }, - "name": "blink_cors_blink_platform_unittests", - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "os": "Ubuntu-16.04" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "blink_platform_unittests", - "test_id_prefix": "ninja://third_party/blink/renderer/platform:blink_platform_unittests/" - }, - { - "args": [ - "--disable-features=OutOfBlinkCors" - ], - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" - }, - "name": "blink_cors_browser_tests", - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "os": "Ubuntu-16.04" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 10 - }, - "test": "browser_tests", - "test_id_prefix": "ninja://chrome/test:browser_tests/" - }, - { - "args": [ - "--disable-features=OutOfBlinkCors" - ], - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" - }, - "name": "blink_cors_content_browsertests", - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "os": "Ubuntu-16.04" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "content_browsertests", - "test_id_prefix": "ninja://content/test:content_browsertests/" - }, - { - "args": [ - "--disable-features=OutOfBlinkCors" - ], - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" - }, - "name": "blink_cors_content_unittests", - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "os": "Ubuntu-16.04" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "content_unittests", - "test_id_prefix": "ninja://content/test:content_unittests/" - }, - { - "args": [ - "--disable-features=OutOfBlinkCors" - ], - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" - }, - "name": "blink_cors_extensions_browsertests", - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "os": "Ubuntu-16.04" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "extensions_browsertests", - "test_id_prefix": "ninja://extensions:extensions_browsertests/" - }, - { - "args": [ - "--disable-features=OutOfBlinkCors" - ], - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" - }, - "name": "blink_cors_extensions_unittests", - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "os": "Ubuntu-16.04" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "extensions_unittests", - "test_id_prefix": "ninja://extensions:extensions_unittests/" - }, - { - "args": [ - "--disable-features=OutOfBlinkCors" - ], - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" - }, - "name": "blink_cors_services_unittests", - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "os": "Ubuntu-16.04" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "services_unittests", - "test_id_prefix": "ninja://services:services_unittests/" - } - ], - "isolated_scripts": [ - { - "args": [ - "--num-retries=3", - "--additional-driver-flag=--disable-features=OutOfBlinkCors", - "--additional-expectations=../../third_party/blink/web_tests/FlagExpectations/disable-features=OutOfBlinkCors" - ], - "isolate_name": "blink_web_tests", - "merge": { - "args": [ - "--verbose" - ], - "script": "//third_party/blink/tools/merge_web_test_results.py" - }, - "name": "blink_web_tests", - "results_handler": "layout tests", - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "os": "Ubuntu-16.04" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 12 - }, - "test_id_prefix": "ninja://:blink_web_tests/" - } - ] - }, "linux-blink-heap-concurrent-marking-tsan-rel": { "gtest_tests": [ {
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json index fdcf6bd..e6c30e4 100644 --- a/testing/buildbot/chromium.linux.json +++ b/testing/buildbot/chromium.linux.json
@@ -9042,187 +9042,6 @@ } ] }, - "linux-blink-cors-rel": { - "gtest_tests": [ - { - "args": [ - "--disable-features=OutOfBlinkCors" - ], - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" - }, - "name": "blink_cors_blink_platform_unittests", - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "os": "Ubuntu-16.04" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "blink_platform_unittests", - "test_id_prefix": "ninja://third_party/blink/renderer/platform:blink_platform_unittests/" - }, - { - "args": [ - "--disable-features=OutOfBlinkCors" - ], - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" - }, - "name": "blink_cors_browser_tests", - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "os": "Ubuntu-16.04" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 10 - }, - "test": "browser_tests", - "test_id_prefix": "ninja://chrome/test:browser_tests/" - }, - { - "args": [ - "--disable-features=OutOfBlinkCors" - ], - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" - }, - "name": "blink_cors_content_browsertests", - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "os": "Ubuntu-16.04" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "content_browsertests", - "test_id_prefix": "ninja://content/test:content_browsertests/" - }, - { - "args": [ - "--disable-features=OutOfBlinkCors" - ], - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" - }, - "name": "blink_cors_content_unittests", - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "os": "Ubuntu-16.04" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "content_unittests", - "test_id_prefix": "ninja://content/test:content_unittests/" - }, - { - "args": [ - "--disable-features=OutOfBlinkCors" - ], - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" - }, - "name": "blink_cors_extensions_browsertests", - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "os": "Ubuntu-16.04" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "extensions_browsertests", - "test_id_prefix": "ninja://extensions:extensions_browsertests/" - }, - { - "args": [ - "--disable-features=OutOfBlinkCors" - ], - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" - }, - "name": "blink_cors_extensions_unittests", - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "os": "Ubuntu-16.04" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "extensions_unittests", - "test_id_prefix": "ninja://extensions:extensions_unittests/" - }, - { - "args": [ - "--disable-features=OutOfBlinkCors" - ], - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" - }, - "name": "blink_cors_services_unittests", - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "os": "Ubuntu-16.04" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "services_unittests", - "test_id_prefix": "ninja://services:services_unittests/" - } - ], - "isolated_scripts": [ - { - "args": [ - "--num-retries=3", - "--additional-driver-flag=--disable-features=OutOfBlinkCors", - "--additional-expectations=../../third_party/blink/web_tests/FlagExpectations/disable-features=OutOfBlinkCors" - ], - "isolate_name": "blink_web_tests", - "merge": { - "args": [ - "--verbose" - ], - "script": "//third_party/blink/tools/merge_web_test_results.py" - }, - "name": "blink_web_tests", - "results_handler": "layout tests", - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "os": "Ubuntu-16.04" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 12 - }, - "test_id_prefix": "ninja://:blink_web_tests/" - } - ] - }, "linux-gcc-rel": { "additional_compile_targets": [ "empty_main"
diff --git a/testing/buildbot/filters/gpu.skiarenderer_vulkan_content_browsertests.filter b/testing/buildbot/filters/gpu.skiarenderer_vulkan_content_browsertests.filter index 0778fa6d5..268d5d2 100644 --- a/testing/buildbot/filters/gpu.skiarenderer_vulkan_content_browsertests.filter +++ b/testing/buildbot/filters/gpu.skiarenderer_vulkan_content_browsertests.filter
@@ -1 +1,4 @@ -# TODO(jonross): Remove once Finch completes. \ No newline at end of file +# TODO(jonross): Remove once Finch completes. + +# Consistent Timeout. https://crbug.com/1116577 +-BackForwardCacheBrowserTest.ReplacedNavigationEntry \ No newline at end of file
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl index c07d2cdc..1f399fa 100644 --- a/testing/buildbot/test_suite_exceptions.pyl +++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -346,12 +346,6 @@ '--debug', ], }, - 'linux-blink-cors-rel': { - 'args': [ - '--additional-driver-flag=--disable-features=OutOfBlinkCors', - '--additional-expectations=../../third_party/blink/web_tests/FlagExpectations/disable-features=OutOfBlinkCors', - ], - }, 'linux-blink-heap-concurrent-marking-tsan-rel': { 'args': [ '--release',
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl index d8a2c2b7..0e8c373 100644 --- a/testing/buildbot/test_suites.pyl +++ b/testing/buildbot/test_suites.pyl
@@ -363,54 +363,6 @@ }, }, - 'blink_cors_gtests': { - 'blink_cors_blink_platform_unittests': { - 'args': [ - '--disable-features=OutOfBlinkCors' - ], - 'test': 'blink_platform_unittests' - }, - 'blink_cors_browser_tests': { - 'args': [ - '--disable-features=OutOfBlinkCors' - ], - 'swarming': { - 'shards': 10, - }, - 'test': 'browser_tests' - }, - 'blink_cors_content_browsertests': { - 'args': [ - '--disable-features=OutOfBlinkCors' - ], - 'test': 'content_browsertests' - }, - 'blink_cors_content_unittests' : { - 'args': [ - '--disable-features=OutOfBlinkCors' - ], - 'test': 'content_unittests' - }, - 'blink_cors_extensions_browsertests': { - 'args': [ - '--disable-features=OutOfBlinkCors' - ], - 'test': 'extensions_browsertests' - }, - 'blink_cors_extensions_unittests': { - 'args': [ - '--disable-features=OutOfBlinkCors' - ], - 'test': 'extensions_unittests' - }, - 'blink_cors_services_unittests': { - 'args': [ - '--disable-features=OutOfBlinkCors' - ], - 'test': 'services_unittests' - } - }, - 'cast_audio_specific_chromium_gtests': { 'cast_audio_backend_unittests': {}, 'cast_base_unittests': {}, @@ -5458,15 +5410,6 @@ 'webview_ui_instrumentation_tests_no_field_trial', ], - 'webview_bot_blink_cors_gtests': [ - 'system_webview_shell_instrumentation_tests', - 'webview_bot_instrumentation_test_apk_gtest', - 'webview_bot_unittests_gtest', - 'webview_cts_tests_gtest', - 'webview_cts_tests_gtest_no_field_trial', - 'webview_ui_instrumentation_tests', - ], - 'webview_bot_system_gtests': [ 'system_webview_shell_instrumentation_tests', 'webview_cts_tests_gtest',
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl index e596d4c..d22bee3 100644 --- a/testing/buildbot/waterfalls.pyl +++ b/testing/buildbot/waterfalls.pyl
@@ -804,21 +804,6 @@ 'use_swarming': True, 'os_type': 'android', }, - 'Android WebView P Blink-CORS FYI (rel)': { - 'mixins': [ - 'pie_fleet', - 'walleye', - ], - 'test_suites': { - 'gtest_tests': 'webview_bot_blink_cors_gtests', - 'isolated_scripts': 'android_wpt_scripts', - }, - 'args': [ - '--disable-features=OutOfBlinkCors', - ], - 'use_swarming': True, - 'os_type': 'android', - }, 'Android WebView P FYI (rel)': { 'mixins': [ 'pie_fleet', @@ -4243,15 +4228,6 @@ 'isolated_scripts': 'chromium_webkit_isolated_scripts', }, }, - 'linux-blink-cors-rel': { - 'mixins': [ - 'linux-xenial', - ], - 'test_suites': { - 'gtest_tests': 'blink_cors_gtests', - 'isolated_scripts': 'chromium_webkit_isolated_scripts', - }, - }, 'linux-gcc-rel': { 'additional_compile_targets': [ 'empty_main',
diff --git a/third_party/android_deps/BUILD.gn b/third_party/android_deps/BUILD.gn index 04bd5cb..60f9847 100644 --- a/third_party/android_deps/BUILD.gn +++ b/third_party/android_deps/BUILD.gn
@@ -802,6 +802,16 @@ } # This is generated, do not edit. Update BuildConfigGenerator.groovy instead. +android_aar_prebuilt("androidx_window_window_java") { + aar_path = "libs/androidx_window_window/window-1.0.0-alpha01.aar" + info_path = "libs/androidx_window_window/androidx_window_window.info" + deps = [ + ":androidx_annotation_annotation_java", + ":androidx_core_core_java", + ] +} + +# This is generated, do not edit. Update BuildConfigGenerator.groovy instead. android_aar_prebuilt("com_android_support_appcompat_v7_java") { aar_path = "libs/com_android_support_appcompat_v7/appcompat-v7-28.0.0.aar" info_path = "libs/com_android_support_appcompat_v7/com_android_support_appcompat_v7.info"
diff --git a/third_party/android_deps/additional_readme_paths.json b/third_party/android_deps/additional_readme_paths.json index d3d975a..7460b3a 100644 --- a/third_party/android_deps/additional_readme_paths.json +++ b/third_party/android_deps/additional_readme_paths.json
@@ -75,6 +75,7 @@ "libs/androidx_viewpager2_viewpager2", "libs/androidx_viewpager_viewpager", "libs/androidx_webkit_webkit", + "libs/androidx_window_window", "libs/backport_util_concurrent_backport_util_concurrent", "libs/classworlds_classworlds", "libs/com_android_support_animated_vector_drawable",
diff --git a/third_party/android_deps/build.gradle b/third_party/android_deps/build.gradle index 6580db6d..7c0a148 100644 --- a/third_party/android_deps/build.gradle +++ b/third_party/android_deps/build.gradle
@@ -28,6 +28,13 @@ // Any known vulnerability of any severity will cause the build to fail. failBuildOnCVSS = 0 suppressionFile = file("vulnerability_supressions.xml") + // Libraries used in these configurations aren't shipped in Chrome. + // They are only used to aid in compiling or testing. + skipConfigurations = [ + "buildCompile", + "androidTestCompile", + "testCompile" + ] } dependencies { @@ -75,6 +82,7 @@ compile "androidx.vectordrawable:vectordrawable-animated:${androidXSupportLibVersion}" compile "androidx.tvprovider:tvprovider:${androidXSupportLibVersion}" compile "androidx.viewpager:viewpager:${androidXSupportLibVersion}" + compile "androidx.window:window:1.0.0-alpha01" compile "androidx.exifinterface:exifinterface:${androidXSupportLibVersion}" // Those are for use by doubledown material design
diff --git a/third_party/android_deps/libs/androidx_window_window/LICENSE b/third_party/android_deps/libs/androidx_window_window/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/third_party/android_deps/libs/androidx_window_window/LICENSE
@@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.
diff --git a/third_party/android_deps/libs/androidx_window_window/OWNERS b/third_party/android_deps/libs/androidx_window_window/OWNERS new file mode 100644 index 0000000..7b571d97 --- /dev/null +++ b/third_party/android_deps/libs/androidx_window_window/OWNERS
@@ -0,0 +1 @@ +file://third_party/android_deps/OWNERS \ No newline at end of file
diff --git a/third_party/android_deps/libs/androidx_window_window/README.chromium b/third_party/android_deps/libs/androidx_window_window/README.chromium new file mode 100644 index 0000000..ad9fa23 --- /dev/null +++ b/third_party/android_deps/libs/androidx_window_window/README.chromium
@@ -0,0 +1,13 @@ +Name: Jetpack WindowManager Library +Short Name: window +URL: https://developer.android.com/jetpack/androidx +Version: 1.0.0-alpha01 +License: Apache Version 2.0 +License File: LICENSE +Security Critical: yes + +Description: +WindowManager Jetpack library. Currently only provides additional functionality on foldable devices. + +Local Modifications: +No modifications.
diff --git a/third_party/android_deps/libs/androidx_window_window/androidx_window_window.info b/third_party/android_deps/libs/androidx_window_window/androidx_window_window.info new file mode 100644 index 0000000..b78d569 --- /dev/null +++ b/third_party/android_deps/libs/androidx_window_window/androidx_window_window.info
@@ -0,0 +1,14 @@ +# Generated by //build/android/gyp/aar.py +# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen". + +aidl = [] +assets = [] +has_classes_jar = true +has_native_libraries = false +has_proguard_flags = false +has_r_text_file = false +is_manifest_empty = false +manifest_package = "androidx.window" +resources = [] +subjar_tuples = [] +subjars = []
diff --git a/third_party/android_deps/libs/androidx_window_window/cipd.yaml b/third_party/android_deps/libs/androidx_window_window/cipd.yaml new file mode 100644 index 0000000..f71998c --- /dev/null +++ b/third_party/android_deps/libs/androidx_window_window/cipd.yaml
@@ -0,0 +1,10 @@ +# Copyright 2018 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# To create CIPD package run the following command. +# cipd create --pkg-def cipd.yaml -tag version:1.0.0-alpha01-cr0 +package: chromium/third_party/android_deps/libs/androidx_window_window +description: "Jetpack WindowManager Library" +data: +- file: window-1.0.0-alpha01.aar
diff --git a/third_party/blink/public/mojom/web_feature/web_feature.mojom b/third_party/blink/public/mojom/web_feature/web_feature.mojom index 5055655..82ffb7d1 100644 --- a/third_party/blink/public/mojom/web_feature/web_feature.mojom +++ b/third_party/blink/public/mojom/web_feature/web_feature.mojom
@@ -2735,6 +2735,8 @@ kGPUAdapter_Name = 3405, kWindowScreenInternal = 3406, kWindowScreenPrimary = 3407, + kThirdPartyCookieRead = 3408, + kThirdPartyCookieWrite = 3409, // Add new features immediately above this line. Don't change assigned // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc b/third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc index feda0b5..942e6bb 100644 --- a/third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc +++ b/third_party/blink/renderer/bindings/core/v8/v8_script_runner.cc
@@ -334,7 +334,7 @@ if (GetMicrotasksScopeDepth(isolate, microtask_queue) > kMaxRecursionDepth) return ThrowStackOverflowExceptionIfNeeded(isolate, microtask_queue); - CHECK(!context->ContextLifecycleObserverSet().IsIteratingOverObservers()); + CHECK(!context->ContextLifecycleObserverList().IsIteratingOverObservers()); // Run the script and keep track of the current recursion depth. v8::MaybeLocal<v8::Value> result; @@ -472,7 +472,7 @@ if (depth >= kMaxRecursionDepth) return ThrowStackOverflowExceptionIfNeeded(isolate, microtask_queue); - CHECK(!context->ContextLifecycleObserverSet().IsIteratingOverObservers()); + CHECK(!context->ContextLifecycleObserverList().IsIteratingOverObservers()); if (ScriptForbiddenScope::IsScriptForbidden()) { ThrowScriptForbiddenException(isolate); @@ -525,7 +525,7 @@ if (depth >= kMaxRecursionDepth) return ThrowStackOverflowExceptionIfNeeded(isolate, microtask_queue); - CHECK(!context->ContextLifecycleObserverSet().IsIteratingOverObservers()); + CHECK(!context->ContextLifecycleObserverList().IsIteratingOverObservers()); if (ScriptForbiddenScope::IsScriptForbidden()) { ThrowScriptForbiddenException(isolate);
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_utils.py b/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_utils.py index acf1a92..b7ddd14 100644 --- a/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_utils.py +++ b/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_utils.py
@@ -20,7 +20,10 @@ return LiteralNode("""\ // Copyright 2019 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file.\ +// found in the LICENSE file. + +// DO NOT EDIT: This file is auto-generated by +// //third_party/blink/renderer/bindings/scripts/generate_bindings.py\ """)
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context.cc b/third_party/blink/renderer/core/display_lock/display_lock_context.cc index 63c9b5df..619799ae 100644 --- a/third_party/blink/renderer/core/display_lock/display_lock_context.cc +++ b/third_party/blink/renderer/core/display_lock/display_lock_context.cc
@@ -109,6 +109,7 @@ break; case EContentVisibility::kAuto: UseCounter::Count(document_, WebFeature::kContentVisibilityAuto); + had_any_viewport_intersection_notifications_ = false; RequestLock(static_cast<uint16_t>(DisplayLockActivationReason::kAny)); break; case EContentVisibility::kHidden: @@ -439,6 +440,7 @@ } void DisplayLockContext::NotifyIsIntersectingViewport() { + had_any_viewport_intersection_notifications_ = true; // If we are now intersecting, then we are definitely not nested in a locked // subtree and we don't need to lock as a result. needs_deferred_not_intersecting_signal_ = false; @@ -451,6 +453,8 @@ } void DisplayLockContext::NotifyIsNotIntersectingViewport() { + had_any_viewport_intersection_notifications_ = true; + if (IsLocked()) { DCHECK(!needs_deferred_not_intersecting_signal_); return;
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context.h b/third_party/blink/renderer/core/display_lock/display_lock_context.h index baa3223..a35bc9af 100644 --- a/third_party/blink/renderer/core/display_lock/display_lock_context.h +++ b/third_party/blink/renderer/core/display_lock/display_lock_context.h
@@ -200,6 +200,10 @@ } } + bool HadAnyViewportIntersectionNotifications() const { + return had_any_viewport_intersection_notifications_; + } + // GC functions. void Trace(Visitor*) const override; @@ -370,6 +374,11 @@ bool needs_graphics_layer_rebuild_ = false; + // This is set to true if we're in the 'auto' mode and had our first + // intersection / non-intersection notification. This is reset to false if the + // 'auto' mode is added again (after being removed). + bool had_any_viewport_intersection_notifications_ = false; + enum class RenderAffectingState : int { kLockRequested, kIntersectsViewport,
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc b/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc index 5b112f9..32881b1 100644 --- a/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc +++ b/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
@@ -24,6 +24,7 @@ #include "third_party/blink/renderer/core/frame/find_in_page.h" #include "third_party/blink/renderer/core/frame/frame_test_helpers.h" #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h" +#include "third_party/blink/renderer/core/geometry/dom_rect.h" #include "third_party/blink/renderer/core/html/html_template_element.h" #include "third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h" #include "third_party/blink/renderer/core/paint/paint_layer.h" @@ -2099,7 +2100,7 @@ EXPECT_EQ(total_count, 10u); GetDocument().getElementById("e")->setAttribute(html_names::kStyleAttr, - "content-visibility: auto"); + "content-visibility: hidden"); UpdateAllLifecyclePhasesForTest(); // Note that the dirty_all call propagate the dirty bit from the unlocked @@ -2115,7 +2116,7 @@ EXPECT_EQ(total_count, 8u); GetDocument().getElementById("a")->setAttribute(html_names::kStyleAttr, - "content-visibility: auto"); + "content-visibility: hidden"); UpdateAllLifecyclePhasesForTest(); // Note that this dirty_all call is now not propagating the dirty bits at all, @@ -2283,19 +2284,8 @@ auto* unrelated_element = GetDocument().getElementById("unrelated"); auto* outer_element = GetDocument().getElementById("outer"); - // Ensure that the visibility switch happens. - RunStartOfLifecycleTasks(); - - // Now that the intersection observer notifications switch the visibility of - // the context, we expect to see dirty layout bits to be propagated. - EXPECT_TRUE(outer_element->GetLayoutObject()->NeedsLayout()); - EXPECT_FALSE(outer_element->GetLayoutObject()->SelfNeedsLayout()); - EXPECT_TRUE(unrelated_element->GetLayoutObject()->NeedsLayout()); - EXPECT_FALSE(unrelated_element->GetLayoutObject()->SelfNeedsLayout()); - EXPECT_TRUE(inner_element->GetLayoutObject()->NeedsLayout()); - EXPECT_FALSE(inner_element->GetLayoutObject()->SelfNeedsLayout()); - - // Clear the layout. + // Ensure that the visibility switch happens. This would also clear the + // layout. UpdateAllLifecyclePhasesForTest(); EXPECT_FALSE(outer_element->GetLayoutObject()->NeedsLayout()); EXPECT_FALSE(outer_element->GetLayoutObject()->SelfNeedsLayout()); @@ -2414,19 +2404,8 @@ auto* unrelated_element = GetDocument().getElementById("unrelated"); auto* outer_element = GetDocument().getElementById("outer"); - // Ensure that the visibility switch happens. - RunStartOfLifecycleTasks(); - - // Now that the intersection observer notifications switch the visibility of - // the context, we expect to see dirty layout bits to be propagated. - EXPECT_TRUE(outer_element->GetLayoutObject()->NeedsLayout()); - EXPECT_FALSE(outer_element->GetLayoutObject()->SelfNeedsLayout()); - EXPECT_TRUE(unrelated_element->GetLayoutObject()->NeedsLayout()); - EXPECT_FALSE(unrelated_element->GetLayoutObject()->SelfNeedsLayout()); - EXPECT_TRUE(inner_element->GetLayoutObject()->NeedsLayout()); - EXPECT_FALSE(inner_element->GetLayoutObject()->SelfNeedsLayout()); - - // Clear the layout. + // Ensure that the visibility switch happens. This would also clear the + // layout. UpdateAllLifecyclePhasesForTest(); EXPECT_FALSE(outer_element->GetLayoutObject()->NeedsLayout()); EXPECT_FALSE(outer_element->GetLayoutObject()->SelfNeedsLayout()); @@ -2990,6 +2969,43 @@ } } +TEST_F(DisplayLockContextRenderingTest, FirstAutoFramePaintsInViewport) { + SetHtmlInnerHTML(R"HTML( + <style> + .spacer { height: 10000px } + .auto { + content-visibility: auto; + contain-intrinsic-size: 1px 200px; + } + .auto > div { height: 100px } + </style> + + <div id=visible><div>content</div></div> + <div class=spacer></div> + <div id=hidden><div>content</div></div> + )HTML"); + + auto* visible = GetDocument().getElementById("visible"); + auto* hidden = GetDocument().getElementById("hidden"); + + visible->classList().Add("auto"); + hidden->classList().Add("auto"); + + UpdateAllLifecyclePhasesForTest(); + + EXPECT_FALSE(visible->GetDisplayLockContext()->IsLocked()); + EXPECT_TRUE(hidden->GetDisplayLockContext()->IsLocked()); + + EXPECT_FALSE(visible->GetLayoutObject()->SelfNeedsLayout()); + EXPECT_FALSE(hidden->GetLayoutObject()->SelfNeedsLayout()); + + auto* visible_rect = visible->getBoundingClientRect(); + auto* hidden_rect = hidden->getBoundingClientRect(); + + EXPECT_FLOAT_EQ(visible_rect->height(), 100); + EXPECT_FLOAT_EQ(hidden_rect->height(), 200); +} + class DisplayLockContextLegacyRenderingTest : public RenderingTest, private ScopedCSSContentVisibilityHiddenMatchableForTest,
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_document_state.cc b/third_party/blink/renderer/core/display_lock/display_lock_document_state.cc index 698424b..054d348 100644 --- a/third_party/blink/renderer/core/display_lock/display_lock_document_state.cc +++ b/third_party/blink/renderer/core/display_lock/display_lock_document_state.cc
@@ -82,10 +82,11 @@ IntersectionObserver& DisplayLockDocumentState::EnsureIntersectionObserver() { if (!intersection_observer_) { - // Use kDeliverDuringPostLifecycleSteps method, since we delay delivering - // the signal to the display lock context until the next frame's rAF - // callbacks have run. This means for the duration of the idle time that - // follows, we won't dirty layout. + // Use kDeliverDuringPostLayoutSteps method, since we will either notify the + // display lock synchronously and re-run layout, or delay delivering the + // signal to the display lock context until the next frame's rAF callbacks + // have run. This means for the duration of the idle time that follows, we + // should always have clean layout. // // Note that we use 50% margin (on the viewport) so that we get the // observation before the element enters the viewport. @@ -94,7 +95,7 @@ WTF::BindRepeating( &DisplayLockDocumentState::ProcessDisplayLockActivationObservation, WrapWeakPersistent(this)), - IntersectionObserver::kDeliverDuringPostLifecycleSteps, + IntersectionObserver::kDeliverDuringPostLayoutSteps, IntersectionObserver::kFractionOfTarget, 0 /* delay */, false /* track_visibility */, false /* always report_root_bounds */, IntersectionObserver::kApplyMarginToTarget); @@ -106,20 +107,46 @@ const HeapVector<Member<IntersectionObserverEntry>>& entries) { DCHECK(document_); DCHECK(document_->View()); + bool had_asynchronous_notifications = false; for (auto& entry : entries) { auto* context = entry->target()->GetDisplayLockContext(); DCHECK(context); - if (entry->isIntersecting()) { - document_->View()->EnqueueStartOfLifecycleTask( - WTF::Bind(&DisplayLockContext::NotifyIsIntersectingViewport, - WrapWeakPersistent(context))); + if (context->HadAnyViewportIntersectionNotifications()) { + if (entry->isIntersecting()) { + document_->View()->EnqueueStartOfLifecycleTask( + WTF::Bind(&DisplayLockContext::NotifyIsIntersectingViewport, + WrapWeakPersistent(context))); + } else { + document_->View()->EnqueueStartOfLifecycleTask( + WTF::Bind(&DisplayLockContext::NotifyIsNotIntersectingViewport, + WrapWeakPersistent(context))); + } + had_asynchronous_notifications = true; } else { - document_->View()->EnqueueStartOfLifecycleTask( - WTF::Bind(&DisplayLockContext::NotifyIsNotIntersectingViewport, - WrapWeakPersistent(context))); + if (entry->isIntersecting()) + context->NotifyIsIntersectingViewport(); + else + context->NotifyIsNotIntersectingViewport(); } } - document_->View()->ScheduleAnimation(); + + // If we had any asynchronous notifications, they would be delivered before + // the next lifecycle. Ensure to schedule a frame so that this process + // happens. + if (had_asynchronous_notifications) { + // Note that since we're processing this from within the lifecycle, post a + // task to schedule a new frame (direct call would be ignored inside a + // lifecycle). + document_->GetTaskRunner(TaskType::kInternalFrameLifecycleControl) + ->PostTask(FROM_HERE, + WTF::Bind(&DisplayLockDocumentState::ScheduleAnimation, + WrapWeakPersistent(this))); + } +} + +void DisplayLockDocumentState::ScheduleAnimation() { + if (document_ && document_->View()) + document_->View()->ScheduleAnimation(); } DisplayLockDocumentState::ScopedForceActivatableDisplayLocks
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_document_state.h b/third_party/blink/renderer/core/display_lock/display_lock_document_state.h index 161dee2..5a310b5 100644 --- a/third_party/blink/renderer/core/display_lock/display_lock_document_state.h +++ b/third_party/blink/renderer/core/display_lock/display_lock_document_state.h
@@ -134,6 +134,8 @@ void ForceLockIfNeededForInfo(Element*, ForcedNodeInfo*); + void ScheduleAnimation(); + Member<Document> document_; Member<IntersectionObserver> intersection_observer_ = nullptr;
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc index 33c232f..bf288e600 100644 --- a/third_party/blink/renderer/core/dom/document.cc +++ b/third_party/blink/renderer/core/dom/document.cc
@@ -3171,12 +3171,12 @@ GetFrame()->GetEventHandlerRegistry().DocumentDetached(*this); // Signal destruction to mutation observers. - synchronous_mutation_observer_set_.ForEachObserver( + synchronous_mutation_observer_list_.ForEachObserver( [](SynchronousMutationObserver* observer) { observer->ContextDestroyed(); - observer->ObserverSetWillBeCleared(); + observer->ObserverListWillBeCleared(); }); - synchronous_mutation_observer_set_.Clear(); + synchronous_mutation_observer_list_.Clear(); cookie_jar_ = nullptr; // Not accessible after navigated away. fetcher_->ClearContext(); @@ -5388,7 +5388,7 @@ for (Range* range : ranges) range->UpdateOwnerDocumentIfNeeded(); } - synchronous_mutation_observer_set_.ForEachObserver( + synchronous_mutation_observer_list_.ForEachObserver( [&](SynchronousMutationObserver* observer) { observer->DidMoveTreeToNewDocument(root); }); @@ -5407,7 +5407,7 @@ ni->NodeWillBeRemoved(n); } - synchronous_mutation_observer_set_.ForEachObserver( + synchronous_mutation_observer_list_.ForEachObserver( [&](SynchronousMutationObserver* observer) { observer->NodeChildrenWillBeRemoved(container); }); @@ -5428,7 +5428,7 @@ range->FixupRemovedNodeAcrossShadowBoundary(n); } - synchronous_mutation_observer_set_.ForEachObserver( + synchronous_mutation_observer_list_.ForEachObserver( [&](SynchronousMutationObserver* observer) { observer->NodeWillBeRemoved(n); }); @@ -5444,7 +5444,7 @@ unsigned offset, unsigned old_length, unsigned new_length) { - synchronous_mutation_observer_set_.ForEachObserver( + synchronous_mutation_observer_list_.ForEachObserver( [&](SynchronousMutationObserver* observer) { observer->DidUpdateCharacterData(character_data, offset, old_length, new_length); @@ -5452,7 +5452,7 @@ } void Document::NotifyChangeChildren(const ContainerNode& container) { - synchronous_mutation_observer_set_.ForEachObserver( + synchronous_mutation_observer_list_.ForEachObserver( [&](SynchronousMutationObserver* observer) { observer->DidChangeChildren(container); }); @@ -5482,7 +5482,7 @@ range->DidMergeTextNodes(node_to_be_removed_with_index, old_length); } - synchronous_mutation_observer_set_.ForEachObserver( + synchronous_mutation_observer_list_.ForEachObserver( [&](SynchronousMutationObserver* observer) { observer->DidMergeTextNodes(merged_node, node_to_be_removed_with_index, old_length); @@ -5495,7 +5495,7 @@ for (Range* range : ranges_) range->DidSplitTextNode(old_node); - synchronous_mutation_observer_set_.ForEachObserver( + synchronous_mutation_observer_list_.ForEachObserver( [&](SynchronousMutationObserver* observer) { observer->DidSplitTextNode(old_node); }); @@ -8143,7 +8143,7 @@ visitor->Trace(computed_node_mapping_); visitor->Trace(mime_handler_view_before_unload_event_listener_); visitor->Trace(cookie_jar_); - visitor->Trace(synchronous_mutation_observer_set_); + visitor->Trace(synchronous_mutation_observer_list_); visitor->Trace(element_explicitly_set_attr_elements_map_); visitor->Trace(display_lock_document_state_); visitor->Trace(font_preload_manager_);
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h index 1d08f4c..a40b925 100644 --- a/third_party/blink/renderer/core/dom/document.h +++ b/third_party/blink/renderer/core/dom/document.h
@@ -66,7 +66,7 @@ #include "third_party/blink/renderer/core/loader/font_preload_manager.h" #include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" -#include "third_party/blink/renderer/platform/heap_observer_set.h" +#include "third_party/blink/renderer/platform/heap_observer_list.h" #include "third_party/blink/renderer/platform/instrumentation/use_counter.h" #include "third_party/blink/renderer/platform/scheduler/public/post_cancellable_task.h" #include "third_party/blink/renderer/platform/supplementable.h" @@ -1609,9 +1609,9 @@ void CancelPendingJavaScriptUrls(); - HeapObserverSet<SynchronousMutationObserver>& - SynchronousMutationObserverSet() { - return synchronous_mutation_observer_set_; + HeapObserverList<SynchronousMutationObserver>& + SynchronousMutationObserverList() { + return synchronous_mutation_observer_list_; } void NotifyUpdateCharacterData(CharacterData* character_data, @@ -2135,8 +2135,8 @@ HeapHashMap<WeakMember<Element>, Member<ExplicitlySetAttrElementsMap>> element_explicitly_set_attr_elements_map_; - HeapObserverSet<SynchronousMutationObserver> - synchronous_mutation_observer_set_; + HeapObserverList<SynchronousMutationObserver> + synchronous_mutation_observer_list_; Member<DisplayLockDocumentState> display_lock_document_state_;
diff --git a/third_party/blink/renderer/core/dom/synchronous_mutation_observer.cc b/third_party/blink/renderer/core/dom/synchronous_mutation_observer.cc index 156a0e88..7deddd69 100644 --- a/third_party/blink/renderer/core/dom/synchronous_mutation_observer.cc +++ b/third_party/blink/renderer/core/dom/synchronous_mutation_observer.cc
@@ -8,7 +8,7 @@ namespace blink { -void SynchronousMutationObserver::ObserverSetWillBeCleared() { +void SynchronousMutationObserver::ObserverListWillBeCleared() { document_ = nullptr; } @@ -17,12 +17,12 @@ return; if (document_) - document_->SynchronousMutationObserverSet().RemoveObserver(this); + document_->SynchronousMutationObserverList().RemoveObserver(this); document_ = document; if (document_) - document_->SynchronousMutationObserverSet().AddObserver(this); + document_->SynchronousMutationObserverList().AddObserver(this); } void SynchronousMutationObserver::Trace(Visitor* visitor) const {
diff --git a/third_party/blink/renderer/core/dom/synchronous_mutation_observer.h b/third_party/blink/renderer/core/dom/synchronous_mutation_observer.h index e574de51..82a35ed8 100644 --- a/third_party/blink/renderer/core/dom/synchronous_mutation_observer.h +++ b/third_party/blink/renderer/core/dom/synchronous_mutation_observer.h
@@ -76,7 +76,7 @@ virtual void ContextDestroyed() {} // Call before clearing an observer list. - void ObserverSetWillBeCleared(); + void ObserverListWillBeCleared(); Document* GetDocument() const { return document_; } void SetDocument(Document*);
diff --git a/third_party/blink/renderer/core/execution_context/execution_context.cc b/third_party/blink/renderer/core/execution_context/execution_context.cc index 2ec6885..29da30b4 100644 --- a/third_party/blink/renderer/core/execution_context/execution_context.cc +++ b/third_party/blink/renderer/core/execution_context/execution_context.cc
@@ -119,7 +119,7 @@ if (lifecycle_state_ == state) return; lifecycle_state_ = state; - context_lifecycle_observer_set_.ForEachObserver( + context_lifecycle_observer_list_.ForEachObserver( [&](ContextLifecycleObserver* observer) { if (!observer->IsExecutionContextLifecycleObserver()) return; @@ -141,30 +141,30 @@ void ExecutionContext::NotifyContextDestroyed() { is_context_destroyed_ = true; - context_lifecycle_observer_set_.ForEachObserver( + context_lifecycle_observer_list_.ForEachObserver( [](ContextLifecycleObserver* observer) { observer->ContextDestroyed(); - observer->ObserverSetWillBeCleared(); + observer->ObserverListWillBeCleared(); }); - context_lifecycle_observer_set_.Clear(); + context_lifecycle_observer_list_.Clear(); } void ExecutionContext::AddContextLifecycleObserver( ContextLifecycleObserver* observer) { - context_lifecycle_observer_set_.AddObserver(observer); + context_lifecycle_observer_list_.AddObserver(observer); } void ExecutionContext::RemoveContextLifecycleObserver( ContextLifecycleObserver* observer) { - DCHECK(context_lifecycle_observer_set_.HasObserver(observer)); - context_lifecycle_observer_set_.RemoveObserver(observer); + DCHECK(context_lifecycle_observer_list_.HasObserver(observer)); + context_lifecycle_observer_list_.RemoveObserver(observer); } unsigned ExecutionContext::ContextLifecycleStateObserverCountForTesting() const { - DCHECK(!context_lifecycle_observer_set_.IsIteratingOverObservers()); + DCHECK(!context_lifecycle_observer_list_.IsIteratingOverObservers()); unsigned lifecycle_state_observers = 0; - context_lifecycle_observer_set_.ForEachObserver( + context_lifecycle_observer_list_.ForEachObserver( [&](ContextLifecycleObserver* observer) { if (!observer->IsExecutionContextLifecycleObserver()) return; @@ -391,7 +391,7 @@ visitor->Trace(pending_exceptions_); visitor->Trace(csp_delegate_); visitor->Trace(timers_); - visitor->Trace(context_lifecycle_observer_set_); + visitor->Trace(context_lifecycle_observer_list_); visitor->Trace(origin_trial_context_); ContextLifecycleNotifier::Trace(visitor); ConsoleLogger::Trace(visitor);
diff --git a/third_party/blink/renderer/core/execution_context/execution_context.h b/third_party/blink/renderer/core/execution_context/execution_context.h index f1ff5a6..e1264a3 100644 --- a/third_party/blink/renderer/core/execution_context/execution_context.h +++ b/third_party/blink/renderer/core/execution_context/execution_context.h
@@ -49,7 +49,7 @@ #include "third_party/blink/renderer/core/frame/dom_timer_coordinator.h" #include "third_party/blink/renderer/platform/context_lifecycle_notifier.h" #include "third_party/blink/renderer/platform/heap/handle.h" -#include "third_party/blink/renderer/platform/heap_observer_set.h" +#include "third_party/blink/renderer/platform/heap_observer_list.h" #include "third_party/blink/renderer/platform/instrumentation/use_counter.h" #include "third_party/blink/renderer/platform/loader/fetch/console_logger.h" #include "third_party/blink/renderer/platform/loader/fetch/https_state.h" @@ -368,8 +368,8 @@ void AddContextLifecycleObserver(ContextLifecycleObserver*) override; void RemoveContextLifecycleObserver(ContextLifecycleObserver*) override; - HeapObserverSet<ContextLifecycleObserver>& ContextLifecycleObserverSet() { - return context_lifecycle_observer_set_; + HeapObserverList<ContextLifecycleObserver>& ContextLifecycleObserverList() { + return context_lifecycle_observer_list_; } unsigned ContextLifecycleStateObserverCountForTesting() const; @@ -439,7 +439,7 @@ DOMTimerCoordinator timers_; - HeapObserverSet<ContextLifecycleObserver> context_lifecycle_observer_set_; + HeapObserverList<ContextLifecycleObserver> context_lifecycle_observer_list_; // Counter that keeps track of how many window interaction calls are allowed // for this ExecutionContext. Callers are expected to call
diff --git a/third_party/blink/renderer/core/execution_context/execution_context_lifecycle_state_observer.cc b/third_party/blink/renderer/core/execution_context/execution_context_lifecycle_state_observer.cc index 262c2900..25ae020 100644 --- a/third_party/blink/renderer/core/execution_context/execution_context_lifecycle_state_observer.cc +++ b/third_party/blink/renderer/core/execution_context/execution_context_lifecycle_state_observer.cc
@@ -57,7 +57,7 @@ #endif if (ExecutionContext* context = GetExecutionContext()) { #if DCHECK_IS_ON() - DCHECK(context->ContextLifecycleObserverSet().HasObserver(this)); + DCHECK(context->ContextLifecycleObserverList().HasObserver(this)); #endif mojom::blink::FrameLifecycleState pause_state = context->ContextPauseState();
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 213a50d..3a79c4c8 100644 --- a/third_party/blink/renderer/core/frame/local_frame_view.cc +++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -1679,6 +1679,52 @@ return true; } +bool LocalFrameView::RunPostLayoutIntersectionObserverSteps() { + DCHECK(frame_->IsLocalRoot()); + DCHECK(Lifecycle().GetState() >= DocumentLifecycle::kPrePaintClean); + + ComputePostLayoutIntersections(0); + + bool needs_more_lifecycle_steps = false; + ForAllNonThrottledLocalFrameViews( + [&needs_more_lifecycle_steps](LocalFrameView& frame_view) { + if (auto* controller = frame_view.GetFrame() + .GetDocument() + ->GetIntersectionObserverController()) { + controller->DeliverNotifications( + IntersectionObserver::kDeliverDuringPostLayoutSteps); + } + // If the lifecycle state changed as a result of the notifications, we + // should run the lifecycle again. + needs_more_lifecycle_steps |= frame_view.Lifecycle().GetState() < + DocumentLifecycle::kPrePaintClean; + }); + + return needs_more_lifecycle_steps; +} + +void LocalFrameView::ComputePostLayoutIntersections(unsigned parent_flags) { + if (ShouldThrottleRendering()) + return; + + unsigned flags = GetIntersectionObservationFlags(parent_flags) | + IntersectionObservation::kPostLayoutDeliveryOnly; + + if (auto* controller = + GetFrame().GetDocument()->GetIntersectionObserverController()) { + controller->ComputeIntersections(flags); + } + + for (Frame* child = frame_->Tree().FirstChild(); child; + child = child->Tree().NextSibling()) { + auto* child_local_frame = DynamicTo<LocalFrame>(child); + if (!child_local_frame) + continue; + if (LocalFrameView* child_view = child_local_frame->View()) + child_view->ComputePostLayoutIntersections(flags); + } +} + void LocalFrameView::ScheduleRelayout() { DCHECK(frame_->View() == this); @@ -2405,6 +2451,9 @@ // the potential to dirty layout (until loop limit is reached) and therefore // the above lifecycle phases need to be re-run until the limit is reached // or no layout is pending. + // Note that after ResizeObserver has settled, we also run intersection + // observations that need to be delievered in post-layout. This process can + // also dirty layout, which will run this loop again. while (true) { bool run_more_lifecycle_phases = RunStyleAndLayoutLifecyclePhases(target_state); @@ -2456,10 +2505,28 @@ } } - run_more_lifecycle_phases = RunResizeObserverSteps(target_state); - if (!run_more_lifecycle_phases) + // ResizeObserver and post-layout IntersectionObserver observation + // deliveries may dirty style and layout. RunResizeObserverSteps will return + // true if any observer ran that may have dirtied style or layout; + // RunPostLayoutIntersectionObserverSteps will return true if any + // observations led to content-visibility intersection changing visibility + // state synchronously (which happens on the first intersection + // observeration of a context). + bool needs_to_repeat_lifecycle = RunResizeObserverSteps(target_state); + // Only run the rest of the steps here if resize observer is done. + if (needs_to_repeat_lifecycle) + continue; + + needs_to_repeat_lifecycle = RunPostLayoutIntersectionObserverSteps(); + if (!needs_to_repeat_lifecycle) break; } + + // Once we exit the ResizeObserver / IntersectionObserver loop above, we need + // to clear the resize observer limits so that next time we run this, we can + // deliver more observations. + ClearResizeObserverLimit(); + // Layout invalidation scope was disabled for resize observer // re-enable it for subsequent steps #if DCHECK_IS_ON() @@ -2492,17 +2559,18 @@ re_run_lifecycles = re_run_lifecycles || result; }); } - if (!re_run_lifecycles) { - ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) { - ResizeObserverController* resize_controller = - ResizeObserverController::From(*frame_view.frame_->DomWindow()); - resize_controller->ClearMinDepth(); - resize_controller->SetLoopLimitErrorDispatched(false); - }); - } return re_run_lifecycles; } +void LocalFrameView::ClearResizeObserverLimit() { + ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) { + ResizeObserverController* resize_controller = + ResizeObserverController::From(*frame_view.frame_->DomWindow()); + resize_controller->ClearMinDepth(); + resize_controller->SetLoopLimitErrorDispatched(false); + }); +} + bool LocalFrameView::RunStyleAndLayoutLifecyclePhases( DocumentLifecycle::LifecycleState target_state) { TRACE_EVENT0("blink,benchmark",
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.h b/third_party/blink/renderer/core/frame/local_frame_view.h index a2644a57..18341c0 100644 --- a/third_party/blink/renderer/core/frame/local_frame_view.h +++ b/third_party/blink/renderer/core/frame/local_frame_view.h
@@ -864,9 +864,19 @@ bool NotifyResizeObservers(DocumentLifecycle::LifecycleState target_state); bool RunResizeObserverSteps(DocumentLifecycle::LifecycleState target_state); + void ClearResizeObserverLimit(); bool CheckLayoutInvalidationIsAllowed() const; + // This runs the intersection observer steps for observations that need to + // happen in post-layout. These results are also delivered (if needed) in the + // same call. Returns true if the lifecycle should process style and layout + // again before proceeding. + bool RunPostLayoutIntersectionObserverSteps(); + // This is a recursive helper for determining intersection observations which + // need to happen in post-layout. + void ComputePostLayoutIntersections(unsigned parent_flags); + PaintController* GetPaintController() { return paint_controller_.get(); } // Returns true if the root object was laid out. Returns false if the layout
diff --git a/third_party/blink/renderer/core/frame/pausable_script_executor.cc b/third_party/blink/renderer/core/frame/pausable_script_executor.cc index 88785f8..2e7dcdc 100644 --- a/third_party/blink/renderer/core/frame/pausable_script_executor.cc +++ b/third_party/blink/renderer/core/frame/pausable_script_executor.cc
@@ -255,9 +255,9 @@ void PausableScriptExecutor::Dispose() { // Remove object as a ExecutionContextLifecycleObserver. // TODO(keishi): Remove IsIteratingOverObservers() check when - // HeapObserverSet() supports removal while iterating. + // HeapObserverList() supports removal while iterating. if (!GetExecutionContext() - ->ContextLifecycleObserverSet() + ->ContextLifecycleObserverList() .IsIteratingOverObservers()) { SetExecutionContext(nullptr); }
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_base.cc b/third_party/blink/renderer/core/frame/web_frame_widget_base.cc index cb6ee2d..fd2dc4b 100644 --- a/third_party/blink/renderer/core/frame/web_frame_widget_base.cc +++ b/third_party/blink/renderer/core/frame/web_frame_widget_base.cc
@@ -829,6 +829,7 @@ nullptr, static_cast<blink::WebMenuSourceType>(source_type)); } } + host_context_menu_location_.reset(); } base::Optional<gfx::Point>
diff --git a/third_party/blink/renderer/core/html/media/autoplay_uma_helper.cc b/third_party/blink/renderer/core/html/media/autoplay_uma_helper.cc index f53e8aa..78163e2 100644 --- a/third_party/blink/renderer/core/html/media/autoplay_uma_helper.cc +++ b/third_party/blink/renderer/core/html/media/autoplay_uma_helper.cc
@@ -278,9 +278,9 @@ void AutoplayUmaHelper::MaybeUnregisterContextDestroyedObserver() { // TODO(keishi): Remove IsIteratingOverObservers() check when - // HeapObserverSet() supports removal while iterating. + // HeapObserverList() supports removal while iterating. if (!ShouldListenToContextDestroyed() && !GetExecutionContext() - ->ContextLifecycleObserverSet() + ->ContextLifecycleObserverList() .IsIteratingOverObservers()) { SetExecutionContext(nullptr); }
diff --git a/third_party/blink/renderer/core/input/pointer_event_manager.cc b/third_party/blink/renderer/core/input/pointer_event_manager.cc index 67884d3..8d8f25e2 100644 --- a/third_party/blink/renderer/core/input/pointer_event_manager.cc +++ b/third_party/blink/renderer/core/input/pointer_event_manager.cc
@@ -256,8 +256,7 @@ element_under_pointer_.at(pointer_event->pointerId()); if (!target) { element_under_pointer_.erase(pointer_event->pointerId()); - } else if (target != - element_under_pointer_.at(pointer_event->pointerId())->target) { + } else if (target != node->target) { element_under_pointer_.Set( pointer_event->pointerId(), MakeGarbageCollected<EventTargetAttributes>(target)); @@ -305,7 +304,7 @@ for (auto pointer_event : canceled_pointer_events) { // If we are sending a pointercancel we have sent the pointerevent to some // target before. - DCHECK(element_under_pointer_.Contains(pointer_event->pointerId())); + CHECK(element_under_pointer_.Contains(pointer_event->pointerId())); Element* target = element_under_pointer_.at(pointer_event->pointerId())->target;
diff --git a/third_party/blink/renderer/core/intersection_observer/intersection_observation.cc b/third_party/blink/renderer/core/intersection_observer/intersection_observation.cc index d8e49a84..8e3ab1a 100644 --- a/third_party/blink/renderer/core/intersection_observer/intersection_observation.cc +++ b/third_party/blink/renderer/core/intersection_observer/intersection_observation.cc
@@ -103,6 +103,16 @@ DCHECK(Observer()); if (!target_ || !observer_->RootIsValid() | !observer_->GetExecutionContext()) return false; + + // If we're processing post-layout deliveries only and we don't have a + // post-layout delivery observer, then return early. + if (flags & kPostLayoutDeliveryOnly) { + if (Observer()->GetDeliveryBehavior() != + IntersectionObserver::kDeliverDuringPostLayoutSteps) { + return false; + } + } + if (flags & (observer_->RootIsImplicit() ? kImplicitRootObserversNeedUpdate : kExplicitRootObserversNeedUpdate)) {
diff --git a/third_party/blink/renderer/core/intersection_observer/intersection_observation.h b/third_party/blink/renderer/core/intersection_observer/intersection_observation.h index 0d1c721..ccf7ba4e 100644 --- a/third_party/blink/renderer/core/intersection_observer/intersection_observation.h +++ b/third_party/blink/renderer/core/intersection_observer/intersection_observation.h
@@ -43,6 +43,9 @@ // If this bit is set, we can skip tracking the sticky frame during // UpdateViewportIntersectionsForSubtree. kCanSkipStickyFrameTracking = 1 << 4, + // If this bit is set, we only process intersection observations that + // require post-layout delivery. + kPostLayoutDeliveryOnly = 1 << 5, }; IntersectionObservation(IntersectionObserver&, Element&);
diff --git a/third_party/blink/renderer/core/intersection_observer/intersection_observer.cc b/third_party/blink/renderer/core/intersection_observer/intersection_observer.cc index c000e84..44d0b55 100644 --- a/third_party/blink/renderer/core/intersection_observer/intersection_observer.cc +++ b/third_party/blink/renderer/core/intersection_observer/intersection_observer.cc
@@ -430,6 +430,14 @@ DCHECK(!RootIsImplicit()); if (!RootIsValid() || !GetExecutionContext() || observations_.IsEmpty()) return false; + + // If we're processing post-layout deliveries only and we're not a post-layout + // delivery observer, then return early. + if (flags & IntersectionObservation::kPostLayoutDeliveryOnly) { + if (GetDeliveryBehavior() != kDeliverDuringPostLayoutSteps) + return false; + } + IntersectionGeometry::RootGeometry root_geometry( IntersectionGeometry::GetRootLayoutObjectForTarget(root(), nullptr, false),
diff --git a/third_party/blink/renderer/core/intersection_observer/intersection_observer.h b/third_party/blink/renderer/core/intersection_observer/intersection_observer.h index ef4317b..963451f5 100644 --- a/third_party/blink/renderer/core/intersection_observer/intersection_observer.h +++ b/third_party/blink/renderer/core/intersection_observer/intersection_observer.h
@@ -63,9 +63,11 @@ // Used to specify when callbacks should be invoked with new notifications. // Blink-internal users of IntersectionObserver will have their callbacks - // invoked synchronously at the end of a lifecycle update. Javascript - // observers will PostTask to invoke their callbacks. + // invoked synchronously either at the end of a lifecycle update or in the + // middle of the lifecycle post layout. Javascript observers will PostTask to + // invoke their callbacks. enum DeliveryBehavior { + kDeliverDuringPostLayoutSteps, kDeliverDuringPostLifecycleSteps, kPostTaskToDeliver };
diff --git a/third_party/blink/renderer/core/layout/layout_box_model_object.cc b/third_party/blink/renderer/core/layout/layout_box_model_object.cc index 2d0bfbfb..61e5c1ef 100644 --- a/third_party/blink/renderer/core/layout/layout_box_model_object.cc +++ b/third_party/blink/renderer/core/layout/layout_box_model_object.cc
@@ -126,11 +126,6 @@ return kBackgroundPaintInScrollingContents; } - // TODO(crbug.com/1113269): Temporarily disable composited scrolling for - // clipped layers. - if (HasClip()) - return kBackgroundPaintInGraphicsLayer; - // Inset box shadow is painted in the scrolling area above the background, and // it doesn't scroll, so the background can only be painted in the main layer. if (HasInsetBoxShadow(StyleRef()))
diff --git a/third_party/blink/renderer/core/layout/ng/custom/custom_layout_child.h b/third_party/blink/renderer/core/layout/ng/custom/custom_layout_child.h index 2b1a0a5..e7fc6cc 100644 --- a/third_party/blink/renderer/core/layout/ng/custom/custom_layout_child.h +++ b/third_party/blink/renderer/core/layout/ng/custom/custom_layout_child.h
@@ -29,6 +29,8 @@ public: CustomLayoutChild(const CSSLayoutDefinition&, NGLayoutInputNode); + CustomLayoutChild(const CustomLayoutChild&) = delete; + CustomLayoutChild& operator=(const CustomLayoutChild&) = delete; ~CustomLayoutChild() override = default; // LayoutChild.idl @@ -52,8 +54,6 @@ NGLayoutInputNode node_; Member<PrepopulatedComputedStylePropertyMap> style_map_; Member<CustomLayoutToken> token_; - - DISALLOW_COPY_AND_ASSIGN(CustomLayoutChild); }; } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/custom/custom_layout_constraints.h b/third_party/blink/renderer/core/layout/ng/custom/custom_layout_constraints.h index c3dfb58..7130128 100644 --- a/third_party/blink/renderer/core/layout/ng/custom/custom_layout_constraints.h +++ b/third_party/blink/renderer/core/layout/ng/custom/custom_layout_constraints.h
@@ -25,6 +25,8 @@ CustomLayoutConstraints(const LogicalSize& border_box_size, SerializedScriptValue* data, v8::Isolate*); + CustomLayoutConstraints(const CustomLayoutConstraints&) = delete; + CustomLayoutConstraints& operator=(const CustomLayoutConstraints&) = delete; ~CustomLayoutConstraints() override; // LayoutConstraints.idl @@ -38,8 +40,6 @@ double fixed_inline_size_; double fixed_block_size_; TraceWrapperV8Reference<v8::Value> layout_worklet_world_v8_data_; - - DISALLOW_COPY_AND_ASSIGN(CustomLayoutConstraints); }; } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/custom/custom_layout_edges.h b/third_party/blink/renderer/core/layout/ng/custom/custom_layout_edges.h index beb7eb1..7b10a60 100644 --- a/third_party/blink/renderer/core/layout/ng/custom/custom_layout_edges.h +++ b/third_party/blink/renderer/core/layout/ng/custom/custom_layout_edges.h
@@ -22,6 +22,8 @@ inline_end_(border_scrollbar_padding.inline_end), block_start_(border_scrollbar_padding.block_start), block_end_(border_scrollbar_padding.block_end) {} + CustomLayoutEdges(const CustomLayoutEdges&) = delete; + CustomLayoutEdges& operator=(const CustomLayoutEdges&) = delete; // layout_edges.idl double inlineStart() const { return inline_start_; } @@ -36,8 +38,6 @@ double inline_end_; double block_start_; double block_end_; - - DISALLOW_COPY_AND_ASSIGN(CustomLayoutEdges); }; } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/custom/custom_layout_fragment.h b/third_party/blink/renderer/core/layout/ng/custom/custom_layout_fragment.h index 13fc70e..40438b03 100644 --- a/third_party/blink/renderer/core/layout/ng/custom/custom_layout_fragment.h +++ b/third_party/blink/renderer/core/layout/ng/custom/custom_layout_fragment.h
@@ -41,6 +41,8 @@ const LogicalSize& size, const base::Optional<LayoutUnit> baseline, v8::Isolate*); + CustomLayoutFragment(const CustomLayoutFragment&) = delete; + CustomLayoutFragment& operator=(const CustomLayoutFragment&) = delete; ~CustomLayoutFragment() override = default; double inlineSize() const { return inline_size_; } @@ -95,8 +97,6 @@ const base::Optional<double> baseline_; TraceWrapperV8Reference<v8::Value> layout_worklet_world_v8_data_; - - DISALLOW_COPY_AND_ASSIGN(CustomLayoutFragment); }; } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/custom/layout_worklet.h b/third_party/blink/renderer/core/layout/ng/custom/layout_worklet.h index 01a2de2..a5e062a0 100644 --- a/third_party/blink/renderer/core/layout/ng/custom/layout_worklet.h +++ b/third_party/blink/renderer/core/layout/ng/custom/layout_worklet.h
@@ -34,6 +34,8 @@ static LayoutWorklet* From(LocalDOMWindow&); explicit LayoutWorklet(LocalDOMWindow&); + LayoutWorklet(const LayoutWorklet&) = delete; + LayoutWorklet& operator=(const LayoutWorklet&) = delete; ~LayoutWorklet() override; typedef HeapHashMap<String, Member<DocumentLayoutDefinition>> @@ -60,8 +62,6 @@ DocumentDefinitionMap document_definition_map_; Member<PendingLayoutRegistry> pending_layout_registry_; - - DISALLOW_COPY_AND_ASSIGN(LayoutWorklet); }; } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/custom/pending_layout_registry.h b/third_party/blink/renderer/core/layout/ng/custom/pending_layout_registry.h index f0c7eb3..bb8537e 100644 --- a/third_party/blink/renderer/core/layout/ng/custom/pending_layout_registry.h +++ b/third_party/blink/renderer/core/layout/ng/custom/pending_layout_registry.h
@@ -19,6 +19,8 @@ class PendingLayoutRegistry : public GarbageCollected<PendingLayoutRegistry> { public: PendingLayoutRegistry() = default; + PendingLayoutRegistry(const PendingLayoutRegistry&) = delete; + PendingLayoutRegistry& operator=(const PendingLayoutRegistry&) = delete; void NotifyLayoutReady(const AtomicString& name); void AddPendingLayout(const AtomicString& name, Node*); @@ -37,8 +39,6 @@ using PendingSet = HeapHashSet<WeakMember<Node>>; using PendingLayoutMap = HeapHashMap<AtomicString, Member<PendingSet>>; PendingLayoutMap pending_layouts_; - - DISALLOW_COPY_AND_ASSIGN(PendingLayoutRegistry); }; } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/inline/empty_offset_mapping_builder.h b/third_party/blink/renderer/core/layout/ng/inline/empty_offset_mapping_builder.h index 7c69dad0..a816d61 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/empty_offset_mapping_builder.h +++ b/third_party/blink/renderer/core/layout/ng/inline/empty_offset_mapping_builder.h
@@ -26,15 +26,15 @@ }; EmptyOffsetMappingBuilder() = default; + EmptyOffsetMappingBuilder(const EmptyOffsetMappingBuilder&) = delete; + EmptyOffsetMappingBuilder& operator=(const EmptyOffsetMappingBuilder&) = + delete; void AppendIdentityMapping(unsigned) {} void AppendCollapsedMapping(unsigned) {} void CollapseTrailingSpace(unsigned) {} void Composite(const EmptyOffsetMappingBuilder&) {} void Concatenate(const EmptyOffsetMappingBuilder&) {} void RestoreTrailingCollapsibleSpace(const LayoutText&, unsigned) {} - - private: - DISALLOW_COPY_AND_ASSIGN(EmptyOffsetMappingBuilder); }; } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.cc index 443c9070..0103170 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.cc
@@ -20,6 +20,10 @@ public: virtual Vector<Result> CollectFrom(const NGPhysicalFragment&) = 0; + NGPhysicalFragmentCollectorBase(const NGPhysicalFragmentCollectorBase&) = + delete; + NGPhysicalFragmentCollectorBase& operator=( + const NGPhysicalFragmentCollectorBase&) = delete; protected: explicit NGPhysicalFragmentCollectorBase() = default; @@ -89,8 +93,6 @@ PhysicalOffset current_offset_to_root_; Vector<Result> results_; bool should_stop_traversing_ = false; - - DISALLOW_COPY_AND_ASSIGN(NGPhysicalFragmentCollectorBase); }; // The visitor emitting all visited fragments. @@ -99,6 +101,8 @@ public: DescendantCollector() = default; + DescendantCollector(const DescendantCollector&) = delete; + DescendantCollector& operator=(const DescendantCollector&) = delete; Vector<Result> CollectFrom(const NGPhysicalFragment& fragment) final { return CollectExclusivelyFrom(fragment); @@ -109,8 +113,6 @@ Emit(); VisitChildren(); } - - DISALLOW_COPY_AND_ASSIGN(DescendantCollector); }; // The visitor emitting fragments generated from the given LayoutInline, @@ -125,6 +127,8 @@ explicit LayoutInlineCollector(const LayoutInline& container) { CollectInclusiveDescendants(container); } + LayoutInlineCollector(const LayoutInlineCollector&) = delete; + LayoutInlineCollector& operator=(const LayoutInlineCollector&) = delete; Vector<Result> CollectFrom(const NGPhysicalFragment& fragment) final { return CollectExclusivelyFrom(fragment); @@ -157,8 +161,6 @@ } HashSet<const LayoutObject*> inclusive_descendants_; - - DISALLOW_COPY_AND_ASSIGN(LayoutInlineCollector); }; } // namespace
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc index ccad6f2..459284b 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
@@ -510,6 +510,8 @@ layout_text_(layout_text) { DCHECK(layout_text_.HasValidInlineItems()); } + NGInlineNodeDataEditor(const NGInlineNodeDataEditor&) = delete; + NGInlineNodeDataEditor& operator=(const NGInlineNodeDataEditor&) = delete; LayoutBlockFlow* GetLayoutBlockFlow() const { return block_flow_; } @@ -740,8 +742,6 @@ const LayoutText& layout_text_; unsigned start_offset_ = 0; unsigned end_offset_ = 0; - - DISALLOW_COPY_AND_ASSIGN(NGInlineNodeDataEditor); }; // static
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h index b309bc5..b978202 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h
@@ -40,6 +40,8 @@ {writing_direction.GetWritingMode(), TextDirection::kLtr}), line_box_type_(NGPhysicalLineBoxFragment::kNormalLineBox), base_direction_(TextDirection::kLtr) {} + NGLineBoxFragmentBuilder(const NGLineBoxFragmentBuilder&) = delete; + NGLineBoxFragmentBuilder& operator=(const NGLineBoxFragmentBuilder&) = delete; void Reset(); @@ -97,8 +99,6 @@ friend class NGLayoutResult; friend class NGPhysicalLineBoxFragment; - - DISALLOW_COPY_AND_ASSIGN(NGLineBoxFragmentBuilder); }; } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h b/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h index c4ee39e..e9c781be 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h
@@ -105,6 +105,8 @@ HashMap<Persistent<const Node>, std::pair<unsigned, unsigned>>; NGOffsetMapping(UnitVector&&, RangeMap&&, String); + NGOffsetMapping(const NGOffsetMapping&) = delete; + NGOffsetMapping& operator=(const NGOffsetMapping&) = delete; ~NGOffsetMapping(); const UnitVector& GetUnits() const { return units_; } @@ -238,8 +240,6 @@ // The text content string of the inline formatting context. Same string as // |NGInlineNodeData::text_content_|. String text_; - - DISALLOW_COPY_AND_ASSIGN(NGOffsetMapping); }; CORE_EXPORT LayoutBlockFlow* NGInlineFormattingContextOf(const Position&);
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_builder.h b/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_builder.h index 957e64a8..20b5c38 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_builder.h +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_builder.h
@@ -62,17 +62,19 @@ public: SourceNodeScope(NGOffsetMappingBuilder* builder, const LayoutObject* node); + SourceNodeScope(const SourceNodeScope&) = delete; + SourceNodeScope& operator=(const SourceNodeScope&) = delete; ~SourceNodeScope(); private: NGOffsetMappingBuilder* const builder_ = nullptr; base::AutoReset<const LayoutObject*> layout_object_auto_reset_; base::AutoReset<unsigned> appended_length_auto_reset_; - - DISALLOW_COPY_AND_ASSIGN(SourceNodeScope); }; NGOffsetMappingBuilder(); + NGOffsetMappingBuilder(const NGOffsetMappingBuilder&) = delete; + NGOffsetMappingBuilder& operator=(const NGOffsetMappingBuilder&) = delete; void ReserveCapacity(unsigned capacity); @@ -140,8 +142,6 @@ String destination_string_; friend class SourceNodeScope; - - DISALLOW_COPY_AND_ASSIGN(NGOffsetMappingBuilder); }; } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_shape.h b/third_party/blink/renderer/core/layout/svg/layout_svg_shape.h index 262ed8f..db4452a 100644 --- a/third_party/blink/renderer/core/layout/svg/layout_svg_shape.h +++ b/third_party/blink/renderer/core/layout/svg/layout_svg_shape.h
@@ -27,7 +27,6 @@ #define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_LAYOUT_SVG_SHAPE_H_ #include <memory> -#include "base/macros.h" #include "third_party/blink/renderer/core/layout/svg/layout_svg_model_object.h" #include "third_party/blink/renderer/core/layout/svg/svg_marker_data.h" #include "third_party/blink/renderer/platform/geometry/float_rect.h" @@ -50,9 +49,10 @@ public: LayoutSVGShapeRareData() = default; + LayoutSVGShapeRareData(const LayoutSVGShapeRareData&) = delete; + LayoutSVGShapeRareData& operator=(const LayoutSVGShapeRareData) = delete; Path non_scaling_stroke_path_; AffineTransform non_scaling_stroke_transform_; - DISALLOW_COPY_AND_ASSIGN(LayoutSVGShapeRareData); }; class LayoutSVGShape : public LayoutSVGModelObject {
diff --git a/third_party/blink/renderer/core/layout/svg/svg_resources.h b/third_party/blink/renderer/core/layout/svg/svg_resources.h index 5f2790b..31662f0 100644 --- a/third_party/blink/renderer/core/layout/svg/svg_resources.h +++ b/third_party/blink/renderer/core/layout/svg/svg_resources.h
@@ -22,7 +22,6 @@ #include <memory> -#include "base/macros.h" #include "base/memory/ptr_util.h" #include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h" #include "third_party/blink/renderer/core/svg/svg_resource_client.h" @@ -49,6 +48,8 @@ public: SVGResources(); + SVGResources(const SVGResources&) = delete; + SVGResources& operator=(const SVGResources&) = delete; static SVGElementResourceClient* GetClient(const LayoutObject&); static FloatRect ReferenceBoxForEffects(const LayoutObject&); @@ -190,7 +191,6 @@ std::unique_ptr<MarkerData> marker_data_; std::unique_ptr<FillStrokeData> fill_stroke_data_; LayoutSVGResourceContainer* linked_resource_; - DISALLOW_COPY_AND_ASSIGN(SVGResources); }; class FilterData final : public GarbageCollected<FilterData> {
diff --git a/third_party/blink/renderer/core/layout/svg/svg_resources_cache.h b/third_party/blink/renderer/core/layout/svg/svg_resources_cache.h index fe545ef7..765d6e5f 100644 --- a/third_party/blink/renderer/core/layout/svg/svg_resources_cache.h +++ b/third_party/blink/renderer/core/layout/svg/svg_resources_cache.h
@@ -21,7 +21,6 @@ #define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_SVG_RESOURCES_CACHE_H_ #include <memory> -#include "base/macros.h" #include "third_party/blink/renderer/core/style/style_difference.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" #include "third_party/blink/renderer/platform/wtf/hash_map.h" @@ -37,6 +36,8 @@ public: SVGResourcesCache(); + SVGResourcesCache(const SVGResourcesCache&) = delete; + SVGResourcesCache& operator=(const SVGResourcesCache&) = delete; ~SVGResourcesCache(); static SVGResources* CachedResourcesForLayoutObject(const LayoutObject&); @@ -70,6 +71,8 @@ TemporaryStyleScope(LayoutObject&, const ComputedStyle& original_style, const ComputedStyle& temporary_style); + TemporaryStyleScope(const TemporaryStyleScope&) = delete; + TemporaryStyleScope& operator=(const TemporaryStyleScope) = delete; ~TemporaryStyleScope(); private: @@ -79,7 +82,6 @@ const ComputedStyle& original_style_; const ComputedStyle& temporary_style_; const bool styles_are_equal_; - DISALLOW_COPY_AND_ASSIGN(TemporaryStyleScope); }; private: @@ -97,7 +99,6 @@ typedef HashMap<const LayoutObject*, std::unique_ptr<SVGResources>> CacheMap; CacheMap cache_; - DISALLOW_COPY_AND_ASSIGN(SVGResourcesCache); }; } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/svg/svg_resources_cycle_solver.h b/third_party/blink/renderer/core/layout/svg/svg_resources_cycle_solver.h index 6a90684..c634748 100644 --- a/third_party/blink/renderer/core/layout/svg/svg_resources_cycle_solver.h +++ b/third_party/blink/renderer/core/layout/svg/svg_resources_cycle_solver.h
@@ -20,7 +20,6 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_SVG_RESOURCES_CYCLE_SOLVER_H_ #define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_SVG_RESOURCES_CYCLE_SOLVER_H_ -#include "base/macros.h" #include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" #include "third_party/blink/renderer/platform/wtf/hash_set.h" @@ -36,6 +35,8 @@ public: SVGResourcesCycleSolver(); + SVGResourcesCycleSolver(const SVGResourcesCycleSolver&) = delete; + SVGResourcesCycleSolver& operator=(const SVGResourcesCycleSolver&) = delete; ~SVGResourcesCycleSolver(); bool IsKnownAcyclic(const LayoutSVGResourceContainer*) const; @@ -71,7 +72,6 @@ using ResourceSet = HashSet<const LayoutSVGResourceContainer*>; ResourceSet active_resources_; ResourceSet dag_cache_; - DISALLOW_COPY_AND_ASSIGN(SVGResourcesCycleSolver); }; } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/svg/svg_text_chunk_builder.h b/third_party/blink/renderer/core/layout/svg/svg_text_chunk_builder.h index b3ba82f..750f50e 100644 --- a/third_party/blink/renderer/core/layout/svg/svg_text_chunk_builder.h +++ b/third_party/blink/renderer/core/layout/svg/svg_text_chunk_builder.h
@@ -20,7 +20,6 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_SVG_TEXT_CHUNK_BUILDER_H_ #define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_SVG_TEXT_CHUNK_BUILDER_H_ -#include "base/macros.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" #include "third_party/blink/renderer/platform/wtf/vector.h" @@ -45,6 +44,8 @@ public: SVGTextChunkBuilder(); + SVGTextChunkBuilder(const SVGTextChunkBuilder&) = delete; + SVGTextChunkBuilder& operator=(const SVGTextChunkBuilder&) = delete; void ProcessTextChunks(const Vector<SVGInlineTextBox*>&); @@ -65,8 +66,6 @@ void ProcessTextAnchorCorrection(bool is_vertical_text, float text_anchor_shift, Vector<SVGTextFragment>&); - - DISALLOW_COPY_AND_ASSIGN(SVGTextChunkBuilder); }; class SVGTextPathChunkBuilder final : public SVGTextChunkBuilder { @@ -74,6 +73,8 @@ public: SVGTextPathChunkBuilder(); + SVGTextPathChunkBuilder(const SVGTextPathChunkBuilder&) = delete; + SVGTextPathChunkBuilder& operator=(const SVGTextPathChunkBuilder&) = delete; float TotalLength() const { return total_length_; } unsigned TotalCharacters() const { return total_characters_; } @@ -84,8 +85,6 @@ float total_length_; unsigned total_characters_; - - DISALLOW_COPY_AND_ASSIGN(SVGTextPathChunkBuilder); }; // Compute the "shift" induced by the 'text-anchor' property.
diff --git a/third_party/blink/renderer/core/layout/svg/svg_text_layout_attributes_builder.h b/third_party/blink/renderer/core/layout/svg/svg_text_layout_attributes_builder.h index 28a4240..7b1a347 100644 --- a/third_party/blink/renderer/core/layout/svg/svg_text_layout_attributes_builder.h +++ b/third_party/blink/renderer/core/layout/svg/svg_text_layout_attributes_builder.h
@@ -20,7 +20,6 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_SVG_TEXT_LAYOUT_ATTRIBUTES_BUILDER_H_ #define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_SVG_TEXT_LAYOUT_ATTRIBUTES_BUILDER_H_ -#include "base/macros.h" #include "third_party/blink/renderer/core/layout/svg/svg_character_data.h" #include "third_party/blink/renderer/platform/heap/handle.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" @@ -46,6 +45,10 @@ public: explicit SVGTextLayoutAttributesBuilder(LayoutSVGText&); + SVGTextLayoutAttributesBuilder(const SVGTextLayoutAttributesBuilder&) = + delete; + SVGTextLayoutAttributesBuilder& operator=( + const SVGTextLayoutAttributesBuilder&) = delete; void BuildLayoutAttributes(); @@ -75,8 +78,6 @@ unsigned character_count_; HeapVector<TextPosition> text_positions_; SVGCharacterDataMap character_data_map_; - - DISALLOW_COPY_AND_ASSIGN(SVGTextLayoutAttributesBuilder); }; } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine.h b/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine.h index 56dbf5a..0556dbec 100644 --- a/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine.h +++ b/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine.h
@@ -21,7 +21,6 @@ #define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_SVG_TEXT_LAYOUT_ENGINE_H_ #include <memory> -#include "base/macros.h" #include "third_party/blink/renderer/core/layout/api/line_layout_svg_inline_text.h" #include "third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.h" #include "third_party/blink/renderer/core/layout/svg/svg_text_fragment.h" @@ -51,6 +50,8 @@ public: SVGTextLayoutEngine(const Vector<LayoutSVGInlineText*>&); + SVGTextLayoutEngine(const SVGTextLayoutEngine&) = delete; + SVGTextLayoutEngine& operator=(const SVGTextLayoutEngine&) = delete; ~SVGTextLayoutEngine(); void LayoutCharactersInTextBoxes(InlineFlowBox* start); @@ -98,7 +99,6 @@ float text_path_displacement_; float text_path_spacing_; float text_path_scaling_; - DISALLOW_COPY_AND_ASSIGN(SVGTextLayoutEngine); }; } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine_baseline.h b/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine_baseline.h index 718b6f0f..c5679aa 100644 --- a/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine_baseline.h +++ b/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine_baseline.h
@@ -20,7 +20,6 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_SVG_TEXT_LAYOUT_ENGINE_BASELINE_H_ #define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_SVG_TEXT_LAYOUT_ENGINE_BASELINE_H_ -#include "base/macros.h" #include "third_party/blink/renderer/core/layout/api/line_layout_item.h" #include "third_party/blink/renderer/core/style/svg_computed_style_defs.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" @@ -38,6 +37,9 @@ public: SVGTextLayoutEngineBaseline(const Font&, float effective_zoom); + SVGTextLayoutEngineBaseline(const SVGTextLayoutEngineBaseline&) = delete; + SVGTextLayoutEngineBaseline& operator=(const SVGTextLayoutEngineBaseline&) = + delete; float CalculateBaselineShift(const ComputedStyle&) const; float CalculateAlignmentBaselineShift(bool is_vertical_text, @@ -54,7 +56,6 @@ // layout inside SVG takes place in unzoomed coordinates we have to compensate // for zoom when reading values from the font descriptor. float effective_zoom_; - DISALLOW_COPY_AND_ASSIGN(SVGTextLayoutEngineBaseline); }; } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine_spacing.h b/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine_spacing.h index ef87631..4bfd6cb3 100644 --- a/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine_spacing.h +++ b/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine_spacing.h
@@ -20,7 +20,6 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_SVG_TEXT_LAYOUT_ENGINE_SPACING_H_ #define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_SVG_TEXT_LAYOUT_ENGINE_SPACING_H_ -#include "base/macros.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" #include "third_party/blink/renderer/platform/wtf/text/unicode.h" @@ -35,6 +34,9 @@ public: SVGTextLayoutEngineSpacing(const Font&, float effective_zoom); + SVGTextLayoutEngineSpacing(const SVGTextLayoutEngineSpacing&) = delete; + SVGTextLayoutEngineSpacing& operator=(const SVGTextLayoutEngineSpacing&) = + delete; float CalculateCSSSpacing(UChar current_character); @@ -42,7 +44,6 @@ const Font& font_; UChar last_character_; float effective_zoom_; - DISALLOW_COPY_AND_ASSIGN(SVGTextLayoutEngineSpacing); }; } // namespace blink
diff --git a/third_party/blink/renderer/core/loader/web_associated_url_loader_impl.cc b/third_party/blink/renderer/core/loader/web_associated_url_loader_impl.cc index 047e741..382ca30 100644 --- a/third_party/blink/renderer/core/loader/web_associated_url_loader_impl.cc +++ b/third_party/blink/renderer/core/loader/web_associated_url_loader_impl.cc
@@ -322,9 +322,9 @@ void Dispose() { parent_ = nullptr; // TODO(keishi): Remove IsIteratingOverObservers() check when - // HeapObserverSet() supports removal while iterating. + // HeapObserverList() supports removal while iterating. if (!GetExecutionContext() - ->ContextLifecycleObserverSet() + ->ContextLifecycleObserverList() .IsIteratingOverObservers()) { SetExecutionContext(nullptr); }
diff --git a/third_party/blink/renderer/core/page/context_menu_controller.cc b/third_party/blink/renderer/core/page/context_menu_controller.cc index 7c40eea..7c9ab47 100644 --- a/third_party/blink/renderer/core/page/context_menu_controller.cc +++ b/third_party/blink/renderer/core/page/context_menu_controller.cc
@@ -41,6 +41,7 @@ #include "third_party/blink/renderer/core/dom/node.h" #include "third_party/blink/renderer/core/editing/editing_tri_state.h" #include "third_party/blink/renderer/core/editing/editor.h" +#include "third_party/blink/renderer/core/editing/ephemeral_range.h" #include "third_party/blink/renderer/core/editing/frame_selection.h" #include "third_party/blink/renderer/core/editing/ime/input_method_controller.h" #include "third_party/blink/renderer/core/editing/selection_controller.h" @@ -69,6 +70,7 @@ #include "third_party/blink/renderer/core/page/context_menu_provider.h" #include "third_party/blink/renderer/core/page/focus_controller.h" #include "third_party/blink/renderer/core/page/page.h" +#include "third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.h" #include "third_party/blink/renderer/platform/exported/wrapped_resource_response.h" namespace blink { @@ -246,6 +248,17 @@ PhysicalOffset(FlooredIntPoint(point))); } + // Store text selection when it happens as it might be cleared when the + // browser will request |TextFragmentSelectorGenerator| to generator selector. + if (!selected_frame->Selection().SelectedText().IsEmpty()) { + VisibleSelectionInFlatTree selection = + selected_frame->Selection().ComputeVisibleSelectionInFlatTree(); + EphemeralRangeInFlatTree selection_range(selection.Start(), + selection.End()); + page_->GetTextFragmentSelectorGenerator().UpdateSelection(selected_frame, + selection_range); + } + WebContextMenuData data; data.mouse_position = selected_frame->View()->FrameToViewport( result.RoundedPointInInnerNodeFrame());
diff --git a/third_party/blink/renderer/core/page/page.cc b/third_party/blink/renderer/core/page/page.cc index 1b35bb8..4065dbe2 100644 --- a/third_party/blink/renderer/core/page/page.cc +++ b/third_party/blink/renderer/core/page/page.cc
@@ -75,6 +75,7 @@ #include "third_party/blink/renderer/core/page/scoped_page_pauser.h" #include "third_party/blink/renderer/core/page/scrolling/overscroll_controller.h" #include "third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h" +#include "third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.h" #include "third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller.h" #include "third_party/blink/renderer/core/page/spatial_navigation_controller.h" #include "third_party/blink/renderer/core/page/validation_message_client_impl.h" @@ -225,7 +226,9 @@ next_related_page_(this), prev_related_page_(this), autoplay_flags_(0), - web_text_autosizer_page_info_({0, 0, 1.f}) { + web_text_autosizer_page_info_({0, 0, 1.f}), + text_fragment_selector_generator_( + MakeGarbageCollected<TextFragmentSelectorGenerator>()) { DCHECK(!AllPages().Contains(this)); AllPages().insert(this); @@ -340,6 +343,7 @@ void Page::DocumentDetached(Document* document) { pointer_lock_controller_->DocumentDetached(document); + text_fragment_selector_generator_->DocumentDetached(document); context_menu_controller_->DocumentDetached(document); if (validation_message_client_) validation_message_client_->DocumentDetached(*document); @@ -531,7 +535,7 @@ if (is_initial_state) return; - page_visibility_observer_set_.ForEachObserver( + page_visibility_observer_list_.ForEachObserver( [](PageVisibilityObserver* observer) { observer->PageVisibilityChanged(); }); @@ -896,7 +900,7 @@ visitor->Trace(focus_controller_); visitor->Trace(context_menu_controller_); visitor->Trace(page_scale_constraints_set_); - visitor->Trace(page_visibility_observer_set_); + visitor->Trace(page_visibility_observer_list_); visitor->Trace(pointer_lock_controller_); visitor->Trace(scrolling_coordinator_); visitor->Trace(browser_controls_); @@ -914,6 +918,7 @@ visitor->Trace(plugins_changed_observers_); visitor->Trace(next_related_page_); visitor->Trace(prev_related_page_); + visitor->Trace(text_fragment_selector_generator_); Supplementable<Page>::Trace(visitor); } @@ -963,11 +968,11 @@ if (agent_metrics_collector_) agent_metrics_collector_->ReportMetrics(); - page_visibility_observer_set_.ForEachObserver( + page_visibility_observer_list_.ForEachObserver( [](PageVisibilityObserver* observer) { - observer->ObserverSetWillBeCleared(); + observer->ObserverListWillBeCleared(); }); - page_visibility_observer_set_.Clear(); + page_visibility_observer_list_.Clear(); page_scheduler_.reset(); }
diff --git a/third_party/blink/renderer/core/page/page.h b/third_party/blink/renderer/core/page/page.h index b136f3b8..13ea3cb 100644 --- a/third_party/blink/renderer/core/page/page.h +++ b/third_party/blink/renderer/core/page/page.h
@@ -40,7 +40,7 @@ #include "third_party/blink/renderer/core/page/viewport_description.h" #include "third_party/blink/renderer/platform/heap/handle.h" #include "third_party/blink/renderer/platform/heap/persistent.h" -#include "third_party/blink/renderer/platform/heap_observer_set.h" +#include "third_party/blink/renderer/platform/heap_observer_list.h" #include "third_party/blink/renderer/platform/scheduler/public/page_lifecycle_state.h" #include "third_party/blink/renderer/platform/scheduler/public/page_scheduler.h" #include "third_party/blink/renderer/platform/supplementable.h" @@ -75,6 +75,7 @@ class PluginData; class PluginsChangedObserver; class PointerLockController; +class TextFragmentSelectorGenerator; class ScopedPagePauser; class ScrollingCoordinator; class ScrollbarTheme; @@ -350,12 +351,16 @@ return history_navigation_virtual_time_pauser_; } - HeapObserverSet<PageVisibilityObserver>& PageVisibilityObserverSet() { - return page_visibility_observer_set_; + HeapObserverList<PageVisibilityObserver>& PageVisibilityObserverList() { + return page_visibility_observer_list_; } static void PrepareForLeakDetection(); + TextFragmentSelectorGenerator& GetTextFragmentSelectorGenerator() const { + return *text_fragment_selector_generator_; + } + private: friend class ScopedPagePauser; @@ -393,7 +398,7 @@ const Member<FocusController> focus_controller_; const Member<ContextMenuController> context_menu_controller_; const Member<PageScaleConstraintsSet> page_scale_constraints_set_; - HeapObserverSet<PageVisibilityObserver> page_visibility_observer_set_; + HeapObserverList<PageVisibilityObserver> page_visibility_observer_list_; const Member<PointerLockController> pointer_lock_controller_; Member<ScrollingCoordinator> scrolling_coordinator_; const Member<BrowserControls> browser_controls_; @@ -477,6 +482,8 @@ WebScopedVirtualTimePauser history_navigation_virtual_time_pauser_; + const Member<TextFragmentSelectorGenerator> text_fragment_selector_generator_; + DISALLOW_COPY_AND_ASSIGN(Page); };
diff --git a/third_party/blink/renderer/core/page/page_visibility_observer.cc b/third_party/blink/renderer/core/page/page_visibility_observer.cc index 886d217..9ad5f41 100644 --- a/third_party/blink/renderer/core/page/page_visibility_observer.cc +++ b/third_party/blink/renderer/core/page/page_visibility_observer.cc
@@ -12,7 +12,7 @@ SetPage(page); } -void PageVisibilityObserver::ObserverSetWillBeCleared() { +void PageVisibilityObserver::ObserverListWillBeCleared() { page_ = nullptr; } @@ -21,12 +21,12 @@ return; if (page_) - page_->PageVisibilityObserverSet().RemoveObserver(this); + page_->PageVisibilityObserverList().RemoveObserver(this); page_ = page; if (page_) - page_->PageVisibilityObserverSet().AddObserver(this); + page_->PageVisibilityObserverList().AddObserver(this); } void PageVisibilityObserver::Trace(Visitor* visitor) const {
diff --git a/third_party/blink/renderer/core/page/page_visibility_observer.h b/third_party/blink/renderer/core/page/page_visibility_observer.h index 5c8b5912ea..26aee047 100644 --- a/third_party/blink/renderer/core/page/page_visibility_observer.h +++ b/third_party/blink/renderer/core/page/page_visibility_observer.h
@@ -39,7 +39,7 @@ virtual void PageVisibilityChanged() = 0; // Call before clearing an observer list. - void ObserverSetWillBeCleared(); + void ObserverListWillBeCleared(); Page* GetPage() const { return page_; } void SetPage(Page*);
diff --git a/third_party/blink/renderer/core/page/scrolling/main_thread_scrolling_reasons_test.cc b/third_party/blink/renderer/core/page/scrolling/main_thread_scrolling_reasons_test.cc index 5b47884..a6f85a4b 100644 --- a/third_party/blink/renderer/core/page/scrolling/main_thread_scrolling_reasons_test.cc +++ b/third_party/blink/renderer/core/page/scrolling/main_thread_scrolling_reasons_test.cc
@@ -397,13 +397,10 @@ cc::MainThreadScrollingReason::kCantPaintScrollingBackgroundAndLCDText); } -#if 0 -// TODO(crbug.com/1113269): Temporarily disabled. TEST_F(NonCompositedMainThreadScrollingReasonsTest, ClipTest) { TestNonCompositedReasons("clip", cc::MainThreadScrollingReason::kNotScrollingOnMain); } -#endif TEST_F(NonCompositedMainThreadScrollingReasonsTest, ClipPathTest) { TestNonCompositedReasons(
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.cc b/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.cc index b930b3de0..5164e55 100644 --- a/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.cc +++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.cc
@@ -15,27 +15,31 @@ constexpr int kExactTextMaxChars = 300; constexpr int kNoContextMinChars = 20; -TextFragmentSelectorGenerator::TextFragmentSelectorGenerator( - LocalFrame* frame, - base::OnceCallback<void(const TextFragmentSelector&)> callback) - : frame_(frame), callback_(std::move(callback)) {} - -// TextFragmentSelectorGenerator is responsible for generating text fragment -// selectors that have a unique match. -void TextFragmentSelectorGenerator::GenerateSelector( +void TextFragmentSelectorGenerator::UpdateSelection( + LocalFrame* selection_frame, const EphemeralRangeInFlatTree& selection_range) { + selection_frame_ = selection_frame; + selection_range_ = MakeGarbageCollected<Range>( + selection_range.GetDocument(), + ToPositionInDOMTree(selection_range.StartPosition()), + ToPositionInDOMTree(selection_range.EndPosition())); +} + +void TextFragmentSelectorGenerator::GenerateSelector() { + EphemeralRangeInFlatTree ephemeral_range(selection_range_); + const TextFragmentSelector kInvalidSelector( TextFragmentSelector::SelectorType::kInvalid); Node& start_first_block_ancestor = FindBuffer::GetFirstBlockLevelAncestorInclusive( - *selection_range.StartPosition().AnchorNode()); + *ephemeral_range.StartPosition().AnchorNode()); Node& end_first_block_ancestor = FindBuffer::GetFirstBlockLevelAncestorInclusive( - *selection_range.EndPosition().AnchorNode()); + *ephemeral_range.EndPosition().AnchorNode()); if (!start_first_block_ancestor.isSameNode(&end_first_block_ancestor)) - std::move(callback_).Run(kInvalidSelector); + NotifySelectorReady(kInvalidSelector); // TODO(gayane): If same node, need to check if start and end are interrupted // by a block. Example: <div>start of the selection <div> sub block </div>end @@ -43,16 +47,16 @@ // TODO(gayane): Move selection start and end to contain full words. - String selected_text = PlainText(selection_range); + String selected_text = PlainText(ephemeral_range); if (selected_text.length() < kNoContextMinChars || selected_text.length() > kExactTextMaxChars) - std::move(callback_).Run(kInvalidSelector); + NotifySelectorReady(kInvalidSelector); selector_ = std::make_unique<TextFragmentSelector>( TextFragmentSelector::SelectorType::kExact, selected_text, "", "", ""); TextFragmentFinder finder(*this, *selector_); - finder.FindMatch(*frame_->GetDocument()); + finder.FindMatch(*selection_frame_->GetDocument()); } void TextFragmentSelectorGenerator::DidFindMatch( @@ -60,16 +64,36 @@ const TextFragmentAnchorMetrics::Match match_metrics, bool is_unique) { if (is_unique) { - std::move(callback_).Run(*selector_); + NotifySelectorReady(*selector_); } else { // TODO(gayane): Should add more range and/or context. - std::move(callback_).Run( + NotifySelectorReady( TextFragmentSelector(TextFragmentSelector::SelectorType::kInvalid)); } } +void TextFragmentSelectorGenerator::SetCallbackForTesting( + base::OnceCallback<void(const TextFragmentSelector&)> callback) { + callback_for_tests_ = std::move(callback); +} + +void TextFragmentSelectorGenerator::NotifySelectorReady( + const TextFragmentSelector& selector) { + if (!callback_for_tests_.is_null()) + std::move(callback_for_tests_).Run(selector); +} + +void TextFragmentSelectorGenerator::DocumentDetached(Document* document) { + if (selection_range_ && selection_range_->OwnerDocument() == *document) { + selection_range_->Dispose(); + selection_range_ = nullptr; + selection_frame_ = nullptr; + } +} + void TextFragmentSelectorGenerator::Trace(Visitor* visitor) const { - visitor->Trace(frame_); + visitor->Trace(selection_frame_); + visitor->Trace(selection_range_); } } // namespace blink
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.h b/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.h index 2ee1620..18220769 100644 --- a/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.h +++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.h
@@ -13,28 +13,48 @@ class LocalFrame; +// TextFragmentSelectorGenerator is responsible for generating text fragment +// selectors for the user selected text according to spec in +// https://github.com/WICG/scroll-to-text-fragment#proposed-solution. +// Generated selectors would be later used to highlight the same +// text if successfully parsed by |TextFragmentAnchor |. Generation will be +// triggered when users request "link to text" for the selected text. class CORE_EXPORT TextFragmentSelectorGenerator final : public GarbageCollected<TextFragmentSelectorGenerator>, public TextFragmentFinder::Client { public: - TextFragmentSelectorGenerator( - LocalFrame* frame, - base::OnceCallback<void(const TextFragmentSelector&)> callback); + explicit TextFragmentSelectorGenerator() = default; - void GenerateSelector(const EphemeralRangeInFlatTree& selection_range); + // Sets the frame and range of the current selection. + void UpdateSelection(LocalFrame* selection_frame, + const EphemeralRangeInFlatTree& selection_range); + + // Generates selector for current selection. + void GenerateSelector(); // TextFragmentFinder::Client interface void DidFindMatch(const EphemeralRangeInFlatTree& match, const TextFragmentAnchorMetrics::Match match_metrics, bool is_unique) override; + // Sets the callback used for notifying test results of |GenerateSelector|. + void SetCallbackForTesting( + base::OnceCallback<void(const TextFragmentSelector&)> callback); + + // Notifies the results of |GenerateSelector|. + void NotifySelectorReady(const TextFragmentSelector& selector); + + void DocumentDetached(Document* document); + void Trace(Visitor*) const; private: - Member<LocalFrame> frame_; - base::OnceCallback<void(const TextFragmentSelector&)> callback_; + Member<LocalFrame> selection_frame_; + Member<Range> selection_range_; std::unique_ptr<TextFragmentSelector> selector_; + base::OnceCallback<void(const TextFragmentSelector&)> callback_for_tests_; + DISALLOW_COPY_AND_ASSIGN(TextFragmentSelectorGenerator); };
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator_test.cc b/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator_test.cc index 2662eeb4..ddb466f7 100644 --- a/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator_test.cc +++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator_test.cc
@@ -41,10 +41,13 @@ callback_called = true; }); - TextFragmentSelectorGenerator generator(GetDocument().GetFrame(), - std::move(callback)); - generator.GenerateSelector( + TextFragmentSelectorGenerator generator; + generator.UpdateSelection( + GetDocument().GetFrame(), ToEphemeralRangeInFlatTree(EphemeralRange(selected_start, selected_end))); + generator.SetCallbackForTesting(std::move(callback)); + generator.GenerateSelector(); + EXPECT_TRUE(callback_called); } @@ -69,10 +72,13 @@ callback_called = true; }); - TextFragmentSelectorGenerator generator(GetDocument().GetFrame(), - std::move(callback)); - generator.GenerateSelector( + TextFragmentSelectorGenerator generator; + generator.UpdateSelection( + GetDocument().GetFrame(), ToEphemeralRangeInFlatTree(EphemeralRange(selected_start, selected_end))); + generator.SetCallbackForTesting(std::move(callback)); + generator.GenerateSelector(); + EXPECT_TRUE(callback_called); } @@ -96,10 +102,13 @@ callback_called = true; }); - TextFragmentSelectorGenerator generator(GetDocument().GetFrame(), - std::move(callback)); - generator.GenerateSelector( + TextFragmentSelectorGenerator generator; + generator.UpdateSelection( + GetDocument().GetFrame(), ToEphemeralRangeInFlatTree(EphemeralRange(selected_start, selected_end))); + generator.SetCallbackForTesting(std::move(callback)); + generator.GenerateSelector(); + EXPECT_TRUE(callback_called); } @@ -125,10 +134,13 @@ callback_called = true; }); - TextFragmentSelectorGenerator generator(GetDocument().GetFrame(), - std::move(callback)); - generator.GenerateSelector( + TextFragmentSelectorGenerator generator; + generator.UpdateSelection( + GetDocument().GetFrame(), ToEphemeralRangeInFlatTree(EphemeralRange(selected_start, selected_end))); + generator.SetCallbackForTesting(std::move(callback)); + generator.GenerateSelector(); + EXPECT_TRUE(callback_called); }
diff --git a/third_party/blink/renderer/core/paint/paint_layer.cc b/third_party/blink/renderer/core/paint/paint_layer.cc index d9fffdb..3512595e 100644 --- a/third_party/blink/renderer/core/paint/paint_layer.cc +++ b/third_party/blink/renderer/core/paint/paint_layer.cc
@@ -165,7 +165,6 @@ previous_paint_result_(kFullyPainted), needs_paint_phase_descendant_outlines_(false), needs_paint_phase_float_(false), - has_descendant_with_clip_path_(false), has_non_isolated_descendant_with_blend_mode_(false), has_fixed_position_descendant_(false), has_sticky_position_descendant_(false), @@ -612,7 +611,6 @@ has_non_isolated_descendant_with_blend_mode_; has_visible_descendant_ = false; has_non_isolated_descendant_with_blend_mode_ = false; - has_descendant_with_clip_path_ = false; has_fixed_position_descendant_ = false; has_sticky_position_descendant_ = false; has_non_contained_absolute_position_descendant_ = false; @@ -646,9 +644,6 @@ child->HasNonIsolatedDescendantWithBlendMode()) || child_style.HasBlendMode(); - has_descendant_with_clip_path_ |= child->HasDescendantWithClipPath() || - child->GetLayoutObject().HasClipPath(); - has_fixed_position_descendant_ |= child->HasFixedPositionDescendant() || child_style.GetPosition() == EPosition::kFixed;
diff --git a/third_party/blink/renderer/core/paint/paint_layer.h b/third_party/blink/renderer/core/paint/paint_layer.h index 5d7ab6210..3b65bd57 100644 --- a/third_party/blink/renderer/core/paint/paint_layer.h +++ b/third_party/blink/renderer/core/paint/paint_layer.h
@@ -895,11 +895,6 @@ const PaintLayer* MaskAncestor() const { return GetAncestorDependentCompositingInputs().mask_ancestor; } - // TODO(crbug.com/1113269): Temporary. - bool HasDescendantWithClipPath() const { - DCHECK(!needs_descendant_dependent_flags_update_); - return has_descendant_with_clip_path_; - } bool HasFixedPositionDescendant() const { DCHECK(!needs_descendant_dependent_flags_update_); return has_fixed_position_descendant_; @@ -1353,9 +1348,6 @@ unsigned needs_paint_phase_descendant_outlines_ : 1; unsigned needs_paint_phase_float_ : 1; - // TODO(crbug.com/1113269): Temporary. - unsigned has_descendant_with_clip_path_ : 1; - // These bitfields are part of ancestor/descendant dependent compositing // inputs. unsigned has_non_isolated_descendant_with_blend_mode_ : 1;
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc index a12399b..116e300 100644 --- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc +++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
@@ -2616,15 +2616,6 @@ } } - // TODO(crbug.com/1113269): Temporary. - if (box->HasClip() || layer_->HasDescendantWithClipPath() || - !!layer_->ClipPathAncestor()) { - non_composited_main_thread_scrolling_reasons_ |= - // Just a random flag to disable composited scrolling. - cc::MainThreadScrollingReason::kCantPaintScrollingBackgroundAndLCDText; - needs_composited_scrolling = false; - } - DCHECK(!(non_composited_main_thread_scrolling_reasons_ & ~cc::MainThreadScrollingReason::kNonCompositedReasons)); return needs_composited_scrolling;
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area_test.cc b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area_test.cc index 7b3bed8..17be9e21 100644 --- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area_test.cc +++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area_test.cc
@@ -319,8 +319,7 @@ GetBackgroundPaintLocation("scroller15")); // css-clip doesn't affect background paint location. - // TODO(crbug.com/1113269): Temporary. - EXPECT_EQ(kBackgroundPaintInGraphicsLayer, + EXPECT_EQ(kBackgroundPaintInScrollingContents, GetBackgroundPaintLocation("css-clip")); // #scroller17 can only be painted once as it is translucent, and it must
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn index 2f42d33..c0b7fd4 100644 --- a/third_party/blink/renderer/platform/BUILD.gn +++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -1136,7 +1136,7 @@ "graphics/video_frame_submitter.h", "graphics/web_graphics_context_3d_provider_wrapper.cc", "graphics/web_graphics_context_3d_provider_wrapper.h", - "heap_observer_set.h", + "heap_observer_list.h", "image-decoders/bmp/bmp_image_decoder.cc", "image-decoders/bmp/bmp_image_decoder.h", "image-decoders/bmp/bmp_image_reader.cc", @@ -1935,7 +1935,7 @@ "graphics/placeholder_image_test.cc", "graphics/static_bitmap_image_test.cc", "graphics/video_frame_submitter_test.cc", - "heap_observer_set_test.cc", + "heap_observer_list_test.cc", "image-decoders/bmp/bmp_image_decoder_test.cc", "image-decoders/fast_shared_buffer_reader_test.cc", "image-decoders/gif/gif_image_decoder_test.cc",
diff --git a/third_party/blink/renderer/platform/context_lifecycle_observer.cc b/third_party/blink/renderer/platform/context_lifecycle_observer.cc index 9beb179..e0b406f 100644 --- a/third_party/blink/renderer/platform/context_lifecycle_observer.cc +++ b/third_party/blink/renderer/platform/context_lifecycle_observer.cc
@@ -8,7 +8,7 @@ namespace blink { -void ContextLifecycleObserver::ObserverSetWillBeCleared() { +void ContextLifecycleObserver::ObserverListWillBeCleared() { notifier_ = nullptr; }
diff --git a/third_party/blink/renderer/platform/context_lifecycle_observer.h b/third_party/blink/renderer/platform/context_lifecycle_observer.h index bc034a9..b4a4198 100644 --- a/third_party/blink/renderer/platform/context_lifecycle_observer.h +++ b/third_party/blink/renderer/platform/context_lifecycle_observer.h
@@ -18,7 +18,7 @@ virtual void ContextDestroyed() = 0; // Call before clearing an observer list. - void ObserverSetWillBeCleared(); + void ObserverListWillBeCleared(); ContextLifecycleNotifier* GetContextLifecycleNotifier() const { return notifier_;
diff --git a/third_party/blink/renderer/platform/heap_observer_set.h b/third_party/blink/renderer/platform/heap_observer_list.h similarity index 83% rename from third_party/blink/renderer/platform/heap_observer_set.h rename to third_party/blink/renderer/platform/heap_observer_list.h index 87e7db7..ac3baf9 100644 --- a/third_party/blink/renderer/platform/heap_observer_set.h +++ b/third_party/blink/renderer/platform/heap_observer_list.h
@@ -2,18 +2,18 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_OBSERVER_SET_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_OBSERVER_SET_H_ +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_OBSERVER_LIST_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_OBSERVER_LIST_H_ #include "base/auto_reset.h" #include "third_party/blink/renderer/platform/heap/handle.h" namespace blink { -// A set of observers. Ensures list is not mutated while iterating. Observers +// A list of observers. Ensures list is not mutated while iterating. Observers // are not retained. template <class ObserverType> -class PLATFORM_EXPORT HeapObserverSet { +class PLATFORM_EXPORT HeapObserverList { DISALLOW_NEW(); public: @@ -49,8 +49,7 @@ observers_.clear(); } - // Safely iterate over the registered lifecycle observers in an unpredictable - // order. + // Safely iterate over the registered lifecycle observers. // // Adding or removing observers is not allowed during iteration. The callable // will only be called synchronously inside ForEachObserver(). @@ -70,7 +69,7 @@ void Trace(Visitor* visitor) const { visitor->Trace(observers_); } private: - using ObserverSet = HeapHashSet<WeakMember<ObserverType>>; + using ObserverSet = HeapLinkedHashSet<WeakMember<ObserverType>>; // TODO(keishi): Clean up iteration state once transition from // LifecycleObserver is complete. @@ -89,4 +88,4 @@ } // namespace blink -#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_OBSERVER_SET_H_ +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_OBSERVER_LIST_H_
diff --git a/third_party/blink/renderer/platform/heap_observer_set_test.cc b/third_party/blink/renderer/platform/heap_observer_list_test.cc similarity index 69% rename from third_party/blink/renderer/platform/heap_observer_set_test.cc rename to third_party/blink/renderer/platform/heap_observer_list_test.cc index 04c5b14..225ac271 100644 --- a/third_party/blink/renderer/platform/heap_observer_set_test.cc +++ b/third_party/blink/renderer/platform/heap_observer_list_test.cc
@@ -24,7 +24,7 @@ * */ -#include "third_party/blink/renderer/platform/heap_observer_set.h" +#include "third_party/blink/renderer/platform/heap_observer_list.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/renderer/platform/heap/persistent.h" #include "third_party/blink/renderer/platform/heap/thread_state.h" @@ -37,12 +37,12 @@ public: TestingNotifier() = default; - HeapObserverSet<TestingObserver>& ObserverList() { return observer_list_; } + HeapObserverList<TestingObserver>& ObserverList() { return observer_list_; } void Trace(Visitor* visitor) const { visitor->Trace(observer_list_); } private: - HeapObserverSet<TestingObserver> observer_list_; + HeapObserverList<TestingObserver> observer_list_; }; class TestingObserver final : public GarbageCollected<TestingObserver> { @@ -56,12 +56,12 @@ int count_ = 0; }; -void Notify(HeapObserverSet<TestingObserver>& observer_list) { +void Notify(HeapObserverList<TestingObserver>& observer_list) { observer_list.ForEachObserver( [](TestingObserver* observer) { observer->OnNotification(); }); } -TEST(HeapObserverSetTest, AddRemove) { +TEST(HeapObserverListTest, AddRemove) { Persistent<TestingNotifier> notifier = MakeGarbageCollected<TestingNotifier>(); Persistent<TestingObserver> observer = @@ -79,7 +79,7 @@ EXPECT_EQ(observer->Count(), 1); } -TEST(HeapObserverSetTest, HasObserver) { +TEST(HeapObserverListTest, HasObserver) { Persistent<TestingNotifier> notifier = MakeGarbageCollected<TestingNotifier>(); Persistent<TestingObserver> observer = @@ -94,7 +94,7 @@ EXPECT_FALSE(notifier->ObserverList().HasObserver(observer.Get())); } -TEST(HeapObserverSetTest, GarbageCollect) { +TEST(HeapObserverListTest, GarbageCollect) { Persistent<TestingNotifier> notifier = MakeGarbageCollected<TestingNotifier>(); Persistent<TestingObserver> observer = @@ -111,7 +111,7 @@ EXPECT_EQ(weak_ref.Get(), nullptr); } -TEST(HeapObserverSetTest, IsIteratingOverObservers) { +TEST(HeapObserverListTest, IsIteratingOverObservers) { Persistent<TestingNotifier> notifier = MakeGarbageCollected<TestingNotifier>(); Persistent<TestingObserver> observer = @@ -124,4 +124,42 @@ }); } +TEST(HeapObserverListTest, ForEachObserverOrder) { + Persistent<TestingNotifier> notifier = + MakeGarbageCollected<TestingNotifier>(); + Persistent<TestingObserver> observer1 = + MakeGarbageCollected<TestingObserver>(); + Persistent<TestingObserver> observer2 = + MakeGarbageCollected<TestingObserver>(); + + HeapVector<Member<TestingObserver>> seen_observers; + + notifier->ObserverList().AddObserver(observer1); + notifier->ObserverList().AddObserver(observer2); + notifier->ObserverList().ForEachObserver( + [&](TestingObserver* observer) { seen_observers.push_back(observer); }); + + ASSERT_EQ(2u, seen_observers.size()); + EXPECT_EQ(observer1.Get(), seen_observers[0].Get()); + EXPECT_EQ(observer2.Get(), seen_observers[1].Get()); + + seen_observers.clear(); + + notifier->ObserverList().RemoveObserver(observer1); + notifier->ObserverList().AddObserver(observer1); + notifier->ObserverList().ForEachObserver( + [&](TestingObserver* observer) { seen_observers.push_back(observer); }); + + ASSERT_EQ(2u, seen_observers.size()); + EXPECT_EQ(observer2.Get(), seen_observers[0].Get()); + EXPECT_EQ(observer1.Get(), seen_observers[1].Get()); + + seen_observers.clear(); + + notifier->ObserverList().Clear(); + notifier->ObserverList().ForEachObserver( + [&](TestingObserver* observer) { seen_observers.push_back(observer); }); + ASSERT_EQ(0u, seen_observers.size()); +} + } // namespace blink
diff --git a/third_party/blink/renderer/platform/mojo/DEPS b/third_party/blink/renderer/platform/mojo/DEPS index 5a7db27e..2748153 100644 --- a/third_party/blink/renderer/platform/mojo/DEPS +++ b/third_party/blink/renderer/platform/mojo/DEPS
@@ -22,7 +22,7 @@ "+third_party/blink/renderer/platform/wtf", "+third_party/blink/renderer/platform/context_lifecycle_observer.h", "+third_party/blink/renderer/platform/context_lifecycle_notifier.h", - "+third_party/blink/renderer/platform/heap_observer_set.h", + "+third_party/blink/renderer/platform/heap_observer_list.h", "+third_party/blink/renderer/platform/heap", ]
diff --git a/third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver_set_test.cc b/third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver_set_test.cc index 3dc9d88..ce48d2e 100644 --- a/third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver_set_test.cc +++ b/third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver_set_test.cc
@@ -15,7 +15,7 @@ #include "third_party/blink/renderer/platform/context_lifecycle_notifier.h" #include "third_party/blink/renderer/platform/heap/heap_test_utilities.h" #include "third_party/blink/renderer/platform/heap/persistent.h" -#include "third_party/blink/renderer/platform/heap_observer_set.h" +#include "third_party/blink/renderer/platform/heap_observer_list.h" #include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h" namespace blink { @@ -49,7 +49,7 @@ } private: - HeapObserverSet<ContextLifecycleObserver> observers_; + HeapObserverList<ContextLifecycleObserver> observers_; }; template <HeapMojoWrapperMode Mode>
diff --git a/third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver_test.cc b/third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver_test.cc index 95811f1..7972a26 100644 --- a/third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver_test.cc +++ b/third_party/blink/renderer/platform/mojo/heap_mojo_associated_receiver_test.cc
@@ -10,7 +10,7 @@ #include "third_party/blink/renderer/platform/context_lifecycle_notifier.h" #include "third_party/blink/renderer/platform/heap/heap_test_utilities.h" #include "third_party/blink/renderer/platform/heap/persistent.h" -#include "third_party/blink/renderer/platform/heap_observer_set.h" +#include "third_party/blink/renderer/platform/heap_observer_list.h" #include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h" namespace blink { @@ -41,7 +41,7 @@ } private: - HeapObserverSet<ContextLifecycleObserver> observers_; + HeapObserverList<ContextLifecycleObserver> observers_; }; template <HeapMojoWrapperMode Mode>
diff --git a/third_party/blink/renderer/platform/mojo/heap_mojo_associated_remote_test.cc b/third_party/blink/renderer/platform/mojo/heap_mojo_associated_remote_test.cc index f8b016d..349c21b 100644 --- a/third_party/blink/renderer/platform/mojo/heap_mojo_associated_remote_test.cc +++ b/third_party/blink/renderer/platform/mojo/heap_mojo_associated_remote_test.cc
@@ -10,7 +10,7 @@ #include "third_party/blink/renderer/platform/context_lifecycle_notifier.h" #include "third_party/blink/renderer/platform/heap/heap_test_utilities.h" #include "third_party/blink/renderer/platform/heap/persistent.h" -#include "third_party/blink/renderer/platform/heap_observer_set.h" +#include "third_party/blink/renderer/platform/heap_observer_list.h" #include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h" namespace blink { @@ -41,7 +41,7 @@ } private: - HeapObserverSet<ContextLifecycleObserver> observers_; + HeapObserverList<ContextLifecycleObserver> observers_; }; class ServiceImpl : public sample::blink::Service {
diff --git a/third_party/blink/renderer/platform/mojo/heap_mojo_receiver_set_test.cc b/third_party/blink/renderer/platform/mojo/heap_mojo_receiver_set_test.cc index c7fb431..56c1394 100644 --- a/third_party/blink/renderer/platform/mojo/heap_mojo_receiver_set_test.cc +++ b/third_party/blink/renderer/platform/mojo/heap_mojo_receiver_set_test.cc
@@ -15,7 +15,7 @@ #include "third_party/blink/renderer/platform/context_lifecycle_notifier.h" #include "third_party/blink/renderer/platform/heap/heap_test_utilities.h" #include "third_party/blink/renderer/platform/heap/persistent.h" -#include "third_party/blink/renderer/platform/heap_observer_set.h" +#include "third_party/blink/renderer/platform/heap_observer_list.h" #include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h" namespace blink { @@ -48,7 +48,7 @@ } private: - HeapObserverSet<ContextLifecycleObserver> observers_; + HeapObserverList<ContextLifecycleObserver> observers_; }; template <HeapMojoWrapperMode Mode, typename ContextType>
diff --git a/third_party/blink/renderer/platform/mojo/heap_mojo_receiver_test.cc b/third_party/blink/renderer/platform/mojo/heap_mojo_receiver_test.cc index 94390be..f2a4475 100644 --- a/third_party/blink/renderer/platform/mojo/heap_mojo_receiver_test.cc +++ b/third_party/blink/renderer/platform/mojo/heap_mojo_receiver_test.cc
@@ -11,7 +11,7 @@ #include "third_party/blink/renderer/platform/context_lifecycle_notifier.h" #include "third_party/blink/renderer/platform/heap/heap_test_utilities.h" #include "third_party/blink/renderer/platform/heap/persistent.h" -#include "third_party/blink/renderer/platform/heap_observer_set.h" +#include "third_party/blink/renderer/platform/heap_observer_list.h" #include "third_party/blink/renderer/platform/mojo/features.h" #include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h" @@ -45,7 +45,7 @@ } private: - HeapObserverSet<ContextLifecycleObserver> observers_; + HeapObserverList<ContextLifecycleObserver> observers_; }; template <HeapMojoWrapperMode Mode>
diff --git a/third_party/blink/renderer/platform/mojo/heap_mojo_remote_test.cc b/third_party/blink/renderer/platform/mojo/heap_mojo_remote_test.cc index 97b764b5..7547cb9 100644 --- a/third_party/blink/renderer/platform/mojo/heap_mojo_remote_test.cc +++ b/third_party/blink/renderer/platform/mojo/heap_mojo_remote_test.cc
@@ -11,7 +11,7 @@ #include "third_party/blink/renderer/platform/context_lifecycle_notifier.h" #include "third_party/blink/renderer/platform/heap/heap_test_utilities.h" #include "third_party/blink/renderer/platform/heap/persistent.h" -#include "third_party/blink/renderer/platform/heap_observer_set.h" +#include "third_party/blink/renderer/platform/heap_observer_list.h" #include "third_party/blink/renderer/platform/mojo/features.h" #include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h" @@ -45,7 +45,7 @@ } private: - HeapObserverSet<ContextLifecycleObserver> observers_; + HeapObserverList<ContextLifecycleObserver> observers_; }; class ServiceImpl : public sample::blink::Service {
diff --git a/third_party/blink/renderer/platform/mojo/heap_mojo_unique_receiver_set_test.cc b/third_party/blink/renderer/platform/mojo/heap_mojo_unique_receiver_set_test.cc index f3fe302..d9b2821 100644 --- a/third_party/blink/renderer/platform/mojo/heap_mojo_unique_receiver_set_test.cc +++ b/third_party/blink/renderer/platform/mojo/heap_mojo_unique_receiver_set_test.cc
@@ -10,7 +10,7 @@ #include "third_party/blink/renderer/platform/context_lifecycle_notifier.h" #include "third_party/blink/renderer/platform/heap/heap_test_utilities.h" #include "third_party/blink/renderer/platform/heap/persistent.h" -#include "third_party/blink/renderer/platform/heap_observer_set.h" +#include "third_party/blink/renderer/platform/heap_observer_list.h" #include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h" namespace blink { @@ -43,7 +43,7 @@ } private: - HeapObserverSet<ContextLifecycleObserver> observers_; + HeapObserverList<ContextLifecycleObserver> observers_; }; template <HeapMojoWrapperMode Mode>
diff --git a/third_party/blink/tools/blinkpy/w3c/common.py b/third_party/blink/tools/blinkpy/w3c/common.py index 845aac5..24acf6d 100644 --- a/third_party/blink/tools/blinkpy/w3c/common.py +++ b/third_party/blink/tools/blinkpy/w3c/common.py
@@ -67,6 +67,37 @@ return filename.endswith('-expected.txt') +def is_disallowed_ini(filename): + """Checks whether the file is a disallowed (.ini) file. + + This is primarily intended to skip WPT metadata .ini files, which are used + in WPT to set expected statuses for tests. Chromium maintains its own list + of such files and we don't want those to be shared with upstream. + + There are a few .ini files that we do allow, which are mostly configuration + files for wptrunner. + + Args: + filename: the basename of the file to check + """ + if not filename.endswith('.ini'): + return False + allowed_inis = [ + # Configuration for mypy support + 'mypy.ini', + # Configuration of wpt lint + 'py27-flake8.ini', + 'py3-flake8.ini', + # Configuration of wpt framework unit tests + 'pytest.ini', + 'tox.ini', + # Contains default locations of tests and manifest for wptrunner. + # Required for wptrunner to work. + 'wptrunner.default.ini', + ] + return filename not in allowed_inis + + def is_basename_skipped(basename): """Checks whether to skip (not sync) a file based on its basename. @@ -81,7 +112,7 @@ 'DIR_METADATA', # https://crbug.com/1103374 ] return (basename in skipped_basenames or is_testharness_baseline(basename) - or basename.startswith('.')) + or basename.startswith('.') or is_disallowed_ini(basename)) def is_file_exportable(path):
diff --git a/third_party/blink/tools/blinkpy/w3c/common_unittest.py b/third_party/blink/tools/blinkpy/w3c/common_unittest.py index 697cd2fb..4e82383c 100644 --- a/third_party/blink/tools/blinkpy/w3c/common_unittest.py +++ b/third_party/blink/tools/blinkpy/w3c/common_unittest.py
@@ -8,8 +8,8 @@ from blinkpy.common.host_mock import MockHost from blinkpy.common.path_finder import RELATIVE_WEB_TESTS from blinkpy.w3c.common import (read_credentials, is_testharness_baseline, - is_basename_skipped, is_file_exportable, - CHROMIUM_WPT_DIR) + is_disallowed_ini, is_basename_skipped, + is_file_exportable, CHROMIUM_WPT_DIR) class CommonTest(unittest.TestCase): @@ -94,6 +94,12 @@ self.assertTrue(is_basename_skipped('.gitignore')) self.assertFalse(is_basename_skipped('something.json')) + def test_is_disallowed_ini(self): + self.assertFalse(is_disallowed_ini('tox.ini')) + self.assertFalse(is_disallowed_ini("wptrunner.default.ini")) + self.assertTrue(is_disallowed_ini('test.html.ini')) + self.assertTrue(is_disallowed_ini('__dir__.ini')) + def test_is_basename_skipped_asserts_basename(self): with self.assertRaises(AssertionError): is_basename_skipped('third_party/fake/OWNERS') @@ -109,6 +115,16 @@ self.assertFalse(is_file_exportable(CHROMIUM_WPT_DIR + 'dom/OWNERS')) self.assertFalse( is_file_exportable(CHROMIUM_WPT_DIR + 'dom/DIR_METADATA')) + self.assertTrue( + is_file_exportable(CHROMIUM_WPT_DIR + + 'tools/wptrunner/wptrunner.default.ini')) + self.assertFalse( + is_file_exportable( + CHROMIUM_WPT_DIR + + 'infrastructure/metadata/infrastructure/expected-fail/timeout.html.ini' + )) + self.assertFalse( + is_file_exportable(CHROMIUM_WPT_DIR + 'dom/historical.html.ini')) def test_is_file_exportable_asserts_path(self): # Rejects basenames.
diff --git a/third_party/blink/tools/wpt_import.py.vpython b/third_party/blink/tools/wpt_import.py.vpython index 57fdf480..7360db2a 100644 --- a/third_party/blink/tools/wpt_import.py.vpython +++ b/third_party/blink/tools/wpt_import.py.vpython
@@ -1,5 +1,5 @@ wheel: < - name: "infra/python/wheels/google_api_python_client-py2_py3" + name: "infra/python/wheels/google-api-python-client-py2_py3" version: "version:1.6.2" >
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index 76f29eb..a36ed559 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -2707,12 +2707,6 @@ crbug.com/626703 [ Linux ] external/wpt/streams/transform-streams/patched-global.any.sharedworker.html [ Timeout ] crbug.com/626703 [ Mac ] external/wpt/streams/transform-streams/patched-global.any.sharedworker.html [ Timeout ] crbug.com/626703 [ Win ] external/wpt/streams/transform-streams/patched-global.any.sharedworker.html [ Timeout ] -crbug.com/626703 [ Linux ] external/wpt/css/css-ui/appearance-button-002.tentative.html [ Failure ] -crbug.com/626703 [ Mac ] external/wpt/css/css-ui/appearance-button-002.tentative.html [ Failure ] -crbug.com/626703 [ Win ] external/wpt/css/css-ui/appearance-button-002.tentative.html [ Failure ] -crbug.com/626703 [ Linux ] external/wpt/css/css-ui/webkit-appearance-button-002.tentative.html [ Failure ] -crbug.com/626703 [ Mac ] external/wpt/css/css-ui/webkit-appearance-button-002.tentative.html [ Failure ] -crbug.com/626703 [ Win ] external/wpt/css/css-ui/webkit-appearance-button-002.tentative.html [ Failure ] crbug.com/626703 [ Linux ] external/wpt/css/css-color/t422-rgba-a0.6-a.xht [ Failure ] crbug.com/626703 [ Linux ] external/wpt/css/css-color/t32-opacity-basic-0.6-a.xht [ Failure ] crbug.com/626703 [ Mac ] external/wpt/css/css-color/t32-opacity-basic-0.6-a.xht [ Failure ] @@ -3597,6 +3591,7 @@ crbug.com/759665 external/wpt/css/css-grid/animation/grid-template-rows-001.html [ Failure ] crbug.com/1018439 external/wpt/css/css-grid/grid-child-percent-basis-resize-1.html [ Failure ] crbug.com/935102 external/wpt/css/css-grid/layout-algorithm/grid-flex-track-intrinsic-sizes-002.html [ Failure ] +crbug.com/1116954 external/wpt/css/css-grid/layout-algorithm/grid-intrinsic-track-sizes-001.html [ Failure ] crbug.com/707359 [ Mac ] external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-003.html [ Failure ] crbug.com/707359 [ Mac ] external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-004.html [ Failure ] crbug.com/707359 [ Mac ] external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-horiz-004.html [ Failure ] @@ -4261,6 +4256,7 @@ crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-fit-content-percentage.html [ Failure ] crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-flex-track-intrinsic-sizes-001.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/external/wpt/css/css-grid/layout-algorithm/grid-intrinsic-track-sizes-001.html [ Failure ] crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-item-margin-auto-columns-rows-001.html [ Failure ] crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-item-margin-auto-columns-rows-vertical-lr-001.html [ Failure ] crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-item-margin-auto-columns-rows-vertical-rl-001.html [ Failure ] @@ -4707,7 +4703,8 @@ crbug.com/678493 http/tests/permissions/chromium/test-request-window.html [ Timeout Pass ] -crbug.com/747751 http/tests/devtools/application-panel/storage-view-reports-quota.js [ Pass Timeout ] +# TODO(petermarshall): Re-enable after landing devtools piechart changes. +crbug.com/747751 http/tests/devtools/application-panel/storage-view-reports-quota.js [ Failure Pass Timeout ] crbug.com/689781 external/wpt/media-source/mediasource-duration.html [ Failure Pass ] crbug.com/689781 [ Win ] http/tests/media/media-source/mediasource-duration.html [ Failure Pass ] @@ -5100,6 +5097,10 @@ crbug.com/919639 [ Fuchsia ] presentation/presentationconnectionavailableevent-ctor-mock.html [ Failure ] crbug.com/919639 [ Fuchsia ] webmidi/permission.html [ Failure ] +# These tests enforce that <select> with appearance:button should look like a button. +crbug.com/1108797 external/wpt/css/css-ui/appearance-button-002.tentative.html [ Failure ] +crbug.com/1108797 external/wpt/css/css-ui/webkit-appearance-button-002.tentative.html [ Failure ] + # These tests timeout when using Scenic ozone platform. crbug.com/1067477 [ Fuchsia ] compositing/sibling-positioning.html [ Skip ] crbug.com/1067477 [ Fuchsia ] css3/selectors3/html/css3-modsel-18.html [ Skip ] @@ -6637,11 +6638,6 @@ #Sheriff 2020-06-25 crbug.com/1010170 media/video-played-reset.html [ Pass Failure ] -# Temporarily disable tests to allow fixing webrtc error logging -crbug.com/1101699 external/wpt/webrtc/RTCPeerConnection-setLocalDescription-answer.html [ Pass Failure ] -crbug.com/1101699 external/wpt/webrtc/RTCPeerConnection-setLocalDescription-pranswer.html [ Pass Failure ] -crbug.com/1101699 virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html [ Pass Failure ] - # Sheriff 2020-07-07 # Additionally disabled on mac due to crbug.com/988248 crbug.com/1083302 media/controls/volumechange-muted-attribute.html [ Pass Failure ] @@ -6740,4 +6736,4 @@ crbug.com/1116681 [ Mac ] fast/frames/iframe-scaling-with-scroll.html [ Pass Failure ] # Sheriff 2020-08-17 -crbug.com/1069546 [ Mac ] compositing/layer-creation/overflow-scroll-overlap.html [ Pass Failure ] \ No newline at end of file +crbug.com/1069546 [ Mac ] compositing/layer-creation/overflow-scroll-overlap.html [ Pass Failure ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json index 97cfc52..d7aec6f4 100644 --- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json +++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -201439,7 +201439,7 @@ [] ], "cors.py": [ - "bc0c1089fe374958383aecd70d5da5a91a5b8037", + "6ed31f2cd7d1782f8b7267d646d3ba26ab1a2a6d", [] ], "eventsource-onmessage-realm.htm": [ @@ -216691,7 +216691,7 @@ [] ], "update_html5lib_tests.py": [ - "0bc21d31f74c237eeb3d0041af1f6eadd3717b12", + "e4f339a6053213645602b58c203b20b46a9b00cc", [] ] }, @@ -218816,7 +218816,7 @@ [] ], "uievents.idl": [ - "67405ebf118b4b584d9cc335918bc45eb3e5907b", + "f86525c2ea723a52b9647b90a2816baf14dec872", [] ], "url.idl": [ @@ -228729,19 +228729,19 @@ [] ], "tee.any-expected.txt": [ - "7fb3f0f3c3da685385830c599d2165be1212ff49", + "6b0a4ca49c45b4233492fc1e2290e93ff25c4839", [] ], "tee.any.serviceworker-expected.txt": [ - "7fb3f0f3c3da685385830c599d2165be1212ff49", + "6b0a4ca49c45b4233492fc1e2290e93ff25c4839", [] ], "tee.any.sharedworker-expected.txt": [ - "7fb3f0f3c3da685385830c599d2165be1212ff49", + "6b0a4ca49c45b4233492fc1e2290e93ff25c4839", [] ], "tee.any.worker-expected.txt": [ - "7fb3f0f3c3da685385830c599d2165be1212ff49", + "6b0a4ca49c45b4233492fc1e2290e93ff25c4839", [] ], "templated.any-expected.txt": [ @@ -230242,7 +230242,7 @@ ] }, "localpaths.py": [ - "93cff2b8e085b90d670d80f5598dcd77e512bad0", + "51aecea7712a2f90ab1778d62fe8b74d722785e6", [] ], "manifest": { @@ -236195,7 +236195,7 @@ [] ], "setup.py": [ - "ab96bd10357cd6b3022364d471e5cebf0cb652dd", + "a459e2c4714104830d667c33c7814ef3c50f567c", [] ], "tox.ini": [ @@ -236221,7 +236221,7 @@ [] ], "base.py": [ - "a027cf32610a49e61f4141bfb5fce5d051385b3e", + "99f6e5cff4c8b826d1390b482eb686da5915083c", [] ], "chrome.py": [ @@ -236253,7 +236253,7 @@ [] ], "firefox.py": [ - "fc5abf8b93cd24ed3dd46c4384dd7c94facce232", + "91384cb0addaeac640e94c8d55faa2ce394af783", [] ], "firefox_android.py": [ @@ -236273,15 +236273,15 @@ [] ], "sauce.py": [ - "3133716a6fe1f8df108ad3ba9a719cce9b057d3d", + "c57ac942ed4e7624a0a7d115df3a210aec5d9ee1", [] ], "servo.py": [ - "5b657993f1900cd34a1460c5bc3a9093fcc7f13c", + "b9476540ac7c53162e70669c4b7ba4883fd75f75", [] ], "servodriver.py": [ - "02b796b7560385cd00902bbfc1b361a542249f85", + "43794e41706d6ccc1f686655c8edeca95e3c4c62", [] ], "webkit.py": [ @@ -236294,11 +236294,11 @@ ] }, "config.py": [ - "e7f9d7b8cc987bfdfecda6548acf82d1be3a28d4", + "d46beb8e71db63e8fdb54ba939792350535b8ff9", [] ], "environment.py": [ - "65f82005f317f8614e5a2febc35a996b9b0c3871", + "e1812b8740a8c077db1101aedf292ba6ec3c488d", [] ], "executors": { @@ -236311,11 +236311,11 @@ [] ], "base.py": [ - "82496fcad9c9d46dbf04b81fbf60b2e1dcdd1045", + "e8a776b59356b6b8755fb60efeb57ecda8e2c6d1", [] ], "executorchrome.py": [ - "3ae318795f0b62468a6a8a991fa07b2a78e2743b", + "3a704754137f587bc7a134874193d2e2167c59c4", [] ], "executoredge.py": [ @@ -236331,7 +236331,7 @@ [] ], "executormarionette.py": [ - "1ba9f06aabc8cf10e91cf3aa92643562f05a1c1a", + "e0e6aba0f57853e863355a308ade56c24575da72", [] ], "executoropera.py": [ @@ -236343,7 +236343,7 @@ [] ], "executorselenium.py": [ - "1fa9953b36e14c3373a4ce1257ee7e19482ce1d4", + "82ab6f25560e67ee3a3877b6ee4af8b6cc200e3a", [] ], "executorservo.py": [ @@ -236351,11 +236351,11 @@ [] ], "executorservodriver.py": [ - "071b506f9af90f7ea46e28ae8814a83996ed9f4a", + "dbed2fedbdf1c686dda800bf182fbfc2ee6e0dd2", [] ], "executorwebdriver.py": [ - "695b16b9cca19525a0656f66da45fe66c599fb8b", + "e0414669372e076fc63fec4c8c65584f9b00f813", [] ], "executorwebkit.py": [ @@ -236414,7 +236414,7 @@ [] ], "font.py": [ - "6226fc66fedf2afc96b5110f3524b00d185cc538", + "910358f51596f9e392f81ef156cdd0b101983b7b", [] ], "formatters": { @@ -236458,7 +236458,7 @@ [] ], "metadata.py": [ - "df31ac40de8b8ee70813c3b2e03d1865f672e29d", + "ab8d4740f3fcc2b186a68d57758d46db47ad97ab", [] ], "print_reftest_runner.html": [ @@ -236523,11 +236523,11 @@ [] ], "state.py": [ - "f8a83525cbd4706bdfbc99a518d2bac123d34e96", + "bdb23fed99e19fa55abeec7202a3a1b471bedc03", [] ], "sync.py": [ - "c3da2098d3c55dd5a79fa662a112335a03fcaa33", + "f878752f4514ae9cce5c74a5f994fc5e71eac826", [] ], "tree.py": [ @@ -236618,11 +236618,11 @@ } }, "wptrunner.py": [ - "a397fd6f0b857e02b6eccd003e7b0a4541e0955b", + "f033205a00b88a6ab2521c5e1e6df51095cf4801", [] ], "wpttest.py": [ - "3750defa6a13de88d4e73f485b51b069db085c4b", + "c670179c81a0666162d5f959b311fda58786c9e3", [] ] }, @@ -236658,7 +236658,7 @@ [] ], "handlers.py": [ - "d315b0212c48aae4f2c805f3f055cd8d1096088b", + "2cc25e2c21cea4ed6826a94320d452c0d386fe2b", [] ], "logger.py": [ @@ -239426,7 +239426,7 @@ [] ], "RTCPeerConnection-setLocalDescription-answer-expected.txt": [ - "cdeaf58bf0684d693b036ee241a7f544954cb749", + "550acfb3a31e64b533be233f27ea8696999170a5", [] ], "RTCPeerConnection-setLocalDescription-offer-expected.txt": [ @@ -239438,7 +239438,7 @@ [] ], "RTCPeerConnection-setLocalDescription-pranswer-expected.txt": [ - "9634cee46c6f82b0b500c16c25a158ee6ac9672f", + "f514bf7310bbe53c48d4c4001fd4ce455bd68f31", [] ], "RTCPeerConnection-setLocalDescription-rollback-expected.txt": [ @@ -243844,25 +243844,25 @@ ], "auth1": { "auth.py": [ - "5ef369336091067e78c6019bc4c6adacdfe46c03", + "db4f7bc4c9fee9a31ff07a9708d6f6299f716c93", [] ] }, "auth10": { "auth.py": [ - "5ef369336091067e78c6019bc4c6adacdfe46c03", + "db4f7bc4c9fee9a31ff07a9708d6f6299f716c93", [] ] }, "auth11": { "auth.py": [ - "5ef369336091067e78c6019bc4c6adacdfe46c03", + "db4f7bc4c9fee9a31ff07a9708d6f6299f716c93", [] ] }, "auth2": { "auth.py": [ - "5ef369336091067e78c6019bc4c6adacdfe46c03", + "db4f7bc4c9fee9a31ff07a9708d6f6299f716c93", [] ], "corsenabled.py": [ @@ -243872,13 +243872,13 @@ }, "auth3": { "auth.py": [ - "5ef369336091067e78c6019bc4c6adacdfe46c03", + "db4f7bc4c9fee9a31ff07a9708d6f6299f716c93", [] ] }, "auth4": { "auth.py": [ - "5ef369336091067e78c6019bc4c6adacdfe46c03", + "db4f7bc4c9fee9a31ff07a9708d6f6299f716c93", [] ] }, @@ -243908,7 +243908,7 @@ }, "auth9": { "auth.py": [ - "5ef369336091067e78c6019bc4c6adacdfe46c03", + "db4f7bc4c9fee9a31ff07a9708d6f6299f716c93", [] ] }, @@ -276616,7 +276616,7 @@ ] ], "grid-intrinsic-track-sizes-001.html": [ - "15ca612c7cb5a639ba6da6931b2e55775e12d4dc", + "f570f02aa709b54693f2a092f46d4d78d680ea9d", [ null, {} @@ -292835,7 +292835,7 @@ ] ], "prefers-contrast.html": [ - "617e0b97256db36b4b84024251c01e48a1400a79", + "fe0d2f057c31c8bd122483c8e282bc1188fc2a69", [ null, {}
diff --git a/third_party/blink/web_tests/external/wpt/bluetooth/resources/bluetooth-test.js b/third_party/blink/web_tests/external/wpt/bluetooth/resources/bluetooth-test.js index 01cabe8..9c5950d 100644 --- a/third_party/blink/web_tests/external/wpt/bluetooth/resources/bluetooth-test.js +++ b/third_party/blink/web_tests/external/wpt/bluetooth/resources/bluetooth-test.js
@@ -19,19 +19,6 @@ } /** - * Loads the scripts in |paths|. - * @param {string[]} paths - * @returns {Promise<void>} A promise chain that resolves when all scripts have - * finished loading. - */ -async function loadScripts(paths) { - for (let path of paths) { - await loadScript(path); - } - return; -} - -/** * Performs the Chromium specific setup necessary to run the tests in the * Chromium browser. This test file is shared between Web Platform Tests and * Blink Web Tests, so this method figures out the correct paths to use for @@ -42,36 +29,30 @@ * @returns {Promise<void>} Resolves when Chromium specific setup is complete. */ async function performChromiumSetup() { - // Make sure we are actually on Chromium with Mojo enabled. - if (typeof Mojo === 'undefined') { + // Determine path prefixes. + let resPrefix = '/resources'; + let extra = ['/resources/chromium/web-bluetooth-test.js']; + const pathname = window.location.pathname; + if (pathname.includes('/web_tests/')) { + let root = pathname.match(/.*(?:web_tests)/); + resPrefix = `${root}/external/wpt/resources`; + extra = [ + `${root}/external/wpt/resources/chromium/web-bluetooth-test.js`, + `${root}/resources/bluetooth/bluetooth-fake-adapter.js`, + ]; + } + + await loadScript(`${resPrefix}/test-only-api.js`); + if (!isChromiumBased) { return; } - // Load the Chromium-specific resources. - let prefix = '/resources/chromium'; - let genPrefix = '/gen'; - let extra = []; - const pathname = window.location.pathname; - if (pathname.includes('/LayoutTests/') || pathname.includes('/web_tests/')) { - let root = pathname.match(/.*(?:LayoutTests|web_tests)/); - prefix = `${root}/external/wpt/resources/chromium`; - extra = [ - `${root}/resources/bluetooth/bluetooth-fake-adapter.js`, - ]; - genPrefix = 'file:///gen'; - } else if (window.location.pathname.startsWith('/bluetooth/https/')) { - extra = [ - '/js-test-resources/bluetooth/bluetooth-fake-adapter.js', - ]; - } - await loadScripts([ - `${genPrefix}/layout_test_data/mojo/public/js/mojo_bindings.js`, - `${genPrefix}/content/test/data/mojo_web_test_helper_test.mojom.js`, - `${genPrefix}/device/bluetooth/public/mojom/uuid.mojom.js`, - `${genPrefix}/url/mojom/origin.mojom.js`, - `${genPrefix}/device/bluetooth/public/mojom/test/fake_bluetooth.mojom.js`, - `${genPrefix}/content/shell/common/web_test/fake_bluetooth_chooser.mojom.js`, - `${prefix}/web-bluetooth-test.js`, + await loadMojoResources([ + '/gen/content/test/data/mojo_web_test_helper_test.mojom.js', + '/gen/device/bluetooth/public/mojom/uuid.mojom.js', + '/gen/url/mojom/origin.mojom.js', + '/gen/device/bluetooth/public/mojom/test/fake_bluetooth.mojom.js', + '/gen/content/shell/common/web_test/fake_bluetooth_chooser.mojom.js', ].concat(extra)); // Call setBluetoothFakeAdapter() to clean up any fake adapters left over by @@ -98,8 +79,10 @@ */ function bluetooth_test(test_function, name, properties) { return promise_test(async (t) => { + assert_implements(navigator.bluetooth, 'missing navigator.bluetooth'); // Trigger Chromium-specific setup. await performChromiumSetup(); + assert_implements(navigator.bluetooth.test, 'missing navigator.bluetooth.test'); await test_function(t); let consumed = await navigator.bluetooth.test.allResponsesConsumed(); assert_true(consumed);
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/content-visibility-026-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/content-visibility-026-expected.txt new file mode 100644 index 0000000..0cdb40fa --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/content-visibility-026-expected.txt
@@ -0,0 +1,7 @@ +This is a testharness.js-based test. +PASS content-visibility: hidden adds contain: size layout style; +FAIL content-visibility: auto adds contain: size layout style paint; assert_equals: expected "size layout style paint" but got "layout style paint" +PASS content-visibility: auto adds contain: size layout style paint, can't be overridden +PASS content-visibility keeps all containment even when shorthands are specified +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/layout-algorithm/grid-intrinsic-track-sizes-001.html b/third_party/blink/web_tests/external/wpt/css/css-grid/layout-algorithm/grid-intrinsic-track-sizes-001.html index 15ca612c..f570f02a 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-grid/layout-algorithm/grid-intrinsic-track-sizes-001.html +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/layout-algorithm/grid-intrinsic-track-sizes-001.html
@@ -4,7 +4,6 @@ <link rel="author" title="Elika J. Etemad" href="http://fantasai.inkedblade.net/contact"> <link rel="help" href="https://www.w3.org/TR/css-grid-1/#algo-content"> <meta name="assert" content="This test checks that the intrinsic contribution of a single grid item smaller than its container is distributed correctly among the tracks it spans when intrinsic tracks are involved."> -<base href="https://wpt.live/css/css-grid/grid-definition/"> <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> <style> #grid {
diff --git a/third_party/blink/web_tests/external/wpt/css/mediaqueries/prefers-contrast.html b/third_party/blink/web_tests/external/wpt/css/mediaqueries/prefers-contrast.html index 617e0b972..fe0d2f0 100644 --- a/third_party/blink/web_tests/external/wpt/css/mediaqueries/prefers-contrast.html +++ b/third_party/blink/web_tests/external/wpt/css/mediaqueries/prefers-contrast.html
@@ -7,8 +7,8 @@ <script> query_should_be_css_parseable("(prefers-contrast)"); query_should_be_css_parseable("(prefers-contrast: no-preference)"); -query_should_be_css_parseable("(prefers-contrast: high)"); -query_should_be_css_parseable("(prefers-contrast: low)"); +query_should_be_css_parseable("(prefers-contrast: more)"); +query_should_be_css_parseable("(prefers-contrast: less)"); query_should_be_css_parseable("(prefers-contrast: forced)"); query_should_not_be_css_parseable("(prefers-contrast: increase)"); @@ -18,11 +18,13 @@ query_should_not_be_css_parseable("(prefers-contrast > increase)"); query_should_not_be_css_parseable("(prefers-increased-contrast)"); query_should_not_be_css_parseable("(prefers-decreased-contrast)"); +query_should_not_be_css_parseable("(prefers-contrast: high)"); +query_should_not_be_css_parseable("(prefers-contrast: low)"); query_should_be_js_parseable("(prefers-contrast)"); query_should_be_js_parseable("(prefers-contrast: no-preference)"); -query_should_be_js_parseable("(prefers-contrast: high)"); -query_should_be_js_parseable("(prefers-contrast: low)"); +query_should_be_js_parseable("(prefers-contrast: more)"); +query_should_be_js_parseable("(prefers-contrast: less)"); query_should_be_js_parseable("(prefers-contrast: forced)"); query_should_not_be_js_parseable("(prefers-contrast: increase)"); @@ -32,6 +34,8 @@ query_should_not_be_js_parseable("(prefers-contrast > increase)"); query_should_not_be_js_parseable("(prefers-increased-contrast)"); query_should_not_be_js_parseable("(prefers-decreased-contrast)"); +query_should_not_be_js_parseable("(prefers-contrast: high)"); +query_should_not_be_js_parseable("(prefers-contrast: low)"); test(() => { // no-preference is the default and all other values evaluate to
diff --git a/third_party/blink/web_tests/external/wpt/eventsource/resources/cors.py b/third_party/blink/web_tests/external/wpt/eventsource/resources/cors.py index bc0c1089..6ed31f2 100644 --- a/third_party/blink/web_tests/external/wpt/eventsource/resources/cors.py +++ b/third_party/blink/web_tests/external/wpt/eventsource/resources/cors.py
@@ -31,6 +31,6 @@ elif handler == b"redirect": return run_other(request, response, os.path.join(request.doc_root, u"common", u"redirect.py")) else: - return run_other(request, response, os.path.join(os.path.split(isomorphic_decode(__file__))[0], isomorphic_decode(handler) + u".py")) + return run_other(request, response, os.path.join(os.path.dirname(isomorphic_decode(__file__)), isomorphic_decode(handler) + u".py")) else: return
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/wide-gamut-canvas/canvas-createImageBitmap-e_srgb.html b/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/wide-gamut-canvas/canvas-createImageBitmap-e_srgb.html index fd9a5e96d..7483800b 100644 --- a/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/wide-gamut-canvas/canvas-createImageBitmap-e_srgb.html +++ b/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/wide-gamut-canvas/canvas-createImageBitmap-e_srgb.html
@@ -44,8 +44,9 @@ tolerance = 0.03; for (var i = 0; i < tests.length; i++) { actual = ctx.getImageData(tests[i][0], tests[i][1], 1, 1).dataUnion; + assert_implements(actual, 'ImageData dataUnion not supported'); expected = tests[i][2]; - assert_true(actual.length === expected.length); + assert_equals(actual.length, expected.length); for (var j = 0; j < actual.length; j++) assert_approx_equals(actual[j], expected[j], tolerance, tests[i][3]); } @@ -171,7 +172,9 @@ ctx1.drawImage(bitmap1, 0, 0); ctx2.drawImage(bitmap2, 0, 0); var data1 = ctx1.getImageData(0, 0, 50, 50).dataUnion; + assert_implements(data1, 'ImageData dataUnion not supported'); var data2 = ctx2.getImageData(0, 0, 50, 50).dataUnion; + assert_implements(data2, 'ImageData dataUnion not supported'); var dataMatched = true; for (var i = 0; i < data1.length; i++) { if (data1[i] != data2[i]) { @@ -286,14 +289,11 @@ // HTMLImageElement - Opaque sRGB // File formats: AVIF, Bitmap, GIF, ICO, JPEG, PNG, WEBP ['avif', 'bmp', 'gif', 'ico', 'jpg', 'png', 'webp'].forEach(ext => { - promise_test(function() { - return new Promise((resolve,reject) => { - var image = new Image(); - image.onload = function() { - resolve(image); - } - image.src = 'resources/pattern-srgb.' + ext; - }).then(testImageBitmapOpaque); + promise_test(async () => { + const image = new Image(); + image.src = 'resources/pattern-srgb.' + ext; + await image.decode(); + await testImageBitmapOpaque(image); }, 'createImageBitmap in e-sRGB from an opaque sRGB HTMLImageElement (' + ext + ') with resize.'); }); @@ -301,14 +301,11 @@ // HTMLImageElement - Transparent sRGB // File formats: AVIF, Bitmap, ICO, PNG, WEBP ['avif', 'bmp', 'ico', 'png', 'webp'].forEach(ext => { - promise_test(function() { - return new Promise((resolve,reject) => { - var image = new Image(); - image.onload = function() { - resolve(image); - } - image.src = 'resources/pattern-srgb-transparent.' + ext; - }).then(testImageBitmapFromTransparentImage); + promise_test(async () => { + const image = new Image(); + image.src = 'resources/pattern-srgb-transparent.' + ext; + await image.decode(); + await testImageBitmapFromTransparentImage(image); }, 'createImageBitmap in e-sRGB from a transparent sRGB HTMLImageElement (' + ext + ') with resize.'); }); @@ -316,56 +313,54 @@ //////////////////////////////////////////////////////////////////////////////// // SVG Image - sRGB -promise_test(function() { - return new Promise((resolve, reject) => { - var image = new Image(); - image.onload = function() { - resolve(image); - } - image.src = 'resources/pattern-srgb.svg' - }).then(testImageBitmapFromSVG); +promise_test(async () => { + const image = new Image(); + image.src = 'resources/pattern-srgb.svg' + await image.decode(); + await testImageBitmapFromSVG(image); }, 'createImageBitmap in e-sRGB from a sRGB SVG image with resize.'); //////////////////////////////////////////////////////////////////////////////// // HTMLVideoElement - sRGB -promise_test(function() { - return new Promise((resolve, reject) => { - var video = document.createElement("video"); - video.oncanplaythrough = function() { - resolve(video); - } - video.preload = "auto"; - video.src = 'resources/pattern-srgb-fullcolor.ogv' - }).then(testImageBitmapVideoSource); +promise_test(async () => { + var video = document.createElement("video"); + assert_implements_optional(video.canPlayType("video/ogg"), "video/ogg not supported"); + video.preload = "auto"; + video.src = 'resources/pattern-srgb-fullcolor.ogv' + await new Promise((resolve, reject) => { + video.onloadeddata = resolve; + video.onerror = reject; + }); + await testImageBitmapVideoSource(video); }, 'createImageBitmap in e-sRGB from a sRGB HTMLVideoElement with resize.'); //////////////////////////////////////////////////////////////////////////////// // HTMLCanvasElement - Opaque sRGB -promise_test(function() { +promise_test(async () => { var testCanvas = initializeTestCanvas('srgb', 'uint8'); - return testImageBitmapOpaque(testCanvas); + await testImageBitmapOpaque(testCanvas); }, 'createImageBitmap in e-sRGB from an opaque sRGB HTMLCanvasElement with resize.'); // HTMLCanvasElement - Opaque e-sRGB -promise_test(function() { +promise_test(async () => { var testCanvas = initializeTestCanvas('srgb', 'float16'); - return testImageBitmapOpaque(testCanvas); + await testImageBitmapOpaque(testCanvas); }, 'createImageBitmap in e-sRGB from an opaque e-sRGB HTMLCanvasElement with resize.'); //////////////////////////////////////////////////////////////////////////////// // HTMLCanvasElement - Transparent sRGB -promise_test(function() { +promise_test(async () => { var testCanvas = initializeTestCanvasTransparent('srgb', 'uint8'); - return testImageBitmapTransparent(testCanvas); + await testImageBitmapTransparent(testCanvas); }, 'createImageBitmap in e-sRGB from a transparent sRGB HTMLCanvasElement with resize.'); // HTMLCanvasElement - Transparent e-sRGB -promise_test(function() { +promise_test(async () => { var testCanvas = initializeTestCanvasTransparent('srgb', 'float16'); - return testImageBitmapTransparent(testCanvas); + await testImageBitmapTransparent(testCanvas); }, 'createImageBitmap in e-sRGB from a transparent e-sRGB HTMLCanvasElement with resize.'); ////////////////////////////////////////////////////////////////////////////// @@ -373,60 +368,48 @@ // Blob from file - Opaque sRGB // File formats: AVIF, Bitmap, GIF, ICO, JPEG, PNG, WEBP ['avif', 'bmp', 'gif', 'ico', 'jpg', 'png', 'webp'].forEach(ext => { - promise_test(function() { - return new Promise((resolve, reject) => { - var xhr = new XMLHttpRequest(); - xhr.open("GET", 'resources/pattern-srgb.' + ext); - xhr.responseType = 'blob'; - xhr.send(); - xhr.onload = function() { - resolve(xhr.response); - }; - }).then(testImageBitmapOpaque); + promise_test(async () => { + const response = await fetch('resources/pattern-srgb.' + ext); + assert_true(response.ok); + const blob = await response.blob(); + await testImageBitmapOpaque(blob); }, 'createImageBitmap in e-sRGB from an opaque sRGB Blob (' + ext + ') with resize.'); }); // Blob form file - Transparent sRGB // File formats: AVIF, Bitmap, ICO, PNG, WEBP ['avif', 'bmp', 'ico', 'png', 'webp'].forEach(ext => { - promise_test(function() { - return new Promise((resolve, reject) => { - var xhr = new XMLHttpRequest(); - xhr.open("GET", 'resources/pattern-srgb-transparent.' + ext); - xhr.responseType = 'blob'; - xhr.send(); - xhr.onload = function() { - resolve(xhr.response); - }; - }).then(testImageBitmapFromTransparentImage); + promise_test(async () => { + const response = await fetch('resources/pattern-srgb-transparent.' + ext); + assert_true(response.ok); + const blob = await response.blob(); + await testImageBitmapFromTransparentImage(blob); }, 'createImageBitmap in e-sRGB from a transparent sRGB Blob (' + ext + ') with resize.'); }); // Color managed blob from canvas function testCreateImageBitmapFromColorManagedBlob(pixelFormat, isTransparent) { - let canvasPixelFormat = 'uint8'; - if (pixelFormat == 'uint16') - canvasPixelFormat = 'float16'; - var testCanvas; - if (isTransparent) - testCanvas = initializeTestCanvasTransparent('srgb', canvasPixelFormat); - else - testCanvas = initializeTestCanvas('srgb', canvasPixelFormat); - var encodeOptions = {}; - encodeOptions.quality = 1; - encodeOptions.type = 'image/png'; - encodeOptions.pixelFormat = pixelFormat; - - var t = async_test('createImageBitmap in e-sRGB from color managed Blob' + - ' with resize. blobPixelFormat: ' + pixelFormat + - ', transparency: ' + isTransparent); - testCanvas.convertToBlob(encodeOptions).then( - t.step_func_done(function(blob) { - if (isTransparent) - testImageBitmapTransparent(blob); - else - testImageBitmapOpaque(blob); - })); + promise_test(async () => { + let canvasPixelFormat = 'uint8'; + if (pixelFormat == 'uint16') + canvasPixelFormat = 'float16'; + let testCanvas; + if (isTransparent) + testCanvas = initializeTestCanvasTransparent('srgb', canvasPixelFormat); + else + testCanvas = initializeTestCanvas('srgb', canvasPixelFormat); + const blob = await testCanvas.convertToBlob({ + quality: 1, + type: 'image/png', + pixelFormat, + }); + if (isTransparent) + await testImageBitmapTransparent(blob); + else + await testImageBitmapOpaque(blob); + }, 'createImageBitmap in e-sRGB from color managed Blob' + + ' with resize. blobPixelFormat: ' + pixelFormat + + ', transparency: ' + isTransparent); } function runAllCreateImageBitmapFromColorManagedBlobTests() { @@ -444,67 +427,67 @@ //////////////////////////////////////////////////////////////////////////////// // ImageData - Opaque sRGB -promise_test(function() { +promise_test(async () => { var canvas = initializeTestCanvas('srgb', 'uint8'); var ctx = canvas.getContext('2d'); var data = ctx.getImageData(0, 0, 20, 20); - return testImageBitmapOpaque(data); + await testImageBitmapOpaque(data); }, 'createImageBitmap in e-sRGB from an opaque sRGB ImageData with resize.'); // ImageData - Opaque e-sRGB -promise_test(function() { +promise_test(async () => { var canvas = initializeTestCanvas('srgb', 'float16'); var ctx = canvas.getContext('2d', {colorSpace: 'srgb', pixelFormat:'float16'}); var data = ctx.getImageData(0, 0, 20, 20); - return testImageBitmapOpaque(data); + await testImageBitmapOpaque(data); }, 'createImageBitmap in e-sRGB from an opaque e-sRGB ImageData with resize.'); //////////////////////////////////////////////////////////////////////////////// // ImageData - Transparent sRGB -promise_test(function() { +promise_test(async () => { var canvas = initializeTestCanvasTransparent('srgb', 'uint8'); var ctx = canvas.getContext('2d'); var data = ctx.getImageData(0, 0, 20, 20); - return testImageBitmapTransparent(data); + await testImageBitmapTransparent(data); }, 'createImageBitmap in e-sRGB from a transparent sRGB ImageData with resize.'); // ImageData - Transparent e-sRGB -promise_test(function() { +promise_test(async () => { var canvas = initializeTestCanvasTransparent('srgb', 'float16'); var ctx = canvas.getContext('2d', {colorSpace: 'srgb', pixelFormat:'float16'}); var data = ctx.getImageData(0, 0, 20, 20); - return testImageBitmapTransparent(data); + await testImageBitmapTransparent(data); }, 'createImageBitmap in e-sRGB from a transparent e-sRGB ImageData with resize.'); //////////////////////////////////////////////////////////////////////////////// // ImageBitmap - Opaque sRGB -promise_test(function() { +promise_test(async () => { var testCanvas = initializeTestCanvas('srgb', 'uint8'); - return createImageBitmap(testCanvas).then(testImageBitmapOpaque); + await createImageBitmap(testCanvas).then(testImageBitmapOpaque); }, 'createImageBitmap in e-sRGB from an opaque sRGB ImageBitmap with resize.'); // ImageBitmap - Opaque e-sRGB -promise_test(function() { +promise_test(async () => { var testCanvas = initializeTestCanvas('srgb', 'float16'); - return createImageBitmap(testCanvas).then(testImageBitmapOpaque); + await createImageBitmap(testCanvas).then(testImageBitmapOpaque); }, 'createImageBitmap in e-sRGB from an opaque e-sRGB ImageBitmap with resize.'); //////////////////////////////////////////////////////////////////////////////// // ImageBitmap - Transparent sRGB -promise_test(function() { +promise_test(async () => { var testCanvas = initializeTestCanvasTransparent('srgb', 'uint8'); - return createImageBitmap(testCanvas).then(testImageBitmapTransparent); + await createImageBitmap(testCanvas).then(testImageBitmapTransparent); }, 'createImageBitmap in e-sRGB from a transparent sRGB ImageBitmap with resize.'); // ImageBitmap - Transparent e-sRGB -promise_test(function() { +promise_test(async () => { var testCanvas = initializeTestCanvasTransparent('srgb', 'float16'); - return createImageBitmap(testCanvas).then(testImageBitmapTransparent); + await createImageBitmap(testCanvas).then(testImageBitmapTransparent); }, 'createImageBitmap in e-sRGB from a transparent e-sRGB ImageBitmap with resize.'); //////////////////////////////////////////////////////////////////////////////// @@ -529,15 +512,15 @@ } //OffscreenCanvas - Opaque sRGB -promise_test(function() { +promise_test(async () => { var offscreen = initializeOffscreenCanvas('srgb', 'uint8'); - return testImageBitmapOpaque(offscreen); + await testImageBitmapOpaque(offscreen); }, 'createImageBitmap in e-sRGB from an opaque sRGB OffscreenCanvas with resize.'); //OffscreenCanvas - Opaque e-sRGB -promise_test(function() { +promise_test(async () => { var offscreen = initializeOffscreenCanvas('srgb', 'float16'); - return testImageBitmapOpaque(offscreen); + await testImageBitmapOpaque(offscreen); }, 'createImageBitmap in e-sRGB from an opaque e-sRGB OffscreenCanvas with resize.'); //////////////////////////////////////////////////////////////////////////////// @@ -562,15 +545,15 @@ } //OffscreenCanvas - Transparent sRGB -promise_test(function() { +promise_test(async () => { var offscreen = initializeOffscreenCanvasTransparent('srgb', 'uint8'); - return testImageBitmapTransparent(offscreen); + await testImageBitmapTransparent(offscreen); }, 'createImageBitmap in e-sRGB from a transparent sRGB OffscreenCanvas with resize.'); //OffscreenCanvas - Transparent e-sRGB -promise_test(function() { +promise_test(async () => { var offscreen = initializeOffscreenCanvasTransparent('srgb', 'float16'); - return testImageBitmapTransparent(offscreen); + await testImageBitmapTransparent(offscreen); }, 'createImageBitmap in e-sRGB from a transparent e-sRGB OffscreenCanvas with resize.'); ////////////////////////////////////////////////////////////////////////////////
diff --git a/third_party/blink/web_tests/external/wpt/html/tools/update_html5lib_tests.py b/third_party/blink/web_tests/external/wpt/html/tools/update_html5lib_tests.py index 0bc21d3..e4f339a 100644 --- a/third_party/blink/web_tests/external/wpt/html/tools/update_html5lib_tests.py +++ b/third_party/blink/web_tests/external/wpt/html/tools/update_html5lib_tests.py
@@ -37,7 +37,7 @@ TESTS_PATH = "html/syntax/parsing/" def get_paths(): - script_path = os.path.split(os.path.abspath(__file__))[0] + script_path = os.path.dirname(os.path.abspath(__file__)) repo_base = get_repo_base(script_path) tests_path = os.path.join(repo_base, TESTS_PATH) return script_path, tests_path @@ -47,7 +47,7 @@ if os.path.exists(os.path.join(path, ".git")): return path else: - path = os.path.split(path)[0] + path = os.path.dirname(path) def get_expected(data): data = "#document\n" + data @@ -100,7 +100,7 @@ def write_test_file(script_dir, out_dir, tests, file_name, template_file_name): file_name = os.path.join(out_dir, file_name + ".html") - short_name = os.path.split(file_name)[1] + short_name = os.path.basename(file_name) with open(os.path.join(script_dir, template_file_name), "r") as f: template = MarkupTemplate(f) @@ -139,7 +139,7 @@ os.path.join("tree-construction", "scripted"))))) for (scripted, test_file) in test_iterator: - input_file_name = os.path.splitext(os.path.split(test_file)[1])[0] + input_file_name = os.path.splitext(os.path.basename(test_file))[0] if scripted: input_file_name = "scripted_" + input_file_name test_data = support.TestData(test_file)
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/uievents.idl b/third_party/blink/web_tests/external/wpt/interfaces/uievents.idl index 67405eb..f86525c 100644 --- a/third_party/blink/web_tests/external/wpt/interfaces/uievents.idl +++ b/third_party/blink/web_tests/external/wpt/interfaces/uievents.idl
@@ -162,3 +162,9 @@ readonly attribute unsigned long charCode; readonly attribute unsigned long keyCode; }; + +partial dictionary KeyboardEventInit { + // The following support legacy user agents + unsigned long charCode = 0; + unsigned long keyCode = 0; +};
diff --git a/third_party/blink/web_tests/external/wpt/lint.ignore b/third_party/blink/web_tests/external/wpt/lint.ignore index a17a094..354e28be 100644 --- a/third_party/blink/web_tests/external/wpt/lint.ignore +++ b/third_party/blink/web_tests/external/wpt/lint.ignore
@@ -714,12 +714,13 @@ # Tests that depend on resources in /gen/ in Chromium: # https://github.com/web-platform-tests/wpt/issues/16455 # Please consult with ecosystem-infra@chromium.org before adding more. -MISSING DEPENDENCY: resources/test-only-api.js +MISSING DEPENDENCY: bluetooth/resources/bluetooth-test.js MISSING DEPENDENCY: contacts/resources/helpers.js MISSING DEPENDENCY: credential-management/support/otpcredential-helper.js MISSING DEPENDENCY: generic-sensor/resources/generic-sensor-helpers.js MISSING DEPENDENCY: idle-detection/interceptor.https.html MISSING DEPENDENCY: orientation-event/resources/orientation-event-helpers.js +MISSING DEPENDENCY: resources/test-only-api.js MISSING DEPENDENCY: screen_enumeration/resources/screenenumeration-helpers.js MISSING DEPENDENCY: shape-detection/resources/shapedetection-helpers.js MISSING DEPENDENCY: web-nfc/resources/nfc-helpers.js @@ -729,7 +730,6 @@ # TODO(Hexcles): delete these files once we include them in mojojs.zip. MOJOM-JS: resources/chromium/image_capture.mojom.js MOJOM-JS: resources/chromium/sensor_provider.mojom.js -MOJOM-JS: resources/chromium/mojo_web_test_helper_test.mojom.js MOJOM-JS: resources/chromium/sensor.mojom.js # Tests that are false positives for using Ahem as a system font
diff --git a/third_party/blink/web_tests/external/wpt/resources/chromium/mojo_web_test_helper_test.mojom.js b/third_party/blink/web_tests/external/wpt/resources/chromium/mojo_web_test_helper_test.mojom.js deleted file mode 100644 index cfbad08..0000000 --- a/third_party/blink/web_tests/external/wpt/resources/chromium/mojo_web_test_helper_test.mojom.js +++ /dev/null
@@ -1,264 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -'use strict'; - -(function() { - var mojomId = 'content/test/data/mojo_web_test_helper_test.mojom'; - if (mojo.internal.isMojomLoaded(mojomId)) { - console.warn('The following mojom is loaded multiple times: ' + mojomId); - return; - } - mojo.internal.markMojomLoaded(mojomId); - - // TODO(yzshen): Define these aliases to minimize the differences between the - // old/new modes. Remove them when the old mode goes away. - var bindings = mojo; - var associatedBindings = mojo; - var codec = mojo.internal; - var validator = mojo.internal; - - var exports = mojo.internal.exposeNamespace('content.mojom'); - - - - function MojoWebTestHelper_Reverse_Params(values) { - this.initDefaults_(); - this.initFields_(values); - } - - - MojoWebTestHelper_Reverse_Params.prototype.initDefaults_ = function() { - this.message = null; - }; - MojoWebTestHelper_Reverse_Params.prototype.initFields_ = function(fields) { - for(var field in fields) { - if (this.hasOwnProperty(field)) - this[field] = fields[field]; - } - }; - - MojoWebTestHelper_Reverse_Params.validate = function(messageValidator, offset) { - var err; - err = messageValidator.validateStructHeader(offset, codec.kStructHeaderSize); - if (err !== validator.validationError.NONE) - return err; - - var kVersionSizes = [ - {version: 0, numBytes: 16} - ]; - err = messageValidator.validateStructVersion(offset, kVersionSizes); - if (err !== validator.validationError.NONE) - return err; - - - // validate MojoWebTestHelper_Reverse_Params.message - err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 0, false) - if (err !== validator.validationError.NONE) - return err; - - return validator.validationError.NONE; - }; - - MojoWebTestHelper_Reverse_Params.encodedSize = codec.kStructHeaderSize + 8; - - MojoWebTestHelper_Reverse_Params.decode = function(decoder) { - var packed; - var val = new MojoWebTestHelper_Reverse_Params(); - var numberOfBytes = decoder.readUint32(); - var version = decoder.readUint32(); - val.message = decoder.decodeStruct(codec.String); - return val; - }; - - MojoWebTestHelper_Reverse_Params.encode = function(encoder, val) { - var packed; - encoder.writeUint32(MojoWebTestHelper_Reverse_Params.encodedSize); - encoder.writeUint32(0); - encoder.encodeStruct(codec.String, val.message); - }; - function MojoWebTestHelper_Reverse_ResponseParams(values) { - this.initDefaults_(); - this.initFields_(values); - } - - - MojoWebTestHelper_Reverse_ResponseParams.prototype.initDefaults_ = function() { - this.reversed = null; - }; - MojoWebTestHelper_Reverse_ResponseParams.prototype.initFields_ = function(fields) { - for(var field in fields) { - if (this.hasOwnProperty(field)) - this[field] = fields[field]; - } - }; - - MojoWebTestHelper_Reverse_ResponseParams.validate = function(messageValidator, offset) { - var err; - err = messageValidator.validateStructHeader(offset, codec.kStructHeaderSize); - if (err !== validator.validationError.NONE) - return err; - - var kVersionSizes = [ - {version: 0, numBytes: 16} - ]; - err = messageValidator.validateStructVersion(offset, kVersionSizes); - if (err !== validator.validationError.NONE) - return err; - - - // validate MojoWebTestHelper_Reverse_ResponseParams.reversed - err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 0, false) - if (err !== validator.validationError.NONE) - return err; - - return validator.validationError.NONE; - }; - - MojoWebTestHelper_Reverse_ResponseParams.encodedSize = codec.kStructHeaderSize + 8; - - MojoWebTestHelper_Reverse_ResponseParams.decode = function(decoder) { - var packed; - var val = new MojoWebTestHelper_Reverse_ResponseParams(); - var numberOfBytes = decoder.readUint32(); - var version = decoder.readUint32(); - val.reversed = decoder.decodeStruct(codec.String); - return val; - }; - - MojoWebTestHelper_Reverse_ResponseParams.encode = function(encoder, val) { - var packed; - encoder.writeUint32(MojoWebTestHelper_Reverse_ResponseParams.encodedSize); - encoder.writeUint32(0); - encoder.encodeStruct(codec.String, val.reversed); - }; - var kMojoWebTestHelper_Reverse_Name = 0; - - function MojoWebTestHelperPtr(handleOrPtrInfo) { - this.ptr = new bindings.InterfacePtrController(MojoWebTestHelper, - handleOrPtrInfo); - } - - function MojoWebTestHelperAssociatedPtr(associatedInterfacePtrInfo) { - this.ptr = new associatedBindings.AssociatedInterfacePtrController( - MojoWebTestHelper, associatedInterfacePtrInfo); - } - - MojoWebTestHelperAssociatedPtr.prototype = - Object.create(MojoWebTestHelperPtr.prototype); - MojoWebTestHelperAssociatedPtr.prototype.constructor = - MojoWebTestHelperAssociatedPtr; - - function MojoWebTestHelperProxy(receiver) { - this.receiver_ = receiver; - } - MojoWebTestHelperPtr.prototype.reverse = function() { - return MojoWebTestHelperProxy.prototype.reverse - .apply(this.ptr.getProxy(), arguments); - }; - - MojoWebTestHelperProxy.prototype.reverse = function(message) { - var params = new MojoWebTestHelper_Reverse_Params(); - params.message = message; - return new Promise(function(resolve, reject) { - var builder = new codec.MessageV1Builder( - kMojoWebTestHelper_Reverse_Name, - codec.align(MojoWebTestHelper_Reverse_Params.encodedSize), - codec.kMessageExpectsResponse, 0); - builder.encodeStruct(MojoWebTestHelper_Reverse_Params, params); - var message = builder.finish(); - this.receiver_.acceptAndExpectResponse(message).then(function(message) { - var reader = new codec.MessageReader(message); - var responseParams = - reader.decodeStruct(MojoWebTestHelper_Reverse_ResponseParams); - resolve(responseParams); - }).catch(function(result) { - reject(Error("Connection error: " + result)); - }); - }.bind(this)); - }; - - function MojoWebTestHelperStub(delegate) { - this.delegate_ = delegate; - } - MojoWebTestHelperStub.prototype.reverse = function(message) { - return this.delegate_ && this.delegate_.reverse && this.delegate_.reverse(message); - } - - MojoWebTestHelperStub.prototype.accept = function(message) { - var reader = new codec.MessageReader(message); - switch (reader.messageName) { - default: - return false; - } - }; - - MojoWebTestHelperStub.prototype.acceptWithResponder = - function(message, responder) { - var reader = new codec.MessageReader(message); - switch (reader.messageName) { - case kMojoWebTestHelper_Reverse_Name: - var params = reader.decodeStruct(MojoWebTestHelper_Reverse_Params); - this.reverse(params.message).then(function(response) { - var responseParams = - new MojoWebTestHelper_Reverse_ResponseParams(); - responseParams.reversed = response.reversed; - var builder = new codec.MessageV1Builder( - kMojoWebTestHelper_Reverse_Name, - codec.align(MojoWebTestHelper_Reverse_ResponseParams.encodedSize), - codec.kMessageIsResponse, reader.requestID); - builder.encodeStruct(MojoWebTestHelper_Reverse_ResponseParams, - responseParams); - var message = builder.finish(); - responder.accept(message); - }); - return true; - default: - return false; - } - }; - - function validateMojoWebTestHelperRequest(messageValidator) { - var message = messageValidator.message; - var paramsClass = null; - switch (message.getName()) { - case kMojoWebTestHelper_Reverse_Name: - if (message.expectsResponse()) - paramsClass = MojoWebTestHelper_Reverse_Params; - break; - } - if (paramsClass === null) - return validator.validationError.NONE; - return paramsClass.validate(messageValidator, messageValidator.message.getHeaderNumBytes()); - } - - function validateMojoWebTestHelperResponse(messageValidator) { - var message = messageValidator.message; - var paramsClass = null; - switch (message.getName()) { - case kMojoWebTestHelper_Reverse_Name: - if (message.isResponse()) - paramsClass = MojoWebTestHelper_Reverse_ResponseParams; - break; - } - if (paramsClass === null) - return validator.validationError.NONE; - return paramsClass.validate(messageValidator, messageValidator.message.getHeaderNumBytes()); - } - - var MojoWebTestHelper = { - name: 'content.mojom.MojoWebTestHelper', - kVersion: 0, - ptrClass: MojoWebTestHelperPtr, - proxyClass: MojoWebTestHelperProxy, - stubClass: MojoWebTestHelperStub, - validateRequest: validateMojoWebTestHelperRequest, - validateResponse: validateMojoWebTestHelperResponse, - }; - MojoWebTestHelperStub.prototype.validator = validateMojoWebTestHelperRequest; - MojoWebTestHelperProxy.prototype.validator = validateMojoWebTestHelperResponse; - exports.MojoWebTestHelper = MojoWebTestHelper; - exports.MojoWebTestHelperPtr = MojoWebTestHelperPtr; - exports.MojoWebTestHelperAssociatedPtr = MojoWebTestHelperAssociatedPtr; -})();
diff --git a/third_party/blink/web_tests/external/wpt/resources/chromium/mojo_web_test_helper_test.mojom.js.headers b/third_party/blink/web_tests/external/wpt/resources/chromium/mojo_web_test_helper_test.mojom.js.headers deleted file mode 100644 index 6805c323..0000000 --- a/third_party/blink/web_tests/external/wpt/resources/chromium/mojo_web_test_helper_test.mojom.js.headers +++ /dev/null
@@ -1 +0,0 @@ -Content-Type: text/javascript; charset=utf-8
diff --git a/third_party/blink/web_tests/external/wpt/resources/test-only-api.js b/third_party/blink/web_tests/external/wpt/resources/test-only-api.js index ae31374..609c4774 100644 --- a/third_party/blink/web_tests/external/wpt/resources/test-only-api.js +++ b/third_party/blink/web_tests/external/wpt/resources/test-only-api.js
@@ -31,7 +31,7 @@ } /** - * A helper for Chromium-based browsers to load Mojo JS bindingds + * A helper for Chromium-based browsers to load Mojo JS bindings * * This is an async function that works in both workers and windows. It first * loads mojo_bindings.js, disables automatic dependency loading, and loads all @@ -39,7 +39,12 @@ * successfully, or rejects if any exception is raised. If testharness.js is * used, an uncaught exception will terminate the test with a harness error * (unless `allow_uncaught_exception` is true), which is usually the desired - * behaviour. Only call this function if isChromiumBased === true. + * behaviour. + * + * This function also works with Blink web tests loaded from file://, in which + * case file:// will be prepended to all '/gen/...' URLs. + * + * Only call this function if isChromiumBased === true. * * @param {Array.<string>} resources - A list of scripts to load: Mojo JS * bindings should be of the form '/gen/../*.mojom.js', the ordering of which @@ -55,14 +60,24 @@ return; } + let genPrefix = ''; + if (self.location.pathname.includes('/web_tests/')) { + // Blink internal web tests + genPrefix = 'file://'; + } + // We want to load mojo_bindings.js separately to set mojo.config. if (resources.some(p => p.endsWith('/mojo_bindings.js'))) { throw new Error('Do not load mojo_bindings.js explicitly.'); } - await loadScript('/gen/layout_test_data/mojo/public/js/mojo_bindings.js'); + await loadScript(genPrefix + '/gen/layout_test_data/mojo/public/js/mojo_bindings.js'); mojo.config.autoLoadMojomDeps = false; for (const path of resources) { - await loadScript(path); + if (path.startsWith('/gen/')) { + await loadScript(genPrefix + path); + } else { + await loadScript(path); + } } }
diff --git a/third_party/blink/web_tests/external/wpt/tools/localpaths.py b/third_party/blink/web_tests/external/wpt/tools/localpaths.py index 93cff2b..51aecea 100644 --- a/third_party/blink/web_tests/external/wpt/tools/localpaths.py +++ b/third_party/blink/web_tests/external/wpt/tools/localpaths.py
@@ -1,7 +1,7 @@ import os import sys -here = os.path.abspath(os.path.split(__file__)[0]) +here = os.path.abspath(os.path.dirname(__file__)) sys.path.insert(0, os.path.join(here)) sys.path.insert(0, os.path.join(here, "wptserve"))
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/setup.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/setup.py index ab96bd1..a459e2c4 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/setup.py +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/setup.py
@@ -11,7 +11,7 @@ from setuptools import setup, find_packages -here = os.path.split(__file__)[0] +here = os.path.dirname(__file__) PACKAGE_NAME = 'wptrunner' PACKAGE_VERSION = '1.14'
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/base.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/base.py index a027cf3..99f6e5cf 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/base.py +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/base.py
@@ -7,7 +7,7 @@ from ..wptcommandline import require_arg # noqa: F401 -here = os.path.split(__file__)[0] +here = os.path.dirname(__file__) def inherit(super_module, child_globals, product_name):
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/firefox.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/firefox.py index fc5abf8b..91384cb 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/firefox.py +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/firefox.py
@@ -30,7 +30,7 @@ from ..process import cast_env -here = os.path.join(os.path.split(__file__)[0]) +here = os.path.dirname(__file__) __wptrunner__ = {"product": "firefox", "check_args": "check_args",
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/sauce.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/sauce.py index 3133716a..c57ac94 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/sauce.py +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/sauce.py
@@ -20,7 +20,7 @@ from ..executors.executorselenium import (SeleniumTestharnessExecutor, # noqa: F401 SeleniumRefTestExecutor) # noqa: F401 -here = os.path.split(__file__)[0] +here = os.path.dirname(__file__) # Number of seconds to wait between polling operations when detecting status of # Sauce Connect sub-process. sc_poll_period = 1
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/servo.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/servo.py index 5b65799..b947654 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/servo.py +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/servo.py
@@ -8,7 +8,7 @@ ServoRefTestExecutor, # noqa: F401 ServoWdspecExecutor) # noqa: F401 -here = os.path.join(os.path.split(__file__)[0]) +here = os.path.dirname(__file__) __wptrunner__ = { "product": "servo",
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/servodriver.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/servodriver.py index 02b796b..43794e4 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/servodriver.py +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/servodriver.py
@@ -13,7 +13,7 @@ ServoWebDriverRefTestExecutor) # noqa: F401 from ..process import cast_env -here = os.path.join(os.path.split(__file__)[0]) +here = os.path.dirname(__file__) __wptrunner__ = { "product": "servodriver",
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/config.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/config.py index e7f9d7b..d46beb8e 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/config.py +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/config.py
@@ -3,7 +3,7 @@ import sys from collections import OrderedDict -here = os.path.split(__file__)[0] +here = os.path.dirname(__file__) class ConfigDict(dict): def __init__(self, base_path, *args, **kwargs): @@ -19,7 +19,7 @@ def read(config_path): config_path = os.path.abspath(config_path) - config_root = os.path.split(config_path)[0] + config_root = os.path.dirname(config_path) parser = SafeConfigParser() success = parser.read(config_path) assert config_path in success, success
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/environment.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/environment.py index 65f8200..e1812b8 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/environment.py +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/environment.py
@@ -11,7 +11,7 @@ from .wptlogging import LogLevelRewriter -here = os.path.split(__file__)[0] +here = os.path.dirname(__file__) repo_root = os.path.abspath(os.path.join(here, os.pardir, os.pardir, os.pardir)) sys.path.insert(0, repo_root)
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/base.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/base.py index 82496fca..e8a776b 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/base.py +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/base.py
@@ -16,7 +16,7 @@ from .actions import actions from .protocol import Protocol, BaseProtocolPart -here = os.path.split(__file__)[0] +here = os.path.dirname(__file__) def executor_kwargs(test_type, server_config, cache_manager, run_info_data,
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executorchrome.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executorchrome.py index 3ae3187..3a70475 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executorchrome.py +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executorchrome.py
@@ -8,7 +8,7 @@ from .protocol import PrintProtocolPart from ..webdriver_server import ChromeDriverServer -here = os.path.join(os.path.split(__file__)[0]) +here = os.path.dirname(__file__) class ChromeDriverPrintProtocolPart(PrintProtocolPart):
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executormarionette.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executormarionette.py index 1ba9f06..e0e6aba0 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executormarionette.py +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executormarionette.py
@@ -12,7 +12,7 @@ marionette = None pytestrunner = None -here = os.path.join(os.path.split(__file__)[0]) +here = os.path.dirname(__file__) from .base import (CallbackHandler, CrashtestExecutor,
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executorselenium.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executorselenium.py index 1fa9953b3..82ab6f25 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executorselenium.py +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executorselenium.py
@@ -24,7 +24,7 @@ TestDriverProtocolPart) from ..testrunner import Stop -here = os.path.join(os.path.split(__file__)[0]) +here = os.path.dirname(__file__) webdriver = None exceptions = None
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executorservodriver.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executorservodriver.py index 071b506f..dbed2fed 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executorservodriver.py +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executorservodriver.py
@@ -16,7 +16,7 @@ webdriver = None ServoCommandExtensions = None -here = os.path.join(os.path.split(__file__)[0]) +here = os.path.dirname(__file__) def do_delayed_imports():
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executorwebdriver.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executorwebdriver.py index 695b16b..e0414669 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executorwebdriver.py +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executorwebdriver.py
@@ -31,7 +31,7 @@ import webdriver as client from webdriver import error -here = os.path.join(os.path.split(__file__)[0]) +here = os.path.dirname(__file__) class WebDriverCallbackHandler(CallbackHandler):
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/font.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/font.py index 6226fc6..910358f 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/font.py +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/font.py
@@ -6,7 +6,7 @@ from shutil import copy2, rmtree from subprocess import call, check_output -HERE = os.path.split(__file__)[0] +HERE = os.path.dirname(__file__) SYSTEM = platform.system().lower()
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/metadata.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/metadata.py index df31ac4..ab8d4740 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/metadata.py +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/metadata.py
@@ -320,7 +320,7 @@ manifest_str = wptmanifest.serialize(expected.node, skip_empty_data=True) assert manifest_str != "" - dir = os.path.split(path)[0] + dir = os.path.dirname(path) if not os.path.exists(dir): os.makedirs(dir) tmp_path = path + ".tmp"
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/update/state.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/update/state.py index f8a8352..bdb23fe 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/update/state.py +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/update/state.py
@@ -1,7 +1,7 @@ import os from six.moves import cPickle as pickle # noqa: N813 -here = os.path.abspath(os.path.split(__file__)[0]) +here = os.path.abspath(os.path.dirname(__file__)) class BaseState(object): def __new__(cls, logger):
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/update/sync.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/update/sync.py index c3da2098..f878752 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/update/sync.py +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/update/sync.py
@@ -8,7 +8,7 @@ from .base import Step, StepRunner from .tree import Commit -here = os.path.abspath(os.path.split(__file__)[0]) +here = os.path.abspath(os.path.dirname(__file__)) def copy_wpt_tree(tree, dest, excludes=None, includes=None): @@ -41,7 +41,7 @@ source_path = os.path.join(tree.root, tree_path) dest_path = os.path.join(dest, tree_path) - dest_dir = os.path.split(dest_path)[0] + dest_dir = os.path.dirname(dest_path) if not os.path.isdir(source_path): if not os.path.exists(dest_dir): os.makedirs(dest_dir) @@ -50,7 +50,7 @@ for source, destination in [("testharness_runner.html", ""), ("testdriver-vendor.js", "resources/")]: source_path = os.path.join(here, os.pardir, source) - dest_path = os.path.join(dest, destination, os.path.split(source)[1]) + dest_path = os.path.join(dest, destination, os.path.basename(source)) shutil.copy2(source_path, dest_path)
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/wptrunner.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/wptrunner.py index a397fd6f..f033205 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/wptrunner.py +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/wptrunner.py
@@ -19,7 +19,7 @@ from .testrunner import ManagerGroup from .browsers.base import NullBrowser -here = os.path.split(__file__)[0] +here = os.path.dirname(__file__) logger = None
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/wpttest.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/wpttest.py index 3750def..c670179 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/wpttest.py +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/wpttest.py
@@ -135,7 +135,7 @@ if path in dirs: break dirs.add(str(path)) - path = os.path.split(path)[0] + path = os.path.dirname(path) mozinfo.find_and_update_from_json(*dirs)
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptserve/wptserve/handlers.py b/third_party/blink/web_tests/external/wpt/tools/wptserve/wptserve/handlers.py index d315b021..2cc25e2 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptserve/wptserve/handlers.py +++ b/third_party/blink/web_tests/external/wpt/tools/wptserve/wptserve/handlers.py
@@ -197,7 +197,7 @@ raise HTTPException(404) def get_headers(self, request, path): - rv = (self.load_headers(request, os.path.join(os.path.split(path)[0], "__dir__")) + + rv = (self.load_headers(request, os.path.join(os.path.dirname(path), "__dir__")) + self.load_headers(request, path)) if not any(key.lower() == b"content-type" for (key, _) in rv):
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-answer-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-answer-expected.txt index cdeaf58..550acfb 100644 --- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-answer-expected.txt +++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-answer-expected.txt
@@ -2,8 +2,8 @@ PASS setLocalDescription() with valid answer should succeed PASS setLocalDescription() with type answer and null sdp should use lastAnswer generated from createAnswer PASS setLocalDescription() with answer not created by own createAnswer() should reject with InvalidModificationError -FAIL Calling setLocalDescription(answer) from stable state should reject with InvalidModificationError promise_rejects_dom: function "function() { throw e }" threw object "OperationError: Failed to execute 'setLocalDescription' on 'RTCPeerConnection': Failed to set local answer sdp: Called in wrong state: kStable" that is not a DOMException InvalidModificationError: property "code" is equal to 0, expected 13 -FAIL Calling setLocalDescription(answer) from have-local-offer state should reject with InvalidModificationError promise_rejects_dom: function "function() { throw e }" threw object "OperationError: Failed to execute 'setLocalDescription' on 'RTCPeerConnection': Failed to set local answer sdp: Called in wrong state: kHaveLocalOffer" that is not a DOMException InvalidModificationError: property "code" is equal to 0, expected 13 +FAIL Calling setLocalDescription(answer) from stable state should reject with InvalidModificationError promise_rejects_dom: function "function() { throw e }" threw object "OperationError: Failed to execute 'setLocalDescription' on 'RTCPeerConnection': Failed to set local answer sdp: Called in wrong state: stable" that is not a DOMException InvalidModificationError: property "code" is equal to 0, expected 13 +FAIL Calling setLocalDescription(answer) from have-local-offer state should reject with InvalidModificationError promise_rejects_dom: function "function() { throw e }" threw object "OperationError: Failed to execute 'setLocalDescription' on 'RTCPeerConnection': Failed to set local answer sdp: Called in wrong state: have-local-offer" that is not a DOMException InvalidModificationError: property "code" is equal to 0, expected 13 PASS Setting previously generated answer after a call to createOffer should work FAIL setLocalDescription(answer) should update internal state with a queued task, in the right order assert_not_equals: pendingRemoteDescription should not be set synchronously after a call to sLD got disallowed value null Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-pranswer-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-pranswer-expected.txt index 9634cee..f514bf73 100644 --- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-pranswer-expected.txt +++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-pranswer-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -FAIL setLocalDescription(pranswer) from stable state should reject with InvalidStateError promise_rejects_dom: function "function() { throw e }" threw object "OperationError: Failed to execute 'setLocalDescription' on 'RTCPeerConnection': Failed to set local pranswer sdp: Called in wrong state: kStable" that is not a DOMException InvalidStateError: property "code" is equal to 0, expected 11 +FAIL setLocalDescription(pranswer) from stable state should reject with InvalidStateError promise_rejects_dom: function "function() { throw e }" threw object "OperationError: Failed to execute 'setLocalDescription' on 'RTCPeerConnection': Failed to set local pranswer sdp: Called in wrong state: stable" that is not a DOMException InvalidStateError: property "code" is equal to 0, expected 11 FAIL setLocalDescription(pranswer) should succeed assert_equals: expected null but got object "[object RTCSessionDescription]" PASS setLocalDescription(pranswer) can be applied multiple times while still in have-local-pranswer PASS setLocalDescription(answer) from have-local-pranswer state should succeed
diff --git a/third_party/blink/web_tests/external/wpt/xhr/resources/auth1/auth.py b/third_party/blink/web_tests/external/wpt/xhr/resources/auth1/auth.py index 5ef3693..db4f7bc 100644 --- a/third_party/blink/web_tests/external/wpt/xhr/resources/auth1/auth.py +++ b/third_party/blink/web_tests/external/wpt/xhr/resources/auth1/auth.py
@@ -3,7 +3,7 @@ from wptserve.utils import isomorphic_decode -here = os.path.split(os.path.abspath(isomorphic_decode(__file__)))[0] +here = os.path.dirname(os.path.abspath(isomorphic_decode(__file__))) def main(request, response): auth = imp.load_source(u"", os.path.join(here,
diff --git a/third_party/blink/web_tests/external/wpt/xhr/resources/auth10/auth.py b/third_party/blink/web_tests/external/wpt/xhr/resources/auth10/auth.py index 5ef3693..db4f7bc 100644 --- a/third_party/blink/web_tests/external/wpt/xhr/resources/auth10/auth.py +++ b/third_party/blink/web_tests/external/wpt/xhr/resources/auth10/auth.py
@@ -3,7 +3,7 @@ from wptserve.utils import isomorphic_decode -here = os.path.split(os.path.abspath(isomorphic_decode(__file__)))[0] +here = os.path.dirname(os.path.abspath(isomorphic_decode(__file__))) def main(request, response): auth = imp.load_source(u"", os.path.join(here,
diff --git a/third_party/blink/web_tests/external/wpt/xhr/resources/auth11/auth.py b/third_party/blink/web_tests/external/wpt/xhr/resources/auth11/auth.py index 5ef3693..db4f7bc 100644 --- a/third_party/blink/web_tests/external/wpt/xhr/resources/auth11/auth.py +++ b/third_party/blink/web_tests/external/wpt/xhr/resources/auth11/auth.py
@@ -3,7 +3,7 @@ from wptserve.utils import isomorphic_decode -here = os.path.split(os.path.abspath(isomorphic_decode(__file__)))[0] +here = os.path.dirname(os.path.abspath(isomorphic_decode(__file__))) def main(request, response): auth = imp.load_source(u"", os.path.join(here,
diff --git a/third_party/blink/web_tests/external/wpt/xhr/resources/auth2/auth.py b/third_party/blink/web_tests/external/wpt/xhr/resources/auth2/auth.py index 5ef3693..db4f7bc 100644 --- a/third_party/blink/web_tests/external/wpt/xhr/resources/auth2/auth.py +++ b/third_party/blink/web_tests/external/wpt/xhr/resources/auth2/auth.py
@@ -3,7 +3,7 @@ from wptserve.utils import isomorphic_decode -here = os.path.split(os.path.abspath(isomorphic_decode(__file__)))[0] +here = os.path.dirname(os.path.abspath(isomorphic_decode(__file__))) def main(request, response): auth = imp.load_source(u"", os.path.join(here,
diff --git a/third_party/blink/web_tests/external/wpt/xhr/resources/auth3/auth.py b/third_party/blink/web_tests/external/wpt/xhr/resources/auth3/auth.py index 5ef3693..db4f7bc 100644 --- a/third_party/blink/web_tests/external/wpt/xhr/resources/auth3/auth.py +++ b/third_party/blink/web_tests/external/wpt/xhr/resources/auth3/auth.py
@@ -3,7 +3,7 @@ from wptserve.utils import isomorphic_decode -here = os.path.split(os.path.abspath(isomorphic_decode(__file__)))[0] +here = os.path.dirname(os.path.abspath(isomorphic_decode(__file__))) def main(request, response): auth = imp.load_source(u"", os.path.join(here,
diff --git a/third_party/blink/web_tests/external/wpt/xhr/resources/auth4/auth.py b/third_party/blink/web_tests/external/wpt/xhr/resources/auth4/auth.py index 5ef3693..db4f7bc 100644 --- a/third_party/blink/web_tests/external/wpt/xhr/resources/auth4/auth.py +++ b/third_party/blink/web_tests/external/wpt/xhr/resources/auth4/auth.py
@@ -3,7 +3,7 @@ from wptserve.utils import isomorphic_decode -here = os.path.split(os.path.abspath(isomorphic_decode(__file__)))[0] +here = os.path.dirname(os.path.abspath(isomorphic_decode(__file__))) def main(request, response): auth = imp.load_source(u"", os.path.join(here,
diff --git a/third_party/blink/web_tests/external/wpt/xhr/resources/auth9/auth.py b/third_party/blink/web_tests/external/wpt/xhr/resources/auth9/auth.py index 5ef3693..db4f7bc 100644 --- a/third_party/blink/web_tests/external/wpt/xhr/resources/auth9/auth.py +++ b/third_party/blink/web_tests/external/wpt/xhr/resources/auth9/auth.py
@@ -3,7 +3,7 @@ from wptserve.utils import isomorphic_decode -here = os.path.split(os.path.abspath(isomorphic_decode(__file__)))[0] +here = os.path.dirname(os.path.abspath(isomorphic_decode(__file__))) def main(request, response): auth = imp.load_source(u"", os.path.join(here,
diff --git a/third_party/blink/web_tests/http/tests/devtools/portals/portals-sources-activate-expected.txt b/third_party/blink/web_tests/http/tests/devtools/portals/portals-sources-activate-expected.txt new file mode 100644 index 0000000..b5ce4e2 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/devtools/portals/portals-sources-activate-expected.txt
@@ -0,0 +1,7 @@ +Checks that breakpoint set inside a portalactivate event handler is hit on activation +error: Item to refresh is not present +Script execution paused. +Call stack: + 0) window.onportalactivate (append-predecessor.html:5) +Script execution resumed. +
diff --git a/third_party/blink/web_tests/http/tests/devtools/portals/portals-sources-activate.js b/third_party/blink/web_tests/http/tests/devtools/portals/portals-sources-activate.js new file mode 100644 index 0000000..bd98d8a2 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/devtools/portals/portals-sources-activate.js
@@ -0,0 +1,20 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + + +(async function () { + TestRunner.addResult(`Checks that breakpoint set inside a portalactivate event handler is hit on activation`); + await TestRunner.loadModule('sources_test_runner'); + await TestRunner.showPanel('sources'); + + await TestRunner.navigatePromise('resources/append-predecessor-host.html'); + + await SourcesTestRunner.startDebuggerTestPromise(); + const sourceFrame = await SourcesTestRunner.showScriptSourcePromise('append-predecessor.html'); + await SourcesTestRunner.toggleBreakpoint(sourceFrame, 4); + TestRunner.evaluateInPage(`setTimeout(() => document.querySelector('portal').activate());`); + const callFrames = await SourcesTestRunner.waitUntilPausedPromise(); + await SourcesTestRunner.captureStackTrace(callFrames); + SourcesTestRunner.completeDebuggerTest(); +})();
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/css/css-grid/layout-algorithm/grid-intrinsic-track-sizes-001-expected.png b/third_party/blink/web_tests/platform/linux/external/wpt/css/css-grid/layout-algorithm/grid-intrinsic-track-sizes-001-expected.png deleted file mode 100644 index 85f7712..0000000 --- a/third_party/blink/web_tests/platform/linux/external/wpt/css/css-grid/layout-algorithm/grid-intrinsic-track-sizes-001-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-intrinsic-track-sizes-001-expected.png b/third_party/blink/web_tests/platform/linux/virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-intrinsic-track-sizes-001-expected.png deleted file mode 100644 index 7c8932c..0000000 --- a/third_party/blink/web_tests/platform/linux/virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-intrinsic-track-sizes-001-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/css/css-grid/layout-algorithm/grid-intrinsic-track-sizes-001-expected.png b/third_party/blink/web_tests/platform/mac/external/wpt/css/css-grid/layout-algorithm/grid-intrinsic-track-sizes-001-expected.png deleted file mode 100644 index ebe7dd2..0000000 --- a/third_party/blink/web_tests/platform/mac/external/wpt/css/css-grid/layout-algorithm/grid-intrinsic-track-sizes-001-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-intrinsic-track-sizes-001-expected.png b/third_party/blink/web_tests/platform/mac/virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-intrinsic-track-sizes-001-expected.png deleted file mode 100644 index 69c3e43..0000000 --- a/third_party/blink/web_tests/platform/mac/virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-intrinsic-track-sizes-001-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/css/css-grid/layout-algorithm/grid-intrinsic-track-sizes-001-expected.png b/third_party/blink/web_tests/platform/win/external/wpt/css/css-grid/layout-algorithm/grid-intrinsic-track-sizes-001-expected.png deleted file mode 100644 index acb5a12..0000000 --- a/third_party/blink/web_tests/platform/win/external/wpt/css/css-grid/layout-algorithm/grid-intrinsic-track-sizes-001-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-intrinsic-track-sizes-001-expected.png b/third_party/blink/web_tests/platform/win/virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-intrinsic-track-sizes-001-expected.png deleted file mode 100644 index 0abebca2..0000000 --- a/third_party/blink/web_tests/platform/win/virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-intrinsic-track-sizes-001-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/external/wpt/css/css-grid/layout-algorithm/grid-intrinsic-track-sizes-001-expected.png b/third_party/blink/web_tests/platform/win7/external/wpt/css/css-grid/layout-algorithm/grid-intrinsic-track-sizes-001-expected.png deleted file mode 100644 index 906abfa..0000000 --- a/third_party/blink/web_tests/platform/win7/external/wpt/css/css-grid/layout-algorithm/grid-intrinsic-track-sizes-001-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-intrinsic-track-sizes-001-expected.png b/third_party/blink/web_tests/platform/win7/virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-intrinsic-track-sizes-001-expected.png deleted file mode 100644 index c6ca020f..0000000 --- a/third_party/blink/web_tests/platform/win7/virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-intrinsic-track-sizes-001-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-answer-expected.txt b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-answer-expected.txt index 3d7f780..6a545e1 100644 --- a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-answer-expected.txt +++ b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-answer-expected.txt
@@ -2,8 +2,8 @@ PASS setLocalDescription() with valid answer should succeed PASS setLocalDescription() with type answer and null sdp should use lastAnswer generated from createAnswer PASS setLocalDescription() with answer not created by own createAnswer() should reject with InvalidModificationError -FAIL Calling setLocalDescription(answer) from stable state should reject with InvalidModificationError promise_rejects_dom: function "function() { throw e }" threw object "OperationError: Failed to execute 'setLocalDescription' on 'RTCPeerConnection': Failed to set local answer sdp: Called in wrong state: kStable" that is not a DOMException InvalidModificationError: property "code" is equal to 0, expected 13 -FAIL Calling setLocalDescription(answer) from have-local-offer state should reject with InvalidModificationError promise_rejects_dom: function "function() { throw e }" threw object "OperationError: Failed to execute 'setLocalDescription' on 'RTCPeerConnection': Failed to set local answer sdp: Called in wrong state: kHaveLocalOffer" that is not a DOMException InvalidModificationError: property "code" is equal to 0, expected 13 +FAIL Calling setLocalDescription(answer) from stable state should reject with InvalidModificationError promise_rejects_dom: function "function() { throw e }" threw object "OperationError: Failed to execute 'setLocalDescription' on 'RTCPeerConnection': Failed to set local answer sdp: Called in wrong state: stable" that is not a DOMException InvalidModificationError: property "code" is equal to 0, expected 13 +FAIL Calling setLocalDescription(answer) from have-local-offer state should reject with InvalidModificationError promise_rejects_dom: function "function() { throw e }" threw object "OperationError: Failed to execute 'setLocalDescription' on 'RTCPeerConnection': Failed to set local answer sdp: Called in wrong state: have-local-offer" that is not a DOMException InvalidModificationError: property "code" is equal to 0, expected 13 FAIL Setting previously generated answer after a call to createOffer should work promise_test: Unhandled rejection with value: object "OperationError: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': Rollback not supported in Plan B" FAIL setLocalDescription(answer) should update internal state with a queued task, in the right order assert_not_equals: pendingRemoteDescription should not be set synchronously after a call to sLD got disallowed value null Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-rollback-expected.txt b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-rollback-expected.txt index c347ec6..b3fb6f5 100644 --- a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-rollback-expected.txt +++ b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-rollback-expected.txt
@@ -11,7 +11,7 @@ FAIL rollback of a remote offer should keep a transceiver without tracks assert_equals: expected 1 but got 0 FAIL explicit rollback of local offer should remove transceivers and transport promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'sender' of undefined" FAIL when using addTransceiver, implicit rollback of a local offer should visit stable state, but not fire negotiationneeded until we settle in stable promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'." -FAIL when using addTrack, implicit rollback of a local offer should visit stable state, but not fire negotiationneeded promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': Failed to set remote offer sdp: Called in wrong state: kHaveLocalOffer" +FAIL when using addTrack, implicit rollback of a local offer should visit stable state, but not fire negotiationneeded promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': Failed to set remote offer sdp: Called in wrong state: have-local-offer" FAIL rollback of a remote offer to negotiated stable state should enable applying of a local offer promise_test: Unhandled rejection with value: object "OperationError: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': Rollback not supported in Plan B" FAIL rollback of a local offer to negotiated stable state should enable applying of a remote offer assert_equals: expected 2 but got 0 FAIL rollback a local offer with audio direction change to negotiated stable state and then add video receiver promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'direction' of undefined"
diff --git a/third_party/closure_compiler/externs/file_manager_private.js b/third_party/closure_compiler/externs/file_manager_private.js index 8967ff6..7d18a799 100644 --- a/third_party/closure_compiler/externs/file_manager_private.js +++ b/third_party/closure_compiler/externs/file_manager_private.js
@@ -622,23 +622,23 @@ chrome.fileManagerPrivate.getFileTasks = function(entries, callback) {}; /** - * Gets the MIME type of a file. - * @param {!Entry} entry The file Entry. + * Gets the MIME type of an entry. + * @param {!Entry} entry The Entry. * @param {function((string|undefined))} callback The MIME type callback. */ chrome.fileManagerPrivate.getMimeType = function(entry, callback) {}; /** * Gets the content sniffed MIME type of a file. - * @param {!Blob} fileBlob Blob created from the file Entry. + * @param {!FileEntry} fileEntry The file entry. * @param {function((string|undefined))} callback The MIME type callback. * $(ref:runtime.lastError) will be set if there was an error. */ -chrome.fileManagerPrivate.getContentMimeType = function(fileBlob, callback) {}; +chrome.fileManagerPrivate.getContentMimeType = function(fileEntry, callback) {}; /** * Gets the content metadata from an Audio or Video file. - * @param {!Blob} fileBlob Blob created from the file Entry. + * @param {!FileEntry} fileEntry The file entry. * @param {string} mimeType The content sniffed mimeType of the file. * @param {boolean} includeImages If true, return metadata tags and thumbnail * images. If false, return metadata tags only. @@ -646,7 +646,7 @@ * callback The content MediaMetadata callback. * $(ref:runtime.lastError) will be set if there was an error. */ -chrome.fileManagerPrivate.getContentMetadata = function(fileBlob, mimeType, +chrome.fileManagerPrivate.getContentMetadata = function(fileEntry, mimeType, includeImages, callback) {}; /**
diff --git a/tools/android/dependency_analysis/js/.eslintrc.json b/tools/android/dependency_analysis/js/.eslintrc.json index 0225135..0ddbd37 100644 --- a/tools/android/dependency_analysis/js/.eslintrc.json +++ b/tools/android/dependency_analysis/js/.eslintrc.json
@@ -22,6 +22,7 @@ } }], "arrow-parens": ["warn", "as-needed"], + "generator-star-spacing": ["error", "before"], "vue/require-default-prop": "off", "vue/html-indent": ["error", 2, { "attribute": 2
diff --git a/tools/android/dependency_analysis/js/src/graph_view.js b/tools/android/dependency_analysis/js/src/graph_view.js index 0ab4eb0..154bd3d 100644 --- a/tools/android/dependency_analysis/js/src/graph_view.js +++ b/tools/android/dependency_analysis/js/src/graph_view.js
@@ -263,6 +263,18 @@ } /** + * @typedef {Object} PhantomTextNode A node that isn't displayed in the + * visualization, but affects the simulation. Used to prevent text overlap + * by being fixed to the right of real nodes (where the text is drawn). + * @property {boolean} isPhantomTextNode A flag (always true) used to + * differentiate these nodes from real ones when processing the simulation. + * @property {!GraphNode} refNode A reference to the node that this phantom node + * is attached to. + * @property {number} dist The distance away from `refNode` that this node + * should be fixed. + */ + +/** * A callback to be triggered whenever a node is clicked in the visualization. * @callback OnNodeClickedCallback * @param {!GraphNode} node The node that was clicked. @@ -350,21 +362,32 @@ .classed('graph-labels', true) .attr('pointer-events', 'none'); + /** @private {!Array<!PhantomTextNode>} */ + this.phantomTextNodes_ = []; + // Using .style() instead of .attr() gets px-based measurements of // percentage-based widths and heights. const width = parseInt(svg.style('width'), 10); const height = parseInt(svg.style('height'), 10); - const centeringStrengthY = 0.1; + const centeringStrengthY = 0.07; const centeringStrengthX = centeringStrengthY * (height / width); /** @private {*} */ this.simulation_ = d3.forceSimulation() .alphaMin(SIMULATION_SPEED_PARAMS.ALPHA_MIN) - .force('chargeForce', d3.forceManyBody().strength(-3000)) + .force('chargeForce', d3.forceManyBody().strength(node => { + if (node.isPhantomTextNode) { + return -1100; + } + return -3000; + })) .force('centerXForce', d3.forceX(width / 2).strength(node => { + if (node.isPhantomTextNode) { + return 0; + } if (node.visualizationState.selectedByFilter) { - return centeringStrengthX * 20; + return centeringStrengthX * 15; } if (node.visualizationState.outboundDepth <= 1) { return centeringStrengthX * 5; @@ -373,8 +396,11 @@ })) .force('centerYForce', d3.forceY(height / 2).strength(node => { + if (node.isPhantomTextNode) { + return 0; + } if (node.visualizationState.selectedByFilter) { - return centeringStrengthY * 20; + return centeringStrengthY * 15; } if (node.visualizationState.outboundDepth <= 1) { return centeringStrengthY * 5; @@ -670,6 +696,12 @@ if (shouldEase) { this.simulation_.velocityDecay(this.getEasedVelocityDecay(tickNum)); } + + // Reset phantom nodes to their fixed positions + this.phantomTextNodes_.forEach(phantomNode => { + phantomNode.x = phantomNode.refNode.x + phantomNode.dist; + phantomNode.y = phantomNode.refNode.y; + }); }; // If we don't ease, the default decay is sufficient for the entire reheat. @@ -705,15 +737,49 @@ } /** + * Generates sparse integers subset in [0, n] that's roughly evenly + * distributed. + * @generator + * @param {number} upperBound Exclusive upper bound on generated values. + * @param {number} separation Ideal separation between generated values. + * @yields {number} Generated integers. + */ + *generateSparseInts(upperBound, separation) { + for (let i = separation; i < upperBound; i += separation) { + yield i; + } + // Add an endpoint if the upper bound is far from the last value generated. + if (upperBound % separation >= separation / 2) { + yield upperBound - 1; + } + } + + /** * Updates the data source used for the visualization. * * @param {!D3GraphData} inputData The new data to use. */ updateGraphData(inputData) { + const DIST_MULTIPLIER = 6.6; const {nodes: inputNodes, edges: inputEdges} = inputData; + this.phantomTextNodes_ = []; + // Generate the phantom text nodes, the list of nodes to be included in the + // physics simulation at the place where node labels will be rendered. + for (const node of inputNodes) { + // A heuristic in the absence of exact label width: place phantom nodes + // approximately every 10 characters away from the real node. + for (const pos of this.generateSparseInts(node.displayName.length, 10)) { + this.phantomTextNodes_.push({ + isPhantomTextNode: true, + refNode: node, + dist: pos * DIST_MULTIPLIER, + }); + } + } + this.simulation_ - .nodes(inputNodes) + .nodes([...inputNodes, ...this.phantomTextNodes_]) .force('links', d3.forceLink(inputEdges).id(edge => edge.id)); let nodesAddedOrRemoved = false;
diff --git a/tools/android/dependency_analysis/js/src/vue_components/class_graph_page.vue b/tools/android/dependency_analysis/js/src/vue_components/class_graph_page.vue index 75fdc3c..bce632d 100644 --- a/tools/android/dependency_analysis/js/src/vue_components/class_graph_page.vue +++ b/tools/android/dependency_analysis/js/src/vue_components/class_graph_page.vue
@@ -187,9 +187,7 @@ if (this.displaySettingsData.nodeFilterData.filterList.length === 0) { // TODO(yjlong): This is test data. Remove this when no longer needed. [ - 'org.chromium.chrome.browser.tabmodel.AsyncTabParams', - 'org.chromium.chrome.browser.ActivityTabProvider', - 'org.chromium.chrome.browser.tabmodel.TabModelSelectorTabModelObserver', + 'org.chromium.chrome.browser.tab.TabImpl', ].forEach(nodeName => this.filterAddOrCheckNode(nodeName)); } },
diff --git a/tools/android/dependency_analysis/js/src/vue_components/package_graph_page.vue b/tools/android/dependency_analysis/js/src/vue_components/package_graph_page.vue index 837cb023..f768465 100644 --- a/tools/android/dependency_analysis/js/src/vue_components/package_graph_page.vue +++ b/tools/android/dependency_analysis/js/src/vue_components/package_graph_page.vue
@@ -159,11 +159,7 @@ if (this.displaySettingsData.nodeFilterData.filterList.length === 0) { // TODO(yjlong): This is test data. Remove this when no longer needed. [ - 'org.chromium.base', - 'org.chromium.chrome.browser.gsa', - 'org.chromium.chrome.browser.omaha', - 'org.chromium.chrome.browser.media', - 'org.chromium.ui.base', + 'org.chromium.chrome.browser.tab', ].forEach(nodeName => this.filterAddOrCheckNode(nodeName)); } },
diff --git a/tools/binary_size/libsupersize/caspian/wasmbuild.patch b/tools/binary_size/libsupersize/caspian/wasmbuild.patch index 65d45ded..ca20f29 100644 --- a/tools/binary_size/libsupersize/caspian/wasmbuild.patch +++ b/tools/binary_size/libsupersize/caspian/wasmbuild.patch
@@ -1,5 +1,5 @@ diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn -index 59dace167eef..ebbe3f37d101 100644 +index e011502180b5..9e55fcd6c74f 100644 --- a/build/config/BUILDCONFIG.gn +++ b/build/config/BUILDCONFIG.gn @@ -291,10 +291,11 @@ is_ios = current_os == "ios" @@ -16,10 +16,10 @@ # ============================================================================= # SOURCES FILTERS diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn -index f4ba837449b5..0fe4f8247c68 100644 +index 0b5de5cd7173..ff761c9b46b3 100644 --- a/build/config/compiler/BUILD.gn +++ b/build/config/compiler/BUILD.gn -@@ -578,6 +578,19 @@ config("compiler") { +@@ -581,6 +581,19 @@ config("compiler") { ldflags += [ "-stdlib=libc++" ] } @@ -39,7 +39,16 @@ # Add flags for link-time optimization. These flags enable # optimizations/transformations that require whole-program visibility at link # time, so they need to be applied to all translation units, and we may end up -@@ -1495,7 +1508,8 @@ config("default_warnings") { +@@ -704,7 +717,7 @@ config("compiler") { + if (use_lld) { + if (is_win) { + ldflags += [ "/call-graph-profile-sort:no" ] +- } else { ++ } else if (!is_wasm) { + ldflags += [ "-Wl,--no-call-graph-profile-sort" ] + } + } +@@ -1510,7 +1523,8 @@ config("default_warnings") { cflags += [ "-Wno-nonportable-include-path" ] } @@ -49,7 +58,7 @@ # Flags NaCl (Clang 3.7) and Xcode 9.2 (Clang clang-900.0.39.2) do not # recognize. cflags += [ -@@ -2257,6 +2271,9 @@ config("symbols") { +@@ -2275,6 +2289,9 @@ config("symbols") { "-debug-info-kind=constructor", ] }
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl index 03709a26..513c1ae 100644 --- a/tools/mb/mb_config.pyl +++ b/tools/mb/mb_config.pyl
@@ -109,7 +109,6 @@ 'chromium.android.fyi': { 'Android WebLayer P FYI (rel)': 'android_release_bot_minimal_symbols_arm64', - 'Android WebView P Blink-CORS FYI (rel)': 'android_release_bot_minimal_symbols_arm64_webview_google', 'Android WebView P FYI (rel)': 'android_release_bot_minimal_symbols_arm64_webview_google', 'android-marshmallow-x86-fyi-rel': 'android_release_bot_minimal_symbols_x86_fastbuild_resource_whitelisting_webview_google', 'android-weblayer-pie-x86-fyi-rel': 'android_release_bot_minimal_symbols_x86_fastbuild_webview_google', @@ -482,7 +481,6 @@ 'fuchsia-x64-cast': 'release_bot_fuchsia_cast', 'fuchsia-x64-dbg': 'debug_bot_fuchsia_compile_only', 'linux-bfcache-rel': 'release_bot', - 'linux-blink-cors-rel': 'release_bot_blink_minimal_symbols', 'linux-gcc-rel': 'release_bot_x86_minimal_symbols_no_clang_cxx11', 'linux-ozone-rel': 'ozone_linux_release_bot', 'linux-trusty-rel': 'gpu_tests_release_bot',
diff --git a/tools/metrics/BUILD.gn b/tools/metrics/BUILD.gn index 17c0874..61f9270 100644 --- a/tools/metrics/BUILD.gn +++ b/tools/metrics/BUILD.gn
@@ -4,23 +4,9 @@ action("histograms_xml") { script = "histograms/merge_xml.py" - sources = [ - "histograms/enums.xml", - "histograms/histograms.xml", - "histograms/histograms_xml/Fingerprint/histograms.xml", - "histograms/histograms_xml/UMA/histograms.xml", - "histograms/histograms_xml/histogram_suffixes.xml", - "histograms/histograms_xml/obsolete_histograms.xml", - "ukm/ukm.xml", - ] output = "$root_out_dir/histograms.xml" outputs = [ output ] - # TODO(crbug/1116096): Automatically list all histograms paths in the - # sources. - args = rebase_path(sources, root_build_dir) + [ - "--output", - rebase_path(output, root_build_dir), - ] + args = ["--output", rebase_path(output, root_build_dir)] } copy("actions_xml") {
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index e081650a..e4bcd4d 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -28755,6 +28755,8 @@ <int value="3405" label="GPUAdapter_Name"/> <int value="3406" label="WindowScreenInternal"/> <int value="3407" label="WindowScreenPrimary"/> + <int value="3408" label="ThirdPartyCookieRead"/> + <int value="3409" label="ThirdPartyCookieWrite"/> </enum> <enum name="FeaturePolicyAllowlistType"> @@ -59542,6 +59544,13 @@ auto-click"/> </enum> +<enum name="ReauthenticationEvent"> + <int value="0" label="Attempt"/> + <int value="1" label="Success"/> + <int value="2" label="Failure"/> + <int value="3" label="Device does't have a passcode set up."/> +</enum> + <enum name="ReceiverAppTypeSet"> <int value="0" label="Other"/> <int value="1" label="Web"/>
diff --git a/tools/metrics/histograms/histogram_paths.py b/tools/metrics/histograms/histogram_paths.py index 76c7842..ddc03768 100644 --- a/tools/metrics/histograms/histogram_paths.py +++ b/tools/metrics/histograms/histogram_paths.py
@@ -39,6 +39,7 @@ ] + HISTOGRAMS_XMLS_RELATIVE ENUMS_XML = path_util.GetInputFile(ENUMS_XML_RELATIVE) +UKM_XML = path_util.GetInputFile('tools/metrics/ukm/ukm.xml') HISTOGRAMS_XMLS = [path_util.GetInputFile(f) for f in HISTOGRAMS_XMLS_RELATIVE] OBSOLETE_XML = path_util.GetInputFile(OBSOLETE_XML_RELATIVE) ALL_XMLS = [ENUMS_XML, OBSOLETE_XML] + HISTOGRAMS_XMLS
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 2777b6d..ba27040 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -73807,6 +73807,26 @@ </summary> </histogram> +<histogram name="IOS.Reauth.Password.Autofill" enum="ReauthenticationEvent" + expires_after="2021-02-01"> + <owner>javierrobles@chromium.org</owner> + <owner>bling-team@google.com</owner> + <summary> + Tracks the results and attempts of reauthentication when using password + Autofill suggestions. + </summary> +</histogram> + +<histogram name="IOS.Reauth.Password.ManualFallback" + enum="ReauthenticationEvent" expires_after="2021-02-01"> + <owner>javierrobles@chromium.org</owner> + <owner>bling-team@google.com</owner> + <summary> + Tracks the results and attempts of reauthentication when using a password in + Manual Fallback. + </summary> +</histogram> + <histogram name="IOS.RepeatedExternalAppPromptResponse" enum="IOSRepeatedExternalAppPromptResponse" expires_after="2020-07-01"> <owner>mrefaat@chromium.org</owner>
diff --git a/tools/metrics/histograms/merge_xml.py b/tools/metrics/histograms/merge_xml.py index 396ee32..6bdccf7 100755 --- a/tools/metrics/histograms/merge_xml.py +++ b/tools/metrics/histograms/merge_xml.py
@@ -13,6 +13,7 @@ import expand_owners import extract_histograms import histogram_configuration_model +import histogram_paths import populate_enums @@ -160,11 +161,16 @@ def main(): parser = argparse.ArgumentParser() - parser.add_argument('inputs', nargs="+") parser.add_argument('--output', required=True) args = parser.parse_args() with open(args.output, 'w') as f: - f.write(PrettyPrintMergedFiles(args.inputs)) + # This is run by + # https://source.chromium.org/chromium/chromium/src/+/master:tools/metrics/BUILD.gn;drc=573e48309695102dec2da1e8f806c18c3200d414;l=5 + # to send the merged histograms.xml to the server side. Providing |UKM_XML| + # here is not to merge ukm.xml but to populate `UkmEventNameHash` enum + # values. + f.write(PrettyPrintMergedFiles( + histogram_paths.ALL_XMLS + [histogram_paths.UKM_XML])) if __name__ == '__main__':
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config index 71d22ae2..9e24dfb 100644 --- a/tools/perf/expectations.config +++ b/tools/perf/expectations.config
@@ -86,7 +86,6 @@ crbug.com/1062104 blink_perf.shadow_dom/imperative-api-insertbefore.html [ Skip ] # Benchmark: dromaeo -crbug.com/984578 [ linux ] dromaeo/http://dromaeo.com?dom-modify [ Skip ] crbug.com/1050065 [ android-pixel-2 ] dromaeo/http://dromaeo.com?dom-modify [ Skip ] # Benchmark: blink_perf.svg
diff --git a/ui/base/clipboard/clipboard_constants.cc b/ui/base/clipboard/clipboard_constants.cc index e435dd2..803c826c 100644 --- a/ui/base/clipboard/clipboard_constants.cc +++ b/ui/base/clipboard/clipboard_constants.cc
@@ -15,6 +15,12 @@ const char kMimeTypeRTF[] = "text/rtf"; const char kMimeTypePNG[] = "image/png"; +#if defined(OS_LINUX) || defined(OS_FUCHSIA) +const char kMimeTypeLinuxUtf8String[] = "UTF8_STRING"; +const char kMimeTypeLinuxString[] = "STRING"; +const char kMimeTypeLinuxText[] = "TEXT"; +#endif // defined(OS_LINUX) || defined(OS_FUCHSIA) + #if !defined(OS_APPLE) const char kMimeTypeWebCustomData[] = "chromium/x-web-custom-data"; const char kMimeTypeWebkitSmartPaste[] = "chromium/x-webkit-paste";
diff --git a/ui/base/clipboard/clipboard_constants.h b/ui/base/clipboard/clipboard_constants.h index bdc32ecba..f6b2422 100644 --- a/ui/base/clipboard/clipboard_constants.h +++ b/ui/base/clipboard/clipboard_constants.h
@@ -38,11 +38,11 @@ // Linux-specific MIME type constants (also used in Fuchsia). #if defined(OS_LINUX) || defined(OS_FUCHSIA) COMPONENT_EXPORT(UI_BASE_CLIPBOARD_TYPES) -constexpr char kMimeTypeLinuxUtf8String[] = "UTF8_STRING"; +extern const char kMimeTypeLinuxUtf8String[]; COMPONENT_EXPORT(UI_BASE_CLIPBOARD_TYPES) -constexpr char kMimeTypeLinuxString[] = "STRING"; +extern const char kMimeTypeLinuxString[]; COMPONENT_EXPORT(UI_BASE_CLIPBOARD_TYPES) -constexpr char kMimeTypeLinuxText[] = "TEXT"; +extern const char kMimeTypeLinuxText[]; #endif // defined(OS_LINUX) || defined(OS_FUCHSIA) #if !defined(OS_APPLE) @@ -76,7 +76,8 @@ #endif // defined(OS_APPLE) #if defined(OS_ANDROID) -COMPONENT_EXPORT(UI_BASE_CLIPBOARD_TYPES) extern const char kMimeTypeImageURI[]; +COMPONENT_EXPORT(UI_BASE_CLIPBOARD_TYPES) +extern const char kMimeTypeImageURI[]; #endif // defined(OS_ANDROID) } // namespace ui
diff --git a/ui/base/clipboard/clipboard_x11.cc b/ui/base/clipboard/clipboard_x11.cc index fff2b73e..b02f4bd 100644 --- a/ui/base/clipboard/clipboard_x11.cc +++ b/ui/base/clipboard/clipboard_x11.cc
@@ -709,6 +709,12 @@ data.AssignTo(result); } +#if defined(USE_OZONE) +bool ClipboardX11::IsSelectionBufferAvailable() const { + return true; +} +#endif // defined(USE_OZONE) + // |data_src| is not used. It's only passed to be consistent with other // platforms. void ClipboardX11::WritePortableRepresentations(
diff --git a/ui/base/clipboard/clipboard_x11.h b/ui/base/clipboard/clipboard_x11.h index d7b429e..9143b11 100644 --- a/ui/base/clipboard/clipboard_x11.h +++ b/ui/base/clipboard/clipboard_x11.h
@@ -65,6 +65,9 @@ void ReadData(const ClipboardFormatType& format, const ClipboardDataEndpoint* data_dst, std::string* result) const override; +#if defined(USE_OZONE) + bool IsSelectionBufferAvailable() const override; +#endif // defined(USE_OZONE) void WritePortableRepresentations( ClipboardBuffer buffer, const ObjectMap& objects,
diff --git a/ui/file_manager/file_manager/foreground/css/file_manager.css b/ui/file_manager/file_manager/foreground/css/file_manager.css index 62d63bc..dd66e60 100644 --- a/ui/file_manager/file_manager/foreground/css/file_manager.css +++ b/ui/file_manager/file_manager/foreground/css/file_manager.css
@@ -3718,7 +3718,9 @@ .file-type-filter-button { align-items: center; - border: 1px solid rgba(0, 0, 0, 15%); + /* don't use browser's default <button> background-color. */ + background-color: unset; + border: 1px solid rgba(0, 0, 0, 10%); border-radius: 20px; box-sizing: border-box; color: var(--google-grey-700); @@ -3728,15 +3730,46 @@ height: 32px; margin-inline-end: 3px; margin-inline-start: 3px; + outline: none; padding: 0 10px; } .file-type-filter-button.active { - background-color: var(--google-blue-50); + background-color: rgba(var(--google-blue-600-rgb), 6%); border: 1px solid transparent; color: var(--google-blue-600); } +.file-type-filter-button:not(:active):hover { + background-color: rgba(0, 0, 0, 4%); +} + +.file-type-filter-button.active:not(:active):hover { + background-color: rgba(var(--google-blue-600-rgb), 10%); +} + +html.pointer-active .file-type-filter-button:not(:active):hover { + background-color: unset; + cursor: default; +} + +html.pointer-active .file-type-filter-button.active:not(:active):hover { + background-color: rgba(var(--google-blue-600-rgb), 6%); + cursor: default; +} + +html.focus-outline-visible .file-type-filter-button:focus { + border: 1px solid var(--google-blue-600); +} + +.file-type-filter-button:active { + background-color: rgba(0, 0, 0, 12%); +} + +.file-type-filter-button.active:active { + background-color: rgba(var(--google-blue-600-rgb), 16%); +} + /* * Preventing FOUC */
diff --git a/ui/file_manager/file_manager/foreground/js/file_type_filters_controller.js b/ui/file_manager/file_manager/foreground/js/file_type_filters_controller.js index 01846fa..f7d8e945 100644 --- a/ui/file_manager/file_manager/foreground/js/file_type_filters_controller.js +++ b/ui/file_manager/file_manager/foreground/js/file_type_filters_controller.js
@@ -62,7 +62,8 @@ * @private */ createFilterButton_(label) { - const button = util.createChild(this.container_, 'file-type-filter-button'); + const button = + util.createChild(this.container_, 'file-type-filter-button', 'button'); button.textContent = label; button.onclick = this.onFilterButtonClicked_.bind(this); return button;
diff --git a/ui/ozone/platform/wayland/BUILD.gn b/ui/ozone/platform/wayland/BUILD.gn index 82219f3..07094f1 100644 --- a/ui/ozone/platform/wayland/BUILD.gn +++ b/ui/ozone/platform/wayland/BUILD.gn
@@ -239,7 +239,6 @@ testonly = true sources = [ - "test/constants.h", "test/global_object.cc", "test/global_object.h", "test/mock_buffer.cc",
diff --git a/ui/ozone/platform/wayland/host/wayland_data_device_unittest.cc b/ui/ozone/platform/wayland/host/wayland_data_device_unittest.cc index 13329fe..855982c 100644 --- a/ui/ozone/platform/wayland/host/wayland_data_device_unittest.cc +++ b/ui/ozone/platform/wayland/host/wayland_data_device_unittest.cc
@@ -15,7 +15,6 @@ #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/clipboard/clipboard_constants.h" #include "ui/events/base_event_utils.h" -#include "ui/ozone/platform/wayland/test/constants.h" #include "ui/ozone/platform/wayland/test/mock_surface.h" #include "ui/ozone/platform/wayland/test/test_data_device.h" #include "ui/ozone/platform/wayland/test/test_data_device_manager.h" @@ -32,6 +31,8 @@ namespace { +constexpr char kSampleClipboardText[] = "This is a sample text for clipboard."; + template <typename StringType> ui::PlatformClipboard::Data ToClipboardData(const StringType& data_string) { std::vector<uint8_t> data_vector; @@ -113,12 +114,12 @@ TEST_P(WaylandDataDeviceManagerTest, WriteToClipboard) { // The client writes data to the clipboard ... std::vector<uint8_t> data_vector( - wl::kSampleClipboardText, - wl::kSampleClipboardText + strlen(wl::kSampleClipboardText)); + kSampleClipboardText, + kSampleClipboardText + strlen(kSampleClipboardText)); clipboard_client_->SetData( scoped_refptr<base::RefCountedBytes>( base::RefCountedBytes::TakeVector(&data_vector)), - {wl::kTextMimeTypeUtf8}, base::BindOnce([]() {})); + {kMimeTypeTextUtf8}, base::BindOnce([]() {})); Sync(); // ... and the server reads it. @@ -126,11 +127,11 @@ auto callback = base::BindOnce( [](base::RunLoop* loop, std::vector<uint8_t>&& data) { std::string string_data(data.begin(), data.end()); - EXPECT_EQ(wl::kSampleClipboardText, string_data); + EXPECT_EQ(kSampleClipboardText, string_data); loop->Quit(); }, &run_loop); - data_device_manager_->data_source()->ReadData(wl::kTextMimeTypeUtf8, + data_device_manager_->data_source()->ReadData(kMimeTypeTextUtf8, std::move(callback)); run_loop.Run(); } @@ -139,8 +140,8 @@ // TODO(nickdiego): implement this in terms of an actual wl_surface that // gets focused and compositor sends data_device data to it. auto* data_offer = data_device_manager_->data_device()->OnDataOffer(); - data_offer->OnOffer(wl::kTextMimeTypeUtf8, - ToClipboardData(std::string(wl::kSampleClipboardText))); + data_offer->OnOffer(kMimeTypeTextUtf8, + ToClipboardData(std::string(kSampleClipboardText))); data_device_manager_->data_device()->OnSelection(data_offer); Sync(); @@ -151,9 +152,9 @@ base::BindOnce([](const base::Optional<PlatformClipboard::Data>& data) { auto& bytes = data->get()->data(); std::string string_data = std::string(bytes.begin(), bytes.end()); - EXPECT_EQ(wl::kSampleClipboardText, string_data); + EXPECT_EQ(kSampleClipboardText, string_data); }); - clipboard_client_->ReadData(wl::kTextMimeTypeUtf8, std::move(callback)); + clipboard_client_->ReadData(kMimeTypeTextUtf8, std::move(callback)); Sync(); } @@ -167,18 +168,18 @@ std::string string_data = std::string(bytes.begin(), bytes.end()); EXPECT_EQ("", string_data); }); - clipboard_client_->ReadData(wl::kTextMimeTypeUtf8, std::move(callback)); + clipboard_client_->ReadData(kMimeTypeTextUtf8, std::move(callback)); } TEST_P(WaylandDataDeviceManagerTest, IsSelectionOwner) { auto callback = base::BindOnce([]() {}); std::vector<uint8_t> data_vector( - wl::kSampleClipboardText, - wl::kSampleClipboardText + strlen(wl::kSampleClipboardText)); + kSampleClipboardText, + kSampleClipboardText + strlen(kSampleClipboardText)); clipboard_client_->SetData( scoped_refptr<base::RefCountedBytes>( base::RefCountedBytes::TakeVector(&data_vector)), - {wl::kTextMimeTypeUtf8}, std::move(callback)); + {kMimeTypeTextUtf8}, std::move(callback)); Sync(); ASSERT_TRUE(clipboard_client_->IsSelectionOwner());
diff --git a/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc b/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc index 09bb92f..8bd11603 100644 --- a/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc +++ b/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc
@@ -26,7 +26,6 @@ #include "ui/ozone/platform/wayland/host/wayland_data_drag_controller.h" #include "ui/ozone/platform/wayland/host/wayland_data_source.h" #include "ui/ozone/platform/wayland/host/wayland_toplevel_window.h" -#include "ui/ozone/platform/wayland/test/constants.h" #include "ui/ozone/platform/wayland/test/mock_surface.h" #include "ui/ozone/platform/wayland/test/test_data_device.h" #include "ui/ozone/platform/wayland/test/test_data_device_manager.h" @@ -47,6 +46,9 @@ namespace { +constexpr char kSampleTextForDragAndDrop[] = + "This is a sample text for drag-and-drop."; + constexpr FilenameToURLPolicy kFilenameToURLPolicy = FilenameToURLPolicy::CONVERT_FILENAMES; @@ -133,7 +135,7 @@ } base::string16 sample_text_for_dnd() const { - static auto text = base::ASCIIToUTF16(wl::kSampleTextForDragAndDrop); + static auto text = base::ASCIIToUTF16(kSampleTextForDragAndDrop); return text; } @@ -157,11 +159,11 @@ auto callback = base::BindOnce( [](base::RunLoop* loop, std::vector<uint8_t>&& data) { std::string result(data.begin(), data.end()); - EXPECT_EQ(wl::kSampleTextForDragAndDrop, result); + EXPECT_EQ(kSampleTextForDragAndDrop, result); loop->Quit(); }, &run_loop); - data_device_manager_->data_source()->ReadData(wl::kTextMimeTypeUtf8, + data_device_manager_->data_source()->ReadData(kMimeTypeTextUtf8, std::move(callback)); run_loop.Run(); @@ -263,7 +265,7 @@ auto callback = base::BindOnce( [](base::RunLoop* loop, std::vector<uint8_t>&& data) { std::string result(data.begin(), data.end()); - EXPECT_EQ(wl::kSampleTextForDragAndDrop, result); + EXPECT_EQ(kSampleTextForDragAndDrop, result); loop->Quit(); }, &run_loop); @@ -275,9 +277,8 @@ TEST_P(WaylandDataDragControllerTest, ReceiveDrag) { auto* data_offer = data_device_manager_->data_device()->OnDataOffer(); - data_offer->OnOffer( - kMimeTypeText, - ToClipboardData(std::string(wl::kSampleTextForDragAndDrop))); + data_offer->OnOffer(kMimeTypeText, + ToClipboardData(std::string(kSampleTextForDragAndDrop))); gfx::Point entered_point(10, 10); // The server sends an enter event. @@ -300,7 +301,7 @@ std::string result; EXPECT_TRUE(contents); result.assign(contents->front_as<char>(), contents->size()); - EXPECT_EQ(wl::kSampleTextForDragAndDrop, result); + EXPECT_EQ(kSampleTextForDragAndDrop, result); }); // The client requests the data and gets callback with it. @@ -313,9 +314,8 @@ TEST_P(WaylandDataDragControllerTest, DropSeveralMimeTypes) { auto* data_offer = data_device_manager_->data_device()->OnDataOffer(); - data_offer->OnOffer( - kMimeTypeText, - ToClipboardData(std::string(wl::kSampleTextForDragAndDrop))); + data_offer->OnOffer(kMimeTypeText, + ToClipboardData(std::string(kSampleTextForDragAndDrop))); data_offer->OnOffer(kMimeTypeMozillaURL, ToClipboardData(base::UTF8ToUTF16( "https://sample.com/\r\n" "Sample")));
diff --git a/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc b/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc index 503c35b6..97ec3766 100644 --- a/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc +++ b/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc
@@ -21,7 +21,6 @@ #include "ui/ozone/platform/wayland/host/wayland_window.h" #include "ui/ozone/platform/wayland/host/wayland_window_drag_controller.h" #include "ui/ozone/platform/wayland/host/wayland_window_manager.h" -#include "ui/ozone/platform/wayland/test/constants.h" #include "ui/ozone/platform/wayland/test/mock_pointer.h" #include "ui/ozone/platform/wayland/test/mock_surface.h" #include "ui/ozone/platform/wayland/test/test_data_device.h"
diff --git a/ui/ozone/platform/wayland/test/constants.h b/ui/ozone/platform/wayland/test/constants.h deleted file mode 100644 index e06dc71..0000000 --- a/ui/ozone/platform/wayland/test/constants.h +++ /dev/null
@@ -1,18 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_OZONE_PLATFORM_WAYLAND_TEST_CONSTANTS_H_ -#define UI_OZONE_PLATFORM_WAYLAND_TEST_CONSTANTS_H_ - -namespace wl { - -constexpr char kSampleClipboardText[] = "This is a sample text for clipboard."; -constexpr char kSampleTextForDragAndDrop[] = - "This is a sample text for drag-and-drop."; -constexpr char kTextMimeTypeUtf8[] = "text/plain;charset=utf-8"; -constexpr char kTextMimeTypeText[] = "text/plain"; - -} // namespace wl - -#endif // UI_OZONE_PLATFORM_WAYLAND_TEST_CONSTANTS_H_
diff --git a/ui/ozone/platform/wayland/test/test_data_offer.cc b/ui/ozone/platform/wayland/test/test_data_offer.cc index 4ba0bc14..73736c7b 100644 --- a/ui/ozone/platform/wayland/test/test_data_offer.cc +++ b/ui/ozone/platform/wayland/test/test_data_offer.cc
@@ -14,7 +14,6 @@ #include "base/task/post_task.h" #include "base/task/task_traits.h" #include "base/task/thread_pool.h" -#include "ui/ozone/platform/wayland/test/constants.h" namespace wl {
diff --git a/ui/ozone/platform/wayland/test/test_data_source.cc b/ui/ozone/platform/wayland/test/test_data_source.cc index 4d11ec8..28acb1f 100644 --- a/ui/ozone/platform/wayland/test/test_data_source.cc +++ b/ui/ozone/platform/wayland/test/test_data_source.cc
@@ -18,7 +18,6 @@ #include "base/task/task_traits.h" #include "base/task/thread_pool.h" #include "base/task_runner_util.h" -#include "ui/ozone/platform/wayland/test/constants.h" namespace wl {
diff --git a/ui/views/bubble/bubble_dialog_delegate_view.cc b/ui/views/bubble/bubble_dialog_delegate_view.cc index 10767c3..77d75d8 100644 --- a/ui/views/bubble/bubble_dialog_delegate_view.cc +++ b/ui/views/bubble/bubble_dialog_delegate_view.cc
@@ -378,12 +378,8 @@ std::unique_ptr<BubbleBorder> border = std::make_unique<BubbleBorder>(arrow(), GetShadow(), color()); - if (CustomShadowsSupported() && GetParams().round_corners) { - border->SetCornerRadius( - base::FeatureList::IsEnabled(features::kEnableMDRoundedCornersOnDialogs) - ? provider->GetCornerRadiusMetric(views::EMPHASIS_MEDIUM) - : 2); - } + if (CustomShadowsSupported() && GetParams().round_corners) + border->SetCornerRadius(GetCornerRadius()); frame->SetBubbleBorder(std::move(border)); return frame;
diff --git a/ui/views/bubble/bubble_frame_view.cc b/ui/views/bubble/bubble_frame_view.cc index f61e398..fed49d4 100644 --- a/ui/views/bubble/bubble_frame_view.cc +++ b/ui/views/bubble/bubble_frame_view.cc
@@ -19,6 +19,7 @@ #include "ui/display/display.h" #include "ui/display/screen.h" #include "ui/gfx/color_palette.h" +#include "ui/gfx/geometry/rounded_corners_f.h" #include "ui/gfx/geometry/vector2d.h" #include "ui/gfx/skia_util.h" #include "ui/native_theme/native_theme.h" @@ -184,29 +185,19 @@ DCHECK_EQ(GetBoundsForClientView().size(), size); DCHECK_EQ(GetWidget()->client_view()->size(), size); - const int radius = bubble_border_->corner_radius(); - const gfx::Insets insets = - GetClientInsetsForFrameWidth(GetContentsBounds().width()); + const gfx::RoundedCornersF corner_radii = GetClientCornerRadii(); - // A mask is not needed if the content does not overlap the rounded corners. - if ((insets.top() > radius && insets.bottom() > radius) || - (insets.left() > radius && insets.right() > radius)) { + // If corner radii are all zero we do not need to apply a mask. + if (corner_radii.IsEmpty()) return false; - } - // We want to clip the client view to a rounded rect that's consistent with - // the bubble's rounded border. However, if there is a header, the top of the - // client view should be straight and flush with that. Likewise, if there is - // a footer, the client view should be straight and flush with that. Therefore - // we set the corner radii separately for top and bottom. - const SkRect rect = SkRect::MakeIWH(size.width(), size.height()); - const SkScalar top_radius = header_view_ ? 0.0f : radius; - const SkScalar bottom_radius = footnote_container_ ? 0.0f : radius; // Format is upper-left x, upper-left y, upper-right x, and so forth, // clockwise around the boundary. - SkScalar radii[]{top_radius, top_radius, top_radius, top_radius, - bottom_radius, bottom_radius, bottom_radius, bottom_radius}; - path->addRoundRect(rect, radii); + SkScalar radii[]{corner_radii.upper_left(), corner_radii.upper_left(), + corner_radii.upper_right(), corner_radii.upper_right(), + corner_radii.lower_right(), corner_radii.lower_right(), + corner_radii.lower_left(), corner_radii.lower_left()}; + path->addRoundRect(SkRect::MakeIWH(size.width(), size.height()), radii); return true; } @@ -664,6 +655,34 @@ return close_->GetMirroredBounds(); } +gfx::RoundedCornersF BubbleFrameView::GetClientCornerRadii() const { + DCHECK(bubble_border_); + const int radius = bubble_border_->corner_radius(); + const gfx::Insets insets = + GetClientInsetsForFrameWidth(GetContentsBounds().width()); + + // Rounded corners do not need to be applied to the client view if the client + // view is sufficiently inset such that its unclipped bounds will not + // intersect with the corners of the containing bubble frame view. + if ((insets.top() > radius && insets.bottom() > radius) || + (insets.left() > radius && insets.right() > radius)) { + return gfx::RoundedCornersF(); + } + + // We want to clip the client view to a rounded rect that's consistent with + // the bubble's rounded border. However, if there is a header, the top of the + // client view should be straight and flush with that. Likewise, if there is + // a footer, the client view should be straight and flush with that. Therefore + // we set the corner radii separately for top and bottom. + gfx::RoundedCornersF corner_radii; + corner_radii.set_upper_left(header_view_ ? 0 : radius); + corner_radii.set_upper_right(header_view_ ? 0 : radius); + corner_radii.set_lower_left(footnote_container_ ? 0 : radius); + corner_radii.set_lower_right(footnote_container_ ? 0 : radius); + + return corner_radii; +} + void BubbleFrameView::MirrorArrowIfOutOfBounds( bool vertical, const gfx::Rect& anchor_rect,
diff --git a/ui/views/bubble/bubble_frame_view.h b/ui/views/bubble/bubble_frame_view.h index 8e71b91..a0f13f8 100644 --- a/ui/views/bubble/bubble_frame_view.h +++ b/ui/views/bubble/bubble_frame_view.h
@@ -20,6 +20,10 @@ #include "ui/views/input_event_activation_protector.h" #include "ui/views/window/non_client_view.h" +namespace gfx { +class RoundedCornersF; +} + namespace views { class FootnoteContainerView; @@ -179,6 +183,12 @@ bool IsCloseButtonVisible() const; gfx::Rect GetCloseButtonMirroredBounds() const; + // Helper function that gives the corner radius values that should be applied + // to the BubbleFrameView's client view. These values depend on the amount of + // inset present on the client view and the presence of header and footer + // views. + gfx::RoundedCornersF GetClientCornerRadii() const; + BubbleBorder* bubble_border_for_testing() const { return bubble_border_; } private:
diff --git a/ui/views/window/dialog_delegate.cc b/ui/views/window/dialog_delegate.cc index 4f8d33641..0d0347e7 100644 --- a/ui/views/window/dialog_delegate.cc +++ b/ui/views/window/dialog_delegate.cc
@@ -233,13 +233,8 @@ border->set_use_theme_background_color(true); DialogDelegate* delegate = widget->widget_delegate()->AsDialogDelegate(); if (delegate) { - if (delegate->GetParams().round_corners) { - border->SetCornerRadius( - base::FeatureList::IsEnabled( - features::kEnableMDRoundedCornersOnDialogs) - ? provider->GetCornerRadiusMetric(views::EMPHASIS_MEDIUM) - : 2); - } + if (delegate->GetParams().round_corners) + border->SetCornerRadius(delegate->GetCornerRadius()); frame->SetFootnoteView(delegate->DisownFootnoteView()); } frame->SetBubbleBorder(std::move(border)); @@ -411,6 +406,14 @@ return ax::mojom::Role::kDialog; } +int DialogDelegate::GetCornerRadius() const { + return base::FeatureList::IsEnabled( + features::kEnableMDRoundedCornersOnDialogs) + ? LayoutProvider::Get()->GetCornerRadiusMetric( + views::EMPHASIS_MEDIUM) + : 2; +} + std::unique_ptr<View> DialogDelegate::DisownFootnoteView() { return std::move(footnote_view_); }
diff --git a/ui/views/window/dialog_delegate.h b/ui/views/window/dialog_delegate.h index c4364e1..76a546592 100644 --- a/ui/views/window/dialog_delegate.h +++ b/ui/views/window/dialog_delegate.h
@@ -285,6 +285,8 @@ const Params& GetParams() const { return params_; } + int GetCornerRadius() const; + // Return ownership of the footnote view for this dialog. Only use this in // subclass overrides of CreateNonClientFrameView. std::unique_ptr<View> DisownFootnoteView();
diff --git a/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/PageInfoTest.java b/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/PageInfoTest.java index 7eb41809..570c491 100644 --- a/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/PageInfoTest.java +++ b/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/PageInfoTest.java
@@ -10,6 +10,7 @@ import static androidx.test.espresso.matcher.ViewMatchers.withText; import android.content.Context; +import android.os.Bundle; import androidx.test.filters.SmallTest; @@ -37,8 +38,10 @@ @SmallTest @MinWebLayerVersion(84) public void testPageInfoLaunches() { + Bundle extras = new Bundle(); + extras.putBoolean(InstrumentationActivity.EXTRA_URLBAR_TEXT_CLICKABLE, false); InstrumentationActivity activity = mActivityTestRule.launchShellWithUrl( - mActivityTestRule.getTestDataURL("simple_page.html")); + mActivityTestRule.getTestDataURL("simple_page.html"), extras); Context remoteContext = TestWebLayer.getRemoteContext(activity.getApplicationContext()); int buttonId = ResourceUtil.getIdentifier(remoteContext, "id/security_button"); @@ -56,4 +59,27 @@ } }); } + + @Test + @SmallTest + @MinWebLayerVersion(86) + public void testSingleTappableContainer() { + Bundle extras = new Bundle(); + extras.putBoolean(InstrumentationActivity.EXTRA_URLBAR_TEXT_CLICKABLE, true); + InstrumentationActivity activity = mActivityTestRule.launchShellWithUrl( + mActivityTestRule.getTestDataURL("simple_page.html"), extras); + + TestThreadUtils.runOnUiThreadBlocking(() -> { + StrictModeContext ignored = StrictModeContext.allowDiskReads(); + EventUtils.simulateTouchCenterOfView(activity.getUrlBarView()); + }); + CriteriaHelper.pollInstrumentationThread(() -> { + try { + onView(withText("Your connection to this site is not secure")) + .check(matches(isDisplayed())); + } catch (Error e) { + throw new CriteriaNotSatisfiedException(e.toString()); + } + }); + } }
diff --git a/weblayer/browser/favicon/favicon_backend_wrapper.cc b/weblayer/browser/favicon/favicon_backend_wrapper.cc index 6549964..9f3108b 100644 --- a/weblayer/browser/favicon/favicon_backend_wrapper.cc +++ b/weblayer/browser/favicon/favicon_backend_wrapper.cc
@@ -76,17 +76,22 @@ } void FaviconBackendWrapper::SetFaviconsOutOfDateForPage(const GURL& page_url) { - if (favicon_backend_) - favicon_backend_->SetFaviconsOutOfDateForPage(page_url); + if (favicon_backend_ && + favicon_backend_->SetFaviconsOutOfDateForPage(page_url)) { + ScheduleCommit(); + } } void FaviconBackendWrapper::SetFavicons(const base::flat_set<GURL>& page_urls, favicon_base::IconType icon_type, const GURL& icon_url, const std::vector<SkBitmap>& bitmaps) { - if (favicon_backend_) { - favicon_backend_->SetFavicons(page_urls, icon_type, icon_url, bitmaps, - favicon::FaviconBitmapType::ON_VISIT); + if (favicon_backend_ && + favicon_backend_ + ->SetFavicons(page_urls, icon_type, icon_url, bitmaps, + favicon::FaviconBitmapType::ON_VISIT) + .did_change_database()) { + ScheduleCommit(); } } @@ -100,7 +105,7 @@ std::set<GURL> changed_urls = favicon_backend_->CloneFaviconMappingsForPages( {page_url_to_read}, icon_types, page_urls_to_write); if (!changed_urls.empty()) - ScheduleCommitForFavicons(); + ScheduleCommit(); } std::vector<favicon_base::FaviconRawBitmapResult> @@ -118,23 +123,23 @@ const std::vector<int>& desired_sizes) { if (!favicon_backend_) return {}; - return favicon_backend_->UpdateFaviconMappingsAndFetch( + auto result = favicon_backend_->UpdateFaviconMappingsAndFetch( page_urls, icon_url, icon_type, desired_sizes); + if (!result.updated_page_urls.empty()) + ScheduleCommit(); + return result.bitmap_results; } void FaviconBackendWrapper::DeleteFaviconMappings( const base::flat_set<GURL>& page_urls, favicon_base::IconType icon_type) { if (!favicon_backend_) - favicon_backend_->DeleteFaviconMappings(page_urls, icon_type); -} + return; -void FaviconBackendWrapper::ScheduleCommitForFavicons() { - if (!commit_timer_.IsRunning()) { - // 10 seconds matches that of HistoryBackend. - commit_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(10), this, - &FaviconBackendWrapper::Commit); - } + auto deleted_page_urls = + favicon_backend_->DeleteFaviconMappings(page_urls, icon_type); + if (!deleted_page_urls.empty()) + ScheduleCommit(); } std::vector<GURL> FaviconBackendWrapper::GetCachedRecentRedirectsForPage( @@ -146,14 +151,16 @@ return {page_url}; } -void FaviconBackendWrapper::OnFaviconChangedForPageAndRedirects( - const GURL& page_url) { - // Nothing to do here as WebLayer doesn't notify of favicon changes through - // this code path. -} - FaviconBackendWrapper::~FaviconBackendWrapper() = default; +void FaviconBackendWrapper::ScheduleCommit() { + if (!commit_timer_.IsRunning()) { + // 10 seconds matches that of HistoryBackend. + commit_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(10), this, + &FaviconBackendWrapper::Commit); + } +} + void FaviconBackendWrapper::Commit() { if (favicon_backend_) favicon_backend_->Commit();
diff --git a/weblayer/browser/favicon/favicon_backend_wrapper.h b/weblayer/browser/favicon/favicon_backend_wrapper.h index 7f83faa..eb74c63 100644 --- a/weblayer/browser/favicon/favicon_backend_wrapper.h +++ b/weblayer/browser/favicon/favicon_backend_wrapper.h
@@ -73,10 +73,8 @@ favicon_base::IconType icon_type); // favicon::FaviconBackendDelegate: - void ScheduleCommitForFavicons() override; std::vector<GURL> GetCachedRecentRedirectsForPage( const GURL& page_url) override; - void OnFaviconChangedForPageAndRedirects(const GURL& page_url) override; private: friend class base::RefCountedDeleteOnSequence<FaviconBackendWrapper>; @@ -85,6 +83,7 @@ ~FaviconBackendWrapper() override; + void ScheduleCommit(); void Commit(); // Called to expire (remove) out of date icons and restart the timer.
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/UrlBarControllerImpl.java b/weblayer/browser/java/org/chromium/weblayer_private/UrlBarControllerImpl.java index 8824ddd..496c520 100644 --- a/weblayer/browser/java/org/chromium/weblayer_private/UrlBarControllerImpl.java +++ b/weblayer/browser/java/org/chromium/weblayer_private/UrlBarControllerImpl.java
@@ -81,8 +81,8 @@ @Override public IObjectWrapper /* View */ createUrlBarView(Bundle options, - @Nullable IObjectWrapper /* OnLongClickListener */ textClickListener, - @Nullable IObjectWrapper /* OnLongClickListener */ textLongClickListener) { + @Nullable IObjectWrapper /* OnLongClickListener */ clickListener, + @Nullable IObjectWrapper /* OnLongClickListener */ longClickListener) { StrictModeWorkaround.apply(); if (mBrowserImpl == null) { throw new IllegalStateException("UrlBarView cannot be created without a valid Browser"); @@ -90,8 +90,7 @@ Context context = mBrowserImpl.getContext(); if (context == null) throw new IllegalStateException("BrowserFragment not attached yet."); - UrlBarView urlBarView = - new UrlBarView(context, options, textClickListener, textLongClickListener); + UrlBarView urlBarView = new UrlBarView(context, options, clickListener, longClickListener); return ObjectWrapper.wrap(urlBarView); } @@ -107,12 +106,12 @@ private TextView mUrlTextView; private ImageButton mSecurityButton; private final SecurityButtonAnimationDelegate mSecurityButtonAnimationDelegate; - OnClickListener mTextClickListener; - OnLongClickListener mTextLongClickListener; + OnClickListener mUrlBarClickListener; + OnLongClickListener mUrlBarLongClickListener; public UrlBarView(@NonNull Context context, @NonNull Bundle options, - @Nullable IObjectWrapper /* OnClickListener */ textClickListener, - @Nullable IObjectWrapper /* OnLongClickListener */ textLongClickListener) { + @Nullable IObjectWrapper /* OnClickListener */ clickListener, + @Nullable IObjectWrapper /* OnLongClickListener */ longClickListener) { super(context); setGravity(Gravity.CENTER_HORIZONTAL); @@ -129,9 +128,9 @@ mSecurityButton = (ImageButton) findViewById(R.id.security_button); mSecurityButtonAnimationDelegate = new SecurityButtonAnimationDelegate( mSecurityButton, mUrlTextView, R.dimen.security_status_icon_size); - mTextClickListener = ObjectWrapper.unwrap(textClickListener, OnClickListener.class); - mTextLongClickListener = - ObjectWrapper.unwrap(textLongClickListener, OnLongClickListener.class); + mUrlBarClickListener = ObjectWrapper.unwrap(clickListener, OnClickListener.class); + mUrlBarLongClickListener = + ObjectWrapper.unwrap(longClickListener, OnLongClickListener.class); updateView(); } @@ -182,19 +181,25 @@ ContextCompat.getColor(embedderContext, mUrlIconColor))); } - mSecurityButton.setOnClickListener(v -> { showPageInfoUi(v); }); - - if (mTextClickListener != null) { - mUrlTextView.setOnClickListener(mTextClickListener); - } - if (mShowPageInfoWhenUrlTextClicked) { - assert (mTextClickListener == null); - mUrlTextView.setOnClickListener(v -> { showPageInfoUi(v); }); - } + // Set clicklisteners on the entire UrlBarView. + assert (mUrlBarClickListener == null); + mSecurityButton.setClickable(false); + setOnClickListener(v -> { showPageInfoUi(v); }); - if (mTextLongClickListener != null) { - mUrlTextView.setOnLongClickListener(mTextLongClickListener); + if (mUrlBarLongClickListener != null) { + setOnLongClickListener(mUrlBarLongClickListener); + } + } else { + // Set a clicklistener on the security status and TextView separately. This mode + // can be used to create an editable URL bar using WebLayer. + mSecurityButton.setOnClickListener(v -> { showPageInfoUi(v); }); + if (mUrlBarClickListener != null) { + mUrlTextView.setOnClickListener(mUrlBarClickListener); + } + if (mUrlBarLongClickListener != null) { + mUrlTextView.setOnLongClickListener(mUrlBarLongClickListener); + } } }
diff --git a/weblayer/shell/android/shell_apk/src/org/chromium/weblayer/shell/InstrumentationActivity.java b/weblayer/shell/android/shell_apk/src/org/chromium/weblayer/shell/InstrumentationActivity.java index 3889aa3..9852e14b 100644 --- a/weblayer/shell/android/shell_apk/src/org/chromium/weblayer/shell/InstrumentationActivity.java +++ b/weblayer/shell/android/shell_apk/src/org/chromium/weblayer/shell/InstrumentationActivity.java
@@ -54,6 +54,10 @@ // True by default. If set to false, the test should call loadWebLayerSync. public static final String EXTRA_CREATE_WEBLAYER = "EXTRA_CREATE_WEBLAYER"; + // Used in tests to specify whether WebLayer URL bar should set default click listeners + // that show Page Info UI on its TextView. + public static final String EXTRA_URLBAR_TEXT_CLICKABLE = "EXTRA_URLBAR_TEXT_CLICKABLE"; + private Profile mProfile; private Fragment mFragment; private Browser mBrowser; @@ -332,12 +336,15 @@ } private void createUrlBarView() { - mUrlBarView = mBrowser.getUrlBarController().createUrlBarView( - UrlBarOptions.builder() - .setTextSizeSP(DEFAULT_TEXT_SIZE) - .setTextColor(android.R.color.black) - .setIconColor(android.R.color.black) - .build()); + UrlBarOptions.Builder optionsBuilder = UrlBarOptions.builder() + .setTextSizeSP(DEFAULT_TEXT_SIZE) + .setTextColor(android.R.color.black) + .setIconColor(android.R.color.black); + if (getIntent().getBooleanExtra(EXTRA_URLBAR_TEXT_CLICKABLE, true)) { + optionsBuilder = optionsBuilder.showPageInfoWhenTextIsClicked(); + } + + mUrlBarView = mBrowser.getUrlBarController().createUrlBarView(optionsBuilder.build()); // The background of the top-view must be opaque, otherwise it bleeds through to the // cc::Layer that mirrors the contents of the top-view.