diff --git a/DEPS b/DEPS index f511bc8..edc260c 100644 --- a/DEPS +++ b/DEPS
@@ -307,11 +307,11 @@ # 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': '93fbb15abfe4161e4280d20498749b3a1e12415b', + 'v8_revision': '4b00f2f2737f7c2b1e4ca41ca2dc7c8a55c805d7', # 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': 'e939f9a9cf76533d3ddaa1bb279813708e7e7d94', + 'angle_revision': '0ddebba548bf85ae807d1d7d3641bd79f7a189b2', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -394,7 +394,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': 'a89ba04022e79cb59bdcdf510392cd2e6cd749b3', + 'devtools_frontend_revision': '5eb9e244097ff37b64738ca222787348f6f05920', # 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. @@ -418,7 +418,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'dawn_revision': 'a1a25d682c7d3ed4206b4b40e6c36f82bfcfa0ea', + 'dawn_revision': 'e9f87b69b96384c508aa2d408601e0881035ff3a', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -818,7 +818,7 @@ 'src/clank': { 'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' + - '99685ad0653a10fa9254bf04244740661468e99e', + '8224cc0dada49684ca5f40d26820ec2d3962ee33', 'condition': 'checkout_android and checkout_src_internal', }, @@ -980,7 +980,7 @@ 'packages': [ { 'package': 'chromium/third_party/androidx', - 'version': 'nk3APjbujCskiTtdIxbZeBGQneKr1rs-yPkqtu3psY8C', + 'version': 'gZ9Ou2JmKklDd0fCtaO5p8SJucTure9ee9bL5XMz5S8C', }, ], 'condition': 'checkout_android', @@ -1196,7 +1196,7 @@ Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), 'src/third_party/devtools-frontend-internal': { - 'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + 'c6bf12d0f4fd78aa7dbc7e5379b2cb7c2503b58b', + 'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + '63790d3a0292fcede670a1a0259e9356916c9bd6', 'condition': 'checkout_src_internal', }, @@ -1841,7 +1841,7 @@ Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'f20c5f7b8f53904edaa98651d764e1b8305d7c14', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '3cce50ae4bc4384dd61b7d2dc877203993b09b19', + Var('webrtc_git') + '/src.git' + '@' + 'ee2fcbab428934630b39e0be128cb0fcd0573aae', # Wuffs' canonical repository is at github.com/google/wuffs, but we use # Skia's mirror of Wuffs, the same as in upstream Skia's DEPS file. @@ -1964,7 +1964,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/help_app/app', - 'version': 'VV5-j8t5Lb3-eKI0lxEy1uXkoRaNKXXeu1J_p__GpWYC', + 'version': 'rtkaLDytxJJJ7cYs6fkrOMlmbQMrwNvdS7pM3dZuWdAC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -3944,7 +3944,7 @@ 'src/components/optimization_guide/internal': { 'url': Var('chrome_git') + '/chrome/components/optimization_guide.git' + '@' + - '1bd7f39830947c4615bf1d40810c3adf862d20bc', + '5e31ebc3259a7849928fafb8bdeb3cd8ca48c8d8', 'condition': 'checkout_src_internal', }, @@ -4004,7 +4004,7 @@ 'src/ios_internal': { 'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' + - 'b41b25ff5c18d9589ef7a1e8e2bec24bffc75acc', + '34c58e6d6072333decae4e8c0b3b93316920f550', 'condition': 'checkout_ios and checkout_src_internal', },
diff --git a/android_webview/browser/aw_feature_list_creator.cc b/android_webview/browser/aw_feature_list_creator.cc index 6c965909..7653a5bab 100644 --- a/android_webview/browser/aw_feature_list_creator.cc +++ b/android_webview/browser/aw_feature_list_creator.cc
@@ -243,7 +243,9 @@ variations::UIStringOverrider ui_string_overrider; variations_field_trial_creator_ = std::make_unique<variations::VariationsFieldTrialCreator>( - client_.get(), std::move(seed_store), ui_string_overrider); + client_.get(), std::move(seed_store), ui_string_overrider, + // Limited entropy field trials are not supported on WebView. + /*limited_entropy_synthetic_trial=*/nullptr); variations_field_trial_creator_->OverrideVariationsPlatform( variations::Study::PLATFORM_ANDROID_WEBVIEW);
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index 8196862..4699bf4 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -4007,6 +4007,7 @@ "//components/desks_storage", "//components/desks_storage:test_support", "//components/feature_engagement/public", + "//components/feature_engagement/test:test_support", "//components/global_media_controls", "//components/language/core/browser:browser", "//components/live_caption:constants",
diff --git a/ash/api/tasks/fake_tasks_client.cc b/ash/api/tasks/fake_tasks_client.cc index 99536fb6..7b5787d 100644 --- a/ash/api/tasks/fake_tasks_client.cc +++ b/ash/api/tasks/fake_tasks_client.cc
@@ -85,31 +85,12 @@ void FakeTasksClient::AddTask(const std::string& task_list_id, const std::string& title, TasksClient::OnTaskSavedCallback callback) { - auto task_list_iter = tasks_in_task_lists_.find(task_list_id); - CHECK(task_list_iter != tasks_in_task_lists_.end()); - - auto pending_task = std::make_unique<Task>( - base::Uuid::GenerateRandomV4().AsLowercaseString(), title, - /*completed=*/false, - /*due=*/absl::nullopt, - /*has_subtasks=*/false, /*has_email_link=*/false, - /*has_notes=*/false, - /*updated=*/base::Time::Now()); - - auto pending_callback = base::BindOnce( - [](ui::ListModel<Task>* tasks, std::unique_ptr<Task> pending_task, - TasksClient::OnTaskSavedCallback callback) { - const auto* const task = tasks->AddAt( - /*index=*/0, std::move(pending_task)); - std::move(callback).Run(task); - }, - task_list_iter->second.get(), std::move(pending_task), - std::move(callback)); - if (paused_) { - pending_add_task_callbacks_.push_back(std::move(pending_callback)); + pending_add_task_callbacks_.push_back( + base::BindOnce(&FakeTasksClient::AddTaskImpl, base::Unretained(this), + task_list_id, title, std::move(callback))); } else { - std::move(pending_callback).Run(); + AddTaskImpl(task_list_id, title, std::move(callback)); } } @@ -117,26 +98,12 @@ const std::string& task_id, const std::string& title, TasksClient::OnTaskSavedCallback callback) { - auto task_list_iter = tasks_in_task_lists_.find(task_list_id); - CHECK(task_list_iter != tasks_in_task_lists_.end()); - - const auto task_iter = std::find_if( - task_list_iter->second->begin(), task_list_iter->second->end(), - [&task_id](const auto& task) { return task->id == task_id; }); - CHECK(task_iter != task_list_iter->second->end()); - - auto pending_callback = base::BindOnce( - [](Task* task, const std::string& title, - TasksClient::OnTaskSavedCallback callback) { - task->title = title; - std::move(callback).Run(task); - }, - task_iter->get(), title, std::move(callback)); - if (paused_) { - pending_update_task_callbacks_.push_back(std::move(pending_callback)); + pending_update_task_callbacks_.push_back( + base::BindOnce(&FakeTasksClient::UpdateTaskImpl, base::Unretained(this), + task_list_id, task_id, title, std::move(callback))); } else { - std::move(pending_callback).Run(); + UpdateTaskImpl(task_list_id, task_id, title, std::move(callback)); } } @@ -174,6 +141,52 @@ return RunPendingCallbacks(pending_update_task_callbacks_); } +void FakeTasksClient::AddTaskImpl(const std::string& task_list_id, + const std::string& title, + TasksClient::OnTaskSavedCallback callback) { + if (run_with_errors_) { + std::move(callback).Run(/*task=*/nullptr); + return; + } + + auto task_list_iter = tasks_in_task_lists_.find(task_list_id); + CHECK(task_list_iter != tasks_in_task_lists_.end()); + + auto pending_task = std::make_unique<Task>( + base::Uuid::GenerateRandomV4().AsLowercaseString(), title, + /*completed=*/false, + /*due=*/absl::nullopt, + /*has_subtasks=*/false, /*has_email_link=*/false, + /*has_notes=*/false, + /*updated=*/base::Time::Now()); + + const auto* const task = task_list_iter->second->AddAt( + /*index=*/0, std::move(pending_task)); + std::move(callback).Run(task); +} + +void FakeTasksClient::UpdateTaskImpl( + const std::string& task_list_id, + const std::string& task_id, + const std::string& title, + TasksClient::OnTaskSavedCallback callback) { + if (run_with_errors_) { + std::move(callback).Run(/*task=*/nullptr); + return; + } + + auto task_list_iter = tasks_in_task_lists_.find(task_list_id); + CHECK(task_list_iter != tasks_in_task_lists_.end()); + + const auto task_iter = std::find_if( + task_list_iter->second->begin(), task_list_iter->second->end(), + [&task_id](const auto& task) { return task->id == task_id; }); + CHECK(task_iter != task_list_iter->second->end()); + + task_iter->get()->title = title; + std::move(callback).Run(task_iter->get()); +} + void FakeTasksClient::PopulateTasks(base::Time tasks_due_time) { task_lists_ = std::make_unique<ui::ListModel<TaskList>>();
diff --git a/ash/api/tasks/fake_tasks_client.h b/ash/api/tasks/fake_tasks_client.h index b74f007..5943f57 100644 --- a/ash/api/tasks/fake_tasks_client.h +++ b/ash/api/tasks/fake_tasks_client.h
@@ -66,10 +66,21 @@ size_t RunPendingUpdateTaskCallbacks(); void set_paused(bool paused) { paused_ = paused; } + void set_run_with_errors(bool run_with_errors) { + run_with_errors_ = run_with_errors; + } ui::ListModel<TaskList>* task_lists() { return task_lists_.get(); } private: + void AddTaskImpl(const std::string& task_list_id, + const std::string& title, + TasksClient::OnTaskSavedCallback callback); + void UpdateTaskImpl(const std::string& task_list_id, + const std::string& task_id, + const std::string& title, + TasksClient::OnTaskSavedCallback callback); + void PopulateTasks(base::Time tasks_due_time); void PopulateTaskLists(base::Time tasks_due_time); @@ -87,7 +98,11 @@ int bubble_closed_count_ = 0; int completed_tasks_ = 0; - // If `false` - callbacks executed immediately. If `true` - callbacks get + // If `false` - callbacks are executed normally; if `true` - executed with + // simulated error (currently works for `AddTask` and `UpdateTask` only). + bool run_with_errors_ = false; + + // If `false` - callbacks are executed immediately; if `true` - callbacks get // saved to the corresponding list and executed once // `RunPending**Callbacks()` is called. bool paused_ = false;
diff --git a/ash/assistant/ui/DEPS b/ash/assistant/ui/DEPS index 484c287..2f6aec8 100644 --- a/ash/assistant/ui/DEPS +++ b/ash/assistant/ui/DEPS
@@ -52,6 +52,8 @@ specific_include_rules = { ".*_unittest\.cc": [ + "+ash/app_list/test/app_list_test_helper.h", + "+ash/app_list/views/search_box_view.h", "+ash/assistant/assistant_controller_impl.h", "+ash/assistant/assistant_interaction_controller_impl.h", "+ash/assistant/assistant_ui_controller.h", @@ -67,6 +69,7 @@ "+chromeos/ash/services/assistant/test_support/mock_assistant.h", "+chromeos/ui/frame/default_frame_header.h", "+chromeos/ui/vector_icons/vector_icons.h", + "+components/feature_engagement/test/scoped_iph_feature_list.h", "+components/prefs", "+components/vector_icons", "+testing/gmock",
diff --git a/ash/assistant/ui/main_stage/launcher_search_iph_view.cc b/ash/assistant/ui/main_stage/launcher_search_iph_view.cc index b387103..96f97ea0 100644 --- a/ash/assistant/ui/main_stage/launcher_search_iph_view.cc +++ b/ash/assistant/ui/main_stage/launcher_search_iph_view.cc
@@ -16,6 +16,7 @@ #include "ash/style/typography.h" #include "base/functional/bind.h" #include "base/i18n/rtl.h" +#include "base/memory/raw_ptr.h" #include "base/metrics/histogram_functions.h" #include "base/rand_util.h" #include "chromeos/ash/services/assistant/public/cpp/assistant_enums.h" @@ -44,6 +45,8 @@ using QueryType = assistant::LauncherSearchIphQueryType; +std::u16string g_chip_text_for_testing; + constexpr char kLauncherSearchIphQueryTypeHistogramPrefix[] = "Assistant.LauncherSearchIphQueryType."; constexpr char kLauncherSearchIphQueryFromSearchBox[] = "SearchBox"; @@ -52,7 +55,8 @@ constexpr int kMainLayoutBetweenChildSpacing = 16; constexpr int kActionContainerBetweenChildSpacing = 8; -constexpr int kNumberOfQueryChips = 3; +constexpr int kNumberOfQueryChipsSearchBox = 3; +constexpr int kNumberOfQueryChipsAssistantPage = 4; constexpr gfx::RoundedCornersF kBackgroundRadiiClamshellLTR = {16, 4, 16, 16}; @@ -71,14 +75,19 @@ constexpr int kBackgroundRadiusTablet = 16; -std::vector<QueryType> GetQueryChips() { +std::vector<QueryType> GetRandomizedQueryChips( + LauncherSearchIphView::UiLocation location) { std::vector<QueryType> chips = { QueryType::kWeather, QueryType::kUnitConversion1, QueryType::kUnitConversion2, QueryType::kTranslation, QueryType::kDefinition, QueryType::kCalculation}; - CHECK_GE(static_cast<int>(chips.size()), kNumberOfQueryChips); + + int num_of_chips = location == LauncherSearchIphView::UiLocation::kSearchBox + ? kNumberOfQueryChipsSearchBox + : kNumberOfQueryChipsAssistantPage; + CHECK_GE(static_cast<int>(chips.size()), num_of_chips); base::RandomShuffle(chips.begin(), chips.end()); - chips.resize(kNumberOfQueryChips); + chips.resize(num_of_chips); return chips; } @@ -100,18 +109,28 @@ } std::u16string GetQueryText(QueryType type) { + if (!g_chip_text_for_testing.empty()) { + return g_chip_text_for_testing; + } + int id = GetQueryTextId(type); return l10n_util::GetStringUTF16(id); } } // namespace +// static +void LauncherSearchIphView::SetChipTextForTesting(const std::u16string& text) { + g_chip_text_for_testing = text; +} + LauncherSearchIphView::LauncherSearchIphView( Delegate* delegate, bool is_in_tablet_mode, std::unique_ptr<ScopedIphSession> scoped_iph_session, UiLocation location) : delegate_(delegate), + is_in_tablet_mode_(is_in_tablet_mode), scoped_iph_session_(std::move(scoped_iph_session)), location_(location) { SetID(ViewId::kSelf); @@ -167,23 +186,7 @@ actions_container->SetBetweenChildSpacing( kActionContainerBetweenChildSpacing); - CreateQueryChips(actions_container); - - if (location_ == UiLocation::kSearchBox) { - views::View* spacer = - actions_container->AddChildView(std::make_unique<views::View>()); - actions_container->SetFlexForView(spacer, 1); - - ash::PillButton* assistant_button = - actions_container->AddChildView(std::make_unique<ash::PillButton>( - base::BindRepeating(&LauncherSearchIphView::OpenAssistantPage, - weak_ptr_factory_.GetWeakPtr()), - l10n_util::GetStringUTF16( - IDS_ASH_ASSISTANT_LAUNCHER_SEARCH_IPH_CHIP_ASSISTANT))); - assistant_button->SetID(ViewId::kAssistant); - assistant_button->SetPillButtonType( - PillButton::Type::kDefaultLargeWithoutIcon); - } + CreateChips(actions_container); if (is_in_tablet_mode || location_ == UiLocation::kAssistantPage) { box_layout_view->SetBackground(views::CreateThemedRoundedRectBackground( @@ -201,15 +204,28 @@ void LauncherSearchIphView::VisibilityChanged(views::View* starting_from, bool is_visible) { - if (is_visible) { + if (is_visible && location_ == UiLocation::kAssistantPage) { + // Only shuffle when the IPH is in AssistantPage. + // When the IPH is in SearchBox, the chips will be recreated every time. ShuffleChipsQuery(); + SetChipsVisibility(); + // Label size should be changed. The `PreferredSizeChanged()` in label is // not bubbled up to this view, so we need to explicitly call it here. PreferredSizeChanged(); } } +void LauncherSearchIphView::OnBoundsChanged(const gfx::Rect& previous_bounds) { + if (location_ == UiLocation::kAssistantPage) { + // Will set visibility of chips in VisibilityChanged(). + return; + } + + SetChipsVisibility(); +} + void LauncherSearchIphView::NotifyAssistantButtonPressedEvent() { if (scoped_iph_session_) { scoped_iph_session_->NotifyEvent(kIphEventNameAssistantClick); @@ -220,6 +236,10 @@ return chips_; } +views::View* LauncherSearchIphView::GetAssistantButtonForTesting() { + return assistant_button_; +} + void LauncherSearchIphView::RunLauncherSearchQuery(QueryType query_type) { const std::string& location = location_ == UiLocation::kSearchBox ? kLauncherSearchIphQueryFromSearchBox @@ -239,9 +259,12 @@ delegate_->OpenAssistantPage(); } -void LauncherSearchIphView::CreateQueryChips(views::View* actions_container) { +void LauncherSearchIphView::CreateChips( + views::BoxLayoutView* actions_container) { + CHECK(chips_.empty()); + int query_chip_view_id = ViewId::kChipStart; - for (auto query_type : GetQueryChips()) { + for (auto query_type : GetRandomizedQueryChips(location_)) { ChipView* chip = actions_container->AddChildView( std::make_unique<ChipView>(ChipView::Type::kLarge)); chip->SetText(GetQueryText(query_type)); @@ -252,11 +275,28 @@ query_chip_view_id++; chips_.emplace_back(chip); } + + // If the IPH is in the search box, will add an assistant button. + if (location_ == UiLocation::kSearchBox) { + views::View* spacer = + actions_container->AddChildView(std::make_unique<views::View>()); + actions_container->SetFlexForView(spacer, 1); + + assistant_button_ = + actions_container->AddChildView(std::make_unique<ash::PillButton>( + base::BindRepeating(&LauncherSearchIphView::OpenAssistantPage, + weak_ptr_factory_.GetWeakPtr()), + l10n_util::GetStringUTF16( + IDS_ASH_ASSISTANT_LAUNCHER_SEARCH_IPH_CHIP_ASSISTANT))); + assistant_button_->SetID(ViewId::kAssistant); + assistant_button_->SetPillButtonType( + PillButton::Type::kDefaultLargeWithoutIcon); + } } void LauncherSearchIphView::ShuffleChipsQuery() { size_t chip_index = 0; - for (auto query_type : GetQueryChips()) { + for (auto query_type : GetRandomizedQueryChips(location_)) { CHECK_LT(chip_index, chips_.size()); auto chip = chips_[chip_index++]; chip->SetText(GetQueryText(query_type)); @@ -266,6 +306,48 @@ } } +void LauncherSearchIphView::SetChipsVisibility() { + const int iph_width = GetContentsBounds().width(); + if (iph_width == 0) { + return; + } + + // Check the PreferredSize of all chips. If the width is wider than the + // available width, do not show the last a few query chips but at least show + // one chip. + int running_width = 0; + for (auto chip : chips_) { + running_width += chip->GetPreferredSize().width(); + running_width += kActionContainerBetweenChildSpacing; + } + + const auto iph_insets = is_in_tablet_mode_ ? kInnerBackgroundInsetsTablet + : kInnerBackgroundInsetsClamshell; + const int available_width = iph_width - iph_insets.width(); + + int assistant_button_width = 0; + if (location_ == UiLocation::kSearchBox) { + assistant_button_width = assistant_button_->GetPreferredSize().width(); + + // Add additional spacing before the `assistant_button_`. + // The multiplier `2` is an arbitrary number. + running_width += 2 * kActionContainerBetweenChildSpacing; + running_width += assistant_button_width; + } else { + // Subtract the last spacing. + running_width -= kActionContainerBetweenChildSpacing; + } + + // At least show one chip. + chips_[0]->SetVisible(true); + + // Show remaining chips if they fit. + for (size_t index = chips_.size() - 1; index > 0; index--) { + chips_[index]->SetVisible(running_width <= available_width); + running_width -= chips_[index]->GetPreferredSize().width(); + } +} + BEGIN_METADATA(LauncherSearchIphView) END_METADATA
diff --git a/ash/assistant/ui/main_stage/launcher_search_iph_view.h b/ash/assistant/ui/main_stage/launcher_search_iph_view.h index a60cc65..54b91a5f 100644 --- a/ash/assistant/ui/main_stage/launcher_search_iph_view.h +++ b/ash/assistant/ui/main_stage/launcher_search_iph_view.h
@@ -17,9 +17,14 @@ #include "ui/views/controls/styled_label.h" #include "ui/views/view.h" +namespace views { +class BoxLayoutView; +} // namespace views + namespace ash { class ChipView; +class PillButton; class LauncherSearchIphView : public views::View { METADATA_HEADER(LauncherSearchIphView, views::View) @@ -57,6 +62,8 @@ kAssistantPage }; + static void SetChipTextForTesting(const std::u16string& text); + LauncherSearchIphView(Delegate* delegate, bool is_in_tablet_mode, std::unique_ptr<ScopedIphSession> scoped_iph_session, @@ -65,27 +72,34 @@ // views::View: void VisibilityChanged(views::View* starting_from, bool is_visible) override; + void OnBoundsChanged(const gfx::Rect& previous_bounds) override; void NotifyAssistantButtonPressedEvent(); std::vector<raw_ptr<ChipView>> GetChipsForTesting(); + views::View* GetAssistantButtonForTesting(); private: void RunLauncherSearchQuery(assistant::LauncherSearchIphQueryType query_type); void OpenAssistantPage(); - void CreateQueryChips(views::View* actions_container); + void CreateChips(views::BoxLayoutView* actions_container); void ShuffleChipsQuery(); + void SetChipsVisibility(); + raw_ptr<Delegate> delegate_ = nullptr; + bool is_in_tablet_mode_ = false; + std::unique_ptr<ScopedIphSession> scoped_iph_session_; UiLocation location_ = UiLocation::kSearchBox; std::vector<raw_ptr<ChipView>> chips_; + raw_ptr<ash::PillButton> assistant_button_ = nullptr; base::WeakPtrFactory<LauncherSearchIphView> weak_ptr_factory_{this}; };
diff --git a/ash/assistant/ui/main_stage/launcher_search_iph_view_unittest.cc b/ash/assistant/ui/main_stage/launcher_search_iph_view_unittest.cc index 39d18e1d..2a35f17 100644 --- a/ash/assistant/ui/main_stage/launcher_search_iph_view_unittest.cc +++ b/ash/assistant/ui/main_stage/launcher_search_iph_view_unittest.cc
@@ -4,12 +4,20 @@ #include "ash/assistant/ui/main_stage/launcher_search_iph_view.h" +#include "ash/app_list/test/app_list_test_helper.h" +#include "ash/app_list/views/search_box_view.h" #include "ash/assistant/test/assistant_ash_test_base.h" #include "ash/assistant/ui/assistant_view_ids.h" #include "ash/assistant/ui/main_stage/chip_view.h" #include "base/memory/raw_ptr.h" +#include "base/run_loop.h" +#include "base/scoped_observation.h" #include "base/test/scoped_feature_list.h" #include "components/feature_engagement/public/feature_constants.h" +#include "components/feature_engagement/test/scoped_iph_feature_list.h" +#include "ui/gfx/geometry/size.h" +#include "ui/views/view.h" +#include "ui/views/view_observer.h" namespace ash { @@ -17,6 +25,38 @@ using LauncherSearchIphViewTest = AssistantAshTestBase; +// TODO(b/317900261): Use ash::ViewDrawnWaiter. +bool IsDrawn(views::View* view) { + return view->IsDrawn() && !view->size().IsEmpty(); +} + +class ViewDrawnWaiter : public views::ViewObserver { + public: + ViewDrawnWaiter() = default; + ~ViewDrawnWaiter() override = default; + + void Wait(views::View* view) { + if (IsDrawn(view)) { + return; + } + + view_observer_.Observe(view); + wait_loop_.Run(); + } + + private: + // views::ViewObserver: + void OnViewBoundsChanged(views::View* view) override { + if (IsDrawn(view)) { + wait_loop_.Quit(); + } + } + + base::RunLoop wait_loop_; + base::ScopedObservation<views::View, views::ViewObserver> view_observer_{ + this}; +}; + } // namespace TEST_F(LauncherSearchIphViewTest, @@ -66,4 +106,190 @@ EXPECT_NE(queries_1, queries_2); } +TEST_F(LauncherSearchIphViewTest, ShowFourChipsInAssistantPage) { + base::test::ScopedFeatureList scoped_feature_list( + feature_engagement::kIPHLauncherSearchHelpUiFeature); + + ShowAssistantUi(); + LauncherSearchIphView* iph_view = static_cast<LauncherSearchIphView*>( + page_view()->GetViewByID(AssistantViewID::kLauncherSearchIph)); + int visible_chips = 0; + for (auto chip : iph_view->GetChipsForTesting()) { + if (chip->GetVisible()) { + visible_chips++; + } + } + EXPECT_EQ(4, visible_chips); +} + +TEST_F(LauncherSearchIphViewTest, ShowTwoChipsInAssistantPage) { + base::test::ScopedFeatureList scoped_feature_list( + feature_engagement::kIPHLauncherSearchHelpUiFeature); + + // Set a testing text to only show two chips. + std::u16string testing_text = u"Long text for two chips"; + LauncherSearchIphView::SetChipTextForTesting(testing_text); + + ShowAssistantUi(); + LauncherSearchIphView* iph_view = static_cast<LauncherSearchIphView*>( + page_view()->GetViewByID(AssistantViewID::kLauncherSearchIph)); + int visible_chips = 0; + for (auto chip : iph_view->GetChipsForTesting()) { + if (chip->GetVisible()) { + visible_chips++; + } + } + EXPECT_EQ(2, visible_chips); +} + +TEST_F(LauncherSearchIphViewTest, ShowOneChipsInAssistantPage) { + base::test::ScopedFeatureList scoped_feature_list( + feature_engagement::kIPHLauncherSearchHelpUiFeature); + + // Set a testing text to only show one chip. + std::u16string testing_text = u"Very long text to only show one chip"; + LauncherSearchIphView::SetChipTextForTesting(testing_text); + + ShowAssistantUi(); + LauncherSearchIphView* iph_view = static_cast<LauncherSearchIphView*>( + page_view()->GetViewByID(AssistantViewID::kLauncherSearchIph)); + int visible_chips = 0; + for (auto chip : iph_view->GetChipsForTesting()) { + if (chip->GetVisible()) { + visible_chips++; + } + } + EXPECT_EQ(1, visible_chips); +} + +TEST_F(LauncherSearchIphViewTest, AtLeastShowOneChipsInAssistantPage) { + base::test::ScopedFeatureList scoped_feature_list( + feature_engagement::kIPHLauncherSearchHelpUiFeature); + + // Set a testing text to only show one chip even the text cannot fix the + // width. + std::u16string testing_text = + u"Very very very very long text cannot fix the width but still show one " + u"chip"; + LauncherSearchIphView::SetChipTextForTesting(testing_text); + + ShowAssistantUi(); + LauncherSearchIphView* iph_view = static_cast<LauncherSearchIphView*>( + page_view()->GetViewByID(AssistantViewID::kLauncherSearchIph)); + int visible_chips = 0; + for (auto chip : iph_view->GetChipsForTesting()) { + if (chip->GetVisible()) { + visible_chips++; + } + } + EXPECT_EQ(1, visible_chips); +} + +TEST_F(LauncherSearchIphViewTest, + ShowIphWhenClickingAssistantButtonInSearchBox) { + GetAppListTestHelper()->search_model()->SetWouldTriggerLauncherSearchIph( + true); + GetAppListTestHelper()->ShowAppList(); + + SearchBoxView* search_box_view = + GetAppListTestHelper()->GetBubbleSearchBoxView(); + LeftClickOn(search_box_view->assistant_button()); + + LauncherSearchIphView* iph_view = static_cast<LauncherSearchIphView*>( + search_box_view->GetViewByID(LauncherSearchIphView::ViewId::kSelf)); + EXPECT_TRUE(!!iph_view); + EXPECT_TRUE(iph_view->GetVisible()); +} + +TEST_F(LauncherSearchIphViewTest, + ShowThreeQueryChipsAndAssistantChipInSearchBox) { + // Set a testing text to show three chips. + std::u16string testing_text = u"Text"; + LauncherSearchIphView::SetChipTextForTesting(testing_text); + + GetAppListTestHelper()->search_model()->SetWouldTriggerLauncherSearchIph( + true); + GetAppListTestHelper()->ShowAppList(); + + SearchBoxView* search_box_view = + GetAppListTestHelper()->GetBubbleSearchBoxView(); + LeftClickOn(search_box_view->assistant_button()); + + LauncherSearchIphView* iph_view = static_cast<LauncherSearchIphView*>( + search_box_view->GetViewByID(LauncherSearchIphView::ViewId::kSelf)); + ViewDrawnWaiter().Wait(iph_view); + + int visible_chips = 0; + for (auto chip : iph_view->GetChipsForTesting()) { + if (chip->GetVisible()) { + visible_chips++; + } + } + EXPECT_EQ(3, visible_chips); + + EXPECT_TRUE(!!iph_view->GetAssistantButtonForTesting()); + EXPECT_TRUE(iph_view->GetAssistantButtonForTesting()->GetVisible()); +} + +TEST_F(LauncherSearchIphViewTest, ShowOneQueryChipAndAssistantChipInSearchBox) { + // Set a testing text to only show one chip. + std::u16string testing_text = u"Very long text to show only one chip"; + LauncherSearchIphView::SetChipTextForTesting(testing_text); + + GetAppListTestHelper()->search_model()->SetWouldTriggerLauncherSearchIph( + true); + GetAppListTestHelper()->ShowAppList(); + + SearchBoxView* search_box_view = + GetAppListTestHelper()->GetBubbleSearchBoxView(); + LeftClickOn(search_box_view->assistant_button()); + + LauncherSearchIphView* iph_view = static_cast<LauncherSearchIphView*>( + search_box_view->GetViewByID(LauncherSearchIphView::ViewId::kSelf)); + ViewDrawnWaiter().Wait(iph_view); + + int visible_chips = 0; + for (auto chip : iph_view->GetChipsForTesting()) { + if (chip->GetVisible()) { + visible_chips++; + } + } + EXPECT_EQ(1, visible_chips); + + EXPECT_TRUE(!!iph_view->GetAssistantButtonForTesting()); + EXPECT_TRUE(iph_view->GetAssistantButtonForTesting()->GetVisible()); +} + +TEST_F(LauncherSearchIphViewTest, AtLeastShowOneQueryChipInSearchBox) { + // Set a testing text to only show one chip even the text cannot fix the + // width. + std::u16string testing_text = + u"Very very very very long text cannot fix the width but still show one " + u"chip"; + LauncherSearchIphView::SetChipTextForTesting(testing_text); + + GetAppListTestHelper()->search_model()->SetWouldTriggerLauncherSearchIph( + true); + GetAppListTestHelper()->ShowAppList(); + + SearchBoxView* search_box_view = + GetAppListTestHelper()->GetBubbleSearchBoxView(); + LeftClickOn(search_box_view->assistant_button()); + + LauncherSearchIphView* iph_view = static_cast<LauncherSearchIphView*>( + search_box_view->GetViewByID(LauncherSearchIphView::ViewId::kSelf)); + ViewDrawnWaiter().Wait(iph_view); + + int visible_chips = 0; + for (auto chip : iph_view->GetChipsForTesting()) { + if (chip->GetVisible()) { + visible_chips++; + } + } + EXPECT_EQ(1, visible_chips); + + EXPECT_TRUE(!!iph_view->GetAssistantButtonForTesting()); + EXPECT_TRUE(iph_view->GetAssistantButtonForTesting()->GetVisible()); +} + } // namespace ash
diff --git a/ash/glanceables/tasks/glanceables_task_view_v2.cc b/ash/glanceables/tasks/glanceables_task_view_v2.cc index 5883455..7ba5c3b 100644 --- a/ash/glanceables/tasks/glanceables_task_view_v2.cc +++ b/ash/glanceables/tasks/glanceables_task_view_v2.cc
@@ -398,7 +398,8 @@ UpdateTaskTitleViewForState(TaskTitleViewState::kView); if (task_id_.empty() || task_title_ != old_title) { - save_callback_.Run(task_id_, base::UTF16ToUTF8(task_title_), + save_callback_.Run(weak_ptr_factory_.GetWeakPtr(), task_id_, + base::UTF16ToUTF8(task_title_), base::BindOnce(&GlanceablesTaskViewV2::OnSaved, weak_ptr_factory_.GetWeakPtr())); // TODO(b/301253574): introduce "disabled" state for this view to prevent
diff --git a/ash/glanceables/tasks/glanceables_task_view_v2.h b/ash/glanceables/tasks/glanceables_task_view_v2.h index f3cc778..ff621ab 100644 --- a/ash/glanceables/tasks/glanceables_task_view_v2.h +++ b/ash/glanceables/tasks/glanceables_task_view_v2.h
@@ -47,6 +47,7 @@ using MarkAsCompletedCallback = base::RepeatingCallback<void(const std::string& task_id, bool completed)>; using SaveCallback = base::RepeatingCallback<void( + base::WeakPtr<GlanceablesTaskViewV2> view, const std::string& task_id, const std::string& title, api::TasksClient::OnTaskSavedCallback callback)>;
diff --git a/ash/glanceables/tasks/glanceables_task_view_v2_unittest.cc b/ash/glanceables/tasks/glanceables_task_view_v2_unittest.cc index e764949..a76b9aa4 100644 --- a/ash/glanceables/tasks/glanceables_task_view_v2_unittest.cc +++ b/ash/glanceables/tasks/glanceables_task_view_v2_unittest.cc
@@ -15,6 +15,7 @@ #include "ash/system/time/calendar_unittest_utils.h" #include "ash/test/ash_test_base.h" #include "base/functional/callback_helpers.h" +#include "base/memory/weak_ptr.h" #include "base/strings/utf_string_conversions.h" #include "base/test/scoped_feature_list.h" #include "base/test/test_future.h" @@ -233,7 +234,8 @@ } TEST_F(GlanceablesTaskViewStableLaunchTest, InvokesSaveCallbackAfterAdding) { - base::test::TestFuture<const std::string&, const std::string&, + base::test::TestFuture<base::WeakPtr<GlanceablesTaskViewV2>, + const std::string&, const std::string&, api::TasksClient::OnTaskSavedCallback> future; @@ -252,7 +254,7 @@ PressAndReleaseKey(ui::VKEY_W); PressAndReleaseKey(ui::VKEY_ESCAPE); - const auto [task_id, title, callback] = future.Take(); + const auto [task_view, task_id, title, callback] = future.Take(); EXPECT_TRUE(task_id.empty()); EXPECT_EQ(title, "New"); } @@ -263,7 +265,8 @@ /*has_subtasks=*/false, /*has_email_link=*/false, /*has_notes=*/false, /*updated=*/base::Time()); - base::test::TestFuture<const std::string&, const std::string&, + base::test::TestFuture<base::WeakPtr<GlanceablesTaskViewV2>, + const std::string&, const std::string&, api::TasksClient::OnTaskSavedCallback> future; @@ -283,13 +286,14 @@ PressAndReleaseKey(ui::VKEY_D); PressAndReleaseKey(ui::VKEY_ESCAPE); - const auto [task_id, title, callback] = future.Take(); + const auto [task_view, task_id, title, callback] = future.Take(); EXPECT_EQ(task_id, "task-id"); EXPECT_EQ(title, "Task title upd"); } TEST_F(GlanceablesTaskViewStableLaunchTest, SupportsEditingRightAfterAdding) { - base::test::TestFuture<const std::string&, const std::string&, + base::test::TestFuture<base::WeakPtr<GlanceablesTaskViewV2>, + const std::string&, const std::string&, api::TasksClient::OnTaskSavedCallback> future; @@ -310,7 +314,7 @@ PressAndReleaseKey(ui::VKEY_ESCAPE); // Verify that `task_id` is empty after adding a task. - auto [task_id, title, callback] = future.Take(); + auto [task_view, task_id, title, callback] = future.Take(); EXPECT_TRUE(task_id.empty()); EXPECT_EQ(title, "New"); @@ -332,7 +336,7 @@ PressAndReleaseKey(ui::VKEY_ESCAPE); // Verify that `task_id` equals to "task-id" after editing the same task. - const auto [task_id, title, callback] = future.Take(); + const auto [task_view, task_id, title, callback] = future.Take(); EXPECT_EQ(task_id, "task-id"); EXPECT_EQ(title, "New 1"); }
diff --git a/ash/glanceables/tasks/glanceables_tasks_view.cc b/ash/glanceables/tasks/glanceables_tasks_view.cc index 063275b9..a65171c 100644 --- a/ash/glanceables/tasks/glanceables_tasks_view.cc +++ b/ash/glanceables/tasks/glanceables_tasks_view.cc
@@ -218,10 +218,10 @@ const auto* const active_task_list = tasks_combobox_model_->GetTaskListAt( task_list_combo_box_view_->GetSelectedIndex().value()); // TODO(b/301253574): make sure there is only one view is in `kEdit` state. - pending_new_task_ = task_items_container_view_->AddChildViewAt( + auto* const pending_new_task = task_items_container_view_->AddChildViewAt( CreateTaskView(active_task_list->id, /*task=*/nullptr), /*index=*/0); - pending_new_task_->UpdateTaskTitleViewForState( + pending_new_task->UpdateTaskTitleViewForState( GlanceablesTaskViewV2::TaskTitleViewState::kEdit); PreferredSizeChanged(); } @@ -347,19 +347,17 @@ void GlanceablesTasksView::SaveTask( const std::string& task_list_id, + base::WeakPtr<GlanceablesTaskViewV2> view, const std::string& task_id, const std::string& title, api::TasksClient::OnTaskSavedCallback callback) { if (task_id.empty()) { - // Empty `task_id` applies only for `pending_new_task_`, meaning that the - // task has not yet been created. Verify that this task has a non-empty - // title, otherwise just delete the view from the scrollable container. - CHECK(pending_new_task_); - views::View* view_to_delete = pending_new_task_; - pending_new_task_ = nullptr; + // Empty `task_id` means that the task has not yet been created. Verify that + // this task has a non-empty title, otherwise just delete the `view` from + // the scrollable container. add_new_task_button_->SetState(views::Button::ButtonState::STATE_NORMAL); - if (title.empty() && view_to_delete) { - task_items_container_view_->RemoveChildViewT(view_to_delete); + if (title.empty() && view) { + task_items_container_view_->RemoveChildViewT(view.get()); return; } } @@ -367,9 +365,9 @@ progress_bar_->UpdateProgressBarVisibility(/*visible=*/true); auto* const client = Shell::Get()->glanceables_controller()->GetTasksClient(); - auto on_task_saved = - base::BindOnce(&GlanceablesTasksView::OnTaskSaved, - weak_ptr_factory_.GetWeakPtr(), std::move(callback)); + auto on_task_saved = base::BindOnce( + &GlanceablesTasksView::OnTaskSaved, weak_ptr_factory_.GetWeakPtr(), + std::move(view), task_id, std::move(callback)); if (task_id.empty()) { client->AddTask(task_list_id, title, std::move(on_task_saved)); } else { @@ -378,10 +376,18 @@ } void GlanceablesTasksView::OnTaskSaved( + base::WeakPtr<GlanceablesTaskViewV2> view, + const std::string& task_id, api::TasksClient::OnTaskSavedCallback callback, const api::Task* task) { if (!task) { - // TODO(b/301253574): show error message. + ShowErrorMessage(u"[l10n] Error"); + if (task_id.empty() && view) { + // Empty `task_id` means that the task has not yet been created. Delete + // the corresponding `view` from the scrollable container in case of + // error. + task_items_container_view_->RemoveChildViewT(view.get()); + } } progress_bar_->UpdateProgressBarVisibility(/*visible=*/false); std::move(callback).Run(task);
diff --git a/ash/glanceables/tasks/glanceables_tasks_view.h b/ash/glanceables/tasks/glanceables_tasks_view.h index e14afb16..986e21d1 100644 --- a/ash/glanceables/tasks/glanceables_tasks_view.h +++ b/ash/glanceables/tasks/glanceables_tasks_view.h
@@ -13,6 +13,7 @@ #include "ash/glanceables/glanceables_metrics.h" #include "ash/system/unified/glanceable_tray_child_bubble.h" #include "base/memory/raw_ptr.h" +#include "base/memory/weak_ptr.h" #include "base/scoped_observation.h" #include "ui/base/metadata/metadata_header_macros.h" #include "ui/base/models/list_model.h" @@ -96,17 +97,22 @@ bool completed); // Saves the task (either creates or updates the existing one). + // `view` - individual task view which triggered this request. // `callback` - done callback passed from an individual task view. void SaveTask(const std::string& task_list_id, + base::WeakPtr<GlanceablesTaskViewV2> view, const std::string& task_id, const std::string& title, api::TasksClient::OnTaskSavedCallback callback); // Handles completion of `SaveTask`. + // `view` - individual task view which triggered this request. // `callback` - callback passed from an individual task view via `SaveTask`. // `task` - newly created or edited task if the request completes // successfully, `nullptr` otherwise. - void OnTaskSaved(api::TasksClient::OnTaskSavedCallback callback, + void OnTaskSaved(base::WeakPtr<GlanceablesTaskViewV2> view, + const std::string& task_id, + api::TasksClient::OnTaskSavedCallback callback, const api::Task* task); // Model for the combobox used to change the active task list. @@ -129,11 +135,6 @@ raw_ptr<GlanceablesListFooterView> list_footer_view_ = nullptr; raw_ptr<GlanceablesProgressBarView> progress_bar_ = nullptr; - // Pending new task that was added after pressing `add_new_task_button_`. - // Used to limit the number of such views to only one and to remove the view - // from `task_items_container_view_` if needed. - raw_ptr<GlanceablesTaskViewV2> pending_new_task_ = nullptr; - // Records the time when the bubble was about to request a task list. Used for // metrics. base::TimeTicks tasks_requested_time_;
diff --git a/ash/glanceables/tasks/glanceables_tasks_view_unittest.cc b/ash/glanceables/tasks/glanceables_tasks_view_unittest.cc index ee70589..ebb1bd5 100644 --- a/ash/glanceables/tasks/glanceables_tasks_view_unittest.cc +++ b/ash/glanceables/tasks/glanceables_tasks_view_unittest.cc
@@ -85,6 +85,11 @@ base::to_underlying(GlanceablesViewId::kProgressBar))); } + const views::View* GetErrorMessage() const { + return views::AsViewClass<views::View>(view_->GetViewByID( + base::to_underlying(GlanceablesViewId::kGlanceablesErrorMessageView))); + } + api::FakeTasksClient* tasks_client() const { return fake_glanceables_tasks_client_.get(); } @@ -305,4 +310,59 @@ EXPECT_EQ(tasks_client()->RunPendingAddTaskCallbacks(), 0u); } +TEST_F(GlanceablesTasksViewTest, HandlesErrorAfterAdding) { + tasks_client()->set_paused(true); + tasks_client()->set_run_with_errors(true); + + const auto* const task_items_container_view = GetTaskItemsContainerView(); + ASSERT_TRUE(task_items_container_view); + + EXPECT_EQ(task_items_container_view->children().size(), 2u); + EXPECT_FALSE(GetErrorMessage()); + + GestureTapOn(GetAddNewTaskButton()); + PressAndReleaseKey(ui::VKEY_N, ui::EF_SHIFT_DOWN); + PressAndReleaseKey(ui::VKEY_E); + PressAndReleaseKey(ui::VKEY_W); + PressAndReleaseKey(ui::VKEY_ESCAPE); + + EXPECT_EQ(task_items_container_view->children().size(), 3u); + EXPECT_FALSE(GetErrorMessage()); + + EXPECT_EQ(tasks_client()->RunPendingAddTaskCallbacks(), 1u); + EXPECT_EQ(task_items_container_view->children().size(), 2u); + EXPECT_TRUE(GetErrorMessage()); +} + +TEST_F(GlanceablesTasksViewTest, HandlesErrorAfterEditing) { + tasks_client()->set_paused(true); + tasks_client()->set_run_with_errors(true); + + const auto* const task_items_container_view = GetTaskItemsContainerView(); + ASSERT_TRUE(task_items_container_view); + + EXPECT_EQ(task_items_container_view->children().size(), 2u); + EXPECT_FALSE(GetErrorMessage()); + + const auto* const title_label = views::AsViewClass<views::Label>( + task_items_container_view->children()[0]->GetViewByID( + base::to_underlying(GlanceablesViewId::kTaskItemTitleLabel))); + GestureTapOn(title_label); + GetEventGenerator()->PressAndReleaseKey(ui::VKEY_SPACE); + GetEventGenerator()->PressAndReleaseKey(ui::VKEY_U); + GetEventGenerator()->PressAndReleaseKey(ui::VKEY_P); + GetEventGenerator()->PressAndReleaseKey(ui::VKEY_D); + PressAndReleaseKey(ui::VKEY_ESCAPE); + + EXPECT_EQ(task_items_container_view->children().size(), 2u); + EXPECT_FALSE(GetErrorMessage()); + + EXPECT_EQ(tasks_client()->RunPendingUpdateTaskCallbacks(), 1u); + EXPECT_EQ(task_items_container_view->children().size(), 2u); + EXPECT_TRUE(GetErrorMessage()); + + // TODO(b/308446582): Confirm if the title needs to be reverted back in case + // of error. +} + } // namespace ash
diff --git a/base/functional/function_ref.h b/base/functional/function_ref.h index 7cf69d9..911146eb 100644 --- a/base/functional/function_ref.h +++ b/base/functional/function_ref.h
@@ -62,18 +62,34 @@ // }([] { return 42; }); template <typename R, typename... Args> class FunctionRef<R(Args...)> { - public: - // `ABSL_ATTRIBUTE_LIFETIME_BOUND` is important since `FunctionRef` retains - // only a reference to `functor`, `functor` must outlive `this`. template <typename Functor, typename RunType = internal::MakeFunctorTraits<Functor>::RunType> - requires std::convertible_to<internal::ExtractReturnType<RunType>, R> && - std::same_as<internal::ExtractArgs<RunType>, - internal::TypeList<Args...>> + static constexpr bool kCompatibleFunctor = + std::convertible_to<internal::ExtractReturnType<RunType>, R> && + std::same_as<internal::ExtractArgs<RunType>, internal::TypeList<Args...>>; + + public: + // `ABSL_ATTRIBUTE_LIFETIME_BOUND` is important; since `FunctionRef` retains + // only a reference to `functor`, `functor` must outlive `this`. + template <typename Functor> + requires kCompatibleFunctor<Functor> // NOLINTNEXTLINE(google-explicit-constructor) FunctionRef(const Functor& functor ABSL_ATTRIBUTE_LIFETIME_BOUND) : wrapped_func_ref_(functor) {} + // Constructs a reference to the given function pointer. This constructor + // serves to exclude this case from lifetime analysis, since the underlying + // code pointed to by a function pointer is safe to invoke even if the + // lifetime of the pointer provided doesn't outlive us, e.g.: + // `const FunctionRef<void(int)> ref = +[](int i) { ... };` + // Without this constructor, the above code would warn about dangling refs. + // TODO(pkasting): Also support ptr-to-member-functions; this requires changes + // in `absl::FunctionRef` or else rewriting this class to not use that one. + template <typename Func> + requires kCompatibleFunctor<Func*> + // NOLINTNEXTLINE(google-explicit-constructor) + FunctionRef(Func* func) : wrapped_func_ref_(func) {} + // Null FunctionRefs are not allowed. FunctionRef() = delete; @@ -85,13 +101,6 @@ return wrapped_func_ref_(std::forward<Args>(args)...); } - absl::FunctionRef<R(Args...)> ToAbsl() const { return wrapped_func_ref_; } - - // In Chrome, converting to `absl::FunctionRef` should be explicitly done - // through `ToAbsl()`. - template <typename Signature> - operator absl::FunctionRef<Signature>() = delete; - private: absl::FunctionRef<R(Args...)> wrapped_func_ref_; };
diff --git a/base/functional/function_ref_nocompile.nc b/base/functional/function_ref_nocompile.nc index e64f7e7..92dbda0 100644 --- a/base/functional/function_ref_nocompile.nc +++ b/base/functional/function_ref_nocompile.nc
@@ -8,20 +8,12 @@ #include "base/functional/bind.h" #include "base/functional/callback.h" #include "base/functional/function_ref.h" -#include "third_party/abseil-cpp/absl/functional/function_ref.h" namespace base { -void NoImplicitVoidify() { - // Return values cannot be implicitly discarded. - FunctionRef<void()> ref([] { return 0; }); // expected-error {{no matching constructor for initialization of 'FunctionRef<void ()>'}} -} - void CannotBindFunctionRefs() { // `Bind{Once,Repeating}` do not accept `FunctionRef` args due to potential // lifetime concerns. - [](absl::FunctionRef<void()> ref) { BindOnce(ref); }([] {}); // expected-error@*:* {{Functor may not be a FunctionRef, since that is a non-owning reference that may go out of scope before the callback executes.}} - [](absl::FunctionRef<void()> ref) { BindRepeating(ref); }([] {}); // expected-error@*:* {{Functor may not be a FunctionRef, since that is a non-owning reference that may go out of scope before the callback executes.}} [](FunctionRef<void()> ref) { BindOnce(ref); }([] {}); // expected-error@*:* {{Functor may not be a FunctionRef, since that is a non-owning reference that may go out of scope before the callback executes.}} [](FunctionRef<void()> ref) { BindRepeating(ref); }([] {}); // expected-error@*:* {{Functor may not be a FunctionRef, since that is a non-owning reference that may go out of scope before the callback executes.}} }
diff --git a/base/functional/function_ref_unittest.cc b/base/functional/function_ref_unittest.cc index 89eab67..5acd40a8 100644 --- a/base/functional/function_ref_unittest.cc +++ b/base/functional/function_ref_unittest.cc
@@ -4,87 +4,142 @@ #include "base/functional/function_ref.h" +#include <stdint.h> + +#include <concepts> + #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/functional/function_ref.h" namespace base { namespace { -char Moo(float) { +char Func(float) { return 'a'; } -struct C { - long Method() { return value; } - long value; -}; - } // namespace -TEST(FunctionRefTest, FreeFunction) { - [](FunctionRef<char(float)> ref) { EXPECT_EQ('a', ref(1.0)); }(&Moo); +TEST(FunctionRef, Lambda) { + auto add = [](int a, int b) { return a + b; }; + + { + const FunctionRef<int(int, int)> ref = add; + EXPECT_EQ(19, ref(17, 2)); + } + + { + const auto add_const = add; + const FunctionRef<int(int, int)> ref = add_const; + EXPECT_EQ(19, ref(17, 2)); + } } -TEST(FunctionRefTest, Method) { - [](FunctionRef<long(C*)> ref) { - C c = {.value = 25L}; - EXPECT_EQ(25L, ref(&c)); - }(&C::Method); -} - -TEST(FunctionRefTest, Lambda) { +TEST(FunctionRef, CapturingLambda) { int x = 3; - auto lambda = [&x]() { return x; }; - [](FunctionRef<int()> ref) { EXPECT_EQ(3, ref()); }(lambda); + const auto lambda = [&x] { return x; }; + FunctionRef<int()> ref = lambda; + EXPECT_EQ(3, ref()); } -// Tests for passing a `base::FunctionRef` as an `absl::FunctionRef`. -TEST(FunctionRefTest, AbslConversion) { - // Matching signatures should work. - { - bool called = false; - auto lambda = [&called](float) { - called = true; - return 'a'; - }; - FunctionRef<char(float)> ref(lambda); - [](absl::FunctionRef<char(float)> absl_ref) { - absl_ref(1.0); - }(ref.ToAbsl()); - EXPECT_TRUE(called); - } - - // `absl::FunctionRef` should be able to adapt "similar enough" signatures. - { - bool called = false; - auto lambda = [&called](float) { - called = true; - return 'a'; - }; - FunctionRef<char(float)> ref(lambda); - [](absl::FunctionRef<void(float)> absl_ref) { - absl_ref(1.0); - }(ref.ToAbsl()); - EXPECT_TRUE(called); - } +TEST(FunctionRef, FunctionPtr) { + [](FunctionRef<char(float)> ref) { EXPECT_EQ('a', ref(1.0)); }(&Func); + const FunctionRef<char(float)> ref = +[](float) { return 'a'; }; + EXPECT_EQ('a', ref(1.0f)); } -// base::FunctionRef allows functors with convertible return types to be -// adapted. -TEST(FunctionRefTest, ConvertibleReturnTypes) { - // Hopefully this never results in a postmorterm-worthy bug... +TEST(FunctionRef, Functor) { + struct S { + int operator()(int x) const { return x; } + }; + const S s; + const FunctionRef<int(int)> ref = s; + EXPECT_EQ(17, ref(17)); +} + +TEST(FunctionRef, Method) { + struct S { + int Method() const { return value; } + + const int value; + }; + const S s(25); + [&s](FunctionRef<int(const S*)> ref) { EXPECT_EQ(25, ref(&s)); }(&S::Method); +} + +// `FunctionRef` allows functors with convertible return types to be adapted. +TEST(FunctionRef, ConvertibleReturnTypes) { { - auto lambda = []() -> bool { return true; }; - [](FunctionRef<int()> ref) { EXPECT_EQ(1, ref()); }(lambda); + const auto lambda = [] { return true; }; + const FunctionRef<int()> ref = lambda; + EXPECT_EQ(1, ref()); } { class Base {}; class Derived : public Base {}; - auto lambda = []() -> Derived* { return nullptr; }; - [](FunctionRef<Base*()> ref) { EXPECT_EQ(nullptr, ref()); }(lambda); + const auto lambda = []() -> Derived* { return nullptr; }; + const FunctionRef<const Base*()> ref = lambda; + EXPECT_EQ(nullptr, ref()); } } +TEST(FunctionRef, ConstructionFromInexactMatches) { + // Lambda. + const auto lambda = [](int32_t x) { return x; }; + + // Capturing lambda. + const auto capturing_lambda = [&](int32_t x) { return lambda(x); }; + + // Function pointer. + int32_t (*const function_ptr)(int32_t) = +lambda; + + // Functor. + struct Functor { + int32_t operator()(int32_t x) const { return x; } + }; + const Functor functor; + + // Method. + struct Obj { + int32_t Method(int32_t x) const { return x; } + }; + int32_t (Obj::*const method)(int32_t) const = &Obj::Method; + + // Each of the objects above should work for a `FunctionRef` with a + // convertible return type. In this case, they all return `int32_t`, which + // should be seamlessly convertible to `int64_t` below. + static_assert( + std::constructible_from<FunctionRef<int64_t(int32_t)>, decltype(lambda)>); + static_assert(std::constructible_from<FunctionRef<int64_t(int32_t)>, + decltype(capturing_lambda)>); + static_assert(std::constructible_from<FunctionRef<int64_t(int32_t)>, + decltype(function_ptr)>); + static_assert(std::constructible_from<FunctionRef<int64_t(int32_t)>, + decltype(functor)>); + static_assert( + std::constructible_from<FunctionRef<int64_t(const Obj*, int32_t)>, + decltype(method)>); + + // It shouldn't be possible to construct a `FunctionRef` from any of the + // objects above if we discard the return value. + static_assert( + !std::constructible_from<FunctionRef<void(int32_t)>, decltype(lambda)>); + static_assert(!std::constructible_from<FunctionRef<void(int32_t)>, + decltype(capturing_lambda)>); + static_assert(!std::constructible_from<FunctionRef<void(int32_t)>, + decltype(function_ptr)>); + static_assert( + !std::constructible_from<FunctionRef<void(int32_t)>, decltype(functor)>); + static_assert(!std::constructible_from<FunctionRef<void(const Obj*, int32_t)>, + decltype(method)>); + + // It shouldn't be possible to construct a `FunctionRef` from a pointer to a + // functor, even with a compatible signature. + static_assert(!std::constructible_from<FunctionRef<int32_t(int32_t)>, + decltype(&functor)>); +} + } // namespace base
diff --git a/chrome/VERSION b/chrome/VERSION index 39baabc..e5bd4748 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=122 MINOR=0 -BUILD=6211 +BUILD=6212 PATCH=0
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceConfiguration.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceConfiguration.java index 9664407..70fd243 100644 --- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceConfiguration.java +++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceConfiguration.java
@@ -110,6 +110,10 @@ new BooleanCachedFieldTrialParameter( ChromeFeatureList.SURFACE_POLISH, SURFACE_POLISH_SCROLLABLE_MVT_PARAM, false); + public static final BooleanCachedFieldTrialParameter SURFACE_POLISH_USE_MAGIC_SPACE = + new BooleanCachedFieldTrialParameter( + ChromeFeatureList.SURFACE_POLISH, "use_magic_space", false); + private static final String STARTUP_UMA_PREFIX = "Startup.Android."; private static final String INSTANT_START_SUBFIX = ".Instant"; private static final String REGULAR_START_SUBFIX = ".NoInstant"; @@ -134,7 +138,7 @@ /** Returns whether a magic space is enabled on Start surface. */ public static boolean useMagicSpace() { return ChromeFeatureList.sSurfacePolish.isEnabled() - && ChromeFeatureList.sMagicStackAndroid.isEnabled() + && SURFACE_POLISH_USE_MAGIC_SPACE.getValue() && ChromeFeatureList.sStartSurfaceRefactor.isEnabled(); }
diff --git a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceMVTilesTest.java b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceMVTilesTest.java index baa6e9b..b57a0869 100644 --- a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceMVTilesTest.java +++ b/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceMVTilesTest.java
@@ -174,12 +174,8 @@ @Test @MediumTest @Feature({"StartSurface"}) - @CommandLineFlags.Add({START_SURFACE_TEST_SINGLE_ENABLED_PARAMS}) - @EnableFeatures({ - ChromeFeatureList.START_SURFACE_REFACTOR, - ChromeFeatureList.SURFACE_POLISH, - ChromeFeatureList.MAGIC_STACK_ANDROID - }) + @CommandLineFlags.Add({START_SURFACE_TEST_SINGLE_ENABLED_PARAMS + "/use_magic_space/true"}) + @EnableFeatures({ChromeFeatureList.START_SURFACE_REFACTOR, ChromeFeatureList.SURFACE_POLISH}) public void testTapMVTilesInSingleSurfaceWithSurfacePolish() { testTapMVTilesInSingleSurfaceImpl(); }
diff --git a/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceMediatorUnitTest.java b/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceMediatorUnitTest.java index 0aedda4..3c75b73 100644 --- a/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceMediatorUnitTest.java +++ b/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceMediatorUnitTest.java
@@ -29,6 +29,7 @@ import static org.mockito.Mockito.when; import static org.chromium.chrome.browser.flags.ChromeFeatureList.INSTANT_START; +import static org.chromium.chrome.features.start_surface.StartSurfaceConfiguration.SURFACE_POLISH_USE_MAGIC_SPACE; import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.BOTTOM_BAR_HEIGHT; import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.EXPLORE_SURFACE_COORDINATOR; import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.IS_EXPLORE_SURFACE_VISIBLE; @@ -1878,14 +1879,11 @@ } @Test - @EnableFeatures({ - ChromeFeatureList.START_SURFACE_REFACTOR, - ChromeFeatureList.SURFACE_POLISH, - ChromeFeatureList.MAGIC_STACK_ANDROID - }) + @EnableFeatures({ChromeFeatureList.START_SURFACE_REFACTOR, ChromeFeatureList.SURFACE_POLISH}) public void testObserverWithSurfacePolish() { + SURFACE_POLISH_USE_MAGIC_SPACE.setForTesting(true); Assert.assertTrue(ChromeFeatureList.sSurfacePolish.isEnabled()); - Assert.assertTrue(ChromeFeatureList.sMagicStackAndroid.isEnabled()); + Assert.assertTrue(SURFACE_POLISH_USE_MAGIC_SPACE.getValue()); doReturn(false).when(mTabModelSelector).isIncognitoSelected(); doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler(); @@ -1954,14 +1952,11 @@ } @Test - @EnableFeatures({ - ChromeFeatureList.START_SURFACE_REFACTOR, - ChromeFeatureList.SURFACE_POLISH, - ChromeFeatureList.MAGIC_STACK_ANDROID - }) + @EnableFeatures({ChromeFeatureList.START_SURFACE_REFACTOR, ChromeFeatureList.SURFACE_POLISH}) public void testShowAndOnHideWithSurfacePolish() { + SURFACE_POLISH_USE_MAGIC_SPACE.setForTesting(true); Assert.assertTrue(ChromeFeatureList.sSurfacePolish.isEnabled()); - Assert.assertTrue(ChromeFeatureList.sMagicStackAndroid.isEnabled()); + Assert.assertTrue(SURFACE_POLISH_USE_MAGIC_SPACE.getValue()); doReturn(false).when(mTabModelSelector).isIncognitoSelected(); doReturn(mVoiceRecognitionHandler).when(mOmniboxStub).getVoiceRecognitionHandler();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java b/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java index efcac74..b23e8eb 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java
@@ -116,6 +116,7 @@ StartSurfaceConfiguration.SURFACE_POLISH_MOVE_DOWN_LOGO, StartSurfaceConfiguration.SURFACE_POLISH_LESS_BRAND_SPACE, StartSurfaceConfiguration.SURFACE_POLISH_SCROLLABLE_MVT, + StartSurfaceConfiguration.SURFACE_POLISH_USE_MAGIC_SPACE, TabUiFeatureUtilities.ANIMATION_START_TIMEOUT_MS, TabUiFeatureUtilities.ZOOMING_MIN_MEMORY, TabUiFeatureUtilities.SKIP_SLOW_ZOOMING,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManagerImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManagerImpl.java index e7ad903..78709957 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManagerImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManagerImpl.java
@@ -51,7 +51,6 @@ import org.chromium.components.signin.identitymanager.IdentityMutator; import org.chromium.components.signin.identitymanager.PrimaryAccountError; import org.chromium.components.signin.metrics.SigninAccessPoint; -import org.chromium.components.signin.metrics.SigninReason; import org.chromium.components.signin.metrics.SignoutDelete; import org.chromium.components.signin.metrics.SignoutReason; import org.chromium.components.sync.SyncService; @@ -474,10 +473,6 @@ "Signin.SigninCompletedAccessPoint", mSignInState.getAccessPoint(), SigninAccessPoint.MAX); - RecordHistogram.recordEnumeratedHistogram( - "Signin.SigninReason", - SigninReason.SIGNIN_PRIMARY_ACCOUNT, - SigninReason.MAX_VALUE + 1); } if (mSignInState.mCallback != null) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationTest.java index 1d9e58c..cad07be9 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationTest.java
@@ -758,7 +758,6 @@ @Test @MediumTest - @DisabledTest(message = "https://crbug.com/1513445") public void testMultipleFresBackButton() throws Exception { launchViewIntent(TEST_URL); FirstRunActivity firstFreActivity = waitForFirstRunActivity(); @@ -772,6 +771,9 @@ 0, secondFreData.abortFirstRunExperienceCallback.getCallCount()); + Assert.assertTrue( + "FirstRunActivity should intercept back press", + secondFreActivity.getOnBackPressedDispatcher().hasEnabledCallbacks()); TestThreadUtils.runOnUiThreadBlocking( secondFreActivity.getOnBackPressedDispatcher()::onBackPressed); secondFreData.abortFirstRunExperienceCallback.waitForCallback(
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 98dd6b3..8e6ebc1 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -2363,6 +2363,11 @@ const FeatureEntry::FeatureParam kSurfacePolish_logo_in_toolbar[] = { {"polish_omnibox_color", "true"}}; +const FeatureEntry::FeatureParam kSurfacePolish_use_magic_space[] = { + {"polish_omnibox_color", "true"}, + {"move_down_logo", "true"}, + {"use_magic_space", "true"}}; + const FeatureEntry::FeatureVariation kSurfacePolishVariations[] = { {"Arm 1: MVP", kSurfacePolish_mvp, std::size(kSurfacePolish_mvp), nullptr}, {"Arm 2: White Omnibox", kSurfacePolish_white_omnibox, @@ -2373,6 +2378,8 @@ std::size(kSurfacePolish_mvp_2row_mvt), nullptr}, {"Arm 5: Logo in toolbar", kSurfacePolish_logo_in_toolbar, std::size(kSurfacePolish_logo_in_toolbar), nullptr}, + {"Use magic space", kSurfacePolish_use_magic_space, + std::size(kSurfacePolish_use_magic_space), nullptr}, }; const FeatureEntry::FeatureParam kFeedPositionAndroid_push_down_feed_small[] = { @@ -6948,10 +6955,6 @@ kSurfacePolishVariations, "SurfacePolish")}, - {"enable-magic-stack-android", flag_descriptions::kMagicStackAndroidName, - flag_descriptions::kMagicStackAndroidDescription, kOsAndroid, - FEATURE_VALUE_TYPE(chrome::android::kMagicStackAndroid)}, - {"enable-show-ntp-at-startup", flag_descriptions::kShowNtpAtStartupAndroidName, flag_descriptions::kShowNtpAtStartupAndroidDescription, kOsAndroid,
diff --git a/chrome/browser/ash/arc/tracing/arc_app_performance_tracing.cc b/chrome/browser/ash/arc/tracing/arc_app_performance_tracing.cc index 48cc644..9d84833d 100644 --- a/chrome/browser/ash/arc/tracing/arc_app_performance_tracing.cc +++ b/chrome/browser/ash/arc/tracing/arc_app_performance_tracing.cc
@@ -192,14 +192,15 @@ const std::optional<PerfTraceResult>& result) { bool success = result.has_value(); - // TODO(matvore): commitDeviation is still expected by Go clients; update it - // to presentDeviation, possibly by populating two fields with the same value - // for a grace period. + // TODO(matvore): commitDeviation is still expected by Go clients; remove it + // once Go clients are expecting presentDeviation. custom_trace_result_.emplace( base::Value::Dict() .Set("success", success) .Set("fps", success ? result->fps : 0) + .Set("perceivedFps", success ? result->perceived_fps : 0) .Set("commitDeviation", success ? result->present_deviation : 0) + .Set("presentDeviation", success ? result->present_deviation : 0) .Set("renderQuality", success ? result->render_quality : 0)); }
diff --git a/chrome/browser/ash/arc/tracing/arc_app_performance_tracing_session.cc b/chrome/browser/ash/arc/tracing/arc_app_performance_tracing_session.cc index 790c97f7..52d4e75 100644 --- a/chrome/browser/ash/arc/tracing/arc_app_performance_tracing_session.cc +++ b/chrome/browser/ash/arc/tracing/arc_app_performance_tracing_session.cc
@@ -92,6 +92,7 @@ VLOG(1) << "Start tracing."; frames_.emplace(); + commit_count_ = 0; exo::Surface* const surface = exo::GetShellRootSurface(window_); DCHECK(surface); @@ -151,11 +152,14 @@ return; } + commit_count_++; frames_->ListenForPresent(surface); } void ArcAppPerformanceTracingSession::Analyze(base::TimeDelta tracing_period) { - if (frames_->presents().size() < 2 || tracing_period <= base::TimeDelta() || + const auto& presents = frames_->presents(); + + if (presents.size() < 2 || tracing_period <= base::TimeDelta() || DetectIdle()) { Stop(std::nullopt); return; @@ -165,10 +169,9 @@ double vsync_error_deviation_accumulator = 0; std::vector<base::TimeDelta> deltas; - deltas.reserve(frames_->presents().size() - 1); + deltas.reserve(presents.size() - 1); - for (auto fitr = frames_->presents().begin() + 1; - fitr != frames_->presents().end(); fitr++) { + for (auto fitr = presents.begin() + 1; fitr != presents.end(); fitr++) { const auto frame_delta = base::Microseconds(*fitr - *(fitr - 1)); deltas.push_back(frame_delta); @@ -186,18 +189,20 @@ vsync_error_deviation_accumulator += (vsync_error.InMicrosecondsF() * vsync_error.InMicrosecondsF()); } - const double present_deviation = + PerfTraceResult result; + result.present_deviation = sqrt(vsync_error_deviation_accumulator / deltas.size()); std::sort(deltas.begin(), deltas.end()); // Get 10% and 90% indices. const size_t lower_position = deltas.size() / 10; const size_t upper_position = deltas.size() - 1 - lower_position; - const double render_quality = deltas[lower_position] / deltas[upper_position]; + result.render_quality = deltas[lower_position] / deltas[upper_position]; - const double fps = deltas.size() / tracing_period.InSecondsF(); + result.fps = commit_count_ / tracing_period.InSecondsF(); + result.perceived_fps = presents.size() / tracing_period.InSecondsF(); - Stop(PerfTraceResult{fps, present_deviation, render_quality}); + Stop(result); } } // namespace arc
diff --git a/chrome/browser/ash/arc/tracing/arc_app_performance_tracing_session.h b/chrome/browser/ash/arc/tracing/arc_app_performance_tracing_session.h index 7f9e0b9..865c2bd 100644 --- a/chrome/browser/ash/arc/tracing/arc_app_performance_tracing_session.h +++ b/chrome/browser/ash/arc/tracing/arc_app_performance_tracing_session.h
@@ -27,7 +27,7 @@ namespace arc { struct PerfTraceResult { - double fps, present_deviation, render_quality; + double fps, perceived_fps, present_deviation, render_quality; }; using TicksNowCallback = base::RepeatingCallback<base::TimeTicks()>; @@ -122,6 +122,10 @@ // Traces and records frame timing. std::optional<PresentFramesTracer> frames_; + // Number of commits that occurred during the trace. This count will include + // frames that were not presented by exo e.g. as a result of late commit. + uint32_t commit_count_; + TicksNowCallback ticks_now_callback_; DoneCallback on_done_;
diff --git a/chrome/browser/ash/arc/tracing/arc_app_performance_tracing_unittest.cc b/chrome/browser/ash/arc/tracing/arc_app_performance_tracing_unittest.cc index 8bc154d..e3dc872 100644 --- a/chrome/browser/ash/arc/tracing/arc_app_performance_tracing_unittest.cc +++ b/chrome/browser/ash/arc/tracing/arc_app_performance_tracing_unittest.cc
@@ -50,9 +50,9 @@ constexpr int kMillisecondsToFirstFrame = 500; struct Application { - std::string package; - std::string activity; - std::string name; + const char* package; + const char* activity; + const char* name; }; std::string GetStatisticName(const std::string& name, @@ -79,6 +79,27 @@ return ReadStatistics(name, kFocusCategory); } +constexpr std::initializer_list<Application> kApplications{ + {"com.mojang.minecraftpe", "com.mojang.minecraftpe.MainActivity", + "MinecraftConsumerEdition"}, + {"com.innersloth.spacemafia", + "com.innersloth.spacemafia.EosUnityPlayerActivity", "AmongUs"}, + {"com.plarium.raidlegends", "com.plarium.unity_app.UnityMainActivity", + "RaidLegends"}, + {"com.valvesoftware.underlords", "com.valvesoftware.underlords.applauncher", + "Underlords"}, + {"com.tocaboca.tocalifeworld", "com.tocaboca.activity.TocaBocaMainActivity", + "TocaLife"}, + {"com.king.candycrushsaga", + "com.king.candycrushsaga.CandyCrushSagaActivity", "CandyCrush"}, + {"com.playrix.homescapes", "com.playrix.homescapes.GoogleActivity", + "Homescapes"}, + {"com.ea.gp.fifamobile", "com.ea.gp.fifamobile.FifaMainActivity", + "FIFAMobile"}, + {"com.miHoYo.GenshinImpact", "com.miHoYo.GetMobileInfo.MainActivity", + "GenshinImpact"}, +}; + } // namespace // BrowserWithTestWindowTest contains required ash/shell support that would not @@ -97,6 +118,11 @@ // testing::Test: void SetUp() override { + ForgetAppMetrics(kFocusCategory); + for (const auto& app : kApplications) { + ForgetAppMetrics(app.name); + } + BrowserWithTestWindowTest::SetUp(); arc_test_.SetUp(profile()); @@ -121,6 +147,17 @@ int64_t task_id = 1; std::unique_ptr<exo::Surface> shell_root_surface_; + void ForgetAppMetrics(const std::string& category) { + base::StatisticsRecorder::ForgetHistogramForTesting( + GetStatisticName("FPS2", category)); + base::StatisticsRecorder::ForgetHistogramForTesting( + GetStatisticName("PerceivedFPS2", category)); + base::StatisticsRecorder::ForgetHistogramForTesting( + GetStatisticName("CommitDeviation2", category)); + base::StatisticsRecorder::ForgetHistogramForTesting( + GetStatisticName("RenderQuality2", category)); + } + // Ensures that tracing is ready to begin, which means up to the point that // waiting for the delayed start has just begun. views::Widget* PrepareArcAppTracing(const std::string& package_name, @@ -321,7 +358,7 @@ tracing_helper().PlayDefaultSequence(shell_root_surface_.get()); tracing_helper().FireTimerForTesting(); - EXPECT_EQ(45L, ReadFocusStatistics("FPS2")); + EXPECT_EQ(48L, ReadFocusStatistics("FPS2")); EXPECT_EQ(216L, ReadFocusStatistics("CommitDeviation2")); EXPECT_EQ(48L, ReadFocusStatistics("RenderQuality2")); arc_widget->Close(); @@ -332,61 +369,37 @@ arc_widget->Close(); } +TEST_F(ArcAppPerformanceTracingTest, DifferingFPSTypes) { + // 32 ms interval is 31.25 FPS. + constexpr base::TimeDelta kCommitInterval = base::Milliseconds(32); + constexpr int kFrameCount = 100; + + UmaPerfReporting::SetTracingPeriodForTesting(kFrameCount * kCommitInterval); + views::Widget* arc_widget = PrepareArcFocusAppTracing(); + + tracing_helper().GetTracingSession()->FireTimerForTesting(); + for (int frame = 0; frame < kFrameCount; frame++) { + tracing_helper().AdvanceTickCount(kCommitInterval); + // One frame of every ten is missed, so perceived FPS is 28.125. + tracing_helper().Commit( + shell_root_surface_.get(), + (frame % 10) == 0 ? PresentType::kDiscarded : PresentType::kSuccessful); + } + + tracing_helper().FireTimerForTesting(); + EXPECT_EQ(31L, ReadFocusStatistics("FPS2")); + EXPECT_EQ(28L, ReadFocusStatistics("PerceivedFPS2")); + arc_widget->Close(); +} + TEST_F(ArcAppPerformanceTracingTest, ApplicationStatisticsReported) { - std::vector<const Application> applications; - - const Application minecraft = {"com.mojang.minecraftpe", - "com.mojang.minecraftpe.MainActivity", - "MinecraftConsumerEdition"}; - applications.push_back(minecraft); - - const Application among_us = { - "com.innersloth.spacemafia", - "com.innersloth.spacemafia.EosUnityPlayerActivity", "AmongUs"}; - applications.push_back(among_us); - - const Application raid_legends = {"com.plarium.raidlegends", - "com.plarium.unity_app.UnityMainActivity", - "RaidLegends"}; - applications.push_back(raid_legends); - - const Application underlords = {"com.valvesoftware.underlords", - "com.valvesoftware.underlords.applauncher", - "Underlords"}; - applications.push_back(underlords); - - const Application toca_life = {"com.tocaboca.tocalifeworld", - "com.tocaboca.activity.TocaBocaMainActivity", - "TocaLife"}; - applications.push_back(toca_life); - - const Application candy_crush = { - "com.king.candycrushsaga", - "com.king.candycrushsaga.CandyCrushSagaActivity", "CandyCrush"}; - applications.push_back(candy_crush); - - const Application homescapes = {"com.playrix.homescapes", - "com.playrix.homescapes.GoogleActivity", - "Homescapes"}; - applications.push_back(homescapes); - - const Application fifa_mobile = {"com.ea.gp.fifamobile", - "com.ea.gp.fifamobile.FifaMainActivity", - "FIFAMobile"}; - applications.push_back(fifa_mobile); - - const Application genshin_impact = {"com.miHoYo.GenshinImpact", - "com.miHoYo.GetMobileInfo.MainActivity", - "GenshinImpact"}; - applications.push_back(genshin_impact); - - for (const Application& application : applications) { + for (const Application& application : kApplications) { views::Widget* const arc_widget = StartArcAppTracing(application.package, application.activity); tracing_helper().PlayDefaultSequence(shell_root_surface_.get()); tracing_helper().FireTimerForTesting(); - EXPECT_EQ(45L, ReadStatistics("FPS2", application.name)); + EXPECT_EQ(48L, ReadStatistics("FPS2", application.name)); EXPECT_EQ(216L, ReadStatistics("CommitDeviation2", application.name)); EXPECT_EQ(48L, ReadStatistics("RenderQuality2", application.name)); arc_widget->Close();
diff --git a/chrome/browser/ash/arc/tracing/test/arc_app_performance_tracing_test_helper.h b/chrome/browser/ash/arc/tracing/test/arc_app_performance_tracing_test_helper.h index 6bd68977..7632ef9 100644 --- a/chrome/browser/ash/arc/tracing/test/arc_app_performance_tracing_test_helper.h +++ b/chrome/browser/ash/arc/tracing/test/arc_app_performance_tracing_test_helper.h
@@ -58,8 +58,9 @@ void PlaySequence(exo::Surface* surface, const std::vector<base::TimeDelta>& deltas); - // Plays default sequence that has FPS = 45, CommitDeviation = 216 and - // RenderQuality = 48% for target tracing period as 1/3 seconds. + // Plays default sequence that has PerceivedFPS = FPS = 48, + // CommitDeviation = 216 and RenderQuality = 48% for target tracing period as + // 1/3 seconds. void PlayDefaultSequence(exo::Surface* surface); // Causes the surface to be committed and its present callback to be invoked.
diff --git a/chrome/browser/ash/arc/tracing/uma_perf_reporting.cc b/chrome/browser/ash/arc/tracing/uma_perf_reporting.cc index 494f87b..faaf256c 100644 --- a/chrome/browser/ash/arc/tracing/uma_perf_reporting.cc +++ b/chrome/browser/ash/arc/tracing/uma_perf_reporting.cc
@@ -31,6 +31,14 @@ static_cast<int>(std::round(fps))); } +void ReportPerceivedFPS(const std::string& category_name, + double perceived_fps) { + DCHECK(!category_name.empty()); + DCHECK_GT(perceived_fps, 0); + base::UmaHistogramCounts100(GetHistogramName(category_name, "PerceivedFPS2"), + static_cast<int>(std::round(perceived_fps))); +} + void ReportCommitDeviation(const std::string& category_name, double error_mcs) { DCHECK(!category_name.empty()); DCHECK_GE(error_mcs, 0); @@ -82,6 +90,7 @@ << ", present_deviation: " << result->present_deviation; ReportFPS(category, result->fps); + ReportPerceivedFPS(category, result->perceived_fps); ReportCommitDeviation(category, result->present_deviation); ReportQuality(category, result->render_quality);
diff --git a/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/BackPressHelper.java b/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/BackPressHelper.java index e76c09eb..cf2e239 100644 --- a/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/BackPressHelper.java +++ b/chrome/browser/back_press/android/java/src/org/chromium/chrome/browser/back_press/BackPressHelper.java
@@ -68,6 +68,10 @@ handler.handleBackPress(); } }; + // Update it now since ObservableSupplier posts updates asynchronously. + if (handler.getHandleBackPressChangedSupplier().get() != null) { + callback.setEnabled(handler.getHandleBackPressChangedSupplier().get()); + } handler.getHandleBackPressChangedSupplier().addObserver(callback::setEnabled); dispatcher.addCallback(lifecycleOwner, callback); }
diff --git a/chrome/browser/extensions/api/braille_display_private/brlapi_connection.h b/chrome/browser/extensions/api/braille_display_private/brlapi_connection.h index a69e1af..596294f 100644 --- a/chrome/browser/extensions/api/braille_display_private/brlapi_connection.h +++ b/chrome/browser/extensions/api/braille_display_private/brlapi_connection.h
@@ -13,15 +13,13 @@ #include "base/functional/callback_forward.h" #include "library_loaders/libbrlapi.h" -namespace extensions { -namespace api { -namespace braille_display_private { +namespace extensions::api::braille_display_private { // A connection to the brlapi server. See brlapi.h for more information // about the semantics of the methods in this class. class BrlapiConnection { public: - typedef base::RepeatingClosure OnDataReadyCallback; + using OnDataReadyCallback = base::RepeatingClosure; enum ConnectResult { CONNECT_ERROR_RETRY, @@ -75,8 +73,6 @@ BrlapiConnection() = default; }; -} // namespace braille_display_private -} // namespace api -} // namespace extensions +} // namespace extensions::api::braille_display_private #endif // CHROME_BROWSER_EXTENSIONS_API_BRAILLE_DISPLAY_PRIVATE_BRLAPI_CONNECTION_H_
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 76f8032a..5e3cdde 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -1406,7 +1406,7 @@ { "name": "cros-labs-overview-desk-navigation", "owners": [ "richui@chromium.org", "janetmac@chromium.org" ], - "expiry_milestone": 122 + "expiry_milestone": 136 }, { "name": "cros-labs-window-cycle-shortcut", @@ -3058,11 +3058,6 @@ "expiry_milestone": 130 }, { - "name": "enable-magic-stack-android", - "owners": [ "hanxi@chromium.org", "xinyiji@chromium.org", "clank-start@chromium.org" ], - "expiry_milestone": 130 - }, - { "name": "enable-managed-configuration-web-api", "owners": [ "apotapchuk@chromium.org" ], "expiry_milestone": 92
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 17adec3..f9c1c17 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -4096,11 +4096,6 @@ const char kInterestFeedV2HeartsName[] = "Interest Feed v2 Hearts"; const char kInterestFeedV2HeartsDescription[] = "Enable hearts on Feedv2."; -const char kMagicStackAndroidName[] = "Magic Stack Android"; -const char kMagicStackAndroidDescription[] = - "Show a magic stack which contains a list of modules on Start surface and " - "NTPs on Android."; - const char kMediaPickerAdoptionStudyName[] = "Android Media Picker Adoption"; const char kMediaPickerAdoptionStudyDescription[] = "Controls how to launch the Android Media Picker (note: This flag is "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 08d5ccd6f..9280f4e 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -2391,9 +2391,6 @@ extern const char kInterestFeedV2HeartsName[]; extern const char kInterestFeedV2HeartsDescription[]; -extern const char kMagicStackAndroidName[]; -extern const char kMagicStackAndroidDescription[]; - extern const char kMediaPickerAdoptionStudyName[]; extern const char kMediaPickerAdoptionStudyDescription[];
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc index 52831238..441cc24 100644 --- a/chrome/browser/flags/android/chrome_feature_list.cc +++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -219,7 +219,6 @@ &kInstantStart, &kLensCameraAssistedSearch, &kLensOnQuickActionSearchWidget, - &kMagicStackAndroid, &kMultiInstanceApplicationStatusCleanup, &kNewTabSearchEngineUrlAndroid, &kNotificationPermissionVariant, @@ -633,10 +632,6 @@ BASE_FEATURE(kInstantStart, "InstantStart", base::FEATURE_DISABLED_BY_DEFAULT); -BASE_FEATURE(kMagicStackAndroid, - "MagicStackAndroid", - base::FEATURE_DISABLED_BY_DEFAULT); - BASE_FEATURE(kMultiInstanceApplicationStatusCleanup, "MultiInstanceApplicationStatusCleanup", base::FEATURE_ENABLED_BY_DEFAULT);
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h index 32f40056..55b17fa 100644 --- a/chrome/browser/flags/android/chrome_feature_list.h +++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -92,7 +92,6 @@ BASE_DECLARE_FEATURE(kLensCameraAssistedSearch); BASE_DECLARE_FEATURE(kLensOnQuickActionSearchWidget); BASE_DECLARE_FEATURE(kLocationBarModelOptimizations); -BASE_DECLARE_FEATURE(kMagicStackAndroid); BASE_DECLARE_FEATURE(kMultiInstanceApplicationStatusCleanup); BASE_DECLARE_FEATURE(kNewTabSearchEngineUrlAndroid); BASE_DECLARE_FEATURE(kNotificationPermissionVariant);
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java index 9042e67..28950e4b 100644 --- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java +++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -274,7 +274,6 @@ public static final String LENS_ON_QUICK_ACTION_SEARCH_WIDGET = "LensOnQuickActionSearchWidget"; public static final String LOOKALIKE_NAVIGATION_URL_SUGGESTIONS_UI = "LookalikeUrlNavigationSuggestionsUI"; - public static final String MAGIC_STACK_ANDROID = "MagicStackAndroid"; public static final String MESSAGES_FOR_ANDROID_ADS_BLOCKED = "MessagesForAndroidAdsBlocked"; public static final String MESSAGES_FOR_ANDROID_INFRASTRUCTURE = "MessagesForAndroidInfrastructure"; @@ -513,7 +512,6 @@ public static final CachedFlag sInstantStart = new CachedFlag(INSTANT_START, false); public static final CachedFlag sHideTabOnTabSwitcher = new CachedFlag(HIDE_TAB_ON_TAB_SWITCHER, true); - public static final CachedFlag sMagicStackAndroid = new CachedFlag(MAGIC_STACK_ANDROID, false); public static final CachedFlag sMultiInstanceApplicationStatusCleanup = new CachedFlag(MUlTI_INSTANCE_APPLICATION_STATUS_CLEANUP, true); public static final CachedFlag sNewTabSearchEngineUrlAndroid = @@ -614,7 +612,6 @@ sIncognitoReauthenticationForAndroid, sInstantStart, sHideTabOnTabSwitcher, - sMagicStackAndroid, sMultiInstanceApplicationStatusCleanup, sNewTabSearchEngineUrlAndroid, sPaintPreviewNewColdStartHeuristic,
diff --git a/chrome/browser/metrics/family_link_user_metrics_provider.cc b/chrome/browser/metrics/family_link_user_metrics_provider.cc index 22aad49..47a72af 100644 --- a/chrome/browser/metrics/family_link_user_metrics_provider.cc +++ b/chrome/browser/metrics/family_link_user_metrics_provider.cc
@@ -21,27 +21,26 @@ bool FamilyLinkUserMetricsProvider::ProvideHistograms() { // This function is called at unpredictable intervals throughout the Chrome // session, so guarantee it will never crash. - - ProfileManager* profile_manager = g_browser_process->profile_manager(); - std::vector<Profile*> profile_list = profile_manager->GetLoadedProfiles(); - std::vector<AccountInfo> primary_accounts; - for (Profile* profile : profile_list) { + ProfileManager* profile_manager = g_browser_process->profile_manager(); + std::vector<Profile*> profile_list = profile_manager->GetLoadedProfiles(); + std::vector<AccountInfo> primary_accounts; + for (Profile* profile : profile_list) { #if !BUILDFLAG(IS_ANDROID) - // TODO(b/274889379): Mock call to GetBrowserCount(). - if (!FamilyLinkUserMetricsProvider:: - skip_active_browser_count_for_unittesting_ && - chrome::GetBrowserCount(profile) == 0) { - // The profile is loaded, but there's no opened browser for this - // profile. - continue; - } -#endif - signin::IdentityManager* identity_manager_ = - IdentityManagerFactory::GetForProfile(profile); - AccountInfo account_info = identity_manager_->FindExtendedAccountInfo( - identity_manager_->GetPrimaryAccountInfo( - signin::ConsentLevel::kSignin)); - primary_accounts.push_back(std::move(account_info)); + // TODO(b/274889379): Mock call to GetBrowserCount(). + if (!FamilyLinkUserMetricsProvider:: + skip_active_browser_count_for_unittesting_ && + chrome::GetBrowserCount(profile) == 0) { + // The profile is loaded, but there's no opened browser for this + // profile. + continue; } - return supervised_user::EmitLogSegmentHistogram(primary_accounts); +#endif + signin::IdentityManager* identity_manager_ = + IdentityManagerFactory::GetForProfile(profile); + AccountInfo account_info = identity_manager_->FindExtendedAccountInfo( + identity_manager_->GetPrimaryAccountInfo( + signin::ConsentLevel::kSignin)); + primary_accounts.push_back(std::move(account_info)); + } + return supervised_user::EmitLogSegmentHistogram(primary_accounts); }
diff --git a/chrome/browser/metrics/variations/chrome_variations_service_client.h b/chrome/browser/metrics/variations/chrome_variations_service_client.h index fed9816c..6f53839 100644 --- a/chrome/browser/metrics/variations/chrome_variations_service_client.h +++ b/chrome/browser/metrics/variations/chrome_variations_service_client.h
@@ -37,7 +37,8 @@ TakeSeedFromNativeVariationsSeedStore() override; void RemoveGoogleGroupsFromPrefsForDeletedProfiles( PrefService* local_state) override; - void RegisterLimitedEntropySyntheticTrial(std::string_view group_name); + void RegisterLimitedEntropySyntheticTrial( + std::string_view group_name) override; private: // variations::VariationsServiceClient:
diff --git a/chrome/browser/optimization_guide/optimization_guide_keyed_service.h b/chrome/browser/optimization_guide/optimization_guide_keyed_service.h index 7830827d..8cb03be2 100644 --- a/chrome/browser/optimization_guide/optimization_guide_keyed_service.h +++ b/chrome/browser/optimization_guide/optimization_guide_keyed_service.h
@@ -263,6 +263,10 @@ scoped_refptr<optimization_guide::OnDeviceModelComponentStateManager> on_device_component_manager_; + // The tab URL provider to use for fetching information for the user's active + // tabs. Will be null if the user is off the record. + std::unique_ptr<optimization_guide::TabUrlProvider> tab_url_provider_; + // Manages the storing, loading, and fetching of hints. std::unique_ptr<optimization_guide::ChromeHintsManager> hints_manager_; @@ -281,10 +285,6 @@ // behavior. std::unique_ptr<optimization_guide::TopHostProvider> top_host_provider_; - // The tab URL provider to use for fetching information for the user's active - // tabs. Will be null if the user is off the record. - std::unique_ptr<optimization_guide::TabUrlProvider> tab_url_provider_; - // Manages the model execution. Not created for off the record profiles. std::unique_ptr<optimization_guide::ModelExecutionManager> model_execution_manager_;
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 2aacd71..873c25b 100644 --- a/chrome/browser/policy/cloud/user_policy_signin_service_browsertest.cc +++ b/chrome/browser/policy/cloud/user_policy_signin_service_browsertest.cc
@@ -151,7 +151,7 @@ return new TurnSyncOnHelper( profile(), signin_metrics::AccessPoint::ACCESS_POINT_BOOKMARK_MANAGER, signin_metrics::PromoAction::PROMO_ACTION_WITH_DEFAULT, - signin_metrics::Reason::kReauthentication, account_info_.account_id, + account_info_.account_id, TurnSyncOnHelper::SigninAbortedMode::REMOVE_ACCOUNT, std::make_unique<TestTurnSyncOnHelperDelegate>(this), base::DoNothing());
diff --git a/chrome/browser/resources/chromeos/BUILD.gn b/chrome/browser/resources/chromeos/BUILD.gn index c97beb3..6ee90ea5 100644 --- a/chrome/browser/resources/chromeos/BUILD.gn +++ b/chrome/browser/resources/chromeos/BUILD.gn
@@ -93,7 +93,6 @@ "crostini_upgrader:closure_compile", "emulator:closure_compile", "gaia_action_buttons:closure_compile", - "internet_config_dialog:closure_compile", "login:closure_compile", "multidevice_internals:closure_compile", "multidevice_setup:closure_compile",
diff --git a/chrome/browser/resources/chromeos/accessibility/.eslintrc.js b/chrome/browser/resources/chromeos/accessibility/.eslintrc.js index 023e5f08..e057646 100644 --- a/chrome/browser/resources/chromeos/accessibility/.eslintrc.js +++ b/chrome/browser/resources/chromeos/accessibility/.eslintrc.js
@@ -31,6 +31,72 @@ 'allowExpressions': true, }, ], + // https://google.github.io/styleguide/jsguide.html#naming + '@typescript-eslint/naming-convention': [ + 'error', + { + selector: ['class', 'interface', 'typeAlias', 'enum', 'typeParameter'], + format: ['StrictPascalCase'], + filter: { + regex: '^(' + + // Exclude TypeScript defined interfaces HTMLElementTagNameMap + // and HTMLElementEventMap. + 'HTMLElementTagNameMap|HTMLElementEventMap|' + + // Exclude native DOM types which are always named like HTML<Foo>Element. + 'HTML[A-Za-z]{0,}Element|' + + // Exclude native DOM interfaces. + 'UIEvent|UIEventInit|DOMError|' + + // Exclude the SACache and SACommands classes. + 'SACache|SACommands)$', + match: false, + }, + }, + { + selector: 'enumMember', + format: ['UPPER_CASE'], + }, + { + selector: 'classMethod', + format: ['strictCamelCase'], + modifiers: ['public'], + }, + { + selector: 'classMethod', + format: ['strictCamelCase'], + modifiers: ['private'], + trailingUnderscore: 'allow', + }, + { + selector: 'classProperty', + format: ['UPPER_CASE'], + modifiers: ['private', 'static', 'readonly'], + }, + { + selector: 'classProperty', + format: ['UPPER_CASE'], + modifiers: ['public', 'static', 'readonly'], + }, + { + selector: 'classProperty', + format: ['camelCase'], + modifiers: ['public'], + }, + { + selector: 'classProperty', + format: ['camelCase'], + modifiers: ['private'], + trailingUnderscore: 'allow', + }, + { + selector: 'parameter', + format: ['camelCase'], + leadingUnderscore: 'allow', + }, + { + selector: 'function', + format: ['camelCase'], + }, + ], }, }, ],
diff --git a/chrome/browser/resources/chromeos/accessibility/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/BUILD.gn index e6620e0..b5ddacc 100644 --- a/chrome/browser/resources/chromeos/accessibility/BUILD.gn +++ b/chrome/browser/resources/chromeos/accessibility/BUILD.gn
@@ -14,6 +14,7 @@ assert(is_chromeos_ash) accessibility_out_dir = "$root_out_dir/resources/chromeos/accessibility/" +tsc_preprocess_folder = "$root_gen_dir/chrome/browser/resources/chromeos/accessibility/tsc_preprocessed" tsc_out_dir = "$target_gen_dir/tsc" group("build") { @@ -170,10 +171,7 @@ group("unit_tests_js") { testonly = true if (is_chromeos_ash) { - deps = [ - ":misc_unit_tests_js", - "chromevox:chromevox_unit_js_tests", - ] + deps = [ ":misc_unit_tests_js" ] } } @@ -183,3 +181,11 @@ gen_include_files = [ "common/testing/accessibility_test_base.js" ] extra_js_files = [ "braille_ime/braille_ime.js" ] } + +# Copy definitions from the main typescript folder into our local definitions +# folder. This can only be done once, otherwise we will get collisions, so do +# this at the very top-level of the build structure. +copy("preprocess_files_for_ts_build") { + sources = [ "//tools/typescript/definitions/chrome_event.d.ts" ] + outputs = [ "$tsc_preprocess_folder/definitions/chrome_event.d.ts" ] +}
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/accessibility_common/BUILD.gn index abdfc7f3..6a78b77 100644 --- a/chrome/browser/resources/chromeos/accessibility/accessibility_common/BUILD.gn +++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/BUILD.gn
@@ -19,8 +19,24 @@ accessibility_common_dir = "$root_out_dir/resources/chromeos/accessibility/accessibility_common" +tsc_preprocess_folder = "$root_gen_dir/chrome/browser/resources/chromeos/accessibility/tsc_preprocessed" tsc_out_dir = "$target_gen_dir/tsc" +misc_sources = [ + "background.html", + "dictation/earcons/audio_end.wav", + "dictation/earcons/audio_initiate.wav", + "dictation/earcons/null_selection.wav", + "dictation/parse/input_text_strategy.js", + "dictation/parse/parse_strategy.js", + "dictation/parse/pumpkin/pumpkin_constants.js", + "dictation/parse/pumpkin_parse_strategy.js", + "dictation/parse/sandboxed_pumpkin_tagger.js", + "dictation/parse/simple_parse_strategy.js", + "dictation/parse/speech_parser.js", + "facegaze/camera_stream.html", +] + # TS files to build. ts_modules = [ "accessibility_common_loader.ts", @@ -51,35 +67,41 @@ "magnifier/magnifier.ts", ] +ts_definitions = [ + "../definitions/accessibility_private_mv2.d.ts", + "../definitions/audio.d.ts", + "../definitions/automation.d.ts", + "../definitions/command_line_private.d.ts", + "../definitions/extensions.d.ts", + "../definitions/extension_types.d.ts", + "../definitions/input_ime.d.ts", + "../definitions/input_method_private.d.ts", + "../definitions/language_settings_private.d.ts", + "../definitions/metrics_private.d.ts", + "../definitions/runtime.d.ts", + "../definitions/settings_private_mv2.d.ts", + "../definitions/speech_recognition_private.d.ts", + "../definitions/tabs.d.ts", + "../definitions/settings_private_mv2.d.ts", + "../definitions/accessibility_features_mv2.d.ts", + "//tools/typescript/definitions/i18n.d.ts", + "//tools/typescript/definitions/windows.d.ts", +] + +# Generated files needed for TS build. +generated_ts_modules = [] +generated_ts_definitions = [] + # JS files needed by the TS compiler. js_deps = [] ts_library("ts_build") { - # Root dir must be the parent directory so it can reach common. - root_dir = "../" + # Root dir must be the tsc preprocessed folder, since it will use both checked-in and generated files. + root_dir = "$tsc_preprocess_folder" out_dir = tsc_out_dir - definitions = [ - "../definitions/accessibility_private_mv2.d.ts", - "../definitions/audio.d.ts", - "../definitions/automation.d.ts", - "../definitions/command_line_private.d.ts", - "../definitions/extensions.d.ts", - "../definitions/extension_types.d.ts", - "../definitions/input_ime.d.ts", - "../definitions/input_method_private.d.ts", - "../definitions/language_settings_private.d.ts", - "../definitions/metrics_private.d.ts", - "../definitions/runtime.d.ts", - "../definitions/settings_private_mv2.d.ts", - "../definitions/speech_recognition_private.d.ts", - "../definitions/tabs.d.ts", - "../definitions/settings_private_mv2.d.ts", - "../definitions/accessibility_features_mv2.d.ts", - "//tools/typescript/definitions/i18n.d.ts", - "//tools/typescript/definitions/windows.d.ts", - ] + definitions = ts_definitions + generated_ts_definitions - in_files = [] + in_files = generated_ts_modules foreach(_js_file, js_deps) { in_files += [ "accessibility_common/" + _js_file ] } @@ -88,6 +110,13 @@ } tsconfig_base = "../tsconfig.base.json" + + # Targets that need to run before running the TS build. + extra_deps = [ + ":preprocess_files_for_ts_build", + "..:preprocess_files_for_ts_build", + "../common:preprocess_files_for_ts_build", + ] } group("build") { @@ -106,21 +135,9 @@ ":ts_build", "../common:copied_files", ] - sources = [ - "background.html", - "dictation/earcons/audio_end.wav", - "dictation/earcons/audio_initiate.wav", - "dictation/earcons/null_selection.wav", - "dictation/parse/input_text_strategy.js", - "dictation/parse/parse_strategy.js", - "dictation/parse/pumpkin/pumpkin_constants.js", - "dictation/parse/pumpkin_parse_strategy.js", - "dictation/parse/sandboxed_pumpkin_tagger.js", - "dictation/parse/simple_parse_strategy.js", - "dictation/parse/speech_parser.js", - "facegaze/camera_stream.html", - ] - sources += filter_include(get_target_outputs(":ts_build"), [ "*.js" ]) + + sources = + misc_sources + filter_include(get_target_outputs(":ts_build"), [ "*.js" ]) rewrite_rules = [ rebase_path("$tsc_out_dir/accessibility_common", root_build_dir) + ":", @@ -254,3 +271,13 @@ outputs = files_to_extract } } + +# Copy all JS and TS sources to a preprocess folder. All generated TS/JS files +# will also be copied into this folder, which will allow us to support a TS +# build that uses both checked-in and generated files. +copy("preprocess_files_for_ts_build") { + sources = misc_sources + ts_modules + outputs = [ + "$tsc_preprocess_folder/accessibility_common/{{source_target_relative}}", + ] +}
diff --git a/chrome/browser/resources/chromeos/accessibility/braille_ime/braille_ime_unittest.js b/chrome/browser/resources/chromeos/accessibility/braille_ime/braille_ime_unittest.js index b925c8c6..6d4f626 100644 --- a/chrome/browser/resources/chromeos/accessibility/braille_ime/braille_ime_unittest.js +++ b/chrome/browser/resources/chromeos/accessibility/braille_ime/braille_ime_unittest.js
@@ -5,7 +5,6 @@ /** * @fileoverview Unit test for the Braille IME. */ -GEN_INCLUDE(['../common/testing/accessibility_test_base.js']); /** * Mock Chrome event supporting one listener. @@ -71,7 +70,7 @@ /** * Test fixture for the braille IME unit test. */ -BrailleImeUnitTest = class extends AccessibilityTestBase { +BrailleImeUnitTest = class extends testing.Test { /** @override */ setUp() { super.setUp(); @@ -149,11 +148,11 @@ TEST_F('BrailleImeUnitTest', 'KeysWhenStandardKeyboardDisabled', function() { this.activateIme(); - expectFalse(this.sendKeyDown('KeyF')); - expectFalse(this.sendKeyDown('KeyD')); - expectFalse(this.sendKeyUp('KeyD')); - expectFalse(this.sendKeyUp('KeyF')); - expectEquals(0, this.port.messages.length); + assertFalse(this.sendKeyDown('KeyF')); + assertFalse(this.sendKeyDown('KeyD')); + assertFalse(this.sendKeyUp('KeyD')); + assertFalse(this.sendKeyUp('KeyF')); + assertEquals(0, this.port.messages.length); }); TEST_F('BrailleImeUnitTest', 'KeysWhenStandardKeysEnabled', function() { @@ -162,46 +161,46 @@ this.onMenuItemActivated.dispatch(ENGINE_ID, this.menuItems[0].id); assertTrue(this.menuItems[0].checked); // Type the letters 'b' and 'c' and verify the right dots get sent. - expectTrue(this.sendKeyDown('KeyF')); - expectTrue(this.sendKeyDown('KeyD')); - expectTrue(this.sendKeyUp('KeyD')); - expectTrue(this.sendKeyUp('KeyF')); - expectTrue(this.sendKeyDown('KeyJ')); - expectTrue(this.sendKeyDown('KeyF')); - expectTrue(this.sendKeyUp('KeyJ')); - expectTrue(this.sendKeyUp('KeyF')); + assertTrue(this.sendKeyDown('KeyF')); + assertTrue(this.sendKeyDown('KeyD')); + assertTrue(this.sendKeyUp('KeyD')); + assertTrue(this.sendKeyUp('KeyF')); + assertTrue(this.sendKeyDown('KeyJ')); + assertTrue(this.sendKeyDown('KeyF')); + assertTrue(this.sendKeyUp('KeyJ')); + assertTrue(this.sendKeyUp('KeyF')); // Make sure that other keys are not handled, either by themselves or while // one of the 'braille keys' is pressed. - expectFalse(this.sendKeyDown('KeyX')); - expectFalse(this.sendKeyUp('KeyX')); + assertFalse(this.sendKeyDown('KeyX')); + assertFalse(this.sendKeyUp('KeyX')); - expectTrue(this.sendKeyDown('KeyS')); // Dot 3 - expectFalse(this.sendKeyDown('KeyG')); // To the right of dot 1. - expectTrue(this.sendKeyUp('KeyS')); - expectFalse(this.sendKeyUp('KeyG')); + assertTrue(this.sendKeyDown('KeyS')); // Dot 3 + assertFalse(this.sendKeyDown('KeyG')); // To the right of dot 1. + assertTrue(this.sendKeyUp('KeyS')); + assertFalse(this.sendKeyUp('KeyG')); // Keys like Ctrl L should not be handled, despite L being a dot key. var ctrlFlag = {ctrlKey: true}; - expectFalse(this.sendKeyDown('ControlLeft', ctrlFlag)); - expectFalse(this.sendKeyDown('KeyL', ctrlFlag)); - expectFalse(this.sendKeyUp('KeyL', ctrlFlag)); - expectFalse(this.sendKeyUp('ControlLeft', ctrlFlag)); + assertFalse(this.sendKeyDown('ControlLeft', ctrlFlag)); + assertFalse(this.sendKeyDown('KeyL', ctrlFlag)); + assertFalse(this.sendKeyUp('KeyL', ctrlFlag)); + assertFalse(this.sendKeyUp('ControlLeft', ctrlFlag)); // Space key by itself should send a blank cell. - expectTrue(this.sendKeyDown('Space')); - expectTrue(this.sendKeyUp('Space')); + assertTrue(this.sendKeyDown('Space')); + assertTrue(this.sendKeyUp('Space')); // Space and braille dots results in no event. - expectTrue(this.sendKeyDown('Space')); - expectTrue(this.sendKeyDown('KeyF')); - expectTrue(this.sendKeyUp('Space')); - expectTrue(this.sendKeyUp('KeyF')); + assertTrue(this.sendKeyDown('Space')); + assertTrue(this.sendKeyDown('KeyF')); + assertTrue(this.sendKeyUp('Space')); + assertTrue(this.sendKeyUp('KeyF')); // Send the braille key first, still no event should be produced. - expectTrue(this.sendKeyDown('KeyF')); - expectTrue(this.sendKeyDown('Space')); - expectTrue(this.sendKeyUp('Space')); - expectTrue(this.sendKeyUp('KeyF')); + assertTrue(this.sendKeyDown('KeyF')); + assertTrue(this.sendKeyDown('Space')); + assertTrue(this.sendKeyUp('Space')); + assertTrue(this.sendKeyUp('KeyF')); assertDeepEquals(this.port.messages, [ {type: 'brailleDots', dots: 0x03}, @@ -217,7 +216,7 @@ this.onMenuItemActivated.dispatch(ENGINE_ID, this.menuItems[0].id); assertTrue(this.menuItems[0].checked); - expectEquals(undefined, this.sendKeyDown('Backspace')); + assertEquals(undefined, this.sendKeyDown('Backspace')); assertDeepEquals( this.port.messages, [{type: 'backspace', requestId: this.lastSentKeyRequestId_ + ''}]); @@ -226,8 +225,8 @@ requestId: this.lastSentKeyRequestId_ + '', result: true, }); - expectEquals(this.lastSentKeyRequestId_, this.lastHandledKeyRequestId_); - expectTrue(this.lastHandledKeyResult_); + assertEquals(this.lastSentKeyRequestId_, this.lastHandledKeyRequestId_); + assertTrue(this.lastHandledKeyResult_); }); TEST_F('BrailleImeUnitTest', 'UseStandardKeyboardSettingPreserved', function() {
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn index acd7000..1e536d11 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn
@@ -410,36 +410,6 @@ } # These tests can run in a pure V8 renderer (e.g. no DOM). - js2gtest("chromevox_unit_js_tests") { - test_type = "unit" - sources = [ - "background/braille/expanding_braille_translator_test.js", - "background/braille/pan_strategy_test.js", - "background/editing/editable_text_base_test.js", - "background/phonetic_data_test.js", - "common/key_sequence_test.js", - "common/spannable_test.js", - "testing/mock_feedback_test.js", - ] - gen_include_files = [ "../common/testing/accessibility_test_base.js" ] - extra_js_files = [ - "../common/testing/accessibility_test_base.js", - "../common/testing/assert_additions.js", - "../common/testing/callback_helper.js", - "background/braille/expanding_braille_translator.js", - "background/braille/pan_strategy.js", - "background/braille/spans.js", - "background/braille/liblouis.js", - "background/editing/editable_text_base.js", - "background/phonetic_data.js", - "common/key_sequence.js", - "common/msgs.js", - "common/spannable.js", - "testing/fake_dom.js", - "testing/mock_feedback.js", - "third_party/tamachiyomi/ja_phonetic_data.js", - ] - } # These tests need a full extension renderer. js2gtest("chromevox_extension_js_tests") { @@ -480,6 +450,20 @@ "panel/panel_test_base.js", "panel/tutorial_test.js", ] + + # These tests need support for async/await (b/317173285). + sources += [ + "background/braille/expanding_braille_translator_test.js", + "background/braille/pan_strategy_test.js", + + # TODO(anastasi): Determine why this test suite is flaky and re-enable. + # "background/editing/editable_text_base_test.js", + "background/phonetic_data_test.js", + "common/key_sequence_test.js", + "common/spannable_test.js", + "testing/mock_feedback_test.js", + ] + gen_include_files = [ "../common/testing/accessibility_test_base.js", "../common/testing/assert_additions.js",
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/expanding_braille_translator_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/expanding_braille_translator_test.js index e04b227..af06b23 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/expanding_braille_translator_test.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/expanding_braille_translator_test.js
@@ -2,13 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -GEN_INCLUDE(['../../../common/testing/accessibility_test_base.js']); +GEN_INCLUDE(['../../testing/chromevox_e2e_test_base.js']); /** * Test fixture. */ -ChromeVoxExpandingBrailleTranslatorUnitTest = - class extends AccessibilityTestBase { +ChromeVoxExpandingBrailleTranslatorUnitTest = class extends ChromeVoxE2ETest { /** @override */ async setUpDeferred() { await super.setUpDeferred(); @@ -19,7 +18,12 @@ 'ExpandingBrailleTranslator', '/chromevox/background/braille/expanding_braille_translator.js'), importModule( - ['ExtraCellsSpan', 'ValueSelectionSpan', 'ValueSpan'], + [ + 'BrailleTextStyleSpan', + 'ExtraCellsSpan', + 'ValueSelectionSpan', + 'ValueSpan', + ], '/chromevox/background/braille/spans.js'), importModule('LibLouis', '/chromevox/background/braille/liblouis.js'), importModule('Spannable', '/chromevox/common/spannable.js'), @@ -27,12 +31,6 @@ } }; -/** @override */ -ChromeVoxExpandingBrailleTranslatorUnitTest.prototype.extraLibraries = [ - '../../../common/testing/assert_additions.js', - '../../testing/fake_dom.js', -]; - /** * An implementation of {@link LibLouis.Translator} whose translation * output is an array buffer of the same byte length as the input and where @@ -86,7 +84,7 @@ } } -TEST_F( +AX_TEST_F( 'ChromeVoxExpandingBrailleTranslatorUnitTest', 'TranslationError', function() { const text = new Spannable('error ok', new ValueSpan()); @@ -268,7 +266,7 @@ const TEXT = 'Hello, world!'; -TEST_F( +AX_TEST_F( 'ChromeVoxExpandingBrailleTranslatorUnitTest', 'successfulTranslations', function() { /** @@ -339,7 +337,7 @@ assertEquals(totalExpectedTranslationTests, totalRunTranslationTests); }); -TEST_F( +AX_TEST_F( 'ChromeVoxExpandingBrailleTranslatorUnitTest', 'StyleTranslations', function() { const formTypeMap = {};
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/pan_strategy_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/pan_strategy_test.js index d9940331..19cd8d2 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/pan_strategy_test.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/pan_strategy_test.js
@@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -GEN_INCLUDE(['../../../common/testing/accessibility_test_base.js']); +GEN_INCLUDE(['../../testing/chromevox_e2e_test_base.js']); /** * Test fixture. */ -ChromeVoxPanStrategyUnitTest = class extends AccessibilityTestBase { +ChromeVoxPanStrategyUnitTest = class extends ChromeVoxE2ETest { /** @override */ async setUpDeferred() { await super.setUpDeferred(); @@ -21,13 +21,6 @@ } }; -/** @override */ -ChromeVoxPanStrategyUnitTest.prototype.extraLibraries = [ - '../../../common/testing/assert_additions.js', - '../../testing/fake_dom.js', -]; - - /** * Creates an array buffer based off of the passed in content. * Note: Input should be a string of numbers, spaces will turn to 0's. @@ -42,7 +35,7 @@ return result; } -TEST_F('ChromeVoxPanStrategyUnitTest', 'FixedPanning', function() { +AX_TEST_F('ChromeVoxPanStrategyUnitTest', 'FixedPanning', function() { const panner = new PanStrategy(); panner.setPanStrategy(false); @@ -95,100 +88,102 @@ assertEqualsJSON({firstRow: 0, lastRow: 1}, panner.viewPort); }); -TEST_F('ChromeVoxPanStrategyUnitTest', 'WrappedPanningSingleLine', function() { - const panner = new PanStrategy(); - panner.setPanStrategy(true); +AX_TEST_F( + 'ChromeVoxPanStrategyUnitTest', 'WrappedPanningSingleLine', function() { + const panner = new PanStrategy(); + panner.setPanStrategy(true); - // 30 cells with blank cells at positions 8, 22 and 26. - const content = createArrayBuffer('11234567 9112345678911 345 789'); - panner.setContent('a', content, [], 0); - assertEqualsJSON({firstRow: 0, lastRow: 0}, panner.viewPort); - assertFalse(panner.next()); - assertFalse(panner.previous()); + // 30 cells with blank cells at positions 8, 22 and 26. + const content = createArrayBuffer('11234567 9112345678911 345 789'); + panner.setContent('a', content, [], 0); + assertEqualsJSON({firstRow: 0, lastRow: 0}, panner.viewPort); + assertFalse(panner.next()); + assertFalse(panner.previous()); - panner.setDisplaySize(1, 10); - assertEqualsJSON({firstRow: 0, lastRow: 0}, panner.viewPort); - assertArrayBuffersEquals( - createArrayBuffer('11234567 '), - panner.getCurrentBrailleViewportContents()); - assertTrue(panner.next()); - assertEqualsJSON({firstRow: 1, lastRow: 1}, panner.viewPort); - assertArrayBuffersEquals( - createArrayBuffer('9112345678'), - panner.getCurrentBrailleViewportContents()); - assertTrue(panner.next()); - assertEqualsJSON({firstRow: 2, lastRow: 2}, panner.viewPort); - assertArrayBuffersEquals( - createArrayBuffer('911 345 '), - panner.getCurrentBrailleViewportContents()); - assertTrue(panner.next()); - assertEqualsJSON({firstRow: 3, lastRow: 3}, panner.viewPort); - assertArrayBuffersEquals( - createArrayBuffer('789'), panner.getCurrentBrailleViewportContents()); - assertFalse(panner.next()); - assertEqualsJSON({firstRow: 3, lastRow: 3}, panner.viewPort); - assertTrue(panner.previous()); - assertEqualsJSON({firstRow: 2, lastRow: 2}, panner.viewPort); - assertTrue(panner.previous()); - assertEqualsJSON({firstRow: 1, lastRow: 1}, panner.viewPort); - assertTrue(panner.previous()); - assertEqualsJSON({firstRow: 0, lastRow: 0}, panner.viewPort); - assertFalse(panner.previous()); + panner.setDisplaySize(1, 10); + assertEqualsJSON({firstRow: 0, lastRow: 0}, panner.viewPort); + assertArrayBuffersEquals( + createArrayBuffer('11234567 '), + panner.getCurrentBrailleViewportContents()); + assertTrue(panner.next()); + assertEqualsJSON({firstRow: 1, lastRow: 1}, panner.viewPort); + assertArrayBuffersEquals( + createArrayBuffer('9112345678'), + panner.getCurrentBrailleViewportContents()); + assertTrue(panner.next()); + assertEqualsJSON({firstRow: 2, lastRow: 2}, panner.viewPort); + assertArrayBuffersEquals( + createArrayBuffer('911 345 '), + panner.getCurrentBrailleViewportContents()); + assertTrue(panner.next()); + assertEqualsJSON({firstRow: 3, lastRow: 3}, panner.viewPort); + assertArrayBuffersEquals( + createArrayBuffer('789'), panner.getCurrentBrailleViewportContents()); + assertFalse(panner.next()); + assertEqualsJSON({firstRow: 3, lastRow: 3}, panner.viewPort); + assertTrue(panner.previous()); + assertEqualsJSON({firstRow: 2, lastRow: 2}, panner.viewPort); + assertTrue(panner.previous()); + assertEqualsJSON({firstRow: 1, lastRow: 1}, panner.viewPort); + assertTrue(panner.previous()); + assertEqualsJSON({firstRow: 0, lastRow: 0}, panner.viewPort); + assertFalse(panner.previous()); - panner.setContent('a', content, [], 21); - assertEqualsJSON({firstRow: 2, lastRow: 2}, panner.viewPort); - assertArrayBuffersEquals( - createArrayBuffer('911 345 '), - panner.getCurrentBrailleViewportContents()); + panner.setContent('a', content, [], 21); + assertEqualsJSON({firstRow: 2, lastRow: 2}, panner.viewPort); + assertArrayBuffersEquals( + createArrayBuffer('911 345 '), + panner.getCurrentBrailleViewportContents()); - panner.setContent('a', content, [], 30); - assertEqualsJSON({firstRow: 3, lastRow: 3}, panner.viewPort); - assertArrayBuffersEquals( - createArrayBuffer('789'), panner.getCurrentBrailleViewportContents()); + panner.setContent('a', content, [], 30); + assertEqualsJSON({firstRow: 3, lastRow: 3}, panner.viewPort); + assertArrayBuffersEquals( + createArrayBuffer('789'), panner.getCurrentBrailleViewportContents()); - panner.setDisplaySize(1, 8); - assertEqualsJSON({firstRow: 0, lastRow: 0}, panner.viewPort); - assertArrayBuffersEquals( - createArrayBuffer('11234567'), - panner.getCurrentBrailleViewportContents()); -}); + panner.setDisplaySize(1, 8); + assertEqualsJSON({firstRow: 0, lastRow: 0}, panner.viewPort); + assertArrayBuffersEquals( + createArrayBuffer('11234567'), + panner.getCurrentBrailleViewportContents()); + }); -TEST_F('ChromeVoxPanStrategyUnitTest', 'WrappedPanningMultiline', function() { - const panner = new PanStrategy(); - panner.setPanStrategy(true); +AX_TEST_F( + 'ChromeVoxPanStrategyUnitTest', 'WrappedPanningMultiline', function() { + const panner = new PanStrategy(); + panner.setPanStrategy(true); - // 30 cells with blank cells at positions 8, 22 and 26. - const content = createArrayBuffer('11234567 9112345678911 345 789'); - panner.setContent('a', content, [], 0); + // 30 cells with blank cells at positions 8, 22 and 26. + const content = createArrayBuffer('11234567 9112345678911 345 789'); + panner.setContent('a', content, [], 0); - panner.setDisplaySize(2, 10); - assertEqualsJSON({firstRow: 0, lastRow: 1}, panner.viewPort); - assertArrayBuffersEquals( - createArrayBuffer('11234567 9112345678'), - panner.getCurrentBrailleViewportContents()); - assertTrue(panner.next()); - assertEqualsJSON({firstRow: 2, lastRow: 3}, panner.viewPort); - assertArrayBuffersEquals( - createArrayBuffer('911 345 789'), - panner.getCurrentBrailleViewportContents()); - assertFalse(panner.next()); - assertEqualsJSON({firstRow: 2, lastRow: 3}, panner.viewPort); - assertArrayBuffersEquals( - createArrayBuffer('911 345 789'), - panner.getCurrentBrailleViewportContents()); - assertTrue(panner.previous()); - assertEqualsJSON({firstRow: 0, lastRow: 1}, panner.viewPort); - assertArrayBuffersEquals( - createArrayBuffer('11234567 9112345678'), - panner.getCurrentBrailleViewportContents()); - assertFalse(panner.previous()); - assertEqualsJSON({firstRow: 0, lastRow: 1}, panner.viewPort); - assertArrayBuffersEquals( - createArrayBuffer('11234567 9112345678'), - panner.getCurrentBrailleViewportContents()); -}); + panner.setDisplaySize(2, 10); + assertEqualsJSON({firstRow: 0, lastRow: 1}, panner.viewPort); + assertArrayBuffersEquals( + createArrayBuffer('11234567 9112345678'), + panner.getCurrentBrailleViewportContents()); + assertTrue(panner.next()); + assertEqualsJSON({firstRow: 2, lastRow: 3}, panner.viewPort); + assertArrayBuffersEquals( + createArrayBuffer('911 345 789'), + panner.getCurrentBrailleViewportContents()); + assertFalse(panner.next()); + assertEqualsJSON({firstRow: 2, lastRow: 3}, panner.viewPort); + assertArrayBuffersEquals( + createArrayBuffer('911 345 789'), + panner.getCurrentBrailleViewportContents()); + assertTrue(panner.previous()); + assertEqualsJSON({firstRow: 0, lastRow: 1}, panner.viewPort); + assertArrayBuffersEquals( + createArrayBuffer('11234567 9112345678'), + panner.getCurrentBrailleViewportContents()); + assertFalse(panner.previous()); + assertEqualsJSON({firstRow: 0, lastRow: 1}, panner.viewPort); + assertArrayBuffersEquals( + createArrayBuffer('11234567 9112345678'), + panner.getCurrentBrailleViewportContents()); + }); -TEST_F('ChromeVoxPanStrategyUnitTest', 'FixedSetContent', function() { +AX_TEST_F('ChromeVoxPanStrategyUnitTest', 'FixedSetContent', function() { const panner = new PanStrategy(); panner.setPanStrategy(false); @@ -203,7 +198,7 @@ assertArraysEquals(expectedMappingValue, panner.brailleToText); }); -TEST_F('ChromeVoxPanStrategyUnitTest', 'WrappedSetContent', function() { +AX_TEST_F('ChromeVoxPanStrategyUnitTest', 'WrappedSetContent', function() { const panner = new PanStrategy(); panner.setPanStrategy(true); @@ -257,7 +252,7 @@ assertArraysEquals(expectedMappingValue, panner.brailleToText); }); -TEST_F( +AX_TEST_F( 'ChromeVoxPanStrategyUnitTest', 'getCurrentTextViewportContents', function() { const panner = new PanStrategy(); @@ -285,26 +280,27 @@ assertEquals('789', panner.getCurrentTextViewportContents()); }); -TEST_F('ChromeVoxPanStrategyUnitTest', 'WrappedUnwrappedCursors', function() { - const panner = new PanStrategy(); - panner.setPanStrategy(true); +AX_TEST_F( + 'ChromeVoxPanStrategyUnitTest', 'WrappedUnwrappedCursors', function() { + const panner = new PanStrategy(); + panner.setPanStrategy(true); - // 30 cells with blank cells at positions 8, 22 and 26. - const content = createArrayBuffer('11234567 9112345678911 345 789'); + // 30 cells with blank cells at positions 8, 22 and 26. + const content = createArrayBuffer('11234567 9112345678911 345 789'); - panner.setCursor(1, 3); - panner.setContent('a', content, [], 0); - panner.setDisplaySize(2, 10); - assertEqualsJSON({start: 1, end: 3}, panner.getCursor()); - assertEqualsJSON({start: 1, end: 3}, panner.wrappedCursor_); + panner.setCursor(1, 3); + panner.setContent('a', content, [], 0); + panner.setDisplaySize(2, 10); + assertEqualsJSON({start: 1, end: 3}, panner.getCursor()); + assertEqualsJSON({start: 1, end: 3}, panner.wrappedCursor_); - panner.setCursor(5, 10); - panner.setContent('a', content, [], 0); - assertEqualsJSON({start: 5, end: 10}, panner.getCursor()); - assertEqualsJSON({start: 5, end: 11}, panner.wrappedCursor_); + panner.setCursor(5, 10); + panner.setContent('a', content, [], 0); + assertEqualsJSON({start: 5, end: 10}, panner.getCursor()); + assertEqualsJSON({start: 5, end: 11}, panner.wrappedCursor_); - panner.setCursor(9, 9); - panner.setContent('a', content, [], 0); - assertEqualsJSON({start: 9, end: 9}, panner.getCursor()); - assertEqualsJSON({start: 10, end: 11}, panner.wrappedCursor_); -}); + panner.setCursor(9, 9); + panner.setContent('a', content, [], 0); + assertEqualsJSON({start: 9, end: 9}, panner.getCursor()); + assertEqualsJSON({start: 10, end: 11}, panner.wrappedCursor_); + });
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/editing/editable_text_base_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/editing/editable_text_base_test.js index da49987..d308c814 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/editing/editable_text_base_test.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/editing/editable_text_base_test.js
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -GEN_INCLUDE(['../../../common/testing/accessibility_test_base.js']); +GEN_INCLUDE(['../../testing/chromevox_e2e_test_base.js']); /** * A TTS class implementing speak and stop methods intended only for testing. @@ -84,7 +84,7 @@ }; /** Test fixture. */ -ChromeVoxEditableTextUnitTest = class extends AccessibilityTestBase { +ChromeVoxEditableTextUnitTest = class extends ChromeVoxE2ETest { /** @override */ async setUpDeferred() { await super.setUpDeferred(); @@ -101,11 +101,12 @@ 'AutomationEditableText', '/chromevox/background/editing/editable_text.js'), importModule( - ['ChromeVoxEditableTextBase', 'TextChangedEvent'], + ['ChromeVoxEditableTextBase', 'TextChangeEvent'], '/chromevox/background/editing/editable_text_base.js'), importModule( 'TypingEchoState', '/chromevox/background/editing/typing_echo.js'), - importModule('TtsInterface', '/chromevox/common/tts_interface.js'), + importModule('TtsInterface', '/chromevox/background/tts_interface.js'), + importModule('Msgs', '/chromevox/common/msgs.js'), importModule('LocalStorage', '/common/local_storage.js'), ]); @@ -128,10 +129,6 @@ } }; -ChromeVoxEditableTextUnitTest.prototype.extraLibraries = [ - '../../../common/testing/assert_additions.js', -]; - function createEditableText(value, start, end, isPassword, tts) { const fakeNode = {state: {editable: true}}; const editable = new AutomationEditableText(fakeNode); @@ -144,7 +141,7 @@ return editable; } -TEST_F('ChromeVoxEditableTextUnitTest', 'CursorNavigation', function() { +AX_TEST_F('ChromeVoxEditableTextUnitTest', 'CursorNavigation', function() { var tts = new TestTts(); var obj = createEditableText('Hello', 0, 0, false, tts); @@ -162,7 +159,7 @@ }); /** Test typing words. */ -TEST_F('ChromeVoxEditableTextUnitTest', 'TypingWords', function() { +AX_TEST_F('ChromeVoxEditableTextUnitTest', 'TypingWords', function() { var tts = new TestTts(); var obj = createEditableText('', 0, 0, false, tts); obj.changed(new TextChangeEvent('H', 1, 1)); @@ -232,7 +229,7 @@ }); /** Test selection. */ -TEST_F('ChromeVoxEditableTextUnitTest', 'Selection', function() { +AX_TEST_F('ChromeVoxEditableTextUnitTest', 'Selection', function() { var tts = new TestTts(); var obj = createEditableText('Hello, world.', 0, 0, false, tts); obj.changed(new TextChangeEvent('Hello, world.', 0, 1)); @@ -273,7 +270,7 @@ * address bar, and it's being autocompleted. Sometimes it's autocompleted * as they type, sometimes there's a short delay. */ -TEST_F('ChromeVoxEditableTextUnitTest', 'Autocomplete', function() { +AX_TEST_F('ChromeVoxEditableTextUnitTest', 'Autocomplete', function() { var tts = new TestTts(); var obj = createEditableText('', 0, 0, false, tts); @@ -323,7 +320,7 @@ /** * Test a few common scenarios where text is replaced. */ -TEST_F('ChromeVoxEditableTextUnitTest', 'ReplacingText', function() { +AX_TEST_F('ChromeVoxEditableTextUnitTest', 'ReplacingText', function() { // Initial value is Alabama. var tts = new TestTts(); var obj = createEditableText('Alabama', 0, 0, false, tts); @@ -362,7 +359,7 @@ /** * Test feedback when text changes in a long sentence. */ -TEST_F('ChromeVoxEditableTextUnitTest', 'ReplacingLongText', function() { +AX_TEST_F('ChromeVoxEditableTextUnitTest', 'ReplacingLongText', function() { var tts = new TestTts(); var obj = createEditableText( 'I love deadlines. I like the whooshing sound they make as they fly by.', @@ -377,7 +374,7 @@ }); /** Tests character echo. */ -TEST_F('ChromeVoxEditableTextUnitTest', 'CharacterEcho', function() { +AX_TEST_F('ChromeVoxEditableTextUnitTest', 'CharacterEcho', function() { LocalStorage.set('typingEcho', TypingEchoState.CHARACTER); var tts = new TestTts(); var obj = createEditableText('', 0, 0, false, tts); @@ -401,41 +398,42 @@ /** Tests character echo in auto complete text fields. */ -TEST_F('ChromeVoxEditableTextUnitTest', 'CharEchoInAutoComplete', function() { - var tts = new TestTts(); - var url = 'chromevox.com'; - var obj = createEditableText(url, 1, 13, false, tts); +AX_TEST_F( + 'ChromeVoxEditableTextUnitTest', 'CharEchoInAutoComplete', function() { + var tts = new TestTts(); + var url = 'chromevox.com'; + var obj = createEditableText(url, 1, 13, false, tts); - // This simulates a user typing into an auto complete text field one character - // at a time. The selection is the completion and we toggle between various - // typing echo options. - LocalStorage.set('typingEcho', TypingEchoState.CHARACTER); - obj.changed(new TextChangeEvent(url, 2, 13)); - LocalStorage.set('typingEcho', TypingEchoState.NONE); - obj.changed(new TextChangeEvent(url, 3, 13)); - LocalStorage.set('typingEcho', TypingEchoState.CHARACTER_AND_WORD); - obj.changed(new TextChangeEvent(url, 4, 13)); - LocalStorage.set('typingEcho', TypingEchoState.WORD); - obj.changed(new TextChangeEvent(url, 5, 13)); + // This simulates a user typing into an auto complete text field one + // character at a time. The selection is the completion and we toggle + // between various typing echo options. + LocalStorage.set('typingEcho', TypingEchoState.CHARACTER); + obj.changed(new TextChangeEvent(url, 2, 13)); + LocalStorage.set('typingEcho', TypingEchoState.NONE); + obj.changed(new TextChangeEvent(url, 3, 13)); + LocalStorage.set('typingEcho', TypingEchoState.CHARACTER_AND_WORD); + obj.changed(new TextChangeEvent(url, 4, 13)); + LocalStorage.set('typingEcho', TypingEchoState.WORD); + obj.changed(new TextChangeEvent(url, 5, 13)); - // The characters should only be read for the typing echo modes containing a - // character. They are commented out below when unexpected to make the test - // clearer to read. - assertEqualStringArrays( - [ - 'h', - url.slice(2), - /* 'r', */ url.slice(3), - 'o', - url.slice(4), - /* 'm', */ url.slice(5), - ], - tts.get()); -}); + // The characters should only be read for the typing echo modes containing + // a character. They are commented out below when unexpected to make the + // test clearer to read. + assertEqualStringArrays( + [ + 'h', + url.slice(2), + /* 'r', */ url.slice(3), + 'o', + url.slice(4), + /* 'm', */ url.slice(5), + ], + tts.get()); + }); /** Tests word echo. */ -TEST_F('ChromeVoxEditableTextUnitTest', 'WordEcho', function() { +AX_TEST_F('ChromeVoxEditableTextUnitTest', 'WordEcho', function() { LocalStorage.set('typingEcho', TypingEchoState.WORD); var tts = new TestTts(); var obj = createEditableText('', 0, 0, false, tts); @@ -457,7 +455,7 @@ /** Tests no echo. */ -TEST_F('ChromeVoxEditableTextUnitTest', 'NoEcho', function() { +AX_TEST_F('ChromeVoxEditableTextUnitTest', 'NoEcho', function() { LocalStorage.set('typingEcho', TypingEchoState.NONE); var tts = new TestTts(); var obj = createEditableText('', 0, 0, false, tts); @@ -478,7 +476,7 @@ }); /** Tests normalization of TextChangeEvent's */ -TEST_F('ChromeVoxEditableTextUnitTest', 'TextChangeEvent', function() { +AX_TEST_F('ChromeVoxEditableTextUnitTest', 'TextChangeEvent', function() { var event1 = new TextChangeEvent('foo', 0, 1, true); var event2 = new TextChangeEvent('foo', 1, 0, true); var event3 = new TextChangeEvent('foo', 1, 1, true); @@ -493,17 +491,18 @@ assertEquals(1, event3.end); }); -TEST_F('ChromeVoxEditableTextUnitTest', 'TypingNonBreakingSpaces', function() { - var tts = new TestTts(); - var obj = createEditableText('Hello', 0, 0, false, tts); +AX_TEST_F( + 'ChromeVoxEditableTextUnitTest', 'TypingNonBreakingSpaces', function() { + var tts = new TestTts(); + var obj = createEditableText('Hello', 0, 0, false, tts); - obj.changed(new TextChangeEvent('h', 1, 1)); - obj.changed(new TextChangeEvent('hi', 2, 2)); - obj.changed(new TextChangeEvent('hi\u00a0', 3, 3)); - obj.changed(new TextChangeEvent('hi t', 4, 4)); - assertEqualStringArrays(['h', 'i', 'hi ', 't'], tts.get()); -}); -TEST_F('ChromeVoxEditableTextUnitTest', 'DoesNotSpeakDeleted', function() { + obj.changed(new TextChangeEvent('h', 1, 1)); + obj.changed(new TextChangeEvent('hi', 2, 2)); + obj.changed(new TextChangeEvent('hi\u00a0', 3, 3)); + obj.changed(new TextChangeEvent('hi t', 4, 4)); + assertEqualStringArrays(['h', 'i', 'hi ', 't'], tts.get()); + }); +AX_TEST_F('ChromeVoxEditableTextUnitTest', 'DoesNotSpeakDeleted', function() { var tts = new TestTts(); var obj = createEditableText('Hello', 0, 0, false, tts); obj.multiline = true;
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/phonetic_data_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/phonetic_data_test.js index 6fcc209..c5b8be3 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/phonetic_data_test.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/phonetic_data_test.js
@@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -GEN_INCLUDE(['../../common/testing/accessibility_test_base.js']); +GEN_INCLUDE(['../testing/chromevox_e2e_test_base.js']); /** * Test fixture for PhoneticData. */ -ChromeVoxPhoneticDataTest = class extends AccessibilityTestBase { +ChromeVoxPhoneticDataTest = class extends ChromeVoxE2ETest { /** @override */ async setUpDeferred() { await super.setUpDeferred(); @@ -20,13 +20,6 @@ } }; -/** @override */ -ChromeVoxPhoneticDataTest.prototype.extraLibraries = [ - '../../common/testing/assert_additions.js', - '../testing/fake_dom.js', - '../third_party/tamachiyomi/ja_phonetic_data.js', -]; - /** * This is only for test. Note that reading is different from production. * This map is not always used for determining phonetic readings. For example, @@ -61,7 +54,7 @@ // TODO(crbug/1195393): Polish phonetic readings so that users can disambiguate // more precisely. -TEST_F('ChromeVoxPhoneticDataTest', 'forCharacterJa', function() { +AX_TEST_F('ChromeVoxPhoneticDataTest', 'forCharacterJa', function() { assertEquals('ヒラガナ アサヒ ノ ア', PhoneticData.forCharacter('あ', 'ja')); assertEquals('カタカナ アサヒ ノ ア', PhoneticData.forCharacter('ア', 'ja')); assertEquals( @@ -88,7 +81,7 @@ assertEquals('アジア ノ ア', PhoneticData.forCharacter('亜', 'ja')); }); -TEST_F('ChromeVoxPhoneticDataTest', 'forTextJaSingleCharacter', function() { +AX_TEST_F('ChromeVoxPhoneticDataTest', 'forTextJaSingleCharacter', function() { assertEquals('あ', PhoneticData.forText('あ', 'ja')); assertEquals('カタカナ ア', PhoneticData.forText('ア', 'ja')); assertEquals('あ', PhoneticData.forText('ぁ', 'ja')); @@ -108,7 +101,7 @@ assertEquals('アジア ノ ア', PhoneticData.forText('亜', 'ja')); }); -TEST_F( +AX_TEST_F( 'ChromeVoxPhoneticDataTest', 'forTextJaPairCharacters_EndWithHiragana', function() { assertEquals('ああ', PhoneticData.forText('ああ', 'ja')); @@ -116,7 +109,7 @@ assertEquals('オオモジ A あ', PhoneticData.forText('Aあ', 'ja')); }); -TEST_F( +AX_TEST_F( 'ChromeVoxPhoneticDataTest', 'forTextJaPairCharacters_EndWithKatakana', function() { assertEquals('カタカナ アア', PhoneticData.forText('アア', 'ja')); @@ -125,7 +118,7 @@ assertEquals('あ カタカナ ア', PhoneticData.forText('あア', 'ja')); }); -TEST_F( +AX_TEST_F( 'ChromeVoxPhoneticDataTest', 'forTextJaPairCharacters_EndWithHiraganaSmallLetter', function() { assertEquals('あぁ', PhoneticData.forText('ぁぁ', 'ja')); @@ -133,7 +126,7 @@ assertEquals('アジア ノ ア あ', PhoneticData.forText('亜ぁ', 'ja')); }); -TEST_F( +AX_TEST_F( 'ChromeVoxPhoneticDataTest', 'forTextJaPairCharacters_EndWithKatakanaSmallLetter', function() { assertEquals( @@ -143,7 +136,7 @@ 'あ カタカナ チイサイ ア', PhoneticData.forText('あァ', 'ja')); }); -TEST_F( +AX_TEST_F( 'ChromeVoxPhoneticDataTest', 'forTextJaPairCharacters_EndWithHalfWidthKatakana', function() { assertEquals('ハンカク アア', PhoneticData.forText('アア', 'ja')); @@ -151,7 +144,7 @@ assertEquals('あ ハンカク ア', PhoneticData.forText('あア', 'ja')); }); -TEST_F( +AX_TEST_F( 'ChromeVoxPhoneticDataTest', 'forTextJaPairCharacters_EndWithHalfWidthKatakanaSmallLetter', function() { assertEquals('ハンカク チイサイ アァ', PhoneticData.forText('ァァ', 'ja')); @@ -159,7 +152,7 @@ assertEquals('あ ハンカク チイサイ ア', PhoneticData.forText('あァ', 'ja')); }); -TEST_F( +AX_TEST_F( 'ChromeVoxPhoneticDataTest', 'forTextJaPairCharacters_EndWithHalfWidthAlphabetUpper', function() { assertEquals('オオモジ AA', PhoneticData.forText('AA', 'ja')); @@ -171,7 +164,7 @@ assertEquals('あ オオモジ A', PhoneticData.forText('あA', 'ja')); }); -TEST_F( +AX_TEST_F( 'ChromeVoxPhoneticDataTest', 'forTextJaPairCharacters_EndWithHalfWidthAlphabetLower', function() { assertEquals('aa', PhoneticData.forText('aa', 'ja')); @@ -180,7 +173,7 @@ 'ゼンカクオオモジ A ハンカク a', PhoneticData.forText('Aa', 'ja')); }); -TEST_F( +AX_TEST_F( 'ChromeVoxPhoneticDataTest', 'forTextJaPairCharacters_EndWithHalfWidthNumeric', function() { assertEquals('11', PhoneticData.forText('11', 'ja')); @@ -189,7 +182,7 @@ 'ゼンカクオオモジ A ハンカク 1', PhoneticData.forText('A1', 'ja')); }); -TEST_F( +AX_TEST_F( 'ChromeVoxPhoneticDataTest', 'forTextJaPairCharacters_EndWithHalfWidthSymbol', function() { assertEquals( @@ -200,7 +193,7 @@ PhoneticData.forText('A@', 'ja')); }); -TEST_F( +AX_TEST_F( 'ChromeVoxPhoneticDataTest', 'forTextJaPairCharacters_EndWithFullWidthAlphabetUpper', function() { assertEquals('ゼンカクオオモジ AA', PhoneticData.forText('AA', 'ja')); @@ -210,7 +203,7 @@ 'あ ゼンカクオオモジ A', PhoneticData.forText('あA', 'ja')); }); -TEST_F( +AX_TEST_F( 'ChromeVoxPhoneticDataTest', 'forTextJaPairCharacters_EndWithFullWidthAlphabetLower', function() { assertEquals('ゼンカク aa', PhoneticData.forText('aa', 'ja')); @@ -219,7 +212,7 @@ assertEquals('あ ゼンカク a', PhoneticData.forText('あa', 'ja')); }); -TEST_F( +AX_TEST_F( 'ChromeVoxPhoneticDataTest', 'forTextJaPairCharacters_EndWithFullWidthNumeric', function() { assertEquals('ゼンカク 11', PhoneticData.forText('11', 'ja')); @@ -228,7 +221,7 @@ assertEquals('あ ゼンカク 1', PhoneticData.forText('あ1', 'ja')); }); -TEST_F( +AX_TEST_F( 'ChromeVoxPhoneticDataTest', 'forTextJaPairCharacters_EndWithFullWidthSymbol', function() { assertEquals( @@ -241,7 +234,7 @@ 'あ ゼンカク アットマーク', PhoneticData.forText('あ@', 'ja')); }); -TEST_F( +AX_TEST_F( 'ChromeVoxPhoneticDataTest', 'forTextJaPairCharacters_EndWithFullWidthGreekUpper', function() { assertEquals( @@ -251,7 +244,7 @@ 'あ オオモジ ギリシャ アルファ', PhoneticData.forText('あΑ', 'ja')); }); -TEST_F( +AX_TEST_F( 'ChromeVoxPhoneticDataTest', 'forTextJaPairCharacters_EndWithFullWidthGreekLower', function() { assertEquals( @@ -263,14 +256,14 @@ assertEquals('あ ギリシャ アルファ', PhoneticData.forText('あα', 'ja')); }); -TEST_F( +AX_TEST_F( 'ChromeVoxPhoneticDataTest', 'forTextJaPairCharacters_EndWithOther', function() { assertEquals( 'アジア ノ ア アジア ノ ア', PhoneticData.forText('亜亜', 'ja')); }); -TEST_F('ChromeVoxPhoneticDataTest', 'forTextJaLongSound', function() { +AX_TEST_F('ChromeVoxPhoneticDataTest', 'forTextJaLongSound', function() { assertEquals('あー', PhoneticData.forText('あー', 'ja')); assertEquals('カタカナ アー', PhoneticData.forText('アー', 'ja')); assertEquals('あー', PhoneticData.forText('ぁー', 'ja')); @@ -281,7 +274,7 @@ assertEquals('アジア ノ ア チョウオン', PhoneticData.forText('亜ー', 'ja')); }); -TEST_F('ChromeVoxPhoneticDataTest', 'forTextSampleSentences', function() { +AX_TEST_F('ChromeVoxPhoneticDataTest', 'forTextSampleSentences', function() { assertEquals( 'コンゲツノコン ニチヨウビノニチ は テンキヨホウノテン クウキノキ です マル', PhoneticData.forText('今日は天気です。', 'ja'));
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/common/key_sequence_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/common/key_sequence_test.js index 84fce1a..bceff2a 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/common/key_sequence_test.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/common/key_sequence_test.js
@@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -GEN_INCLUDE(['../../common/testing/accessibility_test_base.js']); +GEN_INCLUDE(['../testing/chromevox_e2e_test_base.js']); /** * Test fixture. */ -ChromeVoxKeySequenceUnitTest = class extends AccessibilityTestBase { +ChromeVoxKeySequenceUnitTest = class extends ChromeVoxE2ETest { /** * Create mock event object. * @param {number} keyCode The event key code (i.e. 13 for Enter). @@ -154,33 +154,28 @@ } }; -/** @override */ -ChromeVoxKeySequenceUnitTest.prototype.extraLibraries = [ - '../../common/testing/assert_additions.js', - '../testing/fake_dom.js', -]; +AX_TEST_F( + 'ChromeVoxKeySequenceUnitTest', 'SimpleSequenceNoModifier', function() { + const downKey = new KeySequence(this.downArrowEvent, false); -TEST_F('ChromeVoxKeySequenceUnitTest', 'SimpleSequenceNoModifier', function() { - const downKey = new KeySequence(this.downArrowEvent, false); + assertEqualsJSON([KeyCode.DOWN], downKey.keys.keyCode); + assertFalse(downKey.stickyMode); + assertFalse(downKey.prefixKey); + assertFalse(downKey.cvoxModifier); - assertEqualsJSON([KeyCode.DOWN], downKey.keys.keyCode); - assertFalse(downKey.stickyMode); - assertFalse(downKey.prefixKey); - assertFalse(downKey.cvoxModifier); + assertEqualsJSON([false], downKey.keys.altGraphKey); + assertEqualsJSON([false], downKey.keys.altKey); + assertEqualsJSON([false], downKey.keys.ctrlKey); + assertEqualsJSON([false], downKey.keys.metaKey); + assertEqualsJSON([false], downKey.keys.searchKeyHeld); + assertEqualsJSON([false], downKey.keys.shiftKey); - assertEqualsJSON([false], downKey.keys.altGraphKey); - assertEqualsJSON([false], downKey.keys.altKey); - assertEqualsJSON([false], downKey.keys.ctrlKey); - assertEqualsJSON([false], downKey.keys.metaKey); - assertEqualsJSON([false], downKey.keys.searchKeyHeld); - assertEqualsJSON([false], downKey.keys.shiftKey); - - assertEquals(1, downKey.length()); -}); + assertEquals(1, downKey.length()); + }); /** Test another key sequence, this time with the modifier */ -TEST_F( +AX_TEST_F( 'ChromeVoxKeySequenceUnitTest', 'SimpleSequenceWithModifier', function() { const downKey = new KeySequence(this.downArrowEvent, true); @@ -201,7 +196,7 @@ /** Test a key sequence that includes the modifier */ -TEST_F('ChromeVoxKeySequenceUnitTest', 'ModifiedSequence', function() { +AX_TEST_F('ChromeVoxKeySequenceUnitTest', 'ModifiedSequence', function() { const cvoxDownKey = new KeySequence(this.altDownArrowEvent, true); assertEqualsJSON([KeyCode.DOWN], cvoxDownKey.keys.keyCode); @@ -225,7 +220,7 @@ * These should be equal because Ctrl should still function even with * sticky mode on. */ -TEST_F('ChromeVoxKeySequenceUnitTest', 'StickyEquality', function() { +AX_TEST_F('ChromeVoxKeySequenceUnitTest', 'StickyEquality', function() { const ctrlKey = new KeySequence(this.ctrlEvent, false); const ctrlSticky = new KeySequence(this.ctrlStickyEvent, false); @@ -238,7 +233,7 @@ * modifier. * These should not be equal because they do not have the same modifiers. */ -TEST_F('ChromeVoxKeySequenceUnitTest', 'ShiftEquality', function() { +AX_TEST_F('ChromeVoxKeySequenceUnitTest', 'ShiftEquality', function() { const aKey = new KeySequence(this.aEvent, false); const shiftA = new KeySequence(this.shiftAEvent, false); @@ -251,7 +246,7 @@ * on, 'a' with prefix key, and 'a' with ChromeVox modifier held down. These * should all be equal to each other. */ -TEST_F('ChromeVoxKeySequenceUnitTest', 'FourWayEquality', function() { +AX_TEST_F('ChromeVoxKeySequenceUnitTest', 'FourWayEquality', function() { const commandSequence = new KeySequence(this.aEvent, true); const stickySequence = new KeySequence(this.aEventSticky, false); const prefixSequence = new KeySequence(this.aEventPrefix, false); @@ -281,7 +276,7 @@ * modifier specified vs. 'a' key with ChromeVox modifier held down. * These should all be equal to each other.. */ -TEST_F('ChromeVoxKeySequenceUnitTest', 'ShiftPrefixEquality', function() { +AX_TEST_F('ChromeVoxKeySequenceUnitTest', 'ShiftPrefixEquality', function() { const shiftAWithModifier = new KeySequence(this.shiftAEvent, true); const shiftAWithPrefix = new KeySequence(this.shiftAPrefixEvent, false); const shiftASticky = new KeySequence(this.shiftAStickyEvent, false); @@ -309,7 +304,7 @@ * Test inequality - 'a' with modifier key vs. 'a' without modifier key. * These should not be equal. */ -TEST_F('ChromeVoxKeySequenceUnitTest', 'Inequality', function() { +AX_TEST_F('ChromeVoxKeySequenceUnitTest', 'Inequality', function() { const aNoModifier = new KeySequence(this.aEvent, false); const aWithModifier = new KeySequence(this.aEvent, true); @@ -321,7 +316,7 @@ /** * Test equality - adding an additional key onto a sequence. */ -TEST_F('ChromeVoxKeySequenceUnitTest', 'CvoxCtrl', function() { +AX_TEST_F('ChromeVoxKeySequenceUnitTest', 'CvoxCtrl', function() { const cvoxCtrlSequence = new KeySequence(this.ctrlEvent, true); assertTrue(cvoxCtrlSequence.addKeyEvent(this.rightArrowEvent)); @@ -350,7 +345,7 @@ /** * Test for inequality - key sequences in different orders. */ -TEST_F('ChromeVoxKeySequenceUnitTest', 'DifferentSequences', function() { +AX_TEST_F('ChromeVoxKeySequenceUnitTest', 'DifferentSequences', function() { const cvoxBSequence = new KeySequence(this.bEvent, true); assertTrue(cvoxBSequence.addKeyEvent(this.cEvent)); @@ -366,7 +361,7 @@ * Tests modifiers (ctrl, alt, etc) - if two sequences have different modifiers * held down then they aren't equal. */ -TEST_F('ChromeVoxKeySequenceUnitTest', 'MoreModifiers', function() { +AX_TEST_F('ChromeVoxKeySequenceUnitTest', 'MoreModifiers', function() { const ctrlASequence = new KeySequence(this.ctrlAEvent, false); const ctrlModifierKeyASequence = new KeySequence(this.ctrlAEvent, true); @@ -384,7 +379,7 @@ * Tests modifier (ctrl, alt, etc) order - if two sequences have the same * modifiers but held down in a different order then they aren't equal. */ -TEST_F('ChromeVoxKeySequenceUnitTest', 'ModifierOrder', function() { +AX_TEST_F('ChromeVoxKeySequenceUnitTest', 'ModifierOrder', function() { const ctrlShiftSequence = new KeySequence(this.ctrlShiftEvent, false); const shiftCtrlSequence = new KeySequence(this.shiftCtrlEvent, true); @@ -395,7 +390,7 @@ /** * Tests converting from a string to a KeySequence object. */ -TEST_F('ChromeVoxKeySequenceUnitTest', 'FromStr', function() { +AX_TEST_F('ChromeVoxKeySequenceUnitTest', 'FromStr', function() { const ctrlString = KeySequence.fromStr('Ctrl'); assertEqualsJSON(ctrlString.keys.ctrlKey, [true]); assertEqualsJSON(ctrlString.keys.keyCode, [KeyCode.CONTROL]); @@ -432,7 +427,7 @@ /** * Tests converting from a JSON string to a KeySequence object. */ -TEST_F('ChromeVoxKeySequenceUnitTest', 'Deserialize', function() { +AX_TEST_F('ChromeVoxKeySequenceUnitTest', 'Deserialize', function() { const forwardSequence = KeySequence.deserialize({ 'cvoxModifier': true, 'stickyMode': false, @@ -468,7 +463,7 @@ assertEqualsJSON(ctrlSequence.keys.keyCode, [KeyCode.CONTROL]); }); -TEST_F( +AX_TEST_F( 'ChromeVoxKeySequenceUnitTest', 'DeserializeAltShiftCvoxMod', function() { KeySequence.modKeyStr = 'Alt+Shift'; @@ -488,31 +483,34 @@ assertTrue(prevHeadingSeq.keys.shiftKey[0]); }); -TEST_F('ChromeVoxKeySequenceUnitTest', 'DeserializeSearchCvoxMod', function() { - // Test the case when we do want to strip modifiers when deserializing. This - // is important when the key sequence in the key map and the key sequence at - // runtime both contain the bare cvox modifier as a key code such as in the - // case of the Search sticky key and Search cvox modifier. Stripping happens - // by default for key events at runtime. - KeySequence.modKeyStr = 'Search'; +AX_TEST_F( + 'ChromeVoxKeySequenceUnitTest', 'DeserializeSearchCvoxMod', function() { + // Test the case when we do want to strip modifiers when deserializing. + // This is important when the key sequence in the key map and the key + // sequence at runtime both contain the bare cvox modifier as a key code + // such as in the case of the Search sticky key and Search cvox modifier. + // Stripping happens by default for key events at runtime. + KeySequence.modKeyStr = 'Search'; - // First, assert that unstripped seqs imply various modifier fields get set. - let stickySeq = KeySequence.deserialize({keys: {keyCode: [KeyCode.SEARCH]}}); - assertTrue(stickySeq.cvoxModifier); - assertTrue(stickySeq.keys.metaKey[0]); - assertTrue(stickySeq.keys.searchKeyHeld[0]); + // First, assert that unstripped seqs imply various modifier fields get + // set. + let stickySeq = + KeySequence.deserialize({keys: {keyCode: [KeyCode.SEARCH]}}); + assertTrue(stickySeq.cvoxModifier); + assertTrue(stickySeq.keys.metaKey[0]); + assertTrue(stickySeq.keys.searchKeyHeld[0]); - // Next, assert that stripping causes those modifiers to get unset. This is - // desirable at runtime so that we can match against the stripped runtime key - // seqs. - stickySeq = KeySequence.deserialize( - {'skipStripping': false, keys: {keyCode: [KeyCode.SEARCH]}}); - assertTrue(stickySeq.cvoxModifier); - assertFalse(stickySeq.keys.metaKey[0]); - assertFalse(stickySeq.keys.searchKeyHeld[0]); -}); + // Next, assert that stripping causes those modifiers to get unset. This + // is desirable at runtime so that we can match against the stripped + // runtime key seqs. + stickySeq = KeySequence.deserialize( + {'skipStripping': false, keys: {keyCode: [KeyCode.SEARCH]}}); + assertTrue(stickySeq.cvoxModifier); + assertFalse(stickySeq.keys.metaKey[0]); + assertFalse(stickySeq.keys.searchKeyHeld[0]); + }); -TEST_F('ChromeVoxKeySequenceUnitTest', 'RequireStickyMode', function() { +AX_TEST_F('ChromeVoxKeySequenceUnitTest', 'RequireStickyMode', function() { const oneFromMap = KeySequence.deserialize( {requireStickyMode: true, keys: {keyCode: [KeyCode.ONE]}});
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/common/spannable_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/common/spannable_test.js index 8455a9b..b0adced 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/common/spannable_test.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/common/spannable_test.js
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -GEN_INCLUDE(['../../common/testing/accessibility_test_base.js']); +GEN_INCLUDE(['../testing/chromevox_e2e_test_base.js']); UnserializableSpan = function() {}; @@ -57,7 +57,7 @@ /** * Test fixture. */ -ChromeVoxSpannableUnitTest = class extends AccessibilityTestBase { +ChromeVoxSpannableUnitTest = class extends ChromeVoxE2ETest { /** @override */ setUp() { super.setUp(); @@ -80,28 +80,20 @@ } }; - -/** @override */ -ChromeVoxSpannableUnitTest.prototype.extraLibraries = [ - '../../common/testing/assert_additions.js', - '../testing/fake_dom.js', -]; - - -TEST_F('ChromeVoxSpannableUnitTest', 'ToStringUnannotated', function() { +AX_TEST_F('ChromeVoxSpannableUnitTest', 'ToStringUnannotated', function() { assertEquals('', new Spannable().toString()); assertEquals('hello world', new Spannable('hello world').toString()); }); /** Tests that toString works correctly on annotated strings. */ -TEST_F('ChromeVoxSpannableUnitTest', 'ToStringAnnotated', function() { +AX_TEST_F('ChromeVoxSpannableUnitTest', 'ToStringAnnotated', function() { const spannable = new Spannable('Hello Google'); spannable.setSpan('http://www.google.com/', 6, 12); assertEquals('Hello Google', spannable.toString()); }); /** Tests the length calculation. */ -TEST_F('ChromeVoxSpannableUnitTest', 'LengthProperty', function() { +AX_TEST_F('ChromeVoxSpannableUnitTest', 'LengthProperty', function() { const spannable = new Spannable('Hello'); spannable.setSpan({}, 0, 3); assertEquals(5, spannable.length); @@ -112,7 +104,7 @@ }); /** Tests that a span can be added and retrieved at the beginning. */ -TEST_F('ChromeVoxSpannableUnitTest', 'SpanBeginning', function() { +AX_TEST_F('ChromeVoxSpannableUnitTest', 'SpanBeginning', function() { const annotation = {}; const spannable = new Spannable('Hello world'); spannable.setSpan(annotation, 0, 5); @@ -124,7 +116,7 @@ }); /** Tests that a span can be added and retrieved at the beginning. */ -TEST_F('ChromeVoxSpannableUnitTest', 'SpanEnd', function() { +AX_TEST_F('ChromeVoxSpannableUnitTest', 'SpanEnd', function() { const annotation = {}; const spannable = new Spannable('Hello world'); spannable.setSpan(annotation, 6, 11); @@ -136,7 +128,7 @@ }); /** Tests that a zero-length span is not retrieved. */ -TEST_F('ChromeVoxSpannableUnitTest', 'SpanZeroLength', function() { +AX_TEST_F('ChromeVoxSpannableUnitTest', 'SpanZeroLength', function() { const annotation = {}; const spannable = new Spannable('Hello world'); spannable.setSpan(annotation, 3, 3); @@ -147,7 +139,7 @@ }); /** Tests that a removed span is not returned. */ -TEST_F('ChromeVoxSpannableUnitTest', 'RemoveSpan', function() { +AX_TEST_F('ChromeVoxSpannableUnitTest', 'RemoveSpan', function() { const annotation = {}; const spannable = new Spannable('Hello world'); spannable.setSpan(annotation, 0, 3); @@ -158,7 +150,7 @@ }); /** Tests that adding a span in one place removes it from another. */ -TEST_F('ChromeVoxSpannableUnitTest', 'SetSpanMoves', function() { +AX_TEST_F('ChromeVoxSpannableUnitTest', 'SetSpanMoves', function() { const annotation = {}; const spannable = new Spannable('Hello world'); spannable.setSpan(annotation, 0, 3); @@ -170,7 +162,7 @@ }); /** Tests that setSpan objects to out-of-range arguments. */ -TEST_F('ChromeVoxSpannableUnitTest', 'SetSpanRangeError', function() { +AX_TEST_F('ChromeVoxSpannableUnitTest', 'SetSpanRangeError', function() { const spannable = new Spannable('Hello world'); // Start index out of range. @@ -193,7 +185,7 @@ * Tests that multiple spans can be retrieved at one point. * The first one added which applies should be returned by getSpan. */ -TEST_F('ChromeVoxSpannableUnitTest', 'MultipleSpans', function() { +AX_TEST_F('ChromeVoxSpannableUnitTest', 'MultipleSpans', function() { const annotation1 = {number: 1}; const annotation2 = {number: 2}; assertNotSame(annotation1, annotation2); @@ -209,7 +201,7 @@ }); /** Tests that appending appends the strings. */ -TEST_F('ChromeVoxSpannableUnitTest', 'AppendToString', function() { +AX_TEST_F('ChromeVoxSpannableUnitTest', 'AppendToString', function() { const spannable = new Spannable('Google'); assertEquals('Google', spannable.toString()); spannable.append(' Chrome'); @@ -221,7 +213,7 @@ /** * Tests that appending Spannables combines annotations. */ -TEST_F('ChromeVoxSpannableUnitTest', 'AppendAnnotations', function() { +AX_TEST_F('ChromeVoxSpannableUnitTest', 'AppendAnnotations', function() { const annotation1 = {number: 1}; const annotation2 = {number: 2}; assertNotSame(annotation1, annotation2); @@ -237,19 +229,20 @@ /** * Tests that a span's bounds can be retrieved. */ -TEST_F('ChromeVoxSpannableUnitTest', 'GetSpanStartAndEndAndLength', function() { - const annotation = {}; - const spannable = new Spannable('potato wedges'); - spannable.setSpan(annotation, 8, 12); - assertEquals(8, spannable.getSpanStart(annotation)); - assertEquals(12, spannable.getSpanEnd(annotation)); - assertEquals(4, spannable.getSpanLength(annotation)); -}); +AX_TEST_F( + 'ChromeVoxSpannableUnitTest', 'GetSpanStartAndEndAndLength', function() { + const annotation = {}; + const spannable = new Spannable('potato wedges'); + spannable.setSpan(annotation, 8, 12); + assertEquals(8, spannable.getSpanStart(annotation)); + assertEquals(12, spannable.getSpanEnd(annotation)); + assertEquals(4, spannable.getSpanLength(annotation)); + }); /** * Tests that an absent span's bounds are reported correctly. */ -TEST_F( +AX_TEST_F( 'ChromeVoxSpannableUnitTest', 'GetSpanStartAndEndAndLengthAbsent', function() { const annotation = {}; @@ -260,7 +253,7 @@ /** * Test that a zero length span can still be found. */ -TEST_F( +AX_TEST_F( 'ChromeVoxSpannableUnitTest', 'GetSpanStartAndEndAndLengthZeroLength', function() { const annotation = {}; @@ -275,21 +268,22 @@ * Tests that == (but not ===) objects are treated distinctly when getting * span bounds. */ -TEST_F('ChromeVoxSpannableUnitTest', 'GetSpanStartAndEndEquality', function() { - // Note that 0 == '' and '' == 0 in JavaScript. - const spannable = new Spannable('wat'); - spannable.setSpan(0, 0, 0); - spannable.setSpan('', 1, 3); - assertEquals(0, spannable.getSpanStart(0)); - assertEquals(0, spannable.getSpanEnd(0)); - assertEquals(1, spannable.getSpanStart('')); - assertEquals(3, spannable.getSpanEnd('')); -}); +AX_TEST_F( + 'ChromeVoxSpannableUnitTest', 'GetSpanStartAndEndEquality', function() { + // Note that 0 == '' and '' == 0 in JavaScript. + const spannable = new Spannable('wat'); + spannable.setSpan(0, 0, 0); + spannable.setSpan('', 1, 3); + assertEquals(0, spannable.getSpanStart(0)); + assertEquals(0, spannable.getSpanEnd(0)); + assertEquals(1, spannable.getSpanStart('')); + assertEquals(3, spannable.getSpanEnd('')); + }); /** * Tests that substrings have the correct character sequence. */ -TEST_F('ChromeVoxSpannableUnitTest', 'Substring', function() { +AX_TEST_F('ChromeVoxSpannableUnitTest', 'Substring', function() { const assertSubstringResult = function(expected, initial, start, opt_end) { const spannable = new Spannable(initial); const substring = spannable.substring(start, opt_end); @@ -304,7 +298,7 @@ /** * Tests that substring arguments are validated properly. */ -TEST_F('ChromeVoxSpannableUnitTest', 'SubstringRangeError', function() { +AX_TEST_F('ChromeVoxSpannableUnitTest', 'SubstringRangeError', function() { const assertRangeError = function(initial, start, opt_end) { const spannable = new Spannable(initial); assertException('expected range error', function() { @@ -319,7 +313,7 @@ /** * Tests that spans in the substring range are preserved. */ -TEST_F('ChromeVoxSpannableUnitTest', 'SubstringSpansIncluded', function() { +AX_TEST_F('ChromeVoxSpannableUnitTest', 'SubstringSpansIncluded', function() { const assertSpanIncluded = function( expectedSpanStart, expectedSpanEnd, initial, initialSpanStart, initialSpanEnd, start, opt_end) { @@ -353,7 +347,7 @@ * Tests that spans outside the range are omitted. * It's fine to keep zero-length spans at the ends, though. */ -TEST_F('ChromeVoxSpannableUnitTest', 'SubstringSpansExcluded', function() { +AX_TEST_F('ChromeVoxSpannableUnitTest', 'SubstringSpansExcluded', function() { const assertSpanExcluded = function( initial, spanStart, spanEnd, start, opt_end) { const annotation = {}; @@ -371,7 +365,7 @@ /** * Tests that spans which cross the boundary are clipped. */ -TEST_F('ChromeVoxSpannableUnitTest', 'SubstringSpansClipped', function() { +AX_TEST_F('ChromeVoxSpannableUnitTest', 'SubstringSpansClipped', function() { const assertSpanIncluded = function( expectedSpanStart, expectedSpanEnd, initial, initialSpanStart, initialSpanEnd, start, opt_end) { @@ -394,7 +388,7 @@ /** * Tests that whitespace is trimmed. */ -TEST_F('ChromeVoxSpannableUnitTest', 'Trim', function() { +AX_TEST_F('ChromeVoxSpannableUnitTest', 'Trim', function() { const assertTrimResult = function(expected, initial) { assertEquals(expected, new Spannable(initial).trim().toString()); }; @@ -409,7 +403,7 @@ /** * Tests that trim keeps, drops and clips spans. */ -TEST_F('ChromeVoxSpannableUnitTest', 'TrimSpans', function() { +AX_TEST_F('ChromeVoxSpannableUnitTest', 'TrimSpans', function() { const spannable = new Spannable(' \t Kennedy\n'); spannable.setSpan('tab', 1, 2); spannable.setSpan('jfk', 3, 10); @@ -425,7 +419,7 @@ /** * Tests that when a string is all whitespace, we trim off the *end*. */ -TEST_F('ChromeVoxSpannableUnitTest', 'TrimAllWhitespace', function() { +AX_TEST_F('ChromeVoxSpannableUnitTest', 'TrimAllWhitespace', function() { const spannable = new Spannable(' '); spannable.setSpan('cursor 1', 0, 0); spannable.setSpan('cursor 2', 2, 2); @@ -438,7 +432,7 @@ /** * Tests finding a span which is an instance of a given class. */ -TEST_F('ChromeVoxSpannableUnitTest', 'GetSpanInstanceOf', function() { +AX_TEST_F('ChromeVoxSpannableUnitTest', 'GetSpanInstanceOf', function() { function ExampleConstructorBase() {} function ExampleConstructor1() {} function ExampleConstructor2() {} @@ -458,7 +452,7 @@ }); /** Tests trimming only left or right. */ -TEST_F('ChromeVoxSpannableUnitTest', 'TrimLeftOrRight', function() { +AX_TEST_F('ChromeVoxSpannableUnitTest', 'TrimLeftOrRight', function() { const spannable = new Spannable(' '); spannable.setSpan('cursor 1', 0, 0); spannable.setSpan('cursor 2', 2, 2); @@ -494,7 +488,7 @@ assertEquals(0, trimmed3.getSpanEnd('cursor 2')); }); -TEST_F('ChromeVoxSpannableUnitTest', 'Serialize', function() { +AX_TEST_F('ChromeVoxSpannableUnitTest', 'Serialize', function() { const fresh = new Spannable('text'); const freshStatelessSerializable = new StatelessSerializableSpan(); const freshNonStatelessSerializable = new NonStatelessSerializableSpan(14); @@ -518,7 +512,7 @@ freshNonStatelessSerializable, thawnNonStatelessSerializable); }); -TEST_F('ChromeVoxSpannableUnitTest', 'GetSpanIntervals', function() { +AX_TEST_F('ChromeVoxSpannableUnitTest', 'GetSpanIntervals', function() { function Foo() {} function Bar() {} const ms = new MultiSpannable('f12b45f78b01');
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/testing/mock_feedback_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/testing/mock_feedback_test.js index 01ab883..3c99b0a 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/testing/mock_feedback_test.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/testing/mock_feedback_test.js
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -GEN_INCLUDE(['../../common/testing/accessibility_test_base.js']); +GEN_INCLUDE(['chromevox_e2e_test_base.js']); function speak(text, opt_properties) { ChromeVox.tts.speak(text, 0, opt_properties); @@ -21,7 +21,7 @@ /** * Test fixture. */ -MockFeedbackUnitTest = class extends AccessibilityTestBase { +MockFeedbackUnitTest = class extends ChromeVoxE2ETest { constructor() { super(); this.expectedCalls = []; @@ -41,13 +41,7 @@ } }; -MockFeedbackUnitTest.prototype.extraLibraries = [ - '../../common/testing/assert_additions.js', - '../testing/fake_dom.js', // Must come before other files - 'mock_feedback.js', -]; - -TEST_F('MockFeedbackUnitTest', 'speechAndCallbacks', function() { +AX_TEST_F('MockFeedbackUnitTest', 'speechAndCallbacks', function() { let afterThirdStringCalled = false; let spruiousStringEndCallbackCalled = false; let finishCalled = false; @@ -81,7 +75,7 @@ assertTrue(finishCalled); }); -TEST_F('MockFeedbackUnitTest', 'startAndEndCallbacks', function() { +AX_TEST_F('MockFeedbackUnitTest', 'startAndEndCallbacks', function() { let onlyStartCallbackCalled = false; let onlyEndCallbackCalled = false; let bothCallbacksStartCalled = false; @@ -122,7 +116,7 @@ assertTrue(bothCallbacksEndCalled); }); -TEST_F('MockFeedbackUnitTest', 'SpeechAndBraille', function() { +AX_TEST_F('MockFeedbackUnitTest', 'SpeechAndBraille', function() { let secondCallbackCalled = false; let finishCalled = false; const mock = new MockFeedback(function() { @@ -149,7 +143,7 @@ assertTrue(finishCalled); }); -TEST_F('MockFeedbackUnitTest', 'expectWithRegex', function() { +AX_TEST_F('MockFeedbackUnitTest', 'expectWithRegex', function() { let done = false; const mock = new MockFeedback(); mock.install(); @@ -164,7 +158,7 @@ assertTrue(done); }); -TEST_F('MockFeedbackUnitTest', 'expectAfterReplayThrows', function() { +AX_TEST_F('MockFeedbackUnitTest', 'expectAfterReplayThrows', function() { const mock = new MockFeedback(); mock.replay(); assertException('', function() { @@ -172,7 +166,7 @@ }, 'AssertionError'); }); -TEST_F('MockFeedbackUnitTest', 'NoMatchDoesNotFinish', function() { +AX_TEST_F('MockFeedbackUnitTest', 'NoMatchDoesNotFinish', function() { let firstCallbackCalled = false; const mock = new MockFeedback(function() { throw Error('Should not be called'); @@ -191,7 +185,7 @@ assertTrue(firstCallbackCalled); }); -TEST_F('MockFeedbackUnitTest', 'SpeechAndEarcons', function() { +AX_TEST_F('MockFeedbackUnitTest', 'SpeechAndEarcons', function() { let finishCalled = false; const mock = new MockFeedback(function() { finishCalled = true; @@ -221,7 +215,7 @@ assertTrue(finishCalled); }); -TEST_F('MockFeedbackUnitTest', 'SpeechWithLanguage', function() { +AX_TEST_F('MockFeedbackUnitTest', 'SpeechWithLanguage', function() { let finishCalled = false; const mock = new MockFeedback(function() { finishCalled = true;
diff --git a/chrome/browser/resources/chromeos/accessibility/common/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/common/BUILD.gn index f250ad6..7356850f 100644 --- a/chrome/browser/resources/chromeos/accessibility/common/BUILD.gn +++ b/chrome/browser/resources/chromeos/accessibility/common/BUILD.gn
@@ -15,6 +15,7 @@ accessibility_common_out_dir = "$root_out_dir/resources/chromeos/accessibility/common" +tsc_preprocess_folder = "$root_gen_dir/chrome/browser/resources/chromeos/accessibility/tsc_preprocessed" tsc_out_dir = "$target_gen_dir/tsc" group("build") { @@ -24,6 +25,29 @@ ] } +js_sources = [ + "async_util.js", + "automation_predicate.js", + "browser_util.js", + "constants.js", + "cursors/cursor.js", + "cursors/range.js", + "cursors/recovery_strategy.js", + "event_generator.js", + "event_handler.js", + "gdocs_script.js", + "key_code.js", + "local_storage.js", + "node_navigation_utils.js", + "node_utils.js", + "rect_util.js", + "repeated_event_handler.js", + "repeated_tree_change_handler.js", + "sentence_utils.js", + "testing/accessibility_test_base.js", + "testing/test_node_generator.js", +] + # Add typescript files to compile here. ts_modules = [ "array_util.ts", @@ -38,55 +62,50 @@ "string_util.ts", ] +ts_definitions = [ + "../definitions/automation.d.ts", + "../definitions/command_line_private.d.ts", + "../definitions/extensions.d.ts", + "../definitions/extension_types.d.ts", + "../definitions/i18n.d.ts", + "../definitions/runtime.d.ts", + "../definitions/settings_private_mv2.d.ts", + "../definitions/tabs.d.ts", + "../definitions/tts.d.ts", + "//tools/typescript/definitions/windows.d.ts", +] + +# Generated TS definition files. +generated_ts_definitions = + [ "$tsc_preprocess_folder/definitions/chrome_event.d.ts" ] + ts_library("ts_build") { - in_files = ts_modules + root_dir = "$tsc_preprocess_folder" out_dir = tsc_out_dir - definitions = [ - "../definitions/automation.d.ts", - "../definitions/command_line_private.d.ts", - "../definitions/extensions.d.ts", - "../definitions/extension_types.d.ts", - "../definitions/i18n.d.ts", - "../definitions/runtime.d.ts", - "../definitions/settings_private_mv2.d.ts", - "../definitions/tabs.d.ts", - "../definitions/tts.d.ts", - "//tools/typescript/definitions/windows.d.ts", - ] + definitions = ts_definitions + generated_ts_definitions + + in_files = [] + foreach(_ts_file, ts_modules) { + in_files += [ "common/" + _ts_file ] + } tsconfig_base = "../tsconfig.base.json" + + extra_deps = [ + ":preprocess_files_for_ts_build", + "..:preprocess_files_for_ts_build", + ] } run_jsbundler("copied_files") { mode = "copy" dest_dir = accessibility_common_out_dir deps = [ ":ts_build" ] - sources = [ - "async_util.js", - "automation_predicate.js", - "browser_util.js", - "constants.js", - "cursors/cursor.js", - "cursors/range.js", - "cursors/recovery_strategy.js", - "event_generator.js", - "event_handler.js", - "gdocs_script.js", - "key_code.js", - "local_storage.js", - "node_navigation_utils.js", - "node_utils.js", - "rect_util.js", - "repeated_event_handler.js", - "repeated_tree_change_handler.js", - "sentence_utils.js", - "testing/accessibility_test_base.js", - "testing/test_node_generator.js", - ] - sources += filter_include(get_target_outputs(":ts_build"), [ "*.js" ]) + sources = + js_sources + filter_include(get_target_outputs(":ts_build"), [ "*.js" ]) rewrite_rules = [ - rebase_path(tsc_out_dir, root_build_dir) + ":", + rebase_path("$tsc_out_dir/common", root_build_dir) + ":", rebase_path(".", root_build_dir) + ":", ] } @@ -160,3 +179,11 @@ } defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ] } + +# Copy all JS and TS sources to a preprocess folder. All generated TS/JS files +# will also be copied into this folder, which will allow us to support a TS +# build that uses both checked-in and generated files. +copy("preprocess_files_for_ts_build") { + sources = js_sources + ts_modules + outputs = [ "$tsc_preprocess_folder/common/{{source_target_relative}}" ] +}
diff --git a/chrome/browser/resources/chromeos/accessibility/common/chrome_event_handler.ts b/chrome/browser/resources/chromeos/accessibility/common/chrome_event_handler.ts index d6bafd5d..151182b 100644 --- a/chrome/browser/resources/chromeos/accessibility/common/chrome_event_handler.ts +++ b/chrome/browser/resources/chromeos/accessibility/common/chrome_event_handler.ts
@@ -2,7 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import {ChromeEvent} from '../../../../../../tools/typescript/definitions/chrome_event.js'; +// Note: This definition file is generated at build time. +import {ChromeEvent} from '../definitions/chrome_event.js'; type GenericListener<T extends any[]> = (...args: T) => void;
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/switch_access/BUILD.gn index eca39a4..a96cacc 100644 --- a/chrome/browser/resources/chromeos/accessibility/switch_access/BUILD.gn +++ b/chrome/browser/resources/chromeos/accessibility/switch_access/BUILD.gn
@@ -18,7 +18,10 @@ tsc_out_dir = "$target_gen_dir/tsc" # TS files to compile. -ts_modules = [ "commands.ts" ] +ts_modules = [ + "commands.ts", + "navigator_interfaces.ts", +] # JS files needed to compile TS. js_deps = [] @@ -100,7 +103,6 @@ "menu_manager.js", "metrics.js", "navigator.js", - "navigator_interfaces.js", "nodes/back_button_node.js", "nodes/basic_node.js", "nodes/combo_box_node.js",
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/navigator_interfaces.js b/chrome/browser/resources/chromeos/accessibility/switch_access/navigator_interfaces.js deleted file mode 100644 index 71db4e3..0000000 --- a/chrome/browser/resources/chromeos/accessibility/switch_access/navigator_interfaces.js +++ /dev/null
@@ -1,166 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import {constants} from '../common/constants.js'; - -import {SAChildNode, SANode, SARootNode} from './nodes/switch_access_node.js'; - -const AutomationNode = chrome.automation.AutomationNode; -const MenuAction = chrome.accessibilityPrivate.SwitchAccessMenuAction; - -/** @abstract */ -export class ItemNavigatorInterface { - /** - * @param {!SAChildNode} node - * @return {boolean} - * @abstract - */ - currentGroupHasChild(node) {} - - /** - * Enters |this.node_|. - * @abstract - */ - enterGroup() {} - - /** - * Puts focus on the virtual keyboard, if the current node is a text input. - * @abstract - */ - enterKeyboard() {} - - /** - * Unconditionally exits the current group. - * @abstract - */ - exitGroupUnconditionally() {} - - /** - * Exits the specified node, if it is the currently focused group. - * @param {?AutomationNode|SANode} node - * @abstract - */ - exitIfInGroup(node) {} - - /** - * @return {!Promise} - * @abstract - */ - async exitKeyboard() {} - - /** - * Forces the current node to be |node|. - * Should only be called by subclasses of SARootNode and - * only when they are focused. - * @param {!SAChildNode} node - * @abstract - */ - forceFocusedNode(node) {} - - /** - * Returns the current Switch Access tree, for debugging purposes. - * @param {boolean} wholeTree Whether to print the whole tree, or just the - * current focus. - * @return {!SARootNode} - * @abstract - */ - getTreeForDebugging(wholeTree) {} - - /** - * Jumps to a specific automation node. Maintains the history when navigating. - * @param {AutomationNode} automationNode - * @abstract - */ - jumpTo(automationNode) {} - - /** - * Move to the previous interesting node. - * @abstract - */ - moveBackward() {} - - /** - * Move to the next interesting node. - * @abstract - */ - moveForward() {} - - /** - * Tries to move to another node, |node|, but if |node| is a window that's not - * in the foreground it will use |getNext| to find the next node to try. - * Checks against |startingNode| to ensure we don't get stuck in an infinite - * loop. - * @param {!SAChildNode} node The node to try to move into. - * @param {function(!SAChildNode): !SAChildNode} getNext gets the next node to - * try if we cannot move to |next|. Takes |next| as a parameter. - * @param {!SAChildNode} startingNode The first node in the sequence. If we - * loop back to this node, stop trying to move, as there are no other - * nodes we can move to. - * @return {!Promise} - * @abstract - */ - async tryMoving(node, getNext, startingNode) {} - - /** - * Moves to the Switch Access focus up the group stack closest to the ancestor - * that hasn't been invalidated. - * @abstract - */ - moveToValidNode() {} - - /** - * Restarts item scanning from the last point chosen by point scanning. - * @abstract - */ - restart() {} - - /** - * Restores the suspended group and focus, if there is one. - * @abstract - */ - restoreSuspendedGroup() {} - - /** - * Saves the current focus and group, and then exits the group. - * @abstract - */ - suspendCurrentGroup() {} - - // =============== Getter Methods ============== - - /** - * Returns the currently focused node. - * @return {!SAChildNode} - * @abstract - */ - get currentNode() {} - - /** - * Returns the desktop automation node object. - * @return {!AutomationNode} - * @abstract - */ - get desktopNode() {} -} - -/** @abstract */ -export class PointNavigatorInterface { - /** - * Returns the current point scan point. - * @return {!constants.Point} - */ - get currentPoint() {} - - /** Starts point scanning. */ - start() {} - - /** Stops point scanning. */ - stop() {} - - /** - * Performs a mouse action at the currentPoint(). - * @param {MenuAction} action - */ - performMouseAction(action) {} -}
diff --git a/chrome/browser/resources/chromeos/accessibility/switch_access/navigator_interfaces.ts b/chrome/browser/resources/chromeos/accessibility/switch_access/navigator_interfaces.ts new file mode 100644 index 0000000..d5d6398 --- /dev/null +++ b/chrome/browser/resources/chromeos/accessibility/switch_access/navigator_interfaces.ts
@@ -0,0 +1,110 @@ +// Copyright 2021 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import {constants} from '../common/constants.js'; + +import {SAChildNode, SANode, SARootNode} from './nodes/switch_access_node.js'; + +import MenuAction = chrome.accessibilityPrivate.SwitchAccessMenuAction; +type AutomationNode = chrome.automation.AutomationNode; +type Point = constants.Point; + +export abstract class ItemNavigatorInterface { + abstract currentGroupHasChild(node: SAChildNode): boolean; + + /** Enters |this.node_|. */ + abstract enterGroup(): void; + + /** + * Puts focus on the virtual keyboard, if the current node is a text input. + */ + abstract enterKeyboard(): void; + + /** Unconditionally exits the current group. */ + abstract exitGroupUnconditionally(): void; + + /** Exits the specified node, if it is the currently focused group. */ + abstract exitIfInGroup(node: (AutomationNode|SANode|null)): void; + + abstract exitKeyboard(): Promise<void>; + + /** + * Forces the current node to be |node|. + * Should only be called by subclasses of SARootNode and + * only when they are focused. + */ + abstract forceFocusedNode(node: SAChildNode): void; + + /** + * Returns the current Switch Access tree, for debugging purposes. + * @param wholeTree Whether to print the whole tree, or just the + * current focus. + */ + abstract getTreeForDebugging(wholeTree: boolean): SARootNode; + + /** + * Jumps to a specific automation node. Maintains the history when + * navigating. + */ + abstract jumpTo(automationNode: AutomationNode): void; + + /** Move to the previous interesting node. */ + abstract moveBackward(): void; + + /** Move to the next interesting node. */ + abstract moveForward(): void; + + /** + * Tries to move to another node, |node|, but if |node| is a window that's not + * in the foreground it will use |getNext| to find the next node to try. + * Checks against |startingNode| to ensure we don't get stuck in an infinite + * loop. + * @param node The node to try to move into. + * @param getNext gets the next node to + * try if we cannot move to |next|. Takes |next| as a parameter. + * @param startingNode The first node in the sequence. If we + * loop back to this node, stop trying to move, as there are no other + * nodes we can move to. + */ + abstract tryMoving( + _node: SAChildNode, _getNext: (node: SAChildNode) => SAChildNode, + _startingNode: SAChildNode): Promise<void>; + + /** + * Moves to the Switch Access focus up the group stack closest to the ancestor + * that hasn't been invalidated. + */ + abstract moveToValidNode(): void; + + /** Restarts item scanning from the last point chosen by point scanning. */ + abstract restart(): void; + + /** Restores the suspended group and focus, if there is one. */ + abstract restoreSuspendedGroup(): void; + + /** Saves the current focus and group, and then exits the group. */ + abstract suspendCurrentGroup(): void; + + // =============== Getter Methods ============== + + /** Returns the currently focused node. */ + abstract get currentNode(): SAChildNode; + + /** Returns the desktop automation node object. */ + abstract get desktopNode(): AutomationNode; +} + +export abstract class PointNavigatorInterface { + /** Returns the current point scan point. */ + abstract get currentPoint(): Point; + + /** Starts point scanning. */ + abstract start(): void; + + /** Stops point scanning. */ + abstract stop(): void; + + /** Performs a mouse action at the currentPoint(). */ + abstract performMouseAction(action: MenuAction): void; +}
diff --git a/chrome/browser/resources/chromeos/internet_config_dialog/BUILD.gn b/chrome/browser/resources/chromeos/internet_config_dialog/BUILD.gn index a656ae8..b2ea9856 100644 --- a/chrome/browser/resources/chromeos/internet_config_dialog/BUILD.gn +++ b/chrome/browser/resources/chromeos/internet_config_dialog/BUILD.gn
@@ -2,109 +2,36 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import("//chrome/common/features.gni") -import("//third_party/closure_compiler/compile_js.gni") -import("//tools/grit/grit_rule.gni") -import("//tools/grit/preprocess_if_expr.gni") -import("//tools/polymer/html_to_js.gni") -import("//ui/webui/resources/tools/generate_grd.gni") -import("//ui/webui/resources/tools/optimize_webui.gni") +import("//ui/webui/resources/tools/build_webui.gni") -preprocess_folder = "preprocessed" -preprocess_gen_manifest = "preprocessed_gen_manifest.json" +build_webui("build") { + static_files = [ "internet_config_dialog_container.html" ] -if (optimize_webui) { - build_manifest = "build_manifest.json" + # Files holding a Polymer element definition AND have an equivalent .html file. + web_component_files = [ "internet_config_dialog.ts" ] - optimize_webui("build") { - host = "internet-config-dialog" - js_module_in_files = [ "internet_config_dialog.js" ] - input = rebase_path("$target_gen_dir/$preprocess_folder", root_build_dir) - out_manifest = "$target_gen_dir/$build_manifest" - excludes = [ + ts_definitions = [ "//tools/typescript/definitions/chrome_send.d.ts" ] + + ts_deps = [ + "//ash/webui/common/resources:build_ts", + "//third_party/polymer/v3_0:library", + "//ui/webui/resources/cr_components/color_change_listener:build_ts", + "//ui/webui/resources/cr_elements:build_ts", + "//ui/webui/resources/js:build_ts", + "//ui/webui/resources/mojo:build_ts", + ] + + optimize = optimize_webui + if (optimize) { + optimize_webui_host = "internet-config-dialog" + optimize_webui_in_files = [ "internet_config_dialog.js" ] + optimize_webui_excludes = [ "chrome://resources/mojo/chromeos/services/network_config/public/mojom/cros_network_config.mojom-webui.js", "chrome://resources/mojo/chromeos/services/network_config/public/mojom/network_types.mojom-webui.js", "chrome://resources/mojo/services/network/public/mojom/ip_address.mojom-webui.js", "chrome://resources/ash/common/hotspot/cros_hotspot_config.mojom-webui.js", ] - - deps = [ - ":preprocess_generated", - "//ash/webui/common/resources:css_wrapper_files", - "//ash/webui/common/resources:html_wrapper_files", - "//ash/webui/common/resources:preprocess", - "//ui/webui/resources/cr_components/color_change_listener:build_ts", - "//ui/webui/resources/cr_elements:build_ts", - ] } -} -generate_grd("build_grd") { - input_files = [ "internet_config_dialog_container.html" ] - input_files_base_dir = rebase_path(".", "//") - if (optimize_webui) { - deps = [ ":build" ] - resource_path_rewrites = - [ "internet_config_dialog.rollup.js|internet_config_dialog.js" ] - manifest_files = [ "$target_gen_dir/$build_manifest" ] - } else { - deps = [ ":preprocess_generated" ] - manifest_files = [ "$target_gen_dir/$preprocess_gen_manifest" ] - } grd_prefix = "internet_config_dialog" - out_grd = "$target_gen_dir/${grd_prefix}_resources.grd" -} - -preprocess_if_expr("preprocess_generated") { - deps = [ ":web_components" ] - in_folder = target_gen_dir - out_folder = "$target_gen_dir/$preprocess_folder" - out_manifest = "$target_gen_dir/$preprocess_gen_manifest" - in_files = [ "internet_config_dialog.js" ] -} - -js_type_check("closure_compile") { - is_polymer3 = true - closure_flags = default_closure_args + mojom_js_args - deps = [ ":internet_config_dialog" ] -} - -js_library("internet_config_dialog") { - deps = [ - "//ash/webui/common/resources:assert", - "//ash/webui/common/resources:i18n_behavior", - "//ash/webui/common/resources/network:cr_policy_network_behavior_mojo", - "//ash/webui/common/resources/network:network_config", - "//ash/webui/common/resources/network:onc_mojo", - ] - - externs_list = [ - # TODO(crbug/1081815): Use autogenerated files instead of chrome_extensions. - "$externs_path/chrome_extensions.js", - "$externs_path/chrome_send.js", - "$externs_path/networking_private.js", - "//ui/webui/resources/cr_elements/cr_dialog/cr_dialog_externs.js", - ] - extra_sources = [ "$interfaces_path/networking_private_interface.js" ] -} - -html_to_js("web_components") { - js_files = [ "internet_config_dialog.js" ] -} - -grit("resources") { - defines = chrome_grit_defines - - # These arguments are needed since the grd is generated at build time. - enable_input_discovery_for_gn_analyze = false - source = "$target_gen_dir/internet_config_dialog_resources.grd" - deps = [ ":build_grd" ] - - outputs = [ - "grit/internet_config_dialog_resources.h", - "grit/internet_config_dialog_resources_map.cc", - "grit/internet_config_dialog_resources_map.h", - "internet_config_dialog_resources.pak", - ] - output_dir = "$root_gen_dir/chrome" }
diff --git a/chrome/browser/resources/chromeos/internet_config_dialog/internet_config_dialog.js b/chrome/browser/resources/chromeos/internet_config_dialog/internet_config_dialog.ts similarity index 75% rename from chrome/browser/resources/chromeos/internet_config_dialog/internet_config_dialog.js rename to chrome/browser/resources/chromeos/internet_config_dialog/internet_config_dialog.ts index 521f7e9..43f1634b 100644 --- a/chrome/browser/resources/chromeos/internet_config_dialog/internet_config_dialog.js +++ b/chrome/browser/resources/chromeos/internet_config_dialog/internet_config_dialog.ts
@@ -12,11 +12,15 @@ import 'chrome://resources/cr_elements/cr_shared_style.css.js'; import './strings.m.js'; -import {assert} from 'chrome://resources/ash/common/assert.js'; -import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/ash/common/i18n_behavior.js'; import {loadTimeData} from 'chrome://resources/ash/common/load_time_data.m.js'; +import {NetworkConfigElement} from 'chrome://resources/ash/common/network/network_config.js'; import {ColorChangeUpdater} from 'chrome://resources/cr_components/color_change_listener/colors_css_updater.js'; -import {html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js'; +import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js'; +import {assert} from 'chrome://resources/js/assert.js'; +import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; + +import {getTemplate} from './internet_config_dialog.html.js'; /** * @fileoverview @@ -25,28 +29,27 @@ * new network from the system tray). */ -/** - * @constructor - * @extends {PolymerElement} - * @implements {I18nBehaviorInterface} - */ -const InternetConfigDialogElementBase = - mixinBehaviors([I18nBehavior], PolymerElement); +export interface InternetConfigDialogElement { + $: { + networkConfig: NetworkConfigElement, + dialog: CrDialogElement, + }; +} -/** @polymer */ +const InternetConfigDialogElementBase = I18nMixin(PolymerElement); + export class InternetConfigDialogElement extends InternetConfigDialogElementBase { static get is() { - return 'internet-config-dialog'; + return 'internet-config-dialog' as const; } static get template() { - return html`{__html_template__}`; + return getTemplate(); } static get properties() { return { - /** @private */ shareAllowEnable_: { type: Boolean, value() { @@ -54,7 +57,6 @@ }, }, - /** @private */ shareDefault_: { type: Boolean, value() { @@ -64,23 +66,19 @@ /** * The network GUID to configure, or empty when configuring a new network. - * @private */ guid_: String, /** * The type of network to be configured as a string. May be set initially * or updated by network-config. - * @private */ type_: String, - /** @private */ enableConnect_: Boolean, /** * Set by network-config when a configuration error occurs. - * @private */ error_: { type: String, @@ -89,8 +87,14 @@ }; } - /** @override */ - connectedCallback() { + private shareAllowEnable_: boolean; + private shareDefault_: boolean; + private guid_: string; + private type_: string; + private enableConnect_: boolean; + private error_: string; + + override connectedCallback() { super.connectedCallback(); const isJellyEnabled = loadTimeData.valueExists('isJellyEnabled') && @@ -115,7 +119,6 @@ document.head.appendChild(link); document.body.classList.add('jelly-enabled'); - /** @suppress {checkTypes} */ (function() { ColorChangeUpdater.forDocument().start(); })(); @@ -123,41 +126,30 @@ this.$.networkConfig.init(); - /** @type {!CrDialogElement} */ (this.$.dialog).showModal(); + this.$.dialog.showModal(); } - /** @private */ - close_() { + private close_(): void { chrome.send('dialogClose'); } - /** - * @return {string} - * @private - */ - getDialogTitle_() { + private getDialogTitle_(): string { const type = this.i18n('OncType' + this.type_); return this.i18n('internetJoinType', type); } - /** - * @return {string} - * @private - */ - getError_() { + private getError_(): string { if (this.i18nExists(this.error_)) { return this.i18n(this.error_); } return this.i18n('networkErrorUnknown'); } - /** @private */ - onCancelClick_() { + private onCancelClick_(): void { this.close_(); } - /** @private */ - onConnectClick_() { + private onConnectClick_(): void { this.$.networkConfig.connect(); } }
diff --git a/chrome/browser/resources/compose/app.html b/chrome/browser/resources/compose/app.html index d346ad6..75f1fb7 100644 --- a/chrome/browser/resources/compose/app.html +++ b/chrome/browser/resources/compose/app.html
@@ -432,7 +432,8 @@ <select class="md-select" id="lengthMenu" value="[[selectedLength_]]" aria-label="$i18n{lengthMenuTitle}" on-change="onLengthChanged_"> <template is="dom-repeat" items="[[lengthOptions_]]"> - <option value="[[item.value]]" hidden$="[[item.hidden]]"> + <option value="[[item.value]]" disabled$="[[item.isDefault]]" + selected$="[[item.isDefault]]"> [[item.label]] </option> </template> @@ -440,7 +441,8 @@ <select class="md-select" id="toneMenu" value="[[selectedTone_]]" aria-label="$i18n{toneMenuTitle}" on-change="onToneChanged_"> <template is="dom-repeat" items="[[toneOptions_]]"> - <option value="[[item.value]]" hidden$="[[item.hidden]]"> + <option value="[[item.value]]" disabled$="[[item.isDefault]]" + selected$="[[item.isDefault]]"> [[item.label]] </option> </template>
diff --git a/chrome/browser/resources/compose/app.ts b/chrome/browser/resources/compose/app.ts index f6b8aba..34ddd776 100644 --- a/chrome/browser/resources/compose/app.ts +++ b/chrome/browser/resources/compose/app.ts
@@ -149,7 +149,7 @@ { value: Length.kUnset, label: loadTimeData.getString('lengthMenuTitle'), - hidden: true, + isDefault: true, }, { value: Length.kShorter, @@ -169,7 +169,7 @@ { value: Tone.kUnset, label: loadTimeData.getString('toneMenuTitle'), - hidden: true, + isDefault: true, }, { value: Tone.kCasual,
diff --git a/chrome/browser/resources/password_manager/password_manager_app.html b/chrome/browser/resources/password_manager/password_manager_app.html index d9a935f..e1928d8 100644 --- a/chrome/browser/resources/password_manager/password_manager_app.html +++ b/chrome/browser/resources/password_manager/password_manager_app.html
@@ -48,11 +48,11 @@ padding-bottom: 28px; } - /* The breakpoint of 1200px was decided on by the rounded sum of sidebar + /* The breakpoint of 980px was decided on by the rounded sum of sidebar * width, search bar width and help button width with very large font. Smaller * value will force overlapping of search bar and page tittle. */ - @media (max-width: 1200px) { + @media (max-width: 980px) { #content { min-width: auto; /* Add some padding to make room for borders and to prevent focus @@ -80,7 +80,7 @@ } </style> <settings-prefs id="prefs" prefs="{{prefs_}}"></settings-prefs> -<password-manager-toolbar id="toolbar" narrow="[[narrow_]]" +<password-manager-toolbar id="toolbar" narrow="[[narrow_]]" page-name="[[pageTitle_]]" on-search-enter-click="onSearchEnterClick_"> </password-manager-toolbar> <div id="container" role="group"> @@ -129,9 +129,12 @@ </template> </div> </cr-drawer> -<iron-media-query query="(max-width: 1200px)" +<iron-media-query query="(max-width: 980px)" query-matches="{{narrow_}}"> </iron-media-query> +<iron-media-query query="(max-width: 1200px)" + query-matches="{{collapsed_}}"> +</iron-media-query> <cr-toast id="removalToast" duration="5000"> <span id="removalNotification">[[toastMessage_]]</span> <cr-button id="undo-removal" aria-label="$i18n{undoDescription}"
diff --git a/chrome/browser/resources/password_manager/password_manager_app.ts b/chrome/browser/resources/password_manager/password_manager_app.ts index 8d1888b..7e84b37 100644 --- a/chrome/browser/resources/password_manager/password_manager_app.ts +++ b/chrome/browser/resources/password_manager/password_manager_app.ts
@@ -93,7 +93,16 @@ narrow_: { type: Boolean, - observer: 'onNarrowChanged_', + observer: 'onMaxWidthChanged_', + }, + + collapsed_: { + type: Boolean, + observer: 'onMaxWidthChanged_', + }, + + pageTitle_: { + type: String, }, /* @@ -129,6 +138,8 @@ private selectedPage_: Page; private narrow_: boolean; + private collapsed_: boolean; + private pageTitle_: string = this.i18n('passwordManagerTitle'); private toastMessage_: string; private showUndo_: boolean; private focusConfig_: FocusConfig; @@ -214,10 +225,16 @@ return this.$.toolbar.searchField.isSearchFocused(); } - private onNarrowChanged_() { + private onMaxWidthChanged_() { if (this.$.drawer.open && !this.narrow_) { this.$.drawer.close(); } + // Window is greater than 980px but less than 1200px. + if (!this.narrow_ && this.collapsed_) { + this.pageTitle_ = this.i18n('passwordManagerString'); + } else { + this.pageTitle_ = this.i18n('passwordManagerTitle'); + } } private onMenuButtonClick_() {
diff --git a/chrome/browser/resources/password_manager/toolbar.html b/chrome/browser/resources/password_manager/toolbar.html index acb64bba..66c834ac 100644 --- a/chrome/browser/resources/password_manager/toolbar.html +++ b/chrome/browser/resources/password_manager/toolbar.html
@@ -18,11 +18,11 @@ } </style> <cr-toolbar id="mainToolbar" on-keydown="onKeyDown_" - page-name="$i18n{passwordManagerString}" clear-label="$i18n{clearSearch}" + page-name="[[pageName]]" clear-label="$i18n{clearSearch}" search-prompt="$i18n{searchPrompt}" menu-label="$i18n{menuButtonLabel}" autofocus on-search-changed="onSearchChanged_" role="banner" show-menu="[[narrow]]" narrow="[[narrow]]" - narrow-threshold="1200"> + narrow-threshold="980"> <picture slot="product-logo"> <img id="product-logo" srcset="chrome://password-manager/images/password_manager_logo.svg"
diff --git a/chrome/browser/resources/password_manager/toolbar.ts b/chrome/browser/resources/password_manager/toolbar.ts index dd0364d9..35368238 100644 --- a/chrome/browser/resources/password_manager/toolbar.ts +++ b/chrome/browser/resources/password_manager/toolbar.ts
@@ -42,10 +42,12 @@ static get properties() { return { narrow: Boolean, + pageName: String, }; } narrow: boolean; + pageName: string; override currentRouteChanged(newRoute: Route, _oldRoute: Route): void { this.updateSearchTerm(newRoute.queryParameters);
diff --git a/chrome/browser/resources/settings/search_engines_page/search_engine_entry.html b/chrome/browser/resources/settings/search_engines_page/search_engine_entry.html index 7b282be..314a799 100644 --- a/chrome/browser/resources/settings/search_engines_page/search_engine_entry.html +++ b/chrome/browser/resources/settings/search_engines_page/search_engine_entry.html
@@ -3,6 +3,20 @@ font-weight: 500; } + .additional-info-column-group { + align-items: center; + display: flex; + flex: 6; + } + + #controls-column-group { + flex: auto; + margin-left: auto; + display: flex; + justify-content: end; + align-items: center; + } + cr-policy-indicator { display: inline-flex; justify-content: center; @@ -19,12 +33,12 @@ } #shortcut-column { - flex: 4; word-break: break-word; } + #shortcut-column, #url-column-padded { - flex: 3; + flex: auto; margin-inline-end: 40px; } </style> @@ -36,44 +50,46 @@ </site-favicon> <div>[[engine.displayName]]</div> </span> - <span role="cell" id="shortcut-column" hidden="[[!showShortcut]]"> - <div>[[engine.keyword]]</div> - </span> - <span role="cell" id="url-column-padded" class="text-elide" - hidden="[[!showQueryUrl]]"> - <div>[[engine.url]]</div> - </span> - <span role="cell"> - <cr-button class="secondary-button" on-click="onActivateClick_" - hidden="[[!engine.canBeActivated]]" id="activate"> - $i18n{searchEnginesActivate} - </cr-button> - <cr-icon-button class="icon-edit" on-click="onEditClick_" - title="$i18n{edit}" hidden="[[!showEditIcon_]]" - disabled$="[[!engine.canBeEdited]]" id="editIconButton"> - </cr-icon-button> - <cr-icon-button class="icon-more-vert" on-click="onDotsClick_" - disabled$="[[engine.default]]" title="$i18n{moreActions}" - hidden="[[engine.isManaged]]"> - </cr-icon-button> - <cr-action-menu role-description="$i18n{menu}"> - <button class="dropdown-item" on-click="onMakeDefaultClick_" - disabled$="[[!engine.canBeDefault]]" id="makeDefault"> - $i18n{searchEnginesMakeDefault} - </button> - <button class="dropdown-item" on-click="onDeactivateClick_" - hidden="[[!engine.canBeDeactivated]]" id="deactivate"> - $i18n{searchEnginesDeactivate} - </button> - <button class="dropdown-item" on-click="onDeleteClick_" - hidden="[[!engine.canBeRemoved]]" id="delete"> - $i18n{delete} - </button> - </cr-action-menu> - <template is="dom-if" if="[[engine.isManaged]]"> - <cr-policy-indicator indicator-type="userPolicy"> - </cr-policy-indicator> - </dom-if> + <span class="additional-info-column-group"> + <span role="cell" id="shortcut-column" hidden="[[!showShortcut]]"> + <div>[[engine.keyword]]</div> + </span> + <span role="cell" id="url-column-padded" class="text-elide" + hidden="[[!showQueryUrl]]"> + <div>[[engine.url]]</div> + </span> + <span role="cell" id="controls-column-group"> + <cr-button class="secondary-button" on-click="onActivateClick_" + hidden="[[!engine.canBeActivated]]" id="activate"> + $i18n{searchEnginesActivate} + </cr-button> + <cr-icon-button class="icon-edit" on-click="onEditClick_" + title="$i18n{edit}" hidden="[[!showEditIcon_]]" + disabled$="[[!engine.canBeEdited]]" id="editIconButton"> + </cr-icon-button> + <cr-icon-button class="icon-more-vert" on-click="onDotsClick_" + disabled$="[[engine.default]]" title="$i18n{moreActions}" + hidden="[[engine.isManaged]]"> + </cr-icon-button> + <cr-action-menu role-description="$i18n{menu}"> + <button class="dropdown-item" on-click="onMakeDefaultClick_" + disabled$="[[!engine.canBeDefault]]" id="makeDefault"> + $i18n{searchEnginesMakeDefault} + </button> + <button class="dropdown-item" on-click="onDeactivateClick_" + hidden="[[!engine.canBeDeactivated]]" id="deactivate"> + $i18n{searchEnginesDeactivate} + </button> + <button class="dropdown-item" on-click="onDeleteClick_" + hidden="[[!engine.canBeRemoved]]" id="delete"> + $i18n{delete} + </button> + </cr-action-menu> + <template is="dom-if" if="[[engine.isManaged]]"> + <cr-policy-indicator indicator-type="userPolicy"> + </cr-policy-indicator> + </dom-if> + </span> </span> </div> <template is="dom-if" if="[[engine.extension]]">
diff --git a/chrome/browser/resources/settings/search_engines_page/search_engines_list.html b/chrome/browser/resources/settings/search_engines_page/search_engines_list.html index 32e74ad4e..5d53d86 100644 --- a/chrome/browser/resources/settings/search_engines_page/search_engines_list.html +++ b/chrome/browser/resources/settings/search_engines_page/search_engines_list.html
@@ -4,6 +4,20 @@ padding: 10px 0; } + #headers .additional-info-column-group { + align-items: center; + display: flex; + flex: 6; + } + + #headers .controls-group { + flex: auto; + margin-left: auto; + display: flex; + justify-content: end; + align-items: center; + } + #headers .name { flex: 3; } @@ -11,7 +25,8 @@ #headers .shortcut, #headers .url, #headers .url-padded { - flex: 4; + flex: auto; + margin-inline-end: 40px; } settings-search-engine-entry { @@ -40,15 +55,20 @@ <div role="rowgroup"> <div role="row" id="headers" class="column-header"> <span class="name" role="columnheader">[[nameColumnHeader]]</span> - <span class="shortcut" role="columnheader" hidden="[[!showShortcut]]"> - $i18n{searchEnginesShortcut} + <span class="additional-info-column-group"> + <span class="shortcut" role="columnheader" + hidden="[[!showShortcut]]"> + $i18n{searchEnginesShortcut} + </span> + <span class="url-padded" role="columnheader" + hidden="[[!showQueryUrl]]"> + $i18n{searchEnginesQueryURL} + </span> + <span class="controls-group"> + <span class="icon-placeholder"></span> + <span class="icon-placeholder"></span> + </span> </span> - <span class="url-padded" role="columnheader" - hidden="[[!showQueryUrl]]"> - $i18n{searchEnginesQueryURL} - </span> - <span class="icon-placeholder"></span> - <span class="icon-placeholder"></span> </div> </div> <template is="dom-if" if="[[!collapseList]]">
diff --git a/chrome/browser/signin/dice_tab_helper.cc b/chrome/browser/signin/dice_tab_helper.cc index fb750e0..171b7c2 100644 --- a/chrome/browser/signin/dice_tab_helper.cc +++ b/chrome/browser/signin/dice_tab_helper.cc
@@ -23,25 +23,23 @@ // static DiceTabHelper::EnableSyncCallback DiceTabHelper::GetEnableSyncCallbackForBrowser() { - return base::BindRepeating( - [](Profile* profile, signin_metrics::AccessPoint access_point, - signin_metrics::PromoAction promo_action, - signin_metrics::Reason reason, content::WebContents* web_contents, - const CoreAccountInfo& account_info) { - DCHECK(profile); - Browser* browser = web_contents - ? chrome::FindBrowserWithTab(web_contents) - : chrome::FindBrowserWithProfile(profile); - if (!browser) { - return; - } - // TurnSyncOnHelper is suicidal (it will kill itself once it - // finishes enabling sync). - new TurnSyncOnHelper( - profile, browser, access_point, promo_action, reason, - account_info.account_id, - TurnSyncOnHelper::SigninAbortedMode::REMOVE_ACCOUNT); - }); + return base::BindRepeating([](Profile* profile, + signin_metrics::AccessPoint access_point, + signin_metrics::PromoAction promo_action, + content::WebContents* web_contents, + const CoreAccountInfo& account_info) { + DCHECK(profile); + Browser* browser = web_contents ? chrome::FindBrowserWithTab(web_contents) + : chrome::FindBrowserWithProfile(profile); + if (!browser) { + return; + } + // TurnSyncOnHelper is suicidal (it will kill itself once it + // finishes enabling sync). + new TurnSyncOnHelper(profile, browser, access_point, promo_action, + account_info.account_id, + TurnSyncOnHelper::SigninAbortedMode::REMOVE_ACCOUNT); + }); } // static
diff --git a/chrome/browser/signin/dice_tab_helper.h b/chrome/browser/signin/dice_tab_helper.h index 4d074394..5a2a337 100644 --- a/chrome/browser/signin/dice_tab_helper.h +++ b/chrome/browser/signin/dice_tab_helper.h
@@ -27,7 +27,6 @@ base::RepeatingCallback<void(Profile*, signin_metrics::AccessPoint, signin_metrics::PromoAction, - signin_metrics::Reason, content::WebContents*, const CoreAccountInfo&)>;
diff --git a/chrome/browser/signin/process_dice_header_delegate_impl.cc b/chrome/browser/signin/process_dice_header_delegate_impl.cc index 6f45700f..ea69505 100644 --- a/chrome/browser/signin/process_dice_header_delegate_impl.cc +++ b/chrome/browser/signin/process_dice_header_delegate_impl.cc
@@ -83,7 +83,6 @@ signin_metrics::AccessPoint::ACCESS_POINT_UNKNOWN; signin_metrics::PromoAction promo_action = signin_metrics::PromoAction::PROMO_ACTION_NO_SIGNIN_PROMO; - signin_metrics::Reason reason = signin_metrics::Reason::kUnknownReason; GURL redirect_url; EnableSyncCallback enable_sync_callback; OnSigninHeaderReceived on_signin_header_received; @@ -95,7 +94,6 @@ redirect_url = tab_helper->redirect_url(); access_point = tab_helper->signin_access_point(); promo_action = tab_helper->signin_promo_action(); - reason = tab_helper->signin_reason(); // `show_signin_error_callback` may be null if the `DiceTabHelper` was reset // after completion of a signin flow. show_signin_error_callback = @@ -118,7 +116,7 @@ } return std::make_unique<ProcessDiceHeaderDelegateImpl>( - web_contents, is_sync_signin_tab, access_point, promo_action, reason, + web_contents, is_sync_signin_tab, access_point, promo_action, std::move(redirect_url), std::move(enable_sync_callback), std::move(on_signin_header_received), std::move(show_signin_error_callback)); @@ -129,7 +127,6 @@ bool is_sync_signin_tab, signin_metrics::AccessPoint access_point, signin_metrics::PromoAction promo_action, - signin_metrics::Reason reason, GURL redirect_url, EnableSyncCallback enable_sync_callback, OnSigninHeaderReceived on_signin_header_received, @@ -140,7 +137,6 @@ is_sync_signin_tab_(is_sync_signin_tab), access_point_(access_point), promo_action_(promo_action), - reason_(reason), redirect_url_(std::move(redirect_url)), enable_sync_callback_(std::move(enable_sync_callback)), on_signin_header_received_(std::move(on_signin_header_received)), @@ -202,7 +198,7 @@ VLOG(1) << "Start sync after web sign-in."; std::move(enable_sync_callback_) - .Run(&profile_.get(), access_point_, promo_action_, reason_, web_contents, + .Run(&profile_.get(), access_point_, promo_action_, web_contents, account_info); Redirect();
diff --git a/chrome/browser/signin/process_dice_header_delegate_impl.h b/chrome/browser/signin/process_dice_header_delegate_impl.h index 18672f14..be70368 100644 --- a/chrome/browser/signin/process_dice_header_delegate_impl.h +++ b/chrome/browser/signin/process_dice_header_delegate_impl.h
@@ -31,7 +31,6 @@ base::OnceCallback<void(Profile*, signin_metrics::AccessPoint, signin_metrics::PromoAction, - signin_metrics::Reason, content::WebContents*, const CoreAccountInfo&)>; @@ -58,7 +57,6 @@ bool is_sync_signin_tab, signin_metrics::AccessPoint access_point, signin_metrics::PromoAction promo_action, - signin_metrics::Reason reason, GURL redirect_url, EnableSyncCallback enable_sync_callback, OnSigninHeaderReceived on_signin_header_received, @@ -91,7 +89,6 @@ const bool is_sync_signin_tab_; const signin_metrics::AccessPoint access_point_; const signin_metrics::PromoAction promo_action_; - const signin_metrics::Reason reason_; const GURL redirect_url_; EnableSyncCallback enable_sync_callback_; OnSigninHeaderReceived on_signin_header_received_;
diff --git a/chrome/browser/signin/process_dice_header_delegate_impl_unittest.cc b/chrome/browser/signin/process_dice_header_delegate_impl_unittest.cc index 00f7789..abb6573 100644 --- a/chrome/browser/signin/process_dice_header_delegate_impl_unittest.cc +++ b/chrome/browser/signin/process_dice_header_delegate_impl_unittest.cc
@@ -170,7 +170,7 @@ return std::make_unique<ProcessDiceHeaderDelegateImpl>( web_contents(), /*is_sync_signin_tab=*/false, signin_metrics::AccessPoint::ACCESS_POINT_WEB_SIGNIN, - kTestPromoAction, signin_metrics::Reason::kUnknownReason, GURL(), + kTestPromoAction, GURL(), ProcessDiceHeaderDelegateImpl::EnableSyncCallback(), base::BindRepeating( &ProcessDiceHeaderDelegateImplTest::OnSigninHeaderReceived, @@ -200,13 +200,11 @@ void StartSyncCallback(Profile* profile, signin_metrics::AccessPoint access_point, signin_metrics::PromoAction promo_action, - signin_metrics::Reason reason, content::WebContents* contents, const CoreAccountInfo& account_info) { EXPECT_EQ(profile, this->profile()); EXPECT_EQ(access_point, kTestAccessPoint); EXPECT_EQ(promo_action, kTestPromoAction); - EXPECT_EQ(reason, signin_reason_); EXPECT_EQ(web_contents(), contents); EXPECT_EQ(account_info_, account_info); enable_sync_called_ = true;
diff --git a/chrome/browser/signin/signin_ui_delegate.cc b/chrome/browser/signin/signin_ui_delegate.cc index eed80c0..b374286 100644 --- a/chrome/browser/signin/signin_ui_delegate.cc +++ b/chrome/browser/signin/signin_ui_delegate.cc
@@ -13,14 +13,12 @@ Profile* profile, signin_metrics::AccessPoint access_point, signin_metrics::PromoAction promo_action, - signin_metrics::Reason signin_reason, const CoreAccountId& account_id, TurnSyncOnHelper::SigninAbortedMode signin_aborted_mode) { // TurnSyncOnHelper is suicidal (it will delete itself once it finishes // enabling sync). new TurnSyncOnHelper(profile, EnsureBrowser(profile), access_point, - promo_action, signin_reason, account_id, - signin_aborted_mode); + promo_action, account_id, signin_aborted_mode); } // static
diff --git a/chrome/browser/signin/signin_ui_delegate.h b/chrome/browser/signin/signin_ui_delegate.h index a4b8239..ec6fb92d 100644 --- a/chrome/browser/signin/signin_ui_delegate.h +++ b/chrome/browser/signin/signin_ui_delegate.h
@@ -49,7 +49,6 @@ Profile* profile, signin_metrics::AccessPoint access_point, signin_metrics::PromoAction promo_action, - signin_metrics::Reason signin_reason, const CoreAccountId& account_id, TurnSyncOnHelper::SigninAbortedMode signin_aborted_mode);
diff --git a/chrome/browser/signin/signin_ui_delegate_impl_lacros.cc b/chrome/browser/signin/signin_ui_delegate_impl_lacros.cc index 4842e32..22bb4ed 100644 --- a/chrome/browser/signin/signin_ui_delegate_impl_lacros.cc +++ b/chrome/browser/signin/signin_ui_delegate_impl_lacros.cc
@@ -164,10 +164,7 @@ if (!browser) return; - ShowTurnSyncOnUI(profile, access_point, promo_action, - is_reauth ? signin_metrics::Reason::kReauthentication - : signin_metrics::Reason::kSigninPrimaryAccount, - account_id, + ShowTurnSyncOnUI(profile, access_point, promo_action, account_id, is_reauth ? TurnSyncOnHelper::SigninAbortedMode::KEEP_ACCOUNT : TurnSyncOnHelper::SigninAbortedMode::REMOVE_ACCOUNT);
diff --git a/chrome/browser/signin/signin_ui_util.cc b/chrome/browser/signin/signin_ui_util.cc index cad650ec..2b4f936 100644 --- a/chrome/browser/signin/signin_ui_util.cc +++ b/chrome/browser/signin/signin_ui_util.cc
@@ -366,8 +366,7 @@ existing_account_promo_action); signin_metrics::RecordSigninUserActionForAccessPoint(access_point); GetSigninUiDelegate()->ShowTurnSyncOnUI( - profile, access_point, existing_account_promo_action, - signin_metrics::Reason::kSigninPrimaryAccount, account.account_id, + profile, access_point, existing_account_promo_action, account.account_id, signin_aborted_mode); #else NOTREACHED();
diff --git a/chrome/browser/signin/signin_ui_util_unittest.cc b/chrome/browser/signin/signin_ui_util_unittest.cc index 8146e44..504cbaa 100644 --- a/chrome/browser/signin/signin_ui_util_unittest.cc +++ b/chrome/browser/signin/signin_ui_util_unittest.cc
@@ -106,7 +106,6 @@ (Profile * profile, signin_metrics::AccessPoint access_point, signin_metrics::PromoAction promo_action, - signin_metrics::Reason signin_reason, const CoreAccountId& account_id, TurnSyncOnHelper::SigninAbortedMode signin_aborted_mode), ()); @@ -121,7 +120,6 @@ (Profile * profile, signin_metrics::AccessPoint access_point, signin_metrics::PromoAction promo_action, - signin_metrics::Reason signin_reason, const CoreAccountId& account_id, TurnSyncOnHelper::SigninAbortedMode signin_aborted_mode), ()); @@ -160,13 +158,11 @@ void ExpectTurnSyncOn( signin_metrics::AccessPoint access_point, signin_metrics::PromoAction promo_action, - signin_metrics::Reason signin_reason, const CoreAccountId& account_id, TurnSyncOnHelper::SigninAbortedMode signin_aborted_mode) { - EXPECT_CALL( - mock_delegate_, - ShowTurnSyncOnUI(profile(), access_point, promo_action, signin_reason, - account_id, signin_aborted_mode)); + EXPECT_CALL(mock_delegate_, + ShowTurnSyncOnUI(profile(), access_point, promo_action, + account_id, signin_aborted_mode)); } void ExpectNoSigninStartedHistograms( @@ -275,8 +271,7 @@ ? signin_metrics::PromoAction::PROMO_ACTION_WITH_DEFAULT : signin_metrics::PromoAction::PROMO_ACTION_NOT_DEFAULT; ExpectTurnSyncOn(signin_metrics::AccessPoint::ACCESS_POINT_BOOKMARK_BUBBLE, - expected_promo_action, - signin_metrics::Reason::kSigninPrimaryAccount, account_id, + expected_promo_action, account_id, TurnSyncOnHelper::SigninAbortedMode::KEEP_ACCOUNT); EnableSync( GetIdentityManager()->FindExtendedAccountInfoByAccountId(account_id), @@ -712,8 +707,7 @@ : signin_metrics::PromoAction::PROMO_ACTION_NOT_DEFAULT; ExpectTurnSyncOn( signin_metrics::AccessPoint::ACCESS_POINT_BOOKMARK_BUBBLE, - expected_promo_action, signin_metrics::Reason::kSigninPrimaryAccount, - account_id, + expected_promo_action, account_id, TurnSyncOnHelper::SigninAbortedMode::KEEP_ACCOUNT_ON_WEB_ONLY); EnableSync( GetIdentityManager()->FindExtendedAccountInfoByAccountId(account_id), @@ -759,13 +753,11 @@ void ExpectTurnSyncOn( signin_metrics::AccessPoint access_point, signin_metrics::PromoAction promo_action, - signin_metrics::Reason signin_reason, const CoreAccountId& account_id, TurnSyncOnHelper::SigninAbortedMode signin_aborted_mode) { - EXPECT_CALL( - mock_delegate_, - ShowTurnSyncOnUI(profile(), access_point, promo_action, signin_reason, - account_id, signin_aborted_mode)); + EXPECT_CALL(mock_delegate_, + ShowTurnSyncOnUI(profile(), access_point, promo_action, + account_id, signin_aborted_mode)); } protected: @@ -790,8 +782,7 @@ ExpectTurnSyncOn( signin_metrics::AccessPoint::ACCESS_POINT_AVATAR_BUBBLE_SIGN_IN, - expected_promo_action, signin_metrics::Reason::kSigninPrimaryAccount, - account_info.account_id, + expected_promo_action, account_info.account_id, TurnSyncOnHelper::SigninAbortedMode::KEEP_ACCOUNT); EnableSyncFromMultiAccountPromo( profile(), account_info,
diff --git a/chrome/browser/signin/signin_util_win.cc b/chrome/browser/signin/signin_util_win.cc index ccb06b2..8cf7cbc 100644 --- a/chrome/browser/signin/signin_util_win.cc +++ b/chrome/browser/signin/signin_util_win.cc
@@ -88,15 +88,13 @@ if (GetTurnSyncOnHelperDelegateForTestingStorage()->get()) { new TurnSyncOnHelper( profile, kCredentialsProviderAccessPointWin, - signin_metrics::PromoAction::PROMO_ACTION_WITH_DEFAULT, - signin_metrics::Reason::kSigninPrimaryAccount, account_id, + signin_metrics::PromoAction::PROMO_ACTION_WITH_DEFAULT, account_id, TurnSyncOnHelper::SigninAbortedMode::KEEP_ACCOUNT, std::move(*GetTurnSyncOnHelperDelegateForTestingStorage()), base::DoNothing()); } else { new TurnSyncOnHelper(profile, browser, kCredentialsProviderAccessPointWin, signin_metrics::PromoAction::PROMO_ACTION_WITH_DEFAULT, - signin_metrics::Reason::kSigninPrimaryAccount, account_id, TurnSyncOnHelper::SigninAbortedMode::KEEP_ACCOUNT); }
diff --git a/chrome/browser/sync/test/integration/password_sharing_invitation_helper.cc b/chrome/browser/sync/test/integration/password_sharing_invitation_helper.cc new file mode 100644 index 0000000..a983cd4 --- /dev/null +++ b/chrome/browser/sync/test/integration/password_sharing_invitation_helper.cc
@@ -0,0 +1,133 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/sync/test/integration/password_sharing_invitation_helper.h" + +#include <memory> +#include <vector> + +#include "base/uuid.h" +#include "components/sync/engine/nigori/cross_user_sharing_public_key.h" +#include "components/sync/nigori/cryptographer_impl.h" +#include "third_party/abseil-cpp/absl/types/optional.h" + +namespace password_sharing_helper { + +namespace { +constexpr char kSignonRealm[] = "signon_realm"; +constexpr char kOrigin[] = "http://abc.com/"; +constexpr char kUsernameElement[] = "username_element"; +constexpr char kPasswordElement[] = "password_element"; +constexpr char kPasswordDisplayName[] = "password_display_name"; +constexpr char kPasswordAvatarUrl[] = "http://avatar.url/"; + +constexpr char kSenderEmail[] = "sender@gmail.com"; +constexpr char kSenderDisplayName[] = "Sender Name"; +constexpr char kSenderProfileImageUrl[] = "http://sender.url/image"; + +constexpr int kSenderKeyVersion = 0; + +sync_pb::CrossUserSharingPublicKey PublicKeyToProto( + const syncer::CrossUserSharingPublicKey& public_key) { + sync_pb::CrossUserSharingPublicKey proto; + auto raw_public_key = public_key.GetRawPublicKey(); + proto.set_x25519_public_key( + std::string(raw_public_key.begin(), raw_public_key.end())); + proto.set_version(kSenderKeyVersion); + return proto; +} + +// Encrypts the invitation data to simulate the sending client. +std::vector<uint8_t> EncryptInvitationData( + const sync_pb::PasswordSharingInvitationData& unencrypted_password_data, + const sync_pb::CrossUserSharingPublicKey& recipient_public_key, + const syncer::CrossUserSharingPublicPrivateKeyPair& sender_key_pair) { + std::unique_ptr<syncer::CryptographerImpl> sender_cryptographer = + syncer::CryptographerImpl::CreateEmpty(); + + // Clone `sender_key_pair` since the cryptographer requires it to be moved. + absl::optional<syncer::CrossUserSharingPublicPrivateKeyPair> + sender_key_pair_copy = + syncer::CrossUserSharingPublicPrivateKeyPair::CreateByImport( + sender_key_pair.GetRawPrivateKey()); + CHECK(sender_key_pair_copy); + sender_cryptographer->EmplaceKeyPair(std::move(sender_key_pair_copy.value()), + kSenderKeyVersion); + sender_cryptographer->SelectDefaultCrossUserSharingKey(kSenderKeyVersion); + + std::string serialized_data; + bool success = unencrypted_password_data.SerializeToString(&serialized_data); + CHECK(success); + + absl::optional<std::vector<uint8_t>> result = + sender_cryptographer->AuthEncryptForCrossUserSharing( + base::as_bytes(base::make_span(serialized_data)), + base::as_bytes( + base::make_span(recipient_public_key.x25519_public_key()))); + CHECK(result); + + return result.value(); +} +} // namespace + +sync_pb::IncomingPasswordSharingInvitationSpecifics +CreateEncryptedIncomingInvitationSpecifics( + const sync_pb::PasswordSharingInvitationData& invitation_data, + const sync_pb::UserDisplayInfo& sender_display_info, + const sync_pb::CrossUserSharingPublicKey& recipient_public_key, + const syncer::CrossUserSharingPublicPrivateKeyPair& sender_key_pair) { + sync_pb::IncomingPasswordSharingInvitationSpecifics specifics; + std::vector<uint8_t> encrypted_password = EncryptInvitationData( + invitation_data, recipient_public_key, sender_key_pair); + specifics.set_encrypted_password_sharing_invitation_data( + std::string(encrypted_password.begin(), encrypted_password.end())); + specifics.set_guid(base::Uuid::GenerateRandomV4().AsLowercaseString()); + specifics.set_recipient_key_version(recipient_public_key.version()); + + absl::optional<syncer::CrossUserSharingPublicKey> sender_public_key = + syncer::CrossUserSharingPublicKey::CreateByImport( + sender_key_pair.GetRawPublicKey()); + CHECK(sender_public_key); + + sync_pb::UserInfo* sender_info = specifics.mutable_sender_info(); + sender_info->mutable_cross_user_sharing_public_key()->CopyFrom( + PublicKeyToProto(sender_public_key.value())); + sender_info->mutable_user_display_info()->CopyFrom(sender_display_info); + + return specifics; +} + +sync_pb::PasswordSharingInvitationData CreateDefaultIncomingInvitation( + const std::string& username_value, + const std::string& password_value) { + sync_pb::PasswordSharingInvitationData password_invitation_data; + sync_pb::PasswordSharingInvitationData::PasswordGroupData* + password_group_data = + password_invitation_data.mutable_password_group_data(); + + password_group_data->set_username_value(username_value); + password_group_data->set_password_value(password_value); + + sync_pb::PasswordSharingInvitationData::PasswordGroupElementData* + element_data = password_group_data->add_element_data(); + + element_data->set_signon_realm(kSignonRealm); + element_data->set_origin(kOrigin); + element_data->set_username_element(kUsernameElement); + element_data->set_password_element(kPasswordElement); + element_data->set_display_name(kPasswordDisplayName); + element_data->set_avatar_url(kPasswordAvatarUrl); + + return password_invitation_data; +} + +sync_pb::UserDisplayInfo CreateDefaultSenderDisplayInfo() { + sync_pb::UserDisplayInfo sender_display_info; + sender_display_info.set_email(kSenderEmail); + sender_display_info.set_display_name(kSenderDisplayName); + sender_display_info.set_profile_image_url(kSenderProfileImageUrl); + return sender_display_info; +} + +} // namespace password_sharing_helper
diff --git a/chrome/browser/sync/test/integration/password_sharing_invitation_helper.h b/chrome/browser/sync/test/integration/password_sharing_invitation_helper.h new file mode 100644 index 0000000..0bb65166 --- /dev/null +++ b/chrome/browser/sync/test/integration/password_sharing_invitation_helper.h
@@ -0,0 +1,36 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_SYNC_TEST_INTEGRATION_PASSWORD_SHARING_INVITATION_HELPER_H_ +#define CHROME_BROWSER_SYNC_TEST_INTEGRATION_PASSWORD_SHARING_INVITATION_HELPER_H_ + +#include <string> + +#include "components/sync/engine/nigori/cross_user_sharing_public_private_key_pair.h" +#include "components/sync/protocol/nigori_specifics.pb.h" +#include "components/sync/protocol/password_sharing_invitation_specifics.pb.h" + +namespace password_sharing_helper { + +// Creates an incoming password sharing invitation specifics including +// encrypting the `invitation_data`. +sync_pb::IncomingPasswordSharingInvitationSpecifics +CreateEncryptedIncomingInvitationSpecifics( + const sync_pb::PasswordSharingInvitationData& invitation_data, + const sync_pb::UserDisplayInfo& sender_display_info, + const sync_pb::CrossUserSharingPublicKey& recipient_public_key, + const syncer::CrossUserSharingPublicPrivateKeyPair& sender_key_pair); + +// Creates incoming password sharing invitation data with the given password +// value. +sync_pb::PasswordSharingInvitationData CreateDefaultIncomingInvitation( + const std::string& username_value, + const std::string& password_value); + +// Creates default UserDisplayInfo for sender. +sync_pb::UserDisplayInfo CreateDefaultSenderDisplayInfo(); + +} // namespace password_sharing_helper + +#endif // CHROME_BROWSER_SYNC_TEST_INTEGRATION_PASSWORD_SHARING_INVITATION_HELPER_H_
diff --git a/chrome/browser/sync/test/integration/passwords_helper.cc b/chrome/browser/sync/test/integration/passwords_helper.cc index 7904514..7e7008b 100644 --- a/chrome/browser/sync/test/integration/passwords_helper.cc +++ b/chrome/browser/sync/test/integration/passwords_helper.cc
@@ -29,6 +29,7 @@ #include "components/sync/nigori/cryptographer_impl.h" #include "components/sync/protocol/entity_specifics.pb.h" #include "components/sync/protocol/password_specifics.pb.h" +#include "components/sync/service/sync_service_impl.h" #include "content/public/test/test_utils.h" #include "url/gurl.h" @@ -69,6 +70,8 @@ private: // This RunLoop uses kNestableTasksAllowed because it runs nested within // another RunLoop. + // TODO(crbug.com/1514434): consider changing this to PasswordStoreInterface + // observer to avoid nested run loops. base::RunLoop run_loop_{base::RunLoop::Type::kNestableTasksAllowed}; std::vector<std::unique_ptr<PasswordForm>> result_; base::WeakPtrFactory<PasswordStoreConsumerHelper> weak_ptr_factory_{this}; @@ -486,3 +489,42 @@ } return is_matching; } + +PasswordFormsAddedChecker::PasswordFormsAddedChecker( + password_manager::PasswordStoreInterface* password_store, + size_t expected_new_password_forms) + : password_store_(password_store), + expected_new_password_forms_(expected_new_password_forms) { + password_store_->AddObserver(this); +} + +PasswordFormsAddedChecker::~PasswordFormsAddedChecker() { + password_store_->RemoveObserver(this); +} + +bool PasswordFormsAddedChecker::IsExitConditionSatisfied(std::ostream* os) { + *os << "Waiting for " << expected_new_password_forms_ + << " passwords added to the store. "; + + *os << "Current number of added password forms to the store: " + << num_added_passwords_; + return num_added_passwords_ == expected_new_password_forms_; +} + +void PasswordFormsAddedChecker::OnLoginsChanged( + password_manager::PasswordStoreInterface* store, + const password_manager::PasswordStoreChangeList& changes) { + for (const password_manager::PasswordStoreChange& change : changes) { + if (change.type() == password_manager::PasswordStoreChange::ADD) { + num_added_passwords_++; + } + } + + CheckExitCondition(); +} + +void PasswordFormsAddedChecker::OnLoginsRetained( + password_manager::PasswordStoreInterface* store, + const std::vector<password_manager::PasswordForm>& retained_passwords) { + // Not used. +}
diff --git a/chrome/browser/sync/test/integration/passwords_helper.h b/chrome/browser/sync/test/integration/passwords_helper.h index d390584..ffd89ab 100644 --- a/chrome/browser/sync/test/integration/passwords_helper.h +++ b/chrome/browser/sync/test/integration/passwords_helper.h
@@ -6,6 +6,7 @@ #define CHROME_BROWSER_SYNC_TEST_INTEGRATION_PASSWORDS_HELPER_H_ #include <memory> +#include <optional> #include <string> #include <vector> @@ -14,10 +15,12 @@ #include "chrome/browser/sync/test/integration/single_client_status_change_checker.h" #include "chrome/browser/sync/test/integration/sync_test.h" #include "components/password_manager/core/browser/password_form.h" +#include "components/password_manager/core/browser/password_store/password_store_interface.h" namespace syncer { class Cryptographer; class KeyDerivationParams; +class SyncServiceImpl; } namespace password_manager { @@ -27,7 +30,8 @@ namespace passwords_helper { // Returns all logins from |store| matching a fake signon realm (see -// CreateTestPasswordForm()). +// CreateTestPasswordForm()). Note that it uses RunLoop to wait for async +// results and should be avoided from using in StatusChangeChecker. // TODO(treib): Rename this to make clear how specific it is. std::vector<std::unique_ptr<password_manager::PasswordForm>> GetLogins( password_manager::PasswordStoreInterface* store); @@ -215,4 +219,34 @@ std::vector<std::unique_ptr<password_manager::PasswordForm>> expected_forms_; }; +// Waits for the `expected_new_password_forms` of newly added passwords to the +// `password_store`. Note that this object should be created before any changes +// to the store to prevent test flakiness. +class PasswordFormsAddedChecker + : public StatusChangeChecker, + public password_manager::PasswordStoreInterface::Observer { + public: + PasswordFormsAddedChecker( + password_manager::PasswordStoreInterface* password_store, + size_t expected_new_password_forms); + ~PasswordFormsAddedChecker() override; + + // StatusChangeChecker implementation. + bool IsExitConditionSatisfied(std::ostream* os) override; + + // PasswordStoreInterface::Observer implementation. + void OnLoginsChanged( + password_manager::PasswordStoreInterface* store, + const password_manager::PasswordStoreChangeList& changes) override; + void OnLoginsRetained(password_manager::PasswordStoreInterface* store, + const std::vector<password_manager::PasswordForm>& + retained_passwords) override; + + private: + const raw_ptr<password_manager::PasswordStoreInterface> password_store_; + const size_t expected_new_password_forms_; + + size_t num_added_passwords_ = 0; +}; + #endif // CHROME_BROWSER_SYNC_TEST_INTEGRATION_PASSWORDS_HELPER_H_
diff --git a/chrome/browser/sync/test/integration/single_client_incoming_password_sharing_invitation_test.cc b/chrome/browser/sync/test/integration/single_client_incoming_password_sharing_invitation_test.cc index 2891de7..355aaf0 100644 --- a/chrome/browser/sync/test/integration/single_client_incoming_password_sharing_invitation_test.cc +++ b/chrome/browser/sync/test/integration/single_client_incoming_password_sharing_invitation_test.cc
@@ -14,6 +14,7 @@ #include "build/build_config.h" #include "chrome/browser/sync/test/integration/encryption_helper.h" #include "chrome/browser/sync/test/integration/fake_server_match_status_checker.h" +#include "chrome/browser/sync/test/integration/password_sharing_invitation_helper.h" #include "chrome/browser/sync/test/integration/passwords_helper.h" #include "chrome/browser/sync/test/integration/single_client_status_change_checker.h" #include "chrome/browser/sync/test/integration/sync_service_impl_harness.h" @@ -39,6 +40,9 @@ using password_manager::PasswordStoreInterface; using password_manager::metrics_util:: ProcessIncomingPasswordSharingInvitationResult; +using password_sharing_helper::CreateDefaultIncomingInvitation; +using password_sharing_helper::CreateDefaultSenderDisplayInfo; +using password_sharing_helper::CreateEncryptedIncomingInvitationSpecifics; using passwords_helper::GetAccountPasswordStoreInterface; using passwords_helper::GetAllLogins; using passwords_helper::GetProfilePasswordStoreInterface; @@ -56,134 +60,39 @@ namespace { constexpr char kPasswordValue[] = "password"; -constexpr char kSignonRealm[] = "signon_realm"; -constexpr char kOrigin[] = "http://abc.com/"; -constexpr char kUsernameElement[] = "username_element"; constexpr char kUsernameValue[] = "username"; -constexpr char kPasswordElement[] = "password_element"; -constexpr char kPasswordDisplayName[] = "password_display_name"; -constexpr char kPasswordAvatarUrl[] = "http://avatar.url/"; - -constexpr char kSenderEmail[] = "sender@gmail.com"; -constexpr char kSenderDisplayName[] = "Sender Name"; -constexpr char kSenderProfileImageUrl[] = "http://sender.url/image"; - -constexpr char kLocalPasswordValue[] = "local_password_value"; - -constexpr uint32_t kSenderKeyVersion = 1; - -sync_pb::CrossUserSharingPublicKey PublicKeyToProto( - const syncer::CrossUserSharingPublicKey& public_key) { - sync_pb::CrossUserSharingPublicKey proto; - auto raw_public_key = public_key.GetRawPublicKey(); - proto.set_x25519_public_key( - std::string(raw_public_key.begin(), raw_public_key.end())); - proto.set_version(kSenderKeyVersion); - return proto; -} - -PasswordSharingInvitationData CreateUnencryptedInvitationData() { - PasswordSharingInvitationData password_invitation_data; - PasswordSharingInvitationData::PasswordGroupData* password_group_data = - password_invitation_data.mutable_password_group_data(); - - password_group_data->set_username_value(kUsernameValue); - password_group_data->set_password_value(kPasswordValue); - - sync_pb::PasswordSharingInvitationData::PasswordGroupElementData* - element_data = password_group_data->add_element_data(); - - element_data->set_signon_realm(kSignonRealm); - element_data->set_origin(kOrigin); - element_data->set_username_element(kUsernameElement); - element_data->set_password_element(kPasswordElement); - element_data->set_display_name(kPasswordDisplayName); - element_data->set_avatar_url(kPasswordAvatarUrl); - - return password_invitation_data; -} - -std::vector<uint8_t> EncryptInvitationData( - const PasswordSharingInvitationData& unencrypted_password_data, - const sync_pb::CrossUserSharingPublicKey& recipient_public_key, - const syncer::CrossUserSharingPublicPrivateKeyPair& sender_key_pair) { - std::unique_ptr<syncer::CryptographerImpl> sender_cryptographer = - syncer::CryptographerImpl::CreateEmpty(); - - // Clone `sender_key_pair` since the cryptographer requires it to be moved. - absl::optional<syncer::CrossUserSharingPublicPrivateKeyPair> - sender_key_pair_copy = - syncer::CrossUserSharingPublicPrivateKeyPair::CreateByImport( - sender_key_pair.GetRawPrivateKey()); - DCHECK(sender_key_pair_copy); - sender_cryptographer->EmplaceKeyPair(std::move(sender_key_pair_copy.value()), - kSenderKeyVersion); - sender_cryptographer->SelectDefaultCrossUserSharingKey(kSenderKeyVersion); - - std::string serialized_data; - bool success = unencrypted_password_data.SerializeToString(&serialized_data); - DCHECK(success); - - absl::optional<std::vector<uint8_t>> result = - sender_cryptographer->AuthEncryptForCrossUserSharing( - base::as_bytes(base::make_span(serialized_data)), - base::as_bytes( - base::make_span(recipient_public_key.x25519_public_key()))); - DCHECK(result); - - return result.value(); -} IncomingPasswordSharingInvitationSpecifics CreateInvitationSpecifics( const sync_pb::CrossUserSharingPublicKey& recipient_public_key) { - syncer::CrossUserSharingPublicPrivateKeyPair sender_key_pair = - syncer::CrossUserSharingPublicPrivateKeyPair::GenerateNewKeyPair(); - std::vector<uint8_t> encrypted_password = EncryptInvitationData( - CreateUnencryptedInvitationData(), recipient_public_key, sender_key_pair); - IncomingPasswordSharingInvitationSpecifics specifics; - specifics.set_encrypted_password_sharing_invitation_data( - std::string(encrypted_password.begin(), encrypted_password.end())); - specifics.set_guid(base::Uuid::GenerateRandomV4().AsLowercaseString()); - specifics.set_recipient_key_version(recipient_public_key.version()); - - absl::optional<syncer::CrossUserSharingPublicKey> sender_public_key = - syncer::CrossUserSharingPublicKey::CreateByImport( - sender_key_pair.GetRawPublicKey()); - DCHECK(sender_public_key); - sync_pb::UserInfo* sender_info = specifics.mutable_sender_info(); - sender_info->mutable_cross_user_sharing_public_key()->CopyFrom( - PublicKeyToProto(sender_public_key.value())); - sender_info->mutable_user_display_info()->set_email(kSenderEmail); - sender_info->mutable_user_display_info()->set_display_name( - kSenderDisplayName); - sender_info->mutable_user_display_info()->set_profile_image_url( - kSenderProfileImageUrl); - - return specifics; + return CreateEncryptedIncomingInvitationSpecifics( + CreateDefaultIncomingInvitation(kUsernameValue, kPasswordValue), + CreateDefaultSenderDisplayInfo(), recipient_public_key, + /*sender_key_pair=*/ + syncer::CrossUserSharingPublicPrivateKeyPair::GenerateNewKeyPair()); } -// Waits for the incoming password to be stored locally. -class PasswordStoredChecker : public SingleClientStatusChangeChecker { - public: - PasswordStoredChecker(SyncServiceImpl* sync_service, - PasswordStoreInterface* password_store, - size_t expected_count) - : SingleClientStatusChangeChecker(sync_service), - password_store_(password_store), - expected_count_(expected_count) {} +#if !BUILDFLAG(IS_CHROMEOS_ASH) +// Fill in fields in `password_data` required for computing password client tag. +// This is useful for testing collisions. Note that the `invitation` must +// contain only one password in a group. +void FillPasswordClientTagFromInvitation( + const sync_pb::PasswordSharingInvitationData& invitation_data, + sync_pb::PasswordSpecificsData* password_data) { + const sync_pb::PasswordSharingInvitationData::PasswordGroupData& + invitation_group_data = invitation_data.password_group_data(); + CHECK_EQ(invitation_group_data.element_data().size(), 1); + const sync_pb::PasswordSharingInvitationData::PasswordGroupElementData& + invitation_group_element_data = invitation_group_data.element_data(0); - bool IsExitConditionSatisfied(std::ostream* os) override { - *os << "Waiting for " << expected_count_ << " passwords in the store. "; - - size_t current_count = GetAllLogins(password_store_).size(); - *os << "Current password count in the store: " << current_count; - return current_count == expected_count_; - } - - private: - const raw_ptr<PasswordStoreInterface> password_store_; - const size_t expected_count_; -}; + password_data->set_username_value(invitation_group_data.username_value()); + password_data->set_origin(invitation_group_element_data.origin()); + password_data->set_username_element( + invitation_group_element_data.username_element()); + password_data->set_password_element( + invitation_group_element_data.password_element()); + password_data->set_signon_realm(invitation_group_element_data.signon_realm()); +} +#endif // !BUILDFLAG(IS_CHROMEOS_ASH) // Waits until all the incoming invitations are deleted from the fake server. class ServerPasswordInvitationChecker @@ -248,10 +157,12 @@ return nigori_specifics.cross_user_sharing_public_key(); } - void InjectInvitationToServer() { + void InjectInvitationToServer( + const sync_pb::IncomingPasswordSharingInvitationSpecifics& + invitation_specifics) { EntitySpecifics specifics; specifics.mutable_incoming_password_sharing_invitation()->CopyFrom( - CreateInvitationSpecifics(GetPublicKeyFromServer())); + invitation_specifics); GetFakeServer()->InjectEntity( syncer::PersistentUniqueClientEntity::CreateFromSpecificsForTesting( /*non_unique_name=*/"", @@ -260,21 +171,6 @@ /*creation_time=*/0, /*last_modified_time=*/0)); } - void InjectTestPasswordToFakeServer() { - sync_pb::PasswordSpecificsData password_data; - // Used for computing the client tag. - password_data.set_origin(kOrigin); - password_data.set_username_element(kUsernameElement); - password_data.set_username_value(kUsernameValue); - password_data.set_password_element(kPasswordElement); - password_data.set_signon_realm(kSignonRealm); - // Other data. - password_data.set_password_value(kLocalPasswordValue); - - passwords_helper::InjectKeystoreEncryptedServerPassword(password_data, - GetFakeServer()); - } - bool SetupSyncTransportWithoutPasswordAccountStorage() { if (!SetupClients()) { return false; @@ -295,47 +191,68 @@ IN_PROC_BROWSER_TEST_F(SingleClientIncomingPasswordSharingInvitationTest, ShouldStoreIncomingPassword) { ASSERT_TRUE(SetupSync()); - InjectInvitationToServer(); - EXPECT_TRUE(PasswordStoredChecker(GetSyncService(0), - GetProfilePasswordStoreInterface(0), - /*expected_count=*/1) - .Wait()); + + sync_pb::PasswordSharingInvitationData invitation_data = + CreateDefaultIncomingInvitation(kUsernameValue, kPasswordValue); + sync_pb::UserDisplayInfo sender_display_info = + CreateDefaultSenderDisplayInfo(); + + PasswordFormsAddedChecker password_forms_added_checker( + GetProfilePasswordStoreInterface(0), + /*expected_new_password_forms=*/1); + InjectInvitationToServer(CreateEncryptedIncomingInvitationSpecifics( + invitation_data, sender_display_info, + /*recipient_public_key=*/GetPublicKeyFromServer(), + syncer::CrossUserSharingPublicPrivateKeyPair::GenerateNewKeyPair())); + + EXPECT_TRUE(password_forms_added_checker.Wait()); std::vector<std::unique_ptr<PasswordForm>> all_logins = GetAllLogins(GetProfilePasswordStoreInterface(0)); ASSERT_EQ(1u, all_logins.size()); const PasswordForm& password_form = *all_logins.front(); - EXPECT_EQ(password_form.signon_realm, kSignonRealm); - EXPECT_EQ(password_form.url.spec(), kOrigin); + const sync_pb::PasswordSharingInvitationData::PasswordGroupData& + invitation_group_data = invitation_data.password_group_data(); + const sync_pb::PasswordSharingInvitationData::PasswordGroupElementData& + invitation_group_element_data = invitation_group_data.element_data(0); + EXPECT_EQ(password_form.signon_realm, + invitation_group_element_data.signon_realm()); + EXPECT_EQ(password_form.url.spec(), invitation_group_element_data.origin()); EXPECT_EQ(base::UTF16ToUTF8(password_form.username_element), - kUsernameElement); - EXPECT_EQ(base::UTF16ToUTF8(password_form.username_value), kUsernameValue); + invitation_group_element_data.username_element()); + EXPECT_EQ(base::UTF16ToUTF8(password_form.username_value), + invitation_group_data.username_value()); EXPECT_EQ(base::UTF16ToUTF8(password_form.password_element), - kPasswordElement); - EXPECT_EQ(base::UTF16ToUTF8(password_form.password_value), kPasswordValue); + invitation_group_element_data.password_element()); + EXPECT_EQ(base::UTF16ToUTF8(password_form.password_value), + invitation_group_data.password_value()); EXPECT_EQ(base::UTF16ToUTF8(password_form.display_name), - kPasswordDisplayName); - EXPECT_EQ(password_form.icon_url.spec(), kPasswordAvatarUrl); - EXPECT_EQ(base::UTF16ToUTF8(password_form.sender_email), kSenderEmail); - EXPECT_EQ(base::UTF16ToUTF8(password_form.sender_name), kSenderDisplayName); + invitation_group_element_data.display_name()); + EXPECT_EQ(password_form.icon_url.spec(), + invitation_group_element_data.avatar_url()); + + EXPECT_EQ(base::UTF16ToUTF8(password_form.sender_email), + sender_display_info.email()); + EXPECT_EQ(base::UTF16ToUTF8(password_form.sender_name), + sender_display_info.display_name()); EXPECT_EQ(password_form.sender_profile_image_url, - GURL(kSenderProfileImageUrl)); + GURL(sender_display_info.profile_image_url())); } IN_PROC_BROWSER_TEST_F(SingleClientIncomingPasswordSharingInvitationTest, ShouldIssueTombstoneAfterProcessingInvitation) { ASSERT_TRUE(SetupSync()); - InjectInvitationToServer(); + PasswordFormsAddedChecker password_forms_added_checker( + GetProfilePasswordStoreInterface(0), + /*expected_new_password_forms=*/1); + InjectInvitationToServer(CreateInvitationSpecifics(GetPublicKeyFromServer())); // Wait the invitation to be processed and the password stored. - ASSERT_TRUE(PasswordStoredChecker(GetSyncService(0), - GetProfilePasswordStoreInterface(0), - /*expected_count=*/1) - .Wait()); + ASSERT_TRUE(password_forms_added_checker.Wait()); // Check that all the invitations are eventually deleted from the server. - // PasswordStoredChecker above guarantees that there is an invitation present - // on the server (which was injected earlier). + // PasswordFormsAddedChecker above guarantees that there is an invitation + // present on the server (which was injected earlier). EXPECT_TRUE(ServerPasswordInvitationChecker(/*expected_count=*/0).Wait()); } @@ -351,14 +268,14 @@ // Then stop sync service, inject an invitation to the server, and re-enable // sync again. GetClient(0)->SignOutPrimaryAccount(); - InjectInvitationToServer(); + InjectInvitationToServer(CreateInvitationSpecifics(GetPublicKeyFromServer())); + PasswordFormsAddedChecker password_forms_added_checker( + GetProfilePasswordStoreInterface(0), + /*expected_new_password_forms=*/1); ASSERT_TRUE(GetClient(0)->SetupSync()); // Wait the invitation to be processed and the password stored. - ASSERT_TRUE(PasswordStoredChecker(GetSyncService(0), - GetProfilePasswordStoreInterface(0), - /*expected_count=*/1) - .Wait()); + ASSERT_TRUE(password_forms_added_checker.Wait()); EXPECT_THAT(GetAllLogins(GetProfilePasswordStoreInterface(0)), Contains(Pointee( AllOf(Field(&PasswordForm::password_value, @@ -373,6 +290,7 @@ IN_PROC_BROWSER_TEST_F( SingleClientIncomingPasswordSharingInvitationTest, ShouldIgnoreIncomingInvitationIfPasswordExistsAtInitialSync) { + constexpr char kLocalPasswordValue[] = "local_password"; base::HistogramTester histogram_tester; // First, setup sync to initialize Nigori node with a public key to be able to @@ -380,18 +298,32 @@ ASSERT_TRUE(SetupSync()); // Then stop sync service, inject an invitation and a different password - // (but having the same client tag to cause a collision) to the server, and - // re-enable sync again. + // (but having the same client tag to cause a collision) to the server. GetClient(0)->SignOutPrimaryAccount(); - InjectTestPasswordToFakeServer(); - InjectInvitationToServer(); + + sync_pb::PasswordSharingInvitationData invitation_data = + CreateDefaultIncomingInvitation(kUsernameValue, kPasswordValue); + InjectInvitationToServer(CreateEncryptedIncomingInvitationSpecifics( + invitation_data, CreateDefaultSenderDisplayInfo(), + /*recipient_public_key=*/GetPublicKeyFromServer(), + /*sender_key_pair=*/ + syncer::CrossUserSharingPublicPrivateKeyPair::GenerateNewKeyPair())); + + sync_pb::PasswordSpecificsData password_data; + password_data.set_password_value(kLocalPasswordValue); + FillPasswordClientTagFromInvitation(invitation_data, &password_data); + passwords_helper::InjectKeystoreEncryptedServerPassword(password_data, + GetFakeServer()); + + PasswordFormsAddedChecker password_forms_added_checker( + GetProfilePasswordStoreInterface(0), + /*expected_new_password_forms=*/1); + + // Re-enable sync again. ASSERT_TRUE(GetClient(0)->SetupSync()); // Wait the password to be stored. - ASSERT_TRUE(PasswordStoredChecker(GetSyncService(0), - GetProfilePasswordStoreInterface(0), - /*expected_count=*/1) - .Wait()); + ASSERT_TRUE(password_forms_added_checker.Wait()); // Verify that the invitation has been processed and a tombstone has been // uploaded. @@ -436,11 +368,11 @@ PasswordSyncActiveChecker(GetSyncService(0)).Wait(); ASSERT_THAT(GetAllLogins(GetAccountPasswordStoreInterface(0)), IsEmpty()); - InjectInvitationToServer(); - EXPECT_TRUE(PasswordStoredChecker(GetSyncService(0), - GetAccountPasswordStoreInterface(0), - /*expected_count=*/1) - .Wait()); + PasswordFormsAddedChecker password_forms_added_checker( + GetAccountPasswordStoreInterface(0), + /*expected_new_password_forms=*/1); + InjectInvitationToServer(CreateInvitationSpecifics(GetPublicKeyFromServer())); + EXPECT_TRUE(password_forms_added_checker.Wait()); EXPECT_TRUE(ServerPasswordInvitationChecker(/*expected_count=*/0).Wait()); EXPECT_THAT(GetAllLogins(GetProfilePasswordStoreInterface(0)), IsEmpty());
diff --git a/chrome/browser/sync/test/integration/single_client_nigori_sync_test.cc b/chrome/browser/sync/test/integration/single_client_nigori_sync_test.cc index f4b478f8..bcba764 100644 --- a/chrome/browser/sync/test/integration/single_client_nigori_sync_test.cc +++ b/chrome/browser/sync/test/integration/single_client_nigori_sync_test.cc
@@ -22,6 +22,7 @@ #include "chrome/browser/sync/test/integration/bookmarks_helper.h" #include "chrome/browser/sync/test/integration/cookie_helper.h" #include "chrome/browser/sync/test/integration/encryption_helper.h" +#include "chrome/browser/sync/test/integration/password_sharing_invitation_helper.h" #include "chrome/browser/sync/test/integration/passwords_helper.h" #include "chrome/browser/sync/test/integration/secondary_account_helper.h" #include "chrome/browser/sync/test/integration/single_client_status_change_checker.h" @@ -46,6 +47,7 @@ #include "components/sync/engine/nigori/cross_user_sharing_public_private_key_pair.h" #include "components/sync/engine/nigori/key_derivation_params.h" #include "components/sync/engine/nigori/nigori.h" +#include "components/sync/nigori/cross_user_sharing_keys.h" #include "components/sync/nigori/cryptographer_impl.h" #include "components/sync/test/fake_server_nigori_helper.h" #include "components/sync/test/nigori_test_utils.h" @@ -83,6 +85,10 @@ using fake_server::GetServerNigori; using fake_server::SetNigoriInFakeServer; +using password_sharing_helper::CreateDefaultIncomingInvitation; +using password_sharing_helper::CreateDefaultSenderDisplayInfo; +using password_sharing_helper::CreateEncryptedIncomingInvitationSpecifics; +using passwords_helper::GetProfilePasswordStoreInterface; using syncer::BuildCustomPassphraseNigoriSpecifics; using syncer::BuildKeystoreNigoriSpecifics; using syncer::BuildTrustedVaultNigoriSpecifics; @@ -94,6 +100,8 @@ using testing::NotNull; using testing::SizeIs; +constexpr int kKeyPairVersion = 0; + MATCHER_P(IsDataEncryptedWith, key_params, "") { const sync_pb::EncryptedData& encrypted_data = arg; std::unique_ptr<syncer::Nigori> nigori = syncer::Nigori::CreateByDerivation( @@ -136,6 +144,15 @@ ->GetKeyName(); } +syncer::CrossUserSharingKeys GenerateNewKeyPair() { + syncer::CrossUserSharingKeys cross_user_sharing_keys = + syncer::CrossUserSharingKeys::CreateEmpty(); + syncer::CrossUserSharingPublicPrivateKeyPair key_pair = + syncer::CrossUserSharingPublicPrivateKeyPair::GenerateNewKeyPair(); + cross_user_sharing_keys.AddKeyPair(std::move(key_pair), kKeyPairVersion); + return cross_user_sharing_keys; +} + class WifiConfigurationsSyncActiveChecker : public SingleClientStatusChangeChecker { public: @@ -287,8 +304,13 @@ : public SingleClientNigoriSyncTest { public: SingleClientNigoriCrossUserSharingPublicPrivateKeyPairSyncTest() { - override_features_.InitAndEnableFeature( - syncer::kSharingOfferKeyPairBootstrap); + // Enable the password receiving flow to verify cross-user sharing keys by + // decrypting incoming password sharing invitations. + override_features_.InitWithFeatures( + /*enabled_features=*/{syncer::kSharingOfferKeyPairBootstrap, + password_manager::features:: + kPasswordManagerEnableReceiverService}, + /*disabled_features=*/{}); } SingleClientNigoriCrossUserSharingPublicPrivateKeyPairSyncTest( @@ -301,6 +323,49 @@ ~SingleClientNigoriCrossUserSharingPublicPrivateKeyPairSyncTest() override = default; + void InjectInvitationToServer( + const sync_pb::IncomingPasswordSharingInvitationSpecifics& + invitation_specifics) { + sync_pb::EntitySpecifics specifics; + specifics.mutable_incoming_password_sharing_invitation()->CopyFrom( + invitation_specifics); + GetFakeServer()->InjectEntity( + syncer::PersistentUniqueClientEntity::CreateFromSpecificsForTesting( + /*non_unique_name=*/"", + /*client_tag=*/ + specifics.incoming_password_sharing_invitation().guid(), specifics, + /*creation_time=*/0, /*last_modified_time=*/0)); + } + + // Returns the current public key from the server. + sync_pb::CrossUserSharingPublicKey GetPublicKeyFromServer() const { + sync_pb::NigoriSpecifics nigori_specifics; + CHECK(fake_server::GetServerNigori(GetFakeServer(), &nigori_specifics)); + CHECK(nigori_specifics.has_cross_user_sharing_public_key()); + return nigori_specifics.cross_user_sharing_public_key(); + } + + void InjectNigoriWithCrossUserSharingKey( + const std::vector<uint8_t>& keystore_key, + const syncer::CrossUserSharingKeys& key_pair) { + const KeyParamsForTesting kDefaultKeyParams = + Pbkdf2PassphraseKeyParamsForTesting("password"); + const KeyParamsForTesting keystore_key_params = + KeystoreKeyParamsForTesting(keystore_key); + SetNigoriInFakeServer( + BuildKeystoreNigoriSpecificsWithCrossUserSharingKeys( + /*keybag_keys_params=*/{kDefaultKeyParams, keystore_key_params}, + /*keystore_decryptor_params*/ {kDefaultKeyParams}, + /*keystore_key_params=*/keystore_key_params, + /*cross_user_sharing_keys=*/key_pair, + /*cross_user_sharing_public_key=*/ + syncer::CrossUserSharingPublicKey::CreateByImport( + key_pair.GetKeyPair(kKeyPairVersion).GetRawPublicKey()) + .value(), + /*cross_user_sharing_public_key_version=*/kKeyPairVersion), + GetFakeServer()); + } + private: base::test::ScopedFeatureList override_features_; }; @@ -736,6 +801,52 @@ } IN_PROC_BROWSER_TEST_F( + SingleClientNigoriCrossUserSharingPublicPrivateKeyPairSyncTest, + ShouldPreferServerKeyPair) { + // Generates a local key pair and uploads it to the server. + ASSERT_TRUE(SetupSync()); + + sync_pb::NigoriSpecifics specifics; + ASSERT_TRUE(GetServerNigori(GetFakeServer(), &specifics)); + ASSERT_TRUE(specifics.has_cross_user_sharing_public_key()); + + const std::vector<std::vector<uint8_t>>& keystore_keys = + GetFakeServer()->GetKeystoreKeys(); + ASSERT_THAT(keystore_keys, SizeIs(1)); + ASSERT_THAT( + specifics.encryption_keybag(), + IsDataEncryptedWith(KeystoreKeyParamsForTesting(keystore_keys.back()))); + + // Mimic server-side Nigori update by some other client. Current client should + // honor the server version of the key pair with the same version. + syncer::CrossUserSharingKeys new_key_pair = GenerateNewKeyPair(); + InjectNigoriWithCrossUserSharingKey(keystore_keys.front(), new_key_pair); + + // There is no easy way to wait for Cryptographer update to make it sure that + // the new key pair is propagated, so use bookmarks to verify that there was a + // sync cycle before testing password sharing. + // TODO(crbug.com/1511180): consider waiting for Cryptographer update rather + // than relying on bookmarks. + GetFakeServer()->InjectEntity(bookmarks_helper::CreateBookmarkServerEntity( + "title", GURL("http://abc.com"))); + ASSERT_TRUE(bookmarks_helper::BookmarksTitleChecker(0, "title", 1).Wait()); + + // Add a new invitation encrypted using the new generated public key. The + // client should be able to decrypt this invitation. + PasswordFormsAddedChecker password_forms_added_checker( + GetProfilePasswordStoreInterface(0), + /*expected_new_password_forms=*/1); + InjectInvitationToServer(CreateEncryptedIncomingInvitationSpecifics( + CreateDefaultIncomingInvitation("username", "password"), + CreateDefaultSenderDisplayInfo(), + /*recipient_public_key=*/GetPublicKeyFromServer(), + syncer::CrossUserSharingPublicPrivateKeyPair::GenerateNewKeyPair())); + + // Wait the invitation to be processed and the password stored. + EXPECT_TRUE(password_forms_added_checker.Wait()); +} + +IN_PROC_BROWSER_TEST_F( SingleClientNigoriCrossUserSharingPublicPrivateKeyPairSyncTestNoIpProt, PRE_ShouldSyncCrossUserSharingPublicPrivateKeyPair) { const std::vector<std::vector<uint8_t>>& keystore_keys =
diff --git a/chrome/browser/ui/omnibox/chrome_omnibox_client.cc b/chrome/browser/ui/omnibox/chrome_omnibox_client.cc index 8fa47393..6fc1619 100644 --- a/chrome/browser/ui/omnibox/chrome_omnibox_client.cc +++ b/chrome/browser/ui/omnibox/chrome_omnibox_client.cc
@@ -514,6 +514,10 @@ return location_bar_->GetLocationBarModel(); } +base::WeakPtr<OmniboxClient> ChromeOmniboxClient::AsWeakPtr() { + return weak_factory_.GetWeakPtr(); +} + void ChromeOmniboxClient::DoPrerender(const AutocompleteMatch& match) { content::WebContents* web_contents = location_bar_->GetWebContents();
diff --git a/chrome/browser/ui/omnibox/chrome_omnibox_client.h b/chrome/browser/ui/omnibox/chrome_omnibox_client.h index 1b4abc7..db1e94d 100644 --- a/chrome/browser/ui/omnibox/chrome_omnibox_client.h +++ b/chrome/browser/ui/omnibox/chrome_omnibox_client.h
@@ -23,7 +23,7 @@ class LocationBar; class Profile; -class ChromeOmniboxClient : public OmniboxClient { +class ChromeOmniboxClient final : public OmniboxClient { public: ChromeOmniboxClient(LocationBar* location_bar, Browser* browser, @@ -106,6 +106,7 @@ IDNA2008DeviationCharacter deviation_char_in_hostname) override; void OnInputInProgress(bool in_progress) override; void OnPopupVisibilityChanged() override; + base::WeakPtr<OmniboxClient> AsWeakPtr() override; LocationBarModel* GetLocationBarModel() override; // Update shortcuts when a navigation succeeds.
diff --git a/chrome/browser/ui/profiles/signin_intercept_first_run_experience_dialog.cc b/chrome/browser/ui/profiles/signin_intercept_first_run_experience_dialog.cc index af85a4c..1aea686 100644 --- a/chrome/browser/ui/profiles/signin_intercept_first_run_experience_dialog.cc +++ b/chrome/browser/ui/profiles/signin_intercept_first_run_experience_dialog.cc
@@ -317,7 +317,6 @@ // TurnSyncOnHelper deletes itself once done. new TurnSyncOnHelper(browser_->profile(), access_point, promo_action, - signin_metrics::Reason::kSigninPrimaryAccount, account_id_, abort_mode, std::make_unique<InterceptTurnSyncOnHelperDelegate>( weak_ptr_factory_.GetWeakPtr()),
diff --git a/chrome/browser/ui/startup/silent_sync_enabler.cc b/chrome/browser/ui/startup/silent_sync_enabler.cc index 229b654..2b67f2e0 100644 --- a/chrome/browser/ui/startup/silent_sync_enabler.cc +++ b/chrome/browser/ui/startup/silent_sync_enabler.cc
@@ -108,8 +108,7 @@ // TurnSyncOnHelper deletes itself once done. new TurnSyncOnHelper( &profile_.get(), signin_metrics::AccessPoint::ACCESS_POINT_UNKNOWN, - signin_metrics::PromoAction::PROMO_ACTION_NO_SIGNIN_PROMO, - signin_metrics::Reason::kSigninPrimaryAccount, account_id, + signin_metrics::PromoAction::PROMO_ACTION_NO_SIGNIN_PROMO, account_id, TurnSyncOnHelper::SigninAbortedMode::KEEP_ACCOUNT, std::make_unique<SilentTurnSyncOnHelperDelegate>(), std::move(callback_)); }
diff --git a/chrome/browser/ui/views/autofill/popup/popup_cell_utils.cc b/chrome/browser/ui/views/autofill/popup/popup_cell_utils.cc index 79c6311e..5c5d1f2 100644 --- a/chrome/browser/ui/views/autofill/popup/popup_cell_utils.cc +++ b/chrome/browser/ui/views/autofill/popup/popup_cell_utils.cc
@@ -55,6 +55,7 @@ // The additional height of the row in case it has two lines of text. constexpr int kAutofillPopupAdditionalDoubleRowHeight = 22; +constexpr int kAutofillPopupAdditionalDoubleRowHeightNewStyle = 16; // The additional padding of the row in case it has three lines of text. constexpr int kAutofillPopupAdditionalPadding = 16; @@ -154,11 +155,16 @@ case Suggestion::Icon::kKey: return ImageViewFromVectorIcon(kKeyIcon, kIconSize); case Suggestion::Icon::kEdit: - return ImageViewFromVectorIcon(vector_icons::kEditIcon, kIconSize); + return ImageViewFromVectorIcon(vector_icons::kEditChromeRefreshIcon, + kIconSize); case Suggestion::Icon::kCode: return ImageViewFromVectorIcon(vector_icons::kCodeIcon, kIconSize); case Suggestion::Icon::kLocation: - return ImageViewFromVectorIcon(vector_icons::kLocationOnIcon, kIconSize); + return ImageViewFromVectorIcon( + ShouldApplyNewAutofillPopupStyle() + ? vector_icons::kLocationOnChromeRefreshIcon + : vector_icons::kLocationOnIcon, + kIconSize); case Suggestion::Icon::kDelete: return ImageViewFromVectorIcon(kTrashCanLightIcon, kIconSize); case Suggestion::Icon::kClear: @@ -430,13 +436,14 @@ layout.set_cross_axis_alignment( views::BoxLayout::CrossAxisAlignment::kCenter); - // Adjust the cell height based on the number of subtexts. - const int kStandardRowHeight = - views::MenuConfig::instance().touchable_menu_height; - const int kActualHeight = - kStandardRowHeight + - (subtext_views.empty() ? 0 : kAutofillPopupAdditionalDoubleRowHeight); - layout.set_minimum_cross_axis_size(kActualHeight); + // Adjust the row height based on the number of subtexts (lines of text). + int row_height = views::MenuConfig::instance().touchable_menu_height; + if (!subtext_views.empty()) { + row_height += ShouldApplyNewAutofillPopupStyle() + ? kAutofillPopupAdditionalDoubleRowHeightNewStyle + : kAutofillPopupAdditionalDoubleRowHeight; + } + layout.set_minimum_cross_axis_size(row_height); // If there are three rows in total, add extra padding to avoid cramming. DCHECK_LE(subtext_views.size(), 2u);
diff --git a/chrome/browser/ui/views/autofill/popup/popup_view_views.cc b/chrome/browser/ui/views/autofill/popup/popup_view_views.cc index 1e00686..209f8728 100644 --- a/chrome/browser/ui/views/autofill/popup/popup_view_views.cc +++ b/chrome/browser/ui/views/autofill/popup/popup_view_views.cc
@@ -38,6 +38,7 @@ #include "components/autofill/core/browser/ui/popup_item_ids.h" #include "components/autofill/core/browser/ui/popup_types.h" #include "components/autofill/core/browser/ui/suggestion.h" +#include "components/autofill/core/common/aliases.h" #include "components/autofill/core/common/autofill_features.h" #include "components/autofill/core/common/autofill_payments_features.h" #include "components/feature_engagement/public/feature_constants.h" @@ -235,43 +236,7 @@ void PopupViewViews::SetSelectedCell(std::optional<CellIndex> cell_index, PopupCellSelectionSource source) { - std::optional<CellIndex> old_index = GetSelectedCell(); - if (old_index == cell_index) { - return; - } - - if (old_index) { - GetPopupRowViewAt(old_index->first).SetSelectedCell(std::nullopt); - } - - if (open_sub_popup_timer_.IsRunning()) { - open_sub_popup_timer_.Stop(); - } - - if (cell_index && HasPopupRowViewAt(cell_index->first)) { - has_keyboard_focus_ = true; - - row_with_selected_cell_ = cell_index->first; - PopupRowView& new_row = GetPopupRowViewAt(cell_index->first); - new_row.SetSelectedCell(cell_index->second); - new_row.ScrollViewToVisible(); - - bool can_open_sub_popup = - cell_index->second == PopupRowView::CellType::kControl && - !controller_->GetSuggestionAt(cell_index->first).children.empty(); - std::optional<size_t> row_with_open_sub_popup = - can_open_sub_popup ? std::optional(cell_index->first) : std::nullopt; - base::TimeDelta delay = source == PopupCellSelectionSource::kMouse - ? kMouseOpenSubPopupDelay - : kNonMouseOpenSubPopupDelay; - open_sub_popup_timer_.Start( - FROM_HERE, delay, - base::BindOnce(&PopupViewViews::SetRowWithOpenSubPopup, - weak_ptr_factory_.GetWeakPtr(), row_with_open_sub_popup, - source)); - } else { - row_with_selected_cell_ = std::nullopt; - } + SetSelectedCell(cell_index, source, AutoselectFirstSuggestion(false)); } bool PopupViewViews::HandleKeyPressEvent( @@ -430,7 +395,7 @@ row.GetExpandChildSuggestionsView()) { SetSelectedCell( CellIndex{selected_cell->first, PopupRowView::CellType::kControl}, - PopupCellSelectionSource::kKeyboard); + PopupCellSelectionSource::kKeyboard, AutoselectFirstSuggestion(true)); return true; } } @@ -494,7 +459,7 @@ if (open_sub_popup_timer_.IsRunning()) { open_sub_popup_timer_.Stop(); } - SetRowWithOpenSubPopup(std::nullopt, PopupCellSelectionSource::kNonUserInput); + SetRowWithOpenSubPopup(std::nullopt); CreateChildViews(); DoUpdateBoundsAndRedrawPopup(); @@ -590,6 +555,52 @@ feature_engagement::kIPHAutofillExternalAccountProfileSuggestionFeature); } +void PopupViewViews::SetSelectedCell( + std::optional<CellIndex> cell_index, + PopupCellSelectionSource source, + AutoselectFirstSuggestion autoselect_first_suggestion) { + std::optional<CellIndex> old_index = GetSelectedCell(); + if (old_index == cell_index) { + return; + } + + if (old_index) { + GetPopupRowViewAt(old_index->first).SetSelectedCell(std::nullopt); + } + + if (open_sub_popup_timer_.IsRunning()) { + open_sub_popup_timer_.Stop(); + } + + if (cell_index && HasPopupRowViewAt(cell_index->first)) { + has_keyboard_focus_ = true; + + row_with_selected_cell_ = cell_index->first; + PopupRowView& new_selected_row = GetPopupRowViewAt(cell_index->first); + new_selected_row.SetSelectedCell(cell_index->second); + new_selected_row.ScrollViewToVisible(); + + bool can_open_sub_popup = + cell_index->second == PopupRowView::CellType::kControl; + + CHECK(!can_open_sub_popup || + !controller_->GetSuggestionAt(cell_index->first).children.empty()); + + std::optional<size_t> row_with_open_sub_popup = + can_open_sub_popup ? std::optional(cell_index->first) : std::nullopt; + base::TimeDelta delay = source == PopupCellSelectionSource::kMouse + ? kMouseOpenSubPopupDelay + : kNonMouseOpenSubPopupDelay; + open_sub_popup_timer_.Start( + FROM_HERE, delay, + base::BindOnce(&PopupViewViews::SetRowWithOpenSubPopup, + weak_ptr_factory_.GetWeakPtr(), row_with_open_sub_popup, + autoselect_first_suggestion)); + } else { + row_with_selected_cell_ = std::nullopt; + } +} + bool PopupViewViews::HasPopupRowViewAt(size_t index) const { return index < rows_.size() && absl::holds_alternative<PopupRowView*>(rows_[index]); @@ -888,7 +899,7 @@ FROM_HERE, kNoSelectionHideSubPopupDelay, base::BindRepeating(&PopupViewViews::SetRowWithOpenSubPopup, weak_ptr_factory_.GetWeakPtr(), std::nullopt, - PopupCellSelectionSource::kNonUserInput)); + AutoselectFirstSuggestion(false))); } bool PopupViewViews::CanShowDropdownInBounds(const gfx::Rect& bounds) const { @@ -911,7 +922,7 @@ void PopupViewViews::SetRowWithOpenSubPopup( std::optional<size_t> row_index, - PopupCellSelectionSource selection_source) { + AutoselectFirstSuggestion autoselect_first_suggestion) { if (row_with_open_sub_popup_ == row_index) { return; } @@ -932,13 +943,12 @@ CHECK(!suggestion.children.empty()); PopupRowView& row = GetPopupRowViewAt(*row_index); - if (controller_->OpenSubPopup( - row.GetControlCellBounds(), suggestion.children, - AutoselectFirstSuggestion(selection_source == - PopupCellSelectionSource::kKeyboard))) { + if (controller_->OpenSubPopup(row.GetControlCellBounds(), + suggestion.children, + autoselect_first_suggestion)) { row.SetChildSuggestionsDisplayed(true); row_with_open_sub_popup_ = row_index; - if (selection_source == PopupCellSelectionSource::kKeyboard) { + if (autoselect_first_suggestion) { row.SetSelectedCell(std::nullopt); } }
diff --git a/chrome/browser/ui/views/autofill/popup/popup_view_views.h b/chrome/browser/ui/views/autofill/popup/popup_view_views.h index b19f1e8..15c59c0 100644 --- a/chrome/browser/ui/views/autofill/popup/popup_view_views.h +++ b/chrome/browser/ui/views/autofill/popup/popup_view_views.h
@@ -111,6 +111,10 @@ private: friend class PopupViewViewsTestApi; + void SetSelectedCell(std::optional<CellIndex> cell_index, + PopupCellSelectionSource source, + AutoselectFirstSuggestion autoselect_first_suggestion); + // Returns the `PopupRowView` at line number `index`. Assumes that there is // such a view at that line number - otherwise the underlying variant will // check false. @@ -181,8 +185,10 @@ // Opens a sub-popup on a new row (and closes the open one if any), or just // closes the existing if `std::nullopt` is passed. - void SetRowWithOpenSubPopup(std::optional<size_t> row_index, - PopupCellSelectionSource selection_source); + void SetRowWithOpenSubPopup( + std::optional<size_t> row_index, + AutoselectFirstSuggestion autoselect_first_suggestion = + AutoselectFirstSuggestion(false)); // Controller for this view. base::WeakPtr<AutofillPopupController> controller_ = nullptr;
diff --git a/chrome/browser/ui/views/autofill/popup/popup_view_views_unittest.cc b/chrome/browser/ui/views/autofill/popup/popup_view_views_unittest.cc index 640bb02..9eab6b0 100644 --- a/chrome/browser/ui/views/autofill/popup/popup_view_views_unittest.cc +++ b/chrome/browser/ui/views/autofill/popup/popup_view_views_unittest.cc
@@ -945,19 +945,28 @@ << "The cell's sub-popup should be closed."; } -TEST_F(PopupViewViewsTest, NoSubPopupOpenIfNotEligible) { - controller().set_suggestions({ +// `PopupViewViewsTest` is not used in death tests because it sets up a complex +// environment (namely creates a `TestingProfile`) that fails to be created in +// the sub-process (see `ASSERT_DEATH` doc for details). This fail hides +// the real death reason to be tested. +using PopupViewViewsDeathTest = ChromeViewsTestBase; +TEST_F(PopupViewViewsDeathTest, OpenSubPopupWithNoChildrenCheckCrash) { + NiceMock<MockAutofillPopupController> controller; + controller.set_suggestions({ // Regular suggestion with no children, Suggestion(u"Suggestion #1"), Suggestion(u"Suggestion #2"), }); - CreateAndShowView(); + std::unique_ptr<views::Widget> widget = CreateTestWidget(); + std::unique_ptr<PopupViewViews> view = + std::make_unique<PopupViewViews>(controller.GetWeakPtr()); + raw_ptr<PopupViewViews> view_ptr = widget->SetContentsView(std::move(view)); + view_ptr->Show(AutoselectFirstSuggestion(false)); - view().SetSelectedCell(CellIndex{0, CellType::kControl}, - PopupCellSelectionSource::kNonUserInput); - task_environment()->FastForwardBy(PopupViewViews::kNonMouseOpenSubPopupDelay); - EXPECT_EQ(test_api(view()).GetOpenSubPopupRow(), std::nullopt) - << "Opening a sub-popup should happen."; + ASSERT_DEATH( + view_ptr->SetSelectedCell(CellIndex{0, CellType::kControl}, + PopupCellSelectionSource::kNonUserInput), + "can_open_sub_popup"); } TEST_F(PopupViewViewsTest, SubPopupHidingOnNoSelection) { @@ -1041,6 +1050,34 @@ EXPECT_EQ(test_api(*sub_view).GetOpenSubPopupRow(), std::nullopt); } +TEST_F(PopupViewViewsTest, SubPopupOpensWithNoAutoselectByMouse) { + controller().set_suggestions({ + CreateSuggestionWithChildren({Suggestion(u"Child #1")}), + }); + CreateAndShowView(); + + EXPECT_CALL(controller(), + OpenSubPopup(_, _, AutoselectFirstSuggestion(false))); + + view().SetSelectedCell(CellIndex{0, CellType::kControl}, + PopupCellSelectionSource::kMouse); + task_environment()->FastForwardBy(PopupViewViews::kMouseOpenSubPopupDelay); +} + +TEST_F(PopupViewViewsTest, SubPopupOpensWithAutoselectByRightKey) { + controller().set_suggestions({ + CreateSuggestionWithChildren({Suggestion(u"Child #1")}), + }); + CreateAndShowView(); + + EXPECT_CALL(controller(), + OpenSubPopup(_, _, AutoselectFirstSuggestion(true))); + + SimulateKeyPress(ui::VKEY_DOWN); + SimulateKeyPress(ui::VKEY_RIGHT); + task_environment()->FastForwardBy(PopupViewViews::kNonMouseOpenSubPopupDelay); +} + // TODO(crbug.com/1489673): Enable once the view shows itself properly. #if !BUILDFLAG(IS_MAC) // Tests that `GetPopupScreenLocation` returns the bounds and arrow position of
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc index 312f2e9..953b201 100644 --- a/chrome/browser/ui/views/frame/browser_view.cc +++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -2608,11 +2608,8 @@ } void BrowserView::OnWidgetShowStateChanged(views::Widget* widget) { -// TODO(crbug.com/1503145): Investigate and fix on MacOS. -#if !BUILDFLAG(IS_MAC) // `display-state` @media feature value in renderer needs to be updated. SynchronizeRenderWidgetHostVisualPropertiesForMainFrame(); -#endif } void BrowserView::PrimaryPageChanged(content::Page& page) {
diff --git a/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc b/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc index 60ca5cb..e20f263 100644 --- a/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc +++ b/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc
@@ -486,6 +486,7 @@ } void ClickEnableLiveCaptionOnDialog() { + base::RunLoop().RunUntilIdle(); base::RunLoop run_loop; PrefChangeRegistrar change_observer; change_observer.Init(browser()->profile()->GetPrefs()); @@ -499,6 +500,7 @@ } void ClickEnableLiveTranslateOnDialog() { + base::RunLoop().RunUntilIdle(); base::RunLoop run_loop; PrefChangeRegistrar change_observer; change_observer.Init(browser()->profile()->GetPrefs());
diff --git a/chrome/browser/ui/views/payments/payment_method_view_controller.cc b/chrome/browser/ui/views/payments/payment_method_view_controller.cc index dd733e1..09df96c 100644 --- a/chrome/browser/ui/views/payments/payment_method_view_controller.cc +++ b/chrome/browser/ui/views/payments/payment_method_view_controller.cc
@@ -12,6 +12,7 @@ #include "base/functional/bind.h" #include "base/functional/callback.h" #include "base/functional/callback_helpers.h" +#include "base/memory/weak_ptr.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/ui/views/chrome_typography.h" #include "chrome/browser/ui/views/payments/payment_request_dialog_view.h" @@ -40,7 +41,7 @@ namespace { -class PaymentMethodListItem : public PaymentRequestItemList::Item { +class PaymentMethodListItem final : public PaymentRequestItemList::Item { public: // Does not take ownership of |app|, which should not be null and should // outlive this object. |list| is the PaymentRequestItemList object that will @@ -67,6 +68,10 @@ ~PaymentMethodListItem() override {} + base::WeakPtr<PaymentRequestRowView> AsWeakPtr() override { + return weak_ptr_factory_.GetWeakPtr(); + } + private: // PaymentRequestItemList::Item: std::unique_ptr<views::View> CreateExtraView() override { @@ -139,6 +144,7 @@ base::WeakPtr<PaymentApp> app_; base::WeakPtr<PaymentRequestDialogView> dialog_; + base::WeakPtrFactory<PaymentMethodListItem> weak_ptr_factory_{this}; }; } // namespace
diff --git a/chrome/browser/ui/views/payments/payment_request_item_list.h b/chrome/browser/ui/views/payments/payment_request_item_list.h index df246cb..e3a9ef3 100644 --- a/chrome/browser/ui/views/payments/payment_request_item_list.h +++ b/chrome/browser/ui/views/payments/payment_request_item_list.h
@@ -9,6 +9,7 @@ #include <vector> #include "base/memory/raw_ptr.h" +#include "base/memory/weak_ptr.h" #include "chrome/browser/ui/views/payments/payment_request_row_view.h" #include "ui/base/metadata/metadata_header_macros.h" @@ -63,6 +64,10 @@ base::WeakPtr<PaymentRequestSpec> spec() { return spec_; } base::WeakPtr<PaymentRequestState> state() { return state_; } + // PaymentRequestRowView overrides + // Leaf classes must override this and provide their own factory. + base::WeakPtr<PaymentRequestRowView> AsWeakPtr() override = 0; + protected: // Initializes the layout and content of the row. Must be called by subclass // constructors, so that virtual methods providing row contents are
diff --git a/chrome/browser/ui/views/payments/payment_request_item_list_unittest.cc b/chrome/browser/ui/views/payments/payment_request_item_list_unittest.cc index 71d9ed9..0da33d2 100644 --- a/chrome/browser/ui/views/payments/payment_request_item_list_unittest.cc +++ b/chrome/browser/ui/views/payments/payment_request_item_list_unittest.cc
@@ -8,6 +8,7 @@ #include <utility> #include <vector> +#include "base/memory/weak_ptr.h" #include "components/payments/content/payment_request_spec.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/mojom/payments/payment_request.mojom.h" @@ -33,8 +34,7 @@ list, selected, /*clickable=*/true, - /*show_edit_button=*/false), - selected_state_changed_calls_count_(0) { + /*show_edit_button=*/false) { Init(); } @@ -45,6 +45,10 @@ return selected_state_changed_calls_count_; } + base::WeakPtr<PaymentRequestRowView> AsWeakPtr() override { + return weak_ptr_factory_.GetWeakPtr(); + } + private: std::unique_ptr<views::View> CreateContentView( std::u16string* accessible_content) override { @@ -63,7 +67,8 @@ ++selected_state_changed_calls_count_; } - int selected_state_changed_calls_count_; + int selected_state_changed_calls_count_ = 0; + base::WeakPtrFactory<TestListItem> weak_ptr_factory_{this}; }; } // namespace
diff --git a/chrome/browser/ui/views/payments/payment_request_row_view.cc b/chrome/browser/ui/views/payments/payment_request_row_view.cc index 2527577..abb43a8 100644 --- a/chrome/browser/ui/views/payments/payment_request_row_view.cc +++ b/chrome/browser/ui/views/payments/payment_request_row_view.cc
@@ -80,6 +80,10 @@ OnPropertyChanged(&clickable_, views::PropertyEffects::kPropertyEffectsPaint); } +base::WeakPtr<PaymentRequestRowView> PaymentRequestRowView::AsWeakPtr() { + return weak_ptr_factory_.GetWeakPtr(); +} + gfx::Insets PaymentRequestRowView::GetRowInsets() const { return row_insets_; }
diff --git a/chrome/browser/ui/views/payments/payment_request_row_view.h b/chrome/browser/ui/views/payments/payment_request_row_view.h index 57d585b..025cafde 100644 --- a/chrome/browser/ui/views/payments/payment_request_row_view.h +++ b/chrome/browser/ui/views/payments/payment_request_row_view.h
@@ -14,9 +14,7 @@ // This class implements a clickable row of the Payment Request dialog that // darkens on hover and displays a horizontal ruler on its lower bound. -class PaymentRequestRowView - : public views::Button, - public base::SupportsWeakPtr<PaymentRequestRowView> { +class PaymentRequestRowView : public views::Button { public: METADATA_HEADER(PaymentRequestRowView); PaymentRequestRowView(); @@ -39,6 +37,9 @@ previous_row_ = previous_row; } + // Deriving classes must override this and provide their own factory. + virtual base::WeakPtr<PaymentRequestRowView> AsWeakPtr(); + private: // Show/hide the separator at the bottom of the row. This is used to hide the // separator when the row is hovered. @@ -71,6 +72,8 @@ // A non-owned pointer to the previous row object in the UI. Used to hide the // bottom border of the previous row when highlighting this one. May be null. base::WeakPtr<PaymentRequestRowView> previous_row_; + + base::WeakPtrFactory<PaymentRequestRowView> weak_ptr_factory_{this}; }; BEGIN_VIEW_BUILDER(, PaymentRequestRowView, views::Button)
diff --git a/chrome/browser/ui/views/payments/profile_list_view_controller.cc b/chrome/browser/ui/views/payments/profile_list_view_controller.cc index 0044b18..d68c323 100644 --- a/chrome/browser/ui/views/payments/profile_list_view_controller.cc +++ b/chrome/browser/ui/views/payments/profile_list_view_controller.cc
@@ -65,6 +65,10 @@ ~ProfileItem() override {} + base::WeakPtr<PaymentRequestRowView> AsWeakPtr() override { + return weak_ptr_factory_.GetWeakPtr(); + } + private: // PaymentRequestItemList::Item: std::unique_ptr<views::View> CreateContentView( @@ -102,6 +106,7 @@ base::WeakPtr<ProfileListViewController> controller_; raw_ptr<autofill::AutofillProfile> profile_; + base::WeakPtrFactory<ProfileItem> weak_ptr_factory_{this}; }; // The ProfileListViewController subtype for the Shipping address list
diff --git a/chrome/browser/ui/views/payments/shipping_option_view_controller.cc b/chrome/browser/ui/views/payments/shipping_option_view_controller.cc index 24bc095..89e4ca68 100644 --- a/chrome/browser/ui/views/payments/shipping_option_view_controller.cc +++ b/chrome/browser/ui/views/payments/shipping_option_view_controller.cc
@@ -21,7 +21,7 @@ namespace { -class ShippingOptionItem : public PaymentRequestItemList::Item { +class ShippingOptionItem final : public PaymentRequestItemList::Item { public: ShippingOptionItem(mojom::PaymentShippingOptionPtr shipping_option, base::WeakPtr<PaymentRequestSpec> spec, @@ -44,6 +44,10 @@ ~ShippingOptionItem() override {} + base::WeakPtr<PaymentRequestRowView> AsWeakPtr() override { + return weak_ptr_factory_.GetWeakPtr(); + } + private: // payments::PaymentRequestItemList::Item: std::unique_ptr<views::View> CreateContentView( @@ -82,6 +86,7 @@ } mojom::PaymentShippingOptionPtr shipping_option_; + base::WeakPtrFactory<ShippingOptionItem> weak_ptr_factory_{this}; }; } // namespace
diff --git a/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc b/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc index 5df321a..7a9b30f 100644 --- a/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc +++ b/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc
@@ -687,7 +687,6 @@ (Profile * profile, signin_metrics::AccessPoint access_point, signin_metrics::PromoAction promo_action, - signin_metrics::Reason signin_reason, const CoreAccountId& account_id, TurnSyncOnHelper::SigninAbortedMode signin_aborted_mode), ()); @@ -762,7 +761,7 @@ browser()->profile(), signin_metrics::AccessPoint::ACCESS_POINT_AVATAR_BUBBLE_SIGN_IN, signin_metrics::PromoAction::PROMO_ACTION_WITH_DEFAULT, - signin_metrics::Reason::kReauthentication, account_info().account_id, + account_info().account_id, TurnSyncOnHelper::SigninAbortedMode::KEEP_ACCOUNT)) .WillOnce([&loop]() { loop.Quit(); });
diff --git a/chrome/browser/ui/views/profiles/profile_picker_dice_sign_in_provider.cc b/chrome/browser/ui/views/profiles/profile_picker_dice_sign_in_provider.cc index 19735abf..d529bbd 100644 --- a/chrome/browser/ui/views/profiles/profile_picker_dice_sign_in_provider.cc +++ b/chrome/browser/ui/views/profiles/profile_picker_dice_sign_in_provider.cc
@@ -262,7 +262,6 @@ Profile* profile, signin_metrics::AccessPoint /*access_point*/, signin_metrics::PromoAction /*promo_action*/, - signin_metrics::Reason /*reason*/, content::WebContents* /*contents*/, const CoreAccountInfo& account_info) { CHECK_EQ(profile, profile_.get());
diff --git a/chrome/browser/ui/views/profiles/profile_picker_dice_sign_in_provider.h b/chrome/browser/ui/views/profiles/profile_picker_dice_sign_in_provider.h index 207cd44..0b6d9604 100644 --- a/chrome/browser/ui/views/profiles/profile_picker_dice_sign_in_provider.h +++ b/chrome/browser/ui/views/profiles/profile_picker_dice_sign_in_provider.h
@@ -114,7 +114,6 @@ void FinishFlowInPicker(Profile* profile, signin_metrics::AccessPoint access_point, signin_metrics::PromoAction promo_action, - signin_metrics::Reason reason, content::WebContents* contents, const CoreAccountInfo& account_info);
diff --git a/chrome/browser/ui/views/profiles/profile_picker_signed_in_flow_controller.cc b/chrome/browser/ui/views/profiles/profile_picker_signed_in_flow_controller.cc index 292dd9e..398a3b9 100644 --- a/chrome/browser/ui/views/profiles/profile_picker_signed_in_flow_controller.cc +++ b/chrome/browser/ui/views/profiles/profile_picker_signed_in_flow_controller.cc
@@ -69,9 +69,6 @@ new TurnSyncOnHelper( profile_, signin_access_point_, signin_metrics::PromoAction::PROMO_ACTION_NO_SIGNIN_PROMO, - signin_util::IsForceSigninEnabled() - ? signin_metrics::Reason::kForcedSigninPrimaryAccount - : signin_metrics::Reason::kSigninPrimaryAccount, account_info.account_id, TurnSyncOnHelper::SigninAbortedMode::KEEP_ACCOUNT, std::make_unique<ProfilePickerTurnSyncOnDelegate>(
diff --git a/chrome/browser/ui/views/side_panel/side_panel.cc b/chrome/browser/ui/views/side_panel/side_panel.cc index b6c185c..29717df5 100644 --- a/chrome/browser/ui/views/side_panel/side_panel.cc +++ b/chrome/browser/ui/views/side_panel/side_panel.cc
@@ -106,32 +106,30 @@ canvas->sk_canvas()->clipRRect(rect, SkClipOp::kDifference, /*do_anti_alias=*/true); - const SkScalar scaled_border_radii[8] = { - border_radii_.upper_left() * dsf, border_radii_.upper_left() * dsf, - border_radii_.upper_right() * dsf, border_radii_.upper_right() * dsf, - border_radii_.lower_right() * dsf, border_radii_.lower_right() * dsf, - border_radii_.lower_left() * dsf, border_radii_.lower_left() * dsf}; - - // Use ToEnclosedRect to make sure that `rounded_border_path` never end up - // larger than the view bounds. - const gfx::Rect scaled_view_bounds = ToEnclosedRect(scaled_view_bounds_f); - - SkPath rounded_border_path; - rounded_border_path.addRoundRect(gfx::RectToSkRect(scaled_view_bounds), - scaled_border_radii, SkPathDirection::kCW); - - // Add another clip to the canvas that rounds the outer corners of the - // border. - canvas->ClipPath(rounded_border_path, /*do_anti_alias=*/true); - - // Draw the top-container background. { - // Redo device-scale factor, the theme background is drawn in DIPs. Note - // that the clip area above is in pixels, hence the - // UndoDeviceScaleFactor() call before this. + // Redo the device scale factor. The theme background and clip for the + // outer corners are drawn in DIPs. Note that the clip area above is in + // pixels because `UndoDeviceScaleFactor()` was called before this. gfx::ScopedCanvas scoped_rescale(canvas); canvas->Scale(dsf, dsf); + const SkScalar border_radii[8] = { + border_radii_.upper_left(), border_radii_.upper_left(), + border_radii_.upper_right(), border_radii_.upper_right(), + border_radii_.lower_right(), border_radii_.lower_right(), + border_radii_.lower_left(), border_radii_.lower_left()}; + + SkPath rounded_border_path; + rounded_border_path.addRoundRect(gfx::RectToSkRect(view.GetLocalBounds()), + border_radii, SkPathDirection::kCW); + + // Add another clip to the canvas that rounds the outer corners of the + // border. This is done in DIPs because for some device scale factors, the + // conversion to pixels can cause the clip to be off by a pixel, resulting + // in a pixel gap between the side panel border and web contents. + canvas->ClipPath(rounded_border_path, /*do_anti_alias=*/true); + + // Draw the top-container background. TopContainerBackground::PaintBackground(canvas, &view, browser_view_); }
diff --git a/chrome/browser/ui/webui/realbox/realbox_handler.cc b/chrome/browser/ui/webui/realbox/realbox_handler.cc index 9310104..b1d1d3aa 100644 --- a/chrome/browser/ui/webui/realbox/realbox_handler.cc +++ b/chrome/browser/ui/webui/realbox/realbox_handler.cc
@@ -8,6 +8,7 @@ #include "base/base64url.h" #include "base/containers/contains.h" #include "base/functional/bind.h" +#include "base/memory/weak_ptr.h" #include "base/metrics/histogram_macros.h" #include "base/metrics/user_metrics.h" #include "base/metrics/user_metrics_action.h" @@ -453,7 +454,7 @@ // TODO(crbug.com/1431513): Consider inheriting from `ChromeOmniboxClient` // to avoid reimplementation of methods like `OnBookmarkLaunched`. -class RealboxOmniboxClient : public OmniboxClient { +class RealboxOmniboxClient final : public OmniboxClient { public: RealboxOmniboxClient(LocationBarModel* location_bar_model, Profile* profile, @@ -495,12 +496,14 @@ const AutocompleteMatch& alternative_nav_match, IDNA2008DeviationCharacter deviation_char_in_hostname) override; LocationBarModel* GetLocationBarModel() override; + base::WeakPtr<OmniboxClient> AsWeakPtr() override; private: raw_ptr<LocationBarModel> location_bar_model_; raw_ptr<Profile> profile_; raw_ptr<content::WebContents> web_contents_; ChromeAutocompleteSchemeClassifier scheme_classifier_; + base::WeakPtrFactory<RealboxOmniboxClient> weak_factory_{this}; }; RealboxOmniboxClient::RealboxOmniboxClient(LocationBarModel* location_bar_model, @@ -611,6 +614,10 @@ return location_bar_model_; } +base::WeakPtr<OmniboxClient> RealboxOmniboxClient::AsWeakPtr() { + return weak_factory_.GetWeakPtr(); +} + } // namespace // static
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc b/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc index 80012ef..062d43a 100644 --- a/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc +++ b/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc
@@ -397,8 +397,6 @@ signin_metrics::AccessPoint::ACCESS_POINT_FORCED_SIGNIN, signin_metrics::SourceForRefreshTokenOperation:: kInlineLoginHandler_Signin); - - signin_metrics::LogSigninReason(signin_metrics::Reason::kReauthentication); } else { if (confirm_untrusted_signin_) { // Display a confirmation dialog to the user. @@ -462,8 +460,7 @@ new TurnSyncOnHelper( profile_, signin::GetAccessPointForEmbeddedPromoURL(current_url_), - signin_metrics::PromoAction::PROMO_ACTION_NO_SIGNIN_PROMO, - signin::GetSigninReasonForEmbeddedPromoURL(current_url_), account_id, + signin_metrics::PromoAction::PROMO_ACTION_NO_SIGNIN_PROMO, account_id, TurnSyncOnHelper::SigninAbortedMode::REMOVE_ACCOUNT, std::move(delegate), base::BindOnce(&OnSigninComplete, profile_, email_, password_, is_force_sign_in_with_usermanager_));
diff --git a/chrome/browser/ui/webui/signin/turn_sync_on_helper.cc b/chrome/browser/ui/webui/signin/turn_sync_on_helper.cc index 6198ff9c..232820c 100644 --- a/chrome/browser/ui/webui/signin/turn_sync_on_helper.cc +++ b/chrome/browser/ui/webui/signin/turn_sync_on_helper.cc
@@ -194,7 +194,6 @@ Profile* profile, signin_metrics::AccessPoint signin_access_point, signin_metrics::PromoAction signin_promo_action, - signin_metrics::Reason signin_reason, const CoreAccountId& account_id, SigninAbortedMode signin_aborted_mode, std::unique_ptr<Delegate> delegate, @@ -204,7 +203,6 @@ identity_manager_(IdentityManagerFactory::GetForProfile(profile)), signin_access_point_(signin_access_point), signin_promo_action_(signin_promo_action), - signin_reason_(signin_reason), signin_aborted_mode_(signin_aborted_mode), account_info_( identity_manager_->FindExtendedAccountInfoByAccountId(account_id)), @@ -237,13 +235,11 @@ Browser* browser, signin_metrics::AccessPoint signin_access_point, signin_metrics::PromoAction signin_promo_action, - signin_metrics::Reason signin_reason, const CoreAccountId& account_id, SigninAbortedMode signin_aborted_mode) : TurnSyncOnHelper(profile, signin_access_point, signin_promo_action, - signin_reason, account_id, signin_aborted_mode, std::make_unique<TurnSyncOnHelperDelegateImpl>(browser), @@ -500,10 +496,8 @@ signin_access_point_); // If the account is already signed in, `SetPrimaryAccount()` above is a no-op // and the logs below are inaccurate. - // TODO(crbug.com/1402935): Review and rebuild the SigninReason logging. signin_metrics::LogSigninAccessPointCompleted(signin_access_point_, signin_promo_action_); - signin_metrics::LogSigninReason(signin_reason_); base::RecordAction(base::UserMetricsAction("Signin_Signin_Succeed")); bool user_accepted_management =
diff --git a/chrome/browser/ui/webui/signin/turn_sync_on_helper.h b/chrome/browser/ui/webui/signin/turn_sync_on_helper.h index 590a55c..f945ad5f 100644 --- a/chrome/browser/ui/webui/signin/turn_sync_on_helper.h +++ b/chrome/browser/ui/webui/signin/turn_sync_on_helper.h
@@ -140,7 +140,6 @@ TurnSyncOnHelper(Profile* profile, signin_metrics::AccessPoint signin_access_point, signin_metrics::PromoAction signin_promo_action, - signin_metrics::Reason signin_reason, const CoreAccountId& account_id, SigninAbortedMode signin_aborted_mode, std::unique_ptr<Delegate> delegate, @@ -151,7 +150,6 @@ Browser* browser, signin_metrics::AccessPoint signin_access_point, signin_metrics::PromoAction signin_promo_action, - signin_metrics::Reason signin_reason, const CoreAccountId& account_id, SigninAbortedMode signin_aborted_mode); @@ -252,7 +250,6 @@ raw_ptr<signin::IdentityManager> identity_manager_; const signin_metrics::AccessPoint signin_access_point_; const signin_metrics::PromoAction signin_promo_action_; - const signin_metrics::Reason signin_reason_; // Whether the refresh token should be deleted if the Sync flow is aborted. SigninAbortedMode signin_aborted_mode_;
diff --git a/chrome/browser/ui/webui/signin/turn_sync_on_helper_browsertest.cc b/chrome/browser/ui/webui/signin/turn_sync_on_helper_browsertest.cc index 8959b06..08a037f 100644 --- a/chrome/browser/ui/webui/signin/turn_sync_on_helper_browsertest.cc +++ b/chrome/browser/ui/webui/signin/turn_sync_on_helper_browsertest.cc
@@ -235,8 +235,8 @@ new TurnSyncOnHelper( profile, signin_metrics::AccessPoint::ACCESS_POINT_UNKNOWN, signin_metrics::PromoAction::PROMO_ACTION_NO_SIGNIN_PROMO, - signin_metrics::Reason::kUnknownReason, second_account_id, aborted_mode(), - std::move(owned_delegate), run_loop.QuitClosure()); + second_account_id, aborted_mode(), std::move(owned_delegate), + run_loop.QuitClosure()); delegate->WaitUntilBlock(); EXPECT_EQ(Delegate::BlockingStep::kSyncConfirmation, @@ -353,8 +353,7 @@ base::WeakPtr<Delegate> delegate = owned_delegate->GetWeakPtr(); new TurnSyncOnHelper( profile, signin_metrics::AccessPoint::ACCESS_POINT_UNKNOWN, - signin_metrics::PromoAction::PROMO_ACTION_NO_SIGNIN_PROMO, - signin_metrics::Reason::kUnknownReason, account_id, + signin_metrics::PromoAction::PROMO_ACTION_NO_SIGNIN_PROMO, account_id, TurnSyncOnHelper::SigninAbortedMode::REMOVE_ACCOUNT, std::move(owned_delegate), run_loop.QuitClosure()); @@ -419,7 +418,7 @@ new TurnSyncOnHelper( profile, signin_metrics::AccessPoint::ACCESS_POINT_UNKNOWN, signin_metrics::PromoAction::PROMO_ACTION_NO_SIGNIN_PROMO, - signin_metrics::Reason::kUnknownReason, first_account_id, + first_account_id, TurnSyncOnHelper::SigninAbortedMode::KEEP_ACCOUNT_ON_WEB_ONLY, std::move(owned_delegate), run_loop.QuitClosure()); @@ -475,7 +474,7 @@ new TurnSyncOnHelper( profile, signin_metrics::AccessPoint::ACCESS_POINT_UNKNOWN, signin_metrics::PromoAction::PROMO_ACTION_NO_SIGNIN_PROMO, - signin_metrics::Reason::kUnknownReason, second_account_id, + second_account_id, TurnSyncOnHelper::SigninAbortedMode::KEEP_ACCOUNT_ON_WEB_ONLY, std::move(owned_delegate), run_loop.QuitClosure()); @@ -534,8 +533,7 @@ new TurnSyncOnHelper( profile, signin_metrics::AccessPoint::ACCESS_POINT_UNKNOWN, signin_metrics::PromoAction::PROMO_ACTION_NO_SIGNIN_PROMO, - signin_metrics::Reason::kUnknownReason, second_account_id, - TurnSyncOnHelper::SigninAbortedMode::REMOVE_ACCOUNT, + second_account_id, TurnSyncOnHelper::SigninAbortedMode::REMOVE_ACCOUNT, std::move(owned_delegate), run_loop.QuitClosure()); delegate->WaitUntilBlock();
diff --git a/chrome/browser/ui/webui/signin/turn_sync_on_helper_unittest.cc b/chrome/browser/ui/webui/signin/turn_sync_on_helper_unittest.cc index b819c8d..eb45f2b 100644 --- a/chrome/browser/ui/webui/signin/turn_sync_on_helper_unittest.cc +++ b/chrome/browser/ui/webui/signin/turn_sync_on_helper_unittest.cc
@@ -96,8 +96,6 @@ signin_metrics::AccessPoint::ACCESS_POINT_BOOKMARK_MANAGER; const signin_metrics::PromoAction kSigninPromoAction = signin_metrics::PromoAction::PROMO_ACTION_WITH_DEFAULT; -const signin_metrics::Reason kSigninReason = - signin_metrics::Reason::kReauthentication; struct ExpectedMetricsState { // Access point that triggered sign-in, might be different from the one @@ -564,8 +562,8 @@ WeakClosure weak_closure; auto* helper = new TurnSyncOnHelper( - profile(), kAccessPoint, kSigninPromoAction, kSigninReason, account_id_, - mode, std::make_unique<TestTurnSyncOnHelperDelegate>(this), + profile(), kAccessPoint, kSigninPromoAction, account_id_, mode, + std::make_unique<TestTurnSyncOnHelperDelegate>(this), weak_closure.Get().Then(flow_completion_loop_.QuitClosure())); // In no circumstance should the flow complete synchronously. It can cause @@ -670,8 +668,6 @@ EXPECT_THAT( histogram_tester_->GetAllSamples("Signin.SigninCompletedAccessPoint"), BucketsAre(Bucket(kAccessPoint, expected.sign_in_recorded))); - EXPECT_THAT(histogram_tester_->GetAllSamples("Signin.SigninReason"), - BucketsAre(Bucket(kSigninReason, expected.sign_in_recorded))); EXPECT_THAT(histogram_tester_->GetAllSamples("Signin.SyncOptIn.Completed"), BucketsAre(Bucket(kAccessPoint,
diff --git a/chrome/browser/web_applications/test/web_app_test.h b/chrome/browser/web_applications/test/web_app_test.h index 0aeb552..3d988893 100644 --- a/chrome/browser/web_applications/test/web_app_test.h +++ b/chrome/browser/web_applications/test/web_app_test.h
@@ -41,14 +41,13 @@ explicit WebAppTest(WebAppTestTraits&&... traits) : content::RenderViewHostTestHarness( base::trait_helpers::Exclude<WithTestUrlLoaderFactory>::Filter( - traits)...), - shared_url_loader_factory_( - base::trait_helpers::HasTrait<WithTestUrlLoaderFactory, - WebAppTestTraits...>() - ? base::MakeRefCounted< - network::WeakWrapperSharedURLLoaderFactory>( - &test_url_loader_factory_) - : nullptr) {} + traits)...) { + shared_url_loader_factory_ = + base::trait_helpers::HasTrait<WithTestUrlLoaderFactory, + WebAppTestTraits...>() + ? test_url_loader_factory_.GetSafeWeakWrapper() + : nullptr; + } ~WebAppTest() override; @@ -76,9 +75,9 @@ private: base::TimeTicks start_time_ = base::TimeTicks::Now(); + network::TestURLLoaderFactory test_url_loader_factory_; scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_ = nullptr; - network::TestURLLoaderFactory test_url_loader_factory_; TestingProfileManager testing_profile_manager_{ TestingBrowserProcess::GetGlobal()};
diff --git a/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc b/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc index 746976ad..d7b3d44 100644 --- a/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc +++ b/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
@@ -28,6 +28,7 @@ #include "chrome/browser/net/system_network_context_manager.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_observer.h" +#include "chrome/browser/signin/identity_manager_factory.h" #include "chrome/browser/sync/device_info_sync_service_factory.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_finder.h" @@ -48,6 +49,7 @@ #include "components/network_session_configurator/common/network_switches.h" #include "components/pref_registry/pref_registry_syncable.h" #include "components/prefs/pref_service.h" +#include "components/signin/public/identity_manager/identity_manager.h" #include "components/sync/base/features.h" #include "components/sync/protocol/webauthn_credential_specifics.pb.h" #include "components/user_prefs/user_prefs.h" @@ -70,6 +72,7 @@ #include "extensions/browser/extension_registry.h" #include "extensions/common/constants.h" #include "extensions/common/permissions/permissions_data.h" +#include "google_apis/gaia/gaia_constants.h" #include "net/base/url_util.h" #include "third_party/icu/source/common/unicode/locid.h" #include "third_party/icu/source/i18n/unicode/timezone.h" @@ -1232,6 +1235,23 @@ Profile::FromBrowserContext(GetBrowserContext())); CHECK(passkey_model); + base::OnceCallback<void(GoogleServiceAuthError error, + signin::AccessTokenInfo access_token_info)> + callback = base::BindOnce( + &ChromeAuthenticatorRequestDelegate::EnclaveAccessTokenFetched, + weak_ptr_factory_.GetWeakPtr(), + discovery_factory->get_enclave_oauth_token_callback()); + + auto* identity_manager = IdentityManagerFactory::GetForProfile( + Profile::FromBrowserContext(GetBrowserContext())); + access_token_fetcher_ = + std::make_unique<signin::PrimaryAccountAccessTokenFetcher>( + "enclave", identity_manager, + signin::ScopeSet{GaiaConstants::kPasskeysEnclaveOAuth2Scope}, + std::move(callback), + signin::PrimaryAccountAccessTokenFetcher::Mode::kImmediate, + signin::ConsentLevel::kSignin); + std::vector<sync_pb::WebauthnCredentialSpecifics> passkeys = passkey_model->GetPasskeysForRelyingPartyId(rp_id); discovery_factory->set_enclave_passkeys(std::move(passkeys)); @@ -1240,6 +1260,23 @@ weak_ptr_factory_.GetWeakPtr())); } +void ChromeAuthenticatorRequestDelegate::EnclaveAccessTokenFetched( + base::RepeatingCallback<void(absl::optional<std::string_view>)> callback, + GoogleServiceAuthError error, + signin::AccessTokenInfo access_token_info) { + access_token_fetcher_.release(); + + if (error.state() != GoogleServiceAuthError::NONE) { + FIDO_LOG(ERROR) + << "Cloud enclave authenticator access token retrieval failed " + << error.state(); + callback.Run(absl::nullopt); + return; + } + + callback.Run(access_token_info.token); +} + void ChromeAuthenticatorRequestDelegate::OnPasskeyCreated( sync_pb::WebauthnCredentialSpecifics passkey) { webauthn::PasskeyModel* passkey_model =
diff --git a/chrome/browser/webauthn/chrome_authenticator_request_delegate.h b/chrome/browser/webauthn/chrome_authenticator_request_delegate.h index 2572fef0..1b69303 100644 --- a/chrome/browser/webauthn/chrome_authenticator_request_delegate.h +++ b/chrome/browser/webauthn/chrome_authenticator_request_delegate.h
@@ -7,6 +7,7 @@ #include <memory> #include <string> +#include <string_view> #include "base/functional/callback.h" #include "base/gtest_prod_util.h" @@ -15,11 +16,14 @@ #include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "chrome/browser/webauthn/authenticator_request_dialog_model.h" +#include "components/signin/public/identity_manager/access_token_info.h" +#include "components/signin/public/identity_manager/primary_account_access_token_fetcher.h" #include "content/public/browser/authenticator_request_client_delegate.h" #include "content/public/browser/global_routing_id.h" #include "device/fido/cable/cable_discovery_data.h" #include "device/fido/fido_request_handler_base.h" #include "device/fido/fido_transport_protocol.h" +#include "google_apis/gaia/google_service_auth_error.h" #include "third_party/abseil-cpp/absl/types/optional.h" class PrefService; @@ -262,6 +266,12 @@ // Invoked when a new GPM passkey is created, to save it to sync data. void OnPasskeyCreated(sync_pb::WebauthnCredentialSpecifics passkey); + // Invoked when an OAuth access token is available for the Enclave. + void EnclaveAccessTokenFetched( + base::RepeatingCallback<void(absl::optional<std::string_view>)> callback, + GoogleServiceAuthError error, + signin::AccessTokenInfo access_token_info); + #if BUILDFLAG(IS_MAC) // DaysSinceDate returns the number of days between `formatted_date` (in ISO // 8601 format) and `now`. It returns `nullopt` if `formatted_date` cannot be @@ -332,6 +342,10 @@ // True when the cloud enclave authenticator is available for use. bool is_enclave_authenticator_available_ = false; + // Fetcher for OAuth access tokens needed to use the enclave authenticator. + std::unique_ptr<signin::PrimaryAccountAccessTokenFetcher> + access_token_fetcher_; + base::WeakPtrFactory<ChromeAuthenticatorRequestDelegate> weak_ptr_factory_{ this}; };
diff --git a/chrome/build/android-arm32.pgo.txt b/chrome/build/android-arm32.pgo.txt index e2495ec..fcae0e6 100644 --- a/chrome/build/android-arm32.pgo.txt +++ b/chrome/build/android-arm32.pgo.txt
@@ -1 +1 @@ -chrome-android32-main-1703656685-4ceeedd1983a1474df6512d04b4bc2d25d37d7bc.profdata +chrome-android32-main-1703699887-b7b5a1b6cf662080d4ff6160a7ff1fbf42ff0aec.profdata
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt index f008ddb7..83c485dd 100644 --- a/chrome/build/android-arm64.pgo.txt +++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@ -chrome-android64-main-1703656685-484810fd30a28e34694055a6a8d90b24dd817f5d.profdata +chrome-android64-main-1703699887-adef7540ce01e38a008d3e5bb75bf085bcdba05b.profdata
diff --git a/chrome/build/lacros-arm64.pgo.txt b/chrome/build/lacros-arm64.pgo.txt index 91c053f4..c1b2208 100644 --- a/chrome/build/lacros-arm64.pgo.txt +++ b/chrome/build/lacros-arm64.pgo.txt
@@ -1 +1 @@ -chrome-chromeos-arm64-generic-main-1703635025-7a609de957b058cd3008335fa7971e14eef55433.profdata +chrome-chromeos-arm64-generic-main-1703678262-c23ff425500e44dbc7ededc6e40f7ffb27eb854c.profdata
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index 43b4844..c582f8c 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-main-1703656685-6c3ada8f7270d5b8693b4a8790819a89999ea4e0.profdata +chrome-linux-main-1703699887-fc0284ff1f4f0af5272ad7f572c6837c4b74d2e9.profdata
diff --git a/chrome/build/win-arm64.pgo.txt b/chrome/build/win-arm64.pgo.txt index ef264eb..f6010d6 100644 --- a/chrome/build/win-arm64.pgo.txt +++ b/chrome/build/win-arm64.pgo.txt
@@ -1 +1 @@ -chrome-win-arm64-main-1703656685-3f809da454b56ce78a267e2ed20f9aa1db0b25e5.profdata +chrome-win-arm64-main-1703699887-d143abbc0907129f08d61457a3c0fea73b22c712.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index 5fc0c8f4..03bc524 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1703656685-d48a250b9ac191874f5e79c08af37f38ec53c7d4.profdata +chrome-win32-main-1703699887-a5553e522bff004627b52c2b21ccaffce785956c.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index 4319ec2..ce3d4a2 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1703656685-bad04019e5a74364e58815b7b7b6d005e9aa431b.profdata +chrome-win64-main-1703699887-b31c169884dd06741e6b5a30923fca564ed81ab3.profdata
diff --git a/chrome/common/extensions/api/autotest_private.idl b/chrome/common/extensions/api/autotest_private.idl index 89626fb8..5d496141 100644 --- a/chrome/common/extensions/api/autotest_private.idl +++ b/chrome/common/extensions/api/autotest_private.idl
@@ -374,7 +374,9 @@ dictionary ArcAppTracingInfo { boolean success; double fps; + double perceivedFps; double commitDeviation; + double presentDeviation; double renderQuality; };
diff --git a/chrome/common/extensions/chrome_manifest_url_handlers.cc b/chrome/common/extensions/chrome_manifest_url_handlers.cc index 4623c1a5..fc6ab157 100644 --- a/chrome/common/extensions/chrome_manifest_url_handlers.cc +++ b/chrome/common/extensions/chrome_manifest_url_handlers.cc
@@ -67,8 +67,7 @@ GURL url = extension->GetResourceURL(*devtools_str); const bool is_extension_url = url.SchemeIs(kExtensionScheme) && url.host_piece() == extension->id(); - // TODO(caseq): using http(s) is unsupported and will be disabled in m83. - if (!is_extension_url && !url.SchemeIsHTTPOrHTTPS()) { + if (!is_extension_url) { *error = errors::kInvalidDevToolsPage; return false; }
diff --git a/chrome/common/extensions/manifest_tests/extension_manifests_devtools_unittest.cc b/chrome/common/extensions/manifest_tests/extension_manifests_devtools_unittest.cc index feb8ea6..874a2d8 100644 --- a/chrome/common/extensions/manifest_tests/extension_manifests_devtools_unittest.cc +++ b/chrome/common/extensions/manifest_tests/extension_manifests_devtools_unittest.cc
@@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/files/scoped_temp_dir.h" +#include "base/strings/utf_string_conversions.h" #include "chrome/common/extensions/chrome_manifest_url_handlers.h" #include "chrome/common/extensions/manifest_tests/chrome_manifest_test.h" #include "extensions/common/extension.h" @@ -19,17 +21,41 @@ LoadAndExpectError("devtools_extension_invalid_page_url.json", extensions::manifest_errors::kInvalidDevToolsPage); - // TODO(caseq): the implementation should be changed to produce failure - // with the manifest below. - scoped_refptr<extensions::Extension> extension; - extension = LoadAndExpectSuccess("devtools_extension_page_url_https.json"); - EXPECT_EQ("https://bad.example.com/dont_ever_do_this.html", - extensions::chrome_manifest_urls::GetDevToolsPage(extension.get()) - .spec()); + LoadAndExpectError("devtools_extension_page_url_https.json", + extensions::manifest_errors::kInvalidDevToolsPage); - extension = LoadAndExpectSuccess("devtools_extension.json"); + scoped_refptr<extensions::Extension> extension = + LoadAndExpectSuccess("devtools_extension.json"); EXPECT_EQ(extension->url().spec() + "devtools.html", extensions::chrome_manifest_urls::GetDevToolsPage(extension.get()) .spec()); EXPECT_TRUE(extension->permissions_data()->HasEffectiveAccessToAllHosts()); } + +TEST_F(DevToolsPageManifestTest, DevToolsPageAbsoluteUrl) { + auto manifest = base::Value::Dict() + .Set("name", "test") + .Set("version", "1") + .Set("manifest_version", 3) + .Set("devtools_page", "chrome-extension://someid/path"); + std::string error; + base::ScopedTempDir dir; + ASSERT_TRUE(dir.CreateUniqueTempDir()); + scoped_refptr<extensions::Extension> extension = + extensions::Extension::Create( + dir.GetPath(), extensions::mojom::ManifestLocation::kInternal, + manifest, extensions::Extension::NO_FLAGS, "someid", &error); + ASSERT_TRUE(extension.get()); + EXPECT_TRUE(error.empty()); + + // Specifying an absolute URL for a different extension's resource should + // fail, similar to other remote sources. + extension = extensions::Extension::Create( + dir.GetPath(), extensions::mojom::ManifestLocation::kInternal, manifest, + extensions::Extension::NO_FLAGS, "otherid", &error); + ASSERT_FALSE(extension); + ASSERT_FALSE(error.empty()); + EXPECT_EQ( + base::UTF16ToUTF8(extensions::manifest_errors::kInvalidDevToolsPage), + error); +}
diff --git a/chrome/renderer/accessibility/read_anything_app_model.cc b/chrome/renderer/accessibility/read_anything_app_model.cc index e97b5d6..0815b7a 100644 --- a/chrome/renderer/accessibility/read_anything_app_model.cc +++ b/chrome/renderer/accessibility/read_anything_app_model.cc
@@ -166,6 +166,13 @@ ui::AXNode* end_node = GetAXNode(end_node_id_); DCHECK(end_node); + if (!start_node || !end_node) { + DUMP_WILL_BE_NOTREACHED_NORETURN() + << "Selection is invalid. Start node existed? " << !!start_node + << " End node existed? " << !!end_node; + return; + } + // If start node or end node is invisible or ignored, the selection was // invalid. if (start_node->IsInvisibleOrIgnored() || end_node->IsInvisibleOrIgnored()) {
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 62d77ff..7ae1358b 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -11604,6 +11604,8 @@ "../browser/sync/test/integration/multi_client_status_change_checker.h", "../browser/sync/test/integration/offer_helper.cc", "../browser/sync/test/integration/offer_helper.h", + "../browser/sync/test/integration/password_sharing_invitation_helper.cc", + "../browser/sync/test/integration/password_sharing_invitation_helper.h", "../browser/sync/test/integration/passwords_helper.cc", "../browser/sync/test/integration/passwords_helper.h", "../browser/sync/test/integration/quiesce_status_change_checker.cc",
diff --git a/chrome/test/data/webui/compose/compose_app_test.ts b/chrome/test/data/webui/compose/compose_app_test.ts index aae7710a..a284f22 100644 --- a/chrome/test/data/webui/compose/compose_app_test.ts +++ b/chrome/test/data/webui/compose/compose_app_test.ts
@@ -623,7 +623,7 @@ assertTrue(isVisible(app.$.lengthMenu), 'Length menu should be visible.'); assertEquals( - 2, app.$.lengthMenu.querySelectorAll('option:not([hidden])').length); + 2, app.$.lengthMenu.querySelectorAll('option:not([disabled])').length); app.$.lengthMenu.value = `${Length.kShorter}`; app.$.lengthMenu.dispatchEvent(new CustomEvent('change')); @@ -637,7 +637,7 @@ assertTrue(isVisible(app.$.toneMenu), 'Tone menu should be visible.'); assertEquals( - 2, app.$.toneMenu.querySelectorAll('option:not([hidden])').length); + 2, app.$.toneMenu.querySelectorAll('option:not([disabled])').length); app.$.toneMenu.value = `${Tone.kCasual}`; app.$.toneMenu.dispatchEvent(new CustomEvent('change'));
diff --git a/chromeos/ash/components/audio/cras_audio_handler.cc b/chromeos/ash/components/audio/cras_audio_handler.cc index 736f471..79cc902 100644 --- a/chromeos/ash/components/audio/cras_audio_handler.cc +++ b/chromeos/ash/components/audio/cras_audio_handler.cc
@@ -2406,11 +2406,6 @@ // Unmute the audio output after the HDMI transition period. VLOG(1) << "Unmute output after HDMI rediscovering grace period."; SetOutputMuteInternal(false); - - // Notify UI about the mute state change. - for (auto& observer : observers_) { - observer.OnOutputMuteChanged(output_mute_on_); - } } }
diff --git a/chromeos/ash/components/audio/cras_audio_handler_unittest.cc b/chromeos/ash/components/audio/cras_audio_handler_unittest.cc index 4fe97590..9999cd0 100644 --- a/chromeos/ash/components/audio/cras_audio_handler_unittest.cc +++ b/chromeos/ash/components/audio/cras_audio_handler_unittest.cc
@@ -200,7 +200,7 @@ int output_mute_changed_count() const { return output_mute_changed_count_; } - void reset_output_mute_changed_count() { input_mute_changed_count_ = 0; } + void reset_output_mute_changed_count() { output_mute_changed_count_ = 0; } int input_mute_changed_count() const { return input_mute_changed_count_; } @@ -4603,8 +4603,8 @@ EXPECT_FALSE(cras_audio_handler_->IsOutputMuted()); } -// This tests the case of output unmuting event is notified after the hdmi -// output re-discover grace period ends, see crbug.com/512601. +// This tests the case of output unmuting event is not notified after the hdmi +// output re-discover grace period ends. TEST_P(CrasAudioHandlerTest, HDMIOutputUnplugDuringSuspension) { AudioNodeList audio_nodes = GenerateAudioNodeList({kInternalSpeaker, kHDMIOutput}); @@ -4638,7 +4638,7 @@ EXPECT_TRUE(cras_audio_handler_->IsOutputMuted()); // After HDMI re-discover grace period, verify internal speaker is still the - // active output and not muted, and unmute event by system is notified. + // active output and not muted. test_observer_->reset_output_mute_changed_count(); HDMIRediscoverWaiter waiter(this, grace_period_in_ms); waiter.WaitUntilHDMIRediscoverGracePeriodEnd(); @@ -4648,7 +4648,7 @@ EXPECT_EQ(kInternalSpeaker->id, cras_audio_handler_->GetPrimaryActiveOutputNode()); EXPECT_FALSE(cras_audio_handler_->IsOutputMuted()); - EXPECT_EQ(1, test_observer_->output_mute_changed_count()); + EXPECT_EQ(0, test_observer_->output_mute_changed_count()); } TEST_P(CrasAudioHandlerTest, FrontCameraStartStop) {
diff --git a/chromeos/ash/components/fwupd/firmware_update_manager.cc b/chromeos/ash/components/fwupd/firmware_update_manager.cc index ed31f6c..aad1cac 100644 --- a/chromeos/ash/components/fwupd/firmware_update_manager.cc +++ b/chromeos/ash/components/fwupd/firmware_update_manager.cc
@@ -42,25 +42,6 @@ namespace ash { namespace { -// State of the fwupd daemon. Enum defined here: -// https://github.com/fwupd/fwupd/blob/4389f9f913588edae7243a8dbed88ce3788c8bc2/libfwupd/fwupd-enums.h -enum class FwupdStatus { - kUnknown, - kIdle, - kLoading, - kDecompressing, - kDeviceRestart, - kDeviceWrite, - kDeviceVerify, - kScheduling, - kDownloading, - kDeviceRead, - kDeviceErase, - kWaitingForAuth, - kDeviceBusy, - kShutdown, - kWaitingForUser, -}; static constexpr auto FwupdStatusStringMap = base::MakeFixedFlatMap<FwupdStatus, const char*>( @@ -353,6 +334,7 @@ install_controller_receiver_.reset(); update_progress_observer_.reset(); device_request_observer_.reset(); + last_fwupd_status_ = FwupdStatus::kUnknown; } void FirmwareUpdateManager::PrepareForUpdate( @@ -673,6 +655,9 @@ void FirmwareUpdateManager::OnInstallResponse(bool success) { auto state = success ? firmware_update::mojom::UpdateState::kSuccess : firmware_update::mojom::UpdateState::kFailed; + if (!success) { + firmware_update::metrics::EmitInstallFailedWithStatus(last_fwupd_status_); + } const auto result = success ? firmware_update::metrics::FirmwareUpdateInstallResult::kSuccess : firmware_update::metrics::FirmwareUpdateInstallResult:: @@ -726,6 +711,7 @@ return; } const auto status = FwupdStatus(properties->status.value()); + last_fwupd_status_ = status; const auto percentage = properties->percentage.value(); VLOG(1) << "fwupd: OnPropertiesChangedResponse called with Status: " << GetFwupdStatusString(static_cast<FwupdStatus>(status))
diff --git a/chromeos/ash/components/fwupd/firmware_update_manager.h b/chromeos/ash/components/fwupd/firmware_update_manager.h index f1d8a7eb..90bb1961 100644 --- a/chromeos/ash/components/fwupd/firmware_update_manager.h +++ b/chromeos/ash/components/fwupd/firmware_update_manager.h
@@ -35,6 +35,29 @@ } // namespace network namespace ash { + +// State of the fwupd daemon. Enum defined here: +// https://github.com/fwupd/fwupd/blob/4389f9f913588edae7243a8dbed88ce3788c8bc2/libfwupd/fwupd-enums.h +// Keep in sync with corresponding enum in tools/metrics/histograms/enums.xml. +enum class FwupdStatus { + kUnknown, + kIdle, + kLoading, + kDecompressing, + kDeviceRestart, + kDeviceWrite, + kDeviceVerify, + kScheduling, + kDownloading, + kDeviceRead, + kDeviceErase, + kWaitingForAuth, + kDeviceBusy, + kShutdown, + kWaitingForUser, + kMaxValue = kWaitingForUser, +}; + // FirmwareUpdateManager contains all logic that runs the firmware update SWA. class COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_FWUPD) FirmwareUpdateManager : public FwupdClient::Observer, @@ -220,6 +243,9 @@ // The device update that is currently inflight. firmware_update::mojom::FirmwareUpdatePtr inflight_update_; + // The most recent FwupdStatus, used for the purpose of recording metrics. + FwupdStatus last_fwupd_status_ = FwupdStatus::kUnknown; + // Used to show the firmware update notification and to determine which // metric to fire (Startup/Refresh). bool is_first_response_ = true;
diff --git a/chromeos/ash/components/fwupd/firmware_update_manager_unittest.cc b/chromeos/ash/components/fwupd/firmware_update_manager_unittest.cc index 7fd7e28..c3eb608 100644 --- a/chromeos/ash/components/fwupd/firmware_update_manager_unittest.cc +++ b/chromeos/ash/components/fwupd/firmware_update_manager_unittest.cc
@@ -247,6 +247,30 @@ base::RunLoop().RunUntilIdle(); } + firmware_update::mojom::FirmwareUpdatePtr CreateFakeUpdate() { + auto update = firmware_update::mojom::FirmwareUpdate::New(); + update->device_id = "id"; + update->device_name = base::UTF8ToUTF16(std::string("name")); + update->device_version = "version"; + update->device_description = base::UTF8ToUTF16(std::string("description")); + update->priority = firmware_update::mojom::UpdatePriority::kMedium; + update->filepath = base::FilePath("filepath"); + update->checksum = "checksum"; + return update; + } + + void TriggerInstallFailed() { + // Create a fake update so that the following method call works correctly. + firmware_update_manager_->inflight_update_ = CreateFakeUpdate(); + // Trigger an unsuccessful update. + firmware_update_manager_->OnInstallResponse(/*success=*/false); + base::RunLoop().RunUntilIdle(); + } + + void SetStatus(FwupdStatus fwupd_status) { + SetProperties(/*percentage=*/0, static_cast<uint32_t>(fwupd_status)); + } + void SetFakeUrlForTesting(const std::string& fake_url) { firmware_update_manager_->SetFakeUrlForTesting(fake_url); } @@ -1158,4 +1182,53 @@ firmware_update::mojom::DeviceRequestId::kPressUnlock, 1); } +struct FailedInstallParam { + explicit FailedInstallParam(FwupdStatus fwupd_status) + : fwupd_status(fwupd_status) {} + + FwupdStatus fwupd_status; +}; + +class FirmwareUpdateManagerTest_FailedInstall + : public FirmwareUpdateManagerTest, + public testing::WithParamInterface<FailedInstallParam> {}; + +INSTANTIATE_TEST_SUITE_P( + FirmwareUpdateManagerTest_FailedInstall, + FirmwareUpdateManagerTest_FailedInstall, + ::testing::Values(FailedInstallParam(FwupdStatus::kUnknown), + FailedInstallParam(FwupdStatus::kIdle), + FailedInstallParam(FwupdStatus::kLoading), + FailedInstallParam(FwupdStatus::kDecompressing), + FailedInstallParam(FwupdStatus::kDeviceRestart), + FailedInstallParam(FwupdStatus::kDeviceWrite), + FailedInstallParam(FwupdStatus::kDeviceVerify), + FailedInstallParam(FwupdStatus::kScheduling), + FailedInstallParam(FwupdStatus::kDownloading), + FailedInstallParam(FwupdStatus::kDeviceRead), + FailedInstallParam(FwupdStatus::kDeviceErase), + FailedInstallParam(FwupdStatus::kWaitingForAuth), + FailedInstallParam(FwupdStatus::kDeviceBusy), + FailedInstallParam(FwupdStatus::kShutdown), + FailedInstallParam(FwupdStatus::kWaitingForUser))); + +TEST_P(FirmwareUpdateManagerTest_FailedInstall, FailedInstall_WaitingForUser) { + base::HistogramTester histogram_tester; + + // These three steps are necessary for SetStatus and TriggerInstallFailed to + // work correctly. + EXPECT_TRUE(PrepareForUpdate(std::string(kFakeDeviceIdForTesting))); + FakeUpdateProgressObserver update_progress_observer; + SetupProgressObserver(&update_progress_observer); + + SetStatus(GetParam().fwupd_status); + TriggerInstallFailed(); + + histogram_tester.ExpectTotalCount( + "ChromeOS.FirmwareUpdateUi.InstallFailedWithStatus", 1); + histogram_tester.ExpectUniqueSample( + "ChromeOS.FirmwareUpdateUi.InstallFailedWithStatus", + GetParam().fwupd_status, 1); +} + } // namespace ash
diff --git a/chromeos/ash/components/fwupd/histogram_util.cc b/chromeos/ash/components/fwupd/histogram_util.cc index ba506c8f..0512498 100644 --- a/chromeos/ash/components/fwupd/histogram_util.cc +++ b/chromeos/ash/components/fwupd/histogram_util.cc
@@ -32,6 +32,11 @@ num_updates); } +void EmitInstallFailedWithStatus(FwupdStatus last_fwupd_status) { + base::UmaHistogramEnumeration( + "ChromeOS.FirmwareUpdateUi.InstallFailedWithStatus", last_fwupd_status); +} + void EmitInstallResult(FirmwareUpdateInstallResult result) { base::UmaHistogramEnumeration("ChromeOS.FirmwareUpdateUi.InstallResult", result);
diff --git a/chromeos/ash/components/fwupd/histogram_util.h b/chromeos/ash/components/fwupd/histogram_util.h index 5275350..0f00fa87 100644 --- a/chromeos/ash/components/fwupd/histogram_util.h +++ b/chromeos/ash/components/fwupd/histogram_util.h
@@ -9,6 +9,7 @@ #include <string> #include "ash/webui/firmware_update_ui/mojom/firmware_update.mojom.h" +#include "chromeos/ash/components/fwupd/firmware_update_manager.h" namespace ash::firmware_update::metrics { @@ -31,6 +32,7 @@ int num_critical_updates, bool is_startup); +void EmitInstallFailedWithStatus(FwupdStatus last_fwupd_status); void EmitInstallResult(FirmwareUpdateInstallResult result); void EmitDeviceRequest(firmware_update::mojom::DeviceRequestPtr request);
diff --git a/chromeos/profiles/arm-exp.afdo.newest.txt b/chromeos/profiles/arm-exp.afdo.newest.txt index 75bc69b..c118873 100644 --- a/chromeos/profiles/arm-exp.afdo.newest.txt +++ b/chromeos/profiles/arm-exp.afdo.newest.txt
@@ -1 +1 @@ -chromeos-chrome-arm-exp-121-6167.9-1702295304-benchmark-122.0.6191.0-r1-redacted.afdo.xz +chromeos-chrome-arm-exp-122-6167.14-1703504610-benchmark-122.0.6195.0-r3-redacted.afdo.xz
diff --git a/chromeos/profiles/arm.afdo.newest.txt b/chromeos/profiles/arm.afdo.newest.txt index 9b794e02..c522991 100644 --- a/chromeos/profiles/arm.afdo.newest.txt +++ b/chromeos/profiles/arm.afdo.newest.txt
@@ -1 +1 @@ -chromeos-chrome-arm-none-121-6154.0-1702299075-benchmark-122.0.6191.0-r1-redacted.afdo.xz +chromeos-chrome-arm-none-122-6167.14-1703508819-benchmark-122.0.6195.0-r3-redacted.afdo.xz
diff --git a/chromeos/profiles/atom.afdo.newest.txt b/chromeos/profiles/atom.afdo.newest.txt index 08dc9c97..e87b76cf 100644 --- a/chromeos/profiles/atom.afdo.newest.txt +++ b/chromeos/profiles/atom.afdo.newest.txt
@@ -1 +1 @@ -chromeos-chrome-amd64-atom-122-6167.14-1702898748-benchmark-122.0.6192.0-r1-redacted.afdo.xz +chromeos-chrome-amd64-atom-122-6167.14-1703504610-benchmark-122.0.6195.0-r3-redacted.afdo.xz
diff --git a/clank b/clank index 99685ad..8224cc0 160000 --- a/clank +++ b/clank
@@ -1 +1 @@ -Subproject commit 99685ad0653a10fa9254bf04244740661468e99e +Subproject commit 8224cc0dada49684ca5f40d26820ec2d3962ee33
diff --git a/components/certificate_transparency/data/log_list.json b/components/certificate_transparency/data/log_list.json index 3e21953..4233d7b3 100644 --- a/components/certificate_transparency/data/log_list.json +++ b/components/certificate_transparency/data/log_list.json
@@ -1,6 +1,6 @@ { - "version": "29.7", - "log_list_timestamp": "2023-12-26T12:55:30Z", + "version": "29.8", + "log_list_timestamp": "2023-12-27T12:54:53Z", "operators": [ { "name": "Google",
diff --git a/components/feedback/content/content_tracing_manager.cc b/components/feedback/content/content_tracing_manager.cc index efddca3..dd270ba 100644 --- a/components/feedback/content/content_tracing_manager.cc +++ b/components/feedback/content/content_tracing_manager.cc
@@ -103,6 +103,10 @@ } } +base::WeakPtr<TracingManager> ContentTracingManager::AsWeakPtr() { + return weak_ptr_factory_.GetWeakPtr(); +} + void ContentTracingManager::StartTracing() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); content::TracingController::GetInstance()->StartTracing(
diff --git a/components/feedback/content/content_tracing_manager.h b/components/feedback/content/content_tracing_manager.h index c06027f..ef00a480 100644 --- a/components/feedback/content/content_tracing_manager.h +++ b/components/feedback/content/content_tracing_manager.h
@@ -25,7 +25,7 @@ // version of the performance data. That data can then be requested via // GetTraceData(). When the data is no longer needed, it should be discarded // via DiscardTraceData(). -class ContentTracingManager : public TracingManager { +class ContentTracingManager final : public TracingManager { public: ~ContentTracingManager() override; @@ -46,6 +46,8 @@ // Discard the data for trace |id|. void DiscardTraceData(int id) override; + base::WeakPtr<TracingManager> AsWeakPtr() override; + private: ContentTracingManager();
diff --git a/components/feedback/feedback_data.cc b/components/feedback/feedback_data.cc index ce42b09..26d3331 100644 --- a/components/feedback/feedback_data.cc +++ b/components/feedback/feedback_data.cc
@@ -41,7 +41,7 @@ // sending the report. If it is created after this point, then the tracing is // not relevant to this report. if (tracing_manager) { - tracing_manager_ = base::AsWeakPtr(tracing_manager); + tracing_manager_ = tracing_manager->AsWeakPtr(); } }
diff --git a/components/feedback/tracing_manager.h b/components/feedback/tracing_manager.h index 9da2b23f..d638223 100644 --- a/components/feedback/tracing_manager.h +++ b/components/feedback/tracing_manager.h
@@ -25,7 +25,7 @@ // of the performance data. That data can then be requested via GetTraceData(). // When the data is no longer needed, it should be discarded via // DiscardTraceData(). -class TracingManager : public base::SupportsWeakPtr<TracingManager> { +class TracingManager { public: virtual ~TracingManager(); @@ -43,9 +43,12 @@ // Discard the data for trace |id|. virtual void DiscardTraceData(int id) = 0; + // Derived classes must implement this and return pointers from + // a `base::WeakPtrFactory` data member. + virtual base::WeakPtr<TracingManager> AsWeakPtr() = 0; + protected: TracingManager(); }; #endif // COMPONENTS_FEEDBACK_TRACING_MANAGER_H_ -
diff --git a/components/history/core/browser/expire_history_backend.h b/components/history/core/browser/expire_history_backend.h index 6dd21fc9..b019bff 100644 --- a/components/history/core/browser/expire_history_backend.h +++ b/components/history/core/browser/expire_history_backend.h
@@ -281,9 +281,8 @@ raw_ptr<HistoryBackendNotifier> notifier_; // Non-owning pointers to the databases we deal with (MAY BE NULL). - raw_ptr<HistoryDatabase, AcrossTasksDanglingUntriaged> - main_db_; // Main history database. - raw_ptr<favicon::FaviconDatabase, AcrossTasksDanglingUntriaged> favicon_db_; + raw_ptr<HistoryDatabase> main_db_; // Main history database. + raw_ptr<favicon::FaviconDatabase> favicon_db_; // The threshold for "old" history where we will automatically delete it. base::TimeDelta expiration_threshold_; @@ -310,7 +309,7 @@ std::unique_ptr<ExpiringVisitsReader> auto_subframe_visits_reader_; // The HistoryBackendClient; may be null. - raw_ptr<HistoryBackendClient, AcrossTasksDanglingUntriaged> backend_client_; + raw_ptr<HistoryBackendClient> backend_client_; scoped_refptr<base::SequencedTaskRunner> task_runner_;
diff --git a/components/history/core/browser/history_backend.cc b/components/history/core/browser/history_backend.cc index de94ef1..7c6deea 100644 --- a/components/history/core/browser/history_backend.cc +++ b/components/history/core/browser/history_backend.cc
@@ -363,9 +363,9 @@ std::unique_ptr<HistoryBackendClient> backend_client, scoped_refptr<base::SequencedTaskRunner> task_runner) : delegate_(std::move(delegate)), - expirer_(this, backend_client.get(), task_runner), recent_redirects_(kMaxRedirectCount), backend_client_(std::move(backend_client)), + expirer_(this, backend_client_.get(), task_runner), task_runner_(task_runner) { DCHECK(delegate_); } @@ -1334,6 +1334,9 @@ } void HistoryBackend::CloseAllDatabases() { + // Reset to avoid dangling pointers to the database. + history_sync_bridge_.reset(); + expirer_.SetDatabases(/*main_db=*/nullptr, /*favicon_db=*/nullptr); if (db_) { CommitSingletonTransactionIfItExists(); db_.reset(); @@ -3246,7 +3249,6 @@ singleton_transaction_ = db_->CreateTransaction(); bool success = singleton_transaction_->Begin(); - UMA_HISTOGRAM_BOOLEAN("History.Backend.TransactionBeginSuccess", success); if (success) { DCHECK_EQ(db_->transaction_nesting(), 1); } else {
diff --git a/components/history/core/browser/history_backend.h b/components/history/core/browser/history_backend.h index 1e316477..f8ae30f5 100644 --- a/components/history/core/browser/history_backend.h +++ b/components/history/core/browser/history_backend.h
@@ -1042,9 +1042,6 @@ bool scheduled_kill_db_ = false; // Database is being killed due to error. std::unique_ptr<favicon::FaviconBackend> favicon_backend_; - // Manages expiration between the various databases. - ExpireHistoryBackend expirer_; - // A commit has been scheduled to occur sometime in the future. We can check // !IsCancelled() to see if there is a commit scheduled in the future (note // that CancelableOnceClosure starts cancelled with the default constructor), @@ -1080,6 +1077,9 @@ // Used to determine if a URL is bookmarked; may be null. std::unique_ptr<HistoryBackendClient> backend_client_; + // Manages expiration between the various databases. + ExpireHistoryBackend expirer_; + scoped_refptr<base::SequencedTaskRunner> task_runner_; // Listens for the system being under memory pressure.
diff --git a/components/history/core/browser/history_backend_unittest.cc b/components/history/core/browser/history_backend_unittest.cc index 50ec1cc..bcc3f857 100644 --- a/components/history/core/browser/history_backend_unittest.cc +++ b/components/history/core/browser/history_backend_unittest.cc
@@ -217,6 +217,7 @@ using HistoryBackend::UpdateVisitDuration; using HistoryBackend::db_; + using HistoryBackend::expirer_; using HistoryBackend::favicon_backend_; using HistoryBackend::recent_redirects_; @@ -2851,6 +2852,7 @@ // Check that UpdateFaviconMappingsAndFetch() call back to the UI when there is // no valid favicon database. TEST_F(HistoryBackendTest, UpdateFaviconMappingsAndFetchNoDB) { + backend_->expirer_.SetDatabases(/*main_db=*/nullptr, /*favicon_db=*/nullptr); // Make the favicon database invalid. backend_->favicon_backend_.reset();
diff --git a/components/history/core/browser/sync/history_sync_bridge.h b/components/history/core/browser/sync/history_sync_bridge.h index af9875b..f166f90a 100644 --- a/components/history/core/browser/sync/history_sync_bridge.h +++ b/components/history/core/browser/sync/history_sync_bridge.h
@@ -154,8 +154,7 @@ // A non-owning pointer to the database, which is for storing sync metadata // and state. Can be null in case of unrecoverable database errors. - raw_ptr<HistorySyncMetadataDatabase, AcrossTasksDanglingUntriaged> - sync_metadata_database_; + raw_ptr<HistorySyncMetadataDatabase> sync_metadata_database_; // HistoryBackend uses SequencedTaskRunner, so this makes sure // HistorySyncBridge is used on the correct sequence.
diff --git a/components/omnibox/browser/in_memory_url_index.h b/components/omnibox/browser/in_memory_url_index.h index 3c963151..25cb364 100644 --- a/components/omnibox/browser/in_memory_url_index.h +++ b/components/omnibox/browser/in_memory_url_index.h
@@ -16,7 +16,6 @@ #include "base/gtest_prod_util.h" #include "base/memory/raw_ptr.h" #include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" #include "base/scoped_observation.h" #include "base/task/cancelable_task_tracker.h" #include "base/threading/thread_checker.h" @@ -72,7 +71,6 @@ // multi-char16 instance. class InMemoryURLIndex : public KeyedService, public history::HistoryServiceObserver, - public base::SupportsWeakPtr<InMemoryURLIndex>, public base::trace_event::MemoryDumpProvider { public: // `history_service` may be null during unit testing.
diff --git a/components/omnibox/browser/omnibox_client.h b/components/omnibox/browser/omnibox_client.h index 972f4591..59589e2b 100644 --- a/components/omnibox/browser/omnibox_client.h +++ b/components/omnibox/browser/omnibox_client.h
@@ -51,7 +51,7 @@ // (e.g., getting information about the current page, retrieving objects // associated with the current tab, or performing operations that rely on such // objects under the hood). -class OmniboxClient : public base::SupportsWeakPtr<OmniboxClient> { +class OmniboxClient { public: OmniboxClient() = default; virtual ~OmniboxClient() = default; @@ -219,6 +219,8 @@ virtual void OnPopupVisibilityChanged() {} virtual LocationBarModel* GetLocationBarModel() = 0; + + virtual base::WeakPtr<OmniboxClient> AsWeakPtr() = 0; }; #endif // COMPONENTS_OMNIBOX_BROWSER_OMNIBOX_CLIENT_H_
diff --git a/components/omnibox/browser/test_omnibox_client.cc b/components/omnibox/browser/test_omnibox_client.cc index 24e8515..2963bb6 100644 --- a/components/omnibox/browser/test_omnibox_client.cc +++ b/components/omnibox/browser/test_omnibox_client.cc
@@ -111,3 +111,7 @@ void TestOmniboxClient::OnURLOpenedFromOmnibox(OmniboxLog* log) { last_log_disposition_ = log->disposition; } + +base::WeakPtr<OmniboxClient> TestOmniboxClient::AsWeakPtr() { + return weak_factory_.GetWeakPtr(); +}
diff --git a/components/omnibox/browser/test_omnibox_client.h b/components/omnibox/browser/test_omnibox_client.h index 20f70a6..07b1f06d 100644 --- a/components/omnibox/browser/test_omnibox_client.h +++ b/components/omnibox/browser/test_omnibox_client.h
@@ -8,6 +8,7 @@ #include <memory> #include "base/memory/raw_ptr.h" +#include "base/memory/weak_ptr.h" #include "components/omnibox/browser/autocomplete_classifier.h" #include "components/omnibox/browser/autocomplete_match.h" #include "components/omnibox/browser/autocomplete_provider_client.h" @@ -22,7 +23,7 @@ class AutocompleteSchemeClassifier; // Fake implementation of OmniboxClient for use in tests. -class TestOmniboxClient : public testing::NiceMock<OmniboxClient> { +class TestOmniboxClient final : public testing::NiceMock<OmniboxClient> { public: TestOmniboxClient(); ~TestOmniboxClient() override; @@ -67,6 +68,8 @@ MOCK_METHOD(bookmarks::BookmarkModel*, GetBookmarkModel, ()); MOCK_METHOD(PrefService*, GetPrefs, ()); + base::WeakPtr<OmniboxClient> AsWeakPtr() override; + WindowOpenDisposition last_log_disposition() const { return last_log_disposition_; } @@ -77,6 +80,7 @@ TestSchemeClassifier scheme_classifier_; AutocompleteClassifier autocomplete_classifier_; WindowOpenDisposition last_log_disposition_; + base::WeakPtrFactory<TestOmniboxClient> weak_factory_{this}; }; #endif // COMPONENTS_OMNIBOX_BROWSER_TEST_OMNIBOX_CLIENT_H_
diff --git a/components/optimization_guide/core/hints_manager.h b/components/optimization_guide/core/hints_manager.h index 939f2f7..de5d258 100644 --- a/components/optimization_guide/core/hints_manager.h +++ b/components/optimization_guide/core/hints_manager.h
@@ -522,8 +522,7 @@ raw_ptr<TopHostProvider, DanglingUntriaged> top_host_provider_ = nullptr; // The tab URL provider that can be queried. Not owned. - raw_ptr<TabUrlProvider, AcrossTasksDanglingUntriaged> tab_url_provider_ = - nullptr; + raw_ptr<TabUrlProvider> tab_url_provider_ = nullptr; // The timer used to schedule fetching hints from the remote Optimization // Guide Service.
diff --git a/components/optimization_guide/internal b/components/optimization_guide/internal index 1bd7f39..5e31ebc 160000 --- a/components/optimization_guide/internal +++ b/components/optimization_guide/internal
@@ -1 +1 @@ -Subproject commit 1bd7f39830947c4615bf1d40810c3adf862d20bc +Subproject commit 5e31ebc3259a7849928fafb8bdeb3cd8ca48c8d8
diff --git a/components/page_load_metrics/browser/metrics_web_contents_observer.h b/components/page_load_metrics/browser/metrics_web_contents_observer.h index 40adc4484..a07f3d23 100644 --- a/components/page_load_metrics/browser/metrics_web_contents_observer.h +++ b/components/page_load_metrics/browser/metrics_web_contents_observer.h
@@ -12,6 +12,7 @@ #include "base/memory/raw_ptr.h" #include "base/memory/read_only_shared_memory_region.h" +#include "base/memory/weak_ptr.h" #include "base/observer_list.h" #include "base/time/time.h" #include "components/page_load_metrics/browser/page_load_metrics_observer.h" @@ -47,7 +48,6 @@ : public content::WebContentsObserver, public content::WebContentsUserData<MetricsWebContentsObserver>, public content::RenderWidgetHost::InputEventObserver, - public base::SupportsWeakPtr<MetricsWebContentsObserver>, public mojom::PageLoadMetrics { public: // Record a set of WebFeatures directly from the browser process. This @@ -170,6 +170,10 @@ // Returns the time this MetricsWebContentsObserver was created. base::TimeTicks GetCreated(); + base::WeakPtr<MetricsWebContentsObserver> AsWeakPtr() { + return weak_ptr_factory_.GetWeakPtr(); + } + protected: // Protected rather than private so that derived test classes can call // constructor. @@ -363,6 +367,8 @@ base::TimeTicks created_; + base::WeakPtrFactory<MetricsWebContentsObserver> weak_ptr_factory_{this}; + WEB_CONTENTS_USER_DATA_KEY_DECL(); };
diff --git a/components/page_load_metrics/browser/observers/ad_metrics/frame_tree_data.h b/components/page_load_metrics/browser/observers/ad_metrics/frame_tree_data.h index 5b59920c..e1829b0 100644 --- a/components/page_load_metrics/browser/observers/ad_metrics/frame_tree_data.h +++ b/components/page_load_metrics/browser/observers/ad_metrics/frame_tree_data.h
@@ -121,7 +121,7 @@ // typically used to capture an ad creative. It stores frame-specific // information (such as size, activation status, and origin), which is typically // specific to the top frame in the tree. -class FrameTreeData : public base::SupportsWeakPtr<FrameTreeData> { +class FrameTreeData final { public: using FrameTreeNodeId = PageLoadMetricsObserver::FrameTreeNodeId; @@ -255,6 +255,10 @@ return peak_cpu_.peak_windowed_percent(); } + base::WeakPtr<FrameTreeData> AsWeakPtr() { + return weak_ptr_factory_.GetWeakPtr(); + } + private: // Updates whether or not this frame meets the criteria for visibility. void UpdateFrameVisibility(); @@ -345,6 +349,9 @@ // Memory usage by v8 in this ad frame tree. MemoryUsageAggregator memory_usage_; + + // Owns weak pointers to the instance. + base::WeakPtrFactory<FrameTreeData> weak_ptr_factory_{this}; }; } // namespace page_load_metrics
diff --git a/components/page_load_metrics/common/test/weak_mock_timer.cc b/components/page_load_metrics/common/test/weak_mock_timer.cc index a7a1ce1..ae10ec03 100644 --- a/components/page_load_metrics/common/test/weak_mock_timer.cc +++ b/components/page_load_metrics/common/test/weak_mock_timer.cc
@@ -7,10 +7,11 @@ namespace page_load_metrics { namespace test { -WeakMockTimer::WeakMockTimer() {} +WeakMockTimer::WeakMockTimer() = default; +WeakMockTimer::~WeakMockTimer() = default; -WeakMockTimerProvider::WeakMockTimerProvider() {} -WeakMockTimerProvider::~WeakMockTimerProvider() {} +WeakMockTimerProvider::WeakMockTimerProvider() = default; +WeakMockTimerProvider::~WeakMockTimerProvider() = default; base::MockOneShotTimer* WeakMockTimerProvider::GetMockTimer() const { return timer_.get();
diff --git a/components/page_load_metrics/common/test/weak_mock_timer.h b/components/page_load_metrics/common/test/weak_mock_timer.h index c82982e..4ff4274 100644 --- a/components/page_load_metrics/common/test/weak_mock_timer.h +++ b/components/page_load_metrics/common/test/weak_mock_timer.h
@@ -12,13 +12,20 @@ namespace test { // WeakMockTimer is a MockTimer that allows clients to keep WeakPtr<>s to it. -class WeakMockTimer : public base::MockOneShotTimer, - public base::SupportsWeakPtr<WeakMockTimer> { +class WeakMockTimer final : public base::MockOneShotTimer { public: WeakMockTimer(); + ~WeakMockTimer() override; WeakMockTimer(const WeakMockTimer&) = delete; WeakMockTimer& operator=(const WeakMockTimer&) = delete; + + base::WeakPtr<WeakMockTimer> AsWeakPtr() { + return weak_ptr_factory_.GetWeakPtr(); + } + + private: + base::WeakPtrFactory<WeakMockTimer> weak_ptr_factory_{this}; }; // WeakMockTimerProvider is a testing helper class that test classes can inherit
diff --git a/components/password_manager/core/browser/affiliation/affiliation_service_impl.cc b/components/password_manager/core/browser/affiliation/affiliation_service_impl.cc index 7c531089..7d6a6938 100644 --- a/components/password_manager/core/browser/affiliation/affiliation_service_impl.cc +++ b/components/password_manager/core/browser/affiliation/affiliation_service_impl.cc
@@ -248,7 +248,10 @@ void AffiliationServiceImpl::GetGroupingInfo(std::vector<FacetURI> facet_uris, GroupsCallback callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(backend_); + // If `backend` is destroyed there is nothing to do. + if (!backend_) { + return; + } backend_task_runner_->PostTaskAndReplyWithResult( FROM_HERE, @@ -260,7 +263,11 @@ void AffiliationServiceImpl::GetPSLExtensions( base::OnceCallback<void(std::vector<std::string>)> callback) const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(backend_); + // If `backend` is destroyed there is nothing to do. + if (!backend_) { + return; + } + backend_task_runner_->PostTaskAndReplyWithResult( FROM_HERE, base::BindOnce(&AffiliationBackend::GetPSLExtensions,
diff --git a/components/password_manager/core/browser/affiliation/affiliation_service_impl.h b/components/password_manager/core/browser/affiliation/affiliation_service_impl.h index d88c890f..6afb118 100644 --- a/components/password_manager/core/browser/affiliation/affiliation_service_impl.h +++ b/components/password_manager/core/browser/affiliation/affiliation_service_impl.h
@@ -136,7 +136,11 @@ template <typename Method, typename... Args> void PostToBackend(const Method& method, Args&&... args) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - CHECK(backend_); + // If `backend` is destroyed there is nothing to do. + if (!backend_) { + return; + } + backend_task_runner_->PostTask( FROM_HERE, base::BindOnce(method, base::Unretained(backend_.get()), std::forward<Args>(args)...));
diff --git a/components/password_manager/core/browser/password_reuse_detector.cc b/components/password_manager/core/browser/password_reuse_detector.cc index 84c5807..9b8a357 100644 --- a/components/password_manager/core/browser/password_reuse_detector.cc +++ b/components/password_manager/core/browser/password_reuse_detector.cc
@@ -24,14 +24,6 @@ namespace password_manager { -size_t GetMinPasswordLengthToCheck() { - if (base::FeatureList::IsEnabled( - safe_browsing::kEvaluateProtectedPasswordLengthMinimum)) { - return safe_browsing::kEvaluateProtectedPasswordLengthMinimumValue.Get(); - } - return kMinPasswordLengthToCheck; -} - namespace { // Returns true iff |suffix_candidate| is a suffix of |str|. bool IsSuffix(const std::u16string& str, @@ -131,7 +123,7 @@ PasswordReuseDetectorConsumer* consumer) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(consumer); - if (input.size() < GetMinPasswordLengthToCheck()) { + if (input.size() < kMinPasswordLengthToCheck) { consumer->OnReuseCheckDone(false, 0, std::nullopt, {}, SavedPasswordsCount(), std::string(), 0); return; @@ -338,7 +330,7 @@ void PasswordReuseDetector::AddPassword(const PasswordForm& form) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (form.password_value.size() < GetMinPasswordLengthToCheck()) { + if (form.password_value.size() < kMinPasswordLengthToCheck) { return; } @@ -348,7 +340,7 @@ void PasswordReuseDetector::RemovePassword(const PasswordForm& form) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (form.password_value.size() < GetMinPasswordLengthToCheck()) { + if (form.password_value.size() < kMinPasswordLengthToCheck) { return; }
diff --git a/components/password_manager/core/browser/password_reuse_detector.h b/components/password_manager/core/browser/password_reuse_detector.h index 5d3d6b8..df2876f 100644 --- a/components/password_manager/core/browser/password_reuse_detector.h +++ b/components/password_manager/core/browser/password_reuse_detector.h
@@ -24,12 +24,7 @@ // Minimum number of characters in a password for finding it as password reuse. // It does not make sense to consider short strings for password reuse, since it // is quite likely that they are parts of common words. -inline constexpr size_t kMinPasswordLengthToCheck = 8; - -// When kEvaluateProtectedPasswordLengthMinimum is enabled, return our -// experimental minimum password length value. When it is not enabled, return -// kMinPasswordLengthToCheck. -size_t GetMinPasswordLengthToCheck(); +inline constexpr size_t kMinPasswordLengthToCheck = 4; class PasswordReuseDetectorConsumer;
diff --git a/components/password_manager/core/browser/store_metrics_reporter.cc b/components/password_manager/core/browser/store_metrics_reporter.cc index b5d8b255..1f55520 100644 --- a/components/password_manager/core/browser/store_metrics_reporter.cc +++ b/components/password_manager/core/browser/store_metrics_reporter.cc
@@ -449,9 +449,8 @@ const std::vector<std::unique_ptr<PasswordForm>>& forms) { for (const std::unique_ptr<PasswordForm>& form : forms) { if (!form->blocked_by_user && form->password_value.size() > 0) { - metrics_util::LogIsPasswordProtected( - form->password_value.size() >= - password_manager::GetMinPasswordLengthToCheck()); + metrics_util::LogIsPasswordProtected(form->password_value.size() >= + kMinPasswordLengthToCheck); } } }
diff --git a/components/safe_browsing/core/common/features.cc b/components/safe_browsing/core/common/features.cc index c459ce6f..734be8a0 100644 --- a/components/safe_browsing/core/common/features.cc +++ b/components/safe_browsing/core/common/features.cc
@@ -76,14 +76,6 @@ "SafeBrowsingEncryptedArchivesMetadata", base::FEATURE_DISABLED_BY_DEFAULT); -BASE_FEATURE(kEvaluateProtectedPasswordLengthMinimum, - "EvaluateProtectedPasswordLengthMinimum", - base::FEATURE_ENABLED_BY_DEFAULT); - -const base::FeatureParam<int> kEvaluateProtectedPasswordLengthMinimumValue{ - &kEvaluateProtectedPasswordLengthMinimum, "MinimumValue", - /*default_value=*/4}; - BASE_FEATURE(kExtensionTelemetryConfiguration, "SafeBrowsingExtensionTelemetryConfiguration", base::FEATURE_DISABLED_BY_DEFAULT); @@ -330,7 +322,6 @@ {&kCreateWarningShownClientSafeBrowsingReports, false}, {&kDelayedWarnings, true}, {&kDownloadTailoredWarnings, true}, - {&kEvaluateProtectedPasswordLengthMinimum, false}, {&kExtensionTelemetryDisableOffstoreExtensions, true}, {&kExtensionTelemetryInterceptRemoteHostsContactedInRenderer, true}, {&kExtensionTelemetryPotentialPasswordTheft, true},
diff --git a/components/safe_browsing/core/common/features.h b/components/safe_browsing/core/common/features.h index b149a6be..d32515c5 100644 --- a/components/safe_browsing/core/common/features.h +++ b/components/safe_browsing/core/common/features.h
@@ -68,13 +68,6 @@ // passwords for local decryption on encrypted archives. BASE_DECLARE_FEATURE(kEncryptedArchivesMetadata); -// Enables decreased Phishguard password length minimum. -BASE_DECLARE_FEATURE(kEvaluateProtectedPasswordLengthMinimum); - -// Specifies the minimum password length for password protection. -extern const base::FeatureParam<int> - kEvaluateProtectedPasswordLengthMinimumValue; - // Allows the Extension Telemetry Service to accept and use configurations // sent by the server. BASE_DECLARE_FEATURE(kExtensionTelemetryConfiguration);
diff --git a/components/signin/public/base/signin_metrics.cc b/components/signin/public/base/signin_metrics.cc index 2906032..3500222 100644 --- a/components/signin/public/base/signin_metrics.cc +++ b/components/signin/public/base/signin_metrics.cc
@@ -124,10 +124,6 @@ } } -void LogSigninReason(Reason reason) { - base::UmaHistogramEnumeration("Signin.SigninReason", reason); -} - void LogSignInOffered(AccessPoint access_point) { base::UmaHistogramEnumeration("Signin.SignIn.Offered", access_point, AccessPoint::ACCESS_POINT_MAX);
diff --git a/components/signin/public/base/signin_metrics.h b/components/signin/public/base/signin_metrics.h index 7a6e936..ffa89b9 100644 --- a/components/signin/public/base/signin_metrics.h +++ b/components/signin/public/base/signin_metrics.h
@@ -318,9 +318,6 @@ // numeric values should never be reused. // Please keep in Sync with "SigninReason" in // src/tools/metrics/histograms/enums.xml. -// A Java counterpart will be generated for this enum. -// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.components.signin.metrics -// GENERATED_JAVA_CLASS_NAME_OVERRIDE: SigninReason enum class Reason : int { kSigninPrimaryAccount = 0, kAddSecondaryAccount = 1, @@ -482,9 +479,6 @@ void LogSigninAccessPointCompleted(AccessPoint access_point, PromoAction promo_action); -// Tracks the reason of sign in. -void LogSigninReason(Reason reason); - // Logs sign in offered events and their associated access points. // Access points (or features) are responsible for recording this where relevant // for them.
diff --git a/components/supervised_user/core/browser/BUILD.gn b/components/supervised_user/core/browser/BUILD.gn index 267c664c..9ffaaaf5 100644 --- a/components/supervised_user/core/browser/BUILD.gn +++ b/components/supervised_user/core/browser/BUILD.gn
@@ -94,8 +94,8 @@ sources = [ "child_account_service.cc", "child_account_service.h", - "kids_management_url_checker_client.cc", - "kids_management_url_checker_client.h", + "kids_chrome_management_url_checker_client.cc", + "kids_chrome_management_url_checker_client.h", "parental_control_metrics.cc", "parental_control_metrics.h", "permission_request_creator.h", @@ -171,7 +171,7 @@ sources = [ "api_access_token_fetcher_unittest.cc", "child_account_service_unittest.cc", - "kids_management_url_checker_client_unittest.cc", + "kids_chrome_management_url_checker_client_unittest.cc", "list_family_members_service_unittest.cc", "parental_control_metrics_unittest.cc", "proto_fetcher_unittest.cc",
diff --git a/components/supervised_user/core/browser/kids_management_url_checker_client.cc b/components/supervised_user/core/browser/kids_chrome_management_url_checker_client.cc similarity index 69% rename from components/supervised_user/core/browser/kids_management_url_checker_client.cc rename to components/supervised_user/core/browser/kids_chrome_management_url_checker_client.cc index 5bbba65e..dc124a4e 100644 --- a/components/supervised_user/core/browser/kids_management_url_checker_client.cc +++ b/components/supervised_user/core/browser/kids_chrome_management_url_checker_client.cc
@@ -2,10 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/supervised_user/core/browser/kids_management_url_checker_client.h" +#include "components/supervised_user/core/browser/kids_chrome_management_url_checker_client.h" #include <memory> #include <string> +#include <string_view> #include <utility> #include "base/feature_list.h" @@ -25,6 +26,7 @@ #include "third_party/protobuf/src/google/protobuf/message_lite.h" #include "url/gurl.h" +namespace supervised_user { namespace { using kids_chrome_management::ClassifyUrlResponse; @@ -41,50 +43,10 @@ } } -// Flips order of arguments so that the sole unbound argument will be the -// request. -std::unique_ptr< - supervised_user::ProtoFetcher<kids_chrome_management::ClassifyUrlResponse>> -ClassifyURL(signin::IdentityManager* identity_manager, - scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, - const supervised_user::FetcherConfig& config, - const kids_chrome_management::ClassifyUrlRequest& request) { - return supervised_user::CreateClassifyURLFetcher( - *identity_manager, url_loader_factory, request, config); -} - -supervised_user::FetcherConfig GetFetcherConfig() { - if (base::FeatureList::IsEnabled( - supervised_user::kHighestRequestPriorityForClassifyUrl)) { - return supervised_user::kClassifyUrlConfigWithHighestPriority; - } - return supervised_user::kClassifyUrlConfig; -} - -} // namespace - -KidsManagementURLCheckerClient::KidsManagementURLCheckerClient( - signin::IdentityManager* identity_manager, - scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, - const std::string& country) - : safe_search_client_( - url_loader_factory, - supervised_user::kClassifyUrlConfig.traffic_annotation()), - country_(country), - fetch_manager_(base::BindRepeating(&ClassifyURL, - identity_manager, - url_loader_factory, - GetFetcherConfig())) {} - -KidsManagementURLCheckerClient::~KidsManagementURLCheckerClient() = default; - -namespace { -// Functional equivalent of -// KidsManagementURLCheckerClient::ConvertResponseCallback void OnResponse( const GURL& url, safe_search_api::URLCheckerClient::ClientCheckCallback client_callback, - const supervised_user::ProtoFetcherStatus& status, + const ProtoFetcherStatus& status, std::unique_ptr<kids_chrome_management::ClassifyUrlResponse> classify_url_response) { DVLOG(1) << "URL classification = " @@ -100,21 +62,55 @@ std::move(client_callback) .Run(url, ToSafeSearchClientClassification(classify_url_response.get())); } + +// Flips order of arguments so that the sole unbound argument will be the +// request. +std::unique_ptr<ProtoFetcher<kids_chrome_management::ClassifyUrlResponse>> +ClassifyURL(signin::IdentityManager* identity_manager, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + const FetcherConfig& config, + const kids_chrome_management::ClassifyUrlRequest& request) { + return CreateClassifyURLFetcher(*identity_manager, url_loader_factory, + request, config); +} + +FetcherConfig GetFetcherConfig() { + if (base::FeatureList::IsEnabled(kHighestRequestPriorityForClassifyUrl)) { + return kClassifyUrlConfigWithHighestPriority; + } + return kClassifyUrlConfig; +} + } // namespace -void KidsManagementURLCheckerClient::CheckURL( +KidsChromeManagementURLCheckerClient::KidsChromeManagementURLCheckerClient( + signin::IdentityManager* identity_manager, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + std::string_view country) + : safe_search_client_(url_loader_factory, + kClassifyUrlConfig.traffic_annotation()), + country_(country), + fetch_manager_(base::BindRepeating(&ClassifyURL, + identity_manager, + url_loader_factory, + GetFetcherConfig())) {} + +KidsChromeManagementURLCheckerClient::~KidsChromeManagementURLCheckerClient() = + default; + +void KidsChromeManagementURLCheckerClient::CheckURL( const GURL& url, safe_search_api::URLCheckerClient::ClientCheckCallback callback) { - auto classify_url_request = - std::make_unique<kids_chrome_management::ClassifyUrlRequest>(); - classify_url_request->set_url(url.spec()); - classify_url_request->set_region_code(country_); + kids_chrome_management::ClassifyUrlRequest request; + request.set_url(url.spec()); + request.set_region_code(country_); - fetch_manager_.Fetch(*classify_url_request, + fetch_manager_.Fetch(request, base::BindOnce(&OnResponse, url, std::move(callback))); - if (supervised_user::IsShadowKidsApiWithSafeSitesEnabled()) { + if (IsShadowKidsApiWithSafeSitesEnabled()) { // Actual client is timing the latency in Enterprise.SafeSites.Latency safe_search_client_.CheckURL(url, base::DoNothing()); } } +} // namespace supervised_user
diff --git a/components/supervised_user/core/browser/kids_chrome_management_url_checker_client.h b/components/supervised_user/core/browser/kids_chrome_management_url_checker_client.h new file mode 100644 index 0000000..f6be68c --- /dev/null +++ b/components/supervised_user/core/browser/kids_chrome_management_url_checker_client.h
@@ -0,0 +1,60 @@ +// Copyright 2019 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_SUPERVISED_USER_CORE_BROWSER_KIDS_CHROME_MANAGEMENT_URL_CHECKER_CLIENT_H_ +#define COMPONENTS_SUPERVISED_USER_CORE_BROWSER_KIDS_CHROME_MANAGEMENT_URL_CHECKER_CLIENT_H_ + +#include <string> +#include <string_view> + +#include "base/memory/scoped_refptr.h" +#include "components/safe_search_api/safe_search/safe_search_url_checker_client.h" +#include "components/safe_search_api/url_checker_client.h" +#include "components/signin/public/identity_manager/identity_manager.h" +#include "components/supervised_user/core/browser/proto/kidschromemanagement_messages.pb.h" +#include "components/supervised_user/core/browser/proto_fetcher.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" + +class GURL; + +namespace supervised_user { +// This class uses the KidsChromeManagement::ClassifyUrl to check the +// classification of the content on a given URL and returns the result +// asynchronously via a callback. +class KidsChromeManagementURLCheckerClient + : public safe_search_api::URLCheckerClient { + public: + // `country` should be a two-letter country code (ISO 3166-1 alpha-2), e.g., + // "us". + KidsChromeManagementURLCheckerClient( + signin::IdentityManager* identity_manager, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + std::string_view country); + + KidsChromeManagementURLCheckerClient( + const KidsChromeManagementURLCheckerClient&) = delete; + KidsChromeManagementURLCheckerClient& operator=( + const KidsChromeManagementURLCheckerClient&) = delete; + + ~KidsChromeManagementURLCheckerClient() override; + + // Checks whether an `url` is restricted according to + // KidsChromeManagement::ClassifyUrl RPC. + // + // On failure, the `callback` function is called with `url` as the first + // parameter, and UNKNOWN as the second. + void CheckURL(const GURL& url, ClientCheckCallback callback) override; + + private: + safe_search_api::SafeSearchURLCheckerClient safe_search_client_; + const std::string country_; + + ParallelFetchManager<kids_chrome_management::ClassifyUrlRequest, + kids_chrome_management::ClassifyUrlResponse> + fetch_manager_; +}; + +} // namespace supervised_user + +#endif // COMPONENTS_SUPERVISED_USER_CORE_BROWSER_KIDS_CHROME_MANAGEMENT_URL_CHECKER_CLIENT_H_
diff --git a/components/supervised_user/core/browser/kids_management_url_checker_client_unittest.cc b/components/supervised_user/core/browser/kids_chrome_management_url_checker_client_unittest.cc similarity index 85% rename from components/supervised_user/core/browser/kids_management_url_checker_client_unittest.cc rename to components/supervised_user/core/browser/kids_chrome_management_url_checker_client_unittest.cc index bd4ecdc..68767824 100644 --- a/components/supervised_user/core/browser/kids_management_url_checker_client_unittest.cc +++ b/components/supervised_user/core/browser/kids_chrome_management_url_checker_client_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/supervised_user/core/browser/kids_management_url_checker_client.h" +#include "components/supervised_user/core/browser/kids_chrome_management_url_checker_client.h" #include <memory> #include <string> @@ -29,6 +29,7 @@ #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" +namespace supervised_user { namespace { using kids_chrome_management::ClassifyUrlResponse; @@ -52,22 +53,10 @@ } } -class KidsManagementURLCheckerClientTest : public ::testing::Test { +class KidsChromeManagementURLCheckerClientTest : public ::testing::Test { public: - KidsManagementURLCheckerClientTest() { - shadow_call_feature_list_.InitWithFeatures( - /*enabled_features=*/{supervised_user::kShadowKidsApiWithSafeSites}, - /*disabled_features=*/{}); - } - - ~KidsManagementURLCheckerClientTest() override { - // Since scoped_feature_list_::Init* / scoped_feature_list_.Reset are - // stack-based clean-up in the same life-cycle moment. - shadow_call_feature_list_.Reset(); - } - void SetUp() override { - url_classifier_ = std::make_unique<KidsManagementURLCheckerClient>( + url_classifier_ = std::make_unique<KidsChromeManagementURLCheckerClient>( identity_test_env_.identity_manager(), test_url_loader_factory_.GetSafeWeakWrapper(), "us"); } @@ -94,8 +83,7 @@ std::string(kSafeSitesEndpoint), base::StringPrintf(R"json( {"displayClassification": "%s"} - )json", - ConvertToString(classification).c_str())); + )json",ConvertToString(classification).c_str())); } void SimulateMalformedResponse() { @@ -135,7 +123,7 @@ void StartCheckUrl(base::StringPiece url) { url_classifier_->CheckURL( GURL(url), - base::BindOnce(&KidsManagementURLCheckerClientTest::OnCheckDone, + base::BindOnce(&KidsChromeManagementURLCheckerClientTest::OnCheckDone, base::Unretained(this))); } @@ -144,11 +132,11 @@ private: signin::IdentityTestEnvironment identity_test_env_; - std::unique_ptr<KidsManagementURLCheckerClient> url_classifier_; - base::test::ScopedFeatureList shadow_call_feature_list_; + std::unique_ptr<KidsChromeManagementURLCheckerClient> url_classifier_; + base::test::ScopedFeatureList shadow_call_feature_list_{kShadowKidsApiWithSafeSites}; }; -TEST_F(KidsManagementURLCheckerClientTest, UrlAllowed) { +TEST_F(KidsChromeManagementURLCheckerClientTest, UrlAllowed) { MakePrimaryAccountAvailable(); EXPECT_CALL(*this, @@ -162,7 +150,7 @@ SimulateKidsApiResponse(kids_chrome_management::ClassifyUrlResponse::ALLOWED); } -TEST_F(KidsManagementURLCheckerClientTest, HistogramsAreEmitted) { +TEST_F(KidsChromeManagementURLCheckerClientTest, HistogramsAreEmitted) { base::HistogramTester histogram_tester; MakePrimaryAccountAvailable(); @@ -183,7 +171,7 @@ /*expected_count(grew by)*/ 1); } -TEST_F(KidsManagementURLCheckerClientTest, UrlRestricted) { +TEST_F(KidsChromeManagementURLCheckerClientTest, UrlRestricted) { MakePrimaryAccountAvailable(); EXPECT_CALL(*this, @@ -198,7 +186,7 @@ kids_chrome_management::ClassifyUrlResponse::RESTRICTED); } -TEST_F(KidsManagementURLCheckerClientTest, AccessTokenError) { +TEST_F(KidsChromeManagementURLCheckerClientTest, AccessTokenError) { EXPECT_CALL(*this, OnCheckDone(GURL("http://example.com"), safe_search_api::ClientClassification::kUnknown)); @@ -209,7 +197,7 @@ SimulateSafeSitesResponse(safe_search_api::ClientClassification::kAllowed); } -TEST_F(KidsManagementURLCheckerClientTest, NetworkError) { +TEST_F(KidsChromeManagementURLCheckerClientTest, NetworkError) { MakePrimaryAccountAvailable(); EXPECT_CALL(*this, @@ -223,7 +211,7 @@ SimulateNetworkError(net::ERR_UNEXPECTED); } -TEST_F(KidsManagementURLCheckerClientTest, HttpError) { +TEST_F(KidsChromeManagementURLCheckerClientTest, HttpError) { MakePrimaryAccountAvailable(); EXPECT_CALL(*this, @@ -237,7 +225,7 @@ SimulateHttpError(net::HTTP_BAD_GATEWAY); } -TEST_F(KidsManagementURLCheckerClientTest, ServiceError) { +TEST_F(KidsChromeManagementURLCheckerClientTest, ServiceError) { MakePrimaryAccountAvailable(); EXPECT_CALL(*this, @@ -251,7 +239,7 @@ SimulateMalformedResponse(); } -TEST_F(KidsManagementURLCheckerClientTest, +TEST_F(KidsChromeManagementURLCheckerClientTest, PendingRequestsAreCanceledWhenClientIsDestroyed) { EXPECT_CALL(*this, OnCheckDone(_, _)).Times(0); @@ -262,3 +250,4 @@ task_environment_.RunUntilIdle(); } } // namespace +} // namespace supervised_user
diff --git a/components/supervised_user/core/browser/kids_management_url_checker_client.h b/components/supervised_user/core/browser/kids_management_url_checker_client.h deleted file mode 100644 index 3413bcb8..0000000 --- a/components/supervised_user/core/browser/kids_management_url_checker_client.h +++ /dev/null
@@ -1,60 +0,0 @@ -// Copyright 2019 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SUPERVISED_USER_CORE_BROWSER_KIDS_MANAGEMENT_URL_CHECKER_CLIENT_H_ -#define COMPONENTS_SUPERVISED_USER_CORE_BROWSER_KIDS_MANAGEMENT_URL_CHECKER_CLIENT_H_ - -#include <string> - -#include "base/memory/scoped_refptr.h" -#include "components/safe_search_api/safe_search/safe_search_url_checker_client.h" -#include "components/safe_search_api/url_checker_client.h" -#include "components/signin/public/identity_manager/identity_manager.h" -#include "components/supervised_user/core/browser/proto/kidschromemanagement_messages.pb.h" -#include "components/supervised_user/core/browser/proto_fetcher.h" -#include "services/network/public/cpp/shared_url_loader_factory.h" - -class GURL; - -// TODO(crbug.com/988428): Change comments to use KidsChromeManagement instead -// of KidsManagement when migration is complete. - -// This class uses the KidsManagement ClassifyUrl to check the classification -// of the content on a given URL and returns the result asynchronously -// via a callback. -class KidsManagementURLCheckerClient - : public safe_search_api::URLCheckerClient { - public: - // |country| should be a two-letter country code (ISO 3166-1 alpha-2), e.g., - // "us". - KidsManagementURLCheckerClient( - signin::IdentityManager* identity_manager, - scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, - const std::string& country); - - KidsManagementURLCheckerClient(const KidsManagementURLCheckerClient&) = - delete; - KidsManagementURLCheckerClient& operator=( - const KidsManagementURLCheckerClient&) = delete; - - ~KidsManagementURLCheckerClient() override; - - // Checks whether an |url| is restricted according to KidsManagement - // ClassifyUrl RPC. - // - // On failure, the |callback| function is called with |url| as the first - // parameter, and UNKNOWN as the second. - void CheckURL(const GURL& url, ClientCheckCallback callback) override; - - private: - safe_search_api::SafeSearchURLCheckerClient safe_search_client_; - const std::string country_; - - supervised_user::ParallelFetchManager< - kids_chrome_management::ClassifyUrlRequest, - kids_chrome_management::ClassifyUrlResponse> - fetch_manager_; -}; - -#endif // COMPONENTS_SUPERVISED_USER_CORE_BROWSER_KIDS_MANAGEMENT_URL_CHECKER_CLIENT_H_
diff --git a/components/supervised_user/core/browser/supervised_user_url_filter.cc b/components/supervised_user/core/browser/supervised_user_url_filter.cc index 8ddff93..57da2036 100644 --- a/components/supervised_user/core/browser/supervised_user_url_filter.cc +++ b/components/supervised_user/core/browser/supervised_user_url_filter.cc
@@ -20,7 +20,7 @@ #include "base/strings/string_util.h" #include "base/task/thread_pool.h" #include "components/signin/public/identity_manager/identity_manager.h" -#include "components/supervised_user/core/browser/kids_management_url_checker_client.h" +#include "components/supervised_user/core/browser/kids_chrome_management_url_checker_client.h" #include "components/supervised_user/core/common/supervised_user_constants.h" #include "components/supervised_user/core/common/supervised_user_utils.h" #include "components/url_matcher/url_util.h" @@ -682,7 +682,7 @@ std::string country = service_delegate_->GetCountryCode(); std::unique_ptr<safe_search_api::URLCheckerClient> url_checker_client = - std::make_unique<KidsManagementURLCheckerClient>( + std::make_unique<KidsChromeManagementURLCheckerClient>( identity_manager, url_loader_factory, country); async_url_checker_ = std::make_unique<safe_search_api::URLChecker>( std::move(url_checker_client));
diff --git a/components/sync/engine/model_type_worker.cc b/components/sync/engine/model_type_worker.cc index c3484499..70a50f1 100644 --- a/components/sync/engine/model_type_worker.cc +++ b/components/sync/engine/model_type_worker.cc
@@ -267,6 +267,7 @@ !invitation.sender_info().has_cross_user_sharing_public_key()) { LogCrossUserSharingDecryptionResult( CrossUserSharingDecryptionResult::kInvitationMissingFields); + DLOG(ERROR) << "The invitation is missing required fields"; return false; } @@ -281,6 +282,7 @@ if (!decrypted) { LogCrossUserSharingDecryptionResult( CrossUserSharingDecryptionResult::kFailedToDecryptInvitation); + DLOG(ERROR) << "Failed to decrypt the invitation"; return false; } @@ -288,6 +290,7 @@ decrypted->size())) { LogCrossUserSharingDecryptionResult( CrossUserSharingDecryptionResult::kFailedToParseDecryptedInvitation); + DLOG(ERROR) << "Failed to parse the decrypted invitation"; return false; }
diff --git a/components/sync/nigori/cross_user_sharing_keys.cc b/components/sync/nigori/cross_user_sharing_keys.cc index c8fbbca..20b093d 100644 --- a/components/sync/nigori/cross_user_sharing_keys.cc +++ b/components/sync/nigori/cross_user_sharing_keys.cc
@@ -74,7 +74,9 @@ CrossUserSharingKeys CrossUserSharingKeys::Clone() const { CrossUserSharingKeys copy; - copy.AddAllUnknownKeysFrom(*this); + for (const auto& [version, key_pair] : key_pairs_map_) { + copy.AddKeyPair(CloneKeyPair(key_pair), version); + } return copy; } @@ -86,13 +88,6 @@ return key_pairs_map_.contains(key_pair_version); } -void CrossUserSharingKeys::AddAllUnknownKeysFrom( - const CrossUserSharingKeys& other) { - for (const auto& [public_key, key_pair] : other.key_pairs_map_) { - key_pairs_map_.emplace(public_key, CloneKeyPair(key_pair)); - } -} - bool CrossUserSharingKeys::AddKeyPairFromProto( const sync_pb::CrossUserSharingPrivateKey& key) { std::vector<uint8_t> private_key(key.x25519_private_key().begin(), @@ -111,6 +106,8 @@ void CrossUserSharingKeys::AddKeyPair( CrossUserSharingPublicPrivateKeyPair key_pair, uint32_t version) { + // TODO(crbug.com/1511180): verify that the following emplace does not cause + // key loss. key_pairs_map_.emplace(version, std::move(key_pair)); }
diff --git a/components/sync/nigori/cross_user_sharing_keys.h b/components/sync/nigori/cross_user_sharing_keys.h index 1b6f883..1cb742bc 100644 --- a/components/sync/nigori/cross_user_sharing_keys.h +++ b/components/sync/nigori/cross_user_sharing_keys.h
@@ -37,10 +37,6 @@ size_t size() const; bool HasKeyPair(const uint32_t key_version) const; - // Merges all keys from another CrossUserSharingKeys object, which means - // adding all keys that we don't know about. - void AddAllUnknownKeysFrom(const CrossUserSharingKeys& other); - // Adds a Public-private key-pair associated with |version|. void AddKeyPair(CrossUserSharingPublicPrivateKeyPair key_pair, uint32_t version); @@ -61,7 +57,7 @@ CrossUserSharingKeys(); // Public-private key-pairs we know about, mapped by version. - std::map<uint32_t, const CrossUserSharingPublicPrivateKeyPair> key_pairs_map_; + std::map<uint32_t, CrossUserSharingPublicPrivateKeyPair> key_pairs_map_; }; } // namespace syncer
diff --git a/components/sync/nigori/cryptographer_impl.cc b/components/sync/nigori/cryptographer_impl.cc index d7dbd95..c584419 100644 --- a/components/sync/nigori/cryptographer_impl.cc +++ b/components/sync/nigori/cryptographer_impl.cc
@@ -88,9 +88,8 @@ key_bag_.AddAllUnknownKeysFrom(key_bag); } -void CryptographerImpl::EmplaceCrossUserSharingKeysFrom( - const CrossUserSharingKeys& keys) { - cross_user_sharing_keys_.AddAllUnknownKeysFrom(keys); +void CryptographerImpl::ReplaceCrossUserSharingKeys(CrossUserSharingKeys keys) { + cross_user_sharing_keys_ = std::move(keys); } void CryptographerImpl::SelectDefaultEncryptionKey(
diff --git a/components/sync/nigori/cryptographer_impl.h b/components/sync/nigori/cryptographer_impl.h index 4ad8b301..df3134c 100644 --- a/components/sync/nigori/cryptographer_impl.h +++ b/components/sync/nigori/cryptographer_impl.h
@@ -63,8 +63,8 @@ // Does NOT set or change the default encryption key. void EmplaceKeysFrom(const NigoriKeyBag& key_bag); - // Adds all keys from |keys| that weren't previously known. - void EmplaceCrossUserSharingKeysFrom(const CrossUserSharingKeys& keys); + // Drops any pre-existing key pairs and adds all keys from |keys|. + void ReplaceCrossUserSharingKeys(CrossUserSharingKeys keys); // Adds the given Public-private key-pair associated with |version|. void EmplaceKeyPair(CrossUserSharingPublicPrivateKeyPair key_pair,
diff --git a/components/sync/nigori/cryptographer_impl_unittest.cc b/components/sync/nigori/cryptographer_impl_unittest.cc index dd70630a..dfc6d04 100644 --- a/components/sync/nigori/cryptographer_impl_unittest.cc +++ b/components/sync/nigori/cryptographer_impl_unittest.cc
@@ -269,7 +269,7 @@ EXPECT_TRUE(cryptographer->HasKeyPair(0)); } -TEST(CryptographerImplTest, ShouldEmplaceCrossUserSharingKeysFrom) { +TEST(CryptographerImplTest, ShouldReplaceCrossUserSharingKeys) { std::unique_ptr<CryptographerImpl> cryptographer = CryptographerImpl::CreateEmpty(); ASSERT_THAT(cryptographer, NotNull()); @@ -280,12 +280,43 @@ keys.AddKeyPair(CrossUserSharingPublicPrivateKeyPair::GenerateNewKeyPair(), 1); - cryptographer->EmplaceCrossUserSharingKeysFrom(keys); + cryptographer->ReplaceCrossUserSharingKeys(std::move(keys)); EXPECT_TRUE(cryptographer->HasKeyPair(0)); EXPECT_TRUE(cryptographer->HasKeyPair(1)); } +TEST(CryptographerImplTest, ShouldOverwritePreexistingKeys) { + std::unique_ptr<CryptographerImpl> cryptographer = + CryptographerImpl::CreateEmpty(); + CrossUserSharingKeys old_keys = CrossUserSharingKeys::CreateEmpty(); + old_keys.AddKeyPair( + CrossUserSharingPublicPrivateKeyPair::GenerateNewKeyPair(), + /*version=*/0); + old_keys.AddKeyPair( + CrossUserSharingPublicPrivateKeyPair::GenerateNewKeyPair(), + /*version=*/1); + cryptographer->ReplaceCrossUserSharingKeys(old_keys.Clone()); + ASSERT_TRUE(cryptographer->HasKeyPair(/*version=*/0)); + ASSERT_TRUE(cryptographer->HasKeyPair(/*version=*/1)); + + // Generate a new key pair and replace the pre-existing one with the same + // version. The version 1 should also disappear. + CrossUserSharingKeys new_keys = CrossUserSharingKeys::CreateEmpty(); + new_keys.AddKeyPair( + CrossUserSharingPublicPrivateKeyPair::GenerateNewKeyPair(), + /*version=*/0); + cryptographer->ReplaceCrossUserSharingKeys(new_keys.Clone()); + ASSERT_TRUE(cryptographer->HasKeyPair(/*version=*/0)); + ASSERT_FALSE(cryptographer->HasKeyPair(/*version=*/1)); + EXPECT_EQ(cryptographer->GetCrossUserSharingKeyPair(/*version=*/0) + .GetRawPrivateKey(), + new_keys.GetKeyPair(/*version=*/0).GetRawPrivateKey()); + EXPECT_NE(cryptographer->GetCrossUserSharingKeyPair(/*version=*/0) + .GetRawPrivateKey(), + old_keys.GetKeyPair(/*version=*/0).GetRawPrivateKey()); +} + TEST(CryptographerImplTest, ShouldEncryptAndDecryptForCrossUserSharing) { std::unique_ptr<CryptographerImpl> cryptographer_sender = CryptographerImpl::CreateEmpty();
diff --git a/components/sync/nigori/nigori_sync_bridge_impl.cc b/components/sync/nigori/nigori_sync_bridge_impl.cc index de72f4ab..55680cc0 100644 --- a/components/sync/nigori/nigori_sync_bridge_impl.cc +++ b/components/sync/nigori/nigori_sync_bridge_impl.cc
@@ -236,6 +236,7 @@ // These values are persisted to UMA. Entries should not be renumbered and // numeric values should never be reused. +// TODO(crbug.com/1511180): add a bucket for the pending keys state. enum class CrossUserSharingKeyPairStateForUMA { kValidKeyPair = 0, kPublicKeyNotInitialized = 1, @@ -380,6 +381,10 @@ if (base::FeatureList::IsEnabled(kSharingOfferKeyPairBootstrap) && !state_.cross_user_sharing_public_key.has_value()) { + // Generate a new key pair if there is no public key in the local state. + // Note that this can trigger a key pair generation if the current client + // has been just upgraded from the older version (so it wasn't aware of key + // pairs). Other clients are expected to apply the newly generated key pair. QueuePendingLocalCommit( PendingLocalNigoriCommit:: ForCrossUserSharingPublicPrivateKeyInitializer()); @@ -888,8 +893,12 @@ state_.cross_user_sharing_key_pair_version = absl::nullopt; state_.cross_user_sharing_public_key = absl::nullopt; } else if (state_.cross_user_sharing_key_pair_version.has_value()) { - state_.cryptographer->EmplaceCrossUserSharingKeysFrom( - new_cross_user_sharing_keys); + // Use the keys from the server and replace any pre-existing ones (so in + // case of conflict the server wins). One of cases when this can happen is + // when one of older clients is upgraded to a newer version and generated + // a new key pair because it wasn't aware of the previous key pair. + state_.cryptographer->ReplaceCrossUserSharingKeys( + std::move(new_cross_user_sharing_keys)); state_.cryptographer->SelectDefaultCrossUserSharingKey( state_.cross_user_sharing_key_pair_version.value()); }
diff --git a/components/sync/service/model_load_manager.cc b/components/sync/service/model_load_manager.cc index 217b27a..f1dc021 100644 --- a/components/sync/service/model_load_manager.cc +++ b/components/sync/service/model_load_manager.cc
@@ -54,8 +54,11 @@ // Controllers in a FAILED state or with preconditions not met should have // been filtered out by the DataTypeManager. CHECK_NE(dtc->state(), DataTypeController::FAILED); - CHECK_EQ(dtc->GetPreconditionState(), - DataTypeController::PreconditionState::kPreconditionsMet); + // TODO(crbug.com/1514430): consider removing the following CHECK because + // data types can change their state and notify DataTypeManager later. + DUMP_WILL_BE_CHECK_EQ( + dtc->GetPreconditionState(), + DataTypeController::PreconditionState::kPreconditionsMet); preferred_types_without_errors_.Put(type); } }
diff --git a/components/variations/BUILD.gn b/components/variations/BUILD.gn index 4546d2e5..7c3e248 100644 --- a/components/variations/BUILD.gn +++ b/components/variations/BUILD.gn
@@ -52,6 +52,8 @@ "fake_crash.h", "hashing.cc", "hashing.h", + "limited_entropy_mode_gate.cc", + "limited_entropy_mode_gate.h", "metrics.cc", "metrics.h", "platform_field_trials.h",
diff --git a/components/variations/cros_evaluate_seed/cros_variations_field_trial_creator.cc b/components/variations/cros_evaluate_seed/cros_variations_field_trial_creator.cc index a50523fb..443819d5 100644 --- a/components/variations/cros_evaluate_seed/cros_variations_field_trial_creator.cc +++ b/components/variations/cros_evaluate_seed/cros_variations_field_trial_creator.cc
@@ -16,11 +16,13 @@ CrOSVariationsFieldTrialCreator::CrOSVariationsFieldTrialCreator( VariationsServiceClient* client, std::unique_ptr<VariationsSeedStore> seed_store) - : VariationsFieldTrialCreatorBase(client, - std::move(seed_store), - base::BindOnce([](PrefService*) { - return std::string(kFakeLocale); - })) {} + : VariationsFieldTrialCreatorBase( + client, + std::move(seed_store), + base::BindOnce([](PrefService*) { return std::string(kFakeLocale); }), + // The limited entropy synthetic trial will not be registered for this + // purpose. + /*limited_entropy_synthetic_trial=*/nullptr) {} CrOSVariationsFieldTrialCreator::~CrOSVariationsFieldTrialCreator() = default;
diff --git a/components/variations/limited_entropy_mode_gate.cc b/components/variations/limited_entropy_mode_gate.cc new file mode 100644 index 0000000..a3c4fc19 --- /dev/null +++ b/components/variations/limited_entropy_mode_gate.cc
@@ -0,0 +1,25 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/variations/limited_entropy_mode_gate.h" + +namespace variations { + +namespace { +bool g_is_limited_entropy_mode_enabled_for_testing = false; +} + +bool IsLimitedEntropyModeEnabled() { + if (g_is_limited_entropy_mode_enabled_for_testing) { + return true; + } + // TODO(crbug.com/1511779): Enable limited entropy mode by channel. + return false; +} + +void EnableLimitedEntropyModeForTesting() { + g_is_limited_entropy_mode_enabled_for_testing = true; +} + +} // namespace variations
diff --git a/components/variations/limited_entropy_mode_gate.h b/components/variations/limited_entropy_mode_gate.h new file mode 100644 index 0000000..899863c --- /dev/null +++ b/components/variations/limited_entropy_mode_gate.h
@@ -0,0 +1,23 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_VARIATIONS_LIMITED_ENTROPY_MODE_GATE_H_ +#define COMPONENTS_VARIATIONS_LIMITED_ENTROPY_MODE_GATE_H_ + +#include "base/component_export.h" + +namespace variations { + +// Returns true iff this client is eligible to randomize field trials within a +// layer with LIMITED entropy mode, or if the client has called +// EnableLimitedEntropyModeForTesting(). +COMPONENT_EXPORT(VARIATIONS) bool IsLimitedEntropyModeEnabled(); + +// Enables the client to randomize field trials within a layer with LIMITED +// entropy mode. For testing purposes only. +COMPONENT_EXPORT(VARIATIONS) void EnableLimitedEntropyModeForTesting(); + +} // namespace variations + +#endif // COMPONENTS_VARIATIONS_LIMITED_ENTROPY_MODE_GATE_H_
diff --git a/components/variations/service/variations_field_trial_creator.cc b/components/variations/service/variations_field_trial_creator.cc index e7fead5..1d659e1 100644 --- a/components/variations/service/variations_field_trial_creator.cc +++ b/components/variations/service/variations_field_trial_creator.cc
@@ -26,13 +26,15 @@ VariationsFieldTrialCreator::VariationsFieldTrialCreator( VariationsServiceClient* client, std::unique_ptr<VariationsSeedStore> seed_store, - const UIStringOverrider& ui_string_overrider) + const UIStringOverrider& ui_string_overrider, + LimitedEntropySyntheticTrial* limited_entropy_synthetic_trial) : VariationsFieldTrialCreatorBase( client, std::move(seed_store), base::BindOnce([](PrefService* local_state) { return language::GetApplicationLocale(local_state); - })), + }), + limited_entropy_synthetic_trial), ui_string_overrider_(ui_string_overrider) {} VariationsFieldTrialCreator::~VariationsFieldTrialCreator() {}
diff --git a/components/variations/service/variations_field_trial_creator.h b/components/variations/service/variations_field_trial_creator.h index 1dcf22af..c8a79521 100644 --- a/components/variations/service/variations_field_trial_creator.h +++ b/components/variations/service/variations_field_trial_creator.h
@@ -16,6 +16,7 @@ namespace variations { +class LimitedEntropySyntheticTrial; class VariationsServiceClient; // Used to set up field trials based on stored variations seed data. @@ -23,9 +24,11 @@ public: // Caller is responsible for ensuring that objects passed to the constructor // stay valid for the lifetime of this object. - VariationsFieldTrialCreator(VariationsServiceClient* client, - std::unique_ptr<VariationsSeedStore> seed_store, - const UIStringOverrider& ui_string_overrider); + VariationsFieldTrialCreator( + VariationsServiceClient* client, + std::unique_ptr<VariationsSeedStore> seed_store, + const UIStringOverrider& ui_string_overrider, + LimitedEntropySyntheticTrial* limited_entropy_synthetic_trial); VariationsFieldTrialCreator(const VariationsFieldTrialCreator&) = delete; VariationsFieldTrialCreator& operator=(const VariationsFieldTrialCreator&) =
diff --git a/components/variations/service/variations_field_trial_creator_base.cc b/components/variations/service/variations_field_trial_creator_base.cc index eccaccbd..a7e250e 100644 --- a/components/variations/service/variations_field_trial_creator_base.cc +++ b/components/variations/service/variations_field_trial_creator_base.cc
@@ -35,6 +35,7 @@ #include "components/metrics/metrics_state_manager.h" #include "components/prefs/pref_service.h" #include "components/variations/field_trial_config/field_trial_util.h" +#include "components/variations/limited_entropy_mode_gate.h" #include "components/variations/platform_field_trials.h" #include "components/variations/pref_names.h" #include "components/variations/proto/variations_seed.pb.h" @@ -161,6 +162,16 @@ /*is_extended_safe_mode=*/true); } +// Returns true iff the given seed contains a layer with LIMITED entropy mode. +bool ContainsLimitedEntropyLayer(const VariationsSeed& seed) { + for (const Layer& layer_proto : seed.layers()) { + if (layer_proto.entropy_mode() == Layer::LIMITED) { + return true; + } + } + return false; +} + } // namespace BASE_FEATURE(kForceFieldTrialSetupCrashForTesting, @@ -188,13 +199,15 @@ VariationsFieldTrialCreatorBase::VariationsFieldTrialCreatorBase( VariationsServiceClient* client, std::unique_ptr<VariationsSeedStore> seed_store, - base::OnceCallback<std::string(PrefService*)> locale_cb) + base::OnceCallback<std::string(PrefService*)> locale_cb, + LimitedEntropySyntheticTrial* limited_entropy_synthetic_trial) : client_(client), seed_store_(std::move(seed_store)), create_trials_from_seed_called_(false), application_locale_(std::move(locale_cb).Run(seed_store_->local_state())), has_platform_override_(false), - platform_override_(Study::PLATFORM_WINDOWS) {} + platform_override_(Study::PLATFORM_WINDOWS), + limited_entropy_synthetic_trial_(limited_entropy_synthetic_trial) {} VariationsFieldTrialCreatorBase::~VariationsFieldTrialCreatorBase() = default; @@ -645,6 +658,14 @@ RecordVariationsSeedUsage(run_in_safe_mode ? SeedUsage::kSafeSeedUsed : SeedUsage::kRegularSeedUsed); + // Register group membership for the limited entropy synthetic trial if the + // required parameters are non null, and a LIMITED entropy layer is in the + // seed. + if (IsLimitedEntropyModeEnabled() && limited_entropy_synthetic_trial_ && + ContainsLimitedEntropyLayer(seed)) { + client_->RegisterLimitedEntropySyntheticTrial( + limited_entropy_synthetic_trial_->GetGroupName()); + } // Note that passing base::Unretained(this) below is safe because the callback // is executed synchronously. It is not possible to pass UIStringOverrider // directly to VariationsSeedProcessor (which is in components/variations and
diff --git a/components/variations/service/variations_field_trial_creator_base.h b/components/variations/service/variations_field_trial_creator_base.h index 5d9aae2a..748683a8 100644 --- a/components/variations/service/variations_field_trial_creator_base.h +++ b/components/variations/service/variations_field_trial_creator_base.h
@@ -36,7 +36,9 @@ #include "components/variations/proto/study.pb.h" #include "components/variations/seed_response.h" #include "components/variations/service/buildflags.h" +#include "components/variations/service/limited_entropy_synthetic_trial.h" #include "components/variations/service/safe_seed_manager.h" +#include "components/variations/service/variations_service_client.h" #include "components/variations/variations_seed_store.h" #include "components/version_info/channel.h" @@ -110,10 +112,16 @@ // Caller is responsible for ensuring that the VariationsServiceClient passed // to the constructor stays valid for the lifetime of this object. // |locale_cb| computes the locale, given a PrefService for local_state. + // + // The client will be registered to the limited entropy synthetic trial iff + // |limited_entropy_synthetic_trial| is not null. Caller is responsible for + // ensuring |limited_entropy_synthetic_trial| stays valid for the lifetime of + // this object. VariationsFieldTrialCreatorBase( VariationsServiceClient* client, std::unique_ptr<VariationsSeedStore> seed_store, - base::OnceCallback<std::string(PrefService*)> locale_cb); + base::OnceCallback<std::string(PrefService*)> locale_cb, + LimitedEntropySyntheticTrial* limited_entropy_synthetic_trial); VariationsFieldTrialCreatorBase(const VariationsFieldTrialCreatorBase&) = delete; @@ -299,6 +307,9 @@ // These strings are cached before the resource bundle is initialized. std::unordered_map<int, std::u16string> overridden_strings_map_; + // Configurations related to the limited entropy synthetic trial. + raw_ptr<LimitedEntropySyntheticTrial> limited_entropy_synthetic_trial_; + SEQUENCE_CHECKER(sequence_checker_); };
diff --git a/components/variations/service/variations_field_trial_creator_unittest.cc b/components/variations/service/variations_field_trial_creator_unittest.cc index b77913dd..b63f2ad5 100644 --- a/components/variations/service/variations_field_trial_creator_unittest.cc +++ b/components/variations/service/variations_field_trial_creator_unittest.cc
@@ -10,6 +10,7 @@ #include <string> #include <utility> +#include "base/base64.h" #include "base/base_switches.h" #include "base/build_time.h" #include "base/command_line.h" @@ -39,11 +40,13 @@ #include "components/metrics/test/test_enabled_state_provider.h" #include "components/prefs/testing_pref_service.h" #include "components/variations/field_trial_config/field_trial_util.h" +#include "components/variations/limited_entropy_mode_gate.h" #include "components/variations/platform_field_trials.h" #include "components/variations/pref_names.h" #include "components/variations/proto/variations_seed.pb.h" #include "components/variations/scoped_variations_ids_provider.h" #include "components/variations/service/buildflags.h" +#include "components/variations/service/limited_entropy_synthetic_trial.h" #include "components/variations/service/safe_seed_manager.h" #include "components/variations/service/variations_service.h" #include "components/variations/service/variations_service_client.h" @@ -56,6 +59,7 @@ #include "services/network/public/cpp/shared_url_loader_factory.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/zlib/google/compression_utils.h" #if BUILDFLAG(IS_ANDROID) #include "components/variations/seed_response.h" @@ -108,6 +112,38 @@ return seed; } +// Returns a test seed that contains a single study, +// "UMA-Uniformity-Trial-10-Percent", which has a single experiment, "abc", with +// probability weight 100. The study references the 100% slot of a LIMITED +// entropy layer. +VariationsSeed CreateTestSeedWithLimitedEntropyLayer() { + VariationsSeed seed; + seed.set_serial_number(kTestSeedSerialNumber); + + auto* layer = seed.add_layers(); + layer->set_id(1); + layer->set_num_slots(100); + layer->set_entropy_mode(Layer::LIMITED); + + auto* layer_member = layer->add_members(); + layer_member->set_id(1); + auto* slot = layer_member->add_slots(); + slot->set_start(0); + slot->set_end(99); + + Study* study = seed.add_study(); + study->set_name(kTestSeedStudyName); + auto* layer_member_reference = study->mutable_layer(); + layer_member_reference->set_layer_id(1); + layer_member_reference->set_layer_member_id(1); + + Study_Experiment* experiment = study->add_experiment(); + experiment->set_name(kTestSeedExperimentName); + experiment->set_probability_weight(kTestSeedExperimentProbability); + + return seed; +} + // Returns a seed with simple test data. The seed has a single study, // "UMA-Uniformity-Trial-10-Percent", which has a single experiment, // "abc.safe", with probability weight 100. @@ -122,6 +158,14 @@ return seed; } +// Returns a hex string of the GZipped, base64 encoded, and serialized seed. +std::string GZipAndB64EncodeToHexString(const VariationsSeed& seed) { + auto serialized = seed.SerializeAsString(); + std::string compressed; + compression::GzipCompress(serialized, &compressed); + return base::Base64Encode(compressed); +} + // A base::Time instance representing a time in the distant past. Here, it would // return the start for epoch in Unix-like system (Jan 1, 1970). base::Time DistantPast() { @@ -210,6 +254,14 @@ bool IsEnterprise() override { return false; } void RemoveGoogleGroupsFromPrefsForDeletedProfiles( PrefService* local_state) override {} + // TODO(crbug.com/1508150): Remove once the trial has wrapped up. + void RegisterLimitedEntropySyntheticTrial( + std::string_view group_name) override { + limited_entropy_synthetic_trial_group_ = std::string(group_name); + } + std::string_view GetLimitedEntropySyntheticTrialGroupName() { + return limited_entropy_synthetic_trial_group_; + } private: // VariationsServiceClient: @@ -218,6 +270,7 @@ } std::string restrict_parameter_; + std::string limited_entropy_synthetic_trial_group_; }; class MockVariationsServiceClient : public TestVariationsServiceClient { @@ -278,10 +331,12 @@ const base::FilePath user_data_dir = base::FilePath(), metrics::StartupVisibility startup_visibility = metrics::StartupVisibility::kUnknown) - : VariationsFieldTrialCreator(client, - // Pass a VariationsSeedStore to base class. - CreateSeedStore(local_state), - UIStringOverrider()), + : VariationsFieldTrialCreator( + client, + // Pass a VariationsSeedStore to base class. + CreateSeedStore(local_state), + UIStringOverrider(), + /*limited_entropy_synthetic_trial=*/nullptr), enabled_state_provider_(/*consent=*/true, /*enabled=*/true), // Instead, use a TestVariationsSeedStore as the member variable. seed_store_(local_state), @@ -800,7 +855,8 @@ TestVariationsServiceClient variations_service_client; auto seed_store = CreateSeedStore(local_state()); VariationsFieldTrialCreator field_trial_creator( - &variations_service_client, std::move(seed_store), UIStringOverrider()); + &variations_service_client, std::move(seed_store), UIStringOverrider(), + /*limited_entropy_synthetic_trial=*/nullptr); metrics::TestEnabledStateProvider enabled_state_provider( /*consent=*/true, /*enabled=*/true); @@ -850,7 +906,8 @@ /*signature_verification_enabled=*/false, std::make_unique<VariationsSafeSeedStoreLocalState>(local_state())); VariationsFieldTrialCreator field_trial_creator( - &variations_service_client, std::move(seed_store), UIStringOverrider()); + &variations_service_client, std::move(seed_store), UIStringOverrider(), + /*limited_entropy_synthetic_trial=*/nullptr); metrics::TestEnabledStateProvider enabled_state_provider(/*consent=*/true, /*enabled=*/true); @@ -1374,6 +1431,100 @@ namespace { +struct TestCase { + bool is_limited_layer_in_seed; + bool is_limited_entropy_synthetic_trial_applicable; + std::string test_name; + bool is_group_registration_expected; +}; + +const TestCase kTestCases[] = { + {true, true, "ApplicableClientWithLimitedLayer", true}, + {true, false, "NonApplicableClientWithLimitedLayer", false}, + {false, true, "ApplicableClientWithoutLimitedLayer", false}, + {false, false, "NonApplicableClientWithoutLimitedLayer", false}, +}; + +class LimitedEntropySyntheticTrialGroupRegistrationTest + : public FieldTrialCreatorTest, + public ::testing::WithParamInterface<TestCase> { + public: + LimitedEntropySyntheticTrialGroupRegistrationTest() { + EnableLimitedEntropyModeForTesting(); + } +}; + +INSTANTIATE_TEST_SUITE_P(, + LimitedEntropySyntheticTrialGroupRegistrationTest, + ::testing::ValuesIn(kTestCases), + [](const ::testing::TestParamInfo<TestCase>& info) { + return info.param.test_name; + }); + +TEST_P(LimitedEntropySyntheticTrialGroupRegistrationTest, + RegisterGroupMembership) { + const TestCase test_case = GetParam(); + + VariationsSeed seed; + if (test_case.is_limited_layer_in_seed) { + // Sets up a test seed with a LIMITED entropy layer. + seed = CreateTestSeedWithLimitedEntropyLayer(); + } else { + // Sets up a test seed without a LIMITED entropy layer. + seed = CreateTestSeed(); + } + auto encoded_and_compressed = GZipAndB64EncodeToHexString(seed); + local_state()->SetString(prefs::kVariationsCompressedSeed, + encoded_and_compressed); + + // Allows and writes an empty signature for the test seed. + base::CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kAcceptEmptySeedSignatureForTesting); + local_state()->SetString(prefs::kVariationsSeedSignature, ""); + + // Sets up dependencies and mocks. + TestVariationsServiceClient variations_service_client; + LimitedEntropySyntheticTrial limited_entropy_synthetic_trial(local_state()); + auto seed_store = CreateSeedStore(local_state()); + VariationsFieldTrialCreator field_trial_creator( + &variations_service_client, std::move(seed_store), UIStringOverrider(), + test_case.is_limited_entropy_synthetic_trial_applicable + ? &limited_entropy_synthetic_trial + : nullptr); + metrics::TestEnabledStateProvider enabled_state_provider( + /*consent=*/true, + /*enabled=*/true); + auto metrics_state_manager = metrics::MetricsStateManager::Create( + local_state(), &enabled_state_provider, std::wstring(), base::FilePath()); + metrics_state_manager->InstantiateFieldTrialList(); + PlatformFieldTrials platform_field_trials; + NiceMock<MockSafeSeedManager> safe_seed_manager(local_state()); + + // The client should not be registered to a group of the limited entropy + // synthetic trial before the test. + EXPECT_EQ( + std::string(), + variations_service_client.GetLimitedEntropySyntheticTrialGroupName()); + + EXPECT_TRUE(field_trial_creator.SetUpFieldTrials( + /*variation_ids=*/{}, + /*command_line_variation_ids=*/std::string(), + std::vector<base::FeatureList::FeatureOverrideInfo>(), + std::make_unique<base::FeatureList>(), metrics_state_manager.get(), + &platform_field_trials, &safe_seed_manager, + /*add_entropy_source_to_variations_ids=*/true)); + + if (test_case.is_group_registration_expected) { + EXPECT_NE( + std::string(), + variations_service_client.GetLimitedEntropySyntheticTrialGroupName()); + } else { + EXPECT_EQ( + std::string(), + variations_service_client.GetLimitedEntropySyntheticTrialGroupName()); + } +} + // Test feature names prefixed with __ to avoid collision with real features. BASE_FEATURE(kDesktopFeature, "__Desktop", base::FEATURE_DISABLED_BY_DEFAULT); BASE_FEATURE(kPhoneFeature, "__Phone", base::FEATURE_DISABLED_BY_DEFAULT); @@ -1445,7 +1596,7 @@ // Set up the field trials. VariationsFieldTrialCreator field_trial_creator{ &variations_service_client, CreateSeedStore(local_state()), - UIStringOverrider()}; + UIStringOverrider(), /*limited_entropy_synthetic_trial=*/nullptr}; EXPECT_TRUE(field_trial_creator.SetUpFieldTrials( /*variation_ids=*/{}, /*command_line_variation_ids=*/std::string(),
diff --git a/components/variations/service/variations_service.cc b/components/variations/service/variations_service.cc index 573a4bf4..e57a948 100644 --- a/components/variations/service/variations_service.cc +++ b/components/variations/service/variations_service.cc
@@ -351,7 +351,8 @@ MaybeImportFirstRunSeed(client_.get(), local_state), /*signature_verification_enabled=*/true, std::make_unique<VariationsSafeSeedStoreLocalState>(local_state)), - ui_string_overrider) { + ui_string_overrider, + &limited_entropy_synthetic_trial_) { DCHECK(client_); DCHECK(resource_request_allowed_notifier_);
diff --git a/components/variations/service/variations_service_client.h b/components/variations/service/variations_service_client.h index cc67d49..0cbf36c6 100644 --- a/components/variations/service/variations_service_client.h +++ b/components/variations/service/variations_service_client.h
@@ -82,7 +82,8 @@ // Registers the group membership of the limited entropy synthetic trial. // TODO(crbug.com/1508150): Remove once the trial has wrapped up. - void RegisterLimitedEntropySyntheticTrial(std::string_view group_name); + virtual void RegisterLimitedEntropySyntheticTrial( + std::string_view group_name); private: // Gets the channel of the embedder. But all variations callers should use
diff --git a/content/browser/attribution_reporting/attribution_storage_sql.cc b/content/browser/attribution_reporting/attribution_storage_sql.cc index f42e4d03..09eaf14 100644 --- a/content/browser/attribution_reporting/attribution_storage_sql.cc +++ b/content/browser/attribution_reporting/attribution_storage_sql.cc
@@ -749,6 +749,11 @@ return StoreSourceResult::InternalError(); } + DCHECK_LT(AttributionStorageSql::kCurrentVersionNumber, 86); + base::UmaHistogramCustomCounts("Conversions.DbVersionOnSourceStored", + kCurrentVersionNumber, /*min=*/56, + /*exclusive_max=*/86, /*buckets=*/30); + if (attribution_logic == StoredSource::AttributionLogic::kTruthfully) { return StoreSourceResult::Success(); }
diff --git a/content/browser/attribution_reporting/attribution_storage_unittest.cc b/content/browser/attribution_reporting/attribution_storage_unittest.cc index dc93572..6f0bdd0 100644 --- a/content/browser/attribution_reporting/attribution_storage_unittest.cc +++ b/content/browser/attribution_reporting/attribution_storage_unittest.cc
@@ -217,7 +217,10 @@ } TEST_F(AttributionStorageTest, ImpressionStoredAndRetrieved_ValuesIdentical) { + base::HistogramTester histograms; storage()->StoreSource(SourceBuilder().Build()); + histograms.ExpectBucketCount("Conversions.DbVersionOnSourceStored", + AttributionStorageSql::kCurrentVersionNumber, 1); EXPECT_THAT(storage()->GetActiveSources(), ElementsAre(SourceBuilder().BuildStored())); }
diff --git a/content/browser/webauth/authenticator_impl_unittest.cc b/content/browser/webauth/authenticator_impl_unittest.cc index a9efd96..80cabc5a 100644 --- a/content/browser/webauth/authenticator_impl_unittest.cc +++ b/content/browser/webauth/authenticator_impl_unittest.cc
@@ -5926,13 +5926,13 @@ device_1.state->pin = kTestPIN; device_1.config.pin_support = true; std::tie(disconnect_1, device_1.disconnect_events) = - device::FidoDeviceDiscovery::EventStream<bool>::New(); + device::FidoDiscoveryBase::EventStream<bool>::New(); device::test::MultipleVirtualFidoDeviceFactory::DeviceDetails device_2; device_2.state->pin = kTestPIN; device_2.config.pin_support = true; std::tie(disconnect_2, device_2.disconnect_events) = - device::FidoDeviceDiscovery::EventStream<bool>::New(); + device::FidoDiscoveryBase::EventStream<bool>::New(); int callbacks = 0; auto touch_callback = [&](int device_num) -> bool {
diff --git a/content/shell/browser/shell_content_browser_client.cc b/content/shell/browser/shell_content_browser_client.cc index 84da983..c40f945 100644 --- a/content/shell/browser/shell_content_browser_client.cc +++ b/content/shell/browser/shell_content_browser_client.cc
@@ -833,7 +833,10 @@ /*signature_verification_enabled=*/true, std::make_unique<variations::VariationsSafeSeedStoreLocalState>( GetSharedState().local_state.get())), - variations::UIStringOverrider()); + variations::UIStringOverrider(), + // The limited entropy synthetic trial will not be registered for this + // purpose. + /*limited_entropy_synthetic_trial=*/nullptr); variations::SafeSeedManager safe_seed_manager( GetSharedState().local_state.get());
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt index 8020694..47f19fa 100644 --- a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
@@ -522,7 +522,10 @@ # been made more robust. # crbug.com/735483 [ mac amd release ] conformance/rendering/texture-switch-performance.html [ Failure ] -crbug.com/1435021 [ amd-0x67ef angle-metal mac no-clang-coverage release ] conformance/canvas/draw-webgl-to-canvas-test.html [ Failure ] +crbug.com/1435021 [ amd-0x67ef angle-metal mac no-clang-coverage release graphite-disabled ] conformance/canvas/draw-webgl-to-canvas-test.html [ Failure ] + +crbug.com/1513193 [ mac amd angle-metal graphite-enabled ] conformance/canvas/draw-webgl-to-canvas-test.html [ RetryOnFailure ] +crbug.com/1513193 [ mac amd angle-metal graphite-enabled ] conformance/canvas/to-data-url-test.html [ RetryOnFailure ] ## Mac Intel ##
diff --git a/device/fido/cable/fido_cable_discovery.cc b/device/fido/cable/fido_cable_discovery.cc index 018d1fa..e2f412f 100644 --- a/device/fido/cable/fido_cable_discovery.cc +++ b/device/fido/cable/fido_cable_discovery.cc
@@ -153,7 +153,7 @@ adapter_->RemoveObserver(this); } -std::unique_ptr<FidoDeviceDiscovery::EventStream<base::span<const uint8_t, 20>>> +std::unique_ptr<FidoDiscoveryBase::EventStream<base::span<const uint8_t, 20>>> FidoCableDiscovery::GetV2AdvertStream() { DCHECK(!advert_callback_);
diff --git a/device/fido/cable/fido_cable_discovery.h b/device/fido/cable/fido_cable_discovery.h index 85b0664..f3b29ea 100644 --- a/device/fido/cable/fido_cable_discovery.h +++ b/device/fido/cable/fido_cable_discovery.h
@@ -52,8 +52,7 @@ // GetV2AdvertStream returns a stream of caBLEv2 BLE adverts. Only a single // stream is supported. - std::unique_ptr<FidoDeviceDiscovery::EventStream< - base::span<const uint8_t, cablev2::kAdvertSize>>> + std::unique_ptr<EventStream<base::span<const uint8_t, cablev2::kAdvertSize>>> GetV2AdvertStream(); const std::map<CableEidArray, scoped_refptr<BluetoothAdvertisement>>&
diff --git a/device/fido/enclave/enclave_authenticator.cc b/device/fido/enclave/enclave_authenticator.cc index 31635810..2c15390 100644 --- a/device/fido/enclave/enclave_authenticator.cc +++ b/device/fido/enclave/enclave_authenticator.cc
@@ -114,11 +114,42 @@ StartRequest(); } +void EnclaveAuthenticator::SetOauthToken( + absl::optional<std::string_view> token) { + if (token == absl::nullopt) { + state_ = State::kError; + } else { + websocket_client_->set_oauth_token(*token); + } + + if (state_ == State::kWaitingForOauthToken) { + StartRequest(); + return; + } + + if (state_ == State::kInitialized) { + state_ = State::kOauthTokenReceived; + } +} + void EnclaveAuthenticator::StartRequest() { CHECK(!pending_get_assertion_request_ != !pending_make_credential_request_); if (state_ == State::kInitialized) { + state_ = State::kWaitingForOauthToken; + return; + } + + if (state_ == State::kError) { + // This can mean we received a null OAuth token. + CompleteRequestWithError(CtapDeviceResponseCode::kCtap2ErrOther); + return; + } + + if (state_ == State::kOauthTokenReceived || + state_ == State::kWaitingForOauthToken) { CHECK(!handshake_); + state_ = State::kWaitingForHandshakeResponse; handshake_ = std::make_unique<cablev2::HandshakeInitiator>(
diff --git a/device/fido/enclave/enclave_authenticator.h b/device/fido/enclave/enclave_authenticator.h index 64998df2..92ed3982 100644 --- a/device/fido/enclave/enclave_authenticator.h +++ b/device/fido/enclave/enclave_authenticator.h
@@ -6,6 +6,8 @@ #define DEVICE_FIDO_ENCLAVE_ENCLAVE_AUTHENTICATOR_H_ #include <memory> +#include <string> +#include <string_view> #include <vector> #include "base/component_export.h" @@ -35,8 +37,6 @@ namespace enclave { -// TODO(kenrb): Remove the export directive when it is no longer used by the -// client stand-alone app. class COMPONENT_EXPORT(DEVICE_FIDO) EnclaveAuthenticator : public FidoAuthenticator { public: @@ -63,9 +63,13 @@ MakeCredentialOptions options, MakeCredentialCallback callback) override; + void SetOauthToken(absl::optional<std::string_view> token); + private: enum class State { kInitialized, + kWaitingForOauthToken, + kOauthTokenReceived, kWaitingForHandshakeResponse, kConnected, kError,
diff --git a/device/fido/enclave/enclave_discovery.cc b/device/fido/enclave/enclave_discovery.cc index 8d5b3d4c..9f0ba51 100644 --- a/device/fido/enclave/enclave_discovery.cc +++ b/device/fido/enclave/enclave_discovery.cc
@@ -54,11 +54,18 @@ std::vector<sync_pb::WebauthnCredentialSpecifics> passkeys, base::RepeatingCallback<void(sync_pb::WebauthnCredentialSpecifics)> save_passkey_callback, - raw_ptr<network::mojom::NetworkContext> network_context) + raw_ptr<network::mojom::NetworkContext> network_context, + std::unique_ptr<EventStream<absl::optional<std::string_view>>> + oauth_token_provider) : FidoDiscoveryBase(FidoTransportProtocol::kInternal), passkeys_(std::move(passkeys)), save_passkey_callback_(std::move(save_passkey_callback)), - network_context_(network_context) {} + network_context_(network_context), + oauth_token_provider_(std::move(oauth_token_provider)) { + oauth_token_provider_->Connect( + base::BindRepeating(&EnclaveAuthenticatorDiscovery::OnOauthTokenAvailable, + weak_factory_.GetWeakPtr())); +} EnclaveAuthenticatorDiscovery::~EnclaveAuthenticatorDiscovery() = default; @@ -98,4 +105,9 @@ observer()->DiscoveryStarted(this, /*success=*/true, {authenticator_.get()}); } +void EnclaveAuthenticatorDiscovery::OnOauthTokenAvailable( + absl::optional<std::string_view> token) { + authenticator_->SetOauthToken(token); +} + } // namespace device::enclave
diff --git a/device/fido/enclave/enclave_discovery.h b/device/fido/enclave/enclave_discovery.h index 0cd170e9..6d9f5879 100644 --- a/device/fido/enclave/enclave_discovery.h +++ b/device/fido/enclave/enclave_discovery.h
@@ -6,6 +6,7 @@ #define DEVICE_FIDO_ENCLAVE_ENCLAVE_DISCOVERY_H_ #include <memory> +#include <string_view> #include "base/component_export.h" #include "base/memory/raw_ptr.h" @@ -13,6 +14,7 @@ #include "crypto/ec_private_key.h" #include "device/fido/fido_discovery_base.h" #include "services/network/public/mojom/network_context.mojom.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace sync_pb { class WebauthnCredentialSpecifics; @@ -31,7 +33,9 @@ std::vector<sync_pb::WebauthnCredentialSpecifics> passkeys, base::RepeatingCallback<void(sync_pb::WebauthnCredentialSpecifics)> save_passkey_callback, - raw_ptr<network::mojom::NetworkContext> network_context); + raw_ptr<network::mojom::NetworkContext> network_context, + std::unique_ptr<EventStream<absl::optional<std::string_view>>> + oauth_token_provider); ~EnclaveAuthenticatorDiscovery() override; // FidoDiscoveryBase: @@ -39,12 +43,15 @@ private: void AddAuthenticator(); + void OnOauthTokenAvailable(absl::optional<std::string_view> token); std::unique_ptr<EnclaveAuthenticator> authenticator_; std::vector<sync_pb::WebauthnCredentialSpecifics> passkeys_; base::RepeatingCallback<void(sync_pb::WebauthnCredentialSpecifics)> save_passkey_callback_; raw_ptr<network::mojom::NetworkContext> network_context_; + std::unique_ptr<EventStream<absl::optional<std::string_view>>> + oauth_token_provider_; // TODO(https://crbug.com/1459620): Temporary for the stand-in signing // function.
diff --git a/device/fido/enclave/enclave_websocket_client.cc b/device/fido/enclave/enclave_websocket_client.cc index 5e2074d..26cb8ee 100644 --- a/device/fido/enclave/enclave_websocket_client.cc +++ b/device/fido/enclave/enclave_websocket_client.cc
@@ -9,6 +9,7 @@ #include "components/device_event_log/device_event_log.h" #include "device/fido/fido_constants.h" #include "device/fido/fido_parsing_utils.h" +#include "net/http/http_request_headers.h" #include "net/traffic_annotation/network_traffic_annotation.h" namespace device::enclave { @@ -103,6 +104,10 @@ InternalWrite(data); } +void EnclaveWebSocketClient::set_oauth_token(std::string_view token) { + oauth_token_ = token; +} + void EnclaveWebSocketClient::Connect() { // A disconnect handler is used so that the request can be completed in the // event of an unexpected disconnection from the network service. @@ -112,15 +117,18 @@ state_ = State::kConnecting; + std::vector<network::mojom::HttpHeaderPtr> additional_headers; + additional_headers.emplace_back(network::mojom::HttpHeader::New( + net::HttpRequestHeaders::kAuthorization, oauth_token_)); + GURL socket_url; GURL::Replacements replacement; replacement.SetPathStr(username_); socket_url = service_url_.ReplaceComponents(replacement); network_context_->CreateWebSocket( socket_url, {}, net::SiteForCookies(), /*has_storage_access=*/false, - net::IsolationInfo(), - /*additional_headers=*/{}, network::mojom::kBrowserProcessId, - url::Origin::Create(socket_url), + net::IsolationInfo(), std::move(additional_headers), + network::mojom::kBrowserProcessId, url::Origin::Create(socket_url), network::mojom::kWebSocketOptionBlockAllCookies, net::MutableNetworkTrafficAnnotationTag(kTrafficAnnotation), std::move(handshake_remote),
diff --git a/device/fido/enclave/enclave_websocket_client.h b/device/fido/enclave/enclave_websocket_client.h index ad54de70..444a7e9 100644 --- a/device/fido/enclave/enclave_websocket_client.h +++ b/device/fido/enclave/enclave_websocket_client.h
@@ -50,6 +50,8 @@ // received. void Write(base::span<const uint8_t> data); + void set_oauth_token(std::string_view token); + // WebSocketHandshakeClient: void OnOpeningHandshakeStarted( network::mojom::WebSocketHandshakeRequestPtr request) override; @@ -93,6 +95,9 @@ raw_ptr<network::mojom::NetworkContext> network_context_; OnResponseCallback on_response_; + // Token used for the Authorization header in the WebSocket connection. + std::string oauth_token_; + // pending_read_data_ contains a partial message that is being reassembled. std::vector<uint8_t> pending_read_data_; // pending_read_data_index_ contains the number of valid bytes of
diff --git a/device/fido/fido_device_discovery.h b/device/fido/fido_device_discovery.h index 5cb50ce..af32a8f 100644 --- a/device/fido/fido_device_discovery.h +++ b/device/fido/fido_device_discovery.h
@@ -14,7 +14,6 @@ #include <vector> #include "base/component_export.h" -#include "base/functional/bind.h" #include "base/memory/weak_ptr.h" #include "device/fido/fido_discovery_base.h" #include "device/fido/fido_transport_protocol.h" @@ -27,38 +26,6 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoDeviceDiscovery : public FidoDiscoveryBase { public: - // EventStream is an unbuffered pipe that can be passed around and late-bound - // to the receiver. - template <typename T> - class EventStream { - public: - using Callback = base::RepeatingCallback<void(T)>; - - // New returns a callback for writing events, and ownership of an - // |EventStream| that can be connected to in order to receive the events. - // The callback may outlive the |EventStream|. Any events written when - // either the |EventStream| has been deleted, or not yet connected, are - // dropped. - static std::pair<Callback, std::unique_ptr<EventStream<T>>> New() { - auto stream = std::make_unique<EventStream<T>>(); - auto cb = base::BindRepeating(&EventStream::Transmit, - stream->weak_factory_.GetWeakPtr()); - return std::make_pair(std::move(cb), std::move(stream)); - } - - void Connect(Callback connection) { connection_ = std::move(connection); } - - private: - void Transmit(T t) { - if (connection_) { - connection_.Run(std::move(t)); - } - } - - Callback connection_; - base::WeakPtrFactory<EventStream<T>> weak_factory_{this}; - }; - enum class State { kIdle, kStarting,
diff --git a/device/fido/fido_discovery_base.h b/device/fido/fido_discovery_base.h index 66544cf8..2b142c1 100644 --- a/device/fido/fido_discovery_base.h +++ b/device/fido/fido_discovery_base.h
@@ -11,7 +11,10 @@ #include "base/check.h" #include "base/component_export.h" +#include "base/functional/bind.h" +#include "base/functional/callback.h" #include "base/memory/raw_ptr.h" +#include "base/memory/weak_ptr.h" #include "device/fido/fido_transport_protocol.h" namespace device { @@ -20,6 +23,38 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoDiscoveryBase { public: + // EventStream is an unbuffered pipe that can be passed around and late-bound + // to the receiver. + template <typename T> + class EventStream { + public: + using Callback = base::RepeatingCallback<void(T)>; + + // New returns a callback for writing events, and ownership of an + // |EventStream| that can be connected to in order to receive the events. + // The callback may outlive the |EventStream|. Any events written when + // either the |EventStream| has been deleted, or not yet connected, are + // dropped. + static std::pair<Callback, std::unique_ptr<EventStream<T>>> New() { + auto stream = std::make_unique<EventStream<T>>(); + auto cb = base::BindRepeating(&EventStream::Transmit, + stream->weak_factory_.GetWeakPtr()); + return std::make_pair(std::move(cb), std::move(stream)); + } + + void Connect(Callback connection) { connection_ = std::move(connection); } + + private: + void Transmit(T t) { + if (connection_) { + connection_.Run(std::move(t)); + } + } + + Callback connection_; + base::WeakPtrFactory<EventStream<T>> weak_factory_{this}; + }; + FidoDiscoveryBase(const FidoDiscoveryBase&) = delete; FidoDiscoveryBase& operator=(const FidoDiscoveryBase&) = delete;
diff --git a/device/fido/fido_discovery_factory.cc b/device/fido/fido_discovery_factory.cc index 9bfbdbe8..77366a66 100644 --- a/device/fido/fido_discovery_factory.cc +++ b/device/fido/fido_discovery_factory.cc
@@ -194,6 +194,15 @@ enclave_passkey_creation_callback_ = callback; } +base::RepeatingCallback<void(absl::optional<std::string_view>)> +FidoDiscoveryFactory::get_enclave_oauth_token_callback() { + CHECK(!oauth_token_provider_); + base::RepeatingCallback<void(absl::optional<std::string_view>)> ret; + std::tie(ret, oauth_token_provider_) = + FidoDiscoveryBase::EventStream<absl::optional<std::string_view>>::New(); + return ret; +} + // static std::vector<std::unique_ptr<FidoDiscoveryBase>> FidoDiscoveryFactory::SingleDiscovery( @@ -274,7 +283,8 @@ discoveries.emplace_back( std::make_unique<enclave::EnclaveAuthenticatorDiscovery>( std::move(enclave_passkeys_), - std::move(enclave_passkey_creation_callback_), network_context_)); + std::move(enclave_passkey_creation_callback_), network_context_, + std::move(oauth_token_provider_))); } #endif
diff --git a/device/fido/fido_discovery_factory.h b/device/fido/fido_discovery_factory.h index ec95a51..3e043fec 100644 --- a/device/fido/fido_discovery_factory.h +++ b/device/fido/fido_discovery_factory.h
@@ -7,6 +7,7 @@ #include <memory> #include <string> +#include <string_view> #include <vector> #include "base/component_export.h" @@ -103,6 +104,11 @@ base::RepeatingCallback<void(sync_pb::WebauthnCredentialSpecifics)> callback); + // Returns a callback that can be called to provide the OAuth token for + // connecting to the cloud enclave authenticator. + virtual base::RepeatingCallback<void(absl::optional<std::string_view>)> + get_enclave_oauth_token_callback(); + #if BUILDFLAG(IS_MAC) // Configures the Touch ID authenticator. Set to absl::nullopt to disable it. void set_mac_touch_id_info( @@ -191,6 +197,9 @@ std::vector<sync_pb::WebauthnCredentialSpecifics> enclave_passkeys_; base::RepeatingCallback<void(sync_pb::WebauthnCredentialSpecifics)> enclave_passkey_creation_callback_; + std::unique_ptr< + FidoDiscoveryBase::EventStream<absl::optional<std::string_view>>> + oauth_token_provider_; }; } // namespace device
diff --git a/device/fido/virtual_fido_device_factory.cc b/device/fido/virtual_fido_device_factory.cc index 7e6ecc9..abf31f05 100644 --- a/device/fido/virtual_fido_device_factory.cc +++ b/device/fido/virtual_fido_device_factory.cc
@@ -58,8 +58,8 @@ base::RepeatingCallback<void(std::unique_ptr<cablev2::Pairing>)> VirtualFidoDeviceFactory::get_cable_contact_callback() { base::RepeatingCallback<void(std::unique_ptr<cablev2::Pairing>)> ret; - std::tie(ret, contact_device_stream_) = FidoDeviceDiscovery::EventStream< - std::unique_ptr<cablev2::Pairing>>::New(); + std::tie(ret, contact_device_stream_) = + FidoDiscoveryBase::EventStream<std::unique_ptr<cablev2::Pairing>>::New(); return ret; }
diff --git a/device/fido/virtual_fido_device_factory.h b/device/fido/virtual_fido_device_factory.h index dff1081..11d31155 100644 --- a/device/fido/virtual_fido_device_factory.h +++ b/device/fido/virtual_fido_device_factory.h
@@ -12,6 +12,7 @@ #include "base/memory/scoped_refptr.h" #include "device/fido/cable/cable_discovery_data.h" #include "device/fido/fido_constants.h" +#include "device/fido/fido_discovery_base.h" #include "device/fido/fido_discovery_factory.h" #include "device/fido/fido_transport_protocol.h" #include "device/fido/virtual_ctap2_device.h" @@ -69,7 +70,7 @@ private: std::unique_ptr< - FidoDeviceDiscovery::EventStream<std::unique_ptr<cablev2::Pairing>>> + FidoDiscoveryBase::EventStream<std::unique_ptr<cablev2::Pairing>>> contact_device_stream_; ProtocolVersion supported_protocol_ = ProtocolVersion::kU2f; FidoTransportProtocol transport_ =
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd index 4e92073..19e8a42e 100644 --- a/ios/chrome/app/strings/ios_strings.grd +++ b/ios/chrome/app/strings/ios_strings.grd
@@ -1371,6 +1371,15 @@ <message name="IDS_IOS_DOWNLOAD_MANAGER_DOWNLOAD_TO_FILES" desc="Button to start downloading a file to Files e.g. download to local storage. Files is a product name i.e. the Files app on iOS devices and the correct localized version of the product name should be used. [Length: 15em] [iOS only]" meaning="Button to start downloading a file to Files e.g. download to local storage. Files is a product name i.e. the Files app on iOS devices and the correct localized version of the product name should be used. [Length: 15em] [iOS only]"> Files </message> + <message name="IDS_IOS_DOWNLOAD_MANAGER_FILENAME_WITH_SIZE" desc="Label for the download manager when the download has completed. It includes the size of the downloaded file. [iOS only]" meaning="Label for the download manager when the download has completed. It includes the size of the downloaded file. [iOS only]"> + <ph name="FILENAME">$1<ex>image.jpeg</ex></ph> (<ph name="FILESIZE">$2<ex>4 MB</ex></ph>) + </message> + <message name="IDS_IOS_DOWNLOAD_MANAGER_SAVED_TO_DRIVE" desc="Label for the file having been downloaded to Drive. [iOS only]" meaning="Label for the file having been downloaded to Drive. [iOS only]"> + saved in Drive for <ph name="USER_EMAIL">$1<ex>peter.parker@gmail.com</ex></ph>. + </message> + <message name="IDS_IOS_DOWNLOAD_MANAGER_SAVING_TO_DRIVE" desc="Label for the file being downloaded to Drive. [iOS only]" meaning="Label for the file being downloaded to Drive. [iOS only]"> + saving in Drive for <ph name="USER_EMAIL">$1<ex>peter.parker@gmail.com</ex></ph>. + </message> <message name="IDS_IOS_DOWNLOAD_MANAGER_FAILED_ACCESSIBILITY_ANNOUNCEMENT" desc="The accessibility announcement read by Voice Over when the download has failed. [Length: unlimited] [iOS only]"> Download failed </message>
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_DOWNLOAD_MANAGER_FILENAME_WITH_SIZE.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_DOWNLOAD_MANAGER_FILENAME_WITH_SIZE.png.sha1 new file mode 100644 index 0000000..73603dd --- /dev/null +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_DOWNLOAD_MANAGER_FILENAME_WITH_SIZE.png.sha1
@@ -0,0 +1 @@ +815b3d11cefbab6d982ddcb21f73ddcac3024433 \ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_DOWNLOAD_MANAGER_SAVED_TO_DRIVE.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_DOWNLOAD_MANAGER_SAVED_TO_DRIVE.png.sha1 new file mode 100644 index 0000000..eac08d3 --- /dev/null +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_DOWNLOAD_MANAGER_SAVED_TO_DRIVE.png.sha1
@@ -0,0 +1 @@ +3f8c0ad5c0613c5c609eccc7eb1dfa2203fb05e1 \ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_DOWNLOAD_MANAGER_SAVING_TO_DRIVE.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_DOWNLOAD_MANAGER_SAVING_TO_DRIVE.png.sha1 new file mode 100644 index 0000000..73603dd --- /dev/null +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_DOWNLOAD_MANAGER_SAVING_TO_DRIVE.png.sha1
@@ -0,0 +1 @@ +815b3d11cefbab6d982ddcb21f73ddcac3024433 \ No newline at end of file
diff --git a/ios/chrome/browser/download/model/BUILD.gn b/ios/chrome/browser/download/model/BUILD.gn index 3763a23..4219d0c9 100644 --- a/ios/chrome/browser/download/model/BUILD.gn +++ b/ios/chrome/browser/download/model/BUILD.gn
@@ -45,6 +45,7 @@ "//components/keyed_service/ios", "//components/strings", "//ios/chrome/app/strings", + "//ios/chrome/browser/drive/model:drive_tab_helper", "//ios/chrome/browser/overlays/model", "//ios/chrome/browser/overlays/model/public/common/confirmation", "//ios/chrome/browser/overlays/model/public/common/confirmation:util", @@ -52,6 +53,7 @@ "//ios/chrome/browser/shared/model/browser_state", "//ios/chrome/browser/shared/model/utils", "//ios/chrome/browser/shared/public/commands", + "//ios/chrome/browser/shared/public/features", "//ios/chrome/browser/ui/download:features", "//ios/web/common", "//ios/web/public",
diff --git a/ios/chrome/browser/download/model/DEPS b/ios/chrome/browser/download/model/DEPS index e45e3c1..6fba973 100644 --- a/ios/chrome/browser/download/model/DEPS +++ b/ios/chrome/browser/download/model/DEPS
@@ -2,6 +2,7 @@ "+ios/chrome/browser/prerender/model", "+ios/chrome/browser/overlays/model/public", "+ios/chrome/browser/optimization_guide/model", + "+ios/chrome/browser/drive/model", ] specific_include_rules = {
diff --git a/ios/chrome/browser/download/model/download_manager_tab_helper.h b/ios/chrome/browser/download/model/download_manager_tab_helper.h index f295b74..14da962 100644 --- a/ios/chrome/browser/download/model/download_manager_tab_helper.h +++ b/ios/chrome/browser/download/model/download_manager_tab_helper.h
@@ -43,7 +43,7 @@ void SetDelegate(id<DownloadManagerTabHelperDelegate> delegate); // Starts the current download task and remember to save it to Drive. - void StartDownloadTaskAndSaveToDrive(id<SystemIdentity> selected_identity); + virtual void OnDownloadAddedToSaveToDrive(web::DownloadTask* task); protected: // Allow subclassing from DownloadManagerTabHelper for testing purposes. @@ -63,6 +63,8 @@ // Assigns `task` to `task_`; replaces the current download if exists; // instructs the delegate that download has started. void DidCreateDownload(std::unique_ptr<web::DownloadTask> task); + // Returns whether `task_` still needs to be saved to Drive. + bool WillDownloadTaskBeSavedToDrive() const; web::WebState* web_state_ = nullptr; __weak id<DownloadManagerTabHelperDelegate> delegate_ = nil;
diff --git a/ios/chrome/browser/download/model/download_manager_tab_helper.mm b/ios/chrome/browser/download/model/download_manager_tab_helper.mm index 55c87e68..ae51761 100644 --- a/ios/chrome/browser/download/model/download_manager_tab_helper.mm +++ b/ios/chrome/browser/download/model/download_manager_tab_helper.mm
@@ -5,9 +5,12 @@ #import "ios/chrome/browser/download/model/download_manager_tab_helper.h" #import "base/check_op.h" +#import "base/feature_list.h" #import "base/memory/ptr_util.h" #import "base/notreached.h" #import "ios/chrome/browser/download/model/download_manager_tab_helper_delegate.h" +#import "ios/chrome/browser/drive/model/drive_tab_helper.h" +#import "ios/chrome/browser/shared/public/features/features.h" #import "ios/web/public/download/download_task.h" DownloadManagerTabHelper::DownloadManagerTabHelper(web::WebState* web_state) @@ -33,7 +36,8 @@ void DownloadManagerTabHelper::Download( std::unique_ptr<web::DownloadTask> task) { // If downloads are persistent, they cannot be lost once completed. - if (!task_ || task_->GetState() == web::DownloadTask::State::kComplete) { + if (!task_ || (task_->GetState() == web::DownloadTask::State::kComplete && + !WillDownloadTaskBeSavedToDrive())) { // The task is the first download for this web state. DidCreateDownload(std::move(task)); return; @@ -61,9 +65,11 @@ delegate_ = delegate; } -void DownloadManagerTabHelper::StartDownloadTaskAndSaveToDrive( - id<SystemIdentity> selected_identity) { - // TODO(crbug.com/1495353): Start the download task through `delegate_`. +void DownloadManagerTabHelper::OnDownloadAddedToSaveToDrive( + web::DownloadTask* task) { + DCHECK_EQ(task, task_.get()); + [delegate_ downloadManagerTabHelper:this + didAddDownloadToSaveToDrive:task_.get()]; } #pragma mark - web::WebStateObserver @@ -130,4 +136,15 @@ } } +bool DownloadManagerTabHelper::WillDownloadTaskBeSavedToDrive() const { + if (!base::FeatureList::IsEnabled(kIOSSaveToDrive)) { + return false; + } + DriveTabHelper* drive_tab_helper = + DriveTabHelper::FromWebState(task_->GetWebState()); + std::optional<DownloadTaskSaveToDriveData> save_to_drive_data = + drive_tab_helper->GetDownloadTaskSaveToDriveData(); + return save_to_drive_data && save_to_drive_data->task == task_.get(); +} + WEB_STATE_USER_DATA_KEY_IMPL(DownloadManagerTabHelper)
diff --git a/ios/chrome/browser/download/model/download_manager_tab_helper_delegate.h b/ios/chrome/browser/download/model/download_manager_tab_helper_delegate.h index d3ef707..facc710 100644 --- a/ios/chrome/browser/download/model/download_manager_tab_helper_delegate.h +++ b/ios/chrome/browser/download/model/download_manager_tab_helper_delegate.h
@@ -25,23 +25,29 @@ @protocol DownloadManagerTabHelperDelegate<NSObject> // Informs the delegate that a DownloadTask was created. -- (void)downloadManagerTabHelper:(nonnull DownloadManagerTabHelper*)tabHelper - didCreateDownload:(nonnull web::DownloadTask*)download +- (void)downloadManagerTabHelper:(DownloadManagerTabHelper*)tabHelper + didCreateDownload:(web::DownloadTask*)download webStateIsVisible:(BOOL)webStateIsVisible; // Asks the delegate whether the new download task should replace the old // download task. -- (void)downloadManagerTabHelper:(nonnull DownloadManagerTabHelper*)tabHelper - decidePolicyForDownload:(nonnull web::DownloadTask*)download - completionHandler:(nonnull void (^)(NewDownloadPolicy))handler; +- (void)downloadManagerTabHelper:(DownloadManagerTabHelper*)tabHelper + decidePolicyForDownload:(web::DownloadTask*)download + completionHandler:(void (^)(NewDownloadPolicy))handler; // Informs the delegate that WebState related to this download was hidden. -- (void)downloadManagerTabHelper:(nonnull DownloadManagerTabHelper*)tabHelper - didHideDownload:(nonnull web::DownloadTask*)download; +- (void)downloadManagerTabHelper:(DownloadManagerTabHelper*)tabHelper + didHideDownload:(web::DownloadTask*)download; // Informs the delegate that WebState related to this download was shown. -- (void)downloadManagerTabHelper:(nonnull DownloadManagerTabHelper*)tabHelper - didShowDownload:(nonnull web::DownloadTask*)download; +- (void)downloadManagerTabHelper:(DownloadManagerTabHelper*)tabHelper + didShowDownload:(web::DownloadTask*)download; + +// Informs the delegate that `download` was added to Save to Drive and will be +// uploaded once the download has completed. This should lead the delegate to +// start the download task. +- (void)downloadManagerTabHelper:(DownloadManagerTabHelper*)tabHelper + didAddDownloadToSaveToDrive:(web::DownloadTask*)download; @end
diff --git a/ios/chrome/browser/drive/model/BUILD.gn b/ios/chrome/browser/drive/model/BUILD.gn index f28fd10..808a128 100644 --- a/ios/chrome/browser/drive/model/BUILD.gn +++ b/ios/chrome/browser/drive/model/BUILD.gn
@@ -16,6 +16,20 @@ ] } +source_set("drive_tab_helper") { + sources = [ + "download_task_save_to_drive_data.h", + "drive_tab_helper.h", + "drive_tab_helper.mm", + ] + deps = [ + "//base", + "//ios/web/public", + "//ios/web/public:web_state_observer", + "//ios/web/public/download", + ] +} + source_set("drive_service") { sources = [ "drive_service.h", @@ -44,11 +58,17 @@ source_set("unit_tests") { testonly = true - sources = [ "drive_service_factory_unittest.mm" ] + sources = [ + "drive_service_factory_unittest.mm", + "drive_tab_helper_unittest.mm", + ] deps = [ ":drive_service_factory", + ":drive_tab_helper", "//base/test:test_support", "//ios/chrome/browser/shared/model/browser_state:test_support", + "//ios/chrome/browser/signin/model:fake_system_identity", + "//ios/web/public/test/fakes", "//testing/gtest", ] }
diff --git a/ios/chrome/browser/drive/model/download_task_save_to_drive_data.h b/ios/chrome/browser/drive/model/download_task_save_to_drive_data.h new file mode 100644 index 0000000..a741abb --- /dev/null +++ b/ios/chrome/browser/drive/model/download_task_save_to_drive_data.h
@@ -0,0 +1,23 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_DRIVE_MODEL_DOWNLOAD_TASK_SAVE_TO_DRIVE_DATA_H_ +#define IOS_CHROME_BROWSER_DRIVE_MODEL_DOWNLOAD_TASK_SAVE_TO_DRIVE_DATA_H_ + +@protocol SystemIdentity; +namespace web { +class DownloadTask; +} + +// Data necessary to keep track of a DownloadTask whose resulting downloaded +// file should be saved to Drive. +struct DownloadTaskSaveToDriveData { + bool operator==(const DownloadTaskSaveToDriveData& rhs) const = default; + // The `DownloadTask` which will be saved to Drive. + raw_ptr<web::DownloadTask> task; + // The `identity` which should be used to save the downloaded file to Drive. + id<SystemIdentity> identity; +}; + +#endif // IOS_CHROME_BROWSER_DRIVE_MODEL_DOWNLOAD_TASK_SAVE_TO_DRIVE_DATA_H_
diff --git a/ios/chrome/browser/drive/model/drive_tab_helper.h b/ios/chrome/browser/drive/model/drive_tab_helper.h new file mode 100644 index 0000000..e1ddbe9 --- /dev/null +++ b/ios/chrome/browser/drive/model/drive_tab_helper.h
@@ -0,0 +1,61 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_DRIVE_MODEL_DRIVE_TAB_HELPER_H_ +#define IOS_CHROME_BROWSER_DRIVE_MODEL_DRIVE_TAB_HELPER_H_ + +#import "base/scoped_observation.h" +#import "ios/chrome/browser/drive/model/download_task_save_to_drive_data.h" +#import "ios/web/public/download/download_task.h" +#import "ios/web/public/download/download_task_observer.h" +#import "ios/web/public/web_state_observer.h" +#import "ios/web/public/web_state_user_data.h" + +// Manages Save to Drive tab-scoped state i.e. if a `DownloadTask` is received +// through AddDownloadToSaveToDrive(...) then this tab helper +// - 1 - memorises the task, what `SystemIdentity` will be used to save the +// downloaded file to Drive, etc. +// - 2 - observes the `DownloadTask` and uploads the downloaded file using the +// Drive service upon completion of the task. +class DriveTabHelper : public web::WebStateUserData<DriveTabHelper>, + public web::DownloadTaskObserver { + public: + DriveTabHelper(const DriveTabHelper&) = delete; + DriveTabHelper& operator=(const DriveTabHelper&) = delete; + ~DriveTabHelper() override; + + // Adds a DownloadTask to Save to Drive. This download task will be observed + // and the downloaded file will be uploaded to Drive. + void AddDownloadToSaveToDrive(web::DownloadTask* task, + id<SystemIdentity> identity); + // Returns Save to Drive data associated with the current download task. + std::optional<DownloadTaskSaveToDriveData> GetDownloadTaskSaveToDriveData() + const; + + private: + friend class web::WebStateUserData<DriveTabHelper>; + explicit DriveTabHelper(web::WebState* web_state); + + // web::DownloadTaskObserver overrides: + void OnDownloadUpdated(web::DownloadTask* task) override; + void OnDownloadDestroyed(web::DownloadTask* task) override; + + // Resets the Save to Drive data i.e. stop observing the current task, and + // start observing the task in `data` if any. + void ResetSaveToDriveData(std::optional<DownloadTaskSaveToDriveData> data); + + // Associated WebState. + raw_ptr<web::WebState> web_state_; + + // Save to Drive data associated with the current download task. + std::optional<DownloadTaskSaveToDriveData> download_task_save_to_drive_data_; + // Scoped observation to observe the `DownloadTask`. + using ScopedDownloadTaskObservation = + base::ScopedObservation<web::DownloadTask, web::DownloadTaskObserver>; + ScopedDownloadTaskObservation download_task_obs_{this}; + + WEB_STATE_USER_DATA_KEY_DECL(); +}; + +#endif // IOS_CHROME_BROWSER_DRIVE_MODEL_DRIVE_TAB_HELPER_H_
diff --git a/ios/chrome/browser/drive/model/drive_tab_helper.mm b/ios/chrome/browser/drive/model/drive_tab_helper.mm new file mode 100644 index 0000000..2c45fc6 --- /dev/null +++ b/ios/chrome/browser/drive/model/drive_tab_helper.mm
@@ -0,0 +1,59 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/drive/model/drive_tab_helper.h" + +DriveTabHelper::DriveTabHelper(web::WebState* web_state) + : web_state_(web_state) {} + +DriveTabHelper::~DriveTabHelper() = default; + +#pragma mark - Public + +void DriveTabHelper::AddDownloadToSaveToDrive(web::DownloadTask* task, + id<SystemIdentity> identity) { + ResetSaveToDriveData(DownloadTaskSaveToDriveData{ + .task = task, + .identity = identity, + }); +} + +std::optional<DownloadTaskSaveToDriveData> +DriveTabHelper::GetDownloadTaskSaveToDriveData() const { + return download_task_save_to_drive_data_; +} + +#pragma mark - web::DownloadTaskObserver + +void DriveTabHelper::OnDownloadUpdated(web::DownloadTask* task) { + switch (task->GetState()) { + case web::DownloadTask::State::kComplete: + // TODO(crbug.com/1495354): Start uploading the file to Drive. + case web::DownloadTask::State::kCancelled: + case web::DownloadTask::State::kInProgress: + case web::DownloadTask::State::kFailed: + case web::DownloadTask::State::kFailedNotResumable: + case web::DownloadTask::State::kNotStarted: + break; + } +} + +void DriveTabHelper::OnDownloadDestroyed(web::DownloadTask* task) { + ResetSaveToDriveData(std::nullopt); +} + +#pragma mark - Private + +void DriveTabHelper::ResetSaveToDriveData( + std::optional<DownloadTaskSaveToDriveData> data) { + download_task_save_to_drive_data_ = data; + download_task_obs_.Reset(); + if (data) { + download_task_obs_.Observe(data->task); + } +} + +#pragma mark - web::WebStateUserData + +WEB_STATE_USER_DATA_KEY_IMPL(DriveTabHelper)
diff --git a/ios/chrome/browser/drive/model/drive_tab_helper_unittest.mm b/ios/chrome/browser/drive/model/drive_tab_helper_unittest.mm new file mode 100644 index 0000000..45891f2 --- /dev/null +++ b/ios/chrome/browser/drive/model/drive_tab_helper_unittest.mm
@@ -0,0 +1,53 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/drive/model/drive_tab_helper.h" + +#import "ios/chrome/browser/signin/model/fake_system_identity.h" +#import "ios/web/public/test/fakes/fake_download_task.h" +#import "ios/web/public/test/fakes/fake_web_state.h" +#import "testing/platform_test.h" + +namespace { + +// Constants for configuring a fake download task. +const char kTestUrl[] = "https://chromium.test/download.txt"; +const char kTestMimeType[] = "text/html"; + +} // namespace + +// DriveTabHelper unit tests. +class DriveTabHelperTest : public PlatformTest { + protected: + void SetUp() final { + PlatformTest::SetUp(); + web_state_ = std::make_unique<web::FakeWebState>(); + DriveTabHelper::CreateForWebState(web_state_.get()); + download_task_ = + std::make_unique<web::FakeDownloadTask>(GURL(kTestUrl), kTestMimeType); + download_task_->SetWebState(web_state_.get()); + helper_ = DriveTabHelper::FromWebState(web_state_.get()); + } + + std::unique_ptr<web::FakeWebState> web_state_; + std::unique_ptr<web::FakeDownloadTask> download_task_; + raw_ptr<DriveTabHelper> helper_; +}; + +// Tests that upon `DownloadTask` being destroyed, the `DriveTabHelper` stops +// observing it i.e. removes itself from observers and resets its state. The +// "removes itself from observers" bit is checked implicitly when the +// `DownloadTask` destructor is called, since neglecting to remove itself as +// observer would lead to a crash. +TEST_F(DriveTabHelperTest, StopsObservingDestroyedDownloadTask) { + EXPECT_EQ(std::nullopt, helper_->GetDownloadTaskSaveToDriveData()); + FakeSystemIdentity* identity = [FakeSystemIdentity fakeIdentity1]; + helper_->AddDownloadToSaveToDrive(download_task_.get(), identity); + DownloadTaskSaveToDriveData expected_save_to_drive_data{ + .task = download_task_.get(), .identity = identity}; + EXPECT_EQ(expected_save_to_drive_data, + helper_->GetDownloadTaskSaveToDriveData()); + download_task_.reset(); + EXPECT_EQ(std::nullopt, helper_->GetDownloadTaskSaveToDriveData()); +}
diff --git a/ios/chrome/browser/tabs/model/BUILD.gn b/ios/chrome/browser/tabs/model/BUILD.gn index 0cbeb856..18c09667 100644 --- a/ios/chrome/browser/tabs/model/BUILD.gn +++ b/ios/chrome/browser/tabs/model/BUILD.gn
@@ -66,6 +66,7 @@ "//ios/chrome/browser/complex_tasks/model", "//ios/chrome/browser/crash_report/model/breadcrumbs", "//ios/chrome/browser/download/model", + "//ios/chrome/browser/drive/model:drive_tab_helper", "//ios/chrome/browser/favicon", "//ios/chrome/browser/find_in_page/model", "//ios/chrome/browser/find_in_page/model:util",
diff --git a/ios/chrome/browser/tabs/model/tab_helper_util.mm b/ios/chrome/browser/tabs/model/tab_helper_util.mm index 87b9952..1d29243 100644 --- a/ios/chrome/browser/tabs/model/tab_helper_util.mm +++ b/ios/chrome/browser/tabs/model/tab_helper_util.mm
@@ -36,6 +36,7 @@ #import "ios/chrome/browser/download/model/pass_kit_tab_helper.h" #import "ios/chrome/browser/download/model/safari_download_tab_helper.h" #import "ios/chrome/browser/download/model/vcard_tab_helper.h" +#import "ios/chrome/browser/drive/model/drive_tab_helper.h" #import "ios/chrome/browser/favicon/favicon_service_factory.h" #import "ios/chrome/browser/find_in_page/model/find_tab_helper.h" #import "ios/chrome/browser/find_in_page/model/java_script_find_tab_helper.h" @@ -226,6 +227,11 @@ PassKitTabHelper::CreateForWebState(web_state); VcardTabHelper::CreateForWebState(web_state); + // Drive tab helper. + if (base::FeatureList::IsEnabled(kIOSSaveToDrive)) { + DriveTabHelper::CreateForWebState(web_state); + } + PageloadForegroundDurationTabHelper::CreateForWebState(web_state); LookalikeUrlTabHelper::CreateForWebState(web_state);
diff --git a/ios/chrome/browser/ui/download/BUILD.gn b/ios/chrome/browser/ui/download/BUILD.gn index eb32fca..5455bd20 100644 --- a/ios/chrome/browser/ui/download/BUILD.gn +++ b/ios/chrome/browser/ui/download/BUILD.gn
@@ -43,6 +43,7 @@ "//ios/chrome/browser/download/model", "//ios/chrome/browser/drive/model:drive_availability", "//ios/chrome/browser/drive/model:drive_service_factory", + "//ios/chrome/browser/drive/model:drive_tab_helper", "//ios/chrome/browser/infobars/model", "//ios/chrome/browser/main/model", "//ios/chrome/browser/overlays/model", @@ -57,6 +58,7 @@ "//ios/chrome/browser/shared/ui/symbols", "//ios/chrome/browser/shared/ui/util", "//ios/chrome/browser/signin/model", + "//ios/chrome/browser/signin/model:system_identity", "//ios/chrome/browser/store_kit/model", "//ios/chrome/browser/ui/download/activities", "//ios/chrome/browser/ui/presenters",
diff --git a/ios/chrome/browser/ui/download/download_manager_consumer.h b/ios/chrome/browser/ui/download/download_manager_consumer.h index 344d8ba..f676193 100644 --- a/ios/chrome/browser/ui/download/download_manager_consumer.h +++ b/ios/chrome/browser/ui/download/download_manager_consumer.h
@@ -9,6 +9,16 @@ #import "ios/chrome/browser/ui/download/download_manager_state.h" +// Possible destinations for the downloaded file. +enum class DownloadFileDestination { + // The file is downloaded to a temporary location, and then moved to the + // Downloads folder on local storage. + kFiles, + // The file is downloaded to a temporary location, then uploaded to Drive. The + // local copy is removed. + kDrive, +}; + // Consumer for the download manager mediator. @protocol DownloadManagerConsumer <NSObject> @@ -37,6 +47,13 @@ // task has also not started. - (void)setDownloadToDriveButtonVisible:(BOOL)visible; +// Sets the destination for the downloaded file e.g. Files or Drive. +- (void)setDownloadFileDestination:(DownloadFileDestination)destination; + +// If the downloaded file is being saved to Drive, sets the associated user +// email. +- (void)setSaveToDriveUserEmail:(NSString*)userEmail; + @end #endif // IOS_CHROME_BROWSER_UI_DOWNLOAD_DOWNLOAD_MANAGER_CONSUMER_H_
diff --git a/ios/chrome/browser/ui/download/download_manager_coordinator.mm b/ios/chrome/browser/ui/download/download_manager_coordinator.mm index 8d7fee22..bfb770174 100644 --- a/ios/chrome/browser/ui/download/download_manager_coordinator.mm +++ b/ios/chrome/browser/ui/download/download_manager_coordinator.mm
@@ -152,8 +152,8 @@ #pragma mark - DownloadManagerTabHelperDelegate -- (void)downloadManagerTabHelper:(nonnull DownloadManagerTabHelper*)tabHelper - didCreateDownload:(nonnull web::DownloadTask*)download +- (void)downloadManagerTabHelper:(DownloadManagerTabHelper*)tabHelper + didCreateDownload:(web::DownloadTask*)download webStateIsVisible:(BOOL)webStateIsVisible { base::UmaHistogramEnumeration("Download.IOSDownloadFileUI", DownloadFileUI::DownloadFileStarted, @@ -181,9 +181,9 @@ } } -- (void)downloadManagerTabHelper:(nonnull DownloadManagerTabHelper*)tabHelper - decidePolicyForDownload:(nonnull web::DownloadTask*)download - completionHandler:(nonnull void (^)(NewDownloadPolicy))handler { +- (void)downloadManagerTabHelper:(DownloadManagerTabHelper*)tabHelper + decidePolicyForDownload:(web::DownloadTask*)download + completionHandler:(void (^)(NewDownloadPolicy))handler { std::unique_ptr<OverlayRequest> request = OverlayRequest::CreateWithConfig<ConfirmDownloadReplacingRequest>(); @@ -211,16 +211,16 @@ ->AddRequest(std::move(request)); } -- (void)downloadManagerTabHelper:(nonnull DownloadManagerTabHelper*)tabHelper - didHideDownload:(nonnull web::DownloadTask*)download { +- (void)downloadManagerTabHelper:(DownloadManagerTabHelper*)tabHelper + didHideDownload:(web::DownloadTask*)download { DCHECK_EQ(_downloadTask, download); self.animatesPresentation = NO; [self stop]; self.animatesPresentation = YES; } -- (void)downloadManagerTabHelper:(nonnull DownloadManagerTabHelper*)tabHelper - didShowDownload:(nonnull web::DownloadTask*)download { +- (void)downloadManagerTabHelper:(DownloadManagerTabHelper*)tabHelper + didShowDownload:(web::DownloadTask*)download { DCHECK_NE(_downloadTask, download); _downloadTask = download; self.animatesPresentation = NO; @@ -228,6 +228,14 @@ self.animatesPresentation = YES; } +- (void)downloadManagerTabHelper:(DownloadManagerTabHelper*)tabHelper + didAddDownloadToSaveToDrive:(web::DownloadTask*)download { + DCHECK_EQ(_downloadTask, download); + base::RecordAction( + base::UserMetricsAction("IOSDownloadStartDownloadToDrive")); + _mediator.StartDownloading(); +} + #pragma mark - ContainedPresenterDelegate - (void)containedPresenterDidPresent:(id<ContainedPresenter>)presenter { @@ -241,7 +249,7 @@ #pragma mark - DownloadManagerViewControllerDelegate - (void)downloadManagerViewControllerDidClose:(UIViewController*)controller { - if (_downloadTask->GetState() != web::DownloadTask::State::kInProgress) { + if (_mediator.GetDownloadManagerState() != kDownloadManagerStateInProgress) { base::UmaHistogramEnumeration("Download.IOSDownloadFileResult", DownloadFileResult::NotStarted, DownloadFileResult::Count); @@ -286,7 +294,7 @@ base::RecordAction(base::UserMetricsAction("IOSDownloadStartDownload")); _unopenedDownloads.Add(_downloadTask); } - _mediator.StartDowloading(); + _mediator.StartDownloading(); } - (void)downloadManagerViewControllerDidStartDownloadToDrive:
diff --git a/ios/chrome/browser/ui/download/download_manager_mediator.h b/ios/chrome/browser/ui/download/download_manager_mediator.h index aa059b6d..b2964d6 100644 --- a/ios/chrome/browser/ui/download/download_manager_mediator.h +++ b/ios/chrome/browser/ui/download/download_manager_mediator.h
@@ -55,7 +55,10 @@ base::FilePath GetDownloadPath(); // Asynchronously starts download operation. - void StartDowloading(); + void StartDownloading(); + + // Converts web::DownloadTask::State to DownloadManagerState. + DownloadManagerState GetDownloadManagerState() const; private: // Updates consumer from web::DownloadTask. @@ -68,9 +71,6 @@ // Checks if the move has been completed. void MoveComplete(bool move_completed); - // Converts web::DownloadTask::State to DownloadManagerState. - DownloadManagerState GetDownloadManagerState() const; - // Converts DownloadTask progress [0;100] to float progress [0.0f;1.0f]. float GetDownloadManagerProgress() const;
diff --git a/ios/chrome/browser/ui/download/download_manager_mediator.mm b/ios/chrome/browser/ui/download/download_manager_mediator.mm index a08f3444..bd9effc 100644 --- a/ios/chrome/browser/ui/download/download_manager_mediator.mm +++ b/ios/chrome/browser/ui/download/download_manager_mediator.mm
@@ -15,17 +15,78 @@ #import "ios/chrome/browser/download/model/download_directory_util.h" #import "ios/chrome/browser/download/model/external_app_util.h" #import "ios/chrome/browser/drive/model/drive_availability.h" +#import "ios/chrome/browser/drive/model/drive_tab_helper.h" #import "ios/chrome/browser/shared/public/features/features.h" +#import "ios/chrome/browser/signin/model/system_identity.h" #import "ios/chrome/grit/ios_strings.h" #import "ios/web/public/download/download_task.h" #import "net/base/net_errors.h" #import "ui/base/l10n/l10n_util.h" +namespace { + +// Returns the Save to Drive data associated with `task` if any. +std::optional<DownloadTaskSaveToDriveData> GetDownloadTaskSaveToDriveData( + web::DownloadTask* task) { + CHECK_NE(task, nullptr); + if (!base::FeatureList::IsEnabled(kIOSSaveToDrive)) { + return std::nullopt; + } + DriveTabHelper* drive_tab_helper = + DriveTabHelper::FromWebState(task->GetWebState()); + return drive_tab_helper->GetDownloadTaskSaveToDriveData(); +} + +// Returns the downloaded file destination for `task`. `task` cannot be nullptr. +DownloadFileDestination GetDownloadTaskFileDestination( + web::DownloadTask* task) { + CHECK_NE(task, nullptr); + if (GetDownloadTaskSaveToDriveData(task)) { + return DownloadFileDestination::kDrive; + } + + return DownloadFileDestination::kFiles; +} + +// If the `task` will be saved to Drive, returns the Save to Drive user email +// address associated with `task`. +NSString* GetDownloadTaskSaveToDriveUserEmail(web::DownloadTask* task) { + CHECK_NE(task, nullptr); + std::optional<DownloadTaskSaveToDriveData> task_save_to_drive_data = + GetDownloadTaskSaveToDriveData(task); + CHECK(task_save_to_drive_data); + return task_save_to_drive_data->identity.userEmail; +} + +// Returns whether `task` still needs to be saved to Drive. +bool WillDownloadTaskBeSavedToDrive(web::DownloadTask* task) { + CHECK_NE(task, nullptr); + std::optional<DownloadTaskSaveToDriveData> task_save_to_drive_data = + GetDownloadTaskSaveToDriveData(task); + if (!task_save_to_drive_data) { + return false; + } + + // TODO(crbug.com/1495354): Return false if the task has been saved to Drive. + return true; +} + +// Returns whether `task` still needs to be saved to Drive. +float GetDownloadTaskSaveToDriveProgress(web::DownloadTask* task) { + CHECK_NE(task, nullptr); + // TODO(crbug.com/1495354): Return the actual upload progress. + return 0.0f; +} + +} // namespace + DownloadManagerMediator::DownloadManagerMediator() : weak_ptr_factory_(this) {} DownloadManagerMediator::~DownloadManagerMediator() { SetDownloadTask(nullptr); } +#pragma mark - Public + void DownloadManagerMediator::SetIsIncognito(bool is_incognito) { is_incognito_ = is_incognito; } @@ -61,7 +122,7 @@ return download_path_; } -void DownloadManagerMediator::StartDowloading() { +void DownloadManagerMediator::StartDownloading() { base::FilePath download_dir; if (!GetTempDownloadsDirectory(&download_dir)) { [consumer_ setState:kDownloadManagerStateFailed]; @@ -76,26 +137,44 @@ task_->Start(download_dir.Append(task_->GenerateFileName())); } -void DownloadManagerMediator::OnDownloadUpdated(web::DownloadTask* task) { - UpdateConsumer(); +DownloadManagerState DownloadManagerMediator::GetDownloadManagerState() const { + // Returns the `DownloadManagerState`, depending on the state of `task_` and + // the state of the upload to Save to Drive, if that is the destination of the + // downloaded file. + switch (task_->GetState()) { + case web::DownloadTask::State::kNotStarted: + return kDownloadManagerStateNotStarted; + case web::DownloadTask::State::kInProgress: + return kDownloadManagerStateInProgress; + case web::DownloadTask::State::kComplete: + if (WillDownloadTaskBeSavedToDrive(task_)) { + return kDownloadManagerStateInProgress; + } else { + return kDownloadManagerStateSucceeded; + } + case web::DownloadTask::State::kFailed: + return kDownloadManagerStateFailed; + case web::DownloadTask::State::kFailedNotResumable: + return kDownloadManagerStateFailedNotResumable; + case web::DownloadTask::State::kCancelled: + // Download Manager should dismiss the UI after download cancellation. + return kDownloadManagerStateNotStarted; + } } -void DownloadManagerMediator::OnDownloadDestroyed(web::DownloadTask* task) { - SetDownloadTask(nullptr); -} +#pragma mark - Private void DownloadManagerMediator::UpdateConsumer() { DownloadManagerState state = GetDownloadManagerState(); - if (base::FeatureList::IsEnabled(kIOSSaveToDrive) && - [consumer_ - respondsToSelector:@selector(setDownloadToDriveButtonVisible:)]) { + if (base::FeatureList::IsEnabled(kIOSSaveToDrive)) { bool is_save_to_drive_available = drive::IsSaveToDriveAvailable( is_incognito_, identity_manager_, drive_service_); [consumer_ setDownloadToDriveButtonVisible:is_save_to_drive_available]; } - if (state == kDownloadManagerStateSucceeded) { + if (state == kDownloadManagerStateSucceeded && + !WillDownloadTaskBeSavedToDrive(task_)) { base::FilePath user_download_path; GetDownloadsDirectory(&user_download_path); download_path_ = user_download_path.Append(task_->GenerateFileName()); @@ -112,12 +191,20 @@ } if (!base::FeatureList::IsEnabled(kIOSSaveToDrive) && - state == kDownloadManagerStateSucceeded && !IsGoogleDriveAppInstalled() && - [consumer_ respondsToSelector:@selector(setInstallDriveButtonVisible: - animated:)]) { + state == kDownloadManagerStateSucceeded && !IsGoogleDriveAppInstalled()) { [consumer_ setInstallDriveButtonVisible:YES animated:YES]; } + if (base::FeatureList::IsEnabled(kIOSSaveToDrive)) { + [consumer_ + setDownloadFileDestination:GetDownloadTaskFileDestination(task_)]; + + if (WillDownloadTaskBeSavedToDrive(task_)) { + [consumer_ + setSaveToDriveUserEmail:GetDownloadTaskSaveToDriveUserEmail(task_)]; + } + } + [consumer_ setState:state]; [consumer_ setCountOfBytesReceived:task_->GetReceivedBytes()]; [consumer_ setCountOfBytesExpectedToReceive:task_->GetTotalBytes()]; @@ -152,24 +239,6 @@ DCHECK(move_completed); } -DownloadManagerState DownloadManagerMediator::GetDownloadManagerState() const { - switch (task_->GetState()) { - case web::DownloadTask::State::kNotStarted: - return kDownloadManagerStateNotStarted; - case web::DownloadTask::State::kInProgress: - return kDownloadManagerStateInProgress; - case web::DownloadTask::State::kComplete: - return kDownloadManagerStateSucceeded; - case web::DownloadTask::State::kFailed: - return kDownloadManagerStateFailed; - case web::DownloadTask::State::kFailedNotResumable: - return kDownloadManagerStateFailedNotResumable; - case web::DownloadTask::State::kCancelled: - // Download Manager should dismiss the UI after download cancellation. - return kDownloadManagerStateNotStarted; - } -} - int DownloadManagerMediator::GetDownloadManagerA11yAnnouncement() const { switch (task_->GetState()) { case web::DownloadTask::State::kNotStarted: @@ -189,5 +258,24 @@ float DownloadManagerMediator::GetDownloadManagerProgress() const { if (task_->GetPercentComplete() == -1) return 0.0f; - return static_cast<float>(task_->GetPercentComplete()) / 100.0f; + float download_progress = + static_cast<float>(task_->GetPercentComplete()) / 100.0f; + if (!WillDownloadTaskBeSavedToDrive(task_)) { + return download_progress; + } + float save_to_drive_progress = GetDownloadTaskSaveToDriveProgress(task_); + // If the downloaded file needs to be uploaded to Drive, then the overall + // progress is 50% once the download is complete, and then reaches 100% when + // the upload is complete. + return download_progress / 2.0 + save_to_drive_progress / 2.0; +} + +#pragma mark - web::DownloadTaskObserver overrides + +void DownloadManagerMediator::OnDownloadUpdated(web::DownloadTask* task) { + UpdateConsumer(); +} + +void DownloadManagerMediator::OnDownloadDestroyed(web::DownloadTask* task) { + SetDownloadTask(nullptr); }
diff --git a/ios/chrome/browser/ui/download/download_manager_mediator_unittest.mm b/ios/chrome/browser/ui/download/download_manager_mediator_unittest.mm index 3288d30..828c878 100644 --- a/ios/chrome/browser/ui/download/download_manager_mediator_unittest.mm +++ b/ios/chrome/browser/ui/download/download_manager_mediator_unittest.mm
@@ -61,7 +61,7 @@ auto task = std::make_unique<web::FakeDownloadTask>(GURL(kTestUrl), kTestMimeType); mediator_.SetDownloadTask(task.get()); - mediator_.StartDowloading(); + mediator_.StartDownloading(); task.reset(); } @@ -72,7 +72,7 @@ task()->SetGeneratedFileName(base::FilePath(kTestSuggestedFileName)); mediator_.SetDownloadTask(task()); mediator_.SetConsumer(consumer_); - mediator_.StartDowloading(); + mediator_.StartDownloading(); // Starting download is async for task and sync for consumer. EXPECT_EQ(kDownloadManagerStateInProgress, consumer_.state); @@ -103,7 +103,7 @@ task()->SetGeneratedFileName(base::FilePath(kTestSuggestedFileName)); mediator_.SetDownloadTask(task()); mediator_.SetConsumer(consumer_); - mediator_.StartDowloading(); + mediator_.StartDownloading(); // Starting download is async for task and sync for consumer. EXPECT_EQ(kDownloadManagerStateInProgress, consumer_.state); @@ -136,7 +136,7 @@ task()->SetGeneratedFileName(base::FilePath(kTestSuggestedFileName)); mediator_.SetDownloadTask(task()); mediator_.SetConsumer(consumer_); - mediator_.StartDowloading(); + mediator_.StartDownloading(); // Starting download is async for task and sync for consumer. EXPECT_EQ(kDownloadManagerStateInProgress, consumer_.state); @@ -183,7 +183,7 @@ task()->SetGeneratedFileName(base::FilePath(kTestSuggestedFileName)); mediator_.SetDownloadTask(task()); mediator_.SetConsumer(consumer_); - mediator_.StartDowloading(); + mediator_.StartDownloading(); // Starting download is async for task and sync for consumer. EXPECT_EQ(kDownloadManagerStateInProgress, consumer_.state); @@ -207,7 +207,7 @@ task()->SetGeneratedFileName(base::FilePath(kTestSuggestedFileName)); mediator_.SetDownloadTask(task()); mediator_.SetConsumer(consumer_); - mediator_.StartDowloading(); + mediator_.StartDownloading(); // Starting download is async for task and sync for consumer. EXPECT_EQ(kDownloadManagerStateInProgress, consumer_.state); @@ -240,7 +240,7 @@ task()->SetGeneratedFileName(base::FilePath(kTestSuggestedFileName)); mediator_.SetDownloadTask(task()); mediator_.SetConsumer(consumer_); - mediator_.StartDowloading(); + mediator_.StartDownloading(); // Starting download is async for task and sync for consumer. EXPECT_EQ(kDownloadManagerStateInProgress, consumer_.state);
diff --git a/ios/chrome/browser/ui/download/download_manager_view_controller.mm b/ios/chrome/browser/ui/download/download_manager_view_controller.mm index d648d3da..b6be9b50 100644 --- a/ios/chrome/browser/ui/download/download_manager_view_controller.mm +++ b/ios/chrome/browser/ui/download/download_manager_view_controller.mm
@@ -31,13 +31,6 @@ @"google_drive_app_with_background"; #endif -// Possible icons for Download buttons. -enum class DownloadDestinationIcon { - kNoIcon, - kFilesIcon, - kDriveIcon, -}; - // `self.view` constants. constexpr CGFloat kWidthConstraintRegularMultiplier = 0.6; constexpr CGFloat kWidthConstraintCompactMultiplier = 1.0; @@ -73,18 +66,16 @@ // Returns the appropriate image for a destination icon, with or without // background. -UIImage* GetDownloadDestinationIconImage(DownloadDestinationIcon icon, +UIImage* GetDownloadFileDestinationImage(DownloadFileDestination destination, bool with_background) { NSString* image_name = nil; #if BUILDFLAG(IOS_USE_BRANDED_SYMBOLS) - switch (icon) { - case DownloadDestinationIcon::kNoIcon: - break; - case DownloadDestinationIcon::kFilesIcon: + switch (destination) { + case DownloadFileDestination::kFiles: image_name = with_background ? kFilesAppWithBackgroundImage : kFilesAppImage; break; - case DownloadDestinationIcon::kDriveIcon: + case DownloadFileDestination::kDrive: image_name = with_background ? kDriveAppWithBackgroundImage : kDriveAppImage; break; @@ -97,8 +88,9 @@ // Creates a button configuration for a download button. UIButtonConfiguration* CreateDownloadButtonConfiguration( NSString* title, - DownloadDestinationIcon destination_icon, - bool use_image_with_background) { + DownloadFileDestination destination, + bool use_image, + bool use_image_background) { UIButtonConfiguration* conf = [UIButtonConfiguration grayButtonConfiguration]; conf.contentInsets = NSDirectionalEdgeInsetsMake( kDownloadButtonVerticalInset, kDownloadButtonHorizontalInset, @@ -106,8 +98,10 @@ conf.imagePlacement = NSDirectionalRectEdgeTop; conf.imagePadding = kDownloadButtonImagePadding; #if BUILDFLAG(IOS_USE_BRANDED_SYMBOLS) - conf.image = GetDownloadDestinationIconImage(destination_icon, - use_image_with_background); + if (use_image) { + conf.image = + GetDownloadFileDestinationImage(destination, use_image_background); + } #endif if (title) { NSMutableParagraphStyle* centered_style = @@ -139,6 +133,8 @@ float _progress; DownloadManagerState _state; BOOL _downloadToDriveButtonVisible; + DownloadFileDestination _downloadFileDestination; + NSString* _saveToDriveUserEmail; BOOL _addedConstraints; // YES if NSLayoutConstraits were added. // UI elements. @@ -351,6 +347,20 @@ } } +- (void)setDownloadFileDestination:(DownloadFileDestination)destination { + if (_downloadFileDestination != destination) { + _downloadFileDestination = destination; + [self updateViews]; + } +} + +- (void)setSaveToDriveUserEmail:(NSString*)userEmail { + if (![userEmail isEqualToString:_saveToDriveUserEmail]) { + _saveToDriveUserEmail = userEmail; + [self updateViews]; + } +} + #pragma mark - DownloadManagerViewControllerProtocol - (UIView*)openInSourceView { @@ -426,8 +436,8 @@ - (UIButton*)downloadToFilesButton { if (!_downloadToFilesButton) { UIButtonConfiguration* downloadToFilesButtonConf = - CreateDownloadButtonConfiguration( - nil, DownloadDestinationIcon::kFilesIcon, true); + CreateDownloadButtonConfiguration(nil, DownloadFileDestination::kFiles, + false, false); __weak __typeof(self) weakSelf = self; UIAction* downloadToFilesAction = [UIAction actionWithHandler:^(UIAction* action) { @@ -454,8 +464,8 @@ - (UIButton*)downloadToDriveButton { if (!_downloadToDriveButton) { UIButtonConfiguration* downloadToDriveButtonConf = - CreateDownloadButtonConfiguration( - nil, DownloadDestinationIcon::kDriveIcon, true); + CreateDownloadButtonConfiguration(nil, DownloadFileDestination::kDrive, + false, false); __weak __typeof(self) weakSelf = self; UIAction* downloadToDriveAction = [UIAction actionWithHandler:^(UIAction* action) { @@ -687,43 +697,92 @@ _downloadToDriveButtonVisible ? l10n_util::GetNSString(IDS_IOS_DOWNLOAD_MANAGER_DOWNLOAD_TO_FILES) : l10n_util::GetNSString(IDS_IOS_DOWNLOAD_MANAGER_DOWNLOAD), - _downloadToDriveButtonVisible ? DownloadDestinationIcon::kFilesIcon - : DownloadDestinationIcon::kNoIcon, + DownloadFileDestination::kFiles, _downloadToDriveButtonVisible, self.traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark); self.downloadToDriveButton.configuration = CreateDownloadButtonConfiguration( l10n_util::GetNSString(IDS_IOS_DOWNLOAD_MANAGER_DOWNLOAD_TO_DRIVE), - DownloadDestinationIcon::kDriveIcon, + DownloadFileDestination::kDrive, true, self.traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark); } // Sets up views for the state `kDownloadManagerStateInProgress`. - (void)updateViewsForStateInProgress { - self.leadingIcon.image = GetDownloadDestinationIconImage( - DownloadDestinationIcon::kFilesIcon, true); - std::u16string size = - base::SysNSStringToUTF16(GetSizeString(_countOfBytesReceived)); - self.statusLabel.text = l10n_util::GetNSStringF( - IDS_IOS_DOWNLOAD_MANAGER_DOWNLOADING_ELIPSIS, size); + self.leadingIcon.image = + GetDownloadFileDestinationImage(_downloadFileDestination, true); - self.detailLabel.text = _fileName; - self.detailLabel.numberOfLines = 1; + switch (_downloadFileDestination) { + // File is being downloaded to local Downloads folder. + case DownloadFileDestination::kFiles: { + std::u16string size = + base::SysNSStringToUTF16(GetSizeString(_countOfBytesReceived)); + self.statusLabel.text = l10n_util::GetNSStringF( + IDS_IOS_DOWNLOAD_MANAGER_DOWNLOADING_ELIPSIS, size); + + self.detailLabel.text = _fileName; + self.detailLabel.numberOfLines = 1; + break; + } + // File is being downloaded, then uploaded to Drive. + case DownloadFileDestination::kDrive: { + if (_countOfBytesExpectedToReceive == -1) { + self.statusLabel.text = _fileName; + self.statusLabel.lineBreakMode = NSLineBreakByTruncatingMiddle; + } else { + NSString* size = GetSizeString(_countOfBytesExpectedToReceive); + self.statusLabel.text = + l10n_util::GetNSStringF(IDS_IOS_DOWNLOAD_MANAGER_FILENAME_WITH_SIZE, + base::SysNSStringToUTF16(_fileName), + base::SysNSStringToUTF16(size)); + self.statusLabel.numberOfLines = 0; + } + self.detailLabel.text = l10n_util::GetNSStringF( + IDS_IOS_DOWNLOAD_MANAGER_SAVING_TO_DRIVE, + base::SysNSStringToUTF16(_saveToDriveUserEmail)); + self.detailLabel.numberOfLines = 0; + break; + } + } + self.progressView.progress = _progress; } // Sets up views for the state `kDownloadManagerStateSucceeded`. - (void)updateViewsForStateSucceeded { - self.leadingIcon.image = GetDownloadDestinationIconImage( - DownloadDestinationIcon::kFilesIcon, true); - self.statusLabel.text = - l10n_util::GetNSString(IDS_IOS_DOWNLOAD_MANAGER_DOWNLOAD_COMPLETE); - self.detailLabel.text = _fileName; - self.detailLabel.lineBreakMode = NSLineBreakByTruncatingMiddle; + self.leadingIcon.image = + GetDownloadFileDestinationImage(_downloadFileDestination, true); + switch (_downloadFileDestination) { + // File was downloaded to local Downloads folder. + case DownloadFileDestination::kFiles: + self.statusLabel.text = + l10n_util::GetNSString(IDS_IOS_DOWNLOAD_MANAGER_DOWNLOAD_COMPLETE); + self.detailLabel.text = _fileName; + self.detailLabel.lineBreakMode = NSLineBreakByTruncatingMiddle; + break; + // File was downloaded, then uploaded to Drive. + case DownloadFileDestination::kDrive: + if (_countOfBytesExpectedToReceive == -1) { + self.statusLabel.text = _fileName; + self.statusLabel.lineBreakMode = NSLineBreakByTruncatingMiddle; + } else { + NSString* size = GetSizeString(_countOfBytesExpectedToReceive); + self.statusLabel.text = + l10n_util::GetNSStringF(IDS_IOS_DOWNLOAD_MANAGER_FILENAME_WITH_SIZE, + base::SysNSStringToUTF16(_fileName), + base::SysNSStringToUTF16(size)); + self.statusLabel.numberOfLines = 0; + } + self.detailLabel.text = l10n_util::GetNSStringF( + IDS_IOS_DOWNLOAD_MANAGER_SAVED_TO_DRIVE, + base::SysNSStringToUTF16(_saveToDriveUserEmail)); + self.detailLabel.numberOfLines = 0; + break; + } } // Sets up views for the state `kDownloadManagerStateFailed`. - (void)updateViewsForStateFailed { - self.leadingIcon.image = GetDownloadDestinationIconImage( - DownloadDestinationIcon::kFilesIcon, true); + self.leadingIcon.image = + GetDownloadFileDestinationImage(_downloadFileDestination, true); self.statusLabel.text = l10n_util::GetNSString(IDS_IOS_DOWNLOAD_MANAGER_COULDNT_DOWNLOAD); self.detailLabel.text = _fileName; @@ -732,8 +791,8 @@ // Sets up views for the state `kDownloadManagerStateFailedNotResumable`. - (void)updateViewsForStateFailedNotResumable { - self.leadingIcon.image = GetDownloadDestinationIconImage( - DownloadDestinationIcon::kFilesIcon, true); + self.leadingIcon.image = + GetDownloadFileDestinationImage(_downloadFileDestination, true); self.statusLabel.text = l10n_util::GetNSString(IDS_IOS_DOWNLOAD_MANAGER_CANNOT_BE_RETRIED); self.detailLabel.text = _fileName;
diff --git a/ios/chrome/browser/ui/omnibox/chrome_omnibox_client_ios.h b/ios/chrome/browser/ui/omnibox/chrome_omnibox_client_ios.h index 3975a43d..f6a1c86 100644 --- a/ios/chrome/browser/ui/omnibox/chrome_omnibox_client_ios.h +++ b/ios/chrome/browser/ui/omnibox/chrome_omnibox_client_ios.h
@@ -8,6 +8,7 @@ #include <memory> #include <unordered_map> +#include "base/memory/weak_ptr.h" #include "base/scoped_multi_source_observation.h" #include "components/omnibox/browser/autocomplete_match.h" #include "components/omnibox/browser/omnibox_client.h" @@ -24,8 +25,8 @@ class WebState; } // namespace web -class ChromeOmniboxClientIOS : public OmniboxClient, - public web::WebStateObserver { +class ChromeOmniboxClientIOS final : public OmniboxClient, + public web::WebStateObserver { public: ChromeOmniboxClientIOS(WebLocationBar* location_bar, ChromeBrowserState* browser_state, @@ -85,6 +86,7 @@ const AutocompleteMatch& alternative_nav_match, IDNA2008DeviationCharacter deviation_char_in_hostname) override; LocationBarModel* GetLocationBarModel() override; + base::WeakPtr<OmniboxClient> AsWeakPtr() override; // web::WebStateObserver. void DidFinishNavigation(web::WebState* web_state, @@ -109,6 +111,8 @@ // Automatically remove this observer from its host when destroyed. base::ScopedMultiSourceObservation<web::WebState, web::WebStateObserver> scoped_observations_{this}; + + base::WeakPtrFactory<ChromeOmniboxClientIOS> weak_factory_{this}; }; #endif // IOS_CHROME_BROWSER_UI_OMNIBOX_CHROME_OMNIBOX_CLIENT_IOS_H_
diff --git a/ios/chrome/browser/ui/omnibox/chrome_omnibox_client_ios.mm b/ios/chrome/browser/ui/omnibox/chrome_omnibox_client_ios.mm index c00527e0..a1ae0b4 100644 --- a/ios/chrome/browser/ui/omnibox/chrome_omnibox_client_ios.mm +++ b/ios/chrome/browser/ui/omnibox/chrome_omnibox_client_ios.mm
@@ -274,6 +274,10 @@ return location_bar_->GetLocationBarModel(); } +base::WeakPtr<OmniboxClient> ChromeOmniboxClientIOS::AsWeakPtr() { + return weak_factory_.GetWeakPtr(); +} + void ChromeOmniboxClientIOS::DidFinishNavigation( web::WebState* web_state, web::NavigationContext* navigation_context) {
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm b/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm index ffd29b44..95973673 100644 --- a/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm +++ b/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm
@@ -208,6 +208,7 @@ if (_isTextfieldEditing == owns) { return; } +#if !defined(__IPHONE_16_0) || __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_16_0 if (owns) { [[NSNotificationCenter defaultCenter] addObserver:self @@ -220,6 +221,7 @@ name:UIMenuControllerWillShowMenuNotification object:nil]; } +#endif _isTextfieldEditing = owns; } @@ -583,6 +585,7 @@ })); } +#if !defined(__IPHONE_16_0) || __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_16_0 - (void)menuControllerWillShow:(NSNotification*)notification { if (self.showingEditMenu || !self.isTextfieldEditing || !self.textField.window.isKeyWindow) { @@ -602,6 +605,7 @@ self.showingEditMenu = NO; } +#endif - (void)pasteboardDidChange:(NSNotification*)notification { [self updateCachedClipboardState];
diff --git a/ios/chrome/browser/ui/save_to_drive/BUILD.gn b/ios/chrome/browser/ui/save_to_drive/BUILD.gn index efd6e89..7394329 100644 --- a/ios/chrome/browser/ui/save_to_drive/BUILD.gn +++ b/ios/chrome/browser/ui/save_to_drive/BUILD.gn
@@ -14,6 +14,7 @@ "//base", "//ios/chrome/app/strings:ios_strings_grit", "//ios/chrome/browser/download/model", + "//ios/chrome/browser/drive/model:drive_tab_helper", "//ios/chrome/browser/shared/coordinator/chrome_coordinator", "//ios/chrome/browser/shared/model/browser", "//ios/chrome/browser/shared/public/commands", @@ -52,6 +53,8 @@ "//base/test:test_support", "//components/signin/public/identity_manager:test_support", "//ios/chrome/app/strings:ios_strings_grit", + "//ios/chrome/browser/download/model", + "//ios/chrome/browser/drive/model:drive_tab_helper", "//ios/chrome/browser/shared/model/browser/test:test_support", "//ios/chrome/browser/shared/model/browser_state:test_support", "//ios/chrome/browser/shared/model/web_state_list",
diff --git a/ios/chrome/browser/ui/save_to_drive/save_to_drive_mediator.mm b/ios/chrome/browser/ui/save_to_drive/save_to_drive_mediator.mm index 78e1baa..04fd327b 100644 --- a/ios/chrome/browser/ui/save_to_drive/save_to_drive_mediator.mm +++ b/ios/chrome/browser/ui/save_to_drive/save_to_drive_mediator.mm
@@ -5,6 +5,7 @@ #import "ios/chrome/browser/ui/save_to_drive/save_to_drive_mediator.h" #import "ios/chrome/browser/download/model/download_manager_tab_helper.h" +#import "ios/chrome/browser/drive/model/drive_tab_helper.h" #import "ios/chrome/browser/shared/public/commands/save_to_drive_commands.h" #import "ios/chrome/browser/signin/model/system_identity.h" #import "ios/web/public/download/download_task.h" @@ -59,9 +60,11 @@ if (!_downloadTask || !_webState) { return; } + DriveTabHelper* driveTabHelper = DriveTabHelper::FromWebState(_webState); DownloadManagerTabHelper* downloadManagerTabHelper = DownloadManagerTabHelper::FromWebState(_webState); - downloadManagerTabHelper->StartDownloadTaskAndSaveToDrive(identity); + driveTabHelper->AddDownloadToSaveToDrive(_downloadTask, identity); + downloadManagerTabHelper->OnDownloadAddedToSaveToDrive(_downloadTask); } #pragma mark - CRWDownloadTaskObserver
diff --git a/ios/chrome/browser/ui/save_to_drive/save_to_drive_mediator_unittest.mm b/ios/chrome/browser/ui/save_to_drive/save_to_drive_mediator_unittest.mm index 29ac2c0f..25d64a8 100644 --- a/ios/chrome/browser/ui/save_to_drive/save_to_drive_mediator_unittest.mm +++ b/ios/chrome/browser/ui/save_to_drive/save_to_drive_mediator_unittest.mm
@@ -4,7 +4,10 @@ #import "ios/chrome/browser/ui/save_to_drive/save_to_drive_mediator.h" +#import "ios/chrome/browser/download/model/download_manager_tab_helper.h" +#import "ios/chrome/browser/drive/model/drive_tab_helper.h" #import "ios/chrome/browser/shared/public/commands/save_to_drive_commands.h" +#import "ios/chrome/browser/signin/model/fake_system_identity.h" #import "ios/web/public/test/fakes/fake_download_task.h" #import "ios/web/public/test/fakes/fake_web_state.h" #import "testing/platform_test.h" @@ -17,6 +20,27 @@ } // namespace +#pragma mark - FakeDownloadManagerTabHelper + +// Fake `DownloadManagerTabHelper` to override `OnDownloadAddedToSaveToDrive()`. +class FakeDownloadManagerTabHelper final : public DownloadManagerTabHelper { + public: + explicit FakeDownloadManagerTabHelper(web::WebState* web_state) + : DownloadManagerTabHelper(web_state) {} + + static void CreateForWebState(web::WebState* web_state) { + web_state->SetUserData( + UserDataKey(), + std::make_unique<FakeDownloadManagerTabHelper>(web_state)); + } + + void OnDownloadAddedToSaveToDrive(web::DownloadTask* task) override { + download_task_added_to_save_to_drive_ = task; + } + + raw_ptr<web::DownloadTask> download_task_added_to_save_to_drive_ = nullptr; +}; + #pragma mark - FakeSaveToDriveCommandsHandler @interface FakeSaveToDriveCommandsHandler : NSObject <SaveToDriveCommands> @@ -50,6 +74,8 @@ void SetUp() final { PlatformTest::SetUp(); web_state_ = std::make_unique<web::FakeWebState>(); + DriveTabHelper::CreateForWebState(web_state_.get()); + FakeDownloadManagerTabHelper::CreateForWebState(web_state_.get()); download_task_ = std::make_unique<web::FakeDownloadTask>(GURL(kTestUrl), kTestMimeType); download_task_->SetWebState(web_state_.get()); @@ -68,6 +94,15 @@ PlatformTest::TearDown(); } + DriveTabHelper* GetDriveTabHelper() const { + return DriveTabHelper::FromWebState(web_state_.get()); + } + + FakeDownloadManagerTabHelper* GetDownloadManagerTabHelper() const { + return static_cast<FakeDownloadManagerTabHelper*>( + DownloadManagerTabHelper::FromWebState(web_state_.get())); + } + std::unique_ptr<web::FakeWebState> web_state_; std::unique_ptr<web::FakeDownloadTask> download_task_; FakeSaveToDriveCommandsHandler* save_to_drive_commands_handler_; @@ -98,3 +133,23 @@ web_state_->WasHidden(); EXPECT_EQ(nullptr, save_to_drive_commands_handler_.presentedDownloadTask); } + +// Tests that the `DownloadManagerTabHelper` is informed and that the +// `DownloadTask` and the selected identity are sent to the `DriveTabHelper` +// when `startDownloadAndSaveToDriveWithIdentity:` is invoked. +TEST_F(SaveToDriveMediatorTest, AddsDownloadToSaveToDrive) { + id<SystemIdentity> identity = [FakeSystemIdentity fakeIdentity1]; + EXPECT_EQ( + nullptr, + GetDownloadManagerTabHelper()->download_task_added_to_save_to_drive_); + EXPECT_EQ(std::nullopt, + GetDriveTabHelper()->GetDownloadTaskSaveToDriveData()); + [mediator_ startDownloadAndSaveToDriveWithIdentity:identity]; + EXPECT_EQ( + download_task_.get(), + GetDownloadManagerTabHelper()->download_task_added_to_save_to_drive_); + DownloadTaskSaveToDriveData expected_save_to_drive_data{ + .task = download_task_.get(), .identity = identity}; + EXPECT_EQ(expected_save_to_drive_data, + GetDriveTabHelper()->GetDownloadTaskSaveToDriveData()); +}
diff --git a/ios/chrome/browser/variations/model/ios_chrome_variations_service_client.h b/ios/chrome/browser/variations/model/ios_chrome_variations_service_client.h index 88f0e5c7..8d279325 100644 --- a/ios/chrome/browser/variations/model/ios_chrome_variations_service_client.h +++ b/ios/chrome/browser/variations/model/ios_chrome_variations_service_client.h
@@ -44,7 +44,8 @@ PrefService* local_state) override; std::unique_ptr<variations::SeedResponse> TakeSeedFromNativeVariationsSeedStore() override; - void RegisterLimitedEntropySyntheticTrial(std::string_view group_name); + void RegisterLimitedEntropySyntheticTrial( + std::string_view group_name) override; }; #endif // IOS_CHROME_BROWSER_VARIATIONS_MODEL_IOS_CHROME_VARIATIONS_SERVICE_CLIENT_H_
diff --git a/ios/chrome/test/BUILD.gn b/ios/chrome/test/BUILD.gn index 05affd6..8cbfa3d9c 100644 --- a/ios/chrome/test/BUILD.gn +++ b/ios/chrome/test/BUILD.gn
@@ -213,6 +213,7 @@ "//ios/chrome/browser/device_sharing/model:unit_tests", "//ios/chrome/browser/download/model:unit_tests", "//ios/chrome/browser/download/model/background_service:unit_tests", + "//ios/chrome/browser/drive/model:unit_tests", "//ios/chrome/browser/enterprise/model/idle:unit_tests", "//ios/chrome/browser/favicon:unit_tests", "//ios/chrome/browser/feature_engagement/model:unit_tests",
diff --git a/ios/chrome/test/fakes/fake_download_manager_tab_helper_delegate.mm b/ios/chrome/test/fakes/fake_download_manager_tab_helper_delegate.mm index 961cfab2..8b5a782e 100644 --- a/ios/chrome/test/fakes/fake_download_manager_tab_helper_delegate.mm +++ b/ios/chrome/test/fakes/fake_download_manager_tab_helper_delegate.mm
@@ -30,29 +30,33 @@ return YES; } -- (void)downloadManagerTabHelper:(nonnull DownloadManagerTabHelper*)tabHelper - didCreateDownload:(nonnull web::DownloadTask*)download +- (void)downloadManagerTabHelper:(DownloadManagerTabHelper*)tabHelper + didCreateDownload:(web::DownloadTask*)download webStateIsVisible:(BOOL)webStateIsVisible { if (webStateIsVisible) { _state = std::make_unique<web::DownloadTask::State>(download->GetState()); } } -- (void)downloadManagerTabHelper:(nonnull DownloadManagerTabHelper*)tabHelper - decidePolicyForDownload:(nonnull web::DownloadTask*)download - completionHandler:(nonnull void (^)(NewDownloadPolicy))handler { +- (void)downloadManagerTabHelper:(DownloadManagerTabHelper*)tabHelper + decidePolicyForDownload:(web::DownloadTask*)download + completionHandler:(void (^)(NewDownloadPolicy))handler { _decidingPolicyForDownload = download; _decidePolicyForDownloadHandler = handler; } -- (void)downloadManagerTabHelper:(nonnull DownloadManagerTabHelper*)tabHelper - didHideDownload:(nonnull web::DownloadTask*)download { +- (void)downloadManagerTabHelper:(DownloadManagerTabHelper*)tabHelper + didHideDownload:(web::DownloadTask*)download { _state = nullptr; } -- (void)downloadManagerTabHelper:(nonnull DownloadManagerTabHelper*)tabHelper - didShowDownload:(nonnull web::DownloadTask*)download { +- (void)downloadManagerTabHelper:(DownloadManagerTabHelper*)tabHelper + didShowDownload:(web::DownloadTask*)download { _state = std::make_unique<web::DownloadTask::State>(download->GetState()); } +- (void)downloadManagerTabHelper:(DownloadManagerTabHelper*)tabHelper + didAddDownloadToSaveToDrive:(web::DownloadTask*)download { +} + @end
diff --git a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 index f4d12ff..e1d6d21f9 100644 --- a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@ -607f9a03fbe08b2baa82a09446c6609a92227783 \ No newline at end of file +30f62dbb368c351fdae4a63622c50972f281b00d \ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 index d940f24..60f82636 100644 --- a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 +++ b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@ -d40f863a1cfa7984dad2b8867eeec77ed5019963 \ No newline at end of file +37a9a2a967a40a90c6ad074f0cf0fb0fa8ca4659 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 index aab5af6..18fd1156 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -47fb8fc8dc83bfce18205fbb74647cd602568e2a \ No newline at end of file +0b47969c12273a3d8bcd6f79a48b4b56a4d3550c \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 index 25e9b51f1..f6242da7 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -fee2078398ca84bb80b69b8badf51a6156909de9 \ No newline at end of file +c42203504701bb25376b8e7a78c27556670daaf7 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 index c565381b..c6de7b3e 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -acc07487014e69cf960cddc5b8f14b07685e4748 \ No newline at end of file +6875517a4544636bcb67810b87b8aa375d72b375 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 index a8c60a1..e514ab2 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -518073c8ac26df23aa59be27f7c9de2564f3f5d5 \ No newline at end of file +3413b568962786d714702f352871d0c3f76db402 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 index 867f926..2956d64 100644 --- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -e883eb059a99c8eee94c85d130400fe388842576 \ No newline at end of file +575111da51ddf1d10694794586547a89275038f8 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 index 715f46f..f95e2c3 100644 --- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -71fe66266a5ab89d94bc94061cc9c2b9df491956 \ No newline at end of file +45756f3d04551632efcfb82da56b8bedfa6fb200 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 index 5de62f3ae..6474031 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -eb5cc48085b7087000acaf4e876a86b8d92bf99e \ No newline at end of file +4057b0bac9e5d413e5cf98ee03cf4e65b032615a \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 index c42c7d7..28fdd7d 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -20ce80e8664906a9f04765c075f969a2b309f348 \ No newline at end of file +a42d13114dc06dc1c37b46ee0098143fa265667f \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 index 4e97b41..614a69d2 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -86e485a1d983542604981ba62647acc7bc63840a \ No newline at end of file +5b6c00d9de560c742951aeef9145e75078a620a6 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 index 0b8a544..e7a17ffed 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -2703cdf6dccef30552e3953e817421e1dd524613 \ No newline at end of file +0bfa8c3db742b42c0fead14bc9a173e851b335aa \ No newline at end of file
diff --git a/ios_internal b/ios_internal index b41b25f..34c58e6 160000 --- a/ios_internal +++ b/ios_internal
@@ -1 +1 @@ -Subproject commit b41b25ff5c18d9589ef7a1e8e2bec24bffc75acc +Subproject commit 34c58e6d6072333decae4e8c0b3b93316920f550
diff --git a/media/base/BUILD.gn b/media/base/BUILD.gn index f268b27..0cc8642e 100644 --- a/media/base/BUILD.gn +++ b/media/base/BUILD.gn
@@ -195,8 +195,6 @@ "key_system_names.h", "key_systems.cc", "key_systems.h", - "libvpx_thread_wrapper.cc", - "libvpx_thread_wrapper.h", "localized_strings.cc", "localized_strings.h", "logging_override_if_enabled.h", @@ -417,6 +415,10 @@ } if (media_use_libvpx) { + sources += [ + "libvpx_thread_wrapper.cc", + "libvpx_thread_wrapper.h", + ] deps += [ "//third_party/libvpx" ] }
diff --git a/media/base/media.cc b/media/base/media.cc index d3a378c8..d7d066d 100644 --- a/media/base/media.cc +++ b/media/base/media.cc
@@ -28,9 +28,11 @@ namespace media { +#if BUILDFLAG(ENABLE_LIBVPX) BASE_FEATURE(kLibvpxUseChromeThreads, "LibvpxUseChromeThreads", base::FEATURE_DISABLED_BY_DEFAULT); +#endif // BUILDFLAG(ENABLE_LIBVPX) // Media must only be initialized once; use a thread-safe static to do this. class MediaInitializer { @@ -54,9 +56,11 @@ #endif // BUILDFLAG(ENABLE_FFMPEG) +#if BUILDFLAG(ENABLE_LIBVPX) if (base::FeatureList::IsEnabled(kLibvpxUseChromeThreads)) { InitLibVpxThreadWrapper(); } +#endif // BUILDFLAG(ENABLE_LIBVPX) } MediaInitializer(const MediaInitializer&) = delete;
diff --git a/net/http/transport_security_state_static.pins b/net/http/transport_security_state_static.pins index adadcab..157d6ec 100644 --- a/net/http/transport_security_state_static.pins +++ b/net/http/transport_security_state_static.pins
@@ -43,9 +43,9 @@ # hash function for preloaded entries again (we have already done so once). # -# Last updated: 2023-12-26 12:55 UTC +# Last updated: 2023-12-27 12:54 UTC PinsListTimestamp -1703595330 +1703681693 TestSPKI sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
diff --git a/net/http/transport_security_state_static_pins.json b/net/http/transport_security_state_static_pins.json index 9ffff560..29b9a85 100644 --- a/net/http/transport_security_state_static_pins.json +++ b/net/http/transport_security_state_static_pins.json
@@ -31,7 +31,7 @@ // the 'static_spki_hashes' and 'bad_static_spki_hashes' fields in 'pinsets' // refer to, and the timestamp at which the pins list was last updated. // -// Last updated: 2023-12-26 12:55 UTC +// Last updated: 2023-12-27 12:54 UTC // { "pinsets": [
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index e103b7d..a7dce8f3 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -15030,6 +15030,25 @@ ] } ], + "RendererMainIsNormalThreadTypeForWebRTC": [ + { + "platforms": [ + "linux", + "chromeos", + "chromeos_lacros", + "mac", + "windows" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "RendererMainIsNormalThreadTypeForWebRTC" + ] + } + ] + } + ], "ReportCertificateErrors": [ { "platforms": [
diff --git a/third_party/angle b/third_party/angle index e939f9a9..0ddebba 160000 --- a/third_party/angle +++ b/third_party/angle
@@ -1 +1 @@ -Subproject commit e939f9a9cf76533d3ddaa1bb279813708e7e7d94 +Subproject commit 0ddebba548bf85ae807d1d7d3641bd79f7a189b2
diff --git a/third_party/blink/renderer/core/inspector/inspector_network_agent.cc b/third_party/blink/renderer/core/inspector/inspector_network_agent.cc index 1234a3bf..46b8eb9 100644 --- a/third_party/blink/renderer/core/inspector/inspector_network_agent.cc +++ b/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
@@ -123,8 +123,8 @@ constexpr int kDefaultTotalBufferSize = 10 * 1000 * 1000; // 10 MB constexpr int kDefaultResourceBufferSize = 5 * 1000 * 1000; // 5 MB #else -constexpr int kDefaultTotalBufferSize = 100 * 1000 * 1000; // 100 MB -constexpr int kDefaultResourceBufferSize = 10 * 1000 * 1000; // 10 MB +constexpr int kDefaultTotalBufferSize = 200 * 1000 * 1000; // 200 MB +constexpr int kDefaultResourceBufferSize = 20 * 1000 * 1000; // 20 MB #endif // Pattern may contain stars ('*') which match to any (possibly empty) string.
diff --git a/third_party/blink/web_tests/SlowTests b/third_party/blink/web_tests/SlowTests index 0b13e41d..dd5c96e 100644 --- a/third_party/blink/web_tests/SlowTests +++ b/third_party/blink/web_tests/SlowTests
@@ -1364,7 +1364,6 @@ crbug.com/626703 [ Debug ] external/wpt/html/semantics/forms/form-submission-0/multipart-formdata.window.html [ Slow ] crbug.com/626703 [ Linux Release ] external/wpt/html/semantics/forms/form-submission-0/multipart-formdata.window.html [ Slow ] crbug.com/626703 [ Mac11 Release ] external/wpt/html/semantics/forms/form-submission-0/multipart-formdata.window.html [ Slow ] -crbug.com/626703 [ Mac11-arm64 Release ] external/wpt/html/semantics/forms/form-submission-0/multipart-formdata.window.html [ Slow ] crbug.com/626703 [ Mac12 Release ] external/wpt/html/semantics/forms/form-submission-0/multipart-formdata.window.html [ Slow ] crbug.com/626703 [ Mac13 Release ] external/wpt/html/semantics/forms/form-submission-0/multipart-formdata.window.html [ Slow ] crbug.com/626703 [ Release Win ] external/wpt/html/semantics/forms/form-submission-0/multipart-formdata.window.html [ Slow ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index e084829..6f72bbf8 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -2686,11 +2686,9 @@ crbug.com/626703 [ Mac12 ] external/wpt/performance-timeline/back-forward-cache-restoration.tentative.html [ Timeout ] crbug.com/626703 [ Mac12 ] virtual/pna-navigations-warning/external/wpt/fetch/private-network-access/shared-worker-fetch.tentative.https.window.html [ Timeout ] crbug.com/626703 [ Mac12 ] virtual/prefetch-no-vary-search/external/wpt/speculation-rules/prefetch/no-vary-search/prefetch-single-with-hint.https.html?3-3 [ Timeout ] -crbug.com/626703 [ Mac12 ] virtual/prefetch-reusable/external/wpt/speculation-rules/prefetch/no-vary-search/prefetch-single-with-hint.https.html?27-27 [ Timeout ] crbug.com/626703 [ Mac12 ] virtual/prefetch/external/wpt/speculation-rules/prefetch/no-vary-search/prefetch-single.https.html?15-15 [ Timeout ] crbug.com/626703 external/wpt/css/css-backgrounds/border-image-image-type-001.htm [ Failure ] crbug.com/626703 virtual/threaded/external/wpt/css/css-backgrounds/border-image-image-type-001.htm [ Failure ] -crbug.com/626703 [ Mac13 ] virtual/threaded/external/wpt/css/css-backgrounds/border-image-image-type-004.htm [ Failure ] crbug.com/626703 [ Mac10.15 ] virtual/threaded/external/wpt/css/css-backgrounds/border-image-image-type-004.htm [ Failure Timeout ] crbug.com/626703 [ Mac10.15 ] virtual/threaded/external/wpt/css/css-backgrounds/border-image-image-type-005.htm [ Failure Timeout ] crbug.com/626703 external/wpt/css/css-contain/content-visibility/content-visibility-on-g.html [ 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 6d3aec2..14956e1 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
@@ -294809,6 +294809,10 @@ } }, "nonce-hiding": { + "dangling-html-or-body.html.headers": [ + "67d4c81e589d487b25bdb73a89f8ba1c49a0c431", + [] + ], "nonces.html.headers": [ "daf482b5aba4ff052b94c99f422910727c600aae", [] @@ -415011,7 +415015,7 @@ ], "import_export": { "ec_importKey.https.any.js": [ - "31f062e313f6fe9dc735fc9a5588df0c098fde98", + "a01bfbb0ef2e1881e83aaefe76f1ca39805c9304", [ "WebCryptoAPI/import_export/ec_importKey.https.any.html", { @@ -431962,6 +431966,13 @@ ] }, "nonce-hiding": { + "dangling-html-or-body.html": [ + "4ba65e05b885cbc780fab7f1650689016f257ac2", + [ + null, + {} + ] + ], "nonce-hiding-move-document.html": [ "49de893ba03fbd25125fcf13eff8c352e4992d85", [ @@ -557016,7 +557027,7 @@ }, "dom": { "aria-attribute-reflection.html": [ - "e201d4660eb754b9560d1b48f22dd2c063d04658", + "8970938ac92162ecaeb0608d8bc42905fb2818f7", [ null, {}
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/ec_importKey.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/ec_importKey.https.any.js index 31f062e..a01bfbb 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/ec_importKey.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/ec_importKey.https.any.js
@@ -80,6 +80,9 @@ } testFormat(format, algorithm, data, curve, usages, extractable); + if (vector.name === 'ECDH' && format === 'jwk') { + testEcdhJwkAlg(algorithm, { ...data.jwk, alg: 'any alg works here' }, curve, usages, extractable); + } }); }); @@ -90,11 +93,13 @@ var data = keyData[curve]; allValidUsages(vector.privateUsages).forEach(function(usages) { testFormat(format, algorithm, data, curve, usages, extractable); + if (vector.name === 'ECDH' && format === 'jwk') { + testEcdhJwkAlg(algorithm, { ...data.jwk, alg: 'any alg works here' }, curve, usages, extractable); + } }); testEmptyUsages(format, algorithm, data, curve, extractable); }); }); - }); }); @@ -151,6 +156,21 @@ }, "Empty Usages: " + keySize.toString() + " bits " + parameterString(format, false, keyData, algorithm, extractable, usages)); } + // Test ECDH importKey with a JWK format + // Should succeed with any "alg" value + function testEcdhJwkAlg(algorithm, keyData, keySize, usages, extractable) { + const format = "jwk"; + promise_test(function(test) { + return subtle.importKey(format, keyData, algorithm, extractable, usages). + then(function(key) { + assert_equals(key.constructor, CryptoKey, "Imported a CryptoKey object"); + assert_goodCryptoKey(key, algorithm, extractable, usages, keyData.d ? 'private' : 'public'); + }, function(err) { + assert_unreached("Threw an unexpected error: " + err.toString()); + }); + }, "ECDH any JWK alg: " + keySize.toString() + " bits " + parameterString(format, false, keyData, algorithm, extractable, usages)); + } + // Helper methods follow:
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/nonce-hiding/dangling-html-or-body.html b/third_party/blink/web_tests/external/wpt/content-security-policy/nonce-hiding/dangling-html-or-body.html new file mode 100644 index 0000000..4ba65e0 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/content-security-policy/nonce-hiding/dangling-html-or-body.html
@@ -0,0 +1,29 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js" nonce="secret"></script> +<script src="/resources/testharnessreport.js" nonce="secret"></script> + +<!-- `Content-Security-Policy: script-src 'nonce-secret'` delivered via headers --> + +<body> + <style>body[nonce*=secret]{background:url(/security/resources/abe.png);}</style> + <body + <script nonce="secret" src="https://example.com/good.js"></script> + <script nonce="secret"> + test(t => { + const body = document.querySelector('body'); + var style = getComputedStyle(body); + assert_equals(style['background-image'], 'none'); + }, "Nonces don't leak via CSS side-channels when a dangling body is injected."); + </script> + + <style>html[nonce*=secret]{background:url(/security/resources/abe.png);}</style> + <html + <script nonce="secret" src="https://example.com/good.js"></script> + <script nonce="secret"> + test(t => { + const html = document.querySelector('html'); + var style = getComputedStyle(html); + assert_equals(style['background-image'], 'none'); + }, "Nonces don't leak via CSS side-channels when a dangling html is injected."); + </script> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/nonce-hiding/dangling-html-or-body.html.headers b/third_party/blink/web_tests/external/wpt/content-security-policy/nonce-hiding/dangling-html-or-body.html.headers new file mode 100644 index 0000000..67d4c81 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/content-security-policy/nonce-hiding/dangling-html-or-body.html.headers
@@ -0,0 +1 @@ +Content-Security-Policy: script-src 'nonce-secret'
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/aria-attribute-reflection.html b/third_party/blink/web_tests/external/wpt/html/dom/aria-attribute-reflection.html index e201d46..8970938a 100644 --- a/third_party/blink/web_tests/external/wpt/html/dom/aria-attribute-reflection.html +++ b/third_party/blink/web_tests/external/wpt/html/dom/aria-attribute-reflection.html
@@ -8,9 +8,16 @@ <script> function testNullable(element, jsAttr, contentAttr) { + var originalValue = element[jsAttr]; + assert_false(originalValue === null); element[jsAttr] = null; assert_equals(element[jsAttr], null); assert_false(element.hasAttribute(contentAttr)); + // Setting to undefined results in same state as setting to null. + element[jsAttr] = originalValue; + element[jsAttr] = undefined; + assert_equals(element[jsAttr], null); + assert_false(element.hasAttribute(contentAttr)); } </script>
diff --git a/third_party/dawn b/third_party/dawn index a1a25d6..e9f87b6 160000 --- a/third_party/dawn +++ b/third_party/dawn
@@ -1 +1 @@ -Subproject commit a1a25d682c7d3ed4206b4b40e6c36f82bfcfa0ea +Subproject commit e9f87b69b96384c508aa2d408601e0881035ff3a
diff --git a/third_party/devtools-frontend-internal b/third_party/devtools-frontend-internal index c6bf12d..63790d3a 160000 --- a/third_party/devtools-frontend-internal +++ b/third_party/devtools-frontend-internal
@@ -1 +1 @@ -Subproject commit c6bf12d0f4fd78aa7dbc7e5379b2cb7c2503b58b +Subproject commit 63790d3a0292fcede670a1a0259e9356916c9bd6
diff --git a/third_party/devtools-frontend/src b/third_party/devtools-frontend/src index a89ba04..5eb9e24 160000 --- a/third_party/devtools-frontend/src +++ b/third_party/devtools-frontend/src
@@ -1 +1 @@ -Subproject commit a89ba04022e79cb59bdcdf510392cd2e6cd749b3 +Subproject commit 5eb9e244097ff37b64738ca222787348f6f05920
diff --git a/third_party/webrtc b/third_party/webrtc index 3cce50a..ee2fcba 160000 --- a/third_party/webrtc +++ b/third_party/webrtc
@@ -1 +1 @@ -Subproject commit 3cce50ae4bc4384dd61b7d2dc877203993b09b19 +Subproject commit ee2fcbab428934630b39e0be128cb0fcd0573aae
diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec index 23f46fa..98769c24 100644 --- a/tools/gritsettings/resource_ids.spec +++ b/tools/gritsettings/resource_ids.spec
@@ -506,7 +506,7 @@ "META": {"sizes": {"includes": [50]}}, "includes": [4280], }, - "<(SHARED_INTERMEDIATE_DIR)/chrome/browser/resources/chromeos/internet_config_dialog/internet_config_dialog_resources.grd": { + "<(SHARED_INTERMEDIATE_DIR)/chrome/browser/resources/chromeos/internet_config_dialog/resources.grd": { "META": {"sizes": {"includes": [10],}}, "includes": [4300], },
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml index 6815365..2b8235fec 100644 --- a/tools/metrics/actions/actions.xml +++ b/tools/metrics/actions/actions.xml
@@ -13445,6 +13445,15 @@ <description>User started the download in Download Manager.</description> </action> +<action name="IOSDownloadStartDownloadToDrive"> + <owner>qpubert@google.com</owner> + <owner>ewannpv@chromium.org</owner> + <description> + User started the download in Download Manager, with Drive as destination for + their download. + </description> +</action> + <action name="IOSDownloadTryCloseWhenInProgress"> <owner>ewannpv@chromium.org</owner> <owner>sdefresne@chromium.org</owner>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 11ce672..5edd63d 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -27330,7 +27330,6 @@ <int value="-1259901957" label="VrBrowserKeyboard:disabled"/> <int value="-1259809702" label="Enable16Desks:enabled"/> <int value="-1259627326" label="AllowRepeatedUpdates:disabled"/> - <int value="-1258793847" label="MagicStackAndroid:disabled"/> <int value="-1258141852" label="ScrollUnification:enabled"/> <int value="-1257822114" label="ContextMenuPopupForAllScreenSizes:disabled"/> <int value="-1256823053" label="WebRtcHWVP9Encoding:enabled"/> @@ -31962,7 +31961,6 @@ <int value="940705998" label="CrOSLateBootArcSwitchToKeyMintDaemon:disabled"/> <int value="940751405" label="IppFirstSetupForUsbPrinters:enabled"/> <int value="941036016" label="ContentSuggestionsSettings:disabled"/> - <int value="941703796" label="MagicStackAndroid:enabled"/> <int value="941883332" label="ProactiveTabFreezeAndDiscard:disabled"/> <int value="941948340" label="PlaybackSpeedButton:enabled"/> <int value="942357311" label="UpcomingSharingFeatures:disabled"/>
diff --git a/tools/metrics/histograms/metadata/arc/histograms.xml b/tools/metrics/histograms/metadata/arc/histograms.xml index 8c82a224..c41cd365b 100644 --- a/tools/metrics/histograms/metadata/arc/histograms.xml +++ b/tools/metrics/histograms/metadata/arc/histograms.xml
@@ -1995,6 +1995,22 @@ </histogram> <histogram + name="Arc.Runtime.Performance.PerceivedFPS2{ArcPerformanceAppCategories}" + units="fps" expires_after="2024-05-05"> + <owner>khmel@google.com</owner> + <owner>matvore@google.com</owner> + <summary> + Render frames per second, not considering frames which exo could not + present. Only collected if the user has app syncing enabled and doesn't have + a custom passphrase set. {ArcPerformanceAppCategories} + </summary> + <token key="ArcPerformanceAppCategories" + variants="ArcPerformanceAppCategories"> + <variant name=""/> + </token> +</histogram> + +<histogram name="Arc.Runtime.Performance.RenderQuality2{ArcPerformanceAppCategories}" units="%" expires_after="2024-05-05"> <owner>khmel@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/chromeos/enums.xml b/tools/metrics/histograms/metadata/chromeos/enums.xml index 2fd7a34..7ee6309 100644 --- a/tools/metrics/histograms/metadata/chromeos/enums.xml +++ b/tools/metrics/histograms/metadata/chromeos/enums.xml
@@ -855,6 +855,24 @@ <int value="5" label="RemoveReplug"/> </enum> +<enum name="FirmwareUpdateFwupdStatus"> + <int value="0" label="Unknown"/> + <int value="1" label="Idle"/> + <int value="2" label="Loading"/> + <int value="3" label="Decompressing"/> + <int value="4" label="DeviceRestart"/> + <int value="5" label="DeviceWrite"/> + <int value="6" label="DeviceVerify"/> + <int value="7" label="Scheduling"/> + <int value="8" label="Downloading"/> + <int value="9" label="DeviceRead"/> + <int value="10" label="DeviceErase"/> + <int value="11" label="WaitingForAuth"/> + <int value="12" label="DeviceBusy"/> + <int value="13" label="Shutdown"/> + <int value="14" label="WaitingForUser"/> +</enum> + <enum name="FirmwareUpdateInstallResult"> <int value="0" label="Success"/> <int value="1" label="InstallFailed"/>
diff --git a/tools/metrics/histograms/metadata/chromeos/histograms.xml b/tools/metrics/histograms/metadata/chromeos/histograms.xml index bd5f8f1..3a8663f 100644 --- a/tools/metrics/histograms/metadata/chromeos/histograms.xml +++ b/tools/metrics/histograms/metadata/chromeos/histograms.xml
@@ -1194,6 +1194,18 @@ <token key="FeatureName" variants="FeaturesLoggingUsageEvents"/> </histogram> +<histogram name="ChromeOS.FirmwareUpdateUi.InstallFailedWithStatus" + enum="FirmwareUpdateFwupdStatus" expires_after="2024-06-28"> + <owner>cambickel@google.com</owner> + <owner>jimmyxgong@chromium.org</owner> + <owner>zentaro@chromium.org</owner> + <owner>cros-peripherals@google.com</owner> + <summary> + Records the most recent FwupdStatus when a firmware install fails for any + reason. + </summary> +</histogram> + <histogram name="ChromeOS.FirmwareUpdateUi.InstallResult" enum="FirmwareUpdateInstallResult" expires_after="2024-04-28"> <owner>jimmyxgong@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/chromeos_settings/histograms.xml b/tools/metrics/histograms/metadata/chromeos_settings/histograms.xml index 22014d6..c765a4b 100644 --- a/tools/metrics/histograms/metadata/chromeos_settings/histograms.xml +++ b/tools/metrics/histograms/metadata/chromeos_settings/histograms.xml
@@ -97,7 +97,7 @@ </histogram> <histogram name="ChromeOS.Settings.BlurredWindowDuration" units="ms" - expires_after="2024-02-04"> + expires_after="2024-12-27"> <owner>wesokuhara@google.com</owner> <owner>xiaohuic@chromium.org</owner> <owner>cros-settings@google.com</owner> @@ -522,7 +522,7 @@ </histogram> <histogram name="ChromeOS.Settings.SearchLatency" units="ms" - expires_after="2024-02-04"> + expires_after="2024-12-27"> <owner>wesokuhara@google.com</owner> <owner>xiaohuic@chromium.org</owner> <owner>cros-settings@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/custom_tabs/histograms.xml b/tools/metrics/histograms/metadata/custom_tabs/histograms.xml index 65845105..1e8f523 100644 --- a/tools/metrics/histograms/metadata/custom_tabs/histograms.xml +++ b/tools/metrics/histograms/metadata/custom_tabs/histograms.xml
@@ -295,8 +295,8 @@ </histogram> <histogram name="CustomTabs.IncognitoCCTCallerId" enum="IncognitoCCTCallerId" - expires_after="2024-02-04"> - <owner>roagarwal@chromium.org</owner> + expires_after="2024-08-04"> + <owner>arabm@google.com</owner> <owner>chrome-incognito@google.com</owner> <owner>cct-team@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/history/histograms.xml b/tools/metrics/histograms/metadata/history/histograms.xml index 9cc2b2a..39138ca3 100644 --- a/tools/metrics/histograms/metadata/history/histograms.xml +++ b/tools/metrics/histograms/metadata/history/histograms.xml
@@ -58,17 +58,6 @@ </summary> </histogram> -<histogram name="History.Backend.TransactionBeginSuccess" enum="BooleanSuccess" - expires_after="2023-10-01"> - <owner>tommycli@chromium.org</owner> - <owner>chrome-journeys@google.com</owner> - <component>UI>Browser>History</component> - <summary> - Recorded after attempting to begin a singleton transaction within - HistoryBackend. Records whether it was successfully begun or not. - </summary> -</histogram> - <histogram name="History.Backend.TransactionCommitError" enum="SqliteLoggedResultCode" expires_after="2024-02-04"> <owner>tommycli@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/navigation/histograms.xml b/tools/metrics/histograms/metadata/navigation/histograms.xml index c1e156b..8f60e605 100644 --- a/tools/metrics/histograms/metadata/navigation/histograms.xml +++ b/tools/metrics/histograms/metadata/navigation/histograms.xml
@@ -989,7 +989,7 @@ </histogram> <histogram name="Navigation.MainFrameScheme2" enum="NavigationScheme" - expires_after="2024-01-15"> + expires_after="2024-06-15"> <owner>estark@chromium.org</owner> <owner>elawrence@chromium.org</owner> <owner>trusty-transport@chromium.org</owner> @@ -1042,7 +1042,7 @@ </histogram> <histogram name="Navigation.MainFrameSchemeOTR2" enum="NavigationScheme" - expires_after="2024-01-15"> + expires_after="2024-06-15"> <owner>elawrence@chromium.org</owner> <owner>estark@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/network/histograms.xml b/tools/metrics/histograms/metadata/network/histograms.xml index 1152122..78c5f3a0 100644 --- a/tools/metrics/histograms/metadata/network/histograms.xml +++ b/tools/metrics/histograms/metadata/network/histograms.xml
@@ -3066,7 +3066,7 @@ </histogram> <histogram name="Network.Shill.WiFi.AdapterAllowlisted" - enum="WiFiAdapterInAllowlist" expires_after="2024-04-28"> + enum="WiFiAdapterInAllowlist" expires_after="2024-12-31"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3077,7 +3077,7 @@ </histogram> <histogram name="Network.Shill.WiFi.Ap80211kSupport" enum="WiFiAp80211kSupport" - expires_after="2024-12-01"> + expires_after="2024-12-31"> <owner>matthewmwang@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3087,7 +3087,7 @@ </histogram> <histogram name="Network.Shill.WiFi.Ap80211rSupport" enum="WiFiAp80211rSupport" - expires_after="2024-12-01"> + expires_after="2024-12-31"> <owner>matthewmwang@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3097,7 +3097,7 @@ </histogram> <histogram name="Network.Shill.WiFi.Ap80211vBSSMaxIdlePeriodSupport" - enum="WiFiAp80211vBSSMaxIdlePeriodSupport" expires_after="2024-12-01"> + enum="WiFiAp80211vBSSMaxIdlePeriodSupport" expires_after="2024-12-31"> <owner>matthewmwang@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3108,7 +3108,7 @@ </histogram> <histogram name="Network.Shill.WiFi.Ap80211vBSSTransitionSupport" - enum="WiFiAp80211vBSSTransitionSupport" expires_after="2024-12-01"> + enum="WiFiAp80211vBSSTransitionSupport" expires_after="2024-12-31"> <owner>matthewmwang@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3119,7 +3119,7 @@ </histogram> <histogram name="Network.Shill.WiFi.Ap80211vDMSSupport" - enum="WiFiAp80211vDMSSupport" expires_after="2024-02-04"> + enum="WiFiAp80211vDMSSupport" expires_after="2024-12-31"> <owner>matthewmwang@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3129,7 +3129,7 @@ </histogram> <histogram name="Network.Shill.WiFi.ApAlternateEDCASupport" - enum="WiFiApAlternateEDCASupport" expires_after="2024-05-05"> + enum="WiFiApAlternateEDCASupport" expires_after="2024-12-31"> <owner>damiendejean@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3140,7 +3140,7 @@ </histogram> <histogram name="Network.Shill.WiFi.ApChannelSwitch" enum="WiFiApChannelSwitch" - expires_after="2024-04-28"> + expires_after="2024-12-31"> <owner>matthewmwang@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3150,7 +3150,7 @@ </histogram> <histogram name="Network.Shill.WiFi.ApDisconnectReason" enum="WiFiReasonCode" - expires_after="2024-04-28"> + expires_after="2024-12-31"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3160,7 +3160,7 @@ </histogram> <histogram name="Network.Shill.WiFi.ApDisconnectType" enum="WiFiStatusType" - expires_after="2024-04-28"> + expires_after="2024-12-31"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3170,7 +3170,7 @@ </histogram> <histogram name="Network.Shill.WiFi.ApSCSupport" enum="WiFiApSCSupport" - expires_after="2024-05-05"> + expires_after="2024-12-31"> <owner>damiendejean@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3180,7 +3180,7 @@ </histogram> <histogram name="Network.Shill.WiFi.AssocFailureType" enum="WiFiStatusCode" - expires_after="2024-04-28"> + expires_after="2024-12-31"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3192,7 +3192,7 @@ </histogram> <histogram name="Network.Shill.WiFi.AuthFailureType" enum="WiFiStatusCode" - expires_after="2024-05-19"> + expires_after="2024-12-31"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3204,7 +3204,7 @@ </histogram> <histogram name="Network.Shill.WiFi.AutoConnectableServices" units="units" - expires_after="2024-12-01"> + expires_after="2024-12-31"> <owner>matthewmwang@chromium.org</owner> <owner>stevenjb@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> @@ -3215,7 +3215,7 @@ </histogram> <histogram name="Network.Shill.WiFi.AvailableBSSesAtConnect" units="units" - expires_after="2024-02-12"> + expires_after="2024-12-31"> <owner>matthewmwang@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3225,7 +3225,7 @@ </histogram> <histogram name="Network.Shill.WiFi.BadPassphraseServiceType" - enum="WiFiBadPassphraseServiceType" expires_after="2024-02-04"> + enum="WiFiBadPassphraseServiceType" expires_after="2024-12-31"> <owner>yichenyu@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3236,7 +3236,7 @@ </histogram> <histogram name="Network.Shill.WiFi.BSSTransitionManagementSupport" - enum="WiFiBSSTransitionManagementSupport" expires_after="2024-12-01"> + enum="WiFiBSSTransitionManagementSupport" expires_after="2024-12-31"> <owner>matthewmwang@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3247,7 +3247,7 @@ </histogram> <histogram name="Network.Shill.Wifi.Channel" enum="NetworkChannelType" - expires_after="2024-04-28"> + expires_after="2024-12-31"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3257,7 +3257,7 @@ </histogram> <histogram name="Network.Shill.WiFi.CiscoAdaptiveFTSupport" - enum="WiFiCiscoAdaptiveFTSupport" expires_after="2024-04-28"> + enum="WiFiCiscoAdaptiveFTSupport" expires_after="2024-12-31"> <owner>matthewmwang@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3268,7 +3268,7 @@ </histogram> <histogram name="Network.Shill.WiFi.ClientDisconnectReason" - enum="WiFiReasonCode" expires_after="2024-04-28"> + enum="WiFiReasonCode" expires_after="2024-12-31"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3278,7 +3278,7 @@ </histogram> <histogram name="Network.Shill.WiFi.ClientDisconnectType" enum="WiFiStatusType" - expires_after="2024-04-28"> + expires_after="2024-12-31"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3288,7 +3288,7 @@ </histogram> <histogram name="Network.Shill.WiFi.CQMNotification" - enum="WiFiCQMNotificationType" expires_after="2024-04-28"> + enum="WiFiCQMNotificationType" expires_after="2024-12-31"> <owner>kuabhs@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3300,7 +3300,7 @@ </histogram> <histogram name="Network.Shill.Wifi.DevicePresenceStatus" enum="BooleanPresent" - expires_after="2024-04-28"> + expires_after="2024-12-31"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3310,7 +3310,7 @@ </histogram> <histogram name="Network.Shill.Wifi.Disconnect" enum="NetworkDisconnectType" - expires_after="2024-05-12"> + expires_after="2024-12-31"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3320,7 +3320,7 @@ </histogram> <histogram name="Network.Shill.Wifi.EapInnerProtocol" enum="EAPInnerProtocol" - expires_after="2024-12-01"> + expires_after="2024-12-31"> <owner>matthewmwang@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3330,7 +3330,7 @@ </histogram> <histogram name="Network.Shill.Wifi.EapOuterProtocol" enum="EAPOuterProtocol" - expires_after="2024-02-04"> + expires_after="2024-12-31"> <owner>matthewmwang@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3340,7 +3340,7 @@ </histogram> <histogram name="Network.Shill.Wifi.ExpiredLeaseLengthSeconds2" units="seconds" - expires_after="2024-02-04"> + expires_after="2024-12-31"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3351,7 +3351,7 @@ </histogram> <histogram name="Network.Shill.Wifi.FallbackDNSTestResult" - enum="FallbackDNSTestResult" expires_after="2024-12-01"> + enum="FallbackDNSTestResult" expires_after="2024-12-31"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3362,7 +3362,7 @@ </histogram> <histogram name="Network.Shill.WiFi.Hidden.EverConnected" - enum="BooleanConnected" expires_after="2024-04-28"> + enum="BooleanConnected" expires_after="2024-12-31"> <owner>jonmann@chromium.org</owner> <owner>tnagel@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> @@ -3377,7 +3377,7 @@ </histogram> <histogram name="Network.Shill.WiFi.Hidden.LastConnected" units="days" - expires_after="2024-04-28"> + expires_after="2024-12-31"> <owner>jonmann@chromium.org</owner> <owner>tnagel@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> @@ -3391,7 +3391,7 @@ </histogram> <histogram name="Network.Shill.WiFi.HiddenSSIDEverConnected" - enum="BooleanEverConnected" expires_after="2024-05-12"> + enum="BooleanEverConnected" expires_after="2024-12-31"> <owner>tnagel@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <owner>cros-privacy-core@google.com</owner> @@ -3404,7 +3404,7 @@ </histogram> <histogram name="Network.Shill.WiFi.HiddenSSIDNetworkCount" units="units" - expires_after="2024-05-19"> + expires_after="2024-12-31"> <owner>tnagel@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <owner>cros-privacy-core@google.com</owner> @@ -3419,7 +3419,7 @@ </histogram> <histogram name="Network.Shill.WiFi.HS20Support" enum="HotspotSupport" - expires_after="2024-01-14"> + expires_after="2024-12-31"> <owner>kglund@google.com</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3431,7 +3431,7 @@ </histogram> <histogram name="Network.Shill.WiFi.MBOSupport" enum="MBOSupport" - expires_after="2024-02-12"> + expires_after="2024-12-31"> <owner>matthewmwang@google.com</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3453,7 +3453,7 @@ </histogram> <histogram name="Network.Shill.Wifi.NetworkConnectionIPType" - enum="NetworkConnectionIPType" expires_after="2024-02-25"> + enum="NetworkConnectionIPType" expires_after="2024-12-31"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3463,7 +3463,7 @@ </histogram> <histogram name="Network.Shill.Wifi.NetworkProblemDetected" - enum="NetworkProblemType" expires_after="2024-12-01"> + enum="NetworkProblemType" expires_after="2024-12-31"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3634,7 +3634,7 @@ </histogram> <histogram name="Network.Shill.Wifi.PhyMode" enum="NetworkPhyModeType" - expires_after="2024-12-01"> + expires_after="2024-12-31"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3648,7 +3648,7 @@ </histogram> <histogram name="Network.Shill.Wifi.PortalResult" enum="NetworkPortalResult" - expires_after="2024-05-12"> + expires_after="2024-12-31"> <owner>matthewmwang@chromium.org</owner> <owner>stevenjb@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> @@ -3659,7 +3659,7 @@ </histogram> <histogram name="Network.Shill.WiFi.RegulatoryDomain" enum="RegulatoryDomain" - expires_after="2024-02-04"> + expires_after="2024-12-31"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3670,7 +3670,7 @@ </histogram> <histogram name="Network.Shill.WiFi.RememberedNetworkCount" units="units" - expires_after="2024-04-28"> + expires_after="2024-12-31"> <owner>matthewmwang@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3682,7 +3682,7 @@ </histogram> <histogram name="Network.Shill.WiFi.RememberedSystemNetworkCount" units="units" - expires_after="2024-05-19"> + expires_after="2024-12-31"> <owner>matthewmwang@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3698,7 +3698,7 @@ </histogram> <histogram name="Network.Shill.WiFi.RememberedUserNetworkCount" units="units" - expires_after="2024-04-28"> + expires_after="2024-12-31"> <owner>matthewmwang@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3709,7 +3709,7 @@ </histogram> <histogram base="true" name="Network.Shill.WiFi.RoamComplete" - enum="WiFiRoamComplete" expires_after="2024-05-19"> + enum="WiFiRoamComplete" expires_after="2024-12-31"> <!-- Name completed by histogram_suffixes name="RoamSecurityType" --> <owner>matthewmwang@chromium.org</owner> @@ -3722,7 +3722,7 @@ </histogram> <histogram base="true" name="Network.Shill.WiFi.RoamTime" units="ms" - expires_after="2024-12-01"> + expires_after="2024-12-31"> <!-- Name completed by histogram_suffixes name="RoamSecurityType" --> <owner>matthewmwang@chromium.org</owner> @@ -3735,7 +3735,7 @@ </histogram> <histogram name="Network.Shill.WiFi.ScanResult" enum="WiFiScanResult" - expires_after="2024-12-24"> + expires_after="2024-12-31"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3745,7 +3745,7 @@ </histogram> <histogram name="Network.Shill.WiFi.ScanTimeInEbusy" units="ms" - expires_after="2024-12-01"> + expires_after="2024-12-31"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3755,7 +3755,7 @@ </histogram> <histogram name="Network.Shill.Wifi.Security" enum="NetworkSecurityType" - expires_after="2024-04-28"> + expires_after="2024-12-31"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3765,7 +3765,7 @@ </histogram> <histogram name="Network.Shill.Wifi.SecurityChange" - enum="NetworkSecurityChange" expires_after="2024-04-28"> + enum="NetworkSecurityChange" expires_after="2024-12-31"> <owner>andrzejo@google.com</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3778,7 +3778,7 @@ </histogram> <histogram name="Network.Shill.Wifi.ServiceErrors" enum="NetworkServiceError" - expires_after="2024-04-28"> + expires_after="2024-12-31"> <owner>kuabhs@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3787,7 +3787,7 @@ </histogram> <histogram base="true" name="Network.Shill.WiFi.SessionLength" units="ms" - expires_after="2024-12-01"> + expires_after="2024-12-31"> <!-- Name completed by histogram_suffixes name="RoamSecurityType" --> <owner>matthewmwang@chromium.org</owner> @@ -3800,7 +3800,7 @@ </histogram> <histogram name="Network.Shill.WiFi.SessionTagState.{Event}" - enum="WiFiSessionTagState" expires_after="2024-04-28"> + enum="WiFiSessionTagState" expires_after="2024-12-31"> <owner>norvez@chromium.org</owner> <owner>druth@google.com</owner> <owner>cros-network-metrics@google.com</owner> @@ -3818,7 +3818,7 @@ </histogram> <histogram name="Network.Shill.Wifi.SignalAtDisconnect" units="negative dBm" - expires_after="2024-12-01"> + expires_after="2024-12-31"> <owner>matthewmwang@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3828,7 +3828,7 @@ </histogram> <histogram name="Network.Shill.Wifi.SignalStrength" units="negative dBm" - expires_after="2024-02-25"> + expires_after="2024-12-31"> <owner>kuabhs@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3838,7 +3838,7 @@ </histogram> <histogram name="Network.Shill.WiFi.SupplicantAttempts" units="attempts" - expires_after="2024-12-01"> + expires_after="2024-12-31"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3855,7 +3855,7 @@ </histogram> <histogram name="Network.Shill.WiFi.TimeFromRekeyToFailureSeconds" - units="seconds" expires_after="2024-03-17"> + units="seconds" expires_after="2024-12-31"> <owner>billyzhao@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3867,7 +3867,7 @@ </histogram> <histogram name="Network.Shill.Wifi.TimeOnline" units="seconds" - expires_after="2024-04-28"> + expires_after="2024-12-31"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3878,7 +3878,7 @@ </histogram> <histogram name="Network.Shill.Wifi.TimeResumeToReady" units="ms" - expires_after="2024-04-28"> + expires_after="2024-12-31"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3889,7 +3889,7 @@ </histogram> <histogram name="Network.Shill.WiFi.TimeResumeToReadyHB" units="ms" - expires_after="2024-12-01"> + expires_after="2024-12-31"> <owner>matthewmwang@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3901,7 +3901,7 @@ </histogram> <histogram name="Network.Shill.WiFi.TimeResumeToReadyLB" units="ms" - expires_after="2024-12-01"> + expires_after="2024-12-31"> <owner>matthewmwang@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3913,7 +3913,7 @@ </histogram> <histogram name="Network.Shill.WiFi.TimeResumeToReadyUHB" units="ms" - expires_after="2024-12-01"> + expires_after="2024-12-31"> <owner>matthewmwang@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3925,7 +3925,7 @@ </histogram> <histogram name="Network.Shill.Wifi.TimeToConfig" units="ms" - expires_after="2024-04-28"> + expires_after="2024-12-31"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3935,7 +3935,7 @@ </histogram> <histogram name="Network.Shill.Wifi.TimeToConnect" units="ms" - expires_after="2024-04-28"> + expires_after="2024-12-31"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3946,7 +3946,7 @@ </histogram> <histogram name="Network.Shill.Wifi.TimeToInitialize" units="ms" - expires_after="2024-02-04"> + expires_after="2024-12-31"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3956,7 +3956,7 @@ </histogram> <histogram name="Network.Shill.Wifi.TimeToJoin" units="ms" - expires_after="2024-04-28"> + expires_after="2024-12-31"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -3966,7 +3966,7 @@ </histogram> <histogram name="Network.Shill.Wifi.TimeToOnline" units="ms" - expires_after="2024-04-28"> + expires_after="2024-12-31"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -4000,7 +4000,7 @@ </histogram> <histogram name="Network.Shill.Wifi.TimeToScan" units="ms" - expires_after="2024-05-26"> + expires_after="2024-12-31"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -4010,7 +4010,7 @@ </histogram> <histogram name="Network.Shill.Wifi.TimeToScanAndConnect" units="ms" - expires_after="2024-04-28"> + expires_after="2024-12-31"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -4022,7 +4022,7 @@ </histogram> <histogram name="Network.Shill.WiFi.TransmitBitrateMbps" units="Mbps" - expires_after="2024-04-28"> + expires_after="2024-12-31"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -4033,7 +4033,7 @@ </histogram> <histogram name="Network.Shill.Wifi.UnreliableLinkSignalStrength" units="units" - expires_after="2024-04-28"> + expires_after="2024-12-31"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -4044,7 +4044,7 @@ </histogram> <histogram name="Network.Shill.WiFi.UserInitiatedConnectionFailureReason" - enum="ConnectionFailureReason" expires_after="2024-05-19"> + enum="ConnectionFailureReason" expires_after="2024-12-31"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary> @@ -4056,7 +4056,7 @@ </histogram> <histogram name="Network.Shill.WiFi.UserInitiatedConnectionResult" - enum="ConnectionResult" expires_after="2024-04-28"> + enum="ConnectionResult" expires_after="2024-12-31"> <owner>norvez@chromium.org</owner> <owner>cros-network-metrics@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/others/histograms.xml b/tools/metrics/histograms/metadata/others/histograms.xml index b8d9a09e..e742021ee 100644 --- a/tools/metrics/histograms/metadata/others/histograms.xml +++ b/tools/metrics/histograms/metadata/others/histograms.xml
@@ -2916,6 +2916,17 @@ </summary> </histogram> +<histogram name="Conversions.DbVersionOnSourceStored" units="Source" + expires_after="2024-04-28"> + <owner>tquintanilla@chromium.org</owner> + <owner>johnidel@chromium.org</owner> + <owner>measurement-api-dev+metrics@google.com</owner> + <summary> + Records the DB version on every successful source or noised source stored. + This metric was added starting with version 56. + </summary> +</histogram> + <histogram name="Conversions.DebugReport.HttpResponseOrNetErrorCodeAggregatable" enum="CombinedHttpResponseAndNetErrorCode" expires_after="2024-05-10">
diff --git a/tools/metrics/histograms/metadata/platform/histograms.xml b/tools/metrics/histograms/metadata/platform/histograms.xml index 5b7ee65..631d09a 100644 --- a/tools/metrics/histograms/metadata/platform/histograms.xml +++ b/tools/metrics/histograms/metadata/platform/histograms.xml
@@ -504,7 +504,7 @@ </histogram> <histogram name="Platform.ExternalMetrics.SamplesRead" units="count" - expires_after="2024-02-04"> + expires_after="2025-01-30"> <owner>iby@google.com</owner> <owner>mutexlox@google.com</owner> <owner>cros-telemetry@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/signin/histograms.xml b/tools/metrics/histograms/metadata/signin/histograms.xml index 407e80f..ff387fe 100644 --- a/tools/metrics/histograms/metadata/signin/histograms.xml +++ b/tools/metrics/histograms/metadata/signin/histograms.xml
@@ -1646,15 +1646,6 @@ </summary> </histogram> -<histogram name="Signin.SigninReason" enum="SigninReason" - expires_after="2024-04-28"> - <owner>msarda@chromium.org</owner> - <owner>bsazonov@chromium.org</owner> - <owner>droger@chromium.org</owner> - <owner>chrome-signin-team@google.com</owner> - <summary>Logs the reason of each completed sign in.</summary> -</histogram> - <histogram name="Signin.SigninStartedAccessPoint" enum="SigninAccessPoint" expires_after="2024-04-28"> <owner>msarda@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/sync/histograms.xml b/tools/metrics/histograms/metadata/sync/histograms.xml index f46ed6e4..bd522c5 100644 --- a/tools/metrics/histograms/metadata/sync/histograms.xml +++ b/tools/metrics/histograms/metadata/sync/histograms.xml
@@ -863,7 +863,7 @@ </histogram> <histogram name="Sync.ModelTypeCommitWithDepletedQuota" enum="SyncModelTypes" - expires_after="2024-02-04"> + expires_after="2024-11-04"> <owner>rushans@google.com</owner> <owner>treib@chromium.org</owner> <component>Services>Sync</component>
diff --git a/ui/accessibility/ax_node.cc b/ui/accessibility/ax_node.cc index 9834304d..95ab1ad 100644 --- a/ui/accessibility/ax_node.cc +++ b/ui/accessibility/ax_node.cc
@@ -42,6 +42,9 @@ index_in_parent_(index_in_parent), unignored_index_in_parent_(unignored_index_in_parent), parent_(parent) { + // TODO(accessibility): Change to CHECK(tree_) after https://crbug.com/1511053 + // is fixed. + DCHECK(tree_); data_.id = id; }
diff --git a/ui/webui/resources/cr_elements/cr_slider/cr_slider.ts b/ui/webui/resources/cr_elements/cr_slider/cr_slider.ts index 3527e93..98521ed8 100644 --- a/ui/webui/resources/cr_elements/cr_slider/cr_slider.ts +++ b/ui/webui/resources/cr_elements/cr_slider/cr_slider.ts
@@ -295,7 +295,9 @@ return; } - this.getRipple().showAndHoldDown(); + if (!this.getRipple().holdDown) { + this.getRipple().showAndHoldDown(); + } this.showLabel_ = true; }
diff --git a/v8 b/v8 index 93fbb15..4b00f2f 160000 --- a/v8 +++ b/v8
@@ -1 +1 @@ -Subproject commit 93fbb15abfe4161e4280d20498749b3a1e12415b +Subproject commit 4b00f2f2737f7c2b1e4ca41ca2dc7c8a55c805d7