diff --git a/DEPS b/DEPS index e498d6f2..f29bf031 100644 --- a/DEPS +++ b/DEPS
@@ -303,7 +303,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': '063e339bedfcfb9d7c921cd92d9a902ef008ce76', + 'skia_revision': 'dd4077962cd5456478501f733af12b5dfb17b3ea', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. @@ -311,7 +311,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': '82c0ba9350b582eeff34c8c17886ac6b638f281b', + 'angle_revision': '295eece61cce0f7721427d4a42e0fe1821c6d39f', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -818,7 +818,7 @@ 'src/clank': { 'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' + - '73c554959a79725f3f2e1a6f9a902bd4fc2febc3', + '20d5657767c7a726b9144002e4021d087725a89e', 'condition': 'checkout_android and checkout_src_internal', }, @@ -980,7 +980,7 @@ 'packages': [ { 'package': 'chromium/third_party/androidx', - 'version': 'Aym7zNxeVp_a5OUFZfShkxubeUpGPsS42gKXdKNJ7b4C', + 'version': 'fxep2qUxHMuSadHbR8ufKuYVmB9SKknNkkBDLneqqhwC', }, ], 'condition': 'checkout_android', @@ -1190,7 +1190,7 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '86752e9a55281200715749d75a88cf57bf2e7b01', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '259976c7483c321c122169d193e150310f4ea609', 'src/third_party/devtools-frontend/src': Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), @@ -1838,7 +1838,7 @@ Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'f4bf599a8b575df685c31d9c4729a70a04e377ed', 'src/third_party/webgpu-cts/src': - Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'f20c5f7b8f53904edaa98651d764e1b8305d7c14', + Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'ae15a59832989c22982acaeaccdf5d379afced62', 'src/third_party/webrtc': Var('webrtc_git') + '/src.git' + '@' + '8e2ab67045941387e1b25d05f8fb219f524a80a8', @@ -3944,7 +3944,7 @@ 'src/components/optimization_guide/internal': { 'url': Var('chrome_git') + '/chrome/components/optimization_guide.git' + '@' + - 'f35015d6f691b1aadc035cd1644aa3bc19a1a92a', + '22d6e7c48e3a433786898acedc2730a9b1c93e6c', 'condition': 'checkout_src_internal', }, @@ -4004,7 +4004,7 @@ 'src/ios_internal': { 'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' + - 'd8d82ca955498f2a3c907380b829aa6270a64b82', + '27d0f4f79518dfe9f8e15cf52f1130ba3a6a5958', 'condition': 'checkout_ios and checkout_src_internal', },
diff --git a/android_webview/browser/gfx/aw_vulkan_context_provider.h b/android_webview/browser/gfx/aw_vulkan_context_provider.h index 14c9db5..683b09a 100644 --- a/android_webview/browser/gfx/aw_vulkan_context_provider.h +++ b/android_webview/browser/gfx/aw_vulkan_context_provider.h
@@ -8,7 +8,7 @@ #include <memory> #include <optional> -#include "base/memory/raw_ptr_exclusion.h" +#include "base/memory/raw_ptr.h" #include "components/viz/common/gpu/vulkan_context_provider.h" #include "gpu/vulkan/vulkan_device_queue.h" #include "third_party/skia/include/core/SkRefCnt.h" @@ -43,9 +43,7 @@ ~ScopedSecondaryCBDraw() { provider_->SecondaryCMBDrawSubmitted(); } private: - // This field is not a raw_ptr<> because it was filtered by the rewriter - // for: #union - RAW_PTR_EXCLUSION AwVulkanContextProvider* const provider_; + raw_ptr<AwVulkanContextProvider> const provider_; }; AwVulkanContextProvider(const AwVulkanContextProvider&) = delete;
diff --git a/android_webview/browser/gfx/overlay_processor_webview.h b/android_webview/browser/gfx/overlay_processor_webview.h index e27ec41..a8be19272 100644 --- a/android_webview/browser/gfx/overlay_processor_webview.h +++ b/android_webview/browser/gfx/overlay_processor_webview.h
@@ -7,7 +7,6 @@ #include "android_webview/browser/gfx/display_scheduler_webview.h" #include "base/memory/raw_ptr.h" -#include "base/memory/raw_ptr_exclusion.h" #include "base/memory/weak_ptr.h" #include "base/synchronization/waitable_event.h" #include "base/threading/thread_checker.h" @@ -39,9 +38,7 @@ ~ScopedSurfaceControlAvailable(); private: - // This field is not a raw_ptr<> because it was filtered by the rewriter - // for: #union - RAW_PTR_EXCLUSION OverlayProcessorWebView* processor_; + raw_ptr<OverlayProcessorWebView> processor_; }; OverlayProcessorWebView(
diff --git a/android_webview/browser/gfx/scoped_app_gl_state_restore_impl.cc b/android_webview/browser/gfx/scoped_app_gl_state_restore_impl.cc index 1238e1a..211ebe3 100644 --- a/android_webview/browser/gfx/scoped_app_gl_state_restore_impl.cc +++ b/android_webview/browser/gfx/scoped_app_gl_state_restore_impl.cc
@@ -284,7 +284,7 @@ glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &vertex_attrib_[i].stride); glGetVertexAttribPointerv(i, GL_VERTEX_ATTRIB_ARRAY_POINTER, - &vertex_attrib_[i].pointer); + &vertex_attrib_[i].pointer.AsEphemeralRawAddr()); glGetVertexAttribfv(i, GL_CURRENT_VERTEX_ATTRIB, vertex_attrib_[i].current_vertex_attrib); }
diff --git a/android_webview/browser/gfx/scoped_app_gl_state_restore_impl.h b/android_webview/browser/gfx/scoped_app_gl_state_restore_impl.h index aa3d24f4..0a34e9e 100644 --- a/android_webview/browser/gfx/scoped_app_gl_state_restore_impl.h +++ b/android_webview/browser/gfx/scoped_app_gl_state_restore_impl.h
@@ -9,7 +9,7 @@ #include <vector> #include "android_webview/browser/gfx/scoped_app_gl_state_restore.h" -#include "base/memory/raw_ptr_exclusion.h" +#include "base/memory/raw_ptr.h" #include "ui/gl/gl_bindings.h" namespace android_webview { @@ -43,9 +43,7 @@ GLint type; GLint normalized; GLint stride; - // This field is not a raw_ptr<> because it was filtered by the rewriter - // for: #addr-of - RAW_PTR_EXCLUSION GLvoid* pointer; + raw_ptr<GLvoid> pointer; GLint vertex_attrib_array_buffer_binding; GLfloat current_vertex_attrib[4]; };
diff --git a/android_webview/browser/tracing/aw_trace_event_args_allowlist.cc b/android_webview/browser/tracing/aw_trace_event_args_allowlist.cc index df51950..de8a545 100644 --- a/android_webview/browser/tracing/aw_trace_event_args_allowlist.cc +++ b/android_webview/browser/tracing/aw_trace_event_args_allowlist.cc
@@ -5,7 +5,7 @@ #include "android_webview/browser/tracing/aw_trace_event_args_allowlist.h" #include "base/functional/bind.h" -#include "base/memory/raw_ptr_exclusion.h" +#include "base/memory/raw_ptr.h" #include "base/strings/pattern.h" #include "base/strings/string_tokenizer.h" #include "base/strings/string_util.h" @@ -16,9 +16,7 @@ struct AllowlistEntry { const char* category_name; const char* event_name; - // This field is not a raw_ptr<> because it was filtered by the rewriter for: - // #global-scope - RAW_PTR_EXCLUSION const char* const* arg_name_filter; + raw_ptr<const char* const> arg_name_filter; }; const char* const kMemoryDumpAllowedArgs[] = {"dumps", nullptr};
diff --git a/android_webview/js_sandbox/service/js_sandbox_isolate.h b/android_webview/js_sandbox/service/js_sandbox_isolate.h index 426f398..f381e45 100644 --- a/android_webview/js_sandbox/service/js_sandbox_isolate.h +++ b/android_webview/js_sandbox/service/js_sandbox_isolate.h
@@ -14,7 +14,6 @@ #include "base/compiler_specific.h" #include "base/files/scoped_file.h" #include "base/functional/callback_forward.h" -#include "base/memory/raw_ptr_exclusion.h" #include "base/memory/scoped_refptr.h" #include "base/synchronization/lock.h" #include "base/thread_annotations.h"
diff --git a/android_webview/nonembedded/component_updater/aw_component_updater_configurator.cc b/android_webview/nonembedded/component_updater/aw_component_updater_configurator.cc index 2fa0fee..82a5f9e 100644 --- a/android_webview/nonembedded/component_updater/aw_component_updater_configurator.cc +++ b/android_webview/nonembedded/component_updater/aw_component_updater_configurator.cc
@@ -5,10 +5,10 @@ #include "android_webview/nonembedded/component_updater/aw_component_updater_configurator.h" #include <memory> +#include <optional> #include <string> #include <vector> -#include <optional> #include "android_webview/nonembedded/net/network_impl.h" #include "base/android/path_utils.h" #include "base/files/file_path.h" @@ -210,4 +210,8 @@ : std::nullopt; } +bool AwComponentUpdaterConfigurator::IsConnectionMetered() const { + return configurator_impl_.IsConnectionMetered(); +} + } // namespace android_webview
diff --git a/android_webview/nonembedded/component_updater/aw_component_updater_configurator.h b/android_webview/nonembedded/component_updater/aw_component_updater_configurator.h index 5ca90de..192a021 100644 --- a/android_webview/nonembedded/component_updater/aw_component_updater_configurator.h +++ b/android_webview/nonembedded/component_updater/aw_component_updater_configurator.h
@@ -67,6 +67,7 @@ std::optional<bool> IsMachineExternallyManaged() const override; update_client::UpdaterStateProvider GetUpdaterStateProvider() const override; std::optional<base::FilePath> GetCrxCachePath() const override; + bool IsConnectionMetered() const override; protected: friend class base::RefCountedThreadSafe<AwComponentUpdaterConfigurator>;
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index b4521e1..ca2a2f7 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -2568,16 +2568,16 @@ "wm/native_cursor_manager_ash.h", "wm/overlay_layout_manager.cc", "wm/overlay_layout_manager.h", + "wm/overview/birch/birch_bar_view.cc", + "wm/overview/birch/birch_bar_view.h", + "wm/overview/birch/birch_chip_button.cc", + "wm/overview/birch/birch_chip_button.h", "wm/overview/cleanup_animation_observer.cc", "wm/overview/cleanup_animation_observer.h", "wm/overview/delayed_animation_observer.h", "wm/overview/delayed_animation_observer_impl.cc", "wm/overview/delayed_animation_observer_impl.h", "wm/overview/event_handler_delegate.h", - "wm/overview/glanceables/glanceables_bar_view.cc", - "wm/overview/glanceables/glanceables_bar_view.h", - "wm/overview/glanceables/glanceables_chip_button.cc", - "wm/overview/glanceables/glanceables_chip_button.h", "wm/overview/overview_animation_state_waiter.cc", "wm/overview/overview_animation_state_waiter.h", "wm/overview/overview_constants.h",
diff --git a/ash/accelerators/key_hold_detector.cc b/ash/accelerators/key_hold_detector.cc index 3587f0b..a7d919e8e 100644 --- a/ash/accelerators/key_hold_detector.cc +++ b/ash/accelerators/key_hold_detector.cc
@@ -57,7 +57,7 @@ case INITIAL: // Pass through posted event. if (event->flags() & ui::EF_IS_SYNTHESIZED) { - event->set_flags(event->flags() & ~ui::EF_IS_SYNTHESIZED); + event->SetFlags(event->flags() & ~ui::EF_IS_SYNTHESIZED); return; } state_ = PRESSED;
diff --git a/ash/accessibility/chromevox/touch_exploration_controller.cc b/ash/accessibility/chromevox/touch_exploration_controller.cc index 3f35041..296a157 100644 --- a/ash/accessibility/chromevox/touch_exploration_controller.cc +++ b/ash/accessibility/chromevox/touch_exploration_controller.cc
@@ -51,7 +51,7 @@ void SetTouchAccessibilityFlag(ui::Event* event) { // This flag is used to identify mouse move events that were generated from // touch exploration in Chrome code. - event->set_flags(event->flags() | ui::EF_TOUCH_ACCESSIBILITY); + event->SetFlags(event->flags() | ui::EF_TOUCH_ACCESSIBILITY); } std::unique_ptr<ui::GestureProviderAura> BuildGestureProviderAura( @@ -190,7 +190,7 @@ touch_event.pointer_details()); new_event.set_location(location); new_event.set_root_location(root_location); - new_event.set_flags(touch_event.flags()); + new_event.SetFlags(touch_event.flags()); return SendEventFinally(continuation, &new_event); }
diff --git a/ash/accessibility/magnifier/fullscreen_magnifier_controller.cc b/ash/accessibility/magnifier/fullscreen_magnifier_controller.cc index ebf607e..261abe8 100644 --- a/ash/accessibility/magnifier/fullscreen_magnifier_controller.cc +++ b/ash/accessibility/magnifier/fullscreen_magnifier_controller.cc
@@ -438,7 +438,7 @@ it.second->pointer_details()); touch_cancel_event.set_location_f(it.second->location_f()); touch_cancel_event.set_root_location_f(it.second->root_location_f()); - touch_cancel_event.set_flags(it.second->flags()); + touch_cancel_event.SetFlags(it.second->flags()); // TouchExplorationController is watching event stream and managing its // internal state. If an event rewriter (FullscreenMagnifierController)
diff --git a/ash/accessibility/sticky_keys/sticky_keys_controller.cc b/ash/accessibility/sticky_keys/sticky_keys_controller.cc index 9aef323..2cfb2c9 100644 --- a/ash/accessibility/sticky_keys/sticky_keys_controller.cc +++ b/ash/accessibility/sticky_keys/sticky_keys_controller.cc
@@ -42,7 +42,7 @@ *rewritten_event = event.Clone(); if (mod_down_flags & ~event.flags()) { - (*rewritten_event)->set_flags(event.flags() | mod_down_flags); + (*rewritten_event)->SetFlags(event.flags() | mod_down_flags); } if (released)
diff --git a/ash/ambient/OWNERS b/ash/ambient/OWNERS index 574ed11..591b2e9 100644 --- a/ash/ambient/OWNERS +++ b/ash/ambient/OWNERS
@@ -1 +1,8 @@ -file://chromeos/ash/components/assistant/OWNERS +# Please use this reviewer queue instead of specifying an individual reviewer +# unless there is a specific reason for it. +assistive-code-review@google.com + +cowmoo@google.com #{LAST_RESORT_SUGGESTION} +esum@google.com #{LAST_RESORT_SUGGESTION} +wutao@chromium.org #{LAST_RESORT_SUGGESTION} +xiaohuic@chromium.org #{LAST_RESORT_SUGGESTION}
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc index 8be7791..889b6ce3 100644 --- a/ash/constants/ash_features.cc +++ b/ash/constants/ash_features.cc
@@ -1470,8 +1470,8 @@ // Ignores the rate limiting of holding space wallpaper nudge so that it will // show every time a user drags a file over the wallpaper. Enabling this flag // does nothing unless `kHoldingSpaceWallpaperNudge` is also enabled. -BASE_FEATURE(kHoldingSpaceWallpaperNudgeIgnoreRateLimiting, - "HoldingSpaceWallpaperNudgeIgnoreRateLimiting", +BASE_FEATURE(kHoldingSpaceWallpaperNudgeForceEligibility, + "HoldingSpaceWallpaperNudgeForceEligibility", base::FEATURE_DISABLED_BY_DEFAULT); BASE_FEATURE(kHomeButtonQuickAppAccess, @@ -3563,10 +3563,10 @@ kHoldingSpaceWallpaperNudgeEnabledCounterfactually.Get(); } -bool IsHoldingSpaceWallpaperNudgeRateLimitingEnabled() { +bool IsHoldingSpaceWallpaperNudgeForceEligibilityEnabled() { return IsHoldingSpaceWallpaperNudgeEnabled() && - !base::FeatureList::IsEnabled( - kHoldingSpaceWallpaperNudgeIgnoreRateLimiting); + base::FeatureList::IsEnabled( + kHoldingSpaceWallpaperNudgeForceEligibility); } bool IsHomeButtonQuickAppAccessEnabled() {
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h index 2a91e39..1c12de36 100644 --- a/ash/constants/ash_features.h +++ b/ash/constants/ash_features.h
@@ -474,7 +474,7 @@ COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kHoldingSpaceWallpaperNudge); COMPONENT_EXPORT(ASH_CONSTANTS) -BASE_DECLARE_FEATURE(kHoldingSpaceWallpaperNudgeIgnoreRateLimiting); +BASE_DECLARE_FEATURE(kHoldingSpaceWallpaperNudgeForceEligibility); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kHomeButtonQuickAppAccess); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kHotspot); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kVirtualKeyboardNewHeader); @@ -1055,7 +1055,7 @@ COMPONENT_EXPORT(ASH_CONSTANTS) bool IsHoldingSpaceWallpaperNudgeEnabledCounterfactually(); COMPONENT_EXPORT(ASH_CONSTANTS) -bool IsHoldingSpaceWallpaperNudgeRateLimitingEnabled(); +bool IsHoldingSpaceWallpaperNudgeForceEligibilityEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) COMPONENT_EXPORT(ASH_CONSTANTS) bool IsHomeButtonQuickAppAccessEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsHomeButtonWithTextEnabled();
diff --git a/ash/drag_drop/drag_drop_controller.cc b/ash/drag_drop/drag_drop_controller.cc index 2b019ac..8865ca4f 100644 --- a/ash/drag_drop/drag_drop_controller.cc +++ b/ash/drag_drop/drag_drop_controller.cc
@@ -536,7 +536,7 @@ const ui::LocatedEvent& event) { ui::DropTargetEvent e(*drag_data_.get(), event.location_f(), event.root_location_f(), allowed_operations_); - e.set_flags(event.flags()); + e.SetFlags(event.flags()); ui::Event::DispatcherApi(&e).set_target(target); aura::client::DragUpdateInfo drag_info; @@ -623,7 +623,7 @@ ui::DropTargetEvent e(*drag_data_.get(), event.location_f(), event.root_location_f(), allowed_operations_); - e.set_flags(event.flags()); + e.SetFlags(event.flags()); ui::Event::DispatcherApi(&e).set_target(target); for (aura::client::DragDropClientObserver& observer : observers_) {
diff --git a/ash/events/peripheral_customization_event_rewriter.cc b/ash/events/peripheral_customization_event_rewriter.cc index b5197f5..ea2e927 100644 --- a/ash/events/peripheral_customization_event_rewriter.cc +++ b/ash/events/peripheral_customization_event_rewriter.cc
@@ -721,7 +721,7 @@ std::unique_ptr<ui::Event> rewritten_event = CloneEvent(mouse_event); const int remappable_flags = GetRemappableMouseEventFlags(*device_type_to_observe); - rewritten_event->set_flags(rewritten_event->flags() & ~remappable_flags); + rewritten_event->SetFlags(rewritten_event->flags() & ~remappable_flags); if (rewritten_event->IsMouseEvent()) { auto& rewritten_mouse_event = *rewritten_event->AsMouseEvent(); rewritten_mouse_event.set_changed_button_flags( @@ -818,7 +818,7 @@ // remapped, this will behave incorrectly as it will remove "Ctrl". Instead, // this needs to track what keys are being pressed by the device that have // modifiers attached to them. For now, this is close enough to being correct. - event.set_flags(event.flags() & ~modifier_flags); + event.SetFlags(event.flags() & ~modifier_flags); } void PeripheralCustomizationEventRewriter::ApplyRemappedModifiers( @@ -827,7 +827,7 @@ for (const auto& [_, flag] : device_button_to_flags_) { flags |= flag; } - event.set_flags(event.flags() | flags); + event.SetFlags(event.flags() | flags); } std::unique_ptr<ui::Event> PeripheralCustomizationEventRewriter::CloneEvent(
diff --git a/ash/system/holding_space/holding_space_tray_unittest.cc b/ash/system/holding_space/holding_space_tray_unittest.cc index 1ce903e..28ba8ab 100644 --- a/ash/system/holding_space/holding_space_tray_unittest.cc +++ b/ash/system/holding_space/holding_space_tray_unittest.cc
@@ -612,6 +612,27 @@ // Tests ----------------------------------------------------------------------- +// Holding Space used to own the constant which determines its bubble's width +// but now shares a constant with the rest of the system UI bubbles. Holding +// Space UI is not yet implemented to be fully reactive to variable bubble +// widths, so this test adds a speed bump to (hopefully) prevent the shared +// constant from being updated and inadvertently breaking Holding Space UI. +TEST_F(HoldingSpaceTrayTest, BubbleHasExpectedWidth) { + // Start session and verify the holding space tray is showing in the shelf. + StartSession(/*pre_mark_time_of_first_add=*/true); + EXPECT_TRUE(test_api()->IsShowingInShelf()); + + // Show the holding space bubble. + test_api()->Show(); + EXPECT_TRUE(test_api()->IsShowing()); + + // Verify holding space bubble width. + views::View* const bubble = test_api()->GetBubble(); + ASSERT_TRUE(bubble); + ViewDrawnWaiter().Wait(bubble); + EXPECT_EQ(bubble->width(), 360); +} + TEST_F(HoldingSpaceTrayTest, ShowTrayButtonWhenForced) { // Case: Force show in shelf prior to session start. auto force_show_in_shelf =
diff --git a/ash/user_education/holding_space_wallpaper_nudge/holding_space_wallpaper_nudge_controller.cc b/ash/user_education/holding_space_wallpaper_nudge/holding_space_wallpaper_nudge_controller.cc index afd80e6..39d72d9 100644 --- a/ash/user_education/holding_space_wallpaper_nudge/holding_space_wallpaper_nudge_controller.cc +++ b/ash/user_education/holding_space_wallpaper_nudge/holding_space_wallpaper_nudge_controller.cc
@@ -137,7 +137,7 @@ // before. It should be no more than once in a 24 hour period, no more than 3 // times total, and never if the user has pinned a file before. bool NudgeShouldBeShown() { - if (!features::IsHoldingSpaceWallpaperNudgeRateLimitingEnabled()) { + if (features::IsHoldingSpaceWallpaperNudgeForceEligibilityEnabled()) { return true; }
diff --git a/ash/user_education/holding_space_wallpaper_nudge/holding_space_wallpaper_nudge_controller_unittest.cc b/ash/user_education/holding_space_wallpaper_nudge/holding_space_wallpaper_nudge_controller_unittest.cc index b7615b923..6151adf 100644 --- a/ash/user_education/holding_space_wallpaper_nudge/holding_space_wallpaper_nudge_controller_unittest.cc +++ b/ash/user_education/holding_space_wallpaper_nudge/holding_space_wallpaper_nudge_controller_unittest.cc
@@ -270,7 +270,7 @@ HoldingSpaceWallpaperNudgeControllerTestBase( std::optional<bool> counterfactual_enabled, std::optional<bool> drop_to_pin_enabled, - bool rate_limiting_enabled, + bool force_eligibility_enabled, base::test::TaskEnvironment::TimeSource time_source) : UserEducationAshTestBase(time_source) { // NOTE: The `HoldingSpaceWallpaperNudgeController` exists only when the @@ -292,13 +292,13 @@ enabled.emplace_back(features::kHoldingSpaceWallpaperNudge, params); - if (rate_limiting_enabled) { - disabled.emplace_back( - features::kHoldingSpaceWallpaperNudgeIgnoreRateLimiting); - } else { + if (force_eligibility_enabled) { enabled.emplace_back( - features::kHoldingSpaceWallpaperNudgeIgnoreRateLimiting, + features::kHoldingSpaceWallpaperNudgeForceEligibility, base::FieldTrialParams()); + } else { + disabled.emplace_back( + features::kHoldingSpaceWallpaperNudgeForceEligibility); } scoped_feature_list_.InitWithFeaturesAndParameters(enabled, disabled); @@ -437,7 +437,7 @@ : HoldingSpaceWallpaperNudgeControllerTestBase( /*counterfactual_enabled=*/false, /*drop_to_pin_enabled=*/false, - /*rate_limiting_enabled=*/true, + /*force_eligibility_enabled=*/false, base::test::TaskEnvironment::TimeSource::SYSTEM_TIME) {} }; @@ -551,7 +551,7 @@ : HoldingSpaceWallpaperNudgeControllerTestBase( /*counterfactual_enabled=*/false, drop_to_pin_enabled(), - /*rate_limiting_enabled=*/false, + /*force_eligibility_enabled=*/true, base::test::TaskEnvironment::TimeSource::SYSTEM_TIME) {} // Whether the drop-to-pin feature param is enabled. @@ -830,7 +830,7 @@ : HoldingSpaceWallpaperNudgeControllerTestBase( /*counterfactual_enabled=*/false, drop_to_pin_enabled(), - /*rate_limiting_enabled=*/true, + /*force_eligibility_enabled=*/false, base::test::TaskEnvironment::TimeSource::MOCK_TIME) {} // Whether the drop-to-pin feature param is enabled. @@ -1052,7 +1052,7 @@ : HoldingSpaceWallpaperNudgeControllerTestBase( counterfactual_enabled(), drop_to_pin_enabled(), - /*rate_limiting_enabled=*/false, + /*force_eligibility_enabled=*/true, base::test::TaskEnvironment::TimeSource::MOCK_TIME) {} // Whether the is-counterfactual feature parameter is enabled.
diff --git a/ash/webui/common/resources/cellular_setup/activation_code_page.js b/ash/webui/common/resources/cellular_setup/activation_code_page.js index aa085cb..8ff336286 100644 --- a/ash/webui/common/resources/cellular_setup/activation_code_page.js +++ b/ash/webui/common/resources/cellular_setup/activation_code_page.js
@@ -14,10 +14,10 @@ import './cellular_setup_icons.html.js'; import {focusWithoutInk} from '//resources/ash/common/focus_without_ink_js.js'; -import {I18nBehavior} from '//resources/ash/common/i18n_behavior.js'; +import {I18nBehavior, I18nBehaviorInterface} from '//resources/ash/common/i18n_behavior.js'; import {loadTimeData} from '//resources/ash/common/load_time_data.m.js'; import {MojoInterfaceProviderImpl} from '//resources/ash/common/network/mojo_interface_provider.js'; -import {afterNextRender, Polymer} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {afterNextRender, mixinBehaviors, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {CrosNetworkConfig, CrosNetworkConfigInterface} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/cros_network_config.mojom-webui.js'; import {NetworkType} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/network_types.mojom-webui.js'; @@ -66,146 +66,196 @@ */ const ACTIVATION_CODE_PREFIX = 'LPA:1$'; -Polymer({ - _template: getTemplate(), - is: 'activation-code-page', +/** + * @constructor + * @extends {PolymerElement} + * @implements {I18nBehaviorInterface} + */ +const ActivationCodePageElementBase = + mixinBehaviors([I18nBehavior], PolymerElement); - behaviors: [I18nBehavior], +/** @polymer */ +class ActivationCodePageElement extends ActivationCodePageElementBase { + static get is() { + return 'activation-code-page'; + } - properties: { - activationCode: { - type: String, - notify: true, - observer: 'onActivationCodeChanged_', - }, + static get template() { + return getTemplate(); + } - showError: { - type: Boolean, - notify: true, - observer: 'onShowErrorChanged_', - }, + static get properties() { + return { + activationCode: { + type: String, + notify: true, + observer: 'onActivationCodeChanged_', + }, + + showError: { + type: Boolean, + notify: true, + observer: 'onShowErrorChanged_', + }, + + /** + * Readonly property indicating whether the current |activationCode| + * was scanned from QR code. + */ + isFromQrCode: { + type: Boolean, + notify: true, + value: false, + }, + + /** + * Indicates the UI is busy with an operation and cannot be interacted + * with. + */ + showBusy: { + type: Boolean, + value: false, + }, + + /** + * Indicates no profiles were found while scanning. + */ + showNoProfilesFound: { + type: Boolean, + notify: true, + }, + + /** + * Enum used as an ID for specific UI elements. + * A UiElement is passed between html and JS for + * certain UI elements to determine their state. + * + * @type {!UiElement} + */ + UiElement: { + type: Object, + value: UiElement, + }, + + /** + * @type {!PageState} + * @private + */ + state_: { + type: Object, + value: PageState, + observer: 'onStateChanged_', + }, + + /** @private */ + cameraCount_: { + type: Number, + value: 0, + observer: 'onHasCameraCountChanged_', + }, + + /** + * TODO(crbug.com/1093185): add type |BarcodeDetector| when externs + * becomes available + * @private {?Object} + */ + qrCodeDetector_: { + type: Object, + value: null, + }, + + /** + * If true, video is expanded. + */ + expanded_: { + type: Boolean, + value: false, + reflectToAttribute: true, + }, + + /** + * A11y string used to announce the current status of qr code camera + * detection. Used when device web cam is turned on and ready to scan, + * and also used after scan has been completed. + * @private + */ + qrCodeCameraA11yString_: { + type: String, + value: '', + }, + + /** + * If true, device is locked to specific cellular operator. + */ + isDeviceCarrierLocked_: { + type: Boolean, + value: false, + }, + + isCellularCarrierLockEnabled_: { + type: Boolean, + value() { + return loadTimeData.valueExists('isCellularCarrierLockEnabled') && + loadTimeData.getBoolean('isCellularCarrierLockEnabled'); + }, + }, + + /** + * Indicates whether or not |activationCode| matches the correct + * activation code format. If there is a partial match (i.e. the code is + * incomplete but matches the format so far), this will be false. + * @private + */ + isActivationCodeInvalidFormat_: { + type: Boolean, + value: false, + }, + }; + } + + /** @override */ + constructor() { + super(); /** - * Readonly property indicating whether the current |activationCode| - * was scanned from QR code. - */ - isFromQrCode: { - type: Boolean, - notify: true, - value: false, - }, - - /** - * Indicates the UI is busy with an operation and cannot be interacted with. - */ - showBusy: { - type: Boolean, - value: false, - }, - - /** - * Indicates no profiles were found while scanning. - */ - showNoProfilesFound: { - type: Boolean, - notify: true, - }, - - /** - * Enum used as an ID for specific UI elements. - * A UiElement is passed between html and JS for - * certain UI elements to determine their state. - * - * @type {!UiElement} - */ - UiElement: { - type: Object, - value: UiElement, - }, - - /** - * @type {!PageState} + * @type {MediaDevices} * @private */ - state_: { - type: Object, - value: PageState, - observer: 'onStateChanged_', - }, + this.mediaDevices_ = null; - /** @private */ - cameraCount_: { - type: Number, - value: 0, - observer: 'onHasCameraCountChanged_', - }, + /** + * @type {?MediaStream} + * @private + */ + this.stream_ = null; + + /** + * @type {?number} + * @private + */ + this.qrCodeDetectorTimer_ = null; + + /** + * The function used to initiate a repeating timer. Can be overwritten in + * tests. + * @private {function(Function, number)} + */ + this.setIntervalFunction_ = setInterval.bind(window); /** * TODO(crbug.com/1093185): add type |BarcodeDetector| when externs * becomes available - * @private {?Object} + * @suppress {undefinedVars|missingProperties} + * @private */ - qrCodeDetector_: { - type: Object, - value: null, - }, + this.barcodeDetectorClass_ = BarcodeDetector; - /** - * If true, video is expanded. - */ - expanded_: { - type: Boolean, - value: false, - reflectToAttribute: true, - }, - - /** - * A11y string used to announce the current status of qr code camera - * detection. Used when device web cam is turned on and ready to scan, - * and also used after scan has been completed. - * @private - */ - qrCodeCameraA11yString_: { - type: String, - value: '', - }, - - /** - * If true, device is locked to specific cellular operator. - */ - isDeviceCarrierLocked_: { - type: Boolean, - value: false, - }, - - isCellularCarrierLockEnabled_: { - type: Boolean, - value() { - return loadTimeData.valueExists('isCellularCarrierLockEnabled') && - loadTimeData.getBoolean('isCellularCarrierLockEnabled'); - }, - }, - - /** - * Indicates whether or not |activationCode| matches the correct activation - * code format. If there is a partial match (i.e. the code is incomplete but - * matches the format so far), this will be false. - * @private - */ - isActivationCodeInvalidFormat_: { - type: Boolean, - value: false, - }, - }, - - /** @private {?CrosNetworkConfigInterface} */ - networkConfig_: null, - - /** @override */ - created() { + /** @private {typeof ImageCapture} */ + this.imageCaptureClass_ = ImageCapture; if (!this.isCellularCarrierLockEnabled_) { return; } + this.networkConfig_ = MojoInterfaceProviderImpl.getInstance().getMojoServiceRemote(); this.networkConfig_.getDeviceStateList().then(response => { @@ -216,80 +266,51 @@ this.isDeviceCarrierLocked_ = deviceState.isCarrierLocked; } }); - }, - - /** - * @type {MediaDevices} - * @private - */ - mediaDevices_: null, - - /** - * @type {?MediaStream} - * @private - */ - stream_: null, - - /** - * @type {?number} - * @private - */ - qrCodeDetectorTimer_: null, - - - /** - * The function used to initiate a repeating timer. Can be overwritten in - * tests. - * @private {function(Function, number)} - */ - setIntervalFunction_: setInterval.bind(window), - - /** - * TODO(crbug.com/1093185): add type |BarcodeDetector| when externs - * becomes available - * @suppress {undefinedVars|missingProperties} - * @private - */ - barcodeDetectorClass_: BarcodeDetector, - - /** @private {typeof ImageCapture} */ - imageCaptureClass_: ImageCapture, - - /** - * Function used to play the video. Can be overwritten by - * setFakesForTesting(). - * @private {function()} - */ - playVideo_: function() { - this.$$('#video').play(); - }, - - /** - * Function used to stop a stream. Can be overwritten by setFakesForTesting(). - * @private {function(MediaStream)} - */ - stopStream_: function(stream) { - if (stream) { - stream.getTracks()[0].stop(); - } - }, + } /** @override */ ready() { + super.ready(); + this.setMediaDevices(navigator.mediaDevices); this.initBarcodeDetector_(); this.state_ = PageState.MANUAL_ENTRY; - }, + } /** @override */ - detached() { + disconnectedCallback() { + super.disconnectedCallback(); + this.stopStream_(this.stream_); if (this.qrCodeDetectorTimer_) { this.clearQrCodeDetectorTimer_(); } this.mediaDevices_.removeEventListener( 'devicechange', this.updateCameraCount_.bind(this)); - }, + } + + /** + * Function used to play the video. Can be overwritten by + * setFakesForTesting(). + * @private + */ + playVideo_() { + const videoElement = this.shadowRoot.querySelector('#video'); + if (videoElement) { + videoElement.play(); + } + } + + /** + * Function used to stop a stream. Can be overwritten by setFakesForTesting(). + * @param {MediaStream} stream + * @private + */ + stopStream_(stream) { + if (stream) { + stream.getTracks()[0].stop(); + } + } /** * @return {boolean} @@ -297,7 +318,7 @@ */ isScanningAvailable_() { return this.cameraCount_ > 0 && !!this.qrCodeDetector_; - }, + } /** * @return {boolean} @@ -305,7 +326,7 @@ */ shouldShowCarrierLockWarning_() { return this.isCellularCarrierLockEnabled_ && this.isDeviceCarrierLocked_; - }, + } /** * TODO(crbug.com/1093185): Remove suppression when shape_detection extern @@ -326,7 +347,7 @@ this.qrCodeDetector_ = new this.barcodeDetectorClass_({formats: [QR_CODE_FORMAT]}); } - }, + } /** * @param {MediaDevices} mediaDevices @@ -336,7 +357,7 @@ this.updateCameraCount_(); this.mediaDevices_.addEventListener( 'devicechange', this.updateCameraCount_.bind(this)); - }, + } /** * TODO(crbug.com/1093185): Add barcodeDetectorClass type when BarcodeDetector @@ -356,14 +377,14 @@ this.setIntervalFunction_ = setIntervalFunction; this.playVideo_ = playVideoFunction; this.stopStream_ = stopStreamFunction; - }, + } /** * @returns {?number} */ getQrCodeDetectorTimerForTest() { return this.qrCodeDetectorTimer_; - }, + } /** * @return {string} @@ -371,7 +392,7 @@ */ computeActivationCodeClass_() { return this.isScanningAvailable_() ? 'relative' : 'center width-92'; - }, + } /** @private */ updateCameraCount_() { @@ -388,7 +409,7 @@ .catch(e => { this.cameraCount_ = 0; }); - }, + } /** @private */ onHasCameraCountChanged_() { @@ -399,7 +420,7 @@ this.state_ = PageState.SWITCHING_CAM_ENVIRONMENT_TO_USER; this.startScanning_(); } - }, + } /** private */ startScanning_() { @@ -422,9 +443,11 @@ .then(stream => { this.stream_ = stream; if (this.stream_) { - const video = this.$$('#video'); - video.srcObject = stream; - this.playVideo_(); + const video = this.shadowRoot.querySelector('#video'); + if (video) { + video.srcObject = stream; + this.playVideo_(); + } } this.stopStream_(oldStream); @@ -440,7 +463,7 @@ .catch(e => { this.state_ = PageState.SCANNING_FAILURE; }); - }, + } /** * Continuously checks stream if it contains a QR code. If a QR code is @@ -474,7 +497,7 @@ } catch (error) { this.state_ = PageState.SCANNING_FAILURE; } - }, + } /** * @param {ImageBitmap} frame @@ -494,22 +517,28 @@ return qrCodes[0].rawValue; } return null; - }, + } /** @private */ onActivationCodeChanged_() { - this.fire('activation-code-updated', { - activationCode: this.validateActivationCode_(this.activationCode) ? - this.activationCode : - null, + const event = new CustomEvent('activation-code-updated', { + bubbles: true, + composed: true, + detail: { + activationCode: this.validateActivationCode_(this.activationCode) ? + this.activationCode : + null, + }, }); - }, + + this.dispatchEvent(event); + } /** @private */ clearQrCodeDetectorTimer_() { clearTimeout(this.qrCodeDetectorTimer_); this.qrCodeDetectorTimer_ = null; - }, + } /** * Checks if |activationCode| matches or partially matches the correct format. @@ -544,7 +573,7 @@ return false; } return true; - }, + } /** @private */ onSwitchCameraButtonPressed_() { @@ -554,7 +583,7 @@ this.state_ = PageState.SWITCHING_CAM_ENVIRONMENT_TO_USER; } this.startScanning_(); - }, + } /** @private */ onShowErrorChanged_() { @@ -568,7 +597,7 @@ this.state_ = PageState.SCANNING_INSTALL_FAILURE; } } - }, + } /** @private */ onStateChanged_() { @@ -603,11 +632,14 @@ if (this.state_ === PageState.SCANNING_SUCCESS) { this.isFromQrCode = true; this.qrCodeCameraA11yString_ = this.i18n('qrCodeA11YCameraScanSuccess'); - this.fire('focus-default-button'); + this.dispatchEvent(new CustomEvent('focus-default-button', { + bubbles: true, + composed: true, + })); } this.expanded_ = false; - }, + } /** * @param {KeyboardEvent} e @@ -615,7 +647,10 @@ */ onKeyDown_(e) { if (e.key === 'Enter') { - this.fire('forward-navigation-requested'); + this.dispatchEvent(new CustomEvent('forward-navigation-requested', { + bubbles: true, + composed: true, + })); } // Prevents barcode detector video from closing if user tabs through @@ -627,7 +662,7 @@ this.state_ = PageState.MANUAL_ENTRY; e.stopPropagation(); - }, + } /** * @param {UiElement} uiElement @@ -661,7 +696,7 @@ case UiElement.SCAN_INSTALL_FAILURE: return state !== PageState.SCANNING_INSTALL_FAILURE; } - }, + } /** * @param {UiElement} uiElement @@ -680,7 +715,7 @@ default: return false; } - }, + } /** * @return {string} @@ -697,7 +732,7 @@ return this.i18n('scanQRCodeNoProfilesFound'); } return this.i18n('scanQRCode'); - }, + } /** * @param {PageState} state @@ -709,7 +744,7 @@ return true; } return state === PageState.MANUAL_ENTRY_INSTALL_FAILURE; - }, + } /** * @param {boolean} showBusy @@ -724,7 +759,7 @@ // Because this string contains '<' and '>' characters, we cannot use i18n // methods. return loadTimeData.getString('scanQrCodeInputSubtitle'); - }, + } /** * @return {string} @@ -734,5 +769,7 @@ // Because this string contains '<' and '>' characters, we cannot use i18n // methods. return loadTimeData.getString('scanQrCodeInputError'); - }, -}); + } +} + +customElements.define(ActivationCodePageElement.is, ActivationCodePageElement);
diff --git a/ash/webui/common/resources/cellular_setup/activation_verification_page.js b/ash/webui/common/resources/cellular_setup/activation_verification_page.js index e9bff5a..8ba4fcf 100644 --- a/ash/webui/common/resources/cellular_setup/activation_verification_page.js +++ b/ash/webui/common/resources/cellular_setup/activation_verification_page.js
@@ -11,14 +11,30 @@ import '//resources/polymer/v3_0/iron-media-query/iron-media-query.js'; import 'chrome://resources/cros_components/lottie_renderer/lottie-renderer.js'; -import {I18nBehavior} from '//resources/ash/common/i18n_behavior.js'; -import {Polymer} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {I18nBehavior, I18nBehaviorInterface} from '//resources/ash/common/i18n_behavior.js'; +import {mixinBehaviors, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {getTemplate} from './activation_verification_page.html.js'; -Polymer({ - _template: getTemplate(), - is: 'activation-verification-page', +/** + * @constructor + * @extends {PolymerElement} + * @implements {I18nBehaviorInterface} + */ +const ActivationVerificationPageElementBase = + mixinBehaviors([I18nBehavior], PolymerElement); - behaviors: [I18nBehavior], -}); +/** @polymer */ +class ActivationVerificationPageElement extends + ActivationVerificationPageElementBase { + static get is() { + return 'activation-verification-page'; + } + + static get template() { + return getTemplate(); + } +} + +customElements.define( + ActivationVerificationPageElement.is, ActivationVerificationPageElement);
diff --git a/ash/webui/common/resources/cellular_setup/base_page.js b/ash/webui/common/resources/cellular_setup/base_page.js index 7e096d0..357704c 100644 --- a/ash/webui/common/resources/cellular_setup/base_page.js +++ b/ash/webui/common/resources/cellular_setup/base_page.js
@@ -8,42 +8,55 @@ import '//resources/cr_elements/cr_shared_vars.css.js'; import '//resources/polymer/v3_0/iron-flex-layout/iron-flex-layout-classes.js'; -import {I18nBehavior} from '//resources/ash/common/i18n_behavior.js'; -import {Polymer} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {I18nBehavior, I18nBehaviorInterface} from '//resources/ash/common/i18n_behavior.js'; +import {mixinBehaviors, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {getTemplate} from './base_page.html.js'; -Polymer({ - _template: getTemplate(), - is: 'base-page', +/** + * @constructor + * @extends {PolymerElement} + * @implements {I18nBehaviorInterface} + */ +const BasePageElementBase = mixinBehaviors([I18nBehavior], PolymerElement); - behaviors: [I18nBehavior], +/** @polymer */ +class BasePageElement extends BasePageElementBase { + static get is() { + return 'base-page'; + } - properties: { - /** - * Main title for the page. - * - * @type {string} - */ - title: String, + static get template() { + return getTemplate(); + } - /** - * Message displayed under the main title. - * - * @type {string} - */ - message: String, + static get properties() { + return { + /** + * Main title for the page. + * + * @type {string} + */ + title: String, - /** - * Name for the cellular-setup iconset iron-icon displayed beside message. - * - * @type {string} - */ - messageIcon: { - type: String, - value: '', - }, - }, + /** + * Message displayed under the main title. + * + * @type {string} + */ + message: String, + + /** + * Name for the cellular-setup iconset iron-icon displayed beside message. + * + * @type {string} + */ + messageIcon: { + type: String, + value: '', + }, + }; + } /** * @returns {string} @@ -51,7 +64,7 @@ */ getTitle_() { return this.title; - }, + } /** * @returns {boolean} @@ -59,7 +72,7 @@ */ isTitleShown_() { return !!this.title; - }, + } /** * @returns {boolean} @@ -67,5 +80,7 @@ */ isMessageIconShown_() { return !!this.messageIcon; - }, -}); + } +} + +customElements.define(BasePageElement.is, BasePageElement);
diff --git a/ash/webui/common/resources/cellular_setup/button_bar.js b/ash/webui/common/resources/cellular_setup/button_bar.js index a8ec87f..eacd080 100644 --- a/ash/webui/common/resources/cellular_setup/button_bar.js +++ b/ash/webui/common/resources/cellular_setup/button_bar.js
@@ -10,43 +10,54 @@ import {assert, assertNotReached} from '//resources/ash/common/assert.js'; import {focusWithoutInk} from '//resources/ash/common/focus_without_ink_js.js'; -import {I18nBehavior} from '//resources/ash/common/i18n_behavior.js'; -import {Polymer} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {I18nBehavior, I18nBehaviorInterface} from '//resources/ash/common/i18n_behavior.js'; +import {mixinBehaviors, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {getTemplate} from './button_bar.html.js'; import {Button, ButtonBarState, ButtonState, CellularSetupPageName} from './cellular_types.js'; -Polymer({ - _template: getTemplate(), - is: 'button-bar', +/** + * @constructor + * @extends {PolymerElement} + * @implements {I18nBehaviorInterface} + */ +const ButtonBarElementBase = mixinBehaviors([I18nBehavior], PolymerElement); - behaviors: [ - I18nBehavior, - ], +/** @polymer */ +export class ButtonBarElement extends ButtonBarElementBase { + static get is() { + return 'button-bar'; + } - properties: { - /** - * Sets the states of all buttons - * @type {!ButtonBarState} - */ - buttonState: { - type: Object, - value: {}, - }, + static get template() { + return getTemplate(); + } - /** - * @type {!Button} - */ - Button: { - type: Object, - value: Button, - }, + static get properties() { + return { + /** + * Sets the states of all buttons + * @type {!ButtonBarState} + */ + buttonState: { + type: Object, + value: {}, + }, - forwardButtonLabel: { - type: String, - value: '', - }, - }, + /** + * @type {!Button} + */ + Button: { + type: Object, + value: Button, + }, + + forwardButtonLabel: { + type: String, + value: '', + }, + }; + } /** * @param {!Button} buttonName @@ -56,7 +67,7 @@ isButtonHidden_(buttonName) { const state = this.getButtonBarState_(buttonName); return state === ButtonState.HIDDEN; - }, + } /** * @param {!Button} buttonName @@ -66,7 +77,7 @@ isButtonDisabled_(buttonName) { const state = this.getButtonBarState_(buttonName); return state === ButtonState.DISABLED; - }, + } focusDefaultButton() { const buttons = this.shadowRoot.querySelectorAll('cr-button'); @@ -78,22 +89,31 @@ return; } } - }, + } /** @private */ onBackwardButtonClicked_() { - this.fire('backward-nav-requested'); - }, + this.dispatchEvent(new CustomEvent('backward-nav-requested', { + bubbles: true, + composed: true, + })); + } /** @private */ onCancelButtonClicked_() { - this.fire('cancel-requested'); - }, + this.dispatchEvent(new CustomEvent('cancel-requested', { + bubbles: true, + composed: true, + })); + } /** @private */ onForwardButtonClicked_() { - this.fire('forward-nav-requested'); - }, + this.dispatchEvent(new CustomEvent('forward-nav-requested', { + bubbles: true, + composed: true, + })); + } /** * @param {!Button} button @@ -113,5 +133,7 @@ assertNotReached(); return ButtonState.ENABLED; } - }, -}); + } +} + +customElements.define(ButtonBarElement.is, ButtonBarElement);
diff --git a/ash/webui/common/resources/cellular_setup/cellular_setup.js b/ash/webui/common/resources/cellular_setup/cellular_setup.js index d2b4c7d..9ae8b0a 100644 --- a/ash/webui/common/resources/cellular_setup/cellular_setup.js +++ b/ash/webui/common/resources/cellular_setup/cellular_setup.js
@@ -10,102 +10,123 @@ import './psim_flow_ui.js'; import './esim_flow_ui.js'; -import {I18nBehavior} from '//resources/ash/common/i18n_behavior.js'; -import {Polymer} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {I18nBehavior, I18nBehaviorInterface} from '//resources/ash/common/i18n_behavior.js'; +import {mixinBehaviors, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {getTemplate} from './cellular_setup.html.js'; import {CellularSetupDelegate} from './cellular_setup_delegate.js'; import {ButtonBarState, CellularSetupPageName} from './cellular_types.js'; +import {EsimFlowUiElement} from './esim_flow_ui.js'; +import {PsimFlowUiElement} from './psim_flow_ui.js'; -Polymer({ - _template: getTemplate(), - is: 'cellular-setup', +/** + * @constructor + * @extends {PolymerElement} + * @implements {I18nBehaviorInterface} + */ +const CellularSetupElementBase = mixinBehaviors([I18nBehavior], PolymerElement); - behaviors: [I18nBehavior], +/** @polymer */ +class CellularSetupElement extends CellularSetupElementBase { + static get is() { + return 'cellular-setup'; + } - properties: { - /** @type {!CellularSetupDelegate} */ - delegate: Object, + static get template() { + return getTemplate(); + } - /** - * Banner used in pSIM flow to show carrier network name. No banner - * shown if the string is empty. - */ - flowPsimBanner: { - type: String, - notify: true, - value: '', - }, + static get properties() { + return { + /** @type {!CellularSetupDelegate} */ + delegate: Object, - /** - * Header for the flow, shown below the title. No header shown if the string - * is empty. - */ - flowHeader: { - type: String, - notify: true, - value: '', - }, + /** + * Banner used in pSIM flow to show carrier network name. No banner + * shown if the string is empty. + */ + flowPsimBanner: { + type: String, + notify: true, + value: '', + }, - /** - * Name of the currently displayed sub-page. - * @private {!CellularSetupPageName|null} - */ - currentPageName: String, + /** + * Header for the flow, shown below the title. No header shown if the + * string is empty. + */ + flowHeader: { + type: String, + notify: true, + value: '', + }, - /** - * Current user selected setup flow page name. - * @private {!CellularSetupPageName|null} - */ - selectedFlow_: { - type: String, - value: null, - }, + /** + * Name of the currently displayed sub-page. + * @private {!CellularSetupPageName|null} + */ + currentPageName: String, - /** - * Button bar button state. - * @private {!ButtonBarState} - */ - buttonState_: { - type: Object, - notify: true, - }, + /** + * Current user selected setup flow page name. + * @private {!CellularSetupPageName|null} + */ + selectedFlow_: { + type: String, + value: null, + }, - /** - * DOM Element corresponding to the visible page. - * - * @private {!PsimFlowUiElement|!EsimFlowUiElement} - */ - currentPage_: { - type: Object, - observer: 'onPageChange_', - }, + /** + * Button bar button state. + * @private {!ButtonBarState} + */ + buttonState_: { + type: Object, + notify: true, + }, - /** - * Text for the button_bar's 'Forward' button. - * @private {string} - */ - forwardButtonLabel_: { - type: String, - }, - }, + /** + * DOM Element corresponding to the visible page. + * + * @private {!PsimFlowUiElement|!EsimFlowUiElement} + */ + currentPage_: { + type: Object, + observer: 'onPageChange_', + }, - listeners: { - 'backward-nav-requested': 'onBackwardNavRequested_', - 'retry-requested': 'onRetryRequested_', - 'forward-nav-requested': 'onForwardNavRequested_', - 'cancel-requested': 'onCancelRequested_', - 'focus-default-button': 'onFocusDefaultButton_', - }, + /** + * Text for the button_bar's 'Forward' button. + * @private {string} + */ + forwardButtonLabel_: { + type: String, + }, + }; + } /** @override */ - attached() { + connectedCallback() { + super.connectedCallback(); + // By default eSIM flow is selected. if (!this.currentPageName) { this.currentPageName = CellularSetupPageName.ESIM_FLOW_UI; } - }, + } + + /** override */ + ready() { + super.ready(); + + this.addEventListener( + 'backward-nav-requested', this.onBackwardNavRequested_); + this.addEventListener('retry-requested', this.onRetryRequested_); + this.addEventListener('forward-nav-requested', this.onForwardNavRequested_); + this.addEventListener('cancel-requested', this.onCancelRequested_); + this.addEventListener('focus-default-button', this.onFocusDefaultButton_); + } /** @private */ onPageChange_() { @@ -113,31 +134,34 @@ this.flowPsimBanner = ''; this.currentPage_.initSubflow(); } - }, + } /** @private */ onBackwardNavRequested_() { this.currentPage_.navigateBackward(); - }, + } onCancelRequested_() { - this.fire('exit-cellular-setup'); - }, + this.dispatchEvent(new CustomEvent('exit-cellular-setup', { + bubbles: true, + composed: true, + })); + } /** @private */ onRetryRequested_() { // TODO(crbug.com/1093185): Add try again logic. - }, + } /** @private */ onForwardNavRequested_() { this.currentPage_.navigateForward(); - }, + } /** @private */ onFocusDefaultButton_() { this.$.buttonBar.focusDefaultButton(); - }, + } /** * @param {string} currentPage @@ -145,7 +169,7 @@ */ shouldShowPsimFlow_(currentPage) { return currentPage === CellularSetupPageName.PSIM_FLOW_UI; - }, + } /** * @param {string} currentPage @@ -153,5 +177,7 @@ */ shouldShowEsimFlow_(currentPage) { return currentPage === CellularSetupPageName.ESIM_FLOW_UI; - }, -}); + } +} + +customElements.define(CellularSetupElement.is, CellularSetupElement);
diff --git a/ash/webui/common/resources/cellular_setup/confirmation_code_page.js b/ash/webui/common/resources/cellular_setup/confirmation_code_page.js index c14b821e..337e3a9 100644 --- a/ash/webui/common/resources/cellular_setup/confirmation_code_page.js +++ b/ash/webui/common/resources/cellular_setup/confirmation_code_page.js
@@ -12,36 +12,46 @@ import '//resources/polymer/v3_0/paper-spinner/paper-spinner-lite.js'; import './base_page.js'; -import {I18nBehavior} from '//resources/ash/common/i18n_behavior.js'; -import {Polymer} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {I18nBehavior, I18nBehaviorInterface} from '//resources/ash/common/i18n_behavior.js'; +import {mixinBehaviors, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {mojoString16ToString} from 'chrome://resources/js/mojo_type_util.js'; import {ESimProfileProperties} from 'chrome://resources/mojo/chromeos/ash/services/cellular_setup/public/mojom/esim_manager.mojom-webui.js'; import {getTemplate} from './confirmation_code_page.html.js'; -Polymer({ - _template: getTemplate(), - is: 'confirmation-code-page', +/** + * @constructor + * @extends {PolymerElement} + * @implements {I18nBehaviorInterface} + */ +const ConfirmationCodePageElementBase = + mixinBehaviors([I18nBehavior], PolymerElement); - behaviors: [I18nBehavior], +/** @polymer */ +class ConfirmationCodePageElement extends ConfirmationCodePageElementBase { + static get is() { + return 'confirmation-code-page'; + } - properties: { - /** - * @type {?ESimProfileProperties} - */ - profileProperties: { - type: Object, - }, + static get template() { + return getTemplate(); + } - confirmationCode: { - type: String, - notify: true, - }, + static get properties() { + return { + /** + * @type {?ESimProfileProperties} + */ + profileProperties: Object, - showError: { - type: Boolean, - }, - }, + confirmationCode: { + type: String, + notify: true, + }, + + showError: Boolean, + }; + } /** * @param {KeyboardEvent} e @@ -49,10 +59,13 @@ */ onKeyDown_(e) { if (e.key === 'Enter') { - this.fire('forward-navigation-requested'); + this.dispatchEvent(new CustomEvent('forward-navigation-requested', { + bubbles: true, + composed: true, + })); } e.stopPropagation(); - }, + } /** * @return {string} @@ -63,5 +76,8 @@ return ''; } return mojoString16ToString(this.profileProperties.name); - }, -}); + } +} + +customElements.define( + ConfirmationCodePageElement.is, ConfirmationCodePageElement);
diff --git a/ash/webui/common/resources/cellular_setup/confirmation_code_page_legacy.js b/ash/webui/common/resources/cellular_setup/confirmation_code_page_legacy.js index 6da4963d..b4dd1e6 100644 --- a/ash/webui/common/resources/cellular_setup/confirmation_code_page_legacy.js +++ b/ash/webui/common/resources/cellular_setup/confirmation_code_page_legacy.js
@@ -12,63 +12,78 @@ import '//resources/polymer/v3_0/paper-spinner/paper-spinner-lite.js'; import './base_page.js'; -import {I18nBehavior} from '//resources/ash/common/i18n_behavior.js'; -import {Polymer} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {I18nBehavior, I18nBehaviorInterface} from '//resources/ash/common/i18n_behavior.js'; +import {mixinBehaviors, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {mojoString16ToString} from 'chrome://resources/js/mojo_type_util.js'; import {ESimProfileProperties, ESimProfileRemote} from 'chrome://resources/mojo/chromeos/ash/services/cellular_setup/public/mojom/esim_manager.mojom-webui.js'; import {getTemplate} from './confirmation_code_page_legacy.html.js'; -Polymer({ - _template: getTemplate(), - is: 'confirmation-code-page-legacy', +/** + * @constructor + * @extends {PolymerElement} + * @implements {I18nBehaviorInterface} + */ +const ConfirmationCodePageLegacyElementBase = + mixinBehaviors([I18nBehavior], PolymerElement); - behaviors: [I18nBehavior], +/** @polymer */ +class ConfirmationCodePageLegacyElement extends + ConfirmationCodePageLegacyElementBase { + static get is() { + return 'confirmation-code-page-legacy'; + } - properties: { - /** - * @type {?ESimProfileRemote} - */ - profile: { - type: Object, - observer: 'onProfileChanged_', - }, + static get template() { + return getTemplate(); + } - confirmationCode: { - type: String, - notify: true, - }, + static get properties() { + return { + /** + * @type {?ESimProfileRemote} + */ + profile: { + type: Object, + observer: 'onProfileChanged_', + }, - showError: { - type: Boolean, - }, + confirmationCode: { + type: String, + notify: true, + }, - /** - * Indicates the UI is busy with an operation and cannot be interacted with. - */ - showBusy: { - type: Boolean, - value: false, - }, + showError: Boolean, - /** - * @type {?ESimProfileProperties} - * @private - */ - profileProperties_: { - type: Object, - value: null, - }, + /** + * Indicates the UI is busy with an operation and cannot be interacted + * with. + */ + showBusy: { + type: Boolean, + value: false, + }, - /** - * @type {boolean} - * @private - */ - isDarkModeActive_: { - type: Boolean, - value: false, - }, - }, + /** + * @type {?ESimProfileProperties} + * @private + */ + profileProperties_: { + type: Object, + value: null, + }, + + /** + * @type {boolean} + * @private + */ + isDarkModeActive_: { + type: Boolean, + value: false, + }, + + }; + } /** @private */ onProfileChanged_() { @@ -79,7 +94,7 @@ this.profile.getProperties().then(response => { this.profileProperties_ = response.properties; }); - }, + } /** * @param {KeyboardEvent} e @@ -87,10 +102,13 @@ */ onKeyDown_(e) { if (e.key === 'Enter') { - this.fire('forward-navigation-requested'); + this.dispatchEvent(new CustomEvent('forward-navigation-requested', { + bubbles: true, + composed: true, + })); } e.stopPropagation(); - }, + } /** * @return {boolean} @@ -98,7 +116,7 @@ */ shouldShowProfileDetails_() { return !!this.profile; - }, + } /** * @return {string} @@ -109,7 +127,7 @@ return ''; } return mojoString16ToString(this.profileProperties_.name); - }, + } /** * @return {string} @@ -119,5 +137,8 @@ return this.isDarkModeActive_ ? 'chrome://resources/ash/common/cellular_setup/default_esim_profile_dark.svg' : 'chrome://resources/ash/common/cellular_setup/default_esim_profile.svg'; - }, -}); + } +} + +customElements.define( + ConfirmationCodePageLegacyElement.is, ConfirmationCodePageLegacyElement);
diff --git a/ash/webui/common/resources/cellular_setup/esim_flow_ui.js b/ash/webui/common/resources/cellular_setup/esim_flow_ui.js index 5d0966c..004aa18 100644 --- a/ash/webui/common/resources/cellular_setup/esim_flow_ui.js +++ b/ash/webui/common/resources/cellular_setup/esim_flow_ui.js
@@ -14,11 +14,11 @@ import './confirmation_code_page.js'; import {assert, assertNotReached} from '//resources/ash/common/assert.js'; -import {I18nBehavior} from '//resources/ash/common/i18n_behavior.js'; +import {I18nBehavior, I18nBehaviorInterface} from '//resources/ash/common/i18n_behavior.js'; import {hasActiveCellularNetwork} from '//resources/ash/common/network/cellular_utils.js'; import {MojoInterfaceProvider, MojoInterfaceProviderImpl} from '//resources/ash/common/network/mojo_interface_provider.js'; -import {NetworkListenerBehavior} from '//resources/ash/common/network/network_listener_behavior.js'; -import {Polymer} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {NetworkListenerBehavior, NetworkListenerBehaviorInterface} from '//resources/ash/common/network/network_listener_behavior.js'; +import {mixinBehaviors, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {loadTimeData} from 'chrome://resources/ash/common/load_time_data.m.js'; import {ESimManagerRemote, ESimOperationResult, ESimProfileProperties, ESimProfileRemote, EuiccRemote, ProfileInstallMethod, ProfileInstallResult, ProfileState} from 'chrome://resources/mojo/chromeos/ash/services/cellular_setup/public/mojom/esim_manager.mojom-webui.js'; import {FilterType, NetworkStateProperties, NO_LIMIT} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/cros_network_config.mojom-webui.js'; @@ -89,197 +89,190 @@ * Root element for the eSIM cellular setup flow. This element interacts with * the CellularSetup service to carry out the esim activation flow. */ -Polymer({ - _template: getTemplate(), - is: 'esim-flow-ui', - behaviors: [ - I18nBehavior, - NetworkListenerBehavior, - SubflowBehavior, - ], +/** + * @constructor + * @extends {PolymerElement} + * @implements {I18nBehaviorInterface} + * @implements {NetworkListenerBehaviorInterface} + */ +const EsimFlowUiElementBase = mixinBehaviors( + [I18nBehavior, NetworkListenerBehavior, SubflowBehavior], PolymerElement); - properties: { - /** @type {!CellularSetupDelegate} */ - delegate: Object, +/** @polymer */ +export class EsimFlowUiElement extends EsimFlowUiElementBase { + static get is() { + return 'esim-flow-ui'; + } - /** - * Header shown at the top of the flow. No header shown if the string is - * empty. - */ - header: { - type: String, - notify: true, - computed: 'computeHeader_(selectedESimPageName_, showError_)', - }, + static get template() { + return getTemplate(); + } - forwardButtonLabel: { - type: String, - notify: true, - }, + static get properties() { + return { + /** @type {!CellularSetupDelegate} */ + delegate: Object, - /** - * @type {!ESimUiState} - * @private - */ - state_: { - type: String, - value: function() { - if (loadTimeData.valueExists('isSmdsSupportEnabled') && - loadTimeData.getBoolean('isSmdsSupportEnabled')) { - return ESimUiState.PROFILE_SEARCH_CONSENT; - } - return ESimUiState.PROFILE_SEARCH; + /** + * Header shown at the top of the flow. No header shown if the string is + * empty. + */ + header: { + type: String, + notify: true, + computed: 'computeHeader_(selectedESimPageName_, showError_)', }, - observer: 'onStateChanged_', - }, - /** - * Element name of the current selected sub-page. - * This is set in updateSelectedPage_ on initialization. - * @type {?ESimPageName} - * @private - */ - selectedESimPageName_: String, - - /** - * Whether the user has consented to a scan for profiles. - * @type {boolean} - */ - hasConsentedForDiscovery_: { - type: Boolean, - value: false, - }, - - /** - * Whether the user is setting up the eSIM profile manually. - * @type {boolean} - */ - shouldSkipDiscovery_: { - type: Boolean, - value: false, - }, - - /** - * Whether error state should be shown for the current page. - * @private {boolean} - */ - showError_: { - type: Boolean, - value: false, - }, - - /** - * Profiles fetched that have status kPending. - * @type {!Array<!ESimProfileRemote>} - * @private - */ - pendingProfiles_: { - type: Array, - }, - - /** - * Profile selected to be installed. - * @type {?ESimProfileRemote} - * @private - */ - selectedProfile_: { - type: Object, - }, - - /** - * Profile properties fetched from the latest SM-DS scan. - * @type {!Array<!ESimProfileProperties>} - * @private - */ - pendingProfileProperties_: { - type: Array, - }, - - /** - * Profile properties selected to be installed. - * @type {?ESimProfileProperties} - * @private - */ - selectedProfileProperties_: { - type: Object, - }, - - /** @private */ - activationCode_: { - type: String, - value: '', - }, - - /** @private */ - confirmationCode_: { - type: String, - value: '', - observer: 'onConfirmationCodeUpdated_', - }, - - /** @private */ - hasHadActiveCellularNetwork_: { - type: Boolean, - value: false, - }, - - /** @private */ - isActivationCodeFromQrCode_: { - type: Boolean, - }, - - /** - * Return true if SmdsSupportEnabled feature flag is enabled. - */ - smdsSupportEnabled_: { - type: Boolean, - value() { - return loadTimeData.valueExists('isSmdsSupportEnabled') && - loadTimeData.getBoolean('isSmdsSupportEnabled'); + forwardButtonLabel: { + type: String, + notify: true, }, - }, - }, - /** - * Provides an interface to the ESimManager Mojo service. - * @private {?ESimManagerRemote} - */ - eSimManagerRemote_: null, + /** + * @type {!ESimUiState} + * @private + */ + state_: { + type: String, + value: function() { + if (loadTimeData.valueExists('isSmdsSupportEnabled') && + loadTimeData.getBoolean('isSmdsSupportEnabled')) { + return ESimUiState.PROFILE_SEARCH_CONSENT; + } + return ESimUiState.PROFILE_SEARCH; + }, + observer: 'onStateChanged_', + }, - /** @private {?EuiccRemote} */ - euicc_: null, + /** + * Element name of the current selected sub-page. + * This is set in updateSelectedPage_ on initialization. + * @type {?ESimPageName} + * @private + */ + selectedESimPageName_: String, - /** @private {boolean} */ - hasFailedFetchingProfiles_: false, + /** + * Whether the user has consented to a scan for profiles. + * @type {boolean} + */ + hasConsentedForDiscovery_: { + type: Boolean, + value: false, + }, - /** @private {?ProfileInstallResult} */ - lastProfileInstallResult_: null, + /** + * Whether the user is setting up the eSIM profile manually. + * @type {boolean} + */ + shouldSkipDiscovery_: { + type: Boolean, + value: false, + }, - /** - * If there are no active network connections of any type. - * @private {boolean} - */ - isOffline_: false, + /** + * Whether error state should be shown for the current page. + * @private {boolean} + */ + showError_: { + type: Boolean, + value: false, + }, - /** - * The time at which the ESim flow is attached. - * @private {?Date} - */ - timeOnAttached_: null, + /** + * Profiles fetched that have status kPending. + * @type {!Array<!ESimProfileRemote>} + * @private + */ + pendingProfiles_: Array, - listeners: { - 'activation-code-updated': 'onActivationCodeUpdated_', - 'forward-navigation-requested': 'onForwardNavigationRequested_', - }, + /** + * Profile selected to be installed. + * @type {?ESimProfileRemote} + * @private + */ + selectedProfile_: { + type: Object, + observer: 'onSelectedProfileChanged_', + }, - observers: [ - 'onSelectedProfileChanged_(selectedProfile_)', - 'onSelectedProfilePropertiesChanged_(selectedProfileProperties_)', - ], + /** + * Profile properties fetched from the latest SM-DS scan. + * @type {!Array<!ESimProfileProperties>} + * @private + */ + pendingProfileProperties_: Array, + + /** + * Profile properties selected to be installed. + * @type {?ESimProfileProperties} + * @private + */ + selectedProfileProperties_: { + type: Object, + observer: 'onSelectedProfilePropertiesChanged_', + }, + + /** @private */ + activationCode_: { + type: String, + value: '', + }, + + /** @private */ + confirmationCode_: { + type: String, + value: '', + observer: 'onConfirmationCodeUpdated_', + }, + + /** @private */ + hasHadActiveCellularNetwork_: { + type: Boolean, + value: false, + }, + + /** @private */ + isActivationCodeFromQrCode_: Boolean, + + /** + * Return true if SmdsSupportEnabled feature flag is enabled. + */ + smdsSupportEnabled_: { + type: Boolean, + value() { + return loadTimeData.valueExists('isSmdsSupportEnabled') && + loadTimeData.getBoolean('isSmdsSupportEnabled'); + }, + }, + + }; + } /** @override */ - created() { + constructor() { + super(); + + /** @private {?EuiccRemote} */ + this.euicc_ = null; + + /** @private {boolean} */ + this.hasFailedFetchingProfiles_ = false; + + /** @private {?ProfileInstallResult} */ + this.lastProfileInstallResult_ = null; + + /** + * If there are no active network connections of any type. + * @private {boolean} + */ + this.isOffline_ = false; + + /** + * Provides an interface to the ESimManager Mojo service. + * @private {?ESimManagerRemote} + */ this.eSimManagerRemote_ = getESimManagerRemote(); const networkConfig = MojoInterfaceProviderImpl.getInstance().getMojoServiceRemote(); @@ -292,18 +285,36 @@ networkConfig.getNetworkStateList(filter).then(response => { this.onActiveNetworksChanged(response.result); }); - }, + } /** @override */ - attached() { + connectedCallback() { + super.connectedCallback(); + + /** + * The time at which the ESim flow is attached. + * @private {?Date} + */ this.timeOnAttached_ = new Date(); - }, + } /** @override */ - detached() { + disconnectedCallback() { + super.disconnectedCallback(); + let resultCode = null; switch (this.lastProfileInstallResult_) { + case null: + // Handles case when no profile installation was attempted. + if (this.hasFailedFetchingProfiles_) { + resultCode = ESimSetupFlowResult.ERROR_FETCHING_PROFILES; + } else if (this.noProfilesFound_()) { + resultCode = ESimSetupFlowResult.CANCELLED_NO_PROFILES; + } else { + resultCode = ESimSetupFlowResult.CANCELLED_WITHOUT_ERROR; + } + break; case ProfileInstallResult.kSuccess: resultCode = ESimSetupFlowResult.SUCCESS; break; @@ -317,14 +328,6 @@ resultCode = ESimSetupFlowResult.CANCELLED_INVALID_ACTIVATION_CODE; break; default: - // Handles case when no profile installation was attempted. - if (this.hasFailedFetchingProfiles_) { - resultCode = ESimSetupFlowResult.ERROR_FETCHING_PROFILES; - } else if (this.noProfilesFound_()) { - resultCode = ESimSetupFlowResult.CANCELLED_NO_PROFILES; - } else { - resultCode = ESimSetupFlowResult.CANCELLED_WITHOUT_ERROR; - } break; } @@ -346,7 +349,18 @@ chrome.metricsPrivate.recordLongTime( FAILED_ESIM_SETUP_DURATION_METRIC_NAME, elapsedTimeMs); - }, + } + + /** override */ + ready() { + super.ready(); + + this.addEventListener('activation-code-updated', (event) => { + this.onActivationCodeUpdated_(event); + }); + this.addEventListener( + 'forward-navigation-requested', this.onForwardNavigationRequested_); + } /** * NetworkListenerBehavior override @@ -357,7 +371,7 @@ onActiveNetworksChanged(activeNetworks) { this.isOffline_ = !activeNetworks.some( (network) => network.connectionState === ConnectionStateType.kOnline); - }, + } initSubflow() { if (!this.smdsSupportEnabled_) { @@ -366,7 +380,7 @@ this.getEuicc_(); } this.onNetworkStateListChanged(); - }, + } /** @private */ async fetchProfiles_() { @@ -385,7 +399,7 @@ } else { this.state_ = ESimUiState.PROFILE_SELECTION; } - }, + } /** @private */ async getEuicc_() { @@ -398,7 +412,7 @@ return; } this.euicc_ = euicc; - }, + } /** * @private @@ -419,7 +433,7 @@ return properties.state === ProfileState.kPending && properties.activationCode; }); - }, + } /** * @private @@ -436,7 +450,7 @@ this.pendingProfiles_ = []; } this.pendingProfiles_ = await getPendingESimProfiles(this.euicc_); - }, + } /** * @private @@ -464,7 +478,7 @@ response.result === ProfileInstallResult.kFailure) { this.state_ = ESimUiState.SETUP_FINISH; } - }, + } /** @private */ onStateChanged_(newState, oldState) { @@ -475,7 +489,7 @@ this.fetchProfiles_(); } this.initializePageState_(newState, oldState); - }, + } /** @private */ updateSelectedPage_() { @@ -532,9 +546,12 @@ } // If there is a page change, fire focus event. if (oldSelectedESimPageName !== this.selectedESimPageName_) { - this.fire('focus-default-button'); + this.dispatchEvent(new CustomEvent('focus-default-button', { + bubbles: true, + composed: true, + })); } - }, + } /** * @param {boolean} enableForwardBtn @@ -555,7 +572,7 @@ cancel: cancelButtonStateIfEnabled, forward: enableForwardBtn ? ButtonState.ENABLED : ButtonState.DISABLED, }; - }, + } /** * @param {boolean} enableForwardBtn @@ -576,7 +593,7 @@ cancel: cancelButtonStateIfEnabled, forward: enableForwardBtn ? ButtonState.ENABLED : ButtonState.DISABLED, }; - }, + } /** @private */ updateButtonBarState_() { @@ -662,7 +679,7 @@ break; } this.set('buttonState', buttonState); - }, + } /** @private */ updateForwardButtonLabel_() { @@ -675,7 +692,7 @@ this.i18n('next') : this.i18n('skipDiscovery'); } - }, + } /** @private */ initializePageState_(newState, oldState) { @@ -687,7 +704,7 @@ oldState !== ESimUiState.ACTIVATION_CODE_ENTRY_READY) { this.activationCode_ = ''; } - }, + } /** @private */ onActivationCodeUpdated_(event) { @@ -701,7 +718,7 @@ this.state_ = event.detail.activationCode ? ESimUiState.ACTIVATION_CODE_ENTRY_READY : ESimUiState.ACTIVATION_CODE_ENTRY; - }, + } /** @private */ onSelectedProfileChanged_() { @@ -715,7 +732,7 @@ return; } this.updateForwardButtonLabel_(); - }, + } /** @private */ onSelectedProfilePropertiesChanged_() { @@ -729,7 +746,7 @@ return; } this.updateForwardButtonLabel_(); - }, + } /** @private */ onConfirmationCodeUpdated_() { @@ -743,7 +760,7 @@ this.state_ = this.confirmationCode_ ? ESimUiState.CONFIRMATION_CODE_ENTRY_READY : ESimUiState.CONFIRMATION_CODE_ENTRY; - }, + } /** SubflowBehavior override */ navigateForward() { @@ -824,13 +841,16 @@ } break; case ESimUiState.SETUP_FINISH: - this.fire('exit-cellular-setup'); + this.dispatchEvent(new CustomEvent('exit-cellular-setup', { + bubbles: true, + composed: true, + })); break; default: assertNotReached(); break; } - }, + } /** SubflowBehavior override */ navigateBackward() { @@ -855,7 +875,7 @@ 'Navigate backward faled for : ' + this.state_ + ' this state does not support backward navigation.'); assertNotReached(); - }, + } /** @private */ onForwardNavigationRequested_() { @@ -865,7 +885,7 @@ this.state_ === ESimUiState.PROFILE_SELECTION) { this.navigateForward(); } - }, + } /** NetworkListenerBehavior override */ onNetworkStateListChanged() { @@ -877,14 +897,14 @@ this.hasHadActiveCellularNetwork_ = hasActive; } }); - }, + } /** @private */ shouldShowSubpageBusy_() { return this.state_ === ESimUiState.ACTIVATION_CODE_ENTRY_INSTALLING || this.state_ === ESimUiState.CONFIRMATION_CODE_ENTRY_INSTALLING || this.state_ === ESimUiState.PROFILE_SELECTION_INSTALLING; - }, + } /** @private */ getLoadingMessage_() { @@ -895,7 +915,7 @@ return this.hasHadActiveCellularNetwork_ ? this.i18n('eSimProfileDetectDuringActiveCellularConnectionMessage') : this.i18n('eSimProfileDetectMessage'); - }, + } /** * @return {string} @@ -924,7 +944,7 @@ } return ''; - }, + } /** * @return {ProfileInstallMethod} @@ -939,7 +959,7 @@ return this.hasConsentedForDiscovery_ ? ProfileInstallMethod.kViaActivationCodeAfterSmds : ProfileInstallMethod.kViaActivationCodeSkippedSmds; - }, + } /** * Returns true if profiles have been received and none were found. @@ -954,7 +974,7 @@ } else { return (this.pendingProfiles_ && this.pendingProfiles_.length === 0); } - }, + } /** @private*/ profilesFound_() { @@ -965,5 +985,7 @@ } else { return (this.pendingProfiles_ && this.pendingProfiles_.length > 0); } - }, -}); + } +} + +customElements.define(EsimFlowUiElement.is, EsimFlowUiElement);
diff --git a/ash/webui/common/resources/cellular_setup/final_page.js b/ash/webui/common/resources/cellular_setup/final_page.js index e22b03a..176c236 100644 --- a/ash/webui/common/resources/cellular_setup/final_page.js +++ b/ash/webui/common/resources/cellular_setup/final_page.js
@@ -9,34 +9,48 @@ */ import './base_page.js'; -import {I18nBehavior} from '//resources/ash/common/i18n_behavior.js'; -import {Polymer} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {I18nBehavior, I18nBehaviorInterface} from '//resources/ash/common/i18n_behavior.js'; +import {mixinBehaviors, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {CellularSetupDelegate} from './cellular_setup_delegate.js'; import {getTemplate} from './final_page.html.js'; -Polymer({ - _template: getTemplate(), - is: 'final-page', +/** + * @constructor + * @extends {PolymerElement} + * @implements {I18nBehaviorInterface} + */ +const FinalPageElementBase = mixinBehaviors([I18nBehavior], PolymerElement); - behaviors: [I18nBehavior], +/** @polymer */ +export class FinalPageElement extends FinalPageElementBase { + static get is() { + return 'final-page'; + } - properties: { - /** @type {!CellularSetupDelegate} */ - delegate: Object, + static get template() { + return getTemplate(); + } - /** - * Whether error state should be shown. - * @type {boolean} - */ - showError: Boolean, + static get properties() { + return { + /** @type {!CellularSetupDelegate} */ + delegate: Object, - /** @type {string} */ - message: String, + /** + * Whether error state should be shown. + * @type {boolean} + */ + showError: Boolean, - /** @type {string} */ - errorMessage: String, - }, + /** @type {string} */ + message: String, + + /** @type {string} */ + errorMessage: String, + + }; + } /** * @param {boolean} showError @@ -49,7 +63,7 @@ this.i18n('finalPageTitle'); } return null; - }, + } /** * @param {boolean} showError @@ -58,7 +72,7 @@ */ getMessage_(showError) { return showError ? this.errorMessage : this.message; - }, + } /** * @param {boolean} showError @@ -67,7 +81,7 @@ */ getPageBodyClass_(showError) { return showError ? 'error' : ''; - }, + } /** * @param {boolean} showError @@ -77,5 +91,7 @@ getJellyIllustrationName_(showError) { return showError ? 'cellular-setup-illo:error' : 'cellular-setup-illo:final-page-success'; - }, -}); + } +} + +customElements.define(FinalPageElement.is, FinalPageElement);
diff --git a/ash/webui/common/resources/cellular_setup/profile_discovery_consent_page.js b/ash/webui/common/resources/cellular_setup/profile_discovery_consent_page.js index 4826192..c181b8f 100644 --- a/ash/webui/common/resources/cellular_setup/profile_discovery_consent_page.js +++ b/ash/webui/common/resources/cellular_setup/profile_discovery_consent_page.js
@@ -14,23 +14,39 @@ import '//resources/polymer/v3_0/iron-flex-layout/iron-flex-layout-classes.js'; import './base_page.js'; -import {I18nBehavior} from '//resources/ash/common/i18n_behavior.js'; -import {Polymer} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {I18nBehavior, I18nBehaviorInterface} from '//resources/ash/common/i18n_behavior.js'; +import {mixinBehaviors, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {getTemplate} from './profile_discovery_consent_page.html.js'; -Polymer({ - _template: getTemplate(), - is: 'profile-discovery-consent-page', +/** + * @constructor + * @extends {PolymerElement} + * @implements {I18nBehaviorInterface} + */ +const ProfileDiscoveryConsentPageElementBase = + mixinBehaviors([I18nBehavior], PolymerElement); - behaviors: [I18nBehavior], +/** @polymer */ +class ProfileDiscoveryConsentPageElement extends + ProfileDiscoveryConsentPageElementBase { + static get is() { + return 'profile-discovery-consent-page'; + } - properties: { - shouldSkipDiscovery: { - type: Boolean, - notify: true, - }, - }, + static get template() { + return getTemplate(); + } + + static get properties() { + return { + shouldSkipDiscovery: { + type: Boolean, + notify: true, + }, + + }; + } shouldSkipDiscoveryClicked_(e) { // A place holder href with the value "#" is used to have a compliant link. @@ -38,6 +54,12 @@ e.detail.event.preventDefault(); e.stopPropagation(); this.shouldSkipDiscovery = true; - this.fire('forward-navigation-requested'); - }, -}); + this.dispatchEvent(new CustomEvent('forward-navigation-requested', { + bubbles: true, + composed: true, + })); + } +} + +customElements.define( + ProfileDiscoveryConsentPageElement.is, ProfileDiscoveryConsentPageElement);
diff --git a/ash/webui/common/resources/cellular_setup/profile_discovery_list_item.js b/ash/webui/common/resources/cellular_setup/profile_discovery_list_item.js index 52bf1795..faab397 100644 --- a/ash/webui/common/resources/cellular_setup/profile_discovery_list_item.js +++ b/ash/webui/common/resources/cellular_setup/profile_discovery_list_item.js
@@ -15,43 +15,59 @@ import '//resources/polymer/v3_0/paper-spinner/paper-spinner-lite.js'; import './cellular_setup_icons.html.js'; -import {I18nBehavior} from '//resources/ash/common/i18n_behavior.js'; -import {Polymer} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {I18nBehavior, I18nBehaviorInterface} from '//resources/ash/common/i18n_behavior.js'; +import {mixinBehaviors, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {mojoString16ToString} from 'chrome://resources/js/mojo_type_util.js'; import {ESimProfileProperties} from 'chrome://resources/mojo/chromeos/ash/services/cellular_setup/public/mojom/esim_manager.mojom-webui.js'; import {getTemplate} from './profile_discovery_list_item.html.js'; -Polymer({ - _template: getTemplate(), - is: 'profile-discovery-list-item', +/** + * @constructor + * @extends {PolymerElement} + * @implements {I18nBehaviorInterface} + */ +const ProfileDiscoveryListItemElementBase = + mixinBehaviors([I18nBehavior], PolymerElement); - behaviors: [I18nBehavior], +/** @polymer */ +class ProfileDiscoveryListItemElement extends + ProfileDiscoveryListItemElementBase { + static get is() { + return 'profile-discovery-list-item'; + } - properties: { - /** - * @type {?ESimProfileProperties} - */ - profileProperties: { - type: Object, - value: null, - notify: true, - }, + static get template() { + return getTemplate(); + } - selected: { - type: Boolean, - reflectToAttribute: true, - }, + static get properties() { + return { + /** + * @type {?ESimProfileProperties} + */ + profileProperties: { + type: Object, + value: null, + notify: true, + }, - /** - * @type {boolean} - * @private - */ - isDarkModeActive_: { - type: Boolean, - value: false, - }, - }, + selected: { + type: Boolean, + reflectToAttribute: true, + }, + + /** + * @type {boolean} + * @private + */ + isDarkModeActive_: { + type: Boolean, + value: false, + }, + + }; + } /** @private */ getProfileName_() { @@ -59,5 +75,8 @@ return ''; } return mojoString16ToString(this.profileProperties.name); - }, -}); + } +} + +customElements.define( + ProfileDiscoveryListItemElement.is, ProfileDiscoveryListItemElement);
diff --git a/ash/webui/common/resources/cellular_setup/profile_discovery_list_item_legacy.js b/ash/webui/common/resources/cellular_setup/profile_discovery_list_item_legacy.js index 6ebb7528..1cdb38b 100644 --- a/ash/webui/common/resources/cellular_setup/profile_discovery_list_item_legacy.js +++ b/ash/webui/common/resources/cellular_setup/profile_discovery_list_item_legacy.js
@@ -15,55 +15,69 @@ import '//resources/polymer/v3_0/paper-spinner/paper-spinner-lite.js'; import './cellular_setup_icons.html.js'; -import {I18nBehavior} from '//resources/ash/common/i18n_behavior.js'; -import {Polymer} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {I18nBehavior, I18nBehaviorInterface} from '//resources/ash/common/i18n_behavior.js'; +import {mixinBehaviors, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {mojoString16ToString} from 'chrome://resources/js/mojo_type_util.js'; import {ESimProfileProperties, ESimProfileRemote} from 'chrome://resources/mojo/chromeos/ash/services/cellular_setup/public/mojom/esim_manager.mojom-webui.js'; import {getTemplate} from './profile_discovery_list_item_legacy.html.js'; -Polymer({ - _template: getTemplate(), - is: 'profile-discovery-list-item-legacy', +/** + * @constructor + * @extends {PolymerElement} + * @implements {I18nBehaviorInterface} + */ +const ProfileDiscoveryListItemLegacyElementBase = + mixinBehaviors([I18nBehavior], PolymerElement); - behaviors: [I18nBehavior], +/** @polymer */ +class ProfileDiscoveryListItemLegacyElement extends + ProfileDiscoveryListItemLegacyElementBase { + static get is() { + return 'profile-discovery-list-item-legacy'; + } - properties: { - /** @type {?ESimProfileRemote} */ - profile: { - type: Object, - value: null, - observer: 'onProfileChanged_', - }, + static get template() { + return getTemplate(); + } - selected: { - type: Boolean, - reflectToAttribute: true, - }, + static get properties() { + return { + /** @type {?ESimProfileRemote} */ + profile: { + type: Object, + value: null, + observer: 'onProfileChanged_', + }, - showLoadingIndicator: { - type: Boolean, - }, + selected: { + type: Boolean, + reflectToAttribute: true, + }, - /** - * @type {?ESimProfileProperties} - * @private - */ - profileProperties_: { - type: Object, - value: null, - notify: true, - }, + showLoadingIndicator: Boolean, - /** - * @type {boolean} - * @private - */ - isDarkModeActive_: { - type: Boolean, - value: false, - }, - }, + /** + * @type {?ESimProfileProperties} + * @private + */ + profileProperties_: { + type: Object, + value: null, + notify: true, + }, + + /** + * @type {boolean} + * @private + */ + isDarkModeActive_: { + type: Boolean, + value: false, + }, + + }; + } /** @private */ onProfileChanged_() { @@ -74,7 +88,7 @@ this.profile.getProperties().then(response => { this.profileProperties_ = response.properties; }); - }, + } /** @private */ getProfileName_() { @@ -82,5 +96,9 @@ return ''; } return mojoString16ToString(this.profileProperties_.name); - }, -}); + } +} + +customElements.define( + ProfileDiscoveryListItemLegacyElement.is, + ProfileDiscoveryListItemLegacyElement);
diff --git a/ash/webui/common/resources/cellular_setup/profile_discovery_list_page.js b/ash/webui/common/resources/cellular_setup/profile_discovery_list_page.js index 047ea241..41f99f1 100644 --- a/ash/webui/common/resources/cellular_setup/profile_discovery_list_page.js +++ b/ash/webui/common/resources/cellular_setup/profile_discovery_list_page.js
@@ -13,36 +13,50 @@ import './base_page.js'; import './profile_discovery_list_item.js'; -import {I18nBehavior} from '//resources/ash/common/i18n_behavior.js'; -import {Polymer} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {I18nBehavior, I18nBehaviorInterface} from '//resources/ash/common/i18n_behavior.js'; +import {mixinBehaviors, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {ESimProfileProperties} from 'chrome://resources/mojo/chromeos/ash/services/cellular_setup/public/mojom/esim_manager.mojom-webui.js'; import {getTemplate} from './profile_discovery_list_page.html.js'; -Polymer({ - _template: getTemplate(), - is: 'profile-discovery-list-page', +/** + * @constructor + * @extends {PolymerElement} + * @implements {I18nBehaviorInterface} + */ +const ProfileDiscoveryListPageElementBase = + mixinBehaviors([I18nBehavior], PolymerElement); - behaviors: [I18nBehavior], +/** @polymer */ +class ProfileDiscoveryListPageElement extends + ProfileDiscoveryListPageElementBase { + static get is() { + return 'profile-discovery-list-page'; + } - properties: { - /** - * @type {Array<!ESimProfileProperties>} - * @private - */ - pendingProfileProperties: { - type: Array, - }, + static get template() { + return getTemplate(); + } - /** - * @type {?ESimProfileProperties} - * @private - */ - selectedProfileProperties: { - type: Object, - notify: true, - }, - }, + static get properties() { + return { + /** + * @type {Array<!ESimProfileProperties>} + * @private + */ + pendingProfileProperties: Array, + + /** + * @type {?ESimProfileProperties} + * @private + */ + selectedProfileProperties: { + type: Object, + notify: true, + }, + + }; + } /** * @param {ESimProfileProperties} profileProperties @@ -50,7 +64,7 @@ */ isProfilePropertiesSelected_(profileProperties) { return this.selectedProfileProperties === profileProperties; - }, + } /** * @param {Event} e @@ -60,6 +74,12 @@ e.detail.event.preventDefault(); e.stopPropagation(); this.selectedProfileProperties = null; - this.fire('forward-navigation-requested'); - }, -}); + this.dispatchEvent(new CustomEvent('forward-navigation-requested', { + bubbles: true, + composed: true, + })); + } +} + +customElements.define( + ProfileDiscoveryListPageElement.is, ProfileDiscoveryListPageElement);
diff --git a/ash/webui/common/resources/cellular_setup/profile_discovery_list_page_legacy.js b/ash/webui/common/resources/cellular_setup/profile_discovery_list_page_legacy.js index a575939e..d52ead21 100644 --- a/ash/webui/common/resources/cellular_setup/profile_discovery_list_page_legacy.js +++ b/ash/webui/common/resources/cellular_setup/profile_discovery_list_page_legacy.js
@@ -12,44 +12,59 @@ import './base_page.js'; import './profile_discovery_list_item_legacy.js'; -import {I18nBehavior} from '//resources/ash/common/i18n_behavior.js'; -import {Polymer} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {I18nBehavior, I18nBehaviorInterface} from '//resources/ash/common/i18n_behavior.js'; +import {mixinBehaviors, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {ESimProfileRemote} from 'chrome://resources/mojo/chromeos/ash/services/cellular_setup/public/mojom/esim_manager.mojom-webui.js'; import {getTemplate} from './profile_discovery_list_page_legacy.html.js'; -Polymer({ - _template: getTemplate(), - is: 'profile-discovery-list-page-legacy', +/** + * @constructor + * @extends {PolymerElement} + * @implements {I18nBehaviorInterface} + */ +const ProfileDiscoveryListPageLegacyElementBase = + mixinBehaviors([I18nBehavior], PolymerElement); - behaviors: [I18nBehavior], +/** @polymer */ +class ProfileDiscoveryListPageLegacyElement extends + ProfileDiscoveryListPageLegacyElementBase { + static get is() { + return 'profile-discovery-list-page-legacy'; + } - properties: { - /** - * @type {Array<!ESimProfileRemote>} - * @private - */ - pendingProfiles: { - type: Array, - }, + static get template() { + return getTemplate(); + } - /** - * @type {?ESimProfileRemote} - * @private - */ - selectedProfile: { - type: Object, - notify: true, - }, + static get properties() { + return { + /** + * @type {Array<!ESimProfileRemote>} + * @private + */ + pendingProfiles: Array, - /** - * Indicates the UI is busy with an operation and cannot be interacted with. - */ - showBusy: { - type: Boolean, - value: false, - }, - }, + /** + * @type {?ESimProfileRemote} + * @private + */ + selectedProfile: { + type: Object, + notify: true, + }, + + /** + * Indicates the UI is busy with an operation and cannot be interacted + * with. + */ + showBusy: { + type: Boolean, + value: false, + }, + + }; + } /** * @param {ESimProfileRemote} profile @@ -57,5 +72,9 @@ */ isProfileSelected_(profile) { return this.selectedProfile === profile; - }, -}); + } +} + +customElements.define( + ProfileDiscoveryListPageLegacyElement.is, + ProfileDiscoveryListPageLegacyElement);
diff --git a/ash/webui/common/resources/cellular_setup/provisioning_page.js b/ash/webui/common/resources/cellular_setup/provisioning_page.js index aa734518..ede18e9d 100644 --- a/ash/webui/common/resources/cellular_setup/provisioning_page.js +++ b/ash/webui/common/resources/cellular_setup/provisioning_page.js
@@ -13,64 +13,79 @@ import '//resources/polymer/v3_0/iron-flex-layout/iron-flex-layout-classes.js'; import '//resources/polymer/v3_0/paper-spinner/paper-spinner-lite.js'; -import {I18nBehavior} from '//resources/ash/common/i18n_behavior.js'; import {assert} from '//resources/ash/common/assert.js'; -import {Polymer} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {I18nBehavior, I18nBehaviorInterface} from '//resources/ash/common/i18n_behavior.js'; +import {mixinBehaviors, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {CellularMetadata} from 'chrome://resources/mojo/chromeos/ash/services/cellular_setup/public/mojom/cellular_setup.mojom-webui.js'; import {CellularSetupDelegate} from './cellular_setup_delegate.js'; import {getTemplate} from './provisioning_page.html.js'; import {postDeviceDataToWebview} from './webview_post_util.js'; -Polymer({ - _template: getTemplate(), - is: 'provisioning-page', +/** + * @constructor + * @extends {PolymerElement} + * @implements {I18nBehaviorInterface} + */ +const ProvisioningPageElementBase = + mixinBehaviors([I18nBehavior], PolymerElement); - behaviors: [I18nBehavior], +/** @polymer */ +export class ProvisioningPageElement extends ProvisioningPageElementBase { + static get is() { + return 'provisioning-page'; + } - properties: { - /** @type {!CellularSetupDelegate} */ - delegate: Object, + static get template() { + return getTemplate(); + } - /** - * Whether error state should be shown. - * @type {boolean} - */ - showError: { - type: Boolean, - value: false, - notify: true, - }, + static get properties() { + return { + /** @type {!CellularSetupDelegate} */ + delegate: Object, - /** - * Metadata used to open carrier provisioning portal. Expected to start as - * null, then change to a valid object. - * @type {?CellularMetadata} - */ - cellularMetadata: { - type: Object, - value: null, - observer: 'onCellularMetadataChanged_', - }, + /** + * Whether error state should be shown. + * @type {boolean} + */ + showError: { + type: Boolean, + value: false, + notify: true, + }, - /** - * Whether the carrier portal has completed being loaded. - * @private {boolean} - */ - hasCarrierPortalLoaded_: { - type: Boolean, - value: false, - }, + /** + * Metadata used to open carrier provisioning portal. Expected to start as + * null, then change to a valid object. + * @type {?CellularMetadata} + */ + cellularMetadata: { + type: Object, + value: null, + observer: 'onCellularMetadataChanged_', + }, - /** - * The last carrier name provided via |cellularMetadata|. - * @private {string} - */ - carrierName_: { - type: String, - value: '', - }, - }, + /** + * Whether the carrier portal has completed being loaded. + * @private {boolean} + */ + hasCarrierPortalLoaded_: { + type: Boolean, + value: false, + }, + + /** + * The last carrier name provided via |cellularMetadata|. + * @private {string} + */ + carrierName_: { + type: String, + value: '', + }, + + }; + } /** * @return {?string} @@ -87,7 +102,7 @@ return this.i18n('provisioningPageActiveTitle'); } return this.i18n('provisioningPageLoadingTitle', this.carrierName_); - }, + } /** * @return {?string} @@ -98,7 +113,7 @@ return this.i18n('provisioningPageErrorMessage', this.carrierName_); } return null; - }, + } /** * @return {boolean} @@ -106,7 +121,7 @@ */ shouldShowSpinner_() { return !this.showError && !this.hasCarrierPortalLoaded_; - }, + } /** * @return {boolean} @@ -114,15 +129,15 @@ */ shouldShowPortal_() { return !this.showError && this.hasCarrierPortalLoaded_; - }, + } /** * @return {?WebView} * @private */ getPortalWebview() { - return /** @type {?WebView} */ (this.$$('webview')); - }, + return /** @type {?WebView} */ (this.shadowRoot.querySelector('webview')); + } /** @private */ onCellularMetadataChanged_() { @@ -136,7 +151,7 @@ // If |cellularMetadata| is now null, the page should be reset so that a new // attempt can begin. this.resetPage_(); - }, + } /** @private */ loadPortal_() { @@ -165,7 +180,7 @@ // Otherwise, use a normal GET request by specifying the "src". portalWebview.src = this.cellularMetadata.paymentUrl.url; - }, + } /** @private */ resetPage_() { @@ -176,12 +191,12 @@ if (portalWebview) { portalWebview.remove(); } - }, + } /** @private */ onPortalLoadAbort_(event) { this.showError = true; - }, + } /** @private */ onPortalLoadStop_() { @@ -190,13 +205,14 @@ } this.hasCarrierPortalLoaded_ = true; - this.fire('carrier-portal-loaded'); + this.dispatchEvent(new CustomEvent( + 'carrier-portal-loaded', {bubbles: true, composed: true})); // When the portal loads, it expects to receive a message from this frame // alerting it that loading has completed successfully. this.getPortalWebview().contentWindow.postMessage( {msg: 'loadedInWebview'}, this.cellularMetadata.paymentUrl.url); - }, + } /** * @param {!Event} event @@ -223,8 +239,12 @@ // The <webview> provided an update on the status of the activation attempt. if (messageType === 'reportTransactionStatusMsg') { const success = status === 'ok'; - this.fire('on-carrier-portal-result', success); + this.dispatchEvent(new CustomEvent( + 'on-carrier-portal-result', + {bubbles: true, composed: true, detail: success})); return; } - }, -}); + } +} + +customElements.define(ProvisioningPageElement.is, ProvisioningPageElement);
diff --git a/ash/webui/common/resources/cellular_setup/psim_flow_ui.js b/ash/webui/common/resources/cellular_setup/psim_flow_ui.js index 0c23cb5..7f794fb 100644 --- a/ash/webui/common/resources/cellular_setup/psim_flow_ui.js +++ b/ash/webui/common/resources/cellular_setup/psim_flow_ui.js
@@ -7,15 +7,18 @@ import './final_page.js'; import '//resources/polymer/v3_0/iron-pages/iron-pages.js'; -import {I18nBehavior} from '//resources/ash/common/i18n_behavior.js'; import {assert, assertNotReached} from '//resources/ash/common/assert.js'; -import {Polymer} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {I18nBehavior, I18nBehaviorInterface} from '//resources/ash/common/i18n_behavior.js'; +import {mixinBehaviors, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {ActivationDelegateInterface, ActivationDelegateReceiver, ActivationResult, CarrierPortalHandlerRemote, CarrierPortalStatus, CellularMetadata, CellularSetup_StartActivation_ResponseParams, CellularSetupRemote} from 'chrome://resources/mojo/chromeos/ash/services/cellular_setup/public/mojom/cellular_setup.mojom-webui.js'; import {CellularSetupDelegate} from './cellular_setup_delegate.js'; import {ButtonState} from './cellular_types.js'; +import {FinalPageElement} from './final_page.js'; import {getCellularSetupRemote} from './mojo_interface_provider.js'; +import {ProvisioningPageElement} from './provisioning_page.js'; import {getTemplate} from './psim_flow_ui.html.js'; +import {SetupLoadingPageElement} from './setup_loading_page.js'; import {SubflowBehavior} from './subflow_behavior.js'; /** @enum {string} */ @@ -106,152 +109,161 @@ * contains navigation buttons and sub-pages corresponding to each step of the * flow. */ -Polymer({ - _template: getTemplate(), - is: 'psim-flow-ui', - behaviors: [ - I18nBehavior, - SubflowBehavior, - ], +/** + * @constructor + * @extends {PolymerElement} + * @implements {I18nBehaviorInterface} + */ +const PsimFlowUiElementBase = + mixinBehaviors([I18nBehavior, SubflowBehavior], PolymerElement); - properties: { - /** @type {!CellularSetupDelegate} */ - delegate: Object, +/** @polymer */ +export class PsimFlowUiElement extends PsimFlowUiElementBase { + static get is() { + return 'psim-flow-ui'; + } + + static get template() { + return getTemplate(); + } + + static get properties() { + return { + /** @type {!CellularSetupDelegate} */ + delegate: Object, + + /** + * Carrier name; used in dialog title to show the current carrier + * name being setup + * @type {string} + */ + nameOfCarrierPendingSetup: { + type: String, + notify: true, + computed: 'getCarrierText(' + + 'selectedPSimPageName_, cellularMetadata_.*)', + }, + + forwardButtonLabel: { + type: String, + notify: true, + }, + + /** + * @type {!PSimUIState} + * @private + */ + state_: { + type: String, + value: PSimUIState.IDLE, + observer: 'handlePSimUIStateChange_', + }, + + /** + * Element name of the current selected sub-page. + * @type {!PSimPageName} + * @private + */ + selectedPSimPageName_: { + type: String, + value: PSimPageName.SIM_DETECT, + notify: true, + }, + + /** + * DOM Element for the current selected sub-page. + * @private {!SetupLoadingPageElement|!ProvisioningPageElement| + * !FinalPageElement} + */ + selectedPage_: Object, + + /** + * Whether error state should be shown for the current page. + * @private {boolean} + */ + showError_: {type: Boolean, value: false}, + + /** + * Cellular metadata received via the onActivationStarted() callback. If + * that callback has not occurred, this field is null. + * @private {?CellularMetadata} + */ + cellularMetadata_: { + type: Object, + value: null, + }, + + /** + * The current number of tries to detect the SIM. + * @private {number} + */ + startActivationAttempts_: { + type: Number, + value: 0, + }, + + }; + } + + /** @override */ + constructor() { + super(); /** - * Carrier name; used in dialog title to show the current carrier - * name being setup - * @type {string} + * Provides an interface to the CellularSetup Mojo service. + * @private {?CellularSetupRemote} */ - nameOfCarrierPendingSetup: { - type: String, - notify: true, - computed: 'getCarrierText(' + - 'selectedPSimPageName_, cellularMetadata_.*)', - }, - - forwardButtonLabel: { - type: String, - notify: true, - }, + this.cellularSetupRemote_ = getCellularSetupRemote(); /** - * @type {!PSimUIState} - * @private + * Delegate responsible for routing activation started/finished events. + * @private {?ActivationDelegateReceiver} */ - state_: { - type: String, - value: PSimUIState.IDLE, - }, + this.activationDelegateReceiver_ = null; /** - * Element name of the current selected sub-page. - * @type {!PSimPageName} - * @private + * The timeout ID corresponding to a timeout for the current state. If no + * timeout is active, this value is null. + * @private {?number} */ - selectedPSimPageName_: { - type: String, - value: PSimPageName.SIM_DETECT, - notify: true, - }, + this.currentTimeoutId_ = null; /** - * DOM Element for the current selected sub-page. - * @private {!SetupLoadingPageElement|!ProvisioningPageElement| - * !FinalPageElement} + * Handler used to communicate state updates back to the CellularSetup + * service. + * @private {?CarrierPortalHandlerRemote} */ - selectedPage_: Object, + this.carrierPortalHandler_ = null; /** - * Whether error state should be shown for the current page. + * Whether there was a carrier portal error. * @private {boolean} */ - showError_: {type: Boolean, value: false}, + this.didCarrierPortalResultFail_ = false; /** - * Cellular metadata received via the onActivationStarted() callback. If - * that callback has not occurred, this field is null. - * @private {?CellularMetadata} + * The function used to initiate a timer. Can be overwritten in tests. + * @private {function(Function, number)} */ - cellularMetadata_: { - type: Object, - value: null, - }, + this.setTimeoutFunction_ = setTimeout.bind(window); + } + + /** @override */ + connectedCallback() { + super.connectedCallback(); /** - * The current number of tries to detect the SIM. - * @private {number} + * The time at which the PSim flow is attached. + * @private {?Date} */ - startActivationAttempts_: { - type: Number, - value: 0, - }, - }, - - observers: [ - 'updateShowError_(state_)', - 'updateSelectedPage_(state_)', - 'handlePSimUIStateChange_(state_)', - 'updateButtonBarState_(state_)', - ], - - /** - * Provides an interface to the CellularSetup Mojo service. - * @private {?CellularSetupRemote} - */ - cellularSetupRemote_: null, - - /** - * Delegate responsible for routing activation started/finished events. - * @private {?ActivationDelegateReceiver} - */ - activationDelegateReceiver_: null, - - /** - * The timeout ID corresponding to a timeout for the current state. If no - * timeout is active, this value is null. - * @private {?number} - */ - currentTimeoutId_: null, - - /** - * Handler used to communicate state updates back to the CellularSetup - * service. - * @private {?CarrierPortalHandlerRemote} - */ - carrierPortalHandler_: null, - - /** - * Whether there was a carrier portal error. - * @private {boolean} - */ - didCarrierPortalResultFail_: false, - - /** - * The function used to initiate a timer. Can be overwritten in tests. - * @private {function(Function, number)} - */ - setTimeoutFunction_: setTimeout.bind(window), - - /** - * The time at which the PSim flow is attached. - * @private {?Date} - */ - timeOnAttached_: null, - - /** @override */ - created() { - this.cellularSetupRemote_ = getCellularSetupRemote(); - }, - - /** @override */ - attached() { this.timeOnAttached_ = new Date(); - }, + } /** @override */ - detached() { + disconnectedCallback() { + super.disconnectedCallback(); + let resultCode = null; switch (this.state_) { case PSimUIState.IDLE: @@ -303,7 +315,7 @@ chrome.metricsPrivate.recordLongTime( FAILED_PSIM_SETUP_DURATION_METRIC_NAME, elapsedTimeMs); - }, + } /** * Overrides ActivationDelegateInterface. @@ -314,14 +326,15 @@ this.clearTimer_(); this.cellularMetadata_ = metadata; this.state_ = PSimUIState.WAITING_FOR_PORTAL_TO_LOAD; - }, + } initSubflow() { this.state_ = PSimUIState.STARTING_ACTIVATION; this.startActivationAttempts_ = 0; this.updateButtonBarState_(); - this.fire('focus-default-button'); - }, + this.dispatchEvent(new CustomEvent( + 'focus-default-button', {bubbles: true, composed: true})); + } navigateForward() { switch (this.state_) { @@ -335,7 +348,8 @@ case PSimUIState.TIMEOUT_FINISH_ACTIVATION: case PSimUIState.FINAL_TIMEOUT_START_ACTIVATION: case PSimUIState.ALREADY_ACTIVATED: - this.fire('exit-cellular-setup'); + this.dispatchEvent(new CustomEvent( + 'exit-cellular-setup', {bubbles: true, composed: true})); break; case PSimUIState.TIMEOUT_START_ACTIVATION: this.state_ = PSimUIState.STARTING_ACTIVATION; @@ -344,7 +358,7 @@ assertNotReached(); break; } - }, + } /** * Sets the function used to initiate a timer. @@ -353,7 +367,7 @@ */ setTimerFunctionForTest(timerFunction) { this.setTimeoutFunction_ = timerFunction; - }, + } /** @private */ updateButtonBarState_() { @@ -411,7 +425,7 @@ assertNotReached(); } this.set('buttonState', buttonState); - }, + } /** * Overrides ActivationDelegateInterface. @@ -434,7 +448,7 @@ default: assertNotReached(); } - }, + } /** @private */ getCarrierText() { @@ -443,7 +457,7 @@ return this.cellularMetadata_.carrier; } return ''; - }, + } /** @private */ updateShowError_() { @@ -457,7 +471,7 @@ this.showError_ = false; return; } - }, + } /** @private */ updateSelectedPage_() { @@ -484,10 +498,13 @@ default: assertNotReached(); } - }, + } /** @private */ handlePSimUIStateChange_() { + this.updateShowError_(); + this.updateSelectedPage_(); + // Since the state has changed, the previous state did not time out, so // clear any active timeout. this.clearTimer_(); @@ -501,9 +518,10 @@ if (this.state_ === PSimUIState.STARTING_ACTIVATION) { this.startActivation_(); - return; } - }, + + this.updateButtonBarState_(); + } /** @private */ onTimeout_() { @@ -529,7 +547,7 @@ // Only the above states are expected to time out. assertNotReached(); } - }, + } /** @private */ startActivation_() { @@ -550,7 +568,7 @@ (params) => { this.carrierPortalHandler_ = params.observer; }); - }, + } /** @private */ closeActivationConnection_() { @@ -559,7 +577,7 @@ this.activationDelegateReceiver_ = null; this.carrierPortalHandler_ = null; this.cellularMetadata_ = null; - }, + } /** @private */ clearTimer_() { @@ -567,14 +585,14 @@ clearTimeout(this.currentTimeoutId_); } this.currentTimeoutId_ = null; - }, + } /** @private */ onCarrierPortalLoaded_() { this.state_ = PSimUIState.WAITING_FOR_USER_PAYMENT; this.carrierPortalHandler_.onCarrierPortalStatusChange( CarrierPortalStatus.kPortalLoadedWithoutPaidUser); - }, + } /** * @param {!CustomEvent<boolean>} event @@ -585,7 +603,7 @@ this.didCarrierPortalResultFail_ = !success; this.state_ = success ? PSimUIState.ACTIVATION_SUCCESS : PSimUIState.ACTIVATION_FAILURE; - }, + } /** @return {string} */ getLoadingMessage_() { @@ -595,13 +613,13 @@ return this.i18n('simDetectPageFinalErrorMessage'); } return this.i18n('establishNetworkConnectionMessage'); - }, + } /** @return {boolean} */ isSimDetectError_() { return this.state_ === PSimUIState.TIMEOUT_START_ACTIVATION || this.state_ === PSimUIState.FINAL_TIMEOUT_START_ACTIVATION; - }, + } /** @return {string} */ getLoadingTitle_() { @@ -609,5 +627,7 @@ return this.i18n('simDetectPageErrorTitle'); } return ''; - }, -}); + } +} + +customElements.define(PsimFlowUiElement.is, PsimFlowUiElement);
diff --git a/ash/webui/common/resources/cellular_setup/setup_loading_page.js b/ash/webui/common/resources/cellular_setup/setup_loading_page.js index e6e95163..f39beb80 100644 --- a/ash/webui/common/resources/cellular_setup/setup_loading_page.js +++ b/ash/webui/common/resources/cellular_setup/setup_loading_page.js
@@ -12,42 +12,57 @@ import 'chrome://resources/cros_components/lottie_renderer/lottie-renderer.js'; import '//resources/polymer/v3_0/iron-media-query/iron-media-query.js'; -import {I18nBehavior} from '//resources/ash/common/i18n_behavior.js'; -import {Polymer} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {I18nBehavior, I18nBehaviorInterface} from '//resources/ash/common/i18n_behavior.js'; +import {mixinBehaviors, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {getTemplate} from './setup_loading_page.html.js'; -Polymer({ - _template: getTemplate(), - is: 'setup-loading-page', +/** + * @constructor + * @extends {PolymerElement} + * @implements {I18nBehaviorInterface} + */ +const SetupLoadingPageElementBase = + mixinBehaviors([I18nBehavior], PolymerElement); - behaviors: [I18nBehavior], +/** @polymer */ +export class SetupLoadingPageElement extends SetupLoadingPageElementBase { + static get is() { + return 'setup-loading-page'; + } - properties: { - /** - * Message displayed with spinner when in LOADING state. - */ - loadingMessage: { - type: String, - value: '', - }, + static get template() { + return getTemplate(); + } - /** - * Title for page if needed. - * @type {?string} - */ - loadingTitle: { - type: Object, - value: '', - }, + static get properties() { + return { + /** + * Message displayed with spinner when in LOADING state. + */ + loadingMessage: { + type: String, + value: '', + }, - /** - * Displays a sim detect error graphic if true. - */ - isSimDetectError: { - type: Boolean, - value: false, - }, + /** + * Title for page if needed. + * @type {?string} + */ + loadingTitle: { + type: Object, + value: '', + }, - }, -}); + /** + * Displays a sim detect error graphic if true. + */ + isSimDetectError: { + type: Boolean, + value: false, + }, + }; + } +} + +customElements.define(SetupLoadingPageElement.is, SetupLoadingPageElement);
diff --git a/ash/webui/common/resources/cr_elements/BUILD.gn b/ash/webui/common/resources/cr_elements/BUILD.gn index 7f15643..e5928df 100644 --- a/ash/webui/common/resources/cr_elements/BUILD.gn +++ b/ash/webui/common/resources/cr_elements/BUILD.gn
@@ -23,6 +23,11 @@ "cr_toast/cr_toast_manager.ts", ] + non_web_component_files = [ + "cr_container_shadow_mixin.ts", + "i18n_mixin.ts", + ] + icons_html_files = [ "icons.html" ] css_files = [
diff --git a/ash/webui/common/resources/cr_elements/cr_container_shadow_mixin.ts b/ash/webui/common/resources/cr_elements/cr_container_shadow_mixin.ts new file mode 100644 index 0000000..2345da11 --- /dev/null +++ b/ash/webui/common/resources/cr_elements/cr_container_shadow_mixin.ts
@@ -0,0 +1,174 @@ +// Copyright 2017 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview CrContainerShadowMixin holds logic for showing a drop shadow + * near the top of a container element, when the content has scrolled. + * + * Forked from ui/webui/resources/cr_elements/cr_container_shadow_mixin.ts + * + * Elements using this mixin are expected to define a #container element, + * which is the element being scrolled. If the #container element has a + * show-bottom-shadow attribute, a drop shadow will also be shown near the + * bottom of the container element, when there is additional content to scroll + * to. Examples: + * + * For both top and bottom shadows: + * <div id="container" show-bottom-shadow>...</div> + * + * For top shadow only: + * <div id="container">...</div> + * + * The mixin will take care of inserting an element with ID + * 'cr-container-shadow-top' which holds the drop shadow effect, and, + * optionally, an element with ID 'cr-container-shadow-bottom' which holds the + * same effect. A 'has-shadow' CSS class is automatically added to/removed from + * both elements while scrolling, as necessary. Note that the show-bottom-shadow + * attribute is inspected only during attached(), and any changes to it that + * occur after that point will not be respected. + * + * Clients should either use the existing shared styling in + * cr_shared_style.css, '#cr-container-shadow-[top/bottom]' and + * '#cr-container-shadow-[top/bottom].has-shadow', or define their own styles. + */ + +import {assert} from '//resources/js/assert.js'; +import {dedupingMixin, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; + +export enum CrContainerShadowSide { + TOP = 'top', + BOTTOM = 'bottom', +} + +type Constructor<T> = new (...args: any[]) => T; + +export const CrContainerShadowMixin = dedupingMixin( + <T extends Constructor<PolymerElement>>(superClass: T): T& + Constructor<CrContainerShadowMixinInterface> => { + class CrContainerShadowMixin extends superClass implements + CrContainerShadowMixinInterface { + private intersectionObserver_: IntersectionObserver|null = null; + private dropShadows_: Map<CrContainerShadowSide, HTMLDivElement> = + new Map(); + private intersectionProbes_: + Map<CrContainerShadowSide, HTMLDivElement> = new Map(); + private sides_: CrContainerShadowSide[]|null = null; + + override connectedCallback() { + super.connectedCallback(); + + const hasBottomShadow = + this.getContainer_().hasAttribute('show-bottom-shadow'); + this.sides_ = hasBottomShadow ? + [CrContainerShadowSide.TOP, CrContainerShadowSide.BOTTOM] : + [CrContainerShadowSide.TOP]; + this.sides_!.forEach(side => { + // The element holding the drop shadow effect to be shown. + const shadow = document.createElement('div'); + shadow.id = `cr-container-shadow-${side}`; + shadow.classList.add('cr-container-shadow'); + this.dropShadows_.set(side, shadow); + this.intersectionProbes_.set(side, document.createElement('div')); + }); + + this.getContainer_().parentNode!.insertBefore( + this.dropShadows_.get(CrContainerShadowSide.TOP)!, + this.getContainer_()); + this.getContainer_().prepend( + this.intersectionProbes_.get(CrContainerShadowSide.TOP)!); + + if (hasBottomShadow) { + this.getContainer_().parentNode!.insertBefore( + this.dropShadows_.get(CrContainerShadowSide.BOTTOM)!, + this.getContainer_().nextSibling); + this.getContainer_().append( + this.intersectionProbes_.get(CrContainerShadowSide.BOTTOM)!); + } + + this.enableShadowBehavior(true); + } + + override disconnectedCallback() { + super.disconnectedCallback(); + + this.enableShadowBehavior(false); + } + + private getContainer_(): HTMLElement { + return this.shadowRoot!.querySelector('#container')!; + } + + private getIntersectionObserver_(): IntersectionObserver { + const callback = (entries: IntersectionObserverEntry[]) => { + // In some rare cases, there could be more than one entry per + // observed element, in which case the last entry's result + // stands. + for (const entry of entries) { + const target = entry.target; + this.sides_!.forEach(side => { + if (target === this.intersectionProbes_.get(side)) { + this.dropShadows_.get(side)!.classList.toggle( + 'has-shadow', entry.intersectionRatio === 0); + } + }); + } + }; + return new IntersectionObserver( + callback, {root: this.getContainer_(), threshold: 0}); + } + + /** + * @param enable Whether to enable the mixin or disable it. + * This function does nothing if the mixin is already in the + * requested state. + */ + enableShadowBehavior(enable: boolean) { + // Behavior is already enabled/disabled. Return early. + if (enable === !!this.intersectionObserver_) { + return; + } + + if (!enable) { + this.intersectionObserver_!.disconnect(); + this.intersectionObserver_ = null; + return; + } + + this.intersectionObserver_ = this.getIntersectionObserver_(); + + // Need to register the observer within a setTimeout() callback, + // otherwise the drop shadow flashes once on startup, because of the + // DOM modifications earlier in this function causing a relayout. + window.setTimeout(() => { + if (this.intersectionObserver_) { + // In case this is already detached. + this.intersectionProbes_.forEach(probe => { + this.intersectionObserver_!.observe(probe); + }); + } + }); + } + + /** + * Shows the shadows. The shadow mixin must be disabled before + * calling this method, otherwise the intersection observer might + * show the shadows again. + */ + showDropShadows() { + assert(!this.intersectionObserver_); + assert(this.sides_); + for (const side of this.sides_) { + this.dropShadows_.get(side)!.classList.toggle('has-shadow', true); + } + } + } + + return CrContainerShadowMixin; + }); + +export interface CrContainerShadowMixinInterface { + enableShadowBehavior(enable: boolean): void; + + showDropShadows(): void; +}
diff --git a/ash/webui/common/resources/cr_elements/cr_dialog/cr_dialog.ts b/ash/webui/common/resources/cr_elements/cr_dialog/cr_dialog.ts index e45ec87..22a1aaddb 100644 --- a/ash/webui/common/resources/cr_elements/cr_dialog/cr_dialog.ts +++ b/ash/webui/common/resources/cr_elements/cr_dialog/cr_dialog.ts
@@ -26,10 +26,10 @@ import '../cr_hidden_style.css.js'; import '../cr_shared_vars.css.js'; -import {CrContainerShadowMixin} from '//resources/cr_elements/cr_container_shadow_mixin.js'; import {assert} from '//resources/js/assert.js'; import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {CrContainerShadowMixin} from '../cr_container_shadow_mixin.js'; import {CrIconButtonElement} from '../cr_icon_button/cr_icon_button.js'; import {CrInputElement} from '../cr_input/cr_input.js';
diff --git a/ash/webui/common/resources/cr_elements/i18n_mixin.ts b/ash/webui/common/resources/cr_elements/i18n_mixin.ts new file mode 100644 index 0000000..ef93dca --- /dev/null +++ b/ash/webui/common/resources/cr_elements/i18n_mixin.ts
@@ -0,0 +1,120 @@ +// 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. + +/** + * @fileoverview + * 'I18nMixin' is a Mixin offering loading of internationalization + * strings. Typically it is used as [[i18n('someString')]] computed bindings or + * for this.i18n('foo'). It is not needed for HTML $i18n{otherString}, which is + * handled by a C++ templatizer. + * + * Forked from ui/webui/resources/cr_elements/i18n_mixin.ts + */ + +import {loadTimeData} from '//resources/js/load_time_data.js'; +import {parseHtmlSubset, sanitizeInnerHtml, SanitizeInnerHtmlOpts} from '//resources/js/parse_html_subset.js'; +import {dedupingMixin, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; + +type Constructor<T> = new (...args: any[]) => T; + +export const I18nMixin = dedupingMixin( + <T extends Constructor<PolymerElement>>(superClass: T): T& + Constructor<I18nMixinInterface> => { + class I18nMixin extends superClass implements I18nMixinInterface { + /** + * Returns a translated string where $1 to $9 are replaced by the given + * values. + * @param id The ID of the string to translate. + * @param varArgs Values to replace the placeholders $1 to $9 in the + * string. + * @return A translated, substituted string. + */ + private i18nRaw_(id: string, ...varArgs: Array<string|number>) { + return varArgs.length === 0 ? loadTimeData.getString(id) : + loadTimeData.getStringF(id, ...varArgs); + } + + /** + * Returns a translated string where $1 to $9 are replaced by the given + * values. Also sanitizes the output to filter out dangerous HTML/JS. + * Use with Polymer bindings that are *not* inner-h-t-m-l. + * NOTE: This is not related to $i18n{foo} in HTML, see file overview. + * @param id The ID of the string to translate. + * @param varArgs Values to replace the placeholders $1 to $9 in the + * string. + * @return A translated, sanitized, substituted string. + */ + i18n(id: string, ...varArgs: Array<string|number>) { + const rawString = this.i18nRaw_(id, ...varArgs); + return parseHtmlSubset(`<b>${rawString}</b>`).firstChild!.textContent! + ; + } + + /** + * Similar to 'i18n', returns a translated, sanitized, substituted + * string. It receives the string ID and a dictionary containing the + * substitutions as well as optional additional allowed tags and + * attributes. Use with Polymer bindings that are inner-h-t-m-l, for + * example. + * @param id The ID of the string to translate. + */ + i18nAdvanced(id: string, opts?: SanitizeInnerHtmlOpts) { + opts = opts || {}; + const rawString = this.i18nRaw_(id, ...(opts.substitutions || [])); + return sanitizeInnerHtml(rawString, opts); + } + + /** + * Similar to 'i18n', with an unused |locale| parameter used to trigger + * updates when the locale changes. + * @param locale The UI language used. + * @param id The ID of the string to translate. + * @param varArgs Values to replace the placeholders $1 to $9 in the + * string. + * @return A translated, sanitized, substituted string. + */ + i18nDynamic(_locale: string, id: string, ...varArgs: string[]) { + return this.i18n(id, ...varArgs); + } + + /** + * Similar to 'i18nDynamic', but varArgs valus are interpreted as keys + * in loadTimeData. This allows generation of strings that take other + * localized strings as parameters. + * @param locale The UI language used. + * @param id The ID of the string to translate. + * @param varArgs Values to replace the placeholders $1 to $9 + * in the string. Values are interpreted as strings IDs if found in + * the list of localized strings. + * @return A translated, sanitized, substituted string. + */ + i18nRecursive(locale: string, id: string, ...varArgs: string[]) { + let args = varArgs; + if (args.length > 0) { + // Try to replace IDs with localized values. + args = args.map(str => { + return this.i18nExists(str) ? loadTimeData.getString(str) : str; + }); + } + return this.i18nDynamic(locale, id, ...args); + } + + /** + * Returns true if a translation exists for |id|. + */ + i18nExists(id: string) { + return loadTimeData.valueExists(id); + } + } + + return I18nMixin; + }); + +export interface I18nMixinInterface { + i18n(id: string, ...varArgs: Array<string|number>): string; + i18nAdvanced(id: string, opts?: SanitizeInnerHtmlOpts): TrustedHTML; + i18nDynamic(locale: string, id: string, ...varArgs: string[]): string; + i18nRecursive(locale: string, id: string, ...varArgs: string[]): string; + i18nExists(id: string): boolean; +}
diff --git a/ash/webui/common/resources/network/apn_list.d.ts b/ash/webui/common/resources/network/apn_list.d.ts index 93b4d72..e3fb920 100644 --- a/ash/webui/common/resources/network/apn_list.d.ts +++ b/ash/webui/common/resources/network/apn_list.d.ts
@@ -4,6 +4,7 @@ import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {ManagedCellularProperties} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/cros_network_config.mojom-webui.js'; +import {PortalState} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/network_types.mojom-webui.js'; export class ApnList extends PolymerElement { static get is(): string; @@ -24,6 +25,9 @@ value: boolean, }, }; + errorState: string; + portalState: PortalState; + shouldOmitLinks: boolean; openApnDetailDialogInCreateMode(): void; private getApns_; private isConnectedApnAutoDetected_: boolean;
diff --git a/ash/webui/common/resources/network/network_property_list_mojo.d.ts b/ash/webui/common/resources/network/network_property_list_mojo.d.ts index 0756f69..66265d0 100644 --- a/ash/webui/common/resources/network/network_property_list_mojo.d.ts +++ b/ash/webui/common/resources/network/network_property_list_mojo.d.ts
@@ -6,6 +6,7 @@ interface NetworkPropertyListMojoElement extends LegacyElementMixin, HTMLElement { + disabled: boolean; fields: string[]; }
diff --git a/ash/webui/common/resources/network/network_siminfo.d.ts b/ash/webui/common/resources/network/network_siminfo.d.ts index 358c7d1b..bb0033c0 100644 --- a/ash/webui/common/resources/network/network_siminfo.d.ts +++ b/ash/webui/common/resources/network/network_siminfo.d.ts
@@ -7,6 +7,7 @@ import {LegacyElementMixin} from 'chrome://resources/polymer/v3_0/polymer/lib/legacy/legacy-element-mixin.js'; interface NetworkSiminfoElement extends LegacyElementMixin, HTMLElement { + disabled: boolean; getUnlockButton(): CrButtonElement|null; getSimLockToggle(): CrToggleElement|null; }
diff --git a/ash/webui/scanning/resources/BUILD.gn b/ash/webui/scanning/resources/BUILD.gn index 5d1ce0e..be2246c 100644 --- a/ash/webui/scanning/resources/BUILD.gn +++ b/ash/webui/scanning/resources/BUILD.gn
@@ -80,7 +80,6 @@ "//ash/webui/common/resources/cr_elements: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", ]
diff --git a/ash/webui/scanning/resources/action_toolbar.ts b/ash/webui/scanning/resources/action_toolbar.ts index 57c870d..6e5574d 100644 --- a/ash/webui/scanning/resources/action_toolbar.ts +++ b/ash/webui/scanning/resources/action_toolbar.ts
@@ -7,7 +7,7 @@ import 'chrome://resources/ash/common/cr_elements/cr_icon_button/cr_icon_button.js'; import {assert} from 'chrome://resources/ash/common/assert.js'; -import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js'; +import {I18nMixin} from 'chrome://resources/ash/common/cr_elements/i18n_mixin.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {getTemplate} from './action_toolbar.html.js';
diff --git a/ash/webui/scanning/resources/color_mode_select.ts b/ash/webui/scanning/resources/color_mode_select.ts index 9cf71c1..4d76c7a 100644 --- a/ash/webui/scanning/resources/color_mode_select.ts +++ b/ash/webui/scanning/resources/color_mode_select.ts
@@ -6,7 +6,7 @@ import './strings.m.js'; import {assert} from 'chrome://resources/ash/common/assert.js'; -import {I18nMixin, I18nMixinInterface} from 'chrome://resources/cr_elements/i18n_mixin.js'; +import {I18nMixin, I18nMixinInterface} from 'chrome://resources/ash/common/cr_elements/i18n_mixin.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {getTemplate} from './color_mode_select.html.js';
diff --git a/ash/webui/scanning/resources/file_type_select.ts b/ash/webui/scanning/resources/file_type_select.ts index c96ee66c..72603c5 100644 --- a/ash/webui/scanning/resources/file_type_select.ts +++ b/ash/webui/scanning/resources/file_type_select.ts
@@ -5,7 +5,7 @@ import './scan_settings_section.js'; import './strings.m.js'; -import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js'; +import {I18nMixin} from 'chrome://resources/ash/common/cr_elements/i18n_mixin.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {getTemplate} from './file_type_select.html.js';
diff --git a/ash/webui/scanning/resources/loading_page.ts b/ash/webui/scanning/resources/loading_page.ts index 2973172..95f08e4 100644 --- a/ash/webui/scanning/resources/loading_page.ts +++ b/ash/webui/scanning/resources/loading_page.ts
@@ -7,8 +7,8 @@ import 'chrome://resources/polymer/v3_0/paper-progress/paper-progress.js'; import './strings.m.js'; +import {I18nMixin} from 'chrome://resources/ash/common/cr_elements/i18n_mixin.js'; import {loadTimeData} from 'chrome://resources/ash/common/load_time_data.m.js'; -import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {getTemplate} from './loading_page.html.js';
diff --git a/ash/webui/scanning/resources/multi_page_checkbox.ts b/ash/webui/scanning/resources/multi_page_checkbox.ts index eadd70a..6d4d5a8 100644 --- a/ash/webui/scanning/resources/multi_page_checkbox.ts +++ b/ash/webui/scanning/resources/multi_page_checkbox.ts
@@ -6,7 +6,7 @@ import './scan_settings_section.js'; import './strings.m.js'; -import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js'; +import {I18nMixin} from 'chrome://resources/ash/common/cr_elements/i18n_mixin.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {getTemplate} from './multi_page_checkbox.html.js';
diff --git a/ash/webui/scanning/resources/multi_page_scan.ts b/ash/webui/scanning/resources/multi_page_scan.ts index 1cfb854..79468091 100644 --- a/ash/webui/scanning/resources/multi_page_scan.ts +++ b/ash/webui/scanning/resources/multi_page_scan.ts
@@ -7,7 +7,7 @@ import './scanning_fonts.css.js'; import './strings.m.js'; -import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js'; +import {I18nMixin} from 'chrome://resources/ash/common/cr_elements/i18n_mixin.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {getTemplate} from './multi_page_scan.html.js';
diff --git a/ash/webui/scanning/resources/page_size_select.ts b/ash/webui/scanning/resources/page_size_select.ts index 935e7115..59fce8b 100644 --- a/ash/webui/scanning/resources/page_size_select.ts +++ b/ash/webui/scanning/resources/page_size_select.ts
@@ -6,7 +6,7 @@ import './strings.m.js'; import {assert} from 'chrome://resources/ash/common/assert.js'; -import {I18nMixin, I18nMixinInterface} from 'chrome://resources/cr_elements/i18n_mixin.js'; +import {I18nMixin, I18nMixinInterface} from 'chrome://resources/ash/common/cr_elements/i18n_mixin.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {getTemplate} from './page_size_select.html.js';
diff --git a/ash/webui/scanning/resources/resolution_select.ts b/ash/webui/scanning/resources/resolution_select.ts index 6f2fc9ef..3b6f482 100644 --- a/ash/webui/scanning/resources/resolution_select.ts +++ b/ash/webui/scanning/resources/resolution_select.ts
@@ -6,7 +6,7 @@ import './strings.m.js'; import {assert} from 'chrome://resources/ash/common/assert.js'; -import {I18nMixin, I18nMixinInterface} from 'chrome://resources/cr_elements/i18n_mixin.js'; +import {I18nMixin, I18nMixinInterface} from 'chrome://resources/ash/common/cr_elements/i18n_mixin.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {getTemplate} from './resolution_select.html.js';
diff --git a/ash/webui/scanning/resources/scan_done_section.ts b/ash/webui/scanning/resources/scan_done_section.ts index 4cf14e7..4e47fd14 100644 --- a/ash/webui/scanning/resources/scan_done_section.ts +++ b/ash/webui/scanning/resources/scan_done_section.ts
@@ -9,9 +9,9 @@ import './strings.m.js'; import {assert} from 'chrome://resources/ash/common/assert.js'; +import {I18nMixin} from 'chrome://resources/ash/common/cr_elements/i18n_mixin.js'; import {loadTimeData} from 'chrome://resources/ash/common/load_time_data.m.js'; import {strictQuery} from 'chrome://resources/ash/common/typescript_utils/strict_query.js'; -import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js'; import {sanitizeInnerHtml} from 'chrome://resources/js/parse_html_subset.js'; import {FilePath} from 'chrome://resources/mojo/mojo/public/mojom/base/file_path.mojom-webui.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
diff --git a/ash/webui/scanning/resources/scan_preview.ts b/ash/webui/scanning/resources/scan_preview.ts index 1b22288..bad596c7 100644 --- a/ash/webui/scanning/resources/scan_preview.ts +++ b/ash/webui/scanning/resources/scan_preview.ts
@@ -13,8 +13,8 @@ import {assert} from 'chrome://resources/ash/common/assert.js'; import {CrButtonElement} from 'chrome://resources/ash/common/cr_elements/cr_button/cr_button.js'; import {CrDialogElement} from 'chrome://resources/ash/common/cr_elements/cr_dialog/cr_dialog.js'; +import {I18nMixin} from 'chrome://resources/ash/common/cr_elements/i18n_mixin.js'; import {loadTimeData} from 'chrome://resources/ash/common/load_time_data.m.js'; -import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js'; import {DomRepeatEvent, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {ForceHiddenElementsVisibleObserverInterface, ForceHiddenElementsVisibleObserverReceiver} from './accessibility_features.mojom-webui.js';
diff --git a/ash/webui/scanning/resources/scan_to_select.ts b/ash/webui/scanning/resources/scan_to_select.ts index 2d4efe07..28f23bf5 100644 --- a/ash/webui/scanning/resources/scan_to_select.ts +++ b/ash/webui/scanning/resources/scan_to_select.ts
@@ -5,8 +5,8 @@ import './scan_settings_section.js'; import './strings.m.js'; +import {I18nMixin, I18nMixinInterface} from 'chrome://resources/ash/common/cr_elements/i18n_mixin.js'; import {strictQuery} from 'chrome://resources/ash/common/typescript_utils/strict_query.js'; -import {I18nMixin, I18nMixinInterface} from 'chrome://resources/cr_elements/i18n_mixin.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {getTemplate} from './scan_to_select.html.js';
diff --git a/ash/webui/scanning/resources/scanner_select.ts b/ash/webui/scanning/resources/scanner_select.ts index 62bc0353..4dfdb564 100644 --- a/ash/webui/scanning/resources/scanner_select.ts +++ b/ash/webui/scanning/resources/scanner_select.ts
@@ -8,8 +8,8 @@ import './scan_settings_section.js'; import './strings.m.js'; +import {I18nMixin, I18nMixinInterface} from 'chrome://resources/ash/common/cr_elements/i18n_mixin.js'; import {strictQuery} from 'chrome://resources/ash/common/typescript_utils/strict_query.js'; -import {I18nMixin, I18nMixinInterface} from 'chrome://resources/cr_elements/i18n_mixin.js'; import {afterNextRender, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {getTemplate} from './scanner_select.html.js';
diff --git a/ash/webui/scanning/resources/scanning_app.ts b/ash/webui/scanning/resources/scanning_app.ts index 7e5b6e4..62c6b3c 100644 --- a/ash/webui/scanning/resources/scanning_app.ts +++ b/ash/webui/scanning/resources/scanning_app.ts
@@ -30,13 +30,13 @@ import {assert} from 'chrome://resources/ash/common/assert.js'; import {CrButtonElement} from 'chrome://resources/ash/common/cr_elements/cr_button/cr_button.js'; +import {CrContainerShadowMixin, CrContainerShadowMixinInterface} from 'chrome://resources/ash/common/cr_elements/cr_container_shadow_mixin.js'; import {CrDialogElement} from 'chrome://resources/ash/common/cr_elements/cr_dialog/cr_dialog.js'; import {CrToastElement} from 'chrome://resources/ash/common/cr_elements/cr_toast/cr_toast.js'; +import {I18nMixin, I18nMixinInterface} from 'chrome://resources/ash/common/cr_elements/i18n_mixin.js'; import {loadTimeData} from 'chrome://resources/ash/common/load_time_data.m.js'; import {strictQuery} from 'chrome://resources/ash/common/typescript_utils/strict_query.js'; import {ColorChangeUpdater} from 'chrome://resources/cr_components/color_change_listener/colors_css_updater.js'; -import {CrContainerShadowMixin, CrContainerShadowMixinInterface} from 'chrome://resources/cr_elements/cr_container_shadow_mixin.js'; -import {I18nMixin, I18nMixinInterface} from 'chrome://resources/cr_elements/i18n_mixin.js'; import {FilePath} from 'chrome://resources/mojo/mojo/public/mojom/base/file_path.mojom-webui.js'; import {UnguessableToken} from 'chrome://resources/mojo/mojo/public/mojom/base/unguessable_token.mojom-webui.js'; import {IronCollapseElement} from 'chrome://resources/polymer/v3_0/iron-collapse/iron-collapse.js';
diff --git a/ash/webui/scanning/resources/source_select.ts b/ash/webui/scanning/resources/source_select.ts index 0c68cd9e..9d15bf7 100644 --- a/ash/webui/scanning/resources/source_select.ts +++ b/ash/webui/scanning/resources/source_select.ts
@@ -6,7 +6,7 @@ import './strings.m.js'; import {assert} from 'chrome://resources/ash/common/assert.js'; -import {I18nMixin, I18nMixinInterface} from 'chrome://resources/cr_elements/i18n_mixin.js'; +import {I18nMixin, I18nMixinInterface} from 'chrome://resources/ash/common/cr_elements/i18n_mixin.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {ScanSource, SourceType} from './scanning.mojom-webui.js';
diff --git a/ash/webui/shortcut_customization_ui/backend/BUILD.gn b/ash/webui/shortcut_customization_ui/backend/BUILD.gn index 0e0f298..98f2b34 100644 --- a/ash/webui/shortcut_customization_ui/backend/BUILD.gn +++ b/ash/webui/shortcut_customization_ui/backend/BUILD.gn
@@ -20,6 +20,8 @@ "search/search_concept_registry.h", "search/search_handler.cc", "search/search_handler.h", + "text_accelerator_part.cc", + "text_accelerator_part.h", ] deps = [
diff --git a/ash/webui/shortcut_customization_ui/backend/accelerator_layout_table.cc b/ash/webui/shortcut_customization_ui/backend/accelerator_layout_table.cc index 90103649..b360c5cd 100644 --- a/ash/webui/shortcut_customization_ui/backend/accelerator_layout_table.cc +++ b/ash/webui/shortcut_customization_ui/backend/accelerator_layout_table.cc
@@ -25,57 +25,6 @@ namespace ash { -namespace { - -std::u16string GetTextForModifier(ui::EventFlags modifier) { - switch (modifier) { - case ui::EF_SHIFT_DOWN: - return u"shift"; - case ui::EF_CONTROL_DOWN: - return u"ctrl"; - case ui::EF_ALT_DOWN: - return u"alt"; - case ui::EF_COMMAND_DOWN: - return u"meta"; - } - NOTREACHED(); - return std::u16string(); -} - -std::u16string GetTextForDelimiter(TextAcceleratorDelimiter delimiter) { - // Note: Use a switch statement to perform string lookup if/when more - // delimiters are added to the TextAcceleratorDelimiter enum. - CHECK_EQ(delimiter, TextAcceleratorDelimiter::kPlusSign); - return u"+"; -} - -} // namespace - -TextAcceleratorPart::TextAcceleratorPart(ui::EventFlags modifier) { - text = GetTextForModifier(modifier); - type = mojom::TextAcceleratorPartType::kModifier; -} - -TextAcceleratorPart::TextAcceleratorPart(ui::KeyboardCode key_code) { - type = mojom::TextAcceleratorPartType::kKey; - keycode = key_code; -} - -TextAcceleratorPart::TextAcceleratorPart(const std::u16string& plain_text) { - text = plain_text; - type = mojom::TextAcceleratorPartType::kPlainText; -} - -TextAcceleratorPart::TextAcceleratorPart(TextAcceleratorDelimiter delimiter) { - text = GetTextForDelimiter(delimiter); - type = mojom::TextAcceleratorPartType::kDelimiter; -} - -TextAcceleratorPart::TextAcceleratorPart(const TextAcceleratorPart&) = default; -TextAcceleratorPart::~TextAcceleratorPart() = default; -TextAcceleratorPart& TextAcceleratorPart::operator=( - const TextAcceleratorPart&) = default; - // Constructor used for text-based layout accelerators. NonConfigurableAcceleratorDetails::NonConfigurableAcceleratorDetails( int message_id,
diff --git a/ash/webui/shortcut_customization_ui/backend/accelerator_layout_table.h b/ash/webui/shortcut_customization_ui/backend/accelerator_layout_table.h index c314198..f38def8 100644 --- a/ash/webui/shortcut_customization_ui/backend/accelerator_layout_table.h +++ b/ash/webui/shortcut_customization_ui/backend/accelerator_layout_table.h
@@ -14,6 +14,7 @@ #include "ash/public/cpp/accelerators.h" #include "ash/public/mojom/accelerator_info.mojom.h" #include "ash/strings/grit/ash_strings.h" +#include "ash/webui/shortcut_customization_ui/backend/text_accelerator_part.h" #include "base/containers/fixed_flat_set.h" #include "ui/base/accelerators/accelerator.h" #include "ui/events/event_constants.h" @@ -157,11 +158,6 @@ kAmbientMoveToEndOfWord, }; -// Used to separate text accelerator parts in the UI e.g ctrl + 1. -enum TextAcceleratorDelimiter { - kPlusSign, -}; - // Contains details for UI styling of an accelerator. struct AcceleratorLayoutDetails { // The accelerator action id associated for a source. Concat `source` and @@ -189,25 +185,6 @@ mojom::AcceleratorSource source; }; -// Represents a replacement for part of a non-configurable accelerator. -// Contains the text to display as well as its type (Modifier, Key, Plain Text) -// which is needed to determine how to display the text in the shortcut -// customization app. -class TextAcceleratorPart : public mojom::TextAcceleratorPart { - public: - explicit TextAcceleratorPart(ui::EventFlags modifier); - explicit TextAcceleratorPart(ui::KeyboardCode key_code); - explicit TextAcceleratorPart(const std::u16string& plain_text); - explicit TextAcceleratorPart(TextAcceleratorDelimiter delimiter); - TextAcceleratorPart(const TextAcceleratorPart&); - TextAcceleratorPart& operator=(const TextAcceleratorPart&); - ~TextAcceleratorPart(); - - // If the part is a keycode, we store it so that we will always have a way - // to get the accurate localized key string to display. - std::optional<ui::KeyboardCode> keycode; -}; - // Contains info related to a non-configurable accelerator. A non-configurable // accelerator can contain either a standard or text-based accelerator. The // message_id and list of replacements will be provided when dealing
diff --git a/ash/webui/shortcut_customization_ui/backend/text_accelerator_part.cc b/ash/webui/shortcut_customization_ui/backend/text_accelerator_part.cc new file mode 100644 index 0000000..0a015bd --- /dev/null +++ b/ash/webui/shortcut_customization_ui/backend/text_accelerator_part.cc
@@ -0,0 +1,61 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/webui/shortcut_customization_ui/backend/text_accelerator_part.h" + +#include <optional> +#include <string> + +namespace ash { + +namespace { +std::u16string GetTextForModifier(ui::EventFlags modifier) { + switch (modifier) { + case ui::EF_SHIFT_DOWN: + return u"shift"; + case ui::EF_CONTROL_DOWN: + return u"ctrl"; + case ui::EF_ALT_DOWN: + return u"alt"; + case ui::EF_COMMAND_DOWN: + return u"meta"; + } + NOTREACHED(); + return std::u16string(); +} + +std::u16string GetTextForDelimiter(TextAcceleratorDelimiter delimiter) { + // Note: Use a switch statement to perform string lookup if/when more + // delimiters are added to the TextAcceleratorDelimiter enum. + CHECK_EQ(delimiter, TextAcceleratorDelimiter::kPlusSign); + return u"+"; +} +} // namespace + +TextAcceleratorPart::TextAcceleratorPart(ui::EventFlags modifier) { + text = GetTextForModifier(modifier); + type = mojom::TextAcceleratorPartType::kModifier; +} + +TextAcceleratorPart::TextAcceleratorPart(ui::KeyboardCode key_code) { + type = mojom::TextAcceleratorPartType::kKey; + keycode = key_code; +} + +TextAcceleratorPart::TextAcceleratorPart(const std::u16string& plain_text) { + text = plain_text; + type = mojom::TextAcceleratorPartType::kPlainText; +} + +TextAcceleratorPart::TextAcceleratorPart(TextAcceleratorDelimiter delimiter) { + text = GetTextForDelimiter(delimiter); + type = mojom::TextAcceleratorPartType::kDelimiter; +} + +TextAcceleratorPart::TextAcceleratorPart(const TextAcceleratorPart&) = default; +TextAcceleratorPart::~TextAcceleratorPart() = default; +TextAcceleratorPart& TextAcceleratorPart::operator=( + const TextAcceleratorPart&) = default; + +} // namespace ash
diff --git a/ash/webui/shortcut_customization_ui/backend/text_accelerator_part.h b/ash/webui/shortcut_customization_ui/backend/text_accelerator_part.h new file mode 100644 index 0000000..939be29 --- /dev/null +++ b/ash/webui/shortcut_customization_ui/backend/text_accelerator_part.h
@@ -0,0 +1,43 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_WEBUI_SHORTCUT_CUSTOMIZATION_UI_BACKEND_TEXT_ACCELERATOR_PART_H_ +#define ASH_WEBUI_SHORTCUT_CUSTOMIZATION_UI_BACKEND_TEXT_ACCELERATOR_PART_H_ + +#include <cstdint> +#include <optional> +#include <string> + +#include "ash/public/mojom/accelerator_info.mojom.h" +#include "ui/events/event_constants.h" + +namespace ash { + +// Used to separate text accelerator parts in the UI e.g ctrl + 1. +enum TextAcceleratorDelimiter { + kPlusSign, +}; + +// Represents a replacement for part of a non-configurable accelerator. +// Contains the text to display as well as its type (Modifier, Key, Plain Text) +// which is needed to determine how to display the text in the shortcut +// customization app. +class TextAcceleratorPart : public mojom::TextAcceleratorPart { + public: + explicit TextAcceleratorPart(ui::EventFlags modifier); + explicit TextAcceleratorPart(ui::KeyboardCode key_code); + explicit TextAcceleratorPart(const std::u16string& plain_text); + explicit TextAcceleratorPart(TextAcceleratorDelimiter delimiter); + TextAcceleratorPart(const TextAcceleratorPart&); + TextAcceleratorPart& operator=(const TextAcceleratorPart&); + ~TextAcceleratorPart(); + + // If the part is a keycode, we store it so that we will always have a way + // to get the accurate localized key string to display. + std::optional<ui::KeyboardCode> keycode; +}; + +} // namespace ash + +#endif // ASH_WEBUI_SHORTCUT_CUSTOMIZATION_UI_BACKEND_TEXT_ACCELERATOR_PART_H_
diff --git a/ash/wm/overview/glanceables/glanceables_bar_view.cc b/ash/wm/overview/birch/birch_bar_view.cc similarity index 76% rename from ash/wm/overview/glanceables/glanceables_bar_view.cc rename to ash/wm/overview/birch/birch_bar_view.cc index a94f7bf6..35b41e8 100644 --- a/ash/wm/overview/glanceables/glanceables_bar_view.cc +++ b/ash/wm/overview/birch/birch_bar_view.cc
@@ -1,8 +1,8 @@ -// Copyright 2023 The Chromium Authors +// Copyright 2024 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/wm/overview/glanceables/glanceables_bar_view.h" +#include "ash/wm/overview/birch/birch_bar_view.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/resources/vector_icons/vector_icons.h" @@ -39,15 +39,14 @@ } // namespace //------------------------------------------------------------------------------ -// GlanceablesBarView::GlanceablesChipsContainer -// The chips container with glanceables chips and hiding chips button. -class GlanceablesBarView::GlanceablesChipsContainer - : public views::BoxLayoutView { - METADATA_HEADER(GlanceablesChipsContainer, views::BoxLayoutView) +// BirchBarView::BirchChipsContainer +// The chips container with birch chips and hiding chips button. +class BirchBarView::BirchChipsContainer : public views::BoxLayoutView { + METADATA_HEADER(BirchChipsContainer, views::BoxLayoutView) public: - explicit GlanceablesChipsContainer(GlanceablesBarView* glanceable_bar) - : glanceable_bar_(glanceable_bar) { + explicit BirchChipsContainer(BirchBarView* birch_bar) + : birch_bar_(birch_bar) { SetPaintToLayer(); layer()->SetFillsBoundsOpaquely(false); SetOrientation(views::BoxLayout::Orientation::kHorizontal); @@ -55,21 +54,20 @@ SetCrossAxisAlignment(views::BoxLayout::CrossAxisAlignment::kCenter); SetBetweenChildSpacing(kChipSpacing); hide_chips_button_ = AddChildView(std::make_unique<IconButton>( - base::BindRepeating(&GlanceablesBarView::OnShowHideChipsButtonPressed, - base::Unretained(glanceable_bar_), /*show=*/false), + base::BindRepeating(&BirchBarView::OnShowHideChipsButtonPressed, + base::Unretained(birch_bar_), /*show=*/false), IconButton::Type::kMedium, &kChevronDownIcon, u"Hide", false, false)); hide_chips_button_->SetProperty(views::kMarginsKey, kHideButtonMargin); hide_chips_button_->SetEnableBlurredBackgroundShield(true); } - GlanceablesChipsContainer(const GlanceablesChipsContainer&) = delete; - GlanceablesChipsContainer& operator=(const GlanceablesChipsContainer&) = - delete; - ~GlanceablesChipsContainer() override = default; + BirchChipsContainer(const BirchChipsContainer&) = delete; + BirchChipsContainer& operator=(const BirchChipsContainer&) = delete; + ~BirchChipsContainer() override = default; - void AddChip(std::unique_ptr<GlanceablesChipButton> chip) { + void AddChip(std::unique_ptr<BirchChipButton> chip) { if (static_cast<int>(chips_.size()) == kMaxChipsNum) { - NOTREACHED() << "The number of glanceable chips reaches the limit of 4"; + NOTREACHED() << "The number of birch chips reaches the limit of 4"; return; } const size_t child_num = children().size(); @@ -78,7 +76,7 @@ chips_.push_back(AddChildViewAt(std::move(chip), child_num - 1)); } - void RemoveChip(GlanceablesChipButton* chip) { + void RemoveChip(BirchChipButton* chip) { auto iter = base::ranges::find(chips_, chip); if (iter != chips_.end()) { RemoveChildViewT(chip); @@ -88,21 +86,18 @@ } private: - raw_ptr<GlanceablesBarView> glanceable_bar_; - std::vector<raw_ptr<GlanceablesChipButton>> chips_; + raw_ptr<BirchBarView> birch_bar_; + std::vector<raw_ptr<BirchChipButton>> chips_; raw_ptr<IconButton> hide_chips_button_; }; -BEGIN_METADATA(GlanceablesBarView, - GlanceablesChipsContainer, - views::BoxLayoutView) +BEGIN_METADATA(BirchBarView, BirchChipsContainer, views::BoxLayoutView) END_METADATA //------------------------------------------------------------------------------ -// GlanceablesBarView -GlanceablesBarView::GlanceablesBarView() { - chips_container_ = - AddChildView(std::make_unique<GlanceablesChipsContainer>(this)); +// BirchBarView +BirchBarView::BirchBarView() { + chips_container_ = AddChildView(std::make_unique<BirchChipsContainer>(this)); show_chips_button_container_ = AddChildView(std::make_unique<views::View>()); show_chips_button_container_->SetPaintToLayer(); @@ -111,7 +106,7 @@ auto* show_chips_button = show_chips_button_container_->AddChildView(std::make_unique<IconButton>( - base::BindRepeating(&GlanceablesBarView::OnShowHideChipsButtonPressed, + base::BindRepeating(&BirchBarView::OnShowHideChipsButtonPressed, base::Unretained(this), /*show=*/true), IconButton::Type::kMedium, &kChevronUpIcon, u"Show", false, false)); show_chips_button->SetEnableBlurredBackgroundShield(true); @@ -119,10 +114,10 @@ chips_container_->SetVisible(false); } -GlanceablesBarView::~GlanceablesBarView() = default; +BirchBarView::~BirchBarView() = default; -void GlanceablesBarView::ShowWidgetForTesting( - std::unique_ptr<GlanceablesBarView> bar_view) { +void BirchBarView::ShowWidgetForTesting( + std::unique_ptr<BirchBarView> bar_view) { views::Widget::InitParams params; params.type = views::Widget::InitParams::TYPE_POPUP; params.layer_type = ui::LAYER_NOT_DRAWN; @@ -145,7 +140,7 @@ g_widget_for_testing->Show(); } -void GlanceablesBarView::HideWidgetForTesting() { +void BirchBarView::HideWidgetForTesting() { if (g_widget_for_testing) { g_widget_for_testing->CloseWithReason( views::Widget::ClosedReason::kUnspecified); @@ -153,14 +148,14 @@ } } -void GlanceablesBarView::AddChip( +void BirchBarView::AddChip( const ui::ImageModel& icon, const std::u16string& title, const std::u16string& sub_title, views::Button::PressedCallback callback, std::optional<std::u16string> button_title, std::optional<views::Button::PressedCallback> button_callback) { - auto chip = views::Builder<GlanceablesChipButton>() + auto chip = views::Builder<BirchChipButton>() .SetIconImage(icon) .SetTitleText(title) .SetSubtitleText(sub_title) @@ -174,7 +169,7 @@ chips_container_->AddChip(std::move(chip)); } -gfx::Size GlanceablesBarView::CalculatePreferredSize() const { +gfx::Size BirchBarView::CalculatePreferredSize() const { gfx::Size preferred_size; for (views::View* content : children()) { preferred_size.SetToMax(content->GetPreferredSize()); @@ -182,11 +177,11 @@ return gfx::Size(preferred_size.width(), kBarHeight); } -int GlanceablesBarView::GetHeightForWidth(int width) const { +int BirchBarView::GetHeightForWidth(int width) const { return kBarHeight; } -void GlanceablesBarView::Layout() { +void BirchBarView::Layout() { // Centralize the chips container/show button. const gfx::Point center_point = GetContentsBounds().CenterPoint(); for (views::View* content : children()) { @@ -196,11 +191,11 @@ } } -void GlanceablesBarView::RemoveChip(GlanceablesChipButton* chip) { +void BirchBarView::RemoveChip(BirchChipButton* chip) { chips_container_->RemoveChip(chip); } -void GlanceablesBarView::OnAnimationsEnded(bool show) { +void BirchBarView::OnAnimationsEnded(bool show) { // Update contents visibility and opacity on animation completed or aborted. animation_in_progress_ = false; if (show) { @@ -210,7 +205,7 @@ } } -void GlanceablesBarView::OnShowHideChipsButtonPressed(bool show) { +void BirchBarView::OnShowHideChipsButtonPressed(bool show) { if (animation_in_progress_) { return; } @@ -235,7 +230,7 @@ // Setup animations. auto animation_complete_callback = base::BindRepeating( - &GlanceablesBarView::OnAnimationsEnded, base::Unretained(this), show); + &BirchBarView::OnAnimationsEnded, base::Unretained(this), show); views::AnimationBuilder animation_builder; animation_builder.OnEnded(base::OnceClosure(animation_complete_callback)) .OnAborted(base::OnceClosure(animation_complete_callback)) @@ -248,7 +243,7 @@ show ? gfx::Transform() : vertical_shift); } -BEGIN_METADATA(GlanceablesBarView) +BEGIN_METADATA(BirchBarView) END_METADATA } // namespace ash
diff --git a/ash/wm/overview/birch/birch_bar_view.h b/ash/wm/overview/birch/birch_bar_view.h new file mode 100644 index 0000000..ded7da5 --- /dev/null +++ b/ash/wm/overview/birch/birch_bar_view.h
@@ -0,0 +1,74 @@ +// Copyright 2024 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_WM_OVERVIEW_BIRCH_BIRCH_BAR_VIEW_H_ +#define ASH_WM_OVERVIEW_BIRCH_BIRCH_BAR_VIEW_H_ + +#include "ash/wm/overview/birch/birch_chip_button.h" +#include "ui/base/metadata/metadata_header_macros.h" +#include "ui/base/models/image_model.h" +#include "ui/views/controls/button/button.h" +#include "ui/views/view.h" + +namespace ash { + +// The bar container to show/hide birch chips. The birch chips will +// be shown in a row with a hiding chips button at the end. When pressing the +// hiding button, the birch chips will fade out and the showing chips +// button will appear in the center. +class BirchBarView : public views::View, public BirchChipButton::Delegate { + METADATA_HEADER(BirchBarView, views::View) + + public: + // TODO(zxdan): When the data model is implemented, pass in the model to + // generate birch chips. + BirchBarView(); + BirchBarView(const BirchBarView&) = delete; + BirchBarView& operator=(const BirchBarView&) = delete; + ~BirchBarView() override; + + // Note: these are helper functions for test use. + static void ShowWidgetForTesting(std::unique_ptr<BirchBarView> bar_view); + static void HideWidgetForTesting(); + + // Adds a new birch chip to the bar. + // TODO(zxdan): move the function to private when using model and replace the + // arguments with chip data structure. + void AddChip(const ui::ImageModel& icon, + const std::u16string& title, + const std::u16string& sub_title, + views::Button::PressedCallback callback, + std::optional<std::u16string> button_title = std::nullopt, + std::optional<views::Button::PressedCallback> button_callback = + std::nullopt); + + // views::View: + gfx::Size CalculatePreferredSize() const override; + int GetHeightForWidth(int width) const override; + void Layout() override; + + // BirchChipButton::Delegate: + void RemoveChip(BirchChipButton* chip) override; + + private: + class BirchChipsContainer; + + void OnAnimationsEnded(bool show); + void OnShowHideChipsButtonPressed(bool show); + + // The container of the birch chips with the hiding chips button. + raw_ptr<BirchChipsContainer> chips_container_ = nullptr; + // A view contains the show chips button. To sync the scaling and opacity + // animations of the show chips button and its blurred background shield + // (which is stacked below the button's layer during animation), we set the + // button in this container view and animate the container instead of the + // button. + raw_ptr<views::View> show_chips_button_container_ = nullptr; + // Indicating whether there is a showing/hiding animation in progress. + bool animation_in_progress_ = false; +}; + +} // namespace ash + +#endif // ASH_WM_OVERVIEW_BIRCH_BIRCH_BAR_VIEW_H_
diff --git a/ash/wm/overview/glanceables/glanceables_chip_button.cc b/ash/wm/overview/birch/birch_chip_button.cc similarity index 87% rename from ash/wm/overview/glanceables/glanceables_chip_button.cc rename to ash/wm/overview/birch/birch_chip_button.cc index e2a9cb1..97602ecf 100644 --- a/ash/wm/overview/glanceables/glanceables_chip_button.cc +++ b/ash/wm/overview/birch/birch_chip_button.cc
@@ -1,8 +1,8 @@ -// Copyright 2023 The Chromium Authors +// Copyright 2024 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/wm/overview/glanceables/glanceables_chip_button.h" +#include "ash/wm/overview/birch/birch_chip_button.h" #include "ash/strings/grit/ash_strings.h" #include "ash/style/pill_button.h" @@ -57,9 +57,9 @@ } // namespace //------------------------------------------------------------------------------ -// GlanceablesChipButton::RemovalChipMenuController: +// BirchChipButton::RemovalChipMenuController: // The removal chip panel which contains one option to remove the chip. -class GlanceablesChipButton::RemovalChipMenuController +class BirchChipButton::RemovalChipMenuController : public views::ContextMenuController { public: explicit RemovalChipMenuController(ui::SimpleMenuModel::Delegate* delegate) @@ -97,8 +97,8 @@ }; //------------------------------------------------------------------------------ -// GlanceablesChipButton: -GlanceablesChipButton::GlanceablesChipButton() +// BirchChipButton: +BirchChipButton::BirchChipButton() : removal_chip_menu_controller_( std::make_unique<RemovalChipMenuController>(this)) { auto box_layout = std::make_unique<views::BoxLayout>( @@ -123,7 +123,7 @@ kBackgroundColorId, kRoundedCornerRadius)) .SetPreferredSize(kChipSize) // TODO(zxdan): verbalize all the contents in following changes. - .SetAccessibleName(u"Glanceables Chip") + .SetAccessibleName(u"Birch Chip") .AddChildren( // Icon. views::Builder<views::ImageView>().CopyAddressTo(&icon_).SetProperty( @@ -162,35 +162,34 @@ StyleUtil::SetUpFocusRingForView(this); } -GlanceablesChipButton::~GlanceablesChipButton() = default; +BirchChipButton::~BirchChipButton() = default; -void GlanceablesChipButton::SetIconImage(const ui::ImageModel& icon_image) { +void BirchChipButton::SetIconImage(const ui::ImageModel& icon_image) { icon_->SetImage(icon_image); } -void GlanceablesChipButton::SetTitleText(const std::u16string& title) { +void BirchChipButton::SetTitleText(const std::u16string& title) { title_->SetText(title); } -void GlanceablesChipButton::SetSubtitleText(const std::u16string& subtitle) { +void BirchChipButton::SetSubtitleText(const std::u16string& subtitle) { subtitle_->SetText(subtitle); } -void GlanceablesChipButton::SetActionButton( - const std::u16string& label, - views::Button::PressedCallback action) { +void BirchChipButton::SetActionButton(const std::u16string& label, + views::Button::PressedCallback action) { CHECK(!action_button_); box_layout_->set_inside_border_insets(kBorderInsetsWithActionButton); action_button_ = AddChildView(std::make_unique<PillButton>( std::move(action), label, PillButton::Type::kPrimaryWithoutIcon)); } -void GlanceablesChipButton::SetDelegate(Delegate* delegate) { +void BirchChipButton::SetDelegate(Delegate* delegate) { CHECK(!delegate_); delegate_ = delegate; } -void GlanceablesChipButton::OnGestureEvent(ui::GestureEvent* event) { +void BirchChipButton::OnGestureEvent(ui::GestureEvent* event) { if (event->type() == ui::ET_GESTURE_LONG_PRESS) { // Show removal chip panel. gfx::Point screen_location(event->location()); @@ -200,18 +199,18 @@ } } -void GlanceablesChipButton::ExecuteCommand(int command_id, int event_flags) { +void BirchChipButton::ExecuteCommand(int command_id, int event_flags) { // Remove the chip when the option is selected in the removal panel. OnRemoveComponentPressed(); } -void GlanceablesChipButton::OnRemoveComponentPressed() { +void BirchChipButton::OnRemoveComponentPressed() { if (delegate_) { delegate_->RemoveChip(this); } } -BEGIN_METADATA(GlanceablesChipButton, views::Button) +BEGIN_METADATA(BirchChipButton, views::Button) END_METADATA } // namespace ash
diff --git a/ash/wm/overview/glanceables/glanceables_chip_button.h b/ash/wm/overview/birch/birch_chip_button.h similarity index 71% rename from ash/wm/overview/glanceables/glanceables_chip_button.h rename to ash/wm/overview/birch/birch_chip_button.h index 33efafa..3d7e4f4 100644 --- a/ash/wm/overview/glanceables/glanceables_chip_button.h +++ b/ash/wm/overview/birch/birch_chip_button.h
@@ -1,9 +1,9 @@ -// Copyright 2023 The Chromium Authors +// Copyright 2024 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef ASH_WM_OVERVIEW_GLANCEABLES_GLANCEABLES_CHIP_BUTTON_H_ -#define ASH_WM_OVERVIEW_GLANCEABLES_GLANCEABLES_CHIP_BUTTON_H_ +#ifndef ASH_WM_OVERVIEW_BIRCH_BIRCH_CHIP_BUTTON_H_ +#define ASH_WM_OVERVIEW_BIRCH_BIRCH_CHIP_BUTTON_H_ #include "ui/base/metadata/metadata_header_macros.h" #include "ui/base/models/image_model.h" @@ -23,24 +23,24 @@ // A compact view of an app, displaying its icon, name, a brief description, and // an optional call to action. -class GlanceablesChipButton : public views::Button, - public ui::SimpleMenuModel::Delegate { +class BirchChipButton : public views::Button, + public ui::SimpleMenuModel::Delegate { public: - METADATA_HEADER(GlanceablesChipButton); + METADATA_HEADER(BirchChipButton); // The delegate executes the actions when the chip is removed. class Delegate { public: - virtual void RemoveChip(GlanceablesChipButton* chip) = 0; + virtual void RemoveChip(BirchChipButton* chip) = 0; protected: virtual ~Delegate() = default; }; - GlanceablesChipButton(); - GlanceablesChipButton(const GlanceablesChipButton&) = delete; - GlanceablesChipButton& operator=(const GlanceablesChipButton&) = delete; - ~GlanceablesChipButton() override; + BirchChipButton(); + BirchChipButton(const BirchChipButton&) = delete; + BirchChipButton& operator=(const BirchChipButton&) = delete; + ~BirchChipButton() override; // Chip configuration methods. void SetIconImage(const ui::ImageModel& icon_image); @@ -76,11 +76,11 @@ std::unique_ptr<RemovalChipMenuController> removal_chip_menu_controller_; }; -BEGIN_VIEW_BUILDER(/*no export*/, GlanceablesChipButton, views::Button) +BEGIN_VIEW_BUILDER(/*no export*/, BirchChipButton, views::Button) VIEW_BUILDER_PROPERTY(const ui::ImageModel&, IconImage) VIEW_BUILDER_PROPERTY(const std::u16string&, TitleText) VIEW_BUILDER_PROPERTY(const std::u16string&, SubtitleText) -VIEW_BUILDER_PROPERTY(GlanceablesChipButton::Delegate*, Delegate) +VIEW_BUILDER_PROPERTY(BirchChipButton::Delegate*, Delegate) VIEW_BUILDER_METHOD(SetActionButton, const std::u16string&, views::Button::PressedCallback) @@ -88,6 +88,6 @@ } // namespace ash -DEFINE_VIEW_BUILDER(/*no export*/, ash::GlanceablesChipButton) +DEFINE_VIEW_BUILDER(/*no export*/, ash::BirchChipButton) -#endif // ASH_WM_OVERVIEW_GLANCEABLES_GLANCEABLES_CHIP_BUTTON_H_ +#endif // ASH_WM_OVERVIEW_BIRCH_BIRCH_CHIP_BUTTON_H_
diff --git a/ash/wm/overview/glanceables/glanceables_bar_view.h b/ash/wm/overview/glanceables/glanceables_bar_view.h deleted file mode 100644 index c5d2f03..0000000 --- a/ash/wm/overview/glanceables/glanceables_bar_view.h +++ /dev/null
@@ -1,78 +0,0 @@ -// 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 ASH_WM_OVERVIEW_GLANCEABLES_GLANCEABLES_BAR_VIEW_H_ -#define ASH_WM_OVERVIEW_GLANCEABLES_GLANCEABLES_BAR_VIEW_H_ - -#include "ash/wm/overview/glanceables/glanceables_chip_button.h" -#include "ui/base/metadata/metadata_header_macros.h" -#include "ui/base/models/image_model.h" -#include "ui/views/controls/button/button.h" -#include "ui/views/view.h" - -namespace ash { - -class IconButton; - -// The bar container to show/hide glanceable chips. The glanceables chips will -// be shown in a row with a hiding chips button at the end. When pressing the -// hiding button, the glanceables chips will fade out and the showing chips -// button will appear in the center. -class GlanceablesBarView : public views::View, - public GlanceablesChipButton::Delegate { - METADATA_HEADER(GlanceablesBarView, views::View) - - public: - // TODO(zxdan): When the data model is implemented, pass in the model to - // generate glanceable chips. - GlanceablesBarView(); - GlanceablesBarView(const GlanceablesBarView&) = delete; - GlanceablesBarView& operator=(const GlanceablesBarView&) = delete; - ~GlanceablesBarView() override; - - // Note: these are helper functions for test use. - static void ShowWidgetForTesting( - std::unique_ptr<GlanceablesBarView> bar_view); - static void HideWidgetForTesting(); - - // Adds a new glanceable chip to the bar. - // TODO(zxdan): move the function to private when using model and replace the - // arguments with chip data structure. - void AddChip(const ui::ImageModel& icon, - const std::u16string& title, - const std::u16string& sub_title, - views::Button::PressedCallback callback, - std::optional<std::u16string> button_title = std::nullopt, - std::optional<views::Button::PressedCallback> button_callback = - std::nullopt); - - // views::View: - gfx::Size CalculatePreferredSize() const override; - int GetHeightForWidth(int width) const override; - void Layout() override; - - // GlanceablesChipButton::Delegate: - void RemoveChip(GlanceablesChipButton* chip) override; - - private: - class GlanceablesChipsContainer; - - void OnAnimationsEnded(bool show); - void OnShowHideChipsButtonPressed(bool show); - - // The container of the glanceables chips with the hiding chips button. - raw_ptr<GlanceablesChipsContainer> chips_container_ = nullptr; - // A view contains the show chips button. To sync the scaling and opacity - // animations of the show chips button and its blurred background shield - // (which is stacked below the button's layer during animation), we set the - // button in this container view and animate the container instead of the - // button. - raw_ptr<views::View> show_chips_button_container_ = nullptr; - // Indicating whether there is a showing/hiding animation in progress. - bool animation_in_progress_ = false; -}; - -} // namespace ash - -#endif // ASH_WM_OVERVIEW_GLANCEABLES_GLANCEABLES_BAR_VIEW_H_
diff --git a/ash/wm/tablet_mode/tablet_mode_multitask_menu_controller.cc b/ash/wm/tablet_mode/tablet_mode_multitask_menu_controller.cc index 15d6d25..c3dd9be2 100644 --- a/ash/wm/tablet_mode/tablet_mode_multitask_menu_controller.cc +++ b/ash/wm/tablet_mode/tablet_mode_multitask_menu_controller.cc
@@ -94,7 +94,7 @@ if (is_drag_active_) { if (!reserved_for_gesture_sent_) { reserved_for_gesture_sent_ = true; - event->set_flags(event->flags() | ui::EF_RESERVED_FOR_GESTURE); + event->SetFlags(event->flags() | ui::EF_RESERVED_FOR_GESTURE); return; } event->StopPropagation();
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index ad16fe23..7d3d1bc7 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -2872,6 +2872,17 @@ {"Quick Settings Nudge", kCaptureModeEducationQuickSettingsNudge, std::size(kCaptureModeEducationQuickSettingsNudge), nullptr}}; +const FeatureEntry::FeatureParam + kHoldingSpaceWallpaperNudgeDropToPinDisabled[] = {{"drop-to-pin", "false"}}; +const FeatureEntry::FeatureParam kHoldingSpaceWallpaperNudgeDropToPinEnabled[] = + {{"drop-to-pin", "true"}}; +const FeatureEntry::FeatureVariation kHoldingSpaceWallpaperNudgeVariations[] = { + {"with drop-to-pin", kHoldingSpaceWallpaperNudgeDropToPinEnabled, + std::size(kHoldingSpaceWallpaperNudgeDropToPinEnabled), nullptr}, + {"without drop-to-pin", kHoldingSpaceWallpaperNudgeDropToPinDisabled, + std::size(kHoldingSpaceWallpaperNudgeDropToPinDisabled), nullptr}, +}; + #endif // BUILDFLAG(IS_CHROMEOS_ASH) #if BUILDFLAG(IS_CHROMEOS) @@ -9571,14 +9582,6 @@ FEATURE_VALUE_TYPE(features::kRequestDesktopSiteZoom)}, #endif // BUILDFLAG(IS_ANDROID) -#if !BUILDFLAG(IS_ANDROID) - {"enable-web-hid-on-extension-service-worker", - flag_descriptions::kEnableWebHidOnExtensionServiceWorkerName, - flag_descriptions::kEnableWebHidOnExtensionServiceWorkerDescription, - kOsDesktop, - FEATURE_VALUE_TYPE(features::kEnableWebHidOnExtensionServiceWorker)}, -#endif - {"autofill-enable-remade-downstream-metrics", flag_descriptions::kAutofillEnableRemadeDownstreamMetricsName, flag_descriptions::kAutofillEnableRemadeDownstreamMetricsDescription, @@ -9754,11 +9757,6 @@ flag_descriptions::kUseDMSAAForTilesAndroidGLDescription, kOsAndroid, FEATURE_VALUE_TYPE(::features::kUseDMSAAForTilesAndroidGL)}, #endif - {"enable-web-usb-on-extension-service-worker", - flag_descriptions::kEnableWebUsbOnExtensionServiceWorkerName, - flag_descriptions::kEnableWebUsbOnExtensionServiceWorkerDescription, - kOsAndroid | kOsDesktop, - FEATURE_VALUE_TYPE(features::kEnableWebUsbOnExtensionServiceWorker)}, #if BUILDFLAG(IS_CHROMEOS_ASH) {"enable-holding-space-predictability", @@ -9773,6 +9771,18 @@ flag_descriptions::kHoldingSpaceSuggestionsName, flag_descriptions::kHoldingSpaceSuggestionsDescription, kOsCrOS, FEATURE_VALUE_TYPE(ash::features::kHoldingSpaceSuggestions)}, + {"enable-holding-space-wallpaper-nudge", + flag_descriptions::kHoldingSpaceWallpaperNudgeName, + flag_descriptions::kHoldingSpaceWallpaperNudgeDescription, kOsCrOS, + FEATURE_WITH_PARAMS_VALUE_TYPE(ash::features::kHoldingSpaceWallpaperNudge, + kHoldingSpaceWallpaperNudgeVariations, + "HoldingSpaceWallpaperNudge")}, + {"enable-holding-space-wallpaper-nudge-force-eligibility", + flag_descriptions::kHoldingSpaceWallpaperNudgeForceEligibilityName, + flag_descriptions::kHoldingSpaceWallpaperNudgeForceEligibilityDescription, + kOsCrOS, + FEATURE_VALUE_TYPE( + ash::features::kHoldingSpaceWallpaperNudgeForceEligibility)}, {"enable-welcome-tour", flag_descriptions::kWelcomeTourName, flag_descriptions::kWelcomeTourDescription, kOsCrOS, FEATURE_VALUE_TYPE(ash::features::kWelcomeTour)},
diff --git a/chrome/browser/ash/events/event_rewriter_unittest.cc b/chrome/browser/ash/events/event_rewriter_unittest.cc index 888a2e0..7faebfc5 100644 --- a/chrome/browser/ash/events/event_rewriter_unittest.cc +++ b/chrome/browser/ash/events/event_rewriter_unittest.cc
@@ -3346,7 +3346,7 @@ ui::TouchEvent press( ui::ET_TOUCH_PRESSED, location, base::TimeTicks(), ui::PointerDetails(ui::EventPointerType::kTouch, kTouchId)); - press.set_flags(ui::EF_CONTROL_DOWN); + press.SetFlags(ui::EF_CONTROL_DOWN); source().Send(&press); auto events = TakeEvents();
diff --git a/chrome/browser/component_updater/chrome_component_updater_configurator.cc b/chrome/browser/component_updater/chrome_component_updater_configurator.cc index 47a3814..c1a4486 100644 --- a/chrome/browser/component_updater/chrome_component_updater_configurator.cc +++ b/chrome/browser/component_updater/chrome_component_updater_configurator.cc
@@ -12,6 +12,7 @@ #include "base/functional/bind.h" #include "base/functional/callback.h" #include "base/memory/raw_ptr.h" +#include "base/memory/scoped_refptr.h" #include "base/path_service.h" #include "base/strings/sys_string_conversions.h" #include "base/time/time.h" @@ -88,6 +89,7 @@ absl::optional<bool> IsMachineExternallyManaged() const override; update_client::UpdaterStateProvider GetUpdaterStateProvider() const override; absl::optional<base::FilePath> GetCrxCachePath() const override; + bool IsConnectionMetered() const override; private: friend class base::RefCountedThreadSafe<ChromeConfigurator>; @@ -282,6 +284,10 @@ : absl::nullopt; } +bool ChromeConfigurator::IsConnectionMetered() const { + return configurator_impl_.IsConnectionMetered(); +} + } // namespace scoped_refptr<update_client::Configurator>
diff --git a/chrome/browser/component_updater/payload_test_component_installer.cc b/chrome/browser/component_updater/payload_test_component_installer.cc index 0f43f64..290ac2e0 100644 --- a/chrome/browser/component_updater/payload_test_component_installer.cc +++ b/chrome/browser/component_updater/payload_test_component_installer.cc
@@ -92,6 +92,11 @@ return false; } +bool PayloadTestComponentInstallerPolicy::AllowUpdatesOnMeteredConnections() + const { + return false; +} + void RegisterPayloadTestComponent(ComponentUpdateService* cus) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); base::MakeRefCounted<ComponentInstaller>(
diff --git a/chrome/browser/component_updater/payload_test_component_installer.h b/chrome/browser/component_updater/payload_test_component_installer.h index 4ea82d2e..b75b6fb9 100644 --- a/chrome/browser/component_updater/payload_test_component_installer.h +++ b/chrome/browser/component_updater/payload_test_component_installer.h
@@ -33,6 +33,7 @@ std::string GetName() const override; update_client::InstallerAttributes GetInstallerAttributes() const override; bool AllowCachedCopies() const override; + bool AllowUpdatesOnMeteredConnections() const override; }; void RegisterPayloadTestComponent(ComponentUpdateService* cus);
diff --git a/chrome/browser/component_updater/recovery_component_installer.cc b/chrome/browser/component_updater/recovery_component_installer.cc index 803f77b..3c40d30 100644 --- a/chrome/browser/component_updater/recovery_component_installer.cc +++ b/chrome/browser/component_updater/recovery_component_installer.cc
@@ -97,13 +97,15 @@ // Add a flag for re-attempted install with elevated privilege so that the // recovery executable can report back accordingly. - if (is_deferred_run) + if (is_deferred_run) { arguments.push_back("/deferredrun"); + } if (const std::string* recovery_args = manifest.FindString("x-recovery-args")) { - if (base::IsStringASCII(*recovery_args)) + if (base::IsStringASCII(*recovery_args)) { arguments.push_back(*recovery_args); + } } if (const std::string* recovery_add_version = manifest.FindString("x-recovery-add-version")) { @@ -123,10 +125,11 @@ const base::Version& version) { base::CommandLine command_line(command); - const auto arguments = GetRecoveryInstallArguments( - manifest, is_deferred_run, version); - for (const auto& arg : arguments) + const auto arguments = + GetRecoveryInstallArguments(manifest, is_deferred_run, version); + for (const auto& arg : arguments) { command_line.AppendArg(arg); + } return command_line; } @@ -146,21 +149,25 @@ const base::FilePath main_file = path.Append(kRecoveryFileName); const base::FilePath manifest_file = path.Append(FILE_PATH_LITERAL("manifest.json")); - if (!base::PathExists(main_file) || !base::PathExists(manifest_file)) + if (!base::PathExists(main_file) || !base::PathExists(manifest_file)) { return; + } base::Value::Dict manifest(ReadManifest(manifest_file)); const std::string* name = manifest.FindString("name"); - if (!name || *name != kRecoveryManifestName) + if (!name || *name != kRecoveryManifestName) { return; + } std::string proposed_version; if (const std::string* ptr = manifest.FindString("version")) { - if (base::IsStringASCII(*ptr)) + if (base::IsStringASCII(*ptr)) { proposed_version = *ptr; + } } const base::Version version(proposed_version); - if (!version.IsValid()) + if (!version.IsValid()) { return; + } const bool is_deferred_run = true; #if BUILDFLAG(IS_WIN) @@ -184,8 +191,9 @@ // ExecuteWithPrivilegesAndGetPID(): an array of string pointers // that ends with a null pointer. std::vector<const char*> raw_string_args; - for (const auto& arg : arguments) + for (const auto& arg : arguments) { raw_string_args.push_back(arg.c_str()); + } raw_string_args.push_back(nullptr); pid_t pid = -1; @@ -278,14 +286,19 @@ std::end(kRecoverySha2Hash)); if (!cus->RegisterComponent(ComponentRegistration( update_client::GetCrxIdFromPublicKeyHash(public_key_hash), "recovery", - public_key_hash, version, {}, {}, nullptr, - new RecoveryComponentInstaller(version, prefs), false, true, true))) { + public_key_hash, version, /*fingerprint=*/{}, + /*installer_attributes=*/{}, /*action_handler=*/nullptr, + new RecoveryComponentInstaller(version, prefs), + /*requires_network_encryption=*/false, + /*supports_group_policy_enable_component_updates=*/true, + /*allow_cached_copies=*/true, + /*allow_updates_on_metered_connection=*/true))) { NOTREACHED() << "Recovery component registration failed."; } } -void RecoveryUpdateVersionHelper( - const base::Version& version, PrefService* prefs) { +void RecoveryUpdateVersionHelper(const base::Version& version, + PrefService* prefs) { DCHECK_CURRENTLY_ON(BrowserThread::UI); prefs->SetString(prefs::kRecoveryComponentVersion, version.GetString()); } @@ -298,7 +311,8 @@ } RecoveryComponentInstaller::RecoveryComponentInstaller( - const base::Version& version, PrefService* prefs) + const base::Version& version, + PrefService* prefs) : current_version_(version), prefs_(prefs) { DCHECK(version.IsValid()); } @@ -329,8 +343,9 @@ options.start_hidden = true; #endif base::Process process = base::LaunchProcess(cmdline, options); - if (!process.IsValid()) + if (!process.IsValid()) { return false; + } // Let worker pool thread wait for us so we don't block Chrome shutdown. // This task joins a process, hence .WithBaseSyncPrimitives(). @@ -351,13 +366,15 @@ // Sets the POSIX executable permissions on a file bool SetPosixExecutablePermission(const base::FilePath& path) { int permissions = 0; - if (!base::GetPosixFilePermissions(path, &permissions)) + if (!base::GetPosixFilePermissions(path, &permissions)) { return false; + } const int kExecutableMask = base::FILE_PERMISSION_EXECUTE_BY_USER | base::FILE_PERMISSION_EXECUTE_BY_GROUP | base::FILE_PERMISSION_EXECUTE_BY_OTHERS; - if ((permissions & kExecutableMask) == kExecutableMask) + if ((permissions & kExecutableMask) == kExecutableMask) { return true; // No need to update + } return base::SetPosixFilePermissions(path, permissions | kExecutableMask); } #endif // BUILDFLAG(IS_POSIX)
diff --git a/chrome/browser/extensions/updater/chrome_update_client_config.cc b/chrome/browser/extensions/updater/chrome_update_client_config.cc index b94e0bbe..a9304f0 100644 --- a/chrome/browser/extensions/updater/chrome_update_client_config.cc +++ b/chrome/browser/extensions/updater/chrome_update_client_config.cc
@@ -16,6 +16,7 @@ #include "base/functional/bind.h" #include "base/functional/callback.h" #include "base/memory/raw_ptr.h" +#include "base/memory/scoped_refptr.h" #include "base/no_destructor.h" #include "base/path_service.h" #include "base/scoped_observation.h" @@ -201,14 +202,16 @@ } std::vector<GURL> ChromeUpdateClientConfig::UpdateUrl() const { - if (url_override_.has_value()) + if (url_override_.has_value()) { return {*url_override_}; + } return impl_.UpdateUrl(); } std::vector<GURL> ChromeUpdateClientConfig::PingUrl() const { - if (url_override_.has_value()) + if (url_override_.has_value()) { return {*url_override_}; + } return impl_.PingUrl(); } @@ -297,8 +300,9 @@ } bool ChromeUpdateClientConfig::EnabledCupSigning() const { - if (url_override_.has_value()) + if (url_override_.has_value()) { return false; + } return impl_.EnabledCupSigning(); } @@ -356,4 +360,8 @@ : absl::nullopt; } +bool ChromeUpdateClientConfig::IsConnectionMetered() const { + return impl_.IsConnectionMetered(); +} + } // namespace extensions
diff --git a/chrome/browser/extensions/updater/chrome_update_client_config.h b/chrome/browser/extensions/updater/chrome_update_client_config.h index 43222dd..a0f1bc5 100644 --- a/chrome/browser/extensions/updater/chrome_update_client_config.h +++ b/chrome/browser/extensions/updater/chrome_update_client_config.h
@@ -13,6 +13,7 @@ #include "base/functional/callback.h" #include "base/memory/raw_ptr.h" #include "base/memory/ref_counted.h" +#include "base/memory/scoped_refptr.h" #include "base/time/time.h" #include "components/component_updater/configurator_impl.h" #include "components/update_client/configurator.h" @@ -84,6 +85,7 @@ absl::optional<bool> IsMachineExternallyManaged() const override; update_client::UpdaterStateProvider GetUpdaterStateProvider() const override; absl::optional<base::FilePath> GetCrxCachePath() const override; + bool IsConnectionMetered() const override; protected: friend class base::RefCountedThreadSafe<ChromeUpdateClientConfig>;
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index c03033b..36bcb47 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -2896,6 +2896,16 @@ "expiry_milestone": 123 }, { + "name": "enable-holding-space-wallpaper-nudge", + "owners": [ "//ash/user_education/OWNERS" ], + "expiry_milestone": 123 + }, + { + "name": "enable-holding-space-wallpaper-nudge-force-eligibility", + "owners": [ "//ash/user_education/OWNERS" ], + "expiry_milestone": 123 + }, + { "name": "enable-hostname-setting", "owners": [ "khorimoto@chromium.org", "cros-connectivity@google.com" ], "expiry_milestone": 125 @@ -3721,11 +3731,6 @@ "expiry_milestone": 150 }, { - "name": "enable-web-hid-on-extension-service-worker", - "owners": [ "deviceapi-team@google.com" ], - "expiry_milestone": 120 - }, - { "name": "enable-web-payments-experimental-features", "owners": [ "rouslan@chromium.org", "web-payments-team@google.com" ], // This flag is used by early adoption partners to test new Web Payments @@ -3733,11 +3738,6 @@ "expiry_milestone": -1 }, { - "name": "enable-web-usb-on-extension-service-worker", - "owners": [ "deviceapi-team@google.com" ], - "expiry_milestone": 120 - }, - { "name": "enable-webassembly-baseline", "owners": [ "clemensb@chromium.org", "wasm-team@google.com" ], // This flag is often used by developers and partners to test
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 4045bcd..1d49e39 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -1333,11 +1333,6 @@ "When enabled, Chrome will attempt to connect to the system tracing " "service"; -const char kEnableWebUsbOnExtensionServiceWorkerName[] = - "Enable WebUSB on extension service workers"; -const char kEnableWebUsbOnExtensionServiceWorkerDescription[] = - "When enabled, WebUSB API is available on extension service workers."; - const char kEnableWindowsGamingInputDataFetcherName[] = "Enable Windows.Gaming.Input"; const char kEnableWindowsGamingInputDataFetcherDescription[] = @@ -4659,11 +4654,6 @@ const char kReadAnythingLocalSidePanelDescription[] = "Keep the Reading Mode side panel separate and local to each tab."; -const char kEnableWebHidOnExtensionServiceWorkerName[] = - "Enable WebHID on extension service workers"; -const char kEnableWebHidOnExtensionServiceWorkerDescription[] = - "When enabled, WebHID API is available on extension service workers."; - const char kGlobalMediaControlsCastStartStopName[] = "Global media controls control Cast start/stop"; const char kGlobalMediaControlsCastStartStopDescription[] = @@ -6496,6 +6486,21 @@ "Enables pinned file suggestions in holding space to help the user " "understand and discover the ability to pin."; +const char kHoldingSpaceWallpaperNudgeName[] = + "Enable holding space wallpaper nudge"; +const char kHoldingSpaceWallpaperNudgeDescription[] = + "Enables the nudge that educates the user on holding space pinning " + "behavior when the user drags a file over the wallpaper."; + +const char kHoldingSpaceWallpaperNudgeForceEligibilityName[] = + "Force eligibility for holding space wallpaper nudge"; +const char kHoldingSpaceWallpaperNudgeForceEligibilityDescription[] = + "Ignores the rate limits and user type limits put on the holding space " + "wallpaper nudge, meaning it will show whenever a user takes a triggering " + "action, regardless of how much or how recently it has been shown, user " + "new-ness, or account type. Enabling this flag has no effect unless the " + "holding space wallpaper nudge is enabled."; + const char kHotspotName[] = "Hotspot"; const char kHotspotDescription[] = "Enables the Chromebook to share its cellular internet connection to other "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 4cb4316..3c16b105 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -671,9 +671,6 @@ extern const char kEnableNetworkLoggingToFileName[]; extern const char kEnableNetworkLoggingToFileDescription[]; -extern const char kEnableWebUsbOnExtensionServiceWorkerName[]; -extern const char kEnableWebUsbOnExtensionServiceWorkerDescription[]; - extern const char kEnableWindowsGamingInputDataFetcherName[]; extern const char kEnableWindowsGamingInputDataFetcherDescription[]; @@ -2695,9 +2692,6 @@ extern const char kReadAnythingLocalSidePanelName[]; extern const char kReadAnythingLocalSidePanelDescription[]; -extern const char kEnableWebHidOnExtensionServiceWorkerName[]; -extern const char kEnableWebHidOnExtensionServiceWorkerDescription[]; - extern const char kGlobalMediaControlsCastStartStopName[]; extern const char kGlobalMediaControlsCastStartStopDescription[]; @@ -3735,6 +3729,12 @@ extern const char kHoldingSpaceSuggestionsName[]; extern const char kHoldingSpaceSuggestionsDescription[]; +extern const char kHoldingSpaceWallpaperNudgeName[]; +extern const char kHoldingSpaceWallpaperNudgeDescription[]; + +extern const char kHoldingSpaceWallpaperNudgeForceEligibilityName[]; +extern const char kHoldingSpaceWallpaperNudgeForceEligibilityDescription[]; + extern const char kHotspotName[]; extern const char kHotspotDescription[];
diff --git a/chrome/browser/policy/test/component_updater_policy_browsertest.cc b/chrome/browser/policy/test/component_updater_policy_browsertest.cc index a849fa7..1a81d8d 100644 --- a/chrome/browser/policy/test/component_updater_policy_browsertest.cc +++ b/chrome/browser/policy/test/component_updater_policy_browsertest.cc
@@ -171,8 +171,12 @@ // The component uses HTTPS only for network interception purposes. return component_updater::ComponentRegistration( "jebgalgnebhfojomionfpkfelancnnkf", {}, jebg_hash, base::Version("0.9"), - {}, {}, nullptr, base::MakeRefCounted<MockInstaller>(), true, - supports_group_policy_enable_component_updates, true); + /*fingerprint=*/{}, /*installer_attributes=*/{}, + /*action_handler=*/nullptr, base::MakeRefCounted<MockInstaller>(), + /*requires_network_encryption=*/true, + supports_group_policy_enable_component_updates, + /*allow_cached_copies=*/true, + /*allow_updates_on_metered_connection=*/true); } void ComponentUpdaterPolicyTest::UpdateComponent(
diff --git a/chrome/browser/resources/ash/settings/css/base.css b/chrome/browser/resources/ash/settings/css/base.css index 53b47fa..becc64fa 100644 --- a/chrome/browser/resources/ash/settings/css/base.css +++ b/chrome/browser/resources/ash/settings/css/base.css
@@ -22,7 +22,7 @@ } html { - background-color: var(--settings-base-bg-color); + background-color: var(--cros-sys-app_base_shaded); overflow: hidden; /* Remove 300ms delay for 'click' event, when using touch interface. */ touch-action: manipulation;
diff --git a/chrome/browser/resources/ash/settings/main_page_container/main_page_container.html b/chrome/browser/resources/ash/settings/main_page_container/main_page_container.html index eb702ff7..4adb06c 100644 --- a/chrome/browser/resources/ash/settings/main_page_container/main_page_container.html +++ b/chrome/browser/resources/ash/settings/main_page_container/main_page_container.html
@@ -11,6 +11,10 @@ display: none; } + :host-context(body.revamp-wayfinding-enabled):host(:not(.showing-subpage)) { + padding-top: 8px; + } + .banner { align-items: center; background-color: var(--cros-bg-color);
diff --git a/chrome/browser/resources/ash/settings/os_settings_page/os_settings_animated_pages.html b/chrome/browser/resources/ash/settings/os_settings_page/os_settings_animated_pages.html index 68664baf..46e35ef 100644 --- a/chrome/browser/resources/ash/settings/os_settings_page/os_settings_animated_pages.html +++ b/chrome/browser/resources/ash/settings/os_settings_page/os_settings_animated_pages.html
@@ -1,16 +1,3 @@ -<style> - /* L1 page content backdrop style */ - :host-context(body.revamp-wayfinding-enabled) - ::slotted(div[route-path="default"]) { - background-color: var(--settings-content-backdrop-bg-color); - border-radius: 20px; - padding-bottom: 16px; - padding-inline-end: 16px; - padding-inline-start: 16px; - padding-top: 8px; - } -</style> - <iron-pages id="animatedPages" attr-for-selected="route-path" on-iron-select="onIronSelect_"> <slot></slot>
diff --git a/chrome/browser/resources/ash/settings/os_settings_page/settings_card.html b/chrome/browser/resources/ash/settings/os_settings_page/settings_card.html index 16256c5..86755e25 100644 --- a/chrome/browser/resources/ash/settings/os_settings_page/settings_card.html +++ b/chrome/browser/resources/ash/settings/os_settings_page/settings_card.html
@@ -1,6 +1,5 @@ <style> :host { - --settings-card-bg-color: var(--cros-sys-app_base); --settings-card-border-radius: var(--cr-card-border-radius); display: flex; @@ -15,12 +14,6 @@ margin-bottom: 16px; } - @media (prefers-color-scheme: dark) { - :host-context(body.revamp-wayfinding-enabled):host { - --settings-card-bg-color: var(--cros-sys-surface1); - } - } - :host-context(body.revamp-wayfinding-enabled) #header { margin: 0; padding: 8px; @@ -47,7 +40,7 @@ } #card { - background-color: var(--settings-card-bg-color); + background-color: var(--cros-sys-app_base); border-radius: var(--settings-card-border-radius); flex: 1; overflow: hidden;
diff --git a/chrome/browser/resources/ash/settings/os_settings_ui/os_settings_ui.html b/chrome/browser/resources/ash/settings/os_settings_ui/os_settings_ui.html index 4ad6aea..4dbd1a28 100644 --- a/chrome/browser/resources/ash/settings/os_settings_ui/os_settings_ui.html +++ b/chrome/browser/resources/ash/settings/os_settings_ui/os_settings_ui.html
@@ -49,7 +49,7 @@ } #left, - #center, + #main, #right { flex: 1 1 0; } @@ -66,6 +66,17 @@ overscroll-behavior: contain; } + :host-context(body.revamp-wayfinding-enabled) #left os-settings-menu { + background-color: var(--cros-sys-surface3); + border-start-end-radius: 30px; + } + + @media (prefers-color-scheme: dark) { + :host-context(body.revamp-wayfinding-enabled) #left os-settings-menu { + background-color: var(--cros-sys-surface2); + } + } + :host-context(body.revamp-wayfinding-enabled) #drawer { /* TODO(b/316088424) Use window border radius token if available */ --cr-drawer-border-start-end-radius: 12px; @@ -76,7 +87,7 @@ --cr-drawer-width: var(--settings-menu-width); } - #center { + #main { flex-basis: var(--settings-main-basis); } @@ -89,7 +100,7 @@ display: none; } - #center { + #main { min-width: auto; /* Add some padding to make room for borders and to prevent focus * indicators from being cropped. */ @@ -147,7 +158,6 @@ </div> </cr-drawer> </template> -<!-- #container is the shadow container for CrContainerShadowMixin. --> <div id="container" class="no-outline"> <div id="left"> <template is="dom-if" if="[[showNavMenu_]]"> @@ -158,14 +168,12 @@ </os-settings-menu> </template> </div> - <div id="center"> - <os-settings-main - prefs="{{prefs}}" - toolbar-spinner-active="{{toolbarSpinnerActive_}}" - page-availability="[[pageAvailability_]]" - advanced-toggle-expanded="{{advancedOpenedInMain_}}"> - </os-settings-main> - </div> + <os-settings-main id="main" + prefs="{{prefs}}" + toolbar-spinner-active="{{toolbarSpinnerActive_}}" + page-availability="[[pageAvailability_]]" + advanced-toggle-expanded="{{advancedOpenedInMain_}}"> + </os-settings-main> <!-- An additional child of the flex #container to take up space, aligned with the right-hand child of the flex toolbar. --> <div id="right"></div>
diff --git a/chrome/browser/resources/ash/settings/os_toolbar/os_toolbar.html b/chrome/browser/resources/ash/settings/os_toolbar/os_toolbar.html index 6ed1a24..5312569 100644 --- a/chrome/browser/resources/ash/settings/os_toolbar/os_toolbar.html +++ b/chrome/browser/resources/ash/settings/os_toolbar/os_toolbar.html
@@ -1,7 +1,7 @@ <style include="cr-icons cr-hidden-style settings-shared"> :host { align-items: center; - background-color: var(--settings-base-bg-color); + background-color: var(--cros-sys-app_base_shaded); color: var(--cros-text-color-secondary); display: flex; height: var(--settings-toolbar-height);
diff --git a/chrome/browser/resources/ash/settings/settings_vars.css b/chrome/browser/resources/ash/settings/settings_vars.css index 4d2c7971..ac76d40 100644 --- a/chrome/browser/resources/ash/settings/settings_vars.css +++ b/chrome/browser/resources/ash/settings/settings_vars.css
@@ -24,8 +24,6 @@ --cr-radio-group-item-padding: 0; - --settings-base-bg-color: var(--cros-sys-app_base_shaded); - --settings-menu-width: 250px; --settings-menu-item-border-width: 2px; @@ -45,13 +43,9 @@ /* TODO(b/302374851) Move these vars into the html block above once the feature * is fully launched and can be cleaned up. */ -html:has(body.revamp-wayfinding-enabled) { - --settings-base-bg-color: var(--cros-sys-surface3); - +body.revamp-wayfinding-enabled { --settings-container-padding-top: 8px; - --settings-content-backdrop-bg-color: var(--cros-sys-surface1); - --settings-menu-item-width: 256px; --settings-menu-padding-inline-end: 16px; @@ -78,10 +72,4 @@ --iron-icon-fill-color: var(--google-grey-500); --settings-error-color: var(--google-red-300); } - - html:has(body.revamp-wayfinding-enabled) { - --settings-base-bg-color: var(--cros-sys-app_base_shaded); - - --settings-content-backdrop-bg-color: var(--cros-sys-app_base); - } }
diff --git a/chrome/browser/resources/chromeos/accessibility/common/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/common/BUILD.gn index 45acd9b1..9e70c17 100644 --- a/chrome/browser/resources/chromeos/accessibility/common/BUILD.gn +++ b/chrome/browser/resources/chromeos/accessibility/common/BUILD.gn
@@ -29,7 +29,6 @@ "async_util.js", "automation_predicate.js", "browser_util.js", - "event_handler.js", "gdocs_script.js", "key_code.js", "local_storage.js", @@ -48,6 +47,7 @@ "cursors/range.ts", "cursors/recovery_strategy.ts", "event_generator.ts", + "event_handler.ts", "flags.ts", "instance_checker.ts", "paragraph_utils.ts",
diff --git a/chrome/browser/resources/chromeos/accessibility/common/event_handler.js b/chrome/browser/resources/chromeos/accessibility/common/event_handler.js deleted file mode 100644 index 3b9987f8..0000000 --- a/chrome/browser/resources/chromeos/accessibility/common/event_handler.js +++ /dev/null
@@ -1,159 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -const AutomationEvent = chrome.automation.AutomationEvent; -const AutomationNode = chrome.automation.AutomationNode; - -/** - * This class wraps AutomationNode event listeners, adding some convenience - * functions. - */ -export class EventHandler { - /** - * @param {!AutomationNode | !Array<!AutomationNode>} nodes - * @param {!chrome.automation.EventType | - * !Array<!chrome.automation.EventType>} types - * @param {?function(!AutomationEvent)} callback - * @param {{capture: (boolean|undefined), exactMatch: (boolean|undefined), - * listenOnce: (boolean|undefined), predicate: - * ((function(AutomationEvent): boolean)|undefined)}} - * options - * exactMatch Whether to ignore events where the target is not the provided - * node. - * capture True if the event should be processed before it has reached the - * target node, false if it should be processed after. - * listenOnce True if the event listeners should automatically be removed - * when the callback is called once. - * predicate A predicate for what events will be processed. - */ - constructor(nodes, types, callback, options = {}) { - /** @private {!Array<!AutomationNode>} */ - this.nodes_ = nodes instanceof Array ? nodes : [nodes]; - - /** @private {!Array<!chrome.automation.EventType>} */ - this.types_ = types instanceof Array ? types : [types]; - - /** @private {?function(!AutomationEvent)} */ - this.callback_ = callback; - - /** @private {boolean} */ - this.capture_ = options.capture || false; - - /** @private {boolean} */ - this.exactMatch_ = options.exactMatch || false; - - /** @private {boolean} */ - this.listenOnce_ = options.listenOnce || false; - - /** - * Default is a function that always returns true. - * @private {!function(AutomationEvent): boolean} - */ - this.predicate_ = options.predicate || (e => true); - - /** @private {boolean} */ - this.listening_ = false; - - /** @private {!function(AutomationEvent)} */ - this.handler_ = event => this.handleEvent_(event); - } - - /** Starts listening to events. */ - start() { - if (this.listening_) { - return; - } - - for (const node of this.nodes_) { - for (const type of this.types_) { - node.addEventListener(type, this.handler_, this.capture_); - } - } - this.listening_ = true; - } - - /** Stops listening or handling future events. */ - stop() { - for (const node of this.nodes_) { - for (const type of this.types_) { - node.removeEventListener(type, this.handler_, this.capture_); - } - } - this.listening_ = false; - } - - /** - * @return {boolean} Whether this EventHandler is currently listening for - * events. - */ - listening() { - return this.listening_; - } - - /** @param {?function(!AutomationEvent)} callback */ - setCallback(callback) { - this.callback_ = callback; - } - - /** - * Changes what nodes are being listened to. Removes listeners from existing - * nodes before adding listeners on new nodes. - * @param {!AutomationNode | !Array<!AutomationNode>} nodes - */ - setNodes(nodes) { - const wasListening = this.listening_; - this.stop(); - this.nodes_ = nodes instanceof Array ? nodes : [nodes]; - if (wasListening) { - this.start(); - } - } - - /** - * Adds another node to the set of nodes being listened to. - * @param {!AutomationNode} node - */ - addNode(node) { - this.nodes_.push(node); - - if (this.listening_) { - for (const type of this.types_) { - node.addEventListener(type, this.handler_, this.capture_); - } - } - } - - /** - * Removes a specific node from the set of nodes being listened to. - * @param {!AutomationNode} node - */ - removeNode(node) { - this.nodes_ = this.nodes_.filter(n => n !== node); - - if (this.listening_) { - for (const type of this.types_) { - node.removeEventListener(type, this.handler_, this.capture_); - } - } - } - - /** @private */ - handleEvent_(event) { - if (this.exactMatch_ && !this.nodes_.includes(event.target)) { - return; - } - - if (!this.predicate_(event)) { - return; - } - - if (this.listenOnce_) { - this.stop(); - } - - if (this.callback_) { - this.callback_(event); - } - } -}
diff --git a/chrome/browser/resources/chromeos/accessibility/common/event_handler.ts b/chrome/browser/resources/chromeos/accessibility/common/event_handler.ts new file mode 100644 index 0000000..0c38646 --- /dev/null +++ b/chrome/browser/resources/chromeos/accessibility/common/event_handler.ts
@@ -0,0 +1,159 @@ +// Copyright 2020 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +type AutomationEvent = chrome.automation.AutomationEvent; +type AutomationNode = chrome.automation.AutomationNode; +import EventType = chrome.automation.EventType; + +interface EventHandlerOptions { + /** + * Whether to ignore events where the target is not the provided node. + */ + exactMatch?: boolean; + + /** + * True if the event should be processed before it has reached the target + * node, false if it should be processed after. + */ + capture?: boolean; + + /** + * True if the event listeners should automatically be removed when the + * callback is called once. + */ + listenOnce?: boolean; + + /** + * A predicate for what events will be processed. + */ + predicate?: (event: AutomationEvent) => boolean; +} + +/** + * This class wraps AutomationNode event listeners, adding some convenience + * functions. + */ +export class EventHandler { + private nodes_: AutomationNode[]; + private types_: EventType[]; + private callback_: ((event: AutomationEvent) => void)|null; + private capture_: boolean; + private exactMatch_: boolean; + private listenOnce_: boolean; + private listening_ = false; + private predicate_: (event: AutomationEvent) => boolean; + private handler_: (event: AutomationEvent) => void; + + constructor( + nodes: AutomationNode|AutomationNode[], types: EventType|EventType[], + callback: (event: AutomationEvent) => void, + options: EventHandlerOptions = {}) { + this.nodes_ = nodes instanceof Array ? nodes : [nodes]; + this.types_ = types instanceof Array ? types : [types]; + this.callback_ = callback; + this.capture_ = options.capture || false; + this.exactMatch_ = options.exactMatch || false; + this.listenOnce_ = options.listenOnce || false; + + /** + * Default is a function that always returns true. + */ + this.predicate_ = options.predicate || (_e => true); + + this.handler_ = event => this.handleEvent_(event); + } + + /** Starts listening to events. */ + start(): void { + if (this.listening_) { + return; + } + + for (const node of this.nodes_) { + for (const type of this.types_) { + node.addEventListener(type, this.handler_, this.capture_); + } + } + this.listening_ = true; + } + + /** Stops listening or handling future events. */ + stop(): void { + for (const node of this.nodes_) { + for (const type of this.types_) { + node.removeEventListener(type, this.handler_, this.capture_); + } + } + this.listening_ = false; + } + + /** + * @return Whether this EventHandler is currently listening for events. + */ + listening(): boolean { + return this.listening_; + } + + setCallback(callback: ((event: AutomationEvent) => void)|null): void { + this.callback_ = callback; + } + + /** + * Changes what nodes are being listened to. Removes listeners from existing + * nodes before adding listeners on new nodes. + */ + setNodes(nodes: AutomationNode|AutomationNode[]): void { + const wasListening = this.listening_; + // TODO(b/318557827): Shouldn't this be: if (wasListening) this.stop()? + this.stop(); + this.nodes_ = nodes instanceof Array ? nodes : [nodes]; + if (wasListening) { + this.start(); + } + } + + /** + * Adds another node to the set of nodes being listened to. + */ + addNode(node: AutomationNode): void { + this.nodes_.push(node); + + if (this.listening_) { + for (const type of this.types_) { + node.addEventListener(type, this.handler_, this.capture_); + } + } + } + + /** + * Removes a specific node from the set of nodes being listened to. + */ + removeNode(node: AutomationNode): void { + this.nodes_ = this.nodes_.filter(n => n !== node); + + if (this.listening_) { + for (const type of this.types_) { + node.removeEventListener(type, this.handler_, this.capture_); + } + } + } + + private handleEvent_(event: AutomationEvent): void { + if (this.exactMatch_ && !this.nodes_.includes(event.target)) { + return; + } + + if (!this.predicate_(event)) { + return; + } + + if (this.listenOnce_) { + this.stop(); + } + + if (this.callback_) { + this.callback_(event); + } + } +}
diff --git a/chrome/browser/resources/chromeos/cloud_upload/BUILD.gn b/chrome/browser/resources/chromeos/cloud_upload/BUILD.gn index 9ac6ac40..0cfc988 100644 --- a/chrome/browser/resources/chromeos/cloud_upload/BUILD.gn +++ b/chrome/browser/resources/chromeos/cloud_upload/BUILD.gn
@@ -62,7 +62,6 @@ "//ash/webui/common/resources/cr_elements:build_ts", "//third_party/cros-components:cros_components_ts", "//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", ]
diff --git a/chrome/browser/resources/chromeos/internet_detail_dialog/BUILD.gn b/chrome/browser/resources/chromeos/internet_detail_dialog/BUILD.gn index eebb1b09..c1fb7de 100644 --- a/chrome/browser/resources/chromeos/internet_detail_dialog/BUILD.gn +++ b/chrome/browser/resources/chromeos/internet_detail_dialog/BUILD.gn
@@ -15,6 +15,7 @@ ts_definitions = [ "//tools/typescript/definitions/chrome_send.d.ts" ] + ts_composite = true ts_deps = [ "//ash/webui/common/resources:build_ts", "//third_party/polymer/v3_0:library",
diff --git a/chrome/browser/safe_browsing/chrome_password_reuse_detection_manager_client.cc b/chrome/browser/safe_browsing/chrome_password_reuse_detection_manager_client.cc index e04420a7..a9a2f91 100644 --- a/chrome/browser/safe_browsing/chrome_password_reuse_detection_manager_client.cc +++ b/chrome/browser/safe_browsing/chrome_password_reuse_detection_manager_client.cc
@@ -267,9 +267,7 @@ AddToWidgetInputEventObservers(page.GetMainDocument().GetRenderWidgetHost(), this); - if (base::FeatureList::IsEnabled(safe_browsing::kAntiPhishingTelemetry)) { - phishy_interaction_tracker_.HandlePageChanged(); - } + phishy_interaction_tracker_.HandlePageChanged(); } void ChromePasswordReuseDetectionManagerClient::RenderFrameCreated( @@ -318,16 +316,12 @@ } password_reuse_detection_manager_.OnPaste(std::move(text)); - if (base::FeatureList::IsEnabled(safe_browsing::kAntiPhishingTelemetry)) { - phishy_interaction_tracker_.HandlePasteEvent(); - } + phishy_interaction_tracker_.HandlePasteEvent(); } void ChromePasswordReuseDetectionManagerClient::OnInputEvent( const blink::WebInputEvent& event) { - if (base::FeatureList::IsEnabled(safe_browsing::kAntiPhishingTelemetry)) { - phishy_interaction_tracker_.HandleInputEvent(event); - } + phishy_interaction_tracker_.HandleInputEvent(event); #if BUILDFLAG(IS_ANDROID) // On Android, key down events are triggered if a user types in through a // number bar on Android keyboard. If text is typed in through other parts of
diff --git a/chrome/browser/safe_browsing/phishy_interaction_tracker.cc b/chrome/browser/safe_browsing/phishy_interaction_tracker.cc index 4bdc632..c815a93 100644 --- a/chrome/browser/safe_browsing/phishy_interaction_tracker.cc +++ b/chrome/browser/safe_browsing/phishy_interaction_tracker.cc
@@ -12,7 +12,6 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/safe_browsing/safe_browsing_service.h" #include "components/safe_browsing/content/browser/ui_manager.h" -#include "components/safe_browsing/core/common/features.h" #include "content/public/browser/browser_thread.h" #include "ui/base/clipboard/clipboard.h" #include "ui/events/keycodes/keyboard_codes.h" @@ -65,14 +64,11 @@ PhishyInteractionTracker::PhishyInteractionTracker( content::WebContents* web_contents) : web_contents_(web_contents), inactivity_delay_(base::Minutes(5)) { - if (base::FeatureList::IsEnabled(safe_browsing::kAntiPhishingTelemetry)) { - ResetLoggingHelpers(); - } + ResetLoggingHelpers(); } PhishyInteractionTracker::~PhishyInteractionTracker() { - if (base::FeatureList::IsEnabled(safe_browsing::kAntiPhishingTelemetry) && - is_phishy_ && !is_data_logged_) { + if (is_phishy_ && !is_data_logged_) { LogPageData(); inactivity_timer_.Stop(); }
diff --git a/chrome/browser/safe_browsing/phishy_interaction_tracker_unittest.cc b/chrome/browser/safe_browsing/phishy_interaction_tracker_unittest.cc index 86c7e67..5aabeb8a 100644 --- a/chrome/browser/safe_browsing/phishy_interaction_tracker_unittest.cc +++ b/chrome/browser/safe_browsing/phishy_interaction_tracker_unittest.cc
@@ -19,7 +19,6 @@ #include "chrome/test/base/chrome_render_view_host_test_harness.h" #include "chrome/test/base/testing_browser_process.h" #include "components/safe_browsing/content/browser/unsafe_resource_util.h" -#include "components/safe_browsing/core/common/features.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/web_contents.h" #include "content/public/test/mock_render_process_host.h" @@ -89,7 +88,6 @@ base::MakeRefCounted<safe_browsing::TestSafeBrowsingService>(); browser_process_->SetSafeBrowsingService(sb_service_.get()); - feature_list_.InitAndEnableFeature(safe_browsing::kAntiPhishingTelemetry); ui_manager_ = new StrictMock<MockSafeBrowsingUIManager>(); phishy_interaction_tracker_ = base::WrapUnique(new PhishyInteractionTracker(web_contents())); @@ -216,9 +214,6 @@ scoped_refptr<safe_browsing::SafeBrowsingService> sb_service_; std::unique_ptr<PhishyInteractionTracker> phishy_interaction_tracker_; scoped_refptr<MockSafeBrowsingUIManager> ui_manager_; - - private: - base::test::ScopedFeatureList feature_list_; }; TEST_F(PhishyInteractionTrackerTest, CheckHistogramCountsOnPhishyUserEvents) {
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc index 59e0b3c..38be3e1 100644 --- a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc +++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
@@ -1054,27 +1054,6 @@ net::EmbeddedTestServer https_server_; }; -class AntiPhishingTelemetryBrowserTest - : public SafeBrowsingBlockingPageBrowserTest { - public: - AntiPhishingTelemetryBrowserTest() { - base::test::FeatureRefAndParams anti_phishing_telemetry_feature( - safe_browsing::kAntiPhishingTelemetry, {}); - scoped_feature_list_.InitWithFeaturesAndParameters( - {anti_phishing_telemetry_feature}, {}); - } - ~AntiPhishingTelemetryBrowserTest() override = default; - - void SetUp() override { SafeBrowsingBlockingPageBrowserTest::SetUp(); } - - content::WebContents* GetWebContents() { - return browser()->tab_strip_model()->GetActiveWebContents(); - } - - private: - base::test::ScopedFeatureList scoped_feature_list_; -}; - class SafeBrowsingHatsSurveyBrowserTest : public SafeBrowsingBlockingPageBrowserTest { public: @@ -2416,6 +2395,9 @@ EXPECT_TRUE(report.has_warning_shown_timestamp_msec()); } +class AntiPhishingTelemetryBrowserTest + : public SafeBrowsingBlockingPageBrowserTest {}; + INSTANTIATE_TEST_SUITE_P( AntiPhishingTelemetryBrowserTestWithThreatTypeAndIsolationSetting, AntiPhishingTelemetryBrowserTest,
diff --git a/chrome/browser/safe_browsing/safe_browsing_service.cc b/chrome/browser/safe_browsing/safe_browsing_service.cc index 7e77958..2620082f 100644 --- a/chrome/browser/safe_browsing/safe_browsing_service.cc +++ b/chrome/browser/safe_browsing/safe_browsing_service.cc
@@ -553,8 +553,7 @@ const GURL& url, const GURL& page_url, const PhishySiteInteractionMap& phishy_interaction_data) { - if (!base::FeatureList::IsEnabled(kAntiPhishingTelemetry) || !profile || - !IsExtendedReportingEnabled(*profile->GetPrefs())) { + if (!profile || !IsExtendedReportingEnabled(*profile->GetPrefs())) { return false; } DCHECK_CURRENTLY_ON(BrowserThread::UI);
diff --git a/chrome/browser/safe_browsing/safe_browsing_service_unittest.cc b/chrome/browser/safe_browsing/safe_browsing_service_unittest.cc index 3eb8b27..59a2a0d 100644 --- a/chrome/browser/safe_browsing/safe_browsing_service_unittest.cc +++ b/chrome/browser/safe_browsing/safe_browsing_service_unittest.cc
@@ -16,7 +16,6 @@ #include "components/download/public/common/mock_download_item.h" #include "components/safe_browsing/content/browser/safe_browsing_service_interface.h" #include "components/safe_browsing/core/browser/ping_manager.h" -#include "components/safe_browsing/core/common/features.h" #include "components/safe_browsing/core/common/proto/csd.pb.h" #include "components/safe_browsing/core/common/safe_browsing_prefs.h" #include "content/public/browser/download_item_utils.h" @@ -247,13 +246,8 @@ /*show_download_in_folder=*/true)); } -class SafeBrowsingServiceTestWithAntiPhishingTelemetryEnabled +class SafeBrowsingServiceAntiPhishingTelemetryTest : public SafeBrowsingServiceTest { - public: - SafeBrowsingServiceTestWithAntiPhishingTelemetryEnabled() { - feature_list_.InitAndEnableFeature(safe_browsing::kAntiPhishingTelemetry); - } - protected: PhishySiteInteractionMap SetUpPhishyInteractionMap( int expected_click_occurrences, @@ -289,12 +283,9 @@ } return new_map; } - - private: - base::test::ScopedFeatureList feature_list_; }; -TEST_F(SafeBrowsingServiceTestWithAntiPhishingTelemetryEnabled, +TEST_F(SafeBrowsingServiceAntiPhishingTelemetryTest, SendPhishyInteractionsReport_Success) { const int kExpectedClickEventCount = 5; const int kExpectedKeyEventCount = 2;
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 8f024dd2..ed03f731 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -4736,6 +4736,8 @@ sources += [ "startup/web_app_info_recorder_utils.cc", "startup/web_app_info_recorder_utils.h", + "views/media_preview/active_devices_media_coordinator.cc", + "views/media_preview/active_devices_media_coordinator.h", "views/media_preview/camera_preview/camera_coordinator.cc", "views/media_preview/camera_preview/camera_coordinator.h", "views/media_preview/camera_preview/camera_mediator.cc",
diff --git a/chrome/browser/ui/ash/ambient/OWNERS b/chrome/browser/ui/ash/ambient/OWNERS index 574ed11..67d3ebc4 100644 --- a/chrome/browser/ui/ash/ambient/OWNERS +++ b/chrome/browser/ui/ash/ambient/OWNERS
@@ -1 +1 @@ -file://chromeos/ash/components/assistant/OWNERS +file://ash/ambient/OWNERS
diff --git a/chrome/browser/ui/performance_controls/test_support/webui_interactive_test_mixin.h b/chrome/browser/ui/performance_controls/test_support/webui_interactive_test_mixin.h new file mode 100644 index 0000000..089755d --- /dev/null +++ b/chrome/browser/ui/performance_controls/test_support/webui_interactive_test_mixin.h
@@ -0,0 +1,86 @@ +// Copyright 2024 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_UI_PERFORMANCE_CONTROLS_TEST_SUPPORT_WEBUI_INTERACTIVE_TEST_MIXIN_H_ +#define CHROME_BROWSER_UI_PERFORMANCE_CONTROLS_TEST_SUPPORT_WEBUI_INTERACTIVE_TEST_MIXIN_H_ + +#include <type_traits> +#include "base/test/bind.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_element_identifiers.h" +#include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "chrome/test/interaction/interaction_test_util_browser.h" +#include "chrome/test/interaction/interactive_browser_test.h" +#include "chrome/test/interaction/webcontents_interaction_test_util.h" +#include "ui/base/interaction/interactive_test.h" + +namespace { +DEFINE_LOCAL_CUSTOM_ELEMENT_EVENT_TYPE(kElementRenders); +DEFINE_LOCAL_CUSTOM_ELEMENT_EVENT_TYPE(kButtonWasClicked); +DEFINE_LOCAL_CUSTOM_ELEMENT_EVENT_TYPE(kIronCollapseContentShows); +} // namespace + +// Template to be used as a mixin class for performance settings webui +// interactive tests +template <typename T> +class WebUiInteractiveTestMixin : public T { + public: + template <class... Args> + explicit WebUiInteractiveTestMixin(Args&&... args) + : T(std::forward<Args>(args)...) {} + + ~WebUiInteractiveTestMixin() override = default; + + WebUiInteractiveTestMixin(const WebUiInteractiveTestMixin&) = delete; + WebUiInteractiveTestMixin& operator=(const WebUiInteractiveTestMixin&) = + delete; + + auto WaitForElementToRender( + const ui::ElementIdentifier& contents_id, + const WebContentsInteractionTestUtil::DeepQuery& element) { + WebContentsInteractionTestUtil::StateChange element_renders; + element_renders.event = kElementRenders; + element_renders.where = element; + element_renders.test_function = + "(el) => { if (el !== null) { let rect = el.getBoundingClientRect(); " + "return rect.width > 0 && rect.height > 0; } return false; }"; + + return T::WaitForStateChange(contents_id, element_renders); + } + + auto ClickElement(const ui::ElementIdentifier& contents_id, + const WebContentsInteractionTestUtil::DeepQuery& element) { + return T::Steps(T::FlushEvents(), + WaitForElementToRender(contents_id, element), + T::MoveMouseTo(contents_id, element), T::ClickMouse()); + } + + auto WaitForButtonStateChange( + const ui::ElementIdentifier& contents_id, + const WebContentsInteractionTestUtil::DeepQuery& element, + bool is_checked) { + WebContentsInteractionTestUtil::StateChange toggle_selection_change; + toggle_selection_change.event = kButtonWasClicked; + toggle_selection_change.where = element; + toggle_selection_change.test_function = base::StrCat( + {"(el) => { return ", is_checked ? "" : "!", "el.checked; }"}); + + return T::WaitForStateChange(contents_id, toggle_selection_change); + } + + auto WaitForIronListCollapseStateChange( + const ui::ElementIdentifier& contents_id, + const WebContentsInteractionTestUtil::DeepQuery& query) { + WebContentsInteractionTestUtil::StateChange iron_collapse_finish_animating; + iron_collapse_finish_animating.event = kIronCollapseContentShows; + iron_collapse_finish_animating.where = query; + iron_collapse_finish_animating.test_function = + "(el) => { return !el.transitioning; }"; + + return T::WaitForStateChange(contents_id, iron_collapse_finish_animating); + } +}; + +#endif // CHROME_BROWSER_UI_PERFORMANCE_CONTROLS_TEST_SUPPORT_WEBUI_INTERACTIVE_TEST_MIXIN_H_
diff --git a/chrome/browser/ui/views/media_preview/active_devices_media_coordinator.cc b/chrome/browser/ui/views/media_preview/active_devices_media_coordinator.cc new file mode 100644 index 0000000..3e2c293 --- /dev/null +++ b/chrome/browser/ui/views/media_preview/active_devices_media_coordinator.cc
@@ -0,0 +1,139 @@ +// Copyright 2024 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/ui/views/media_preview/active_devices_media_coordinator.h" + +#include <string> +#include <vector> + +#include "chrome/browser/ui/views/media_preview/media_view.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/media_device_id.h" +#include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h" +#include "ui/views/view.h" + +namespace { + +using EligibleDevices = MediaCoordinator::EligibleDevices; + +bool IsWithinWebContents(content::GlobalRenderFrameHostId render_frame_host_id, + content::WebContents* web_contents) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + bool is_request_in_frame = false; + web_contents->GetPrimaryMainFrame()->ForEachRenderFrameHost( + [&is_request_in_frame, + render_frame_host_id](content::RenderFrameHost* render_frame_host) { + if (render_frame_host->GetGlobalId() == render_frame_host_id) { + is_request_in_frame = true; + } + }); + return is_request_in_frame; +} + +} // namespace + +ActiveDevicesMediaCoordinator::ActiveDevicesMediaCoordinator( + content::WebContents* web_contents, + MediaCoordinator::ViewType view_type, + views::View* parent_view) + : web_contents_(web_contents), + view_type_(view_type), + parent_view_(parent_view), + stream_type_(view_type_ == MediaCoordinator::ViewType::kCameraOnly + ? blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE + : blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE) { + CHECK(parent_view_); + CHECK(web_contents_); + container_ = parent_view_->AddChildView(std::make_unique<MediaView>()); + CHECK(container_); + + MediaCaptureDevicesDispatcher::GetInstance()->AddObserver(this); + UpdateMediaCoordinatorList(); +} + +ActiveDevicesMediaCoordinator::~ActiveDevicesMediaCoordinator() { + MediaCaptureDevicesDispatcher::GetInstance()->RemoveObserver(this); +} + +void ActiveDevicesMediaCoordinator::UpdateMediaCoordinatorList() { + web_contents_->GetMediaCaptureRawDeviceIdsOpened( + stream_type_, + base::BindOnce( + &ActiveDevicesMediaCoordinator::GotDeviceIdsOpenedForWebContents, + base::Unretained(this))); +} + +void ActiveDevicesMediaCoordinator::GotDeviceIdsOpenedForWebContents( + std::vector<std::string> active_device_ids) { + if (active_device_ids.empty()) { + media_coordinators_.clear(); + AddMediaCoordinatorForDevice(/*active_device_id=*/ + std::nullopt); + return; + } + + base::flat_set<std::string> active_device_id_set{active_device_ids}; + for (const auto& key : GetMediaCoordinatorKeys()) { + if (!active_device_id_set.erase(key)) { + // remove the coordinator because it isn't active anymore. + media_coordinators_.erase(key); + } + } + + for (const auto& active_device_id : active_device_id_set) { + AddMediaCoordinatorForDevice(active_device_id); + } +} + +void ActiveDevicesMediaCoordinator::AddMediaCoordinatorForDevice( + const std::optional<std::string>& active_device_id) { + std::vector<std::string> active_device_id_vector; + if (active_device_id.has_value()) { + active_device_id_vector.push_back(active_device_id.value()); + } + EligibleDevices eligible_devices; + if (view_type_ == MediaCoordinator::ViewType::kCameraOnly) { + eligible_devices.cameras = active_device_id_vector; + } else { + eligible_devices.mics = active_device_id_vector; + } + + auto coordinator_key = active_device_id.value_or("changeable"); + media_coordinators_.emplace(coordinator_key, + std::make_unique<MediaCoordinator>( + view_type_, *container_, + /*index=*/std::nullopt, + /*is_subsection=*/true, eligible_devices)); +} + +void ActiveDevicesMediaCoordinator::OnRequestUpdate( + int render_process_id, + int render_frame_id, + blink::mojom::MediaStreamType stream_type, + const content::MediaRequestState state) { + if (stream_type != stream_type_) { + return; + } + + if (!IsWithinWebContents( + content::GlobalRenderFrameHostId{render_process_id, render_frame_id}, + web_contents_)) { + return; + } + + if (state == content::MediaRequestState::MEDIA_REQUEST_STATE_DONE || + state == content::MediaRequestState::MEDIA_REQUEST_STATE_CLOSING) { + UpdateMediaCoordinatorList(); + } +} + +std::vector<std::string> +ActiveDevicesMediaCoordinator::GetMediaCoordinatorKeys() { + std::vector<std::string> keys; + keys.reserve(media_coordinators_.size()); + for (const auto& [key, _] : media_coordinators_) { + keys.push_back(key); + } + return keys; +}
diff --git a/chrome/browser/ui/views/media_preview/active_devices_media_coordinator.h b/chrome/browser/ui/views/media_preview/active_devices_media_coordinator.h new file mode 100644 index 0000000..240cd90 --- /dev/null +++ b/chrome/browser/ui/views/media_preview/active_devices_media_coordinator.h
@@ -0,0 +1,54 @@ +// Copyright 2024 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_UI_VIEWS_MEDIA_PREVIEW_ACTIVE_DEVICES_MEDIA_COORDINATOR_H_ +#define CHROME_BROWSER_UI_VIEWS_MEDIA_PREVIEW_ACTIVE_DEVICES_MEDIA_COORDINATOR_H_ + +#include <memory> +#include <optional> +#include <string> +#include <vector> + +#include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h" +#include "chrome/browser/ui/views/media_preview/media_coordinator.h" +#include "content/public/browser/web_contents.h" + +class ActiveDevicesMediaCoordinator + : public MediaCaptureDevicesDispatcher::Observer { + public: + ActiveDevicesMediaCoordinator(content::WebContents* web_contents, + MediaCoordinator::ViewType view_type, + views::View* parent_view); + ActiveDevicesMediaCoordinator(const ActiveDevicesMediaCoordinator&) = delete; + ActiveDevicesMediaCoordinator& operator=( + const ActiveDevicesMediaCoordinator&) = delete; + ~ActiveDevicesMediaCoordinator() override; + + private: + void UpdateMediaCoordinatorList(); + + void GotDeviceIdsOpenedForWebContents( + std::vector<std::string> active_device_ids); + + void AddMediaCoordinatorForDevice( + const std::optional<std::string>& active_device_id); + + // MediaCaptureDevicesDispatcher::Observer impl. + void OnRequestUpdate(int render_process_id, + int render_frame_id, + blink::mojom::MediaStreamType stream_type, + const content::MediaRequestState state) override; + + std::vector<std::string> GetMediaCoordinatorKeys(); + + raw_ptr<content::WebContents> web_contents_; + MediaCoordinator::ViewType view_type_; + raw_ptr<views::View> parent_view_; + blink::mojom::MediaStreamType stream_type_; + raw_ptr<views::View> container_; + base::flat_map<std::string, std::unique_ptr<MediaCoordinator>> + media_coordinators_; +}; + +#endif // CHROME_BROWSER_UI_VIEWS_MEDIA_PREVIEW_ACTIVE_DEVICES_MEDIA_COORDINATOR_H_
diff --git a/chrome/browser/ui/views/media_preview/camera_preview/camera_coordinator.cc b/chrome/browser/ui/views/media_preview/camera_preview/camera_coordinator.cc index e1d44a21..901db5a 100644 --- a/chrome/browser/ui/views/media_preview/camera_preview/camera_coordinator.cc +++ b/chrome/browser/ui/views/media_preview/camera_preview/camera_coordinator.cc
@@ -13,11 +13,14 @@ #include "mojo/public/cpp/bindings/remote.h" #include "services/video_capture/public/mojom/video_source.mojom.h" -CameraCoordinator::CameraCoordinator(views::View& parent_view, - bool needs_borders) +CameraCoordinator::CameraCoordinator( + views::View& parent_view, + bool needs_borders, + const std::vector<std::string>& eligible_camera_ids) : camera_mediator_( base::BindRepeating(&CameraCoordinator::OnVideoSourceInfosReceived, - base::Unretained(this))) { + base::Unretained(this))), + eligible_camera_ids_(eligible_camera_ids) { auto* camera_view = parent_view.AddChildView(std::make_unique<MediaView>()); camera_view_tracker_.SetView(camera_view); // Safe to use base::Unretained() because `this` owns / outlives @@ -50,8 +53,12 @@ } std::vector<VideoSourceInfo> relevant_device_infos; - relevant_device_infos.reserve(device_infos.size()); for (const auto& device_info : device_infos) { + if (!eligible_camera_ids_.empty() && + !eligible_camera_ids_.contains(device_info.descriptor.device_id)) { + continue; + } + relevant_device_infos.emplace_back(device_info); }
diff --git a/chrome/browser/ui/views/media_preview/camera_preview/camera_coordinator.h b/chrome/browser/ui/views/media_preview/camera_preview/camera_coordinator.h index c280ad6..de4f6464 100644 --- a/chrome/browser/ui/views/media_preview/camera_preview/camera_coordinator.h +++ b/chrome/browser/ui/views/media_preview/camera_preview/camera_coordinator.h
@@ -19,7 +19,9 @@ // Maintains the lifetime of its views. class CameraCoordinator { public: - CameraCoordinator(views::View& parent_view, bool needs_borders); + CameraCoordinator(views::View& parent_view, + bool needs_borders, + const std::vector<std::string>& eligible_camera_ids); CameraCoordinator(const CameraCoordinator&) = delete; CameraCoordinator& operator=(const CameraCoordinator&) = delete; ~CameraCoordinator(); @@ -44,6 +46,7 @@ views::ViewTracker camera_view_tracker_; CameraSelectorComboboxModel combobox_model_; std::string active_device_id_; + base::flat_set<std::string> eligible_camera_ids_; std::optional<CameraViewController> camera_view_controller_; std::optional<VideoStreamCoordinator> video_stream_coordinator_; };
diff --git a/chrome/browser/ui/views/media_preview/camera_preview/camera_coordinator_unittest.cc b/chrome/browser/ui/views/media_preview/camera_preview/camera_coordinator_unittest.cc index a282ef4..ab1f51b6 100644 --- a/chrome/browser/ui/views/media_preview/camera_preview/camera_coordinator_unittest.cc +++ b/chrome/browser/ui/views/media_preview/camera_preview/camera_coordinator_unittest.cc
@@ -7,6 +7,7 @@ #include <stddef.h> #include <memory> +#include <optional> #include <string> #include "base/run_loop.h" @@ -14,6 +15,7 @@ #include "base/system/system_monitor.h" #include "base/test/gmock_callback_support.h" #include "base/test/mock_callback.h" +#include "base/test/test_future.h" #include "chrome/browser/ui/views/frame/test_with_browser_view.h" #include "chrome/grit/generated_resources.h" #include "components/media_effects/test/fake_video_capture_service.h" @@ -32,6 +34,22 @@ constexpr char kDeviceId2[] = "device_id_2"; constexpr char kDeviceName2[] = "device_name_2"; +MATCHER_P(HasItems, items, "") { + if (arg.GetItemCount() != items.size()) { + *result_listener << "item count is " << arg.GetItemCount(); + return false; + } + + for (size_t i = 0; i < items.size(); ++i) { + if (base::UTF8ToUTF16(items[i]) != arg.GetItemAt(i)) { + *result_listener << "item at index " << i << " is " << arg.GetItemAt(i); + return false; + } + } + + return true; +} + } // namespace class CameraCoordinatorTest : public TestWithBrowserView { @@ -41,10 +59,9 @@ content::OverrideVideoCaptureServiceForTesting( &fake_video_capture_service_); fake_video_capture_service_.SetOnGetVideoSourceCallback( - mock_video_source_callback_.Get()); - parent_view_ = std::make_unique<views::View>(); - coordinator_ = std::make_unique<CameraCoordinator>(*parent_view_, - /*needs_borders=*/true); + on_get_video_source_future_.GetRepeatingCallback()); + parent_view_.emplace(); + InitializeCoordinator(/*eligible_camera_ids=*/{}); } void TearDown() override { @@ -55,6 +72,12 @@ TestWithBrowserView::TearDown(); } + void InitializeCoordinator(std::vector<std::string> eligible_camera_ids) { + coordinator_.emplace(*parent_view_, + /*needs_borders=*/true, + /*eligible_camera_ids=*/eligible_camera_ids); + } + const CameraSelectorComboboxModel& GetComboboxModel() const { return coordinator_->GetComboboxModelForTest(); } @@ -69,82 +92,93 @@ l10n_util::GetStringUTF16(IDS_MEDIA_PREVIEW_NO_CAMERAS_FOUND_COMBOBOX)); } + bool AddFakeCamera(const media::VideoCaptureDeviceDescriptor& descriptor) { + replied_with_source_infos_future_.Clear(); + fake_video_capture_service_.SetOnRepliedWithSourceInfosCallback( + replied_with_source_infos_future_.GetCallback()); + fake_video_capture_service_.AddFakeCamera(descriptor); + return replied_with_source_infos_future_.WaitAndClear(); + } + + bool RemoveFakeCamera(const std::string& device_id) { + replied_with_source_infos_future_.Clear(); + fake_video_capture_service_.SetOnRepliedWithSourceInfosCallback( + replied_with_source_infos_future_.GetCallback()); + fake_video_capture_service_.RemoveFakeCamera(device_id); + return replied_with_source_infos_future_.WaitAndClear(); + } + base::SystemMonitor monitor_; - std::unique_ptr<views::View> parent_view_; - std::unique_ptr<CameraCoordinator> coordinator_; + std::optional<views::View> parent_view_; + std::optional<CameraCoordinator> coordinator_; media_effects::FakeVideoCaptureService fake_video_capture_service_; - base::MockCallback< - media_effects::FakeVideoSourceProvider::GetVideoSourceCallback> - mock_video_source_callback_; + base::test::TestFuture<void> replied_with_source_infos_future_; + base::test::TestFuture< + const std::string&, + mojo::PendingReceiver<video_capture::mojom::VideoSource>> + on_get_video_source_future_; }; TEST_F(CameraCoordinatorTest, RelevantVideoCaptureDeviceInfoExtraction) { VerifyEmptyCombobox(); // Add first camera, and connect to it. - // Camera connection is done automatically to the device at combobox's default + // camera connection is done automatically to the device at combobox's default // index (i.e. 0). - base::RunLoop run_loop; - EXPECT_CALL(mock_video_source_callback_, Run(kDeviceId, _)) - .WillOnce(base::test::RunOnceClosure(run_loop.QuitClosure())); - fake_video_capture_service_.AddFakeCamera({kDeviceName, kDeviceId}); - run_loop.Run(); - EXPECT_EQ(GetComboboxModel().GetItemCount(), size_t(1)); - EXPECT_EQ(GetComboboxModel().GetItemAt(/*index=*/0), - base::UTF8ToUTF16({kDeviceName})); + ASSERT_TRUE(AddFakeCamera({kDeviceName, kDeviceId})); + EXPECT_EQ(std::get<0>(on_get_video_source_future_.Take()), kDeviceId); + EXPECT_THAT(GetComboboxModel(), HasItems(std::vector{kDeviceName})); // Add second camera and connection to the first is not affected. - base::RunLoop run_loop2; - EXPECT_CALL(mock_video_source_callback_, Run).Times(0); - fake_video_capture_service_.SetOnRepliedWithSourceInfosCallback( - run_loop2.QuitClosure()); - fake_video_capture_service_.AddFakeCamera({kDeviceName2, kDeviceId2}); - run_loop2.Run(); - EXPECT_EQ(GetComboboxModel().GetItemCount(), size_t(2)); - EXPECT_EQ(GetComboboxModel().GetItemAt(/*index=*/0), - base::UTF8ToUTF16({kDeviceName})); - EXPECT_EQ(GetComboboxModel().GetItemAt(/*index=*/1), - base::UTF8ToUTF16({kDeviceName2})); + ASSERT_TRUE(AddFakeCamera({kDeviceName2, kDeviceId2})); + EXPECT_FALSE(on_get_video_source_future_.IsReady()); + EXPECT_THAT(GetComboboxModel(), + HasItems(std::vector{kDeviceName, kDeviceName2})); // Remove first camera, and connect to the second one. - base::RunLoop run_loop3; - EXPECT_CALL(mock_video_source_callback_, Run(kDeviceId2, _)) - .WillOnce(base::test::RunOnceClosure(run_loop3.QuitClosure())); - fake_video_capture_service_.RemoveFakeCamera(kDeviceId); - run_loop3.Run(); - EXPECT_EQ(GetComboboxModel().GetItemCount(), size_t(1)); - EXPECT_EQ(GetComboboxModel().GetItemAt(/*index=*/0), - base::UTF8ToUTF16({kDeviceName2})); + ASSERT_TRUE(RemoveFakeCamera(kDeviceId)); + EXPECT_EQ(std::get<0>(on_get_video_source_future_.Take()), kDeviceId2); + EXPECT_THAT(GetComboboxModel(), HasItems(std::vector{kDeviceName2})); // Re-add first camera and connect to it. - base::RunLoop run_loop4; - EXPECT_CALL(mock_video_source_callback_, Run(kDeviceId, _)) - .WillOnce(base::test::RunOnceClosure(run_loop4.QuitClosure())); - fake_video_capture_service_.AddFakeCamera({kDeviceName, kDeviceId}); - run_loop4.Run(); - EXPECT_EQ(GetComboboxModel().GetItemCount(), size_t(2)); - EXPECT_EQ(GetComboboxModel().GetItemAt(/*index=*/0), - base::UTF8ToUTF16({kDeviceName})); - EXPECT_EQ(GetComboboxModel().GetItemAt(/*index=*/1), - base::UTF8ToUTF16({kDeviceName2})); + ASSERT_TRUE(AddFakeCamera({kDeviceName, kDeviceId})); + EXPECT_EQ(std::get<0>(on_get_video_source_future_.Take()), kDeviceId); + EXPECT_THAT(GetComboboxModel(), + HasItems(std::vector{kDeviceName, kDeviceName2})); // Remove second camera, and connection to the first is not affected. - base::RunLoop run_loop5; - EXPECT_CALL(mock_video_source_callback_, Run).Times(0); - fake_video_capture_service_.SetOnRepliedWithSourceInfosCallback( - run_loop5.QuitClosure()); - fake_video_capture_service_.RemoveFakeCamera(kDeviceId2); - run_loop5.Run(); - EXPECT_EQ(GetComboboxModel().GetItemCount(), size_t(1)); - EXPECT_EQ(GetComboboxModel().GetItemAt(/*index=*/0), - base::UTF8ToUTF16({kDeviceName})); + ASSERT_TRUE(RemoveFakeCamera(kDeviceId2)); + EXPECT_FALSE(on_get_video_source_future_.IsReady()); + EXPECT_THAT(GetComboboxModel(), HasItems(std::vector{kDeviceName})); // Remove first camera. - base::RunLoop run_loop6; - fake_video_capture_service_.SetOnRepliedWithSourceInfosCallback( - run_loop6.QuitClosure()); - fake_video_capture_service_.RemoveFakeCamera(kDeviceId); - run_loop6.Run(); + ASSERT_TRUE(RemoveFakeCamera(kDeviceId)); + VerifyEmptyCombobox(); +} + +TEST_F(CameraCoordinatorTest, + RelevantVideoCaptureDeviceInfoExtraction_ConstrainedToEligibleDevices) { + InitializeCoordinator({kDeviceId2}); + VerifyEmptyCombobox(); + + // Add first camera. It won't be added to the combobox because it's not in the + // eligible list. + ASSERT_TRUE(AddFakeCamera({kDeviceName, kDeviceId})); + EXPECT_FALSE(on_get_video_source_future_.IsReady()); + VerifyEmptyCombobox(); + + // Add second camera and connect to it since it's in the eligible list. + ASSERT_TRUE(AddFakeCamera({kDeviceName2, kDeviceId2})); + EXPECT_EQ(std::get<0>(on_get_video_source_future_.Take()), kDeviceId2); + EXPECT_THAT(GetComboboxModel(), HasItems(std::vector{kDeviceName2})); + + // Remove first camera, nothing changes since it wasn't in the combobox. + ASSERT_TRUE(RemoveFakeCamera(kDeviceId)); + EXPECT_FALSE(on_get_video_source_future_.IsReady()); + EXPECT_THAT(GetComboboxModel(), HasItems(std::vector{kDeviceName2})); + + // Remove second camera. + ASSERT_TRUE(RemoveFakeCamera(kDeviceId2)); VerifyEmptyCombobox(); } @@ -152,56 +186,35 @@ VerifyEmptyCombobox(); // Add first camera, and connect to it. - base::RunLoop run_loop; - EXPECT_CALL(mock_video_source_callback_, Run(kDeviceId, _)) - .WillOnce(base::test::RunOnceClosure(run_loop.QuitClosure())); - fake_video_capture_service_.AddFakeCamera({kDeviceName, kDeviceId}); - run_loop.Run(); + ASSERT_TRUE(AddFakeCamera({kDeviceName, kDeviceId})); + EXPECT_EQ(std::get<0>(on_get_video_source_future_.Take()), kDeviceId); // Add second camera and connection to the first is not affected. - base::RunLoop run_loop2; - EXPECT_CALL(mock_video_source_callback_, Run).Times(0); - fake_video_capture_service_.SetOnRepliedWithSourceInfosCallback( - run_loop2.QuitClosure()); - fake_video_capture_service_.AddFakeCamera({kDeviceName2, kDeviceId2}); - run_loop2.Run(); + ASSERT_TRUE(AddFakeCamera({kDeviceName2, kDeviceId2})); + EXPECT_FALSE(on_get_video_source_future_.IsReady()); // Connect to the second camera. - base::RunLoop run_loop3; - EXPECT_CALL(mock_video_source_callback_, Run(kDeviceId2, _)) - .WillOnce(base::test::RunOnceClosure(run_loop3.QuitClosure())); coordinator_->OnVideoSourceChanged(/*selected_index=*/1); - run_loop3.Run(); + EXPECT_EQ(std::get<0>(on_get_video_source_future_.Take()), kDeviceId2); } TEST_F(CameraCoordinatorTest, TryConnectToSameDevice) { VerifyEmptyCombobox(); // Add camera, and connect to it. - base::RunLoop run_loop; - EXPECT_CALL(mock_video_source_callback_, Run(kDeviceId, _)) - .WillOnce(base::test::RunOnceClosure(run_loop.QuitClosure())); - fake_video_capture_service_.AddFakeCamera({kDeviceName, kDeviceId}); - run_loop.Run(); + ASSERT_TRUE(AddFakeCamera({kDeviceName, kDeviceId})); + EXPECT_EQ(std::get<0>(on_get_video_source_future_.Take()), kDeviceId); // Try connect to the camera. // Nothing is expected because we are already connected. - EXPECT_CALL(mock_video_source_callback_, Run).Times(0); coordinator_->OnVideoSourceChanged(/*selected_index=*/0); - base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(on_get_video_source_future_.IsReady()); // Remove camera. - base::RunLoop run_loop2; - fake_video_capture_service_.SetOnRepliedWithSourceInfosCallback( - run_loop2.QuitClosure()); - fake_video_capture_service_.RemoveFakeCamera(kDeviceId); - run_loop2.Run(); + ASSERT_TRUE(RemoveFakeCamera(kDeviceId)); VerifyEmptyCombobox(); // Add camera, and connect to it again. - base::RunLoop run_loop3; - EXPECT_CALL(mock_video_source_callback_, Run(kDeviceId, _)) - .WillOnce(base::test::RunOnceClosure(run_loop3.QuitClosure())); - fake_video_capture_service_.AddFakeCamera({kDeviceName, kDeviceId}); - run_loop3.Run(); + ASSERT_TRUE(AddFakeCamera({kDeviceName, kDeviceId})); + EXPECT_EQ(std::get<0>(on_get_video_source_future_.Take()), kDeviceId); }
diff --git a/chrome/browser/ui/views/media_preview/camera_preview/camera_view_controller.cc b/chrome/browser/ui/views/media_preview/camera_preview/camera_view_controller.cc index 5277fdd..8c381ec4 100644 --- a/chrome/browser/ui/views/media_preview/camera_preview/camera_view_controller.cc +++ b/chrome/browser/ui/views/media_preview/camera_preview/camera_view_controller.cc
@@ -34,7 +34,7 @@ void CameraViewController::UpdateVideoSourceInfos( std::vector<VideoSourceInfo> video_source_infos) { - bool has_devices = !video_source_infos.empty(); + auto video_source_info_count = video_source_infos.size(); combobox_model_->UpdateDeviceList(std::move(video_source_infos)); - base_controller_->AdjustComboboxEnabledState(has_devices); + base_controller_->OnDeviceListChanged(video_source_info_count); }
diff --git a/chrome/browser/ui/views/media_preview/media_coordinator.cc b/chrome/browser/ui/views/media_preview/media_coordinator.cc index 8bb7deae..3f3092c 100644 --- a/chrome/browser/ui/views/media_preview/media_coordinator.cc +++ b/chrome/browser/ui/views/media_preview/media_coordinator.cc
@@ -12,11 +12,21 @@ #include "ui/views/border.h" #include "ui/views/view.h" +MediaCoordinator::EligibleDevices::EligibleDevices() = default; +MediaCoordinator::EligibleDevices::EligibleDevices( + std::vector<std::string> cameras, + std::vector<std::string> mics) + : cameras(cameras), mics(mics) {} +MediaCoordinator::EligibleDevices::~EligibleDevices() = default; +MediaCoordinator::EligibleDevices::EligibleDevices(const EligibleDevices&) = + default; + MediaCoordinator::MediaCoordinator(ViewType view_type, views::View& parent_view, std::optional<size_t> index, - bool is_subsection) { - auto* media_view = + bool is_subsection, + EligibleDevices eligible_devices) { + media_view_ = parent_view.AddChildViewAt(std::make_unique<MediaView>(is_subsection), index.value_or(parent_view.children().size())); @@ -27,19 +37,29 @@ const int kBorderThickness = provider->GetDistanceMetric(views::DISTANCE_RELATED_CONTROL_VERTICAL); - media_view->SetBorder(views::CreateThemedRoundedRectBorder( + media_view_->SetBorder(views::CreateThemedRoundedRectBorder( kBorderThickness, kRoundedRadius, ui::kColorButtonBorder)); - media_view->SetBackground(views::CreateThemedRoundedRectBackground( + media_view_->SetBackground(views::CreateThemedRoundedRectBackground( ui::kColorButtonBorder, kRoundedRadius)); } if (view_type != ViewType::kMicOnly) { - camera_coordinator_.emplace(*media_view, /*needs_borders=*/!is_subsection); + camera_coordinator_.emplace(*media_view_, /*needs_borders=*/!is_subsection, + eligible_devices.cameras); } if (view_type != ViewType::kCameraOnly) { - mic_coordinator_.emplace(*media_view, /*needs_borders=*/!is_subsection); + mic_coordinator_.emplace(*media_view_, /*needs_borders=*/!is_subsection, + eligible_devices.mics); } } -MediaCoordinator::~MediaCoordinator() = default; +MediaCoordinator::~MediaCoordinator() { + // Reset child coordinators before removing view. + camera_coordinator_.reset(); + mic_coordinator_.reset(); + if (media_view_ && media_view_->parent()) { + media_view_->parent()->RemoveChildViewT( + std::exchange(media_view_, nullptr)); + } +}
diff --git a/chrome/browser/ui/views/media_preview/media_coordinator.h b/chrome/browser/ui/views/media_preview/media_coordinator.h index b6af350f..6cdbd2f 100644 --- a/chrome/browser/ui/views/media_preview/media_coordinator.h +++ b/chrome/browser/ui/views/media_preview/media_coordinator.h
@@ -8,6 +8,7 @@ #include <stddef.h> #include <optional> +#include <string> #include "chrome/browser/ui/views/media_preview/camera_preview/camera_coordinator.h" #include "chrome/browser/ui/views/media_preview/mic_preview/mic_coordinator.h" @@ -21,15 +22,30 @@ public: enum class ViewType { kBoth, kCameraOnly, kMicOnly }; + // Specifies a selected device. Non-empty strings will cause the preview to + // display only that device and disable the combobox. + struct EligibleDevices { + EligibleDevices(); + EligibleDevices(std::vector<std::string> cameras, + std::vector<std::string> mics); + ~EligibleDevices(); + EligibleDevices(const EligibleDevices&); + + std::vector<std::string> cameras; + std::vector<std::string> mics; + }; + MediaCoordinator(ViewType view_type, views::View& parent_view, std::optional<size_t> index, - bool is_subsection); + bool is_subsection, + EligibleDevices eligible_devices); MediaCoordinator(const MediaCoordinator&) = delete; MediaCoordinator& operator=(const MediaCoordinator&) = delete; ~MediaCoordinator(); private: + raw_ptr<views::View> media_view_ = nullptr; std::optional<CameraCoordinator> camera_coordinator_; std::optional<MicCoordinator> mic_coordinator_; };
diff --git a/chrome/browser/ui/views/media_preview/media_view_controller_base.cc b/chrome/browser/ui/views/media_preview/media_view_controller_base.cc index 5fcd45f..788d6b5 100644 --- a/chrome/browser/ui/views/media_preview/media_view_controller_base.cc +++ b/chrome/browser/ui/views/media_preview/media_view_controller_base.cc
@@ -69,10 +69,11 @@ device_selector_combobox_->SetCallback({}); } -void MediaViewControllerBase::AdjustComboboxEnabledState(bool has_devices) { +void MediaViewControllerBase::OnDeviceListChanged(size_t device_count) { + bool has_devices = device_count > 0; live_feed_container_->SetVisible(has_devices); no_device_connected_label_->SetVisible(!has_devices); - device_selector_combobox_->SetEnabled(has_devices); + device_selector_combobox_->SetEnabled(device_count > 1); if (has_devices) { OnComboboxSelection(); }
diff --git a/chrome/browser/ui/views/media_preview/media_view_controller_base.h b/chrome/browser/ui/views/media_preview/media_view_controller_base.h index 3525e06..ae08661 100644 --- a/chrome/browser/ui/views/media_preview/media_view_controller_base.h +++ b/chrome/browser/ui/views/media_preview/media_view_controller_base.h
@@ -46,9 +46,8 @@ // Returns the immediate parent view of the live camera/mic feeds. MediaView& GetLiveFeedContainer() { return live_feed_container_.get(); } - // Enables the combobox if there are connected devices (e.g.`has_devices` is - // true). - void AdjustComboboxEnabledState(bool has_devices); + // Enables the combobox if `device_count` > 1. + void OnDeviceListChanged(size_t device_count); private: friend class MediaViewControllerBaseTest;
diff --git a/chrome/browser/ui/views/media_preview/media_view_controller_base_unittest.cc b/chrome/browser/ui/views/media_preview/media_view_controller_base_unittest.cc index 47f5839..692ca287c 100644 --- a/chrome/browser/ui/views/media_preview/media_view_controller_base_unittest.cc +++ b/chrome/browser/ui/views/media_preview/media_view_controller_base_unittest.cc
@@ -16,6 +16,9 @@ #include "ui/views/controls/combobox/combobox.h" #include "ui/views/controls/label.h" +using testing::_; +using testing::Eq; + class MediaViewControllerBaseTest : public TestWithBrowserView { protected: void SetUp() override { @@ -45,14 +48,34 @@ std::unique_ptr<MediaViewControllerBase> controller_; }; -TEST_F(MediaViewControllerBaseTest, UpdateComboboxEnabledStateTest) { +TEST_F(MediaViewControllerBaseTest, OnDeviceListChanged_NoDevices) { EXPECT_TRUE(IsNoDeviceLabelVisible()); EXPECT_FALSE(IsComboboxEnabled()); - EXPECT_CALL(source_change_callback_, Run(testing::_)) - .WillOnce( - [](std::optional<size_t> index) { EXPECT_EQ(std::nullopt, index); }); - controller_->AdjustComboboxEnabledState(/*has_devices=*/true); + EXPECT_CALL(source_change_callback_, Run(_)).Times(0); + controller_->OnDeviceListChanged(/*device_count=*/0); + + EXPECT_TRUE(IsNoDeviceLabelVisible()); + EXPECT_FALSE(IsComboboxEnabled()); +} + +TEST_F(MediaViewControllerBaseTest, OnDeviceListChanged_OneDevice) { + EXPECT_TRUE(IsNoDeviceLabelVisible()); + EXPECT_FALSE(IsComboboxEnabled()); + + EXPECT_CALL(source_change_callback_, Run(Eq(std::nullopt))); + controller_->OnDeviceListChanged(/*device_count=*/1); + + EXPECT_FALSE(IsNoDeviceLabelVisible()); + EXPECT_FALSE(IsComboboxEnabled()); +} + +TEST_F(MediaViewControllerBaseTest, OnDeviceListChanged_MultipleDevices) { + EXPECT_TRUE(IsNoDeviceLabelVisible()); + EXPECT_FALSE(IsComboboxEnabled()); + + EXPECT_CALL(source_change_callback_, Run(Eq(std::nullopt))); + controller_->OnDeviceListChanged(/*device_count=*/2); EXPECT_FALSE(IsNoDeviceLabelVisible()); EXPECT_TRUE(IsComboboxEnabled());
diff --git a/chrome/browser/ui/views/media_preview/mic_preview/mic_coordinator.cc b/chrome/browser/ui/views/media_preview/mic_preview/mic_coordinator.cc index 95024aa..d2e78ade 100644 --- a/chrome/browser/ui/views/media_preview/mic_preview/mic_coordinator.cc +++ b/chrome/browser/ui/views/media_preview/mic_preview/mic_coordinator.cc
@@ -30,10 +30,13 @@ } // namespace -MicCoordinator::MicCoordinator(views::View& parent_view, bool needs_borders) +MicCoordinator::MicCoordinator(views::View& parent_view, + bool needs_borders, + const std::vector<std::string>& eligible_mic_ids) : mic_mediator_( base::BindRepeating(&MicCoordinator::OnAudioSourceInfosReceived, - base::Unretained(this))) { + base::Unretained(this))), + eligible_mic_ids_(eligible_mic_ids) { auto* mic_view = parent_view.AddChildView(std::make_unique<MediaView>()); mic_view_tracker_.SetView(mic_view); // Safe to use base::Unretained() because `this` owns / outlives @@ -72,6 +75,10 @@ media::AudioDeviceDescription::kDefaultDeviceId) { continue; } + if (!eligible_mic_ids_.empty() && + !eligible_mic_ids_.contains(device_info.unique_id)) { + continue; + } bool is_default = system_default_device_name && device_info.device_name == system_default_device_name.value();
diff --git a/chrome/browser/ui/views/media_preview/mic_preview/mic_coordinator.h b/chrome/browser/ui/views/media_preview/mic_preview/mic_coordinator.h index 3100201..7620b21 100644 --- a/chrome/browser/ui/views/media_preview/mic_preview/mic_coordinator.h +++ b/chrome/browser/ui/views/media_preview/mic_preview/mic_coordinator.h
@@ -24,7 +24,9 @@ // Maintains the lifetime of its views. class MicCoordinator { public: - MicCoordinator(views::View& parent_view, bool needs_borders); + MicCoordinator(views::View& parent_view, + bool needs_borders, + const std::vector<std::string>& eligible_mic_ids); MicCoordinator(const MicCoordinator&) = delete; MicCoordinator& operator=(const MicCoordinator&) = delete; ~MicCoordinator(); @@ -53,6 +55,7 @@ views::ViewTracker mic_view_tracker_; MicSelectorComboboxModel combobox_model_; std::string active_device_id_; + base::flat_set<std::string> eligible_mic_ids_; std::optional<MicViewController> mic_view_controller_; std::optional<AudioStreamCoordinator> audio_stream_coordinator_; };
diff --git a/chrome/browser/ui/views/media_preview/mic_preview/mic_coordinator_unittest.cc b/chrome/browser/ui/views/media_preview/mic_preview/mic_coordinator_unittest.cc index aa6b374..08d19664 100644 --- a/chrome/browser/ui/views/media_preview/mic_preview/mic_coordinator_unittest.cc +++ b/chrome/browser/ui/views/media_preview/mic_preview/mic_coordinator_unittest.cc
@@ -65,9 +65,8 @@ fake_audio_service_.SetOnRepliedWithInputDeviceDescriptionsCallback( replied_with_device_descriptions_future_.GetCallback()); - parent_view_ = std::make_unique<views::View>(); - coordinator_ = std::make_unique<MicCoordinator>(*parent_view_, - /*needs_borders=*/true); + parent_view_.emplace(); + InitializeCoordinator({}); ASSERT_TRUE(replied_with_device_descriptions_future_.WaitAndClear()); } @@ -76,6 +75,12 @@ TestWithBrowserView::TearDown(); } + void InitializeCoordinator(std::vector<std::string> eligible_mic_ids) { + coordinator_.emplace(*parent_view_, + /*needs_borders=*/true, + /*eligible_mic_ids=*/eligible_mic_ids); + } + const MicSelectorComboboxModel& GetComboboxModel() const { return coordinator_->GetComboboxModelForTest(); } @@ -90,6 +95,22 @@ l10n_util::GetStringUTF16(IDS_MEDIA_PREVIEW_NO_MICS_FOUND_COMBOBOX)); } + bool AddFakeInputDevice(const media::AudioDeviceDescription& descriptor) { + replied_with_device_descriptions_future_.Clear(); + fake_audio_service_.SetOnRepliedWithInputDeviceDescriptionsCallback( + replied_with_device_descriptions_future_.GetCallback()); + fake_audio_service_.AddFakeInputDevice(descriptor); + return replied_with_device_descriptions_future_.WaitAndClear(); + } + + bool RemoveFakeInputDevice(const std::string& device_id) { + replied_with_device_descriptions_future_.Clear(); + fake_audio_service_.SetOnRepliedWithInputDeviceDescriptionsCallback( + replied_with_device_descriptions_future_.GetCallback()); + fake_audio_service_.RemoveFakeInputDevice(device_id); + return replied_with_device_descriptions_future_.WaitAndClear(); + } + base::SystemMonitor monitor_; media_effects::FakeAudioService fake_audio_service_; std::optional<base::AutoReset<audio::mojom::AudioService*>> @@ -99,8 +120,8 @@ base::test::TestFuture<void> on_bind_stream_factory_future_; base::test::TestFuture<void> replied_with_device_descriptions_future_; - std::unique_ptr<views::View> parent_view_; - std::unique_ptr<MicCoordinator> coordinator_; + std::optional<views::View> parent_view_; + std::optional<MicCoordinator> coordinator_; }; TEST_F(MicCoordinatorTest, RelevantAudioInputDeviceInfoExtraction) { @@ -109,46 +130,64 @@ // Add first mic, and connect to it. // Mic connection is done automatically to the device at combobox's default // index (i.e. 0). - fake_audio_service_.AddFakeInputDevice({kDeviceName, kDeviceId, kGroupId}); + ASSERT_TRUE(AddFakeInputDevice({kDeviceName, kDeviceId, kGroupId})); ASSERT_TRUE(on_bind_stream_factory_future_.WaitAndClear()); EXPECT_EQ(on_input_stream_id_future_.Take(), kDeviceId); EXPECT_THAT(GetComboboxModel(), HasItems(std::vector{kDeviceName})); // Add second mic and connection to the first is not affected. - fake_audio_service_.SetOnRepliedWithInputDeviceDescriptionsCallback( - replied_with_device_descriptions_future_.GetCallback()); - fake_audio_service_.AddFakeInputDevice({kDeviceName2, kDeviceId2, kGroupId2}); - ASSERT_TRUE(replied_with_device_descriptions_future_.WaitAndClear()); + ASSERT_TRUE(AddFakeInputDevice({kDeviceName2, kDeviceId2, kGroupId2})); EXPECT_FALSE(on_input_stream_id_future_.IsReady()); EXPECT_THAT(GetComboboxModel(), HasItems(std::vector{kDeviceName, kDeviceName2})); // Remove first mic, and connect to the second one. - fake_audio_service_.RemoveFakeInputDevice(kDeviceId); + ASSERT_TRUE(RemoveFakeInputDevice(kDeviceId)); ASSERT_TRUE(on_bind_stream_factory_future_.WaitAndClear()); EXPECT_EQ(on_input_stream_id_future_.Take(), kDeviceId2); EXPECT_THAT(GetComboboxModel(), HasItems(std::vector{kDeviceName2})); // Re-add first mic and connect to it. - fake_audio_service_.AddFakeInputDevice({kDeviceName, kDeviceId, kGroupId}); + ASSERT_TRUE(AddFakeInputDevice({kDeviceName, kDeviceId, kGroupId})); ASSERT_TRUE(on_bind_stream_factory_future_.WaitAndClear()); EXPECT_EQ(on_input_stream_id_future_.Take(), kDeviceId); EXPECT_THAT(GetComboboxModel(), HasItems(std::vector{kDeviceName, kDeviceName2})); // Remove second mic, and connection to the first is not affected. - fake_audio_service_.SetOnRepliedWithInputDeviceDescriptionsCallback( - replied_with_device_descriptions_future_.GetCallback()); - fake_audio_service_.RemoveFakeInputDevice(kDeviceId2); - ASSERT_TRUE(replied_with_device_descriptions_future_.WaitAndClear()); + ASSERT_TRUE(RemoveFakeInputDevice(kDeviceId2)); EXPECT_FALSE(on_input_stream_id_future_.IsReady()); EXPECT_THAT(GetComboboxModel(), HasItems(std::vector{kDeviceName})); // Remove first mic. - fake_audio_service_.SetOnRepliedWithInputDeviceDescriptionsCallback( - replied_with_device_descriptions_future_.GetCallback()); - fake_audio_service_.RemoveFakeInputDevice(kDeviceId); - ASSERT_TRUE(replied_with_device_descriptions_future_.WaitAndClear()); + ASSERT_TRUE(RemoveFakeInputDevice(kDeviceId)); + VerifyEmptyCombobox(); +} + +TEST_F(MicCoordinatorTest, + RelevantAudioInputDeviceInfoExtraction_ConstrainedToEligibleDevices) { + InitializeCoordinator({kDeviceId2}); + VerifyEmptyCombobox(); + + // Add first mic. It won't be added to the combobox because it's not in the + // eligible list. + ASSERT_TRUE(AddFakeInputDevice({kDeviceName, kDeviceId, kGroupId})); + EXPECT_FALSE(on_input_stream_id_future_.IsReady()); + VerifyEmptyCombobox(); + + // Add second mic and connect to it since it's in the eligible list. + ASSERT_TRUE(AddFakeInputDevice({kDeviceName2, kDeviceId2, kGroupId2})); + ASSERT_TRUE(on_bind_stream_factory_future_.WaitAndClear()); + EXPECT_EQ(on_input_stream_id_future_.Take(), kDeviceId2); + EXPECT_THAT(GetComboboxModel(), HasItems(std::vector{kDeviceName2})); + + // Remove first mic, nothing changes since it wasn't in the combobox. + ASSERT_TRUE(RemoveFakeInputDevice(kDeviceId)); + EXPECT_FALSE(on_input_stream_id_future_.IsReady()); + EXPECT_THAT(GetComboboxModel(), HasItems(std::vector{kDeviceName2})); + + // Remove second mic. + ASSERT_TRUE(RemoveFakeInputDevice(kDeviceId2)); VerifyEmptyCombobox(); } @@ -156,15 +195,12 @@ VerifyEmptyCombobox(); // Add first mic, and connect to it. - fake_audio_service_.AddFakeInputDevice({kDeviceName, kDeviceId, kGroupId}); + ASSERT_TRUE(AddFakeInputDevice({kDeviceName, kDeviceId, kGroupId})); ASSERT_TRUE(on_bind_stream_factory_future_.WaitAndClear()); EXPECT_EQ(on_input_stream_id_future_.Take(), kDeviceId); // Add second mic and connection to the first is not affected. - fake_audio_service_.SetOnRepliedWithInputDeviceDescriptionsCallback( - replied_with_device_descriptions_future_.GetCallback()); - fake_audio_service_.AddFakeInputDevice({kDeviceName2, kDeviceId2, kGroupId2}); - ASSERT_TRUE(replied_with_device_descriptions_future_.WaitAndClear()); + ASSERT_TRUE(AddFakeInputDevice({kDeviceName2, kDeviceId2, kGroupId2})); EXPECT_FALSE(on_input_stream_id_future_.IsReady()); // Connect to the second mic. @@ -177,7 +213,7 @@ VerifyEmptyCombobox(); // Add mic, and connect to it. - fake_audio_service_.AddFakeInputDevice({kDeviceName, kDeviceId, kGroupId}); + ASSERT_TRUE(AddFakeInputDevice({kDeviceName, kDeviceId, kGroupId})); ASSERT_TRUE(on_bind_stream_factory_future_.WaitAndClear()); EXPECT_EQ(on_input_stream_id_future_.Take(), kDeviceId); @@ -188,14 +224,11 @@ EXPECT_FALSE(on_input_stream_id_future_.IsReady()); // Remove mic. - fake_audio_service_.SetOnRepliedWithInputDeviceDescriptionsCallback( - replied_with_device_descriptions_future_.GetCallback()); - fake_audio_service_.RemoveFakeInputDevice(kDeviceId); - ASSERT_TRUE(replied_with_device_descriptions_future_.WaitAndClear()); + ASSERT_TRUE(RemoveFakeInputDevice(kDeviceId)); VerifyEmptyCombobox(); // Add mic, and connect to it again. - fake_audio_service_.AddFakeInputDevice({kDeviceName, kDeviceId, kGroupId}); + ASSERT_TRUE(AddFakeInputDevice({kDeviceName, kDeviceId, kGroupId})); ASSERT_TRUE(on_bind_stream_factory_future_.WaitAndClear()); EXPECT_EQ(on_input_stream_id_future_.Take(), kDeviceId); } @@ -204,7 +237,7 @@ VerifyEmptyCombobox(); // Add mic, and connect to it. - fake_audio_service_.AddFakeInputDevice({kDeviceName, kDeviceId, kGroupId}); + ASSERT_TRUE(AddFakeInputDevice({kDeviceName, kDeviceId, kGroupId})); ASSERT_TRUE(on_bind_stream_factory_future_.WaitAndClear()); EXPECT_EQ(on_input_stream_id_future_.Take(), kDeviceId); EXPECT_THAT(GetComboboxModel(), HasItems(std::vector{kDeviceName})); @@ -213,11 +246,9 @@ // Add the same mic again with the default id. // One mic is expected to exist in the model with secondary text as default. - fake_audio_service_.SetOnRepliedWithInputDeviceDescriptionsCallback( - replied_with_device_descriptions_future_.GetCallback()); - fake_audio_service_.AddFakeInputDevice( - {kDeviceName, media::AudioDeviceDescription::kDefaultDeviceId, kGroupId}); - ASSERT_TRUE(replied_with_device_descriptions_future_.WaitAndClear()); + ASSERT_TRUE(AddFakeInputDevice( + {kDeviceName, media::AudioDeviceDescription::kDefaultDeviceId, + kGroupId})); EXPECT_FALSE(on_input_stream_id_future_.IsReady()); EXPECT_THAT(GetComboboxModel(), HasItems(std::vector{kDeviceName})); EXPECT_EQ(GetComboboxModel().GetDropDownSecondaryTextAt(/*index=*/0),
diff --git a/chrome/browser/ui/views/media_preview/mic_preview/mic_view_controller.cc b/chrome/browser/ui/views/media_preview/mic_preview/mic_view_controller.cc index baadda80..fbd9da0 100644 --- a/chrome/browser/ui/views/media_preview/mic_preview/mic_view_controller.cc +++ b/chrome/browser/ui/views/media_preview/mic_preview/mic_view_controller.cc
@@ -65,7 +65,7 @@ void MicViewController::UpdateAudioSourceInfos( std::vector<AudioSourceInfo> audio_source_infos) { - bool has_devices = !audio_source_infos.empty(); + auto audio_source_info_count = audio_source_infos.size(); combobox_model_->UpdateDeviceList(std::move(audio_source_infos)); - base_controller_->AdjustComboboxEnabledState(has_devices); + base_controller_->OnDeviceListChanged(audio_source_info_count); }
diff --git a/chrome/browser/ui/views/page_info/page_info_bubble_view.cc b/chrome/browser/ui/views/page_info/page_info_bubble_view.cc index 467a74b..0af24f2 100644 --- a/chrome/browser/ui/views/page_info/page_info_bubble_view.cc +++ b/chrome/browser/ui/views/page_info/page_info_bubble_view.cc
@@ -229,7 +229,7 @@ presenter_->RecordPageInfoAction( PageInfo::PageInfoAction::PAGE_INFO_PERMISSION_DIALOG_OPENED); std::unique_ptr<views::View> permissions_page_view = - view_factory_->CreatePermissionPageView(type); + view_factory_->CreatePermissionPageView(type, web_contents()); permissions_page_view->SetID( PageInfoViewFactory::VIEW_ID_PAGE_INFO_CURRENT_VIEW); page_container_->SwitchToPage(std::move(permissions_page_view));
diff --git a/chrome/browser/ui/views/page_info/page_info_permission_content_view.cc b/chrome/browser/ui/views/page_info/page_info_permission_content_view.cc index 937aa5b..7923e9a7 100644 --- a/chrome/browser/ui/views/page_info/page_info_permission_content_view.cc +++ b/chrome/browser/ui/views/page_info/page_info_permission_content_view.cc
@@ -28,8 +28,12 @@ PageInfoPermissionContentView::PageInfoPermissionContentView( PageInfo* presenter, ChromePageInfoUiDelegate* ui_delegate, - ContentSettingsType type) - : presenter_(presenter), type_(type), ui_delegate_(ui_delegate) { + ContentSettingsType type, + content::WebContents* web_contents) + : presenter_(presenter), + type_(type), + ui_delegate_(ui_delegate), + web_contents_(web_contents) { ChromeLayoutProvider* layout_provider = ChromeLayoutProvider::Get(); // Use the same insets as buttons and permission rows in the main page for @@ -209,7 +213,7 @@ auto view_type = type_ == ContentSettingsType::MEDIASTREAM_CAMERA ? MediaCoordinator::ViewType::kCameraOnly : MediaCoordinator::ViewType::kMicOnly; - media_preview_coordinator_.emplace(view_type, *this, /*index=*/std::nullopt, - /*is_subsection=*/true); + active_devices_media_preview_coordinator_.emplace(web_contents_, view_type, + /*parent_view=*/this); #endif }
diff --git a/chrome/browser/ui/views/page_info/page_info_permission_content_view.h b/chrome/browser/ui/views/page_info/page_info_permission_content_view.h index f3f39be..8b1baa9 100644 --- a/chrome/browser/ui/views/page_info/page_info_permission_content_view.h +++ b/chrome/browser/ui/views/page_info/page_info_permission_content_view.h
@@ -10,7 +10,7 @@ #include "ui/views/view.h" #if !BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_FUCHSIA) -#include "chrome/browser/ui/views/media_preview/media_coordinator.h" +#include "chrome/browser/ui/views/media_preview/active_devices_media_coordinator.h" #endif class ChromePageInfoUiDelegate; @@ -38,7 +38,8 @@ public: PageInfoPermissionContentView(PageInfo* presenter, ChromePageInfoUiDelegate* ui_delegate, - ContentSettingsType type); + ContentSettingsType type, + content::WebContents* web_contents); ~PageInfoPermissionContentView() override; // PageInfoUI implementations. @@ -60,6 +61,7 @@ ContentSettingsType type_; raw_ptr<ChromePageInfoUiDelegate> ui_delegate_ = nullptr; PageInfo::PermissionInfo permission_; + raw_ptr<content::WebContents> web_contents_ = nullptr; raw_ptr<NonAccessibleImageView> icon_ = nullptr; raw_ptr<views::Label> title_ = nullptr; @@ -68,7 +70,8 @@ raw_ptr<views::Checkbox> remember_setting_ = nullptr; #if !BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_FUCHSIA) - std::optional<MediaCoordinator> media_preview_coordinator_; + std::optional<ActiveDevicesMediaCoordinator> + active_devices_media_preview_coordinator_; #endif };
diff --git a/chrome/browser/ui/views/page_info/page_info_view_factory.cc b/chrome/browser/ui/views/page_info/page_info_view_factory.cc index 78e5e46..05bc896 100644 --- a/chrome/browser/ui/views/page_info/page_info_view_factory.cc +++ b/chrome/browser/ui/views/page_info/page_info_view_factory.cc
@@ -144,12 +144,13 @@ } std::unique_ptr<views::View> PageInfoViewFactory::CreatePermissionPageView( - ContentSettingsType type) { + ContentSettingsType type, + content::WebContents* web_contents) { return std::make_unique<PageInfoSubpageView>( CreateSubpageHeader(PageInfoUI::PermissionTypeToUIString(type), presenter_->GetSubjectNameForDisplay()), std::make_unique<PageInfoPermissionContentView>(presenter_, ui_delegate_, - type)); + type, web_contents)); } std::unique_ptr<views::View>
diff --git a/chrome/browser/ui/views/page_info/page_info_view_factory.h b/chrome/browser/ui/views/page_info/page_info_view_factory.h index 89a389f..4aeb222 100644 --- a/chrome/browser/ui/views/page_info/page_info_view_factory.h +++ b/chrome/browser/ui/views/page_info/page_info_view_factory.h
@@ -160,7 +160,8 @@ base::OnceClosure initialized_callback); [[nodiscard]] std::unique_ptr<views::View> CreateSecurityPageView(); [[nodiscard]] std::unique_ptr<views::View> CreatePermissionPageView( - ContentSettingsType type); + ContentSettingsType type, + content::WebContents* web_contents); [[nodiscard]] std::unique_ptr<views::View> CreateAdPersonalizationPageView(); [[nodiscard]] std::unique_ptr<views::View> CreateCookiesPageView();
diff --git a/chrome/browser/ui/views/permissions/permission_prompt_bubble_one_origin_view.cc b/chrome/browser/ui/views/permissions/permission_prompt_bubble_one_origin_view.cc index 7d5b9ea3..96a9c3324 100644 --- a/chrome/browser/ui/views/permissions/permission_prompt_bubble_one_origin_view.cc +++ b/chrome/browser/ui/views/permissions/permission_prompt_bubble_one_origin_view.cc
@@ -252,6 +252,7 @@ } media_preview_coordinator_.emplace(view_type.value(), *this, index, - /*is_subsection=*/false); + /*is_subsection=*/false, + MediaCoordinator::EligibleDevices{}); #endif }
diff --git a/chrome/browser/ui/webui/ash/login/core_oobe_handler.cc b/chrome/browser/ui/webui/ash/login/core_oobe_handler.cc index d3bfac49..3afa0d1d 100644 --- a/chrome/browser/ui/webui/ash/login/core_oobe_handler.cc +++ b/chrome/browser/ui/webui/ash/login/core_oobe_handler.cc
@@ -226,7 +226,7 @@ void CoreOobeHandler::HandleRaiseTabKeyEvent(bool reverse) { ui::KeyEvent event(ui::ET_KEY_PRESSED, ui::VKEY_TAB, ui::EF_NONE); if (reverse) { - event.set_flags(ui::EF_SHIFT_DOWN); + event.SetFlags(ui::EF_SHIFT_DOWN); } SendEventToSink(&event); }
diff --git a/chrome/browser/ui/webui/settings/people_handler.cc b/chrome/browser/ui/webui/settings/people_handler.cc index 498ff02..59aef1c 100644 --- a/chrome/browser/ui/webui/settings/people_handler.cc +++ b/chrome/browser/ui/webui/settings/people_handler.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/ui/webui/settings/people_handler.h" +#include <memory> #include <optional> #include <string> @@ -42,6 +43,7 @@ #include "chrome/common/url_constants.h" #include "chrome/common/webui_url_constants.h" #include "chrome/grit/generated_resources.h" +#include "components/prefs/pref_change_registrar.h" #include "components/prefs/pref_service.h" #include "components/signin/core/browser/signin_error_controller.h" #include "components/signin/public/base/consent_level.h" @@ -323,8 +325,9 @@ void PeopleHandler::OnJavascriptAllowed() { PrefService* prefs = profile_->GetPrefs(); - profile_pref_registrar_.Init(prefs); - profile_pref_registrar_.Add( + profile_pref_registrar_ = std::make_unique<PrefChangeRegistrar>(); + profile_pref_registrar_->Init(prefs); + profile_pref_registrar_->Add( prefs::kSigninAllowed, base::BindRepeating(&PeopleHandler::UpdateSyncStatus, base::Unretained(this))); @@ -343,7 +346,7 @@ } void PeopleHandler::OnJavascriptDisallowed() { - profile_pref_registrar_.RemoveAll(); + profile_pref_registrar_.reset(); identity_manager_observation_.Reset(); sync_service_observation_.Reset(); }
diff --git a/chrome/browser/ui/webui/settings/people_handler.h b/chrome/browser/ui/webui/settings/people_handler.h index 1a35db1..a598ab2 100644 --- a/chrome/browser/ui/webui/settings/people_handler.h +++ b/chrome/browser/ui/webui/settings/people_handler.h
@@ -250,7 +250,7 @@ std::unique_ptr<base::OneShotTimer> engine_start_timer_; // Used to listen for pref changes to allow or disallow signin. - PrefChangeRegistrar profile_pref_registrar_; + std::unique_ptr<PrefChangeRegistrar> profile_pref_registrar_; // Manages observer lifetimes. base::ScopedObservation<signin::IdentityManager,
diff --git a/chrome/browser/ui/webui/settings/performance_settings_interactive_uitest.cc b/chrome/browser/ui/webui/settings/performance_settings_interactive_uitest.cc index 3caf94f..3bfc450 100644 --- a/chrome/browser/ui/webui/settings/performance_settings_interactive_uitest.cc +++ b/chrome/browser/ui/webui/settings/performance_settings_interactive_uitest.cc
@@ -16,6 +16,7 @@ #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/performance_controls/test_support/battery_saver_browser_test_mixin.h" #include "chrome/browser/ui/performance_controls/test_support/memory_saver_interactive_test_mixin.h" +#include "chrome/browser/ui/performance_controls/test_support/webui_interactive_test_mixin.h" #include "chrome/browser/ui/tabs/tab_enums.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/webui/feedback/feedback_dialog.h" @@ -41,16 +42,9 @@ namespace { DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kPerformanceSettingsPage); DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kSecondTabContent); -DEFINE_LOCAL_CUSTOM_ELEMENT_EVENT_TYPE(kButtonWasClicked); -DEFINE_LOCAL_CUSTOM_ELEMENT_EVENT_TYPE(kElementRenders); DEFINE_LOCAL_CUSTOM_ELEMENT_EVENT_TYPE(kElementHides); -DEFINE_LOCAL_CUSTOM_ELEMENT_EVENT_TYPE(kIronCollapseContentShows); DEFINE_LOCAL_CUSTOM_ELEMENT_EVENT_TYPE(kExceptionDialogShows); -constexpr char kCheckJsElementIsChecked[] = "(el) => { return el.checked; }"; -constexpr char kCheckJsElementIsNotChecked[] = - "(el) => { return !el.checked; }"; - const WebContentsInteractionTestUtil::DeepQuery kMemorySaverToggleQuery = { "settings-ui", "settings-main", @@ -90,38 +84,14 @@ } // namespace class MemorySettingsInteractiveTest - : public MemorySaverInteractiveTestMixin<InteractiveBrowserTest> { + : public MemorySaverInteractiveTestMixin< + WebUiInteractiveTestMixin<InteractiveBrowserTest>> { public: void SetUpOnMainThread() override { MemorySaverInteractiveTestMixin::SetUpOnMainThread(); SetMemorySaverModeEnabled(true); } - auto WaitForElementToRender(const ui::ElementIdentifier& contents_id, - const DeepQuery& element) { - StateChange element_renders; - element_renders.event = kElementRenders; - element_renders.where = element; - element_renders.test_function = - "(el) => { if (el !== null) { let rect = el.getBoundingClientRect(); " - "return rect.width > 0 && rect.height > 0; } return false; }"; - - return WaitForStateChange(contents_id, element_renders); - } - - auto ClickElement(const ui::ElementIdentifier& contents_id, - const DeepQuery& element) { - return Steps(FlushEvents(), WaitForElementToRender(contents_id, element), - MoveMouseTo(contents_id, element), ClickMouse()); - } - - auto CheckTabCount(int expected_tab_count) { - auto get_tab_count = base::BindLambdaForTesting( - [this]() { return browser()->tab_strip_model()->GetTabCount(); }); - - return CheckResult(get_tab_count, expected_tab_count); - } - auto CheckMemorySaverModePrefState(MemorySaverModeState state) { return CheckResult( base::BindLambdaForTesting([]() { @@ -142,32 +112,6 @@ })); } - auto WaitForButtonStateChange(const ui::ElementIdentifier& contents_id, - DeepQuery element, - bool is_checked) { - StateChange toggle_selection_change; - toggle_selection_change.event = kButtonWasClicked; - toggle_selection_change.where = element; - toggle_selection_change.type = StateChange::Type::kExistsAndConditionTrue; - toggle_selection_change.test_function = - is_checked ? kCheckJsElementIsChecked : kCheckJsElementIsNotChecked; - - return WaitForStateChange(contents_id, toggle_selection_change); - } - - auto WaitForIronListCollapseStateChange(ui::ElementIdentifier webcontents_id, - DeepQuery query) { - StateChange iron_collapse_finish_animating; - iron_collapse_finish_animating.event = kIronCollapseContentShows; - iron_collapse_finish_animating.where = query; - iron_collapse_finish_animating.type = - StateChange::Type::kExistsAndConditionTrue; - iron_collapse_finish_animating.test_function = - "(el) => { return !el.transitioning; }"; - - return WaitForStateChange(webcontents_id, iron_collapse_finish_animating); - } - private: base::test::ScopedFeatureList scoped_feature_list_; }; @@ -178,8 +122,8 @@ NavigateWebContents(kPerformanceSettingsPage, GURL(chrome::kChromeUIPerformanceSettingsURL)), WaitForElementToRender(kPerformanceSettingsPage, kMemorySaverToggleQuery), - CheckJsResultAt(kPerformanceSettingsPage, kMemorySaverToggleQuery, - kCheckJsElementIsChecked), + WaitForButtonStateChange(kPerformanceSettingsPage, + kMemorySaverToggleQuery, true), // Turn Off Memory Saver Mode ClickElement(kPerformanceSettingsPage, kMemorySaverToggleQuery), @@ -210,7 +154,8 @@ GURL(chrome::kChromeUIPerformanceSettingsURL)), InstrumentNextTab(kLearnMorePage), ClickElement(kPerformanceSettingsPage, memory_saver_learn_more), - WaitForShow(kLearnMorePage), CheckTabCount(2), + WaitForShow(kLearnMorePage), + CheckResult([&]() { return browser()->tab_strip_model()->count(); }, 2), WaitForWebContentsReady(kLearnMorePage, GURL(chrome::kMemorySaverModeLearnMoreUrl))); } @@ -224,8 +169,8 @@ NavigateWebContents(kPerformanceSettingsPage, GURL(chrome::kChromeUIPerformanceSettingsURL)), WaitForElementToRender(kPerformanceSettingsPage, kMemorySaverToggleQuery), - CheckJsResultAt(kPerformanceSettingsPage, kMemorySaverToggleQuery, - kCheckJsElementIsChecked), + WaitForButtonStateChange(kPerformanceSettingsPage, + kMemorySaverToggleQuery, true), // Turn Off Memory Saver Mode ClickElement(kPerformanceSettingsPage, kMemorySaverToggleQuery), @@ -293,8 +238,8 @@ NavigateWebContents(kPerformanceSettingsPage, GURL(chrome::kChromeUIPerformanceSettingsURL)), WaitForElementToRender(kPerformanceSettingsPage, kMemorySaverToggleQuery), - CheckJsResultAt(kPerformanceSettingsPage, kMemorySaverToggleQuery, - kCheckJsElementIsChecked), + WaitForButtonStateChange(kPerformanceSettingsPage, + kMemorySaverToggleQuery, true), // Enable memory saver mode to discard tabs based on a timer ClickElement(kPerformanceSettingsPage, kDiscardOnTimerQuery), @@ -328,8 +273,8 @@ NavigateWebContents(kPerformanceSettingsPage, GURL(chrome::kChromeUIPerformanceSettingsURL)), WaitForElementToRender(kPerformanceSettingsPage, kMemorySaverToggleQuery), - CheckJsResultAt(kPerformanceSettingsPage, kMemorySaverToggleQuery, - kCheckJsElementIsChecked), + WaitForButtonStateChange(kPerformanceSettingsPage, + kMemorySaverToggleQuery, true), // Turn Off Memory Saver Mode ClickElement(kPerformanceSettingsPage, kMemorySaverToggleQuery), @@ -393,8 +338,8 @@ NavigateWebContents(kPerformanceSettingsPage, GURL(chrome::kChromeUIPerformanceSettingsURL)), WaitForElementToRender(kPerformanceSettingsPage, kMemorySaverToggleQuery), - CheckJsResultAt(kPerformanceSettingsPage, kMemorySaverToggleQuery, - kCheckJsElementIsChecked), + WaitForButtonStateChange(kPerformanceSettingsPage, + kMemorySaverToggleQuery, true), // Select discard on timer option ClickElement(kPerformanceSettingsPage, kDiscardOnTimerQuery), @@ -441,25 +386,14 @@ #if !BUILDFLAG(IS_CHROMEOS) class BatterySettingsInteractiveTest - : public BatterySaverBrowserTestMixin<InteractiveBrowserTest> { + : public BatterySaverBrowserTestMixin< + WebUiInteractiveTestMixin<InteractiveBrowserTest>> { public: base::BatteryLevelProvider::BatteryState GetFakeBatteryState() override { return base::test::TestBatteryLevelProvider::CreateBatteryState(1, true, 100); } - auto ClickElement(const ui::ElementIdentifier& contents_id, - const DeepQuery& element) { - return Steps(MoveMouseTo(contents_id, element), ClickMouse()); - } - - auto CheckTabCount(int expected_tab_count) { - auto get_tab_count = base::BindLambdaForTesting( - [this]() { return browser()->tab_strip_model()->GetTabCount(); }); - - return CheckResult(get_tab_count, expected_tab_count); - } - auto CheckBatteryStateLogged(const base::HistogramTester& histogram_tester, BatterySaverModeState state, int expected_count) { @@ -470,44 +404,6 @@ })); } - auto WaitForButtonStateChange(const ui::ElementIdentifier& contents_id, - DeepQuery element, - bool is_checked) { - StateChange toggle_selection_change; - toggle_selection_change.event = kButtonWasClicked; - toggle_selection_change.where = element; - toggle_selection_change.type = StateChange::Type::kExistsAndConditionTrue; - toggle_selection_change.test_function = - is_checked ? kCheckJsElementIsChecked : kCheckJsElementIsNotChecked; - - return WaitForStateChange(contents_id, toggle_selection_change); - } - - auto WaitForElementToRender(const ui::ElementIdentifier& contents_id, - const DeepQuery& element) { - StateChange element_renders; - element_renders.event = kElementRenders; - element_renders.where = element; - element_renders.type = StateChange::Type::kExistsAndConditionTrue; - element_renders.test_function = - "(el) => { return el.clientWidth > 0 && el.clientHeight > 0; }"; - - return WaitForStateChange(contents_id, element_renders); - } - - auto WaitForIronListCollapseStateChange(ui::ElementIdentifier webcontents_id, - DeepQuery query) { - StateChange iron_collapse_finish_animating; - iron_collapse_finish_animating.event = kIronCollapseContentShows; - iron_collapse_finish_animating.where = query; - iron_collapse_finish_animating.type = - StateChange::Type::kExistsAndConditionTrue; - iron_collapse_finish_animating.test_function = - "(el) => { return !el.transitioning; }"; - - return WaitForStateChange(webcontents_id, iron_collapse_finish_animating); - } - private: base::test::ScopedFeatureList scoped_feature_list_; }; @@ -525,7 +421,8 @@ GURL(chrome::kChromeUIPerformanceSettingsURL)), InstrumentNextTab(kLearnMorePage), ClickElement(kPerformanceSettingsPage, battery_saver_learn_more), - WaitForShow(kLearnMorePage), CheckTabCount(2), + WaitForShow(kLearnMorePage), + CheckResult([&]() { return browser()->tab_strip_model()->count(); }, 2), WaitForWebContentsReady(kLearnMorePage, GURL(chrome::kBatterySaverModeLearnMoreUrl))); } @@ -555,8 +452,8 @@ NavigateWebContents(kPerformanceSettingsPage, GURL(chrome::kChromeUIPerformanceSettingsURL)), WaitForElementToRender(kPerformanceSettingsPage, battery_saver_toggle), - CheckJsResultAt(kPerformanceSettingsPage, battery_saver_toggle, - kCheckJsElementIsChecked), + WaitForButtonStateChange(kPerformanceSettingsPage, battery_saver_toggle, + true), // Turn off Battery Saver Mode ClickElement(kPerformanceSettingsPage, battery_saver_toggle), @@ -610,7 +507,8 @@ #endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) #elif BUILDFLAG(IS_CHROMEOS_ASH) -class BatterySettingsInteractiveTest : public InteractiveAshTest { +class BatterySettingsInteractiveTest + : public WebUiInteractiveTestMixin<InteractiveAshTest> { public: BatterySettingsInteractiveTest() : scoped_feature_list_(ash::features::kBatterySaver) {} @@ -621,25 +519,6 @@ kForceDeviceHasBatterySwitch); } - auto WaitForElementToRender(const ui::ElementIdentifier& contents_id, - const DeepQuery& element) { - StateChange element_renders; - element_renders.event = kElementRenders; - element_renders.where = element; - element_renders.type = StateChange::Type::kExistsAndConditionTrue; - element_renders.test_function = - "(el) => { return el !== null && el.clientWidth > 0 && el.clientHeight " - "> 0; }"; - - return WaitForStateChange(contents_id, element_renders); - } - - auto ClickElement(const ui::ElementIdentifier& contents_id, - const DeepQuery& element) { - return Steps(WaitForElementToRender(contents_id, element), - MoveMouseTo(contents_id, element), ClickMouse()); - } - private: base::test::ScopedFeatureList scoped_feature_list_; }; @@ -672,13 +551,14 @@ #endif // BUILDFLAG(IS_CHROMEOS_ASH) class TabDiscardExceptionsSettingsInteractiveTest - : public MemorySettingsInteractiveTest { + : public MemorySaverInteractiveTestMixin< + WebUiInteractiveTestMixin<InteractiveBrowserTest>> { public: void SetUp() override { scoped_feature_list_.InitAndEnableFeature( performance_manager::features::kDiscardExceptionsImprovements); - MemorySettingsInteractiveTest::SetUp(); + MemorySaverInteractiveTestMixin::SetUp(); } auto WaitForElementToHide(const ui::ElementIdentifier& contents_id, @@ -735,10 +615,8 @@ toggle_selection_change.event = kButtonWasClicked; toggle_selection_change.where = element; toggle_selection_change.type = StateChange::Type::kExistsAndConditionTrue; - toggle_selection_change.test_function = - is_disabled ? "(el) => el.disabled === true" - : "(el) => el.disabled === false"; - + toggle_selection_change.test_function = base::StrCat( + {"(el) => el.disabled === ", is_disabled ? "true" : "false"}); return WaitForStateChange(contents_id, toggle_selection_change); }
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index 803c5d3..32a0b43 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1704304651-a17042d366bdc4880ce41120cbbea90368a15659.profdata +chrome-win32-main-1704315597-fccaab2d242c7d5139573163711577cac00087c5.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index 6740020..fb92dc6d 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1704304651-b9afcdcf1d41cfef4ad04b7b88c39224b9ee0f0d.profdata +chrome-win64-main-1704315597-bd9b2d46d75914af5e2333c5f67c85ad3892be4d.profdata
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index c07091a..6c7b2713 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -660,6 +660,7 @@ "../browser/ui/performance_controls/test_support/memory_saver_browser_test_mixin.h", "../browser/ui/performance_controls/test_support/memory_saver_interactive_test_mixin.h", "../browser/ui/performance_controls/test_support/user_education_browser_test_mixin.h", + "../browser/ui/performance_controls/test_support/webui_interactive_test_mixin.h", "../browser/ui/profiles/profile_ui_test_utils.h", "../browser/ui/safety_hub/safety_hub_test_util.cc", "../browser/ui/safety_hub/safety_hub_test_util.h",
diff --git a/chrome/test/data/webui/chromeos/BUILD.gn b/chrome/test/data/webui/chromeos/BUILD.gn index 6fdcd43..7968405 100644 --- a/chrome/test/data/webui/chromeos/BUILD.gn +++ b/chrome/test/data/webui/chromeos/BUILD.gn
@@ -180,7 +180,7 @@ "fake_network_config_mojom.js", "fake_passpoint_service_mojom.ts", "internet_config_dialog_test.js", - "internet_detail_dialog_test.js", + "internet_detail_dialog_test.ts", "mock_controller.js", "mock_controller.m.js", "mojo_webui_test_support.js", @@ -243,6 +243,9 @@ "chrome://chrome-signin/arc_account_picker/*|" + rebase_path("//chrome/browser/resources/chromeos/arc_account_picker/*", target_gen_dir), + "chrome://internet-detail-dialog/*|" + rebase_path( + "${root_gen_dir}/chrome/browser/resources/chromeos/internet_detail_dialog/tsc/*", + target_gen_dir), "chrome://webui-test/*|" + rebase_path("$root_gen_dir/chrome/test/data/webui/tsc/*", target_gen_dir), @@ -250,8 +253,10 @@ deps = [ "//ash/webui/common/resources:build_ts", + "//chrome/browser/resources/chromeos/internet_detail_dialog:build_ts", "//chrome/test/data/webui:build_ts", "//third_party/polymer/v3_0:library", + "//ui/webui/resources/cr_elements:build_ts", "//ui/webui/resources/js:build_ts", "//ui/webui/resources/mojo:build_ts", ]
diff --git a/chrome/test/data/webui/chromeos/ash_common/cr_elements/BUILD.gn b/chrome/test/data/webui/chromeos/ash_common/cr_elements/BUILD.gn index 8691314..f5d18fe 100644 --- a/chrome/test/data/webui/chromeos/ash_common/cr_elements/BUILD.gn +++ b/chrome/test/data/webui/chromeos/ash_common/cr_elements/BUILD.gn
@@ -10,14 +10,20 @@ "cr_action_menu_test.ts", "cr_button_test.ts", "cr_checkbox_test.ts", + "cr_container_shadow_mixin_test.ts", "cr_dialog_test.ts", "cr_expand_button_test.ts", "cr_icon_button_test.ts", "cr_input_test.ts", "cr_toast_manager_test.ts", "cr_toast_test.ts", + "i18n_mixin_test.ts", ] + # Using custom config to turn off useDefineForClassFields TS compiler flag + # which is necessary when defining Polymer elements. + ts_tsconfig_base = "tsconfig_base.json" + ts_deps = [ "//ash/webui/common/resources/cr_elements:build_ts", "//third_party/polymer/v3_0:library",
diff --git a/chrome/test/data/webui/chromeos/ash_common/cr_elements/ash_common_cr_elements_browsertest.cc b/chrome/test/data/webui/chromeos/ash_common/cr_elements/ash_common_cr_elements_browsertest.cc index 3d21466c..aa611939 100644 --- a/chrome/test/data/webui/chromeos/ash_common/cr_elements/ash_common_cr_elements_browsertest.cc +++ b/chrome/test/data/webui/chromeos/ash_common/cr_elements/ash_common_cr_elements_browsertest.cc
@@ -16,6 +16,11 @@ RunTest("chromeos/ash_common/cr_elements/cr_button_test.js", "mocha.run()"); } +IN_PROC_BROWSER_TEST_F(AshCommonCrElementsTest, CrContainerShadowMixin) { + RunTest("chromeos/ash_common/cr_elements/cr_container_shadow_mixin_test.js", + "mocha.run()"); +} + IN_PROC_BROWSER_TEST_F(AshCommonCrElementsTest, CrDialog) { RunTest("chromeos/ash_common/cr_elements/cr_dialog_test.js", "mocha.run()"); } @@ -38,3 +43,7 @@ RunTest("chromeos/ash_common/cr_elements/cr_toast_manager_test.js", "mocha.run()"); } + +IN_PROC_BROWSER_TEST_F(AshCommonCrElementsTest, I18nMixin) { + RunTest("chromeos/ash_common/cr_elements/i18n_mixin_test.js", "mocha.run()"); +}
diff --git a/chrome/test/data/webui/chromeos/ash_common/cr_elements/cr_container_shadow_mixin_test.ts b/chrome/test/data/webui/chromeos/ash_common/cr_elements/cr_container_shadow_mixin_test.ts new file mode 100644 index 0000000..6c34b04a --- /dev/null +++ b/chrome/test/data/webui/chromeos/ash_common/cr_elements/cr_container_shadow_mixin_test.ts
@@ -0,0 +1,74 @@ +// 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. + +// clang-format off +import {CrContainerShadowMixin} from 'chrome://resources/ash/common/cr_elements/cr_container_shadow_mixin.js'; +import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; +// clang-format on + +suite('CrContainerShadowBehavior', function() { + const TestElementBase = CrContainerShadowMixin(PolymerElement); + + class TestElement extends TestElementBase { + static get is() { + return 'test-element'; + } + + static get template() { + return html` + <style> + #container { + height: 50px; + } + </style> + <div id="before"></div> + <div id="container" show-bottom-shadow$="[[showBottomShadow]]"></div> + <div id="after"></div> + `; + } + + static get properties() { + return { + showBottomShadow: Boolean, + }; + } + + showBottomShadow: boolean = false; + } + + customElements.define(TestElement.is, TestElement); + + setup(function() { + document.body.innerHTML = window.trustedTypes!.emptyHTML; + }); + + test('no bottom shadow', function() { + const element = document.createElement('test-element') as TestElement; + document.body.appendChild(element); + + // Should not have a bottom shadow div. + assertFalse( + !!element.shadowRoot!.querySelector('#cr-container-shadow-bottom')); + assertTrue(!!element.shadowRoot!.querySelector('#cr-container-shadow-top')); + + element.showBottomShadow = true; + + // Still no bottom shadow since this is only checked in connectedCallback(); + assertFalse( + !!element.shadowRoot!.querySelector('#cr-container-shadow-bottom')); + assertTrue(!!element.shadowRoot!.querySelector('#cr-container-shadow-top')); + }); + + test('show bottom shadow', function() { + const element = document.createElement('test-element') as TestElement; + element.showBottomShadow = true; + document.body.appendChild(element); + + // Has both shadows. + assertTrue( + !!element.shadowRoot!.querySelector('#cr-container-shadow-bottom')); + assertTrue(!!element.shadowRoot!.querySelector('#cr-container-shadow-top')); + }); +});
diff --git a/chrome/test/data/webui/chromeos/ash_common/cr_elements/i18n_mixin_test.ts b/chrome/test/data/webui/chromeos/ash_common/cr_elements/i18n_mixin_test.ts new file mode 100644 index 0000000..7964dc9e --- /dev/null +++ b/chrome/test/data/webui/chromeos/ash_common/cr_elements/i18n_mixin_test.ts
@@ -0,0 +1,74 @@ +// 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. + +import {I18nMixin} from 'chrome://resources/ash/common/cr_elements/i18n_mixin.js'; +import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; +import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {assertEquals, assertFalse, assertThrows, assertTrue} from 'chrome://webui-test/chai_assert.js'; + +const TestElementBase = I18nMixin(PolymerElement); +class TestElement extends TestElementBase {} +customElements.define('test-element', TestElement); + +suite('I18nMixinTest', function() { + const allowedByDefault = '<a href="https://google.com">Google!</a>'; + const text = 'I\'m just text, nobody should have a problem with me!'; + const nonBreakingSpace = 'A\u00a0B\u00a0C'; // \u00a0 is a unicode nbsp. + + let testElement: TestElement; + + suiteSetup(function() { + loadTimeData.data = { + 'allowedByDefault': allowedByDefault, + 'customAttr': '<a is="action-link">Take action!</a>', + 'optionalTag': '<img>', + 'javascriptHref': '<a href="javascript:alert(1)">teh hax</a>', + 'script': '<script>alert(/xss/)</scr' + + 'ipt>', + 'text': text, + 'nonBreakingSpace': nonBreakingSpace, + }; + }); + + setup(function() { + document.body.innerHTML = window.trustedTypes!.emptyHTML; + testElement = document.createElement('test-element') as TestElement; + document.body.appendChild(testElement); + }); + + test('i18n', function() { + assertEquals(text, testElement.i18n('text')); + assertEquals(nonBreakingSpace, testElement.i18n('nonBreakingSpace')); + + assertThrows(function() { + testElement.i18n('customAttr'); + }); + assertThrows(function() { + testElement.i18n('optionalTag'); + }); + assertThrows(function() { + testElement.i18n('javascriptHref'); + }); + assertThrows(function() { + testElement.i18n('script'); + }); + }); + + test('i18n advanced', function() { + assertEquals( + allowedByDefault, + testElement.i18nAdvanced('allowedByDefault').toString()); + testElement.i18nAdvanced('customAttr', {attrs: ['is']}); + testElement.i18nAdvanced('optionalTag', {tags: ['img']}); + }); + + test('i18n dynamic', function() { + assertEquals(text, testElement.i18nDynamic('en', 'text')); + }); + + test('i18n exists', function() { + assertTrue(testElement.i18nExists('text')); + assertFalse(testElement.i18nExists('missingText')); + }); +});
diff --git a/chrome/test/data/webui/chromeos/ash_common/cr_elements/tsconfig_base.json b/chrome/test/data/webui/chromeos/ash_common/cr_elements/tsconfig_base.json new file mode 100644 index 0000000..b2ec655 --- /dev/null +++ b/chrome/test/data/webui/chromeos/ash_common/cr_elements/tsconfig_base.json
@@ -0,0 +1,6 @@ +{ + "extends": "../tsconfig_base.json", + "compilerOptions": { + "useDefineForClassFields": false + } +}
diff --git a/chrome/test/data/webui/chromeos/cloud_upload/BUILD.gn b/chrome/test/data/webui/chromeos/cloud_upload/BUILD.gn index 75f19f6..119e3da1 100644 --- a/chrome/test/data/webui/chromeos/cloud_upload/BUILD.gn +++ b/chrome/test/data/webui/chromeos/cloud_upload/BUILD.gn
@@ -25,7 +25,6 @@ "//chrome/browser/resources/chromeos/cloud_upload:build_ts", "//chrome/test/data/webui/chromeos:build_ts", "//third_party/cros-components:cros_components_ts", - "//ui/webui/resources/cr_elements:build_ts", "//ui/webui/resources/js:build_ts", ] }
diff --git a/chrome/test/data/webui/chromeos/internet_detail_dialog_test.js b/chrome/test/data/webui/chromeos/internet_detail_dialog_test.js deleted file mode 100644 index 1f59db0..0000000 --- a/chrome/test/data/webui/chromeos/internet_detail_dialog_test.js +++ /dev/null
@@ -1,542 +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 'chrome://internet-detail-dialog/internet_detail_dialog.js'; - -import {InternetDetailDialogBrowserProxyImpl} from 'chrome://internet-detail-dialog/internet_detail_dialog_browser_proxy.js'; -import {MojoInterfaceProviderImpl} from 'chrome://resources/ash/common/network/mojo_interface_provider.js'; -import {OncMojo} from 'chrome://resources/ash/common/network/onc_mojo.js'; -import {CrosNetworkConfigRemote, InhibitReason, MAX_NUM_CUSTOM_APNS} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/cros_network_config.mojom-webui.js'; -import {ConnectionStateType, DeviceStateType, NetworkType, OncSource, PortalState} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/network_types.mojom-webui.js'; -import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -import {FakeNetworkConfig} from 'chrome://webui-test/chromeos/fake_network_config_mojom.js'; -import {TestBrowserProxy} from 'chrome://webui-test/test_browser_proxy.js'; - -/** @implements {InternetDetailDialogBrowserProxy} */ -export class TestInternetDetailDialogBrowserProxy extends TestBrowserProxy { - constructor() { - super([ - 'getDialogArguments', - 'closeDialog', - 'showPortalSignin', - ]); - } - - /** @override */ - getDialogArguments() { - return JSON.stringify({guid: 'guid'}); - } - - /** @override */ - closeDialog() {} - - /** @override */ - showPortalSignin() {} -} - -suite('internet-detail-dialog', () => { - const guid = 'guid'; - const test_iccid = '11111111111111111'; - let internetDetailDialog = null; - - /** @type {?CrosNetworkConfigRemote} */ - let mojoApi_; - - suiteSetup(function() { - mojoApi_ = new FakeNetworkConfig(); - MojoInterfaceProviderImpl.getInstance().remote_ = mojoApi_; - }); - - function flushAsync() { - flush(); - // Use setTimeout to wait for the next macrotask. - return new Promise(resolve => setTimeout(resolve)); - } - - function getManagedProperties(type, opt_source) { - const result = OncMojo.getDefaultManagedProperties(type, guid, name); - if (opt_source) { - result.source = opt_source; - } - return result; - } - - setup(async () => { - PolymerTest.clearBody(); - InternetDetailDialogBrowserProxyImpl.setInstance( - new TestInternetDetailDialogBrowserProxy()); - mojoApi_.resetForTest(); - }); - - teardown(function() { - // If a previous test was run with Jelly, the css needs to be removed. - const old_elements = - document.querySelectorAll('link[href*=\'chrome://theme/colors.css\']'); - old_elements.forEach(function(node) { - node.remove(); - }); - assertFalse( - !!document.querySelector('link[href*=\'chrome://theme/colors.css\']')); - - document.body.classList.remove('jelly-enabled'); - }); - - async function init() { - internetDetailDialog = document.createElement('internet-detail-dialog'); - document.body.appendChild(internetDetailDialog); - await flushAsync(); - } - - async function setupCellularNetwork( - isPrimary, isInhibited, connectedApn, customApnList, errorState, - portalState) { - await mojoApi_.setNetworkTypeEnabledState(NetworkType.kCellular, true); - - const cellularNetwork = - getManagedProperties(NetworkType.kCellular, OncSource.kDevice); - cellularNetwork.typeProperties.cellular.iccid = test_iccid; - // Required for connectDisconnectButton to be rendered. - cellularNetwork.connectionState = isPrimary ? - ConnectionStateType.kConnected : - ConnectionStateType.kNotConnected; - // Required for networkChooseMobile to be rendered. - cellularNetwork.typeProperties.cellular.supportNetworkScan = true; - cellularNetwork.typeProperties.cellular.connectedApn = connectedApn; - cellularNetwork.typeProperties.cellular.customApnList = customApnList; - cellularNetwork.errorState = errorState; - cellularNetwork.portalState = portalState; - - mojoApi_.setManagedPropertiesForTest(cellularNetwork); - mojoApi_.setDeviceStateForTest({ - type: NetworkType.kCellular, - deviceState: DeviceStateType.kEnabled, - inhibitReason: - (isInhibited ? InhibitReason.kInstallingProfile : - InhibitReason.kNotInhibited), - simInfos: [{ - iccid: test_iccid, - isPrimary: isPrimary, - }], - }); - } - - function getElement(selector) { - const element = internetDetailDialog.$$(selector); - assertTrue(!!element); - return element; - } - - suite('captive portal ui updates', () => { - function getButton(buttonId) { - const button = - internetDetailDialog.shadowRoot.querySelector(`#${buttonId}`); - assertTrue(!!button); - return button; - } - - test('WiFi in a portal portalState', function() { - mojoApi_.setNetworkTypeEnabledState(NetworkType.kWiFi, true); - const wifiNetwork = getManagedProperties(NetworkType.kWiFi, 'wifi_user'); - wifiNetwork.source = OncSource.kUser; - wifiNetwork.connectable = true; - wifiNetwork.connectionState = ConnectionStateType.kPortal; - wifiNetwork.portalState = PortalState.kPortal; - - mojoApi_.setManagedPropertiesForTest(wifiNetwork); - init(); - return flushAsync().then(() => { - const networkStateText = - internetDetailDialog.shadowRoot.querySelector(`#networkState`); - assertTrue(networkStateText.hasAttribute('warning')); - assertEquals( - networkStateText.textContent.trim(), - internetDetailDialog.i18n('networkListItemSignIn')); - const signinButton = getButton('signinButton'); - assertTrue(!!signinButton); - assertFalse(signinButton.hasAttribute('hidden')); - assertFalse(signinButton.disabled); - }); - }); - - test('WiFi in a no internet portalState', function() { - mojoApi_.setNetworkTypeEnabledState(NetworkType.kWiFi, true); - const wifiNetwork = getManagedProperties(NetworkType.kWiFi, 'wifi_user'); - wifiNetwork.source = OncSource.kUser; - wifiNetwork.connectable = true; - wifiNetwork.connectionState = ConnectionStateType.kPortal; - wifiNetwork.portalState = PortalState.kNoInternet; - - mojoApi_.setManagedPropertiesForTest(wifiNetwork); - init(); - return flushAsync().then(() => { - const networkStateText = - internetDetailDialog.shadowRoot.querySelector(`#networkState`); - assertTrue(networkStateText.hasAttribute('warning')); - assertEquals( - networkStateText.textContent.trim(), - internetDetailDialog.i18n( - 'networkListItemConnectedNoConnectivity')); - const signinButton = getButton('signinButton'); - assertTrue(!!signinButton); - assertTrue(signinButton.hasAttribute('hidden')); - assertTrue(signinButton.disabled); - }); - }); - - test('WiFi in a proxy-auth portalState', function() { - mojoApi_.setNetworkTypeEnabledState(NetworkType.kWiFi, true); - const wifiNetwork = getManagedProperties(NetworkType.kWiFi, 'wifi_user'); - wifiNetwork.source = OncSource.kUser; - wifiNetwork.connectable = true; - wifiNetwork.connectionState = ConnectionStateType.kPortal; - wifiNetwork.portalState = PortalState.kProxyAuthRequired; - - mojoApi_.setManagedPropertiesForTest(wifiNetwork); - init(); - return flushAsync().then(() => { - const networkStateText = - internetDetailDialog.shadowRoot.querySelector(`#networkState`); - assertTrue(networkStateText.hasAttribute('warning')); - assertEquals( - networkStateText.textContent.trim(), - internetDetailDialog.i18n('networkListItemSignIn')); - const signinButton = getButton('signinButton'); - assertTrue(!!signinButton); - assertFalse(signinButton.hasAttribute('hidden')); - assertFalse(signinButton.disabled); - }); - }); - }); - - test('Network not on active sim, hide configurations', async () => { - await setupCellularNetwork(/*isPrimary=*/ false, /*isInhibited=*/ false); - - await init(); - assertFalse(internetDetailDialog.showConfigurableSections_); - - const managedProperties = internetDetailDialog.managedProperties_; - assertTrue(internetDetailDialog.showCellularSim_(managedProperties)); - assertFalse(!!internetDetailDialog.$$('network-siminfo')); - - // The 'Forget' and 'ConnectDisconnect' buttons should still be showing. - assertTrue(!!internetDetailDialog.$$('cr-button')); - }); - - test('Network on active sim, show configurations', async () => { - await setupCellularNetwork(/*isPrimary=*/ true, /*isInhibited=*/ false); - - await init(); - assertTrue(internetDetailDialog.showConfigurableSections_); - - const managedProperties = internetDetailDialog.managedProperties_; - assertTrue(internetDetailDialog.showCellularSim_(managedProperties)); - assertTrue(!!internetDetailDialog.$$('network-siminfo')); - }); - - test('Dialog disabled when inhibited', async () => { - // Start uninhibited. - await setupCellularNetwork(/*isPrimary=*/ true, /*isInhibited=*/ false); - await init(); - - const connectDisconnectButton = getElement('#connectDisconnect'); - const networkSimInfo = getElement('network-siminfo'); - const networkChooseMobile = getElement('network-choose-mobile'); - const networkApnlist = getElement('network-apnlist'); - const networkProxy = getElement('network-proxy'); - const networkIpConfig = getElement('network-ip-config'); - const networkNameservers = getElement('network-nameservers'); - const infoFields = getElement('network-property-list-mojo'); - - assertFalse(connectDisconnectButton.disabled); - assertFalse(networkSimInfo.disabled); - assertFalse(networkChooseMobile.disabled); - assertFalse(networkApnlist.disabled); - assertTrue(networkProxy.editable); - assertFalse(networkIpConfig.disabled); - assertFalse(networkNameservers.disabled); - assertFalse(infoFields.disabled); - - // Mock device being inhibited. - mojoApi_.setDeviceStateForTest({ - type: NetworkType.kCellular, - deviceState: DeviceStateType.kEnabled, - inhibitReason: InhibitReason.kInstallingProfile, - simInfos: [{ - iccid: test_iccid, - isPrimary: true, - }], - }); - await flushAsync(); - - assertTrue(connectDisconnectButton.disabled); - assertTrue(networkSimInfo.disabled); - assertTrue(networkChooseMobile.disabled); - assertTrue(networkApnlist.disabled); - assertFalse(networkProxy.editable); - assertTrue(networkIpConfig.disabled); - assertTrue(networkNameservers.disabled); - assertTrue(infoFields.disabled); - - // Uninhibit. - mojoApi_.setDeviceStateForTest({ - type: NetworkType.kCellular, - deviceState: DeviceStateType.kEnabled, - inhibitReason: InhibitReason.kNotInhibited, - simInfos: [{ - iccid: test_iccid, - isPrimary: true, - }], - }); - await flushAsync(); - - assertFalse(connectDisconnectButton.disabled); - assertFalse(networkSimInfo.disabled); - assertFalse(networkChooseMobile.disabled); - assertFalse(networkApnlist.disabled); - assertTrue(networkProxy.editable); - assertFalse(networkIpConfig.disabled); - assertFalse(networkNameservers.disabled); - assertFalse(infoFields.disabled); - }); - - // Syntactic sugar for running test twice with different values for the - // apnRevamp feature flag. - [true, false].forEach(isApnRevampEnabled => { - test('Show/Hide APN row correspondingly to ApnRevamp flag', async () => { - loadTimeData.overrideValues({ - apnRevamp: isApnRevampEnabled, - }); - const errorState = 'invalid-apn'; - await setupCellularNetwork( - /* isPrimary= */ true, /* isInhibited= */ false, - /* connectedApn= */ undefined, /* customApnList= */ undefined, - errorState, PortalState.kNoInternet); - - await init(); - const legacyApnElement = - internetDetailDialog.shadowRoot.querySelector('network-apnlist'); - const apnSection = - internetDetailDialog.shadowRoot.querySelector('cr-expand-button'); - - if (isApnRevampEnabled) { - assertFalse(!!legacyApnElement); - assertTrue(!!apnSection); - assertEquals( - internetDetailDialog.i18n('internetApnPageTitle'), - internetDetailDialog.shadowRoot.querySelector('#apnRowTitle') - .textContent); - const getApnSectionSublabel = () => - internetDetailDialog.shadowRoot.querySelector('#apnRowSublabel') - .textContent.trim(); - assertFalse(!!getApnSectionSublabel()); - const getApnList = () => - internetDetailDialog.shadowRoot.querySelector('apn-list'); - assertTrue(!!getApnList()); - assertTrue(getApnList().shouldOmitLinks); - assertEquals(errorState, getApnList().errorState); - assertEquals(PortalState.kNoInternet, getApnList().portalState); - const isApnListShowing = () => - internetDetailDialog.shadowRoot.querySelector('iron-collapse') - .opened; - assertFalse(isApnListShowing()); - - // Add a connected APN. - const accessPointName = 'access point name'; - await setupCellularNetwork( - /* isPrimary= */ true, /* isInhibited= */ false, - {accessPointName: accessPointName}); - - // Force a refresh. - internetDetailDialog.onDeviceStateListChanged(); - await flushAsync(); - assertEquals(accessPointName, getApnSectionSublabel()); - assertFalse( - internetDetailDialog.shadowRoot.querySelector('#apnRowSublabel') - .hasAttribute('warning')); - assertFalse(isApnListShowing()); - - // Update the APN's name property and add a restricted connectivity - // state. - const name = 'name'; - await setupCellularNetwork( - /* isPrimary= */ true, /* isInhibited= */ false, - {accessPointName: accessPointName, name: name}, - /* customApnList= */ undefined, /* errorState= */ undefined, - PortalState.kNoInternet); - - // Force a refresh. - internetDetailDialog.onDeviceStateListChanged(); - await flushAsync(); - assertEquals(name, getApnSectionSublabel()); - assertTrue( - internetDetailDialog.shadowRoot.querySelector('#apnRowSublabel') - .hasAttribute('warning')); - assertFalse(isApnListShowing()); - - // Expand the section, the sublabel should no longer show. - apnSection.click(); - await flushAsync(); - assertFalse(!!getApnSectionSublabel()); - assertTrue(isApnListShowing()); - - // Collapse the section, the sublabel should show. - apnSection.click(); - await flushAsync(); - assertEquals(name, getApnSectionSublabel()); - assertFalse(isApnListShowing()); - } else { - assertTrue(!!legacyApnElement); - assertFalse(!!apnSection); - } - }); - }); - - test( - 'Disable and show tooltip for New APN button when custom APNs limit is' + - ' reached', - async () => { - loadTimeData.overrideValues({ - apnRevamp: true, - }); - await setupCellularNetwork( - /* isPrimary= */ true, /* isInhibited= */ false, - {accessPointName: 'access point name'}, []); - await init(); - internetDetailDialog.shadowRoot.querySelector('cr-expand-button') - .click(); - - const getApnButton = () => - internetDetailDialog.shadowRoot.querySelector( - '#createCustomApnButton'); - const getApnTooltip = () => - internetDetailDialog.shadowRoot.querySelector('#apnTooltip'); - - assertTrue(!!getApnButton()); - assertFalse(!!getApnTooltip()); - assertFalse(getApnButton().disabled); - - // We're setting the list of APNs to the max number - await setupCellularNetwork( - /* isPrimary= */ true, /* isInhibited= */ false, - {accessPointName: 'access point name'}, - Array.apply(null, {length: MAX_NUM_CUSTOM_APNS}).map(_ => { - return { - accessPointName: 'apn', - }; - })); - internetDetailDialog.onDeviceStateListChanged(); - await flushAsync(); - - assertTrue(!!getApnTooltip()); - assertTrue(getApnButton().disabled); - assertTrue(getApnTooltip().innerHTML.includes( - internetDetailDialog.i18n('customApnLimitReached'))); - - await setupCellularNetwork( - /* isPrimary= */ true, /* isInhibited= */ false, - {accessPointName: 'access point name'}, []); - internetDetailDialog.onDeviceStateListChanged(); - await flushAsync(); - - assertFalse(!!getApnTooltip()); - assertFalse(getApnButton().disabled); - - getApnButton().click(); - await flushAsync(); - assertTrue(!!internetDetailDialog.shadowRoot.querySelector('apn-list') - .shadowRoot.querySelector('apn-detail-dialog')); - }); - - [false, true].forEach(isJellyEnabled => { - test('Dynamic theme CSS is added when isJellyEnabled is set', async () => { - loadTimeData.overrideValues({ - isJellyEnabled: isJellyEnabled, - }); - await setupCellularNetwork( - /*isPrimary=*/ true, /*isInhibited=*/ false); - await init(); - - const linkEl = - document.querySelector('link[href*=\'chrome://theme/colors.css\']'); - if (isJellyEnabled) { - assertTrue(!!linkEl); - assertTrue(document.body.classList.contains('jelly-enabled')); - } else { - assertEquals(null, linkEl); - assertFalse(document.body.classList.contains('jelly-enabled')); - } - }); - }); - - test('Show toast on show-error-toast event', async function() { - loadTimeData.overrideValues({ - apnRevamp: true, - }); - await init(); - const getErrorToast = () => - internetDetailDialog.shadowRoot.querySelector('#errorToast'); - assertFalse(getErrorToast().open); - - const message = 'Toast message'; - const event = new CustomEvent('show-error-toast', {detail: message}); - internetDetailDialog.dispatchEvent(event); - await flushAsync(); - assertTrue(getErrorToast().open); - assertEquals( - internetDetailDialog.shadowRoot.querySelector('#errorToastMessage') - .innerHTML, - message); - }); - - test( - 'Dont show toast on show-error-toast event when ApnRevamp false', - async function() { - loadTimeData.overrideValues({ - apnRevamp: false, - }); - await init(); - const getErrorToast = () => - internetDetailDialog.shadowRoot.querySelector('#errorToast'); - assertFalse(!!getErrorToast()); - - const message = 'Toast message'; - const event = new CustomEvent('show-error-toast', {detail: message}); - internetDetailDialog.dispatchEvent(event); - await flushAsync(); - assertFalse(!!getErrorToast()); - }); - - test('MacAddress not shown when invalid', async function() { - mojoApi_.setNetworkTypeEnabledState(NetworkType.kWiFi, true); - const wifiNetwork = getManagedProperties(NetworkType.kWiFi, 'wifi_user'); - wifiNetwork.source = OncSource.kUser; - wifiNetwork.connectable = true; - wifiNetwork.connectionState = ConnectionStateType.kConnected; - - mojoApi_.setManagedPropertiesForTest(wifiNetwork); - mojoApi_.setDeviceStateForTest({ - type: NetworkType.kWiFi, - deviceState: DeviceStateType.kEnabled, - macAddress: '01:10:10:10:10:10', - }); - await flushAsync(); - - init(); - await flushAsync(); - let macAddress = getElement('#macAddress'); - - assertTrue(!!macAddress); - assertFalse(macAddress.hidden); - - mojoApi_.setDeviceStateForTest({ - type: NetworkType.kWiFi, - deviceState: DeviceStateType.kEnabled, - macAddress: '00:00:00:00:00:00', - }); - await flushAsync(); - - macAddress = getElement('#macAddress'); - assertTrue(macAddress.hidden); - }); -});
diff --git a/chrome/test/data/webui/chromeos/internet_detail_dialog_test.ts b/chrome/test/data/webui/chromeos/internet_detail_dialog_test.ts new file mode 100644 index 0000000..6f05992 --- /dev/null +++ b/chrome/test/data/webui/chromeos/internet_detail_dialog_test.ts
@@ -0,0 +1,601 @@ +// 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 'chrome://internet-detail-dialog/internet_detail_dialog.js'; + +import {InternetDetailDialogElement} from 'chrome://internet-detail-dialog/internet_detail_dialog.js'; +import {InternetDetailDialogBrowserProxy, InternetDetailDialogBrowserProxyImpl} from 'chrome://internet-detail-dialog/internet_detail_dialog_browser_proxy.js'; +import {ApnList} from 'chrome://resources/ash/common/network/apn_list.js'; +import {MojoInterfaceProviderImpl} from 'chrome://resources/ash/common/network/mojo_interface_provider.js'; +import {NetworkApnListElement} from 'chrome://resources/ash/common/network/network_apnlist.js'; +import {NetworkChooseMobileElement} from 'chrome://resources/ash/common/network/network_choose_mobile.js'; +import {NetworkIpConfigElement} from 'chrome://resources/ash/common/network/network_ip_config.js'; +import {NetworkNameserversElement} from 'chrome://resources/ash/common/network/network_nameservers.js'; +import {NetworkPropertyListMojoElement} from 'chrome://resources/ash/common/network/network_property_list_mojo.js'; +import {NetworkProxyElement} from 'chrome://resources/ash/common/network/network_proxy.js'; +import {NetworkSiminfoElement} from 'chrome://resources/ash/common/network/network_siminfo.js'; +import {OncMojo} from 'chrome://resources/ash/common/network/onc_mojo.js'; +import {CrButtonElement} from 'chrome://resources/cr_elements/cr_button/cr_button.js'; +import {CrToastElement} from 'chrome://resources/cr_elements/cr_toast/cr_toast.js'; +import {assert} from 'chrome://resources/js/assert.js'; +import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; +import {ApnAuthenticationType, ApnIpType, ApnProperties, ApnState, ApnType, InhibitReason, MAX_NUM_CUSTOM_APNS, SIMInfo} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/cros_network_config.mojom-webui.js'; +import {ConnectionStateType, DeviceStateType, NetworkType, OncSource, PortalState} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/network_types.mojom-webui.js'; +import {IronCollapseElement} from 'chrome://resources/polymer/v3_0/iron-collapse/iron-collapse.js'; +import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; +import {TestBrowserProxy} from 'chrome://webui-test/test_browser_proxy.js'; + +import {FakeNetworkConfig} from './fake_network_config_mojom.js'; + +export class TestInternetDetailDialogBrowserProxy extends TestBrowserProxy + implements InternetDetailDialogBrowserProxy { + constructor() { + super([ + 'getDialogArguments', + 'closeDialog', + 'showPortalSignin', + ]); + } + + getDialogArguments() { + return JSON.stringify({guid: 'guid'}); + } + + closeDialog() {} + + showPortalSignin() {} +} + +suite('internet-detail-dialog', () => { + const guid = 'guid'; + const testIccid = '11111111111111111'; + let internetDetailDialog: InternetDetailDialogElement; + + let mojoApi: FakeNetworkConfig; + + suiteSetup(function() { + mojoApi = new FakeNetworkConfig(); + MojoInterfaceProviderImpl.getInstance().setMojoServiceRemoteForTest( + mojoApi); + }); + + function flushAsync() { + flush(); + // Use setTimeout to wait for the next macrotask. + return new Promise(resolve => setTimeout(resolve)); + } + + function getManagedProperties( + type: NetworkType, name?: string, source?: OncSource) { + const result = + OncMojo.getDefaultManagedProperties(type, guid, name ? name : ''); + if (source) { + result.source = source; + } + return result; + } + + setup(async () => { + assert(window.trustedTypes); + document.body.innerHTML = window.trustedTypes.emptyHTML; + InternetDetailDialogBrowserProxyImpl.setInstance( + new TestInternetDetailDialogBrowserProxy()); + mojoApi.resetForTest(); + }); + + teardown(function() { + // If a previous test was run with Jelly, the css needs to be removed. + const old_elements = + document.querySelectorAll('link[href*=\'chrome://theme/colors.css\']'); + old_elements.forEach(function(node) { + node.remove(); + }); + assertFalse( + !!document.querySelector('link[href*=\'chrome://theme/colors.css\']')); + + document.body.classList.remove('jelly-enabled'); + }); + + async function init() { + internetDetailDialog = document.createElement('internet-detail-dialog'); + document.body.appendChild(internetDetailDialog); + await flushAsync(); + } + + async function setupCellularNetwork( + isPrimary: boolean, isInhibited: boolean, connectedApn?: ApnProperties, + customApnList?: ApnProperties[], errorState?: string, + portalState?: PortalState) { + await mojoApi.setNetworkTypeEnabledState(NetworkType.kCellular, true); + + const cellularNetwork = getManagedProperties( + NetworkType.kCellular, /*name=*/ undefined, OncSource.kDevice); + if (cellularNetwork.typeProperties.cellular) { + cellularNetwork.typeProperties.cellular.iccid = testIccid; + // Required for networkChooseMobile to be rendered. + cellularNetwork.typeProperties.cellular.supportNetworkScan = true; + cellularNetwork.typeProperties.cellular.connectedApn = connectedApn; + cellularNetwork.typeProperties.cellular.customApnList = customApnList; + } + // Required for connectDisconnectButton to be rendered. + cellularNetwork.connectionState = isPrimary ? + ConnectionStateType.kConnected : + ConnectionStateType.kNotConnected; + cellularNetwork.errorState = errorState; + if (portalState) { + cellularNetwork.portalState = portalState; + } + + mojoApi.setManagedPropertiesForTest(cellularNetwork); + setDeviceState( + NetworkType.kCellular, DeviceStateType.kEnabled, + (isInhibited ? InhibitReason.kInstallingProfile : + InhibitReason.kNotInhibited), + [{ + iccid: testIccid, + isPrimary: isPrimary, + slotId: 1, + eid: 'eid', + }]); + } + + function setDeviceState( + type: NetworkType, deviceState: DeviceStateType, + inhibitReason?: InhibitReason, simInfos?: SIMInfo[], + macAddress?: string) { + mojoApi.setDeviceStateForTest({ + type: type, + deviceState: deviceState, + inhibitReason: inhibitReason ? inhibitReason : + InhibitReason.kNotInhibited, + simInfos: simInfos ? simInfos : undefined, + ipv4Address: undefined, + ipv6Address: undefined, + imei: undefined, + macAddress: macAddress, + scanning: false, + simLockStatus: undefined, + simAbsent: false, + managedNetworkAvailable: false, + serial: undefined, + isCarrierLocked: false, + }); + } + + function createApn(accessPointName: string, name?: string) { + return { + accessPointName: accessPointName, + id: undefined, + authentication: ApnAuthenticationType.kAutomatic, + language: undefined, + localizedName: undefined, + name: name, + password: undefined, + username: undefined, + attach: undefined, + state: ApnState.kEnabled, + ipType: ApnIpType.kAutomatic, + apnTypes: [ApnType.kDefault], + }; + } + + function getElement<T extends HTMLElement = HTMLElement>(selector: string): + T { + const element = internetDetailDialog.shadowRoot!.querySelector<T>(selector); + assert(element); + return element; + } + + suite('captive portal ui updates', () => { + function getButton(buttonId: string): CrButtonElement { + const button = + internetDetailDialog.shadowRoot!.querySelector<CrButtonElement>( + `#${buttonId}`); + assertTrue(!!button); + return button; + } + + test('WiFi in a portal portalState', function() { + mojoApi.setNetworkTypeEnabledState(NetworkType.kWiFi, true); + const wifiNetwork = getManagedProperties(NetworkType.kWiFi, 'wifi_user'); + wifiNetwork.source = OncSource.kUser; + wifiNetwork.connectable = true; + wifiNetwork.connectionState = ConnectionStateType.kPortal; + wifiNetwork.portalState = PortalState.kPortal; + + mojoApi.setManagedPropertiesForTest(wifiNetwork); + init(); + return flushAsync().then(() => { + const networkStateText = getElement('#networkState'); + assertTrue(networkStateText.hasAttribute('warning')); + assert(networkStateText.textContent); + assertEquals( + networkStateText.textContent.trim(), + internetDetailDialog.i18n('networkListItemSignIn')); + const signinButton = getButton('signinButton'); + assertTrue(!!signinButton); + assertFalse(signinButton.hasAttribute('hidden')); + assertFalse(signinButton.disabled); + }); + }); + + test('WiFi in a no internet portalState', function() { + mojoApi.setNetworkTypeEnabledState(NetworkType.kWiFi, true); + const wifiNetwork = getManagedProperties(NetworkType.kWiFi, 'wifi_user'); + wifiNetwork.source = OncSource.kUser; + wifiNetwork.connectable = true; + wifiNetwork.connectionState = ConnectionStateType.kPortal; + wifiNetwork.portalState = PortalState.kNoInternet; + + mojoApi.setManagedPropertiesForTest(wifiNetwork); + init(); + return flushAsync().then(() => { + const networkStateText = getElement('#networkState'); + assertTrue(networkStateText.hasAttribute('warning')); + assert(networkStateText.textContent); + assertEquals( + networkStateText.textContent.trim(), + internetDetailDialog.i18n( + 'networkListItemConnectedNoConnectivity')); + const signinButton = getButton('signinButton'); + assertTrue(!!signinButton); + assertTrue(signinButton.hasAttribute('hidden')); + assertTrue(signinButton.disabled); + }); + }); + + test('WiFi in a proxy-auth portalState', function() { + mojoApi.setNetworkTypeEnabledState(NetworkType.kWiFi, true); + const wifiNetwork = getManagedProperties(NetworkType.kWiFi, 'wifi_user'); + wifiNetwork.source = OncSource.kUser; + wifiNetwork.connectable = true; + wifiNetwork.connectionState = ConnectionStateType.kPortal; + wifiNetwork.portalState = PortalState.kProxyAuthRequired; + + mojoApi.setManagedPropertiesForTest(wifiNetwork); + init(); + return flushAsync().then(() => { + const networkStateText = getElement('#networkState'); + assertTrue(networkStateText.hasAttribute('warning')); + assert(networkStateText.textContent); + assertEquals( + networkStateText.textContent.trim(), + internetDetailDialog.i18n('networkListItemSignIn')); + const signinButton = getButton('signinButton'); + assertTrue(!!signinButton); + assertFalse(signinButton.hasAttribute('hidden')); + assertFalse(signinButton.disabled); + }); + }); + }); + + test('Network not on active sim, hide configurations', async () => { + await setupCellularNetwork(/*isPrimary=*/ false, /*isInhibited=*/ false); + + await init(); + assertFalse( + !!internetDetailDialog.shadowRoot!.querySelector<HTMLElement>('.hr')); + + assertFalse(!!internetDetailDialog.shadowRoot!.querySelector<HTMLElement>( + 'network-siminfo')); + + // The 'Forget' and 'ConnectDisconnect' buttons should still be showing. + assertTrue(!!internetDetailDialog.shadowRoot!.querySelector<HTMLElement>( + 'cr-button')); + }); + + test('Network on active sim, show configurations', async () => { + await setupCellularNetwork(/*isPrimary=*/ true, /*isInhibited=*/ false); + + await init(); + assertTrue( + !!internetDetailDialog.shadowRoot!.querySelector<HTMLElement>('.hr')); + + assertTrue(!!internetDetailDialog.shadowRoot!.querySelector<HTMLElement>( + 'network-siminfo')); + }); + + test('Dialog disabled when inhibited', async () => { + // Start uninhibited. + await setupCellularNetwork(/*isPrimary=*/ true, /*isInhibited=*/ false); + await init(); + + const connectDisconnectButton = + getElement<CrButtonElement>('#connectDisconnect'); + const networkSimInfo = getElement<NetworkSiminfoElement>('network-siminfo'); + const networkChooseMobile = + getElement<NetworkChooseMobileElement>('network-choose-mobile'); + const networkApnlist = getElement<NetworkApnListElement>('network-apnlist'); + const networkProxy = getElement<NetworkProxyElement>('network-proxy'); + const networkIpConfig = + getElement<NetworkIpConfigElement>('network-ip-config'); + const networkNameservers = + getElement<NetworkNameserversElement>('network-nameservers'); + const infoFields = getElement<NetworkPropertyListMojoElement>( + 'network-property-list-mojo'); + + assertFalse(connectDisconnectButton.disabled); + assertFalse(networkSimInfo.disabled); + assertFalse(networkChooseMobile.disabled); + assertFalse(networkApnlist.disabled); + assertTrue(networkProxy.editable); + assertFalse(networkIpConfig.disabled); + assertFalse(networkNameservers.disabled); + assertFalse(infoFields.disabled); + + // Mock device being inhibited. + setDeviceState( + NetworkType.kCellular, + DeviceStateType.kEnabled, + InhibitReason.kInstallingProfile, + [{ + iccid: testIccid, + isPrimary: true, + slotId: 1, + eid: 'eid', + }], + ); + await flushAsync(); + + assertTrue(connectDisconnectButton.disabled); + assertTrue(networkSimInfo.disabled); + assertTrue(networkChooseMobile.disabled); + assertTrue(networkApnlist.disabled); + assertFalse(networkProxy.editable); + assertTrue(networkIpConfig.disabled); + assertTrue(networkNameservers.disabled); + assertTrue(infoFields.disabled); + + // Uninhibit. + setDeviceState( + NetworkType.kCellular, + DeviceStateType.kEnabled, + InhibitReason.kNotInhibited, + [{ + iccid: testIccid, + isPrimary: true, + slotId: 1, + eid: 'eid', + }], + ); + await flushAsync(); + + assertFalse(connectDisconnectButton.disabled); + assertFalse(networkSimInfo.disabled); + assertFalse(networkChooseMobile.disabled); + assertFalse(networkApnlist.disabled); + assertTrue(networkProxy.editable); + assertFalse(networkIpConfig.disabled); + assertFalse(networkNameservers.disabled); + assertFalse(infoFields.disabled); + }); + + // Syntactic sugar for running test twice with different values for the + // apnRevamp feature flag. + [true, false].forEach(isApnRevampEnabled => { + test('Show/Hide APN row correspondingly to ApnRevamp flag', async () => { + loadTimeData.overrideValues({ + apnRevamp: isApnRevampEnabled, + }); + const errorState = 'invalid-apn'; + await setupCellularNetwork( + /* isPrimary= */ true, /* isInhibited= */ false, + /* connectedApn= */ undefined, /* customApnList= */ undefined, + errorState, PortalState.kNoInternet); + + await init(); + const legacyApnElement = + internetDetailDialog.shadowRoot!.querySelector('network-apnlist'); + const apnSection = + internetDetailDialog.shadowRoot!.querySelector('cr-expand-button'); + + if (isApnRevampEnabled) { + assertFalse(!!legacyApnElement); + assertTrue(!!apnSection); + assertEquals( + internetDetailDialog.i18n('internetApnPageTitle'), + getElement('#apnRowTitle').textContent); + const apnRowSublabel = getElement('#apnRowSublabel'); + const getApnSectionSublabel = () => { + assert(apnRowSublabel.textContent); + return apnRowSublabel.textContent.trim(); + }; + + assertFalse(!!getApnSectionSublabel()); + const getApnList = () => getElement<ApnList>('apn-list'); + assertTrue(getApnList().shouldOmitLinks); + assertEquals(errorState, getApnList().errorState); + assertEquals(PortalState.kNoInternet, getApnList().portalState); + const isApnListShowing = () => + getElement<IronCollapseElement>('iron-collapse').opened; + + assertFalse(isApnListShowing()); + + // Add a connected APN. + const accessPointName = 'access point name'; + await setupCellularNetwork( + /* isPrimary= */ true, /* isInhibited= */ false, + createApn(accessPointName)); + + // Force a refresh. + internetDetailDialog.onDeviceStateListChanged(); + await flushAsync(); + assertEquals(accessPointName, getApnSectionSublabel()); + assertFalse(apnRowSublabel.hasAttribute('warning')); + assertFalse(isApnListShowing()); + + // Update the APN's name property and add a restricted connectivity + // state. + const name = 'name'; + await setupCellularNetwork( + /* isPrimary= */ true, /* isInhibited= */ false, + createApn(accessPointName, name), + /* customApnList= */ undefined, /* errorState= */ undefined, + PortalState.kNoInternet); + + // Force a refresh. + internetDetailDialog.onDeviceStateListChanged(); + await flushAsync(); + assertEquals(name, getApnSectionSublabel()); + assertTrue(apnRowSublabel.hasAttribute('warning')); + assertFalse(isApnListShowing()); + + // Expand the section, the sublabel should no longer show. + apnSection.click(); + await flushAsync(); + assertFalse(!!getApnSectionSublabel()); + assertTrue(isApnListShowing()); + + // Collapse the section, the sublabel should show. + apnSection.click(); + await flushAsync(); + assertEquals(name, getApnSectionSublabel()); + assertFalse(isApnListShowing()); + } else { + assertTrue(!!legacyApnElement); + assertFalse(!!apnSection); + } + }); + }); + + test( + 'Disable and show tooltip for New APN button when custom APNs limit is' + + ' reached', + async () => { + loadTimeData.overrideValues({ + apnRevamp: true, + }); + await setupCellularNetwork( + /* isPrimary= */ true, /* isInhibited= */ false, + createApn(/*accessPointName=*/ 'access point name'), []); + await init(); + getElement('cr-expand-button').click(); + + const getApnButton = () => + getElement<CrButtonElement>('#createCustomApnButton'); + + const getApnTooltip = () => + internetDetailDialog.shadowRoot!.querySelector('#apnTooltip'); + + assertTrue(!!getApnButton()); + assertFalse(!!getApnTooltip()); + assertFalse(getApnButton().disabled); + + // We're setting the list of APNs to the max number + await setupCellularNetwork( + /* isPrimary= */ true, /* isInhibited= */ false, + createApn(/*accessPointName=*/ 'access point name'), + Array(MAX_NUM_CUSTOM_APNS) + .fill(createApn(/*accessPointName=*/ 'apn'))); + internetDetailDialog.onDeviceStateListChanged(); + await flushAsync(); + + assertTrue(getApnButton().disabled); + const apnTooltip = getApnTooltip(); + assert(apnTooltip); + assertTrue(apnTooltip.innerHTML.includes( + internetDetailDialog.i18n('customApnLimitReached'))); + + await setupCellularNetwork( + /* isPrimary= */ true, /* isInhibited= */ false, + createApn(/*accessPointName=*/ 'access point name'), []); + internetDetailDialog.onDeviceStateListChanged(); + await flushAsync(); + + assertFalse(!!getApnTooltip()); + assertFalse(getApnButton().disabled); + + getApnButton().click(); + await flushAsync(); + assertTrue(!!getElement('apn-list') + .shadowRoot!.querySelector('apn-detail-dialog')); + }); + + [false, true].forEach(isJellyEnabled => { + test('Dynamic theme CSS is added when isJellyEnabled is set', async () => { + loadTimeData.overrideValues({ + isJellyEnabled: isJellyEnabled, + }); + await setupCellularNetwork( + /*isPrimary=*/ true, /*isInhibited=*/ false); + await init(); + + const linkEl = + document.querySelector('link[href*=\'chrome://theme/colors.css\']'); + if (isJellyEnabled) { + assertTrue(!!linkEl); + assertTrue(document.body.classList.contains('jelly-enabled')); + } else { + assertEquals(null, linkEl); + assertFalse(document.body.classList.contains('jelly-enabled')); + } + }); + }); + + test('Show toast on show-error-toast event', async function() { + loadTimeData.overrideValues({ + apnRevamp: true, + }); + await init(); + const getErrorToast = () => getElement<CrToastElement>('#errorToast'); + assertFalse(getErrorToast().open); + + const message = 'Toast message'; + const event = new CustomEvent('show-error-toast', {detail: message}); + internetDetailDialog.dispatchEvent(event); + await flushAsync(); + assertTrue(getErrorToast().open); + assertEquals(getElement('#errorToastMessage').innerHTML, message); + }); + + test( + 'Dont show toast on show-error-toast event when ApnRevamp false', + async function() { + loadTimeData.overrideValues({ + apnRevamp: false, + }); + await init(); + const getErrorToast = () => + internetDetailDialog.shadowRoot!.querySelector('#errorToast'); + assertFalse(!!getErrorToast()); + + const message = 'Toast message'; + const event = new CustomEvent('show-error-toast', {detail: message}); + internetDetailDialog.dispatchEvent(event); + await flushAsync(); + assertFalse(!!getErrorToast()); + }); + + test('MacAddress not shown when invalid', async function() { + mojoApi.setNetworkTypeEnabledState(NetworkType.kWiFi, true); + const wifiNetwork = getManagedProperties(NetworkType.kWiFi, 'wifi_user'); + wifiNetwork.source = OncSource.kUser; + wifiNetwork.connectable = true; + wifiNetwork.connectionState = ConnectionStateType.kConnected; + + mojoApi.setManagedPropertiesForTest(wifiNetwork); + setDeviceState( + NetworkType.kWiFi, DeviceStateType.kEnabled, + /*inhibitReason=*/ undefined, /*simInfos=*/ undefined, + /*macAddress=*/ '01:10:10:10:10:10'); + await flushAsync(); + + init(); + await flushAsync(); + let macAddress = getElement('#macAddress'); + + assertTrue(!!macAddress); + assertFalse(macAddress.hidden); + + setDeviceState( + NetworkType.kWiFi, DeviceStateType.kEnabled, + /*inhibitReason=*/ undefined, /*simInfos=*/ undefined, + /*macAddress=*/ '00:00:00:00:00:00'); + await flushAsync(); + + macAddress = getElement('#macAddress'); + assertTrue(macAddress.hidden); + }); +});
diff --git a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/activation_code_page_test.js b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/activation_code_page_test.js index 7611590..d481e96 100644 --- a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/activation_code_page_test.js +++ b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/activation_code_page_test.js
@@ -101,8 +101,9 @@ await enumerateDeviceResolvedPromise; } - test('Page description', async function () { - const description = activationCodePage.$$('#description'); + test('Page description', async function() { + const description = + activationCodePage.shadowRoot.querySelector('#description'); assertTrue(!!description); // Mock camera on @@ -115,7 +116,7 @@ // Clearing devices to test without camera mediaDevices.removeDevice(); - await resolveEnumeratedDevicesPromise(); + await resolveEnumeratedDevicesPromise(); activationCodePage.showNoProfilesFound = true; assertEquals(description.innerText.trim(), loadTimeData.getString('enterActivationCodeNoProfilesFound')); @@ -125,20 +126,27 @@ }); test('UI states', async function() { - let qrCodeDetectorContainer = activationCodePage.$$('#esimQrCodeDetection'); + let qrCodeDetectorContainer = + activationCodePage.shadowRoot.querySelector('#esimQrCodeDetection'); const activationCodeContainer = - activationCodePage.$$('#activationCodeContainer'); - const video = activationCodePage.$$('#video'); + activationCodePage.shadowRoot.querySelector('#activationCodeContainer'); + const video = activationCodePage.shadowRoot.querySelector('#video'); const startScanningContainer = - activationCodePage.$$('#startScanningContainer'); - const startScanningButton = activationCodePage.$$('#startScanningButton'); - const scanFinishContainer = activationCodePage.$$('#scanFinishContainer'); - const switchCameraButton = activationCodePage.$$('#switchCameraButton'); + activationCodePage.shadowRoot.querySelector('#startScanningContainer'); + const startScanningButton = + activationCodePage.shadowRoot.querySelector('#startScanningButton'); + const scanFinishContainer = + activationCodePage.shadowRoot.querySelector('#scanFinishContainer'); + const switchCameraButton = + activationCodePage.shadowRoot.querySelector('#switchCameraButton'); const getUseCameraAgainButton = () => { - return activationCodePage.$$('#useCameraAgainButton'); + return activationCodePage.shadowRoot.querySelector( + '#useCameraAgainButton'); }; - const scanSuccessContainer = activationCodePage.$$('#scanSuccessContainer'); - const scanFailureContainer = activationCodePage.$$('#scanFailureContainer'); + const scanSuccessContainer = + activationCodePage.shadowRoot.querySelector('#scanSuccessContainer'); + const scanFailureContainer = + activationCodePage.shadowRoot.querySelector('#scanFailureContainer'); assertTrue(!!qrCodeDetectorContainer); assertTrue(!!activationCodeContainer); @@ -150,7 +158,8 @@ assertFalse(!!getUseCameraAgainButton()); assertTrue(!!scanSuccessContainer); assertTrue(!!scanFailureContainer); - assertFalse(!!activationCodePage.$$('paper-spinner-lite')); + assertFalse( + !!activationCodePage.shadowRoot.querySelector('paper-spinner-lite')); // Initial state should only be showing the start scanning UI. assertFalse(startScanningContainer.hidden); @@ -158,7 +167,8 @@ assertTrue(video.hidden); assertTrue(scanFinishContainer.hidden); assertTrue(switchCameraButton.hidden); - assertFalse(!!activationCodePage.$$('paper-spinner-lite')); + assertFalse( + !!activationCodePage.shadowRoot.querySelector('paper-spinner-lite')); // Click the start scanning button. startScanningButton.click(); @@ -191,7 +201,7 @@ assertFalse(activationCodePage.showError); // Simulate typing in the input. - activationCodePage.$$('#activationCode') + activationCodePage.shadowRoot.querySelector('#activationCode') .dispatchEvent(new KeyboardEvent('keydown', {key: 'A'})); await flushAsync(); @@ -201,11 +211,13 @@ assertTrue(video.hidden); assertTrue(scanFinishContainer.hidden); assertTrue(switchCameraButton.hidden); - assertFalse(!!activationCodePage.$$('paper-spinner-lite')); + assertFalse( + !!activationCodePage.shadowRoot.querySelector('paper-spinner-lite')); activationCodePage.showBusy = true; await flushAsync(); - assertTrue(!!activationCodePage.$$('paper-spinner-lite')); + assertTrue( + !!activationCodePage.shadowRoot.querySelector('paper-spinner-lite')); // Mock, no media devices present mediaDevices.removeDevice(); @@ -213,15 +225,18 @@ // When no camera device is present qrCodeDetector container should // not be shown - qrCodeDetectorContainer = activationCodePage.$$('#esimQrCodeDetection'); + qrCodeDetectorContainer = + activationCodePage.shadowRoot.querySelector('#esimQrCodeDetection'); assertFalse(!!qrCodeDetectorContainer); }); test('Switch camera button states', async function() { - const video = activationCodePage.$$('#video'); - const startScanningButton = activationCodePage.$$('#startScanningButton'); - const switchCameraButton = activationCodePage.$$('#switchCameraButton'); + const video = activationCodePage.shadowRoot.querySelector('#video'); + const startScanningButton = + activationCodePage.shadowRoot.querySelector('#startScanningButton'); + const switchCameraButton = + activationCodePage.shadowRoot.querySelector('#switchCameraButton'); assertTrue(!!video); assertTrue(!!startScanningButton); @@ -290,10 +305,14 @@ }); test('UI is disabled when showBusy property is set', async function() { - const startScanningButton = activationCodePage.$$('#startScanningButton'); - const switchCameraButton = activationCodePage.$$('#switchCameraButton'); - const tryAgainButton = activationCodePage.$$('#tryAgainButton'); - const input = activationCodePage.$$('#activationCode'); + const startScanningButton = + activationCodePage.shadowRoot.querySelector('#startScanningButton'); + const switchCameraButton = + activationCodePage.shadowRoot.querySelector('#switchCameraButton'); + const tryAgainButton = + activationCodePage.shadowRoot.querySelector('#tryAgainButton'); + const input = + activationCodePage.shadowRoot.querySelector('#activationCode'); assertTrue(!!startScanningButton); assertTrue(!!switchCameraButton); @@ -317,11 +336,12 @@ 'Do not show qrContainer when BarcodeDetector is not ready', async function() { let qrCodeDetectorContainer = - activationCodePage.$$('#esimQrCodeDetection'); + activationCodePage.shadowRoot.querySelector('#esimQrCodeDetection'); assertTrue(!!qrCodeDetectorContainer); // Activation code input should be at the bottom of the page. - assertTrue(activationCodePage.$$('#activationCodeContainer') + assertTrue(activationCodePage.shadowRoot + .querySelector('#activationCodeContainer') .classList.contains('relative')); FakeBarcodeDetector.setShouldFail(true); @@ -329,11 +349,13 @@ FakeBarcodeDetector, FakeImageCapture, setIntervalFunction, playVideoFunction, stopStreamFunction); - qrCodeDetectorContainer = activationCodePage.$$('#esimQrCodeDetection'); + qrCodeDetectorContainer = + activationCodePage.shadowRoot.querySelector('#esimQrCodeDetection'); assertFalse(!!qrCodeDetectorContainer); // Activation code input should now be in the center of the page. - assertTrue(activationCodePage.$$('#activationCodeContainer') + assertTrue(activationCodePage.shadowRoot + .querySelector('#activationCodeContainer') .classList.contains('center')); }); @@ -342,7 +364,8 @@ activationCodePage.addEventListener('forward-navigation-requested', () => { eventFired = true; }); - const input = activationCodePage.$$('#activationCode'); + const input = + activationCodePage.shadowRoot.querySelector('#activationCode'); input.dispatchEvent(new KeyboardEvent('keydown', {key: 'Enter'})); await flushAsync(); @@ -352,11 +375,13 @@ test( 'Install error after manual entry should show error on input', async function() { - const input = activationCodePage.$$('#activationCode'); + const input = + activationCodePage.shadowRoot.querySelector('#activationCode'); const startScanningContainer = - activationCodePage.$$('#startScanningContainer'); + activationCodePage.shadowRoot.querySelector( + '#startScanningContainer'); const scanFinishContainer = - activationCodePage.$$('#scanFinishContainer'); + activationCodePage.shadowRoot.querySelector('#scanFinishContainer'); assertTrue(!!input); assertTrue(!!startScanningContainer); assertTrue(!!scanFinishContainer); @@ -374,18 +399,23 @@ test( 'Install error after scanning should show error on camera', async function() { - const input = activationCodePage.$$('#activationCode'); + const input = + activationCodePage.shadowRoot.querySelector('#activationCode'); const startScanningContainer = - activationCodePage.$$('#startScanningContainer'); + activationCodePage.shadowRoot.querySelector( + '#startScanningContainer'); const startScanningButton = - activationCodePage.$$('#startScanningButton'); + activationCodePage.shadowRoot.querySelector('#startScanningButton'); const scanFinishContainer = - activationCodePage.$$('#scanFinishContainer'); + activationCodePage.shadowRoot.querySelector('#scanFinishContainer'); const scanInstallFailureHeader = - activationCodePage.$$('#scanInstallFailureHeader'); - const scanSucessHeader = activationCodePage.$$('#scanSucessHeader'); + activationCodePage.shadowRoot.querySelector( + '#scanInstallFailureHeader'); + const scanSucessHeader = + activationCodePage.shadowRoot.querySelector('#scanSucessHeader'); const getUseCameraAgainButton = () => { - return activationCodePage.$$('#useCameraAgainButton'); + return activationCodePage.shadowRoot.querySelector( + '#useCameraAgainButton'); }; assertTrue(!!input); assertTrue(!!startScanningContainer); @@ -428,9 +458,12 @@ }); test('Tabbing does not close video stream', async function() { - const startScanningButton = activationCodePage.$$('#startScanningButton'); - const getVideo = () => activationCodePage.$$('#video'); - const input = activationCodePage.$$('#activationCode'); + const startScanningButton = + activationCodePage.shadowRoot.querySelector('#startScanningButton'); + const getVideo = () => + activationCodePage.shadowRoot.querySelector('#video'); + const input = + activationCodePage.shadowRoot.querySelector('#activationCode'); assertTrue(!!startScanningButton); assertTrue(!!getVideo()); @@ -460,8 +493,9 @@ test( 'Clear qr code detection timeout when video is hidden', async function() { const startScanningButton = - activationCodePage.$$('#startScanningButton'); - const getVideo = () => activationCodePage.$$('#video'); + activationCodePage.shadowRoot.querySelector('#startScanningButton'); + const getVideo = () => + activationCodePage.shadowRoot.querySelector('#video'); assertTrue(!!startScanningButton); assertTrue(!!getVideo()); @@ -483,7 +517,8 @@ }); test('Input entered manually is validated', async function() { - const input = activationCodePage.$$('#activationCode'); + const input = + activationCodePage.shadowRoot.querySelector('#activationCode'); assertTrue(!!input); assertFalse(input.invalid); @@ -537,16 +572,22 @@ }); test('Scanned code is validated', async function() { - const input = activationCodePage.$$('#activationCode'); + const input = + activationCodePage.shadowRoot.querySelector('#activationCode'); const startScanningContainer = - activationCodePage.$$('#startScanningContainer'); - const startScanningButton = activationCodePage.$$('#startScanningButton'); - const scanFinishContainer = activationCodePage.$$('#scanFinishContainer'); + activationCodePage.shadowRoot.querySelector('#startScanningContainer'); + const startScanningButton = + activationCodePage.shadowRoot.querySelector('#startScanningButton'); + const scanFinishContainer = + activationCodePage.shadowRoot.querySelector('#scanFinishContainer'); const scanInstallFailureHeader = - activationCodePage.$$('#scanInstallFailureHeader'); - const scanSucessHeader = activationCodePage.$$('#scanSucessHeader'); + activationCodePage.shadowRoot.querySelector( + '#scanInstallFailureHeader'); + const scanSucessHeader = + activationCodePage.shadowRoot.querySelector('#scanSucessHeader'); const getUseCameraAgainButton = () => { - return activationCodePage.$$('#useCameraAgainButton'); + return activationCodePage.shadowRoot.querySelector( + '#useCameraAgainButton'); }; assertTrue(!!input); assertTrue(!!startScanningContainer); @@ -628,7 +669,8 @@ }); test('check carrier lock warning', async function() { - assertTrue(!!activationCodePage.$$('#carrierLockWarningContainer')); + assertTrue(!!activationCodePage.shadowRoot.querySelector( + '#carrierLockWarningContainer')); }); test( @@ -641,7 +683,8 @@ }); await flushAsync(); const page = document.createElement('activation-code-page'); - assertFalse(!!page.$$('#carrierLockWarningContainer')); + assertFalse( + !!page.shadowRoot?.querySelector('#carrierLockWarningContainer')); }); test( @@ -655,6 +698,7 @@ }); await flushAsync(); const page = document.createElement('activation-code-page'); - assertFalse(!!page.$$('#carrierLockWarningContainer')); + assertFalse( + !!page.shadowRoot?.querySelector('#carrierLockWarningContainer')); }); });
diff --git a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/base_page_test.js b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/base_page_test.js index a7c1756f..093c7f79 100644 --- a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/base_page_test.js +++ b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/base_page_test.js
@@ -17,25 +17,25 @@ test('Title is shown', function() { basePage.title = 'Base page titile'; flush(); - const title = basePage.$$('#title'); + const title = basePage.shadowRoot.querySelector('#title'); assertTrue(!!title); }); test('Title is not shown', function() { - const title = basePage.$$('#title'); + const title = basePage.shadowRoot.querySelector('#title'); assertFalse(!!title); }); test('Message icon is shown', function() { basePage.messageIcon = 'warning'; flush(); - const messageIcon = basePage.$$('iron-icon'); + const messageIcon = basePage.shadowRoot.querySelector('iron-icon'); assertTrue(!!messageIcon); assertFalse(messageIcon.hidden); }); test('Message icon is not shown', function() { - const messageIcon = basePage.$$('iron-icon'); + const messageIcon = basePage.shadowRoot.querySelector('iron-icon'); assertTrue(!!messageIcon); assertTrue(messageIcon.hidden); });
diff --git a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/button_bar_test.js b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/button_bar_test.js index a50e88d..6ab3e49 100644 --- a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/button_bar_test.js +++ b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/button_bar_test.js
@@ -61,23 +61,29 @@ test('individual buttons appear if enabled', function() { setStateForAllButtons(ButtonState.ENABLED); - assertTrue(isButtonShownAndEnabled(buttonBar.$$('#backward'))); - assertTrue(isButtonShownAndEnabled(buttonBar.$$('#cancel'))); - assertTrue(isButtonShownAndEnabled(buttonBar.$$('#forward'))); + assertTrue(isButtonShownAndEnabled( + buttonBar.shadowRoot.querySelector('#backward'))); + assertTrue( + isButtonShownAndEnabled(buttonBar.shadowRoot.querySelector('#cancel'))); + assertTrue(isButtonShownAndEnabled( + buttonBar.shadowRoot.querySelector('#forward'))); }); test('individual buttons appear but are diabled', function() { setStateForAllButtons(ButtonState.DISABLED); - assertTrue(isButtonShownAndDisabled(buttonBar.$$('#backward'))); - assertTrue(isButtonShownAndDisabled(buttonBar.$$('#cancel'))); - assertTrue(isButtonShownAndDisabled(buttonBar.$$('#forward'))); + assertTrue(isButtonShownAndDisabled( + buttonBar.shadowRoot.querySelector('#backward'))); + assertTrue(isButtonShownAndDisabled( + buttonBar.shadowRoot.querySelector('#cancel'))); + assertTrue(isButtonShownAndDisabled( + buttonBar.shadowRoot.querySelector('#forward'))); }); test('individual buttons are hidden', function() { setStateForAllButtons(ButtonState.HIDDEN); - assertTrue(isButtonHidden(buttonBar.$$('#backward'))); - assertTrue(isButtonHidden(buttonBar.$$('#cancel'))); - assertTrue(isButtonHidden(buttonBar.$$('#forward'))); + assertTrue(isButtonHidden(buttonBar.shadowRoot.querySelector('#backward'))); + assertTrue(isButtonHidden(buttonBar.shadowRoot.querySelector('#cancel'))); + assertTrue(isButtonHidden(buttonBar.shadowRoot.querySelector('#forward'))); }); test('default focus is on last button if all are enabled', function() { @@ -86,7 +92,9 @@ flush(); - assertEquals(buttonBar.shadowRoot.activeElement, buttonBar.$$('#forward')); + assertEquals( + buttonBar.shadowRoot.activeElement, + buttonBar.shadowRoot.querySelector('#forward')); }); test('default focus is on first button if rest are hidden', function() { @@ -99,7 +107,9 @@ flush(); - assertEquals(buttonBar.shadowRoot.activeElement, buttonBar.$$('#backward')); + assertEquals( + buttonBar.shadowRoot.activeElement, + buttonBar.shadowRoot.querySelector('#backward')); }); test( @@ -115,6 +125,7 @@ flush(); assertEquals( - buttonBar.shadowRoot.activeElement, buttonBar.$$('#backward')); + buttonBar.shadowRoot.activeElement, + buttonBar.shadowRoot.querySelector('#backward')); }); });
diff --git a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/cellular_setup_test.js b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/cellular_setup_test.js index 0a318a26..dedd143 100644 --- a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/cellular_setup_test.js +++ b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/cellular_setup_test.js
@@ -55,16 +55,16 @@ test('Show pSim flow ui', async function() { init(); await flushAsync(); - let eSimFlow = cellularSetupPage.$$('esim-flow-ui'); - let pSimFlow = cellularSetupPage.$$('psim-flow-ui'); + let eSimFlow = cellularSetupPage.shadowRoot.querySelector('esim-flow-ui'); + let pSimFlow = cellularSetupPage.shadowRoot.querySelector('psim-flow-ui'); assertTrue(!!eSimFlow); assertFalse(!!pSimFlow); cellularSetupPage.currentPageName = CellularSetupPageName.PSIM_FLOW_UI; await flushAsync(); - eSimFlow = cellularSetupPage.$$('esim-flow-ui'); - pSimFlow = cellularSetupPage.$$('psim-flow-ui'); + eSimFlow = cellularSetupPage.shadowRoot.querySelector('esim-flow-ui'); + pSimFlow = cellularSetupPage.shadowRoot.querySelector('psim-flow-ui'); assertFalse(!!eSimFlow); assertTrue(!!pSimFlow); @@ -73,8 +73,8 @@ test('Show eSIM flow ui', async function() { init(); await flushAsync(); - const eSimFlow = cellularSetupPage.$$('esim-flow-ui'); - const pSimFlow = cellularSetupPage.$$('psim-flow-ui'); + const eSimFlow = cellularSetupPage.shadowRoot.querySelector('esim-flow-ui'); + const pSimFlow = cellularSetupPage.shadowRoot.querySelector('psim-flow-ui'); // By default eSIM flow is always shown assertTrue(!!eSimFlow);
diff --git a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/confirmation_code_page_legacy_test.js b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/confirmation_code_page_legacy_test.js index 550d01d4..8c636c8 100644 --- a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/confirmation_code_page_legacy_test.js +++ b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/confirmation_code_page_legacy_test.js
@@ -33,7 +33,8 @@ 'forward-navigation-requested', () => { eventFired = true; }); - const input = confirmationCodePageLegacy.$$('#confirmationCode'); + const input = confirmationCodePageLegacy.shadowRoot.querySelector( + '#confirmationCode'); input.dispatchEvent(new KeyboardEvent('keydown', {key: 'Enter'})); await flushAsync();
diff --git a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/confirmation_code_page_test.js b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/confirmation_code_page_test.js index fcb4df1..b2ae3566 100644 --- a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/confirmation_code_page_test.js +++ b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/confirmation_code_page_test.js
@@ -33,7 +33,8 @@ 'forward-navigation-requested', () => { eventFired = true; }); - const input = confirmationCodePage.$$('#confirmationCode'); + const input = + confirmationCodePage.shadowRoot.querySelector('#confirmationCode'); input.dispatchEvent(new KeyboardEvent('keydown', {key: 'Enter'})); await flushAsync();
diff --git a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/esim_flow_ui_legacy_test.js b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/esim_flow_ui_legacy_test.js index a661e49..0348122 100644 --- a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/esim_flow_ui_legacy_test.js +++ b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/esim_flow_ui_legacy_test.js
@@ -127,12 +127,16 @@ setSmdsSupportEnabled(false); flush(); - ironPages = eSimPage.$$('iron-pages'); - profileLoadingPage = eSimPage.$$('#profileLoadingPage'); - profileDiscoveryPageLegacy = eSimPage.$$('#profileDiscoveryPageLegacy'); - activationCodePage = eSimPage.$$('#activationCodePage'); - confirmationCodePageLegacy = eSimPage.$$('#confirmationCodePageLegacy'); - finalPage = eSimPage.$$('#finalPage'); + ironPages = eSimPage.shadowRoot.querySelector('iron-pages'); + profileLoadingPage = + eSimPage.shadowRoot.querySelector('#profileLoadingPage'); + profileDiscoveryPageLegacy = + eSimPage.shadowRoot.querySelector('#profileDiscoveryPageLegacy'); + activationCodePage = + eSimPage.shadowRoot.querySelector('#activationCodePage'); + confirmationCodePageLegacy = + eSimPage.shadowRoot.querySelector('#confirmationCodePageLegacy'); + finalPage = eSimPage.shadowRoot.querySelector('#finalPage'); // Captures the function that is called every time the interval timer // timeouts. @@ -200,7 +204,8 @@ async function enterConfirmationCode(backButtonState) { const confirmationCodeInput = - confirmationCodePageLegacy.$$('#confirmationCode'); + confirmationCodePageLegacy.shadowRoot.querySelector( + '#confirmationCode'); confirmationCodeInput.value = 'CONFIRMATION_CODE'; assertFalse(confirmationCodeInput.invalid); @@ -216,7 +221,8 @@ async function assertFinalPageAndPressDoneButton(shouldBeShowingError) { assertSelectedPage(ESimPageName.FINAL, finalPage); - assertEquals(!!finalPage.$$('.error'), shouldBeShowingError); + assertEquals( + !!finalPage.shadowRoot.querySelector('.error'), shouldBeShowingError); assertEquals(ButtonState.ENABLED, eSimPage.buttonState.forward); assertEquals(ButtonState.HIDDEN, eSimPage.buttonState.backward); assertEquals(ButtonState.HIDDEN, eSimPage.buttonState.cancel); @@ -270,7 +276,9 @@ forwardButtonShouldBeEnabled, backButtonState) { if (!forwardButtonShouldBeEnabled) { // In the initial state, input should be cleared. - assertEquals(activationCodePage.$$('#activationCode').value, ''); + assertEquals( + activationCodePage.shadowRoot.querySelector('#activationCode').value, + ''); } assertSelectedPage(ESimPageName.ACTIVATION_CODE, activationCodePage); assertButtonState(forwardButtonShouldBeEnabled, backButtonState); @@ -281,7 +289,10 @@ if (!forwardButtonShouldBeEnabled) { // In the initial state, input should be cleared. assertEquals( - confirmationCodePageLegacy.$$('#confirmationCode').value, ''); + confirmationCodePageLegacy.shadowRoot + .querySelector('#confirmationCode') + .value, + ''); } assertSelectedPage( ESimPageName.CONFIRMATION_CODE_LEGACY, confirmationCodePageLegacy); @@ -306,7 +317,8 @@ /*forwardButtonShouldBeEnabled*/ false, /*backButtonState*/ ButtonState.HIDDEN); // Insert an activation code. - activationCodePage.$$('#activationCode').value = ACTIVATION_CODE_VALID; + activationCodePage.shadowRoot.querySelector('#activationCode').value = + ACTIVATION_CODE_VALID; // Forward button should now be enabled. assertActivationCodePage( @@ -404,8 +416,8 @@ assertConfirmationCodePageLegacy( /*forwardButtonShouldBeEnabled*/ false, /*backButtonState*/ ButtonState.ENABLED); - confirmationCodePageLegacy.$$('#confirmationCode').value = - 'CONFIRMATION_CODE'; + confirmationCodePageLegacy.shadowRoot.querySelector('#confirmationCode') + .value = 'CONFIRMATION_CODE'; eSimPage.navigateBackward(); await flushAsync(); @@ -415,7 +427,7 @@ /*forwardButtonShouldBeEnabled*/ true, /*backButtonState*/ ButtonState.HIDDEN); assertEquals( - activationCodePage.$$('#activationCode').value, + activationCodePage.shadowRoot.querySelector('#activationCode').value, ACTIVATION_CODE_VALID); endFlowAndVerifyResult( @@ -467,7 +479,8 @@ assertFocusDefaultButtonEventFired(); // Insert an activation code. - activationCodePage.$$('#activationCode').value = ACTIVATION_CODE_VALID; + activationCodePage.shadowRoot.querySelector('#activationCode').value = + ACTIVATION_CODE_VALID; assertFalse(focusDefaultButtonEventFired); assertActivationCodePage( @@ -512,8 +525,9 @@ /*forwardButtonShouldBeEnabled*/ false, /*backButtonState*/ ButtonState.ENABLED); assertFocusDefaultButtonEventFired(); - confirmationCodePageLegacy.$$('#confirmationCode').value = - 'CONFIRMATION_CODE'; + confirmationCodePageLegacy.shadowRoot + .querySelector('#confirmationCode') + .value = 'CONFIRMATION_CODE'; assertFalse(focusDefaultButtonEventFired); // Simulate pressing 'Backward'. @@ -525,7 +539,8 @@ /*backButtonState*/ ButtonState.ENABLED); assertFocusDefaultButtonEventFired(); assertEquals( - activationCodePage.$$('#activationCode').value, + activationCodePage.shadowRoot.querySelector('#activationCode') + .value, ACTIVATION_CODE_VALID); eSimPage.navigateBackward(); @@ -543,7 +558,8 @@ async function selectProfile() { // Select the first profile on the list. - const profileList = profileDiscoveryPageLegacy.$$('#profileList'); + const profileList = + profileDiscoveryPageLegacy.shadowRoot.querySelector('#profileList'); profileList.selectItem(profileList.items[0]); flush(); @@ -623,8 +639,9 @@ assertConfirmationCodePageLegacy( /*forwardButtonShouldBeEnabled*/ false, /*backButtonState*/ ButtonState.ENABLED); - confirmationCodePageLegacy.$$('#confirmationCode').value = - 'CONFIRMATION_CODE'; + confirmationCodePageLegacy.shadowRoot + .querySelector('#confirmationCode') + .value = 'CONFIRMATION_CODE'; eSimPage.navigateBackward(); await flushAsync();
diff --git a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/esim_flow_ui_test.js b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/esim_flow_ui_test.js index 22bda02..eefefb6 100644 --- a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/esim_flow_ui_test.js +++ b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/esim_flow_ui_test.js
@@ -120,13 +120,18 @@ document.body.appendChild(eSimPage); flush(); - ironPages = eSimPage.$$('iron-pages'); - profileLoadingPage = eSimPage.$$('#profileLoadingPage'); - profileDiscoveryConsentPage = eSimPage.$$('#profileDiscoveryConsentPage'); - profileDiscoveryPage = eSimPage.$$('#profileDiscoveryPage'); - activationCodePage = eSimPage.$$('#activationCodePage'); - confirmationCodePage = eSimPage.$$('#confirmationCodePage'); - finalPage = eSimPage.$$('#finalPage'); + ironPages = eSimPage.shadowRoot.querySelector('iron-pages'); + profileLoadingPage = + eSimPage.shadowRoot.querySelector('#profileLoadingPage'); + profileDiscoveryConsentPage = + eSimPage.shadowRoot.querySelector('#profileDiscoveryConsentPage'); + profileDiscoveryPage = + eSimPage.shadowRoot.querySelector('#profileDiscoveryPage'); + activationCodePage = + eSimPage.shadowRoot.querySelector('#activationCodePage'); + confirmationCodePage = + eSimPage.shadowRoot.querySelector('#confirmationCodePage'); + finalPage = eSimPage.shadowRoot.querySelector('#finalPage'); // Captures the function that is called every time the interval timer // timeouts. @@ -183,7 +188,8 @@ } async function enterConfirmationCode(backButtonState) { - const confirmationCodeInput = confirmationCodePage.$$('#confirmationCode'); + const confirmationCodeInput = + confirmationCodePage.shadowRoot.querySelector('#confirmationCode'); confirmationCodeInput.value = 'CONFIRMATION_CODE'; assertFalse(confirmationCodeInput.invalid); @@ -199,7 +205,8 @@ async function assertFinalPageAndPressDoneButton(shouldBeShowingError) { assertSelectedPage(ESimPageName.FINAL, finalPage); - assertEquals(!!finalPage.$$('.error'), shouldBeShowingError); + assertEquals( + !!finalPage.shadowRoot.querySelector('.error'), shouldBeShowingError); assertEquals(ButtonState.ENABLED, eSimPage.buttonState.forward); assertEquals(ButtonState.HIDDEN, eSimPage.buttonState.backward); assertEquals(ButtonState.HIDDEN, eSimPage.buttonState.cancel); @@ -254,7 +261,7 @@ // When the user clicks the "manually" link, they opt out of profile // discovery. - profileDiscoveryConsentPage.$$('#shouldSkipDiscovery') + profileDiscoveryConsentPage.shadowRoot.querySelector('#shouldSkipDiscovery') .shadowRoot.querySelector('a') .click(); await flushAsync(); @@ -282,7 +289,9 @@ forwardButtonShouldBeEnabled, backButtonState) { if (!forwardButtonShouldBeEnabled) { // In the initial state, input should be cleared. - assertEquals(activationCodePage.$$('#activationCode').value, ''); + assertEquals( + activationCodePage.shadowRoot.querySelector('#activationCode').value, + ''); } assertSelectedPage(ESimPageName.ACTIVATION_CODE, activationCodePage); assertButtonState(forwardButtonShouldBeEnabled); @@ -292,7 +301,10 @@ forwardButtonShouldBeEnabled, backButtonState) { if (!forwardButtonShouldBeEnabled) { // In the initial state, input should be cleared. - assertEquals(confirmationCodePage.$$('#confirmationCode').value, ''); + assertEquals( + confirmationCodePage.shadowRoot.querySelector('#confirmationCode') + .value, + ''); } assertSelectedPage(ESimPageName.CONFIRMATION_CODE, confirmationCodePage); assertButtonState(forwardButtonShouldBeEnabled); @@ -340,8 +352,8 @@ /*forwardButtonShouldBeEnabled*/ false, /*backButtonState*/ ButtonState.HIDDEN); // Insert an activation code. - activationCodePage.$$('#activationCode').value = - ACTIVATION_CODE_VALID; + activationCodePage.shadowRoot.querySelector('#activationCode') + .value = ACTIVATION_CODE_VALID; // Forward button should now be enabled. assertActivationCodePage( /*forwardButtonShouldBeEnabled*/ true, @@ -439,8 +451,8 @@ assertConfirmationCodePage( /*forwardButtonShouldBeEnabled*/ false, /*backButtonState*/ ButtonState.ENABLED); - confirmationCodePage.$$('#confirmationCode').value = - 'CONFIRMATION_CODE'; + confirmationCodePage.shadowRoot.querySelector('#confirmationCode') + .value = 'CONFIRMATION_CODE'; eSimPage.navigateBackward(); await flushAsync(); @@ -450,7 +462,8 @@ /*forwardButtonShouldBeEnabled*/ true, /*backButtonState*/ ButtonState.HIDDEN); assertEquals( - activationCodePage.$$('#activationCode').value, + activationCodePage.shadowRoot.querySelector('#activationCode') + .value, ACTIVATION_CODE_VALID); endFlowAndVerifyResult( @@ -508,7 +521,8 @@ assertFocusDefaultButtonEventFired(); // Insert an activation code. - activationCodePage.$$('#activationCode').value = ACTIVATION_CODE_VALID; + activationCodePage.shadowRoot.querySelector('#activationCode').value = + ACTIVATION_CODE_VALID; assertFalse(focusDefaultButtonEventFired); assertActivationCodePage( @@ -517,7 +531,7 @@ } function skipProfileList() { - profileDiscoveryPage.$$('#profileListMessage') + profileDiscoveryPage.shadowRoot.querySelector('#profileListMessage') .shadowRoot.querySelector('a') .click(); @@ -530,7 +544,8 @@ assertFocusDefaultButtonEventFired(); // Insert an activation code. - activationCodePage.$$('#activationCode').value = ACTIVATION_CODE_VALID; + activationCodePage.shadowRoot.querySelector('#activationCode').value = + ACTIVATION_CODE_VALID; assertFalse(focusDefaultButtonEventFired); assertActivationCodePage( @@ -620,8 +635,8 @@ /*forwardButtonShouldBeEnabled*/ false, /*backButtonState*/ ButtonState.ENABLED); assertFocusDefaultButtonEventFired(); - confirmationCodePage.$$('#confirmationCode').value = - 'CONFIRMATION_CODE'; + confirmationCodePage.shadowRoot.querySelector('#confirmationCode') + .value = 'CONFIRMATION_CODE'; assertFalse(focusDefaultButtonEventFired); // Simulate pressing 'Backward'. @@ -633,7 +648,8 @@ /*backButtonState*/ ButtonState.ENABLED); assertFocusDefaultButtonEventFired(); assertEquals( - activationCodePage.$$('#activationCode').value, + activationCodePage.shadowRoot.querySelector('#activationCode') + .value, ACTIVATION_CODE_VALID); eSimPage.navigateBackward(); @@ -651,7 +667,8 @@ async function selectProfile() { // Select the first profile on the list. - const profileList = profileDiscoveryPage.$$('#profileList'); + const profileList = + profileDiscoveryPage.shadowRoot.querySelector('#profileList'); profileList.selectItem(profileList.items[0]); flush(); @@ -728,8 +745,8 @@ assertConfirmationCodePage( /*forwardButtonShouldBeEnabled*/ false, /*backButtonState*/ ButtonState.ENABLED); - confirmationCodePage.$$('#confirmationCode').value = - 'CONFIRMATION_CODE'; + confirmationCodePage.shadowRoot.querySelector('#confirmationCode') + .value = 'CONFIRMATION_CODE'; eSimPage.navigateBackward(); await flushAsync();
diff --git a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/final_page_test.js b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/final_page_test.js index aaeb9af7..83c2d7ec 100644 --- a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/final_page_test.js +++ b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/final_page_test.js
@@ -20,7 +20,7 @@ }); test('Base test', function() { - const basePage = finalPage.$$('base-page'); + const basePage = finalPage.shadowRoot.querySelector('base-page'); assertTrue(!!basePage); }); });
diff --git a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/provisioning_page_test.js b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/provisioning_page_test.js index a64850f..8a64ec8 100644 --- a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/provisioning_page_test.js +++ b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/provisioning_page_test.js
@@ -21,7 +21,7 @@ }); test('Base test', function() { - const basePage = provisioningPage.$$('base-page'); + const basePage = provisioningPage.shadowRoot.querySelector('base-page'); assertTrue(!!basePage); }); });
diff --git a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/psim_flow_ui_test.js b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/psim_flow_ui_test.js index 4f98d6d..4dac726 100644 --- a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/psim_flow_ui_test.js +++ b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/psim_flow_ui_test.js
@@ -98,7 +98,8 @@ cellularActivationDelegate = cellularSetupRemote.getLastActivationDelegate(); - const provisioningPage = pSimPage.$$('#provisioningPage'); + const provisioningPage = + pSimPage.shadowRoot.querySelector('#provisioningPage'); assertTrue(!!provisioningPage); assertFalse( pSimPage.selectedPSimPageName_ === PSimPageName.provisioningPage); @@ -222,7 +223,8 @@ cellularActivationDelegate = cellularSetupRemote.getLastActivationDelegate(); - const provisioningPage = pSimPage.$$('#provisioningPage'); + const provisioningPage = + pSimPage.shadowRoot.querySelector('#provisioningPage'); assertTrue(!!provisioningPage); assertFalse( pSimPage.selectedPSimPageName_ === PSimPageName.provisioningPage); @@ -235,7 +237,8 @@ }); test('Portal error metric logged', () => { - const provisioningPage = pSimPage.$$('#provisioningPage'); + const provisioningPage = + pSimPage.shadowRoot.querySelector('#provisioningPage'); provisioningPage.fire('carrier-portal-result', false); endFlowAndVerifyResult(PSimSetupFlowResult.CANCELLED_PORTAL_ERROR);
diff --git a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/setup_loading_page_test.js b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/setup_loading_page_test.js index f7f5f2e..f210c44 100644 --- a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/setup_loading_page_test.js +++ b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/setup_loading_page_test.js
@@ -18,19 +18,23 @@ document.body.appendChild(setupLoadingPage); flush(); - basePage = setupLoadingPage.$$('base-page'); + basePage = setupLoadingPage.shadowRoot.querySelector('base-page'); assertTrue(!!basePage); }); test('Loading animation and error graphic shown correctly', function() { setupLoadingPage.isSimDetectError = false; flush(); - assertTrue(!!setupLoadingPage.$$('#animationContainer')); - assertTrue(setupLoadingPage.$$('#simDetectError').hidden); + assertTrue( + !!setupLoadingPage.shadowRoot.querySelector('#animationContainer')); + assertTrue( + setupLoadingPage.shadowRoot.querySelector('#simDetectError').hidden); setupLoadingPage.isSimDetectError = true; flush(); - assertFalse(!!setupLoadingPage.$$('#animationContainer')); - assertFalse(setupLoadingPage.$$('#simDetectError').hidden); + assertFalse( + !!setupLoadingPage.shadowRoot.querySelector('#animationContainer')); + assertFalse( + setupLoadingPage.shadowRoot.querySelector('#simDetectError').hidden); }); });
diff --git a/chrome/updater/configurator.cc b/chrome/updater/configurator.cc index 0a6e645..fe16252 100644 --- a/chrome/updater/configurator.cc +++ b/chrome/updater/configurator.cc
@@ -231,4 +231,8 @@ return updater::GetCrxDiffCacheDirectory(GetUpdaterScope()); } +bool Configurator::IsConnectionMetered() const { + return false; +} + } // namespace updater
diff --git a/chrome/updater/configurator.h b/chrome/updater/configurator.h index 1c0cd33..53ff874 100644 --- a/chrome/updater/configurator.h +++ b/chrome/updater/configurator.h
@@ -80,6 +80,7 @@ std::optional<bool> IsMachineExternallyManaged() const override; update_client::UpdaterStateProvider GetUpdaterStateProvider() const override; std::optional<base::FilePath> GetCrxCachePath() const override; + bool IsConnectionMetered() const override; scoped_refptr<PersistedData> GetUpdaterPersistedData() const; virtual GURL CrashUploadURL() const;
diff --git a/chrome/updater/test/integration_tests_win.cc b/chrome/updater/test/integration_tests_win.cc index c4c96c6..8a457de2 100644 --- a/chrome/updater/test/integration_tests_win.cc +++ b/chrome/updater/test/integration_tests_win.cc
@@ -181,35 +181,15 @@ void ExpectUpdateRegKeyClean(UpdaterScope scope) { const HKEY root = UpdaterScopeToHKeyRoot(scope); - if (!RegKeyExists(root, UPDATER_KEY)) { - return; - } - - for (base::win::RegistryValueIterator updater_value_iter(root, UPDATER_KEY, - KEY_WOW64_32KEY); - updater_value_iter.Valid(); ++updater_value_iter) { - EXPECT_TRUE( - base::Contains(kRegValuesLastInstaller, updater_value_iter.Name())) - << updater_value_iter.Name(); - } - - base::win::RegistryKeyIterator updater_key_iter(root, UPDATER_KEY, - KEY_WOW64_32KEY); if (IsSystemInstall(scope)) { - // App activity bits are written to HKCU only. - EXPECT_EQ(updater_key_iter.SubkeyCount(), 0u); + EXPECT_EQ(RegKeyExists(root, CLIENT_STATE_KEY), false); return; } - if (updater_key_iter.SubkeyCount() == 0) { + // `ClientState` may exist with lastrun values for user installs. + if (!RegKeyExists(root, CLIENT_STATE_KEY)) { return; } - - // `ClientState` is the only allowed sub-key of `UPDATER_KEY` for user - // installs. - EXPECT_EQ(updater_key_iter.SubkeyCount(), 1u); - EXPECT_STREQ(updater_key_iter.Name(), L"ClientState"); - EXPECT_THAT(base::win::RegKey(root, CLIENT_STATE_KEY, Wow6432(KEY_READ)) .GetValueCount(), base::test::ValueIs(0u)); @@ -297,7 +277,7 @@ EXPECT_FALSE(RegKeyExists(HKEY_LOCAL_MACHINE, key)); } } - EXPECT_FALSE(RegKeyExists(root, CLIENTS_KEY)); + EXPECT_FALSE(RegKeyExists(root, CLIENT_STATE_KEY)); ExpectUpdateRegKeyClean(scope); if (!IsSystemInstall(scope)) {
diff --git a/chrome/updater/win/setup/uninstall.cc b/chrome/updater/win/setup/uninstall.cc index 2cbc16a..668672f7 100644 --- a/chrome/updater/win/setup/uninstall.cc +++ b/chrome/updater/win/setup/uninstall.cc
@@ -95,47 +95,16 @@ } } -void DeleteUpdaterKey(UpdaterScope scope) { - const HKEY root = UpdaterScopeToHKeyRoot(scope); - - // Delete all the sub keys of `UPDATER_KEY`. - std::vector<std::wstring> sub_keys; - for (base::win::RegistryKeyIterator updater_key_iter(root, UPDATER_KEY, - KEY_WOW64_32KEY); - updater_key_iter.Valid(); ++updater_key_iter) { - sub_keys.push_back(updater_key_iter.Name()); - } - - for (const auto& sub_key : sub_keys) { - const std::wstring subkey_path = - base::StrCat({UPDATER_KEY, L"\\", sub_key}); - installer::DeleteRegistryKey(root, subkey_path, KEY_WOW64_32KEY); - } - - // Delete all the values of `UPDATER_KEY`, except the `LastInstaller*` values. - std::vector<std::wstring> values; - for (base::win::RegistryValueIterator updater_value_iter(root, UPDATER_KEY, - KEY_WOW64_32KEY); - updater_value_iter.Valid(); ++updater_value_iter) { - if (!base::Contains(kRegValuesLastInstaller, updater_value_iter.Name())) { - values.push_back(updater_value_iter.Name()); - } - } - for (const auto& value : values) { - installer::DeleteRegistryValue(root, UPDATER_KEY, KEY_WOW64_32KEY, value); - } - - // Finally, delete `UPDATER_KEY` if it is empty. - base::win::RegKey updater_key; - if (updater_key.Open(root, UPDATER_KEY, Wow6432(KEY_QUERY_VALUE)) == - ERROR_SUCCESS && - updater_key.GetValueCount().value_or(1) == 0) { - updater_key.DeleteKey(L"", base::win::RegKey::RecursiveDelete(false)); +void DeleteClientStateKey(UpdaterScope scope) { + base::win::RegKey client_state; + if (client_state.Open(UpdaterScopeToHKeyRoot(scope), CLIENT_STATE_KEY, + Wow6432(KEY_QUERY_VALUE)) == ERROR_SUCCESS) { + client_state.DeleteKey(L"", base::win::RegKey::RecursiveDelete(true)); } } void DeleteGoogleUpdateFilesAndKeys(UpdaterScope scope) { - DeleteUpdaterKey(scope); + DeleteClientStateKey(scope); const std::optional<base::FilePath> target_path = GetGoogleUpdateExePath(scope); @@ -185,7 +154,7 @@ // Reverses the changes made by setup. This is a best effort uninstall: // 1. Deletes the scheduled task. -// 2. Deletes the Clients and ClientState keys. +// 2. Deletes the ClientState key. // 3. Runs the uninstall script in the install directory of the updater. // The execution of this function and the script race each other but the script // loops and waits in between iterations trying to delete the install directory.
diff --git a/chromeos/ash/components/assistant/OWNERS b/chromeos/ash/components/assistant/OWNERS index fbebcec..0dd0eb7 100644 --- a/chromeos/ash/components/assistant/OWNERS +++ b/chromeos/ash/components/assistant/OWNERS
@@ -2,6 +2,7 @@ # unless there is a specific reason for it. assistive-code-review@google.com +angelaxiao@chromium.org #{LAST_RESORT_SUGGESTION} esum@google.com #{LAST_RESORT_SUGGESTION} wutao@chromium.org #{LAST_RESORT_SUGGESTION} xiaohuic@chromium.org #{LAST_RESORT_SUGGESTION}
diff --git a/chromeos/chromeos_strings.grd b/chromeos/chromeos_strings.grd index 573ed32..bcedd23 100644 --- a/chromeos/chromeos_strings.grd +++ b/chromeos/chromeos_strings.grd
@@ -4616,13 +4616,13 @@ <ph name="ATTACH">Attach</ph> (<ph name="IA">IA</ph>) </message> <message name="IDS_SETTINGS_APN_A11Y_DEFAULT_AND_ATTACH_APN" desc="Accessibility text for when an APN is both a default and an attach APN"> - APN is type default and attach. + APN is type default and <ph name="ATTACH">attach</ph>. </message> <message name="IDS_SETTINGS_APN_A11Y_DEFAULT_APN_ONLY" desc="Accessibility text for when an APN is only a default APN"> APN is type default. </message> <message name="IDS_SETTINGS_APN_A11Y_ATTACH_APN_ONLY" desc="Accessibility text for when an APN is only an attach APN"> - APN is type attach. + APN is type <ph name="ATTACH">attach</ph>. </message> <message name="IDS_SETTINGS_APN_DIALOG_DEFAULT_APN_REQUIRED" desc="Error message that is shown whenever a default APN type is required"> A default APN is required @@ -4634,7 +4634,7 @@ Automatically detected </message> <message name="IDS_SETTINGS_APN_WARNING_PROMPT_FOR_DISABLE_REMOVE" desc="Warning Prompt describing why the APN can't be disabled or removed."> - Can't disable or remove this APN. Make sure enabled attach APNs are disabled or removed. + Can't disable or remove this APN. Make sure enabled <ph name="ATTACH">attach</ph> APNs are disabled or removed. </message> <message name="IDS_SETTINGS_APN_WARNING_PROMPT_FOR_ENABLE" desc="Warning Prompt describing why the APN can't be enabled."> Can’t enable this APN. Make sure a default APN is added.
diff --git a/chromeos/chromeos_strings_grd/IDS_SETTINGS_APN_A11Y_ATTACH_APN_ONLY.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SETTINGS_APN_A11Y_ATTACH_APN_ONLY.png.sha1 index f0a27785..dc9c4704 100644 --- a/chromeos/chromeos_strings_grd/IDS_SETTINGS_APN_A11Y_ATTACH_APN_ONLY.png.sha1 +++ b/chromeos/chromeos_strings_grd/IDS_SETTINGS_APN_A11Y_ATTACH_APN_ONLY.png.sha1
@@ -1 +1 @@ -580ad7bfd1ac9c3c261fdd02f07298d3e924dc8b \ No newline at end of file +c5730e2c8e36799256b4d2ba9d39e454f2d04e91 \ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_SETTINGS_APN_A11Y_DEFAULT_AND_ATTACH_APN.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SETTINGS_APN_A11Y_DEFAULT_AND_ATTACH_APN.png.sha1 index 0b4dd31..dc9c4704 100644 --- a/chromeos/chromeos_strings_grd/IDS_SETTINGS_APN_A11Y_DEFAULT_AND_ATTACH_APN.png.sha1 +++ b/chromeos/chromeos_strings_grd/IDS_SETTINGS_APN_A11Y_DEFAULT_AND_ATTACH_APN.png.sha1
@@ -1 +1 @@ -77d95ecf7eed3bda97ceef5f94830e3a4b8b6194 \ No newline at end of file +c5730e2c8e36799256b4d2ba9d39e454f2d04e91 \ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_SETTINGS_APN_WARNING_PROMPT_FOR_DISABLE_REMOVE.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SETTINGS_APN_WARNING_PROMPT_FOR_DISABLE_REMOVE.png.sha1 index a8120fdd..b0f4a70 100644 --- a/chromeos/chromeos_strings_grd/IDS_SETTINGS_APN_WARNING_PROMPT_FOR_DISABLE_REMOVE.png.sha1 +++ b/chromeos/chromeos_strings_grd/IDS_SETTINGS_APN_WARNING_PROMPT_FOR_DISABLE_REMOVE.png.sha1
@@ -1 +1 @@ -b39ce41e2160c0b38aa30a0a25f8774dd0ae6f33 \ No newline at end of file +b0a495b4cd1e9ef8e1443bf88e88ba3936965263 \ No newline at end of file
diff --git a/clank b/clank index 73c5549..20d5657 160000 --- a/clank +++ b/clank
@@ -1 +1 @@ -Subproject commit 73c554959a79725f3f2e1a6f9a902bd4fc2febc3 +Subproject commit 20d5657767c7a726b9144002e4021d087725a89e
diff --git a/components/component_updater/BUILD.gn b/components/component_updater/BUILD.gn index 13f683b..d459f161 100644 --- a/components/component_updater/BUILD.gn +++ b/components/component_updater/BUILD.gn
@@ -47,6 +47,7 @@ "//components/prefs", "//components/update_client", "//components/version_info", + "//net", "//third_party/boringssl:boringssl", "//ui/base", "//url", @@ -83,6 +84,7 @@ "//components/crx_file", "//components/prefs:test_support", "//components/update_client:test_support", + "//net:test_support", "//services/service_manager/public/cpp", "//testing/gmock", "//testing/gtest",
diff --git a/components/component_updater/DEPS b/components/component_updater/DEPS index 68c6559..8596a02 100644 --- a/components/component_updater/DEPS +++ b/components/component_updater/DEPS
@@ -6,4 +6,5 @@ "+services/service_manager/public", "+ui", "+url", + "+net", ]
diff --git a/components/component_updater/component_installer.cc b/components/component_updater/component_installer.cc index fbc62f5..cf9f785 100644 --- a/components/component_updater/component_installer.cc +++ b/components/component_updater/component_installer.cc
@@ -57,6 +57,10 @@ return true; } +bool ComponentInstallerPolicy::AllowUpdatesOnMeteredConnections() const { + return true; +} + ComponentInstaller::RegistrationInfo::RegistrationInfo() : version(kNullVersion) {} @@ -529,7 +533,8 @@ installer_policy_->GetInstallerAttributes(), action_handler_, this, installer_policy_->RequiresNetworkEncryption(), installer_policy_->SupportsGroupPolicyEnabledComponentUpdates(), - installer_policy_->AllowCachedCopies()))) { + installer_policy_->AllowCachedCopies(), + installer_policy_->AllowUpdatesOnMeteredConnections()))) { VLOG(0) << "Component registration failed for " << installer_policy_->GetName(); if (!callback.is_null()) {
diff --git a/components/component_updater/component_installer.h b/components/component_updater/component_installer.h index fe597860..992c017 100644 --- a/components/component_updater/component_installer.h +++ b/components/component_updater/component_installer.h
@@ -122,6 +122,12 @@ // storage overhead is valued higher than the cost of performing a full update // at the expected cadence, disabling cached copies is a reasonable choice. virtual bool AllowCachedCopies() const; + + // Returns true if the component should not update over metered connections. + // Defaults to |true|. This only controls whether updates are accepted: if the + // network type changes from unmetered to metered during a download, there is + // no guarantee that the transfer will be suspended or cancelled. + virtual bool AllowUpdatesOnMeteredConnections() const; }; // Defines the installer for Chrome components. The behavior of this class is
diff --git a/components/component_updater/component_installer_unittest.cc b/components/component_updater/component_installer_unittest.cc index 7fae408a..eb140b0b 100644 --- a/components/component_updater/component_installer_unittest.cc +++ b/components/component_updater/component_installer_unittest.cc
@@ -8,6 +8,7 @@ #include <utility> #include <vector> +#include "base/barrier_closure.h" #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/functional/bind.h" @@ -20,6 +21,7 @@ #include "base/sequence_checker.h" #include "base/strings/strcat.h" #include "base/strings/stringprintf.h" +#include "base/task/bind_post_task.h" #include "base/task/sequenced_task_runner.h" #include "base/test/bind.h" #include "base/test/scoped_path_override.h" @@ -131,8 +133,10 @@ const base::FilePath& install_dir, base::Value::Dict manifest)>; explicit MockInstallerPolicy( - ComponentReadyCallback component_ready_cb = ComponentReadyCallback()) - : component_ready_cb_(std::move(component_ready_cb)) {} + ComponentReadyCallback component_ready_cb = ComponentReadyCallback(), + base::RepeatingClosure uninstall_cb = base::DoNothing()) + : component_ready_cb_(std::move(component_ready_cb)), + uninstall_cb_(uninstall_cb) {} ~MockInstallerPolicy() override = default; bool VerifyInstallation(const base::Value::Dict& manifest, @@ -152,7 +156,7 @@ return update_client::CrxInstaller::Result(0); } - void OnCustomUninstall() override {} + void OnCustomUninstall() override { uninstall_cb_.Run(); } void ComponentReady(const base::Version& version, const base::FilePath& install_dir, @@ -184,6 +188,7 @@ } ComponentReadyCallback component_ready_cb_; + base::RepeatingClosure uninstall_cb_; }; class MockUpdateScheduler : public UpdateScheduler { @@ -297,8 +302,9 @@ base::FilePath component_dir = base_dir.AppendASCII(name).AppendASCII(version); - if (!base::CreateDirectory(component_dir)) + if (!base::CreateDirectory(component_dir)) { return absl::nullopt; + } if (!base::WriteFile(component_dir.AppendASCII("manifest.json"), base::StringPrintf(R"({ @@ -307,8 +313,9 @@ "min_env_version": "%s" })", name.c_str(), version.c_str(), - min_env_version.c_str()))) + min_env_version.c_str()))) { return absl::nullopt; + } return absl::make_optional(component_dir); } @@ -317,32 +324,19 @@ // and its component policy, through the instance of the CrxComponent, to the // component updater service. TEST_F(ComponentInstallerTest, RegisterComponent) { - class LoopHandler { - public: - LoopHandler(int max_cnt, base::OnceClosure quit_closure) - : max_cnt_(max_cnt), quit_closure_(std::move(quit_closure)) {} - - void OnUpdate(const std::vector<std::string>& ids, - const UpdateClient::CrxDataCallback& crx_data_callback) { - static int cnt = 0; - ++cnt; - if (cnt >= max_cnt_) - std::move(quit_closure_).Run(); - } - - private: - const int max_cnt_; - base::OnceClosure quit_closure_; - }; - base::ScopedPathOverride scoped_path_override(DIR_COMPONENT_USER); const std::string id("jebgalgnebhfojomionfpkfelancnnkf"); // Quit after one update check has been fired. - LoopHandler loop_handler(1, quit_closure()); + base::RepeatingClosure barrier_callback = + base::BarrierClosure(1, quit_closure()); EXPECT_CALL(update_client(), DoUpdate(_, _)) - .WillRepeatedly(Invoke(&loop_handler, &LoopHandler::OnUpdate)); + .WillRepeatedly( + [&](const std::vector<std::string>& ids, + const UpdateClient::CrxDataCallback& crx_data_callback) { + barrier_callback.Run(); + }); EXPECT_CALL(update_client(), GetCrxUpdateState(id, _)).Times(1); EXPECT_CALL(update_client(), Stop()).Times(1); @@ -590,4 +584,40 @@ ASSERT_EQ(registration_info->version, base::Version("7.0.0.0")); } +TEST_F(ComponentInstallerTest, Uninstall) { + base::RunLoop run_loop; + auto installer = base::MakeRefCounted<ComponentInstaller>( + std::make_unique<MockInstallerPolicy>( + MockInstallerPolicy::ComponentReadyCallback(), + base::BindPostTaskToCurrentDefault(run_loop.QuitClosure()))); + + Unpack( + update_client::GetTestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx")); + + const auto unpack_path = result().unpack_path; + EXPECT_TRUE(base::DirectoryExists(unpack_path)); + EXPECT_EQ(update_client::jebg_public_key, result().public_key); + + base::ScopedPathOverride scoped_path_override(DIR_COMPONENT_USER); + base::FilePath base_dir; + EXPECT_TRUE(base::PathService::Get(DIR_COMPONENT_USER, &base_dir)); + base_dir = base_dir.Append(relative_install_dir); + EXPECT_TRUE(base::CreateDirectory(base_dir)); + + installer->Register( + component_updater(), base::BindLambdaForTesting([&]() { + installer->Install( + unpack_path, update_client::jebg_public_key, nullptr, + base::DoNothing(), + base::BindLambdaForTesting( + [&](const update_client::CrxInstaller::Result& result) { + EXPECT_EQ(0, result.error); + installer->Uninstall(); + })); + })); + run_loop.Run(); + + EXPECT_FALSE(base::PathExists(base_dir)); +} + } // namespace component_updater
diff --git a/components/component_updater/component_updater_service.cc b/components/component_updater/component_updater_service.cc index ed21e9c..b54eff1 100644 --- a/components/component_updater/component_updater_service.cc +++ b/components/component_updater/component_updater_service.cc
@@ -80,7 +80,8 @@ scoped_refptr<update_client::CrxInstaller> installer, bool requires_network_encryption, bool supports_group_policy_enable_component_updates, - bool allow_cached_copies) + bool allow_cached_copies, + bool allow_updates_on_metered_connection) : app_id(app_id), name(name), public_key_hash(public_key_hash), @@ -92,7 +93,9 @@ requires_network_encryption(requires_network_encryption), supports_group_policy_enable_component_updates( supports_group_policy_enable_component_updates), - allow_cached_copies(allow_cached_copies) {} + allow_cached_copies(allow_cached_copies), + allow_updates_on_metered_connection(allow_updates_on_metered_connection) { +} ComponentRegistration::ComponentRegistration( const ComponentRegistration& other) = default; ComponentRegistration& ComponentRegistration::operator=( @@ -285,6 +288,8 @@ crx.installer_attributes = component.installer_attributes; crx.requires_network_encryption = component.requires_network_encryption; crx.allow_cached_copies = component.allow_cached_copies; + crx.allow_updates_on_metered_connection = + component.allow_updates_on_metered_connection; crx.brand = brand_; crx.crx_format_requirement =
diff --git a/components/component_updater/component_updater_service.h b/components/component_updater/component_updater_service.h index ef30796..6838a99 100644 --- a/components/component_updater/component_updater_service.h +++ b/components/component_updater/component_updater_service.h
@@ -94,7 +94,8 @@ scoped_refptr<update_client::CrxInstaller> installer, bool requires_network_encryption, bool supports_group_policy_enable_component_updates, - bool allow_cached_copies); + bool allow_cached_copies, + bool allow_updates_on_metered_connection); ComponentRegistration(const ComponentRegistration& other); ComponentRegistration& operator=(const ComponentRegistration& other); ComponentRegistration(ComponentRegistration&& other); @@ -112,6 +113,7 @@ bool requires_network_encryption; bool supports_group_policy_enable_component_updates; bool allow_cached_copies; + bool allow_updates_on_metered_connection; }; // The component update service is in charge of installing or upgrading select
diff --git a/components/component_updater/component_updater_service_unittest.cc b/components/component_updater/component_updater_service_unittest.cc index fbb78ccb..0a2bcbe 100644 --- a/components/component_updater/component_updater_service_unittest.cc +++ b/components/component_updater/component_updater_service_unittest.cc
@@ -317,12 +317,23 @@ std::vector<uint8_t> hash; hash.assign(std::begin(abag_hash), std::end(abag_hash)); - ComponentRegistration component1(id1, {}, hash, base::Version("1.0"), {}, {}, - nullptr, installer, false, true, true); + ComponentRegistration component1( + id1, /*name=*/{}, hash, base::Version("1.0"), /*fingerprint=*/{}, {}, + /*action_handler=*/nullptr, installer, + /*requires_network_encryption=*/false, + /*supports_group_policy_enable_component_updates=*/true, + /*allow_cached_copies=*/true, + /*allow_updates_on_metered_connection=*/true); hash.assign(std::begin(jebg_hash), std::end(jebg_hash)); - ComponentRegistration component2(id2, {}, hash, base::Version("0.9"), {}, {}, - nullptr, installer, false, true, true); + ComponentRegistration component2( + id2, /*name=*/{}, hash, base::Version("0.9"), + /*fingerprint=*/{}, /*installer_attributes=*/{}, + /*action_handler=*/nullptr, installer, + /*requires_network_encryption=*/false, + /*supports_group_policy_enable_component_updates=*/true, + /*allow_cached_copies=*/true, + /*allow_updates_on_metered_connection=*/true); // Quit after two update checks have fired. LoopHandler loop_handler(2, quit_closure()); @@ -381,18 +392,27 @@ std::vector<uint8_t> hash; hash.assign(std::begin(jebg_hash), std::end(jebg_hash)); EXPECT_TRUE(cus.RegisterComponent(ComponentRegistration( - "jebgalgnebhfojomionfpkfelancnnkf", {}, hash, base::Version("0.9"), {}, - {}, nullptr, base::MakeRefCounted<MockInstaller>(), false, true, - true))); + "jebgalgnebhfojomionfpkfelancnnkf", /*name=*/{}, hash, + base::Version("0.9"), /*fingerprint=*/{}, /*installer_attributes=*/{}, + /*action_handler=*/nullptr, base::MakeRefCounted<MockInstaller>(), + /*requires_network_encryption=*/false, + /*supports_group_policy_enable_component_updates=*/true, + /*allow_cached_copies=*/true, + /*allow_updates_on_metered_connection=*/true))); } { using update_client::abag_hash; std::vector<uint8_t> hash; hash.assign(std::begin(abag_hash), std::end(abag_hash)); EXPECT_TRUE(cus.RegisterComponent(ComponentRegistration( - "abagagagagagagagagagagagagagagag", {}, hash, base::Version("0.9"), {}, - {}, nullptr, base::MakeRefCounted<MockInstaller>(), false, true, - true))); + "abagagagagagagagagagagagagagagag", /*name=*/{}, hash, + base::Version("0.9"), /*fingerprint=*/{}, + /*installer_attributes=*/{}, /*action_handler=*/nullptr, + base::MakeRefCounted<MockInstaller>(), + /*requires_network_encryption=*/false, + /*supports_group_policy_enable_component_updates=*/true, + /*allow_cached_copies=*/true, + /*allow_updates_on_metered_connection=*/true))); } OnDemandTester ondemand_tester; @@ -430,8 +450,14 @@ EXPECT_CALL(scheduler(), Stop()).Times(1); EXPECT_TRUE(component_updater().RegisterComponent(ComponentRegistration( - "jebgalgnebhfojomionfpkfelancnnkf", {}, hash, base::Version("0.9"), {}, - {}, nullptr, base::MakeRefCounted<MockInstaller>(), false, true, true))); + "jebgalgnebhfojomionfpkfelancnnkf", /*name=*/{}, hash, + base::Version("0.9"), {}, + /*installer_attributes=*/{}, /*action_handler=*/nullptr, + base::MakeRefCounted<MockInstaller>(), + /*requires_network_encryption=*/false, + /*supports_group_policy_enable_component_updates=*/true, + /*allow_cached_copies=*/true, + /*allow_updates_on_metered_connection=*/true))); component_updater().MaybeThrottle("jebgalgnebhfojomionfpkfelancnnkf", base::DoNothing());
diff --git a/components/component_updater/configurator_impl.cc b/components/component_updater/configurator_impl.cc index 0e9fe9c..20612b65 100644 --- a/components/component_updater/configurator_impl.cc +++ b/components/component_updater/configurator_impl.cc
@@ -23,6 +23,7 @@ #include "components/update_client/protocol_handler.h" #include "components/update_client/utils.h" #include "components/version_info/version_info.h" +#include "net/base/network_change_notifier.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "url/gurl.h" @@ -51,8 +52,9 @@ ConfiguratorImpl::~ConfiguratorImpl() = default; base::TimeDelta ConfiguratorImpl::InitialDelay() const { - if (!initial_delay_.is_zero()) + if (!initial_delay_.is_zero()) { return initial_delay_; + } return fast_update_ ? base::Seconds(10) : base::Minutes(1); } @@ -69,13 +71,15 @@ } std::vector<GURL> ConfiguratorImpl::UpdateUrl() const { - if (url_source_override_.is_valid()) + if (url_source_override_.is_valid()) { return {GURL(url_source_override_)}; + } std::vector<GURL> urls{GURL(kUpdaterJSONDefaultUrl), GURL(kUpdaterJSONFallbackUrl)}; - if (require_encryption_) + if (require_encryption_) { update_client::RemoveUnsecureUrls(&urls); + } return urls; } @@ -151,4 +155,9 @@ #endif } +bool ConfiguratorImpl::IsConnectionMetered() const { + return net::NetworkChangeNotifier::GetConnectionCost() == + net::NetworkChangeNotifier::CONNECTION_COST_METERED; +} + } // namespace component_updater
diff --git a/components/component_updater/configurator_impl.h b/components/component_updater/configurator_impl.h index 9a31551..a7ea4da 100644 --- a/components/component_updater/configurator_impl.h +++ b/components/component_updater/configurator_impl.h
@@ -99,6 +99,8 @@ update_client::UpdaterStateProvider GetUpdaterStateProvider() const; + bool IsConnectionMetered() const; + private: base::flat_map<std::string, std::string> extra_info_; const bool background_downloads_enabled_;
diff --git a/components/component_updater/configurator_impl_unittest.cc b/components/component_updater/configurator_impl_unittest.cc index ad6a5b6c..dcaf61b 100644 --- a/components/component_updater/configurator_impl_unittest.cc +++ b/components/component_updater/configurator_impl_unittest.cc
@@ -6,11 +6,14 @@ #include "base/command_line.h" #include "base/test/scoped_command_line.h" +#include "base/test/task_environment.h" #include "base/time/time.h" #include "components/component_updater/component_updater_command_line_config_policy.h" #include "components/component_updater/component_updater_switches.h" #include "components/component_updater/configurator_impl.h" #include "components/update_client/command_line_config_policy.h" +#include "net/base/mock_network_change_notifier.h" +#include "net/base/network_change_notifier.h" #include "testing/gtest/include/gtest/gtest.h" namespace component_updater { @@ -25,6 +28,9 @@ const ComponentUpdaterConfiguratorImplTest&) = delete; ~ComponentUpdaterConfiguratorImplTest() override = default; + + private: + base::test::TaskEnvironment environment_; }; TEST_F(ComponentUpdaterConfiguratorImplTest, FastUpdate) { @@ -32,19 +38,19 @@ base::CommandLine cmdline(base::CommandLine::NO_PROGRAM); std::unique_ptr<ConfiguratorImpl> config = std::make_unique<ConfiguratorImpl>( ComponentUpdaterCommandLineConfigPolicy(&cmdline), false); - CHECK_EQ(base::Minutes(1), config->InitialDelay()); - CHECK_EQ(base::Hours(5), config->NextCheckDelay()); - CHECK_EQ(base::Minutes(30), config->OnDemandDelay()); - CHECK_EQ(base::Minutes(15), config->UpdateDelay()); + EXPECT_EQ(base::Minutes(1), config->InitialDelay()); + EXPECT_EQ(base::Hours(5), config->NextCheckDelay()); + EXPECT_EQ(base::Minutes(30), config->OnDemandDelay()); + EXPECT_EQ(base::Minutes(15), config->UpdateDelay()); // Test the fast-update timings. cmdline.AppendSwitchASCII("--component-updater", "fast-update"); config = std::make_unique<ConfiguratorImpl>( ComponentUpdaterCommandLineConfigPolicy(&cmdline), false); - CHECK_EQ(base::Seconds(10), config->InitialDelay()); - CHECK_EQ(base::Hours(5), config->NextCheckDelay()); - CHECK_EQ(base::Seconds(2), config->OnDemandDelay()); - CHECK_EQ(base::Seconds(10), config->UpdateDelay()); + EXPECT_EQ(base::Seconds(10), config->InitialDelay()); + EXPECT_EQ(base::Hours(5), config->NextCheckDelay()); + EXPECT_EQ(base::Seconds(2), config->OnDemandDelay()); + EXPECT_EQ(base::Seconds(10), config->UpdateDelay()); } TEST_F(ComponentUpdaterConfiguratorImplTest, FastUpdateWithCustomPolicy) { @@ -66,10 +72,10 @@ std::unique_ptr<ConfiguratorImpl> config = std::make_unique<ConfiguratorImpl>( DefaultCommandLineConfigPolicy(), false); - CHECK_EQ(base::Minutes(1), config->InitialDelay()); - CHECK_EQ(base::Hours(5), config->NextCheckDelay()); - CHECK_EQ(base::Minutes(30), config->OnDemandDelay()); - CHECK_EQ(base::Minutes(15), config->UpdateDelay()); + EXPECT_EQ(base::Minutes(1), config->InitialDelay()); + EXPECT_EQ(base::Hours(5), config->NextCheckDelay()); + EXPECT_EQ(base::Minutes(30), config->OnDemandDelay()); + EXPECT_EQ(base::Minutes(15), config->UpdateDelay()); // Test the fast-update timings. class FastUpdateCommandLineConfigurator @@ -81,16 +87,16 @@ }; config = std::make_unique<ConfiguratorImpl>( FastUpdateCommandLineConfigurator(), false); - CHECK_EQ(base::Seconds(10), config->InitialDelay()); - CHECK_EQ(base::Hours(5), config->NextCheckDelay()); - CHECK_EQ(base::Seconds(2), config->OnDemandDelay()); - CHECK_EQ(base::Seconds(10), config->UpdateDelay()); + EXPECT_EQ(base::Seconds(10), config->InitialDelay()); + EXPECT_EQ(base::Hours(5), config->NextCheckDelay()); + EXPECT_EQ(base::Seconds(2), config->OnDemandDelay()); + EXPECT_EQ(base::Seconds(10), config->UpdateDelay()); } TEST_F(ComponentUpdaterConfiguratorImplTest, InitialDelay) { std::unique_ptr<ConfiguratorImpl> config = std::make_unique<ConfiguratorImpl>( update_client::CommandLineConfigPolicy(), false); - CHECK_EQ(base::Minutes(1), config->InitialDelay()); + EXPECT_EQ(base::Minutes(1), config->InitialDelay()); class CommandLineConfigPolicy : public update_client::CommandLineConfigPolicy { @@ -120,21 +126,21 @@ CommandLineConfigPolicy clcp; clcp.set_fast_update(true); config = std::make_unique<ConfiguratorImpl>(clcp, false); - CHECK_EQ(base::Seconds(10), config->InitialDelay()); + EXPECT_EQ(base::Seconds(10), config->InitialDelay()); } { CommandLineConfigPolicy clcp; clcp.set_fast_update(false); config = std::make_unique<ConfiguratorImpl>(clcp, false); - CHECK_EQ(base::Minutes(1), config->InitialDelay()); + EXPECT_EQ(base::Minutes(1), config->InitialDelay()); } { CommandLineConfigPolicy clcp; clcp.set_initial_delay(base::Minutes(2)); config = std::make_unique<ConfiguratorImpl>(clcp, false); - CHECK_EQ(base::Minutes(2), config->InitialDelay()); + EXPECT_EQ(base::Minutes(2), config->InitialDelay()); } { @@ -145,7 +151,7 @@ "initial-delay=3.14"); config = std::make_unique<ConfiguratorImpl>( ComponentUpdaterCommandLineConfigPolicy(command_line), false); - CHECK_EQ(base::Seconds(3.14), config->InitialDelay()); + EXPECT_EQ(base::Seconds(3.14), config->InitialDelay()); } } @@ -186,4 +192,24 @@ EXPECT_EQ("dev", extra_request_params["testsource"]); } +TEST_F(ComponentUpdaterConfiguratorImplTest, MeteredConnection) { + std::unique_ptr<net::test::MockNetworkChangeNotifier> + network_change_notifier = net::test::MockNetworkChangeNotifier::Create(); + base::CommandLine cmdline(base::CommandLine::NO_PROGRAM); + std::unique_ptr<ConfiguratorImpl> config = std::make_unique<ConfiguratorImpl>( + ComponentUpdaterCommandLineConfigPolicy(&cmdline), false); + + network_change_notifier->SetConnectionCost( + net::NetworkChangeNotifier::CONNECTION_COST_UNKNOWN); + EXPECT_EQ(false, config->IsConnectionMetered()); + + network_change_notifier->SetConnectionCost( + net::NetworkChangeNotifier::CONNECTION_COST_METERED); + EXPECT_EQ(true, config->IsConnectionMetered()); + + network_change_notifier->SetConnectionCost( + net::NetworkChangeNotifier::CONNECTION_COST_UNMETERED); + EXPECT_EQ(false, config->IsConnectionMetered()); +} + } // namespace component_updater
diff --git a/components/optimization_guide/internal b/components/optimization_guide/internal index f35015d..22d6e7c 160000 --- a/components/optimization_guide/internal +++ b/components/optimization_guide/internal
@@ -1 +1 @@ -Subproject commit f35015d6f691b1aadc035cd1644aa3bc19a1a92a +Subproject commit 22d6e7c48e3a433786898acedc2730a9b1c93e6c
diff --git a/components/safe_browsing/content/browser/safe_browsing_blocking_page.cc b/components/safe_browsing/content/browser/safe_browsing_blocking_page.cc index d6bf88e2..faa64d5 100644 --- a/components/safe_browsing/content/browser/safe_browsing_blocking_page.cc +++ b/components/safe_browsing/content/browser/safe_browsing_blocking_page.cc
@@ -131,11 +131,8 @@ } void SafeBrowsingBlockingPage::OnInterstitialClosing() { - if (base::FeatureList::IsEnabled(safe_browsing::kAntiPhishingTelemetry) || - base::FeatureList::IsEnabled(safe_browsing::kRedWarningSurvey)) { - interstitial_interactions_ = - sb_error_ui()->get_interstitial_interaction_data(); - } + interstitial_interactions_ = + sb_error_ui()->get_interstitial_interaction_data(); // If this is a phishing interstitial and the user did not make a decision // through the UI, record that interaction in UMA @@ -143,11 +140,8 @@ controller()->metrics_helper()->RecordUserInteraction( security_interstitials::MetricsHelper::CLOSE_INTERSTITIAL_WITHOUT_UI); - // If kAntiPhishingTelemetry is enabled, add - // CMD_CLOSE_INTERSTITIAL_WITHOUT_UI interaction to interactions. - if (interstitial_interactions_ && - (base::FeatureList::IsEnabled(safe_browsing::kAntiPhishingTelemetry) || - base::FeatureList::IsEnabled(safe_browsing::kRedWarningSurvey))) { + // Add CMD_CLOSE_INTERSTITIAL_WITHOUT_UI interaction to interactions. + if (interstitial_interactions_) { interstitial_interactions_->insert_or_assign( security_interstitials::SecurityInterstitialCommand:: CMD_CLOSE_INTERSTITIAL_WITHOUT_UI, @@ -192,11 +186,9 @@ if (num_visits >= 0) { report->set_repeat_visit(num_visits > 0); } - if ((base::FeatureList::IsEnabled(safe_browsing::kAntiPhishingTelemetry) || - base::FeatureList::IsEnabled(safe_browsing::kRedWarningSurvey)) && - (report->type() == ClientSafeBrowsingReportRequest::URL_PHISHING || - report->type() == - ClientSafeBrowsingReportRequest::URL_CLIENT_SIDE_PHISHING)) { + if (report->type() == ClientSafeBrowsingReportRequest::URL_PHISHING || + report->type() == + ClientSafeBrowsingReportRequest::URL_CLIENT_SIDE_PHISHING) { client_report_utils::FillInterstitialInteractionsHelper(report.get(), interactions); } @@ -234,11 +226,8 @@ // Finish computing threat details. TriggerManager will decide if its safe to // send the report. - if (base::FeatureList::IsEnabled(safe_browsing::kAntiPhishingTelemetry) || - base::FeatureList::IsEnabled(safe_browsing::kRedWarningSurvey)) { - trigger_manager_->SetInterstitialInteractions( - std::move(interstitial_interactions_)); - } + trigger_manager_->SetInterstitialInteractions( + std::move(interstitial_interactions_)); bool is_hats_candidate = false; if (base::FeatureList::IsEnabled(kRedWarningSurvey)) { is_hats_candidate =
diff --git a/components/safe_browsing/content/browser/threat_details.cc b/components/safe_browsing/content/browser/threat_details.cc index 40ae3ae..84841dc 100644 --- a/components/safe_browsing/content/browser/threat_details.cc +++ b/components/safe_browsing/content/browser/threat_details.cc
@@ -831,9 +831,6 @@ } bool ThreatDetails::ShouldFillInterstitialInteractions() { - if (!base::FeatureList::IsEnabled(safe_browsing::kAntiPhishingTelemetry)) { - return false; - } static constexpr auto valid_report_types = base::MakeFixedFlatSet<ClientSafeBrowsingReportRequest::ReportType>( {ClientSafeBrowsingReportRequest::URL_PHISHING,
diff --git a/components/safe_browsing/core/common/features.cc b/components/safe_browsing/core/common/features.cc index f2b89cd1..781b584 100644 --- a/components/safe_browsing/core/common/features.cc +++ b/components/safe_browsing/core/common/features.cc
@@ -29,10 +29,6 @@ "AddWarningShownTSToClientSafeBrowsingReport", base::FEATURE_DISABLED_BY_DEFAULT); -BASE_FEATURE(kAntiPhishingTelemetry, - "AntiPhishingTelemetry", - base::FEATURE_ENABLED_BY_DEFAULT); - BASE_FEATURE(kClientSideDetectionKillswitch, "ClientSideDetectionKillswitch", base::FEATURE_DISABLED_BY_DEFAULT); @@ -303,7 +299,6 @@ } kExperimentalFeatures[]{ {&kAdSamplerTriggerFeature, false}, {&kAddWarningShownTSToClientSafeBrowsingReport, false}, - {&kAntiPhishingTelemetry, false}, {&kClientSideDetectionKillswitch, true}, {&kCreateWarningShownClientSafeBrowsingReports, false}, {&kDelayedWarnings, true},
diff --git a/components/safe_browsing/core/common/features.h b/components/safe_browsing/core/common/features.h index 6fdb311..c0d57e0 100644 --- a/components/safe_browsing/core/common/features.h +++ b/components/safe_browsing/core/common/features.h
@@ -21,9 +21,6 @@ // Enables adding warning shown timestamp to client safe browsing report. BASE_DECLARE_FEATURE(kAddWarningShownTSToClientSafeBrowsingReport); -// Enables logging new phishing prevention data. -BASE_DECLARE_FEATURE(kAntiPhishingTelemetry); - // Killswitch for client side phishing detection. Since client side models are // run on a large fraction of navigations, crashes due to the model are very // impactful, even if only a small fraction of users have a bad version of the
diff --git a/components/security_interstitials/core/safe_browsing_loud_error_ui.cc b/components/security_interstitials/core/safe_browsing_loud_error_ui.cc index 7811c8a1..b1892cce 100644 --- a/components/security_interstitials/core/safe_browsing_loud_error_ui.cc +++ b/components/security_interstitials/core/safe_browsing_loud_error_ui.cc
@@ -139,10 +139,7 @@ void SafeBrowsingLoudErrorUI::HandleCommand( SecurityInterstitialCommand command) { - if (base::FeatureList::IsEnabled(safe_browsing::kAntiPhishingTelemetry) || - base::FeatureList::IsEnabled(safe_browsing::kRedWarningSurvey)) { - UpdateInterstitialInteractionData(command); - } + UpdateInterstitialInteractionData(command); switch (command) { case CMD_PROCEED: {
diff --git a/components/update_client/component.cc b/components/update_client/component.cc index d3d2652..85c94b7 100644 --- a/components/update_client/component.cc +++ b/components/update_client/component.cc
@@ -921,7 +921,9 @@ component.is_update_available_ = true; component.NotifyObservers(Events::COMPONENT_UPDATE_FOUND); - if (!component.crx_component()->updates_enabled) { + if (!component.crx_component()->updates_enabled || + (!component.crx_component()->allow_updates_on_metered_connection && + component.config()->IsConnectionMetered())) { component.error_category_ = ErrorCategory::kService; component.error_code_ = static_cast<int>(ServiceError::UPDATE_DISABLED); component.extra_code1_ = 0;
diff --git a/components/update_client/configurator.h b/components/update_client/configurator.h index ddba835..0382f5022 100644 --- a/components/update_client/configurator.h +++ b/components/update_client/configurator.h
@@ -149,6 +149,8 @@ // puffin patches. virtual absl::optional<base::FilePath> GetCrxCachePath() const = 0; + virtual bool IsConnectionMetered() const = 0; + protected: friend class base::RefCountedThreadSafe<Configurator>;
diff --git a/components/update_client/test_configurator.cc b/components/update_client/test_configurator.cc index ea72b53..c489e25 100644 --- a/components/update_client/test_configurator.cc +++ b/components/update_client/test_configurator.cc
@@ -12,6 +12,7 @@ #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" #include "base/functional/bind.h" +#include "base/memory/scoped_refptr.h" #include "base/path_service.h" #include "base/time/time.h" #include "base/version.h" @@ -63,7 +64,8 @@ test_shared_loader_factory_, base::BindRepeating([](const GURL& url) { return false; }))), updater_state_provider_(base::BindRepeating( - [](bool /*is_machine*/) { return UpdaterStateAttributes(); })) { + [](bool /*is_machine*/) { return UpdaterStateAttributes(); })), + is_network_connection_metered_(false) { std::ignore = crx_cache_root_temp_dir_.CreateUniqueTempDir(); } @@ -86,15 +88,17 @@ } std::vector<GURL> TestConfigurator::UpdateUrl() const { - if (!update_check_urls_.empty()) + if (!update_check_urls_.empty()) { return update_check_urls_; + } return MakeDefaultUrls(); } std::vector<GURL> TestConfigurator::PingUrl() const { - if (!ping_url_.is_empty()) + if (!ping_url_.is_empty()) { return std::vector<GURL>(1, ping_url_); + } return UpdateUrl(); } @@ -192,6 +196,10 @@ crx_cache_root_temp_dir_.GetPath().AppendASCII("crx_cache")); } +bool TestConfigurator::IsConnectionMetered() const { + return is_network_connection_metered_; +} + void TestConfigurator::SetOnDemandTime(base::TimeDelta time) { ondemand_time_ = time; } @@ -231,6 +239,11 @@ is_machine_externally_managed_ = is_machine_externally_managed; } +void TestConfigurator::SetIsNetworkConnectionMetered( + bool is_network_connection_metered) { + is_network_connection_metered_ = is_network_connection_metered; +} + void TestConfigurator::SetUpdaterStateProvider( UpdaterStateProvider update_state_provider) { updater_state_provider_ = update_state_provider;
diff --git a/components/update_client/test_configurator.h b/components/update_client/test_configurator.h index 63418d2..f6d7db5 100644 --- a/components/update_client/test_configurator.h +++ b/components/update_client/test_configurator.h
@@ -105,6 +105,7 @@ absl::optional<bool> IsMachineExternallyManaged() const override; UpdaterStateProvider GetUpdaterStateProvider() const override; absl::optional<base::FilePath> GetCrxCachePath() const override; + bool IsConnectionMetered() const override; void SetOnDemandTime(base::TimeDelta seconds); void SetInitialDelay(base::TimeDelta seconds); @@ -117,6 +118,7 @@ scoped_refptr<CrxDownloaderFactory> crx_downloader_factory); void SetIsMachineExternallyManaged( absl::optional<bool> is_machine_externally_managed); + void SetIsNetworkConnectionMetered(bool is_network_connection_metered); void SetUpdaterStateProvider(UpdaterStateProvider update_state_provider); network::TestURLLoaderFactory* test_url_loader_factory() { return &test_url_loader_factory_; @@ -146,6 +148,7 @@ scoped_refptr<CrxDownloaderFactory> crx_downloader_factory_; UpdaterStateProvider updater_state_provider_; absl::optional<bool> is_machine_externally_managed_; + bool is_network_connection_metered_; base::ScopedTempDir crx_cache_root_temp_dir_; };
diff --git a/components/update_client/update_checker.cc b/components/update_client/update_checker.cc index 79623ad2..a2111ce4 100644 --- a/components/update_client/update_checker.cc +++ b/components/update_client/update_checker.cc
@@ -183,10 +183,11 @@ sent_ids.push_back(app_id); std::string install_source; - if (!crx_component->install_source.empty()) + if (!crx_component->install_source.empty()) { install_source = crx_component->install_source; - else if (component->is_foreground()) + } else if (component->is_foreground()) { install_source = "ondemand"; + } apps.push_back(MakeProtocolApp( app_id, crx_component->version, crx_component->ap, crx_component->brand, @@ -195,16 +196,20 @@ crx_component->installer_attributes, metadata_->GetCohort(app_id), metadata_->GetCohortHint(app_id), metadata_->GetCohortName(app_id), crx_component->channel, crx_component->disabled_reasons, - MakeProtocolUpdateCheck(!crx_component->updates_enabled, - crx_component->target_version_prefix, - crx_component->rollback_allowed, - crx_component->same_version_update_allowed), + MakeProtocolUpdateCheck( + !crx_component->updates_enabled || + (!crx_component->allow_updates_on_metered_connection && + config_->IsConnectionMetered()), + crx_component->target_version_prefix, + crx_component->rollback_allowed, + crx_component->same_version_update_allowed), [](const std::string& install_data_index) -> std::vector<protocol_request::Data> { - if (install_data_index.empty()) + if (install_data_index.empty()) { return {}; - else + } else { return {{"install", install_data_index, ""}}; + } }(crx_component->install_data_index), MakeProtocolPing(app_id, metadata_, active_ids.find(app_id) != active_ids.end()), @@ -286,14 +291,17 @@ const int daynum = results.daystart_elapsed_days; for (const auto& result : results.list) { auto entry = result.cohort_attrs.find(ProtocolParser::Result::kCohort); - if (entry != result.cohort_attrs.end()) + if (entry != result.cohort_attrs.end()) { metadata_->SetCohort(result.extension_id, entry->second); + } entry = result.cohort_attrs.find(ProtocolParser::Result::kCohortName); - if (entry != result.cohort_attrs.end()) + if (entry != result.cohort_attrs.end()) { metadata_->SetCohortName(result.extension_id, entry->second); + } entry = result.cohort_attrs.find(ProtocolParser::Result::kCohortHint); - if (entry != result.cohort_attrs.end()) + if (entry != result.cohort_attrs.end()) { metadata_->SetCohortHint(result.extension_id, entry->second); + } } base::OnceClosure reply =
diff --git a/components/update_client/update_checker_unittest.cc b/components/update_client/update_checker_unittest.cc index 5b5f2d7..36726b0a 100644 --- a/components/update_client/update_checker_unittest.cc +++ b/components/update_client/update_checker_unittest.cc
@@ -74,7 +74,8 @@ std::unique_ptr<Component> MakeComponent(const std::string& brand) const; std::unique_ptr<Component> MakeComponent( const std::string& brand, - const std::string& install_data_index) const; + const std::string& install_data_index, + bool allow_updates_on_metered_connection) const; absl::optional<base::Value::Dict> ParseRequest(int request_number); base::Value GetFirstAppAsValue(const base::Value::Dict& request); base::Value::Dict GetFirstAppAsDict(const base::Value::Dict& request); @@ -157,8 +158,9 @@ } void UpdateCheckerTest::Quit() { - if (!quit_closure_.is_null()) + if (!quit_closure_.is_null()) { std::move(quit_closure_).Run(); + } } void UpdateCheckerTest::UpdateCheckComplete( @@ -189,12 +191,13 @@ std::unique_ptr<Component> UpdateCheckerTest::MakeComponent( const std::string& brand) const { - return MakeComponent(brand, {}); + return MakeComponent(brand, {}, true); } std::unique_ptr<Component> UpdateCheckerTest::MakeComponent( const std::string& brand, - const std::string& install_data_index) const { + const std::string& install_data_index, + bool allow_updates_on_metered_connection) const { CrxComponent crx_component; crx_component.app_id = "jebgalgnebhfojomionfpkfelancnnkf"; crx_component.brand = brand; @@ -204,6 +207,8 @@ crx_component.installer = nullptr; crx_component.version = base::Version("0.9"); crx_component.fingerprint = "fp1"; + crx_component.allow_updates_on_metered_connection = + allow_updates_on_metered_connection; auto component = std::make_unique<Component>(*update_context_, kUpdateItemId); component->state_ = std::make_unique<Component::StateNew>(component.get()); @@ -258,7 +263,7 @@ update_checker_ = UpdateChecker::Create(config_, metadata_.get()); update_context_->components[kUpdateItemId] = - MakeComponent("TEST", "foobar_install_data_index"); + MakeComponent("TEST", "foobar_install_data_index", true); auto& component = update_context_->components[kUpdateItemId]; component->crx_component_->installer_attributes["ap"] = "some_ap"; @@ -747,14 +752,14 @@ ASSERT_EQ(3, post_interceptor_->GetCount()) << post_interceptor_->GetRequestsAsString(); - { + { absl::optional<base::Value::Dict> root = ParseRequest(0); ASSERT_TRUE(root); const base::Value app = GetFirstAppAsValue(root.value()); EXPECT_EQ(10, app.GetDict().FindIntByDottedPath("ping.a").value()); EXPECT_EQ(-2, app.GetDict().FindIntByDottedPath("ping.r").value()); - } - { + } + { absl::optional<base::Value::Dict> root = ParseRequest(1); ASSERT_TRUE(root); const base::Value app = GetFirstAppAsValue(root.value()); @@ -762,15 +767,15 @@ EXPECT_EQ(3383, app.GetDict().FindByDottedPath("ping.rd")->GetInt()); EXPECT_TRUE( app.GetDict().FindByDottedPath("ping.ping_freshness")->is_string()); - } - { + } + { absl::optional<base::Value::Dict> root = ParseRequest(2); ASSERT_TRUE(root); const base::Value app = GetFirstAppAsValue(root.value()); EXPECT_EQ(3383, app.GetDict().FindByDottedPath("ping.rd")->GetInt()); EXPECT_TRUE( app.GetDict().FindByDottedPath("ping.ping_freshness")->is_string()); - } + } } TEST_P(UpdateCheckerTest, UpdateCheckInstallSource) { @@ -1074,6 +1079,72 @@ } } +TEST_P(UpdateCheckerTest, UpdateDisabledByMeteredConnection) { + update_checker_ = UpdateChecker::Create(config_, metadata_.get()); + + update_context_->components[kUpdateItemId] = + MakeComponent("TEST", "foobar_install_data_index", false); + + auto& component = update_context_->components[kUpdateItemId]; + auto crx_component = component->crx_component(); + + // Ignore this test parameter to keep the test simple. + update_context_->is_foreground = false; + { + // Tests the scenario where: + // * the component updates are enabled on a non-metered connection. + // Expects the the update check to not include the "updatedisabled" + // attribute. + config_->SetIsNetworkConnectionMetered(false); + auto post_interceptor = std::make_unique<URLLoaderPostInterceptor>( + config_->test_url_loader_factory()); + EXPECT_TRUE(post_interceptor->ExpectRequest( + std::make_unique<PartialMatch>("updatecheck"), + GetTestFilePath("updatecheck_reply_1.json"))); + update_checker_->CheckForUpdates( + update_context_, {}, + base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete, + base::Unretained(this))); + RunThreads(); + const auto& request = post_interceptor->GetRequestBody(0); + const auto root = base::JSONReader::Read(request); + ASSERT_TRUE(root); + const base::Value::Dict app = GetFirstAppAsDict(root->GetDict()); + EXPECT_EQ(kUpdateItemId, CHECK_DEREF(app.FindString("appid"))); + EXPECT_EQ("0.9", CHECK_DEREF(app.FindString("version"))); + EXPECT_EQ(true, app.FindBool("enabled")); + EXPECT_TRUE(app.FindDict("updatecheck")->empty()); + } + { + // Tests the scenario where: + // * updates are disabled due to a metered network connection. + // Expects the update check to include the "updatedisabled" attribute. + config_->SetIsNetworkConnectionMetered(true); + component->set_crx_component(*crx_component); + auto post_interceptor = std::make_unique<URLLoaderPostInterceptor>( + config_->test_url_loader_factory()); + EXPECT_TRUE(post_interceptor->ExpectRequest( + std::make_unique<PartialMatch>("updatecheck"), + GetTestFilePath("updatecheck_reply_1.json"))); + update_checker_->CheckForUpdates( + update_context_, {}, + base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete, + base::Unretained(this))); + RunThreads(); + const auto& request = post_interceptor->GetRequestBody(0); + const auto root = base::JSONReader::Read(request); + ASSERT_TRUE(root); + const base::Value app_as_val = GetFirstAppAsValue(root->GetDict()); + const base::Value::Dict app = GetFirstAppAsDict(root->GetDict()); + EXPECT_EQ(kUpdateItemId, CHECK_DEREF(app.FindString("appid"))); + EXPECT_EQ("0.9", CHECK_DEREF(app.FindString("version"))); + EXPECT_EQ(true, app.FindBool("enabled")); + EXPECT_TRUE(app_as_val.GetDict() + .FindBoolByDottedPath("updatecheck.updatedisabled") + .value()); + } +} + TEST_P(UpdateCheckerTest, SameVersionUpdateAllowed) { update_checker_ = UpdateChecker::Create(config_, metadata_.get());
diff --git a/components/update_client/update_client.h b/components/update_client/update_client.h index 3d34920..a6ea29b 100644 --- a/components/update_client/update_client.h +++ b/components/update_client/update_client.h
@@ -378,6 +378,9 @@ // Specifies that this CRX can be cached for differential updates. // The default for this value is |true|. bool allow_cached_copies = true; + + // Specifies whether updates can be initiated on metered network connections. + bool allow_updates_on_metered_connection = true; }; // Called when a non-blocking call of UpdateClient completes.
diff --git a/docs/updater/functional_spec.md b/docs/updater/functional_spec.md index 1f440bb5..3d790df 100644 --- a/docs/updater/functional_spec.md +++ b/docs/updater/functional_spec.md
@@ -1448,8 +1448,9 @@ 24 times but never had a product (besides itself) registered for updates. The updater uninstaller removes all updater files, registry keys, RPC hooks, -scheduled tasks, and so forth from the file system, except that it leaves a -small log file in its data directory. +scheduled tasks, and so forth from the system, except that: +* it leaves a small log file in its data directory. +* it leaves the Clients registry key in Windows registry. ## Associated Tools
diff --git a/ios/chrome/browser/component_updater/model/ios_component_updater_configurator.mm b/ios/chrome/browser/component_updater/model/ios_component_updater_configurator.mm index 1294a49..1608d7d4 100644 --- a/ios/chrome/browser/component_updater/model/ios_component_updater_configurator.mm +++ b/ios/chrome/browser/component_updater/model/ios_component_updater_configurator.mm
@@ -13,6 +13,7 @@ #import "base/containers/flat_map.h" #import "base/files/file_path.h" +#import "base/memory/scoped_refptr.h" #import "base/path_service.h" #import "base/version.h" #import "components/component_updater/component_updater_command_line_config_policy.h" @@ -72,6 +73,7 @@ std::optional<bool> IsMachineExternallyManaged() const override; update_client::UpdaterStateProvider GetUpdaterStateProvider() const override; std::optional<base::FilePath> GetCrxCachePath() const override; + bool IsConnectionMetered() const override; private: friend class base::RefCountedThreadSafe<IOSConfigurator>; @@ -235,6 +237,10 @@ return path.Append(FILE_PATH_LITERAL("ios_crx_cache")); } +bool IOSConfigurator::IsConnectionMetered() const { + return configurator_impl_.IsConnectionMetered(); +} + } // namespace scoped_refptr<update_client::Configurator> MakeIOSComponentUpdaterConfigurator(
diff --git a/ios/chrome/browser/ui/ntp/feed_top_section/feed_top_section_mediator.mm b/ios/chrome/browser/ui/ntp/feed_top_section/feed_top_section_mediator.mm index 539e68c..a24399b 100644 --- a/ios/chrome/browser/ui/ntp/feed_top_section/feed_top_section_mediator.mm +++ b/ios/chrome/browser/ui/ntp/feed_top_section/feed_top_section_mediator.mm
@@ -145,16 +145,12 @@ - (void)notificationsPromoViewMainButtonWasTapped { // Show the Notifications promo alert. - PushNotificationService* service = - GetApplicationContext()->GetPushNotificationService(); - id<SystemIdentity> identity = self.authenticationService->GetPrimaryIdentity( - signin::ConsentLevel::kSignin); __weak FeedTopSectionMediator* weakSelf = self; // Request displaying the OS notifications permission prompt. [PushNotificationUtil requestPushNotificationPermission:^( BOOL granted, BOOL promptShown, NSError* error) { if (error) { - [self updateFeedTopSectionWhenClosed]; + [self closeNotificationPromoAndEnablePref:NO]; return; } if (!promptShown && !granted) { @@ -165,42 +161,25 @@ dispatch_async(dispatch_get_main_queue(), ^{ [weakSelf .notificationsPresenter presentPushNotificationPermissionAlert]; - [self updateFeedTopSectionWhenClosed]; }); return; } if (promptShown && granted) { // If the OS prompt is shown and the user granted notifications access, // save the preference and close the promo. - // This callback can be executed on a background thread, make sure the UI - // is updated on the main thread. - dispatch_async(dispatch_get_main_queue(), ^{ - service->SetPreference(identity.gaiaID, - PushNotificationClientId::kContent, true); - [self updateFeedTopSectionWhenClosed]; - }); - return; - } - if (promptShown && !granted) { - // If the OS prompt is shown and the user denied notifications access, - // close the promo. - // This callback can be executed on a background thread, make sure the UI - // is updated on the main thread. - dispatch_async(dispatch_get_main_queue(), ^{ - [self updateFeedTopSectionWhenClosed]; - }); + [self closeNotificationPromoAndEnablePref:YES]; return; } if (!promptShown && granted) { // If the OS prompt has been previously shown but notifications are not // active on Chrome activate the notifications. This is an edge case. - // This callback can be executed on a background thread, make sure the UI - // is updated on the main thread. - dispatch_async(dispatch_get_main_queue(), ^{ - service->SetPreference(identity.gaiaID, - PushNotificationClientId::kContent, true); - [self updateFeedTopSectionWhenClosed]; - }); + [self closeNotificationPromoAndEnablePref:YES]; + return; + } + if (promptShown && !granted) { + // If the OS prompt is shown and the user denied notifications access, + // close the promo. + [self closeNotificationPromoAndEnablePref:NO]; return; } }]; @@ -208,6 +187,25 @@ #pragma mark - Private +// Helper method to close the promo on the main thread. Takes `enablePref` as a +// parameter which toggles the pref ON only. +- (void)closeNotificationPromoAndEnablePref:(BOOL)enablePref { + // This callback can be executed on a background thread, make sure the UI + // is updated on the main thread. + dispatch_async(dispatch_get_main_queue(), ^{ + if (enablePref) { + PushNotificationService* service = + GetApplicationContext()->GetPushNotificationService(); + id<SystemIdentity> identity = + self.authenticationService->GetPrimaryIdentity( + signin::ConsentLevel::kSignin); + service->SetPreference(identity.gaiaID, + PushNotificationClientId::kContent, true); + } + [self updateFeedTopSectionWhenClosed]; + }); +} + // Handles closing the promo, and the NTP and Feed Top Section layout when the // promo is closed. - (void)updateFeedTopSectionWhenClosed {
diff --git a/ios/web_view/internal/component_updater/web_view_component_updater_configurator.mm b/ios/web_view/internal/component_updater/web_view_component_updater_configurator.mm index 8aee2276..eface87 100644 --- a/ios/web_view/internal/component_updater/web_view_component_updater_configurator.mm +++ b/ios/web_view/internal/component_updater/web_view_component_updater_configurator.mm
@@ -3,7 +3,6 @@ // found in the LICENSE file. #import "ios/web_view/internal/component_updater/web_view_component_updater_configurator.h" -#import "base/time/time.h" #import <stdint.h> @@ -15,6 +14,7 @@ #import "base/containers/flat_map.h" #import "base/files/file_path.h" #import "base/path_service.h" +#import "base/time/time.h" #import "base/version.h" #import "components/component_updater/component_updater_command_line_config_policy.h" #import "components/component_updater/configurator_impl.h" @@ -75,6 +75,7 @@ std::optional<bool> IsMachineExternallyManaged() const override; update_client::UpdaterStateProvider GetUpdaterStateProvider() const override; std::optional<base::FilePath> GetCrxCachePath() const override; + bool IsConnectionMetered() const override; private: friend class base::RefCountedThreadSafe<WebViewConfigurator>; @@ -240,6 +241,10 @@ return path.Append(FILE_PATH_LITERAL("ios_webview_crx_cache")); } +bool WebViewConfigurator::IsConnectionMetered() const { + return configurator_impl_.IsConnectionMetered(); +} + } // namespace scoped_refptr<update_client::Configurator> MakeComponentUpdaterConfigurator(
diff --git a/ios_internal b/ios_internal index d8d82ca..27d0f4f 160000 --- a/ios_internal +++ b/ios_internal
@@ -1 +1 @@ -Subproject commit d8d82ca955498f2a3c907380b829aa6270a64b82 +Subproject commit 27d0f4f79518dfe9f8e15cf52f1130ba3a6a5958
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 90bbf84..9454cf9 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -1437,6 +1437,21 @@ ] } ], + "AutofillEnablePaymentsMandatoryReauth": [ + { + "platforms": [ + "ios" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "AutofillEnablePaymentsMandatoryReauth" + ] + } + ] + } + ], "AutofillEnableSupportForParsingWithSharedLabels": [ { "platforms": [
diff --git a/third_party/angle b/third_party/angle index 82c0ba9..295eece6 160000 --- a/third_party/angle +++ b/third_party/angle
@@ -1 +1 @@ -Subproject commit 82c0ba9350b582eeff34c8c17886ac6b638f281b +Subproject commit 295eece61cce0f7721427d4a42e0fe1821c6d39f
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context.cc b/third_party/blink/renderer/core/display_lock/display_lock_context.cc index b33a596..17f09746 100644 --- a/third_party/blink/renderer/core/display_lock/display_lock_context.cc +++ b/third_party/blink/renderer/core/display_lock/display_lock_context.cc
@@ -581,7 +581,7 @@ // We also need to notify the AX cache (if it exists) to update the childrens // of |element_| in the AX cache. if (auto* ax_cache = element_->GetDocument().ExistingAXObjectCache()) { - ax_cache->SubtreeIsAttached(element_); + ax_cache->RemoveSubtreeWhenSafe(element_); } // Schedule ContentVisibilityAutoStateChange event if needed.
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_colorspace_bgra8unorm.https.html b/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_colorspace_bgra8unorm.https.html index c29e904..9976ea02 100644 --- a/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_colorspace_bgra8unorm.https.html +++ b/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_colorspace_bgra8unorm.https.html
@@ -15,6 +15,7 @@ <link rel="help" href="https://gpuweb.github.io/gpuweb/" /> <meta name="assert" content="WebGPU bgra8norm canvas with colorSpace set should be rendered correctly" /> <link rel="match" href="./ref/canvas_colorspace-ref.html" /> + <meta name=fuzzy content="maxDifference=0-2;totalPixels=0-9999999"> <script type="module"> import { runColorSpaceTest } from './canvas_colorspace.html.js'; runColorSpaceTest('bgra8unorm');
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_colorspace_rgba16float.https.html b/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_colorspace_rgba16float.https.html index 2b868d6..c898d90 100644 --- a/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_colorspace_rgba16float.https.html +++ b/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_colorspace_rgba16float.https.html
@@ -15,7 +15,7 @@ <link rel="help" href="https://gpuweb.github.io/gpuweb/" /> <meta name="assert" content="WebGPU rgba16float canvas with colorSpace set should be rendered correctly" /> <link rel="match" href="./ref/canvas_colorspace-ref.html" /> - <meta name=fuzzy content="maxDifference=1;totalPixels=8192"> + <meta name=fuzzy content="maxDifference=0-2;totalPixels=0-9999999"> <script type="module"> import { runColorSpaceTest } from './canvas_colorspace.html.js'; runColorSpaceTest('rgba16float');
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_colorspace_rgba8unorm.https.html b/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_colorspace_rgba8unorm.https.html index 33fb6dc..eafd264e 100644 --- a/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_colorspace_rgba8unorm.https.html +++ b/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_colorspace_rgba8unorm.https.html
@@ -15,6 +15,7 @@ <link rel="help" href="https://gpuweb.github.io/gpuweb/" /> <meta name="assert" content="WebGPU rgba8unorm canvas with colorSpace set should be rendered correctly" /> <link rel="match" href="./ref/canvas_colorspace-ref.html" /> + <meta name=fuzzy content="maxDifference=0-2;totalPixels=0-9999999"> <script type="module"> import { runColorSpaceTest } from './canvas_colorspace.html.js'; runColorSpaceTest('rgba8unorm');
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_composite_alpha_bgra8unorm_premultiplied_copy.https.html b/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_composite_alpha_bgra8unorm_premultiplied_copy.https.html index 9633eb8..972ee26d 100644 --- a/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_composite_alpha_bgra8unorm_premultiplied_copy.https.html +++ b/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_composite_alpha_bgra8unorm_premultiplied_copy.https.html
@@ -9,7 +9,7 @@ content="WebGPU canvas should have correct orientation, components, scaling, filtering, color space" /> <link rel="match" href="./ref/canvas_composite_alpha_premultiplied-ref.html" /> - <meta name=fuzzy content="maxDifference=0-2;totalPixels=0-400"> + <meta name=fuzzy content="maxDifference=0-2;totalPixels=0-9999999"> <style> body { background-color: #F0E68C; } #c-canvas { background-color: #8CF0E6; }
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_composite_alpha_bgra8unorm_premultiplied_draw.https.html b/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_composite_alpha_bgra8unorm_premultiplied_draw.https.html index 8800d93c2..cde343ed 100644 --- a/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_composite_alpha_bgra8unorm_premultiplied_draw.https.html +++ b/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_composite_alpha_bgra8unorm_premultiplied_draw.https.html
@@ -9,7 +9,7 @@ content="WebGPU canvas should have correct orientation, components, scaling, filtering, color space" /> <link rel="match" href="./ref/canvas_composite_alpha_premultiplied-ref.html" /> - <meta name=fuzzy content="maxDifference=0-2;totalPixels=0-400"> + <meta name=fuzzy content="maxDifference=0-2;totalPixels=0-9999999"> <style> body { background-color: #F0E68C; } #c-canvas { background-color: #8CF0E6; }
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_composite_alpha_rgba16float_premultiplied_copy.https.html b/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_composite_alpha_rgba16float_premultiplied_copy.https.html index 77597b54..c3241d9a 100644 --- a/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_composite_alpha_rgba16float_premultiplied_copy.https.html +++ b/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_composite_alpha_rgba16float_premultiplied_copy.https.html
@@ -9,7 +9,7 @@ content="WebGPU canvas should have correct orientation, components, scaling, filtering, color space" /> <link rel="match" href="./ref/canvas_composite_alpha_premultiplied-ref.html" /> - <meta name=fuzzy content="maxDifference=0-2;totalPixels=0-400"> + <meta name=fuzzy content="maxDifference=0-2;totalPixels=0-9999999"> <style> body { background-color: #F0E68C; } #c-canvas { background-color: #8CF0E6; }
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_composite_alpha_rgba16float_premultiplied_draw.https.html b/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_composite_alpha_rgba16float_premultiplied_draw.https.html index 9b2baf5..80cca9b 100644 --- a/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_composite_alpha_rgba16float_premultiplied_draw.https.html +++ b/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_composite_alpha_rgba16float_premultiplied_draw.https.html
@@ -9,7 +9,7 @@ content="WebGPU canvas should have correct orientation, components, scaling, filtering, color space" /> <link rel="match" href="./ref/canvas_composite_alpha_premultiplied-ref.html" /> - <meta name=fuzzy content="maxDifference=0-2;totalPixels=0-400"> + <meta name=fuzzy content="maxDifference=0-2;totalPixels=0-9999999"> <style> body { background-color: #F0E68C; } #c-canvas { background-color: #8CF0E6; }
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_composite_alpha_rgba8unorm_premultiplied_copy.https.html b/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_composite_alpha_rgba8unorm_premultiplied_copy.https.html index b5ca6a88..510ba1da 100644 --- a/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_composite_alpha_rgba8unorm_premultiplied_copy.https.html +++ b/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_composite_alpha_rgba8unorm_premultiplied_copy.https.html
@@ -9,7 +9,7 @@ content="WebGPU canvas should have correct orientation, components, scaling, filtering, color space" /> <link rel="match" href="./ref/canvas_composite_alpha_premultiplied-ref.html" /> - <meta name=fuzzy content="maxDifference=0-2;totalPixels=0-400"> + <meta name=fuzzy content="maxDifference=0-2;totalPixels=0-9999999"> <style> body { background-color: #F0E68C; } #c-canvas { background-color: #8CF0E6; }
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_composite_alpha_rgba8unorm_premultiplied_draw.https.html b/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_composite_alpha_rgba8unorm_premultiplied_draw.https.html index cacc4879..20655f6 100644 --- a/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_composite_alpha_rgba8unorm_premultiplied_draw.https.html +++ b/third_party/blink/web_tests/wpt_internal/webgpu/web_platform/reftests/canvas_composite_alpha_rgba8unorm_premultiplied_draw.https.html
@@ -9,7 +9,7 @@ content="WebGPU canvas should have correct orientation, components, scaling, filtering, color space" /> <link rel="match" href="./ref/canvas_composite_alpha_premultiplied-ref.html" /> - <meta name=fuzzy content="maxDifference=0-2;totalPixels=0-400"> + <meta name=fuzzy content="maxDifference=0-2;totalPixels=0-9999999"> <style> body { background-color: #F0E68C; } #c-canvas { background-color: #8CF0E6; }
diff --git a/third_party/depot_tools b/third_party/depot_tools index 86752e9..259976c 160000 --- a/third_party/depot_tools +++ b/third_party/depot_tools
@@ -1 +1 @@ -Subproject commit 86752e9a55281200715749d75a88cf57bf2e7b01 +Subproject commit 259976c7483c321c122169d193e150310f4ea609
diff --git a/third_party/skia b/third_party/skia index 063e339..dd40779 160000 --- a/third_party/skia +++ b/third_party/skia
@@ -1 +1 @@ -Subproject commit 063e339bedfcfb9d7c921cd92d9a902ef008ce76 +Subproject commit dd4077962cd5456478501f733af12b5dfb17b3ea
diff --git a/third_party/webgpu-cts/src b/third_party/webgpu-cts/src index f20c5f7b..ae15a59 160000 --- a/third_party/webgpu-cts/src +++ b/third_party/webgpu-cts/src
@@ -1 +1 @@ -Subproject commit f20c5f7b8f53904edaa98651d764e1b8305d7c14 +Subproject commit ae15a59832989c22982acaeaccdf5d379afced62
diff --git a/third_party/webgpu-cts/ts_sources.txt b/third_party/webgpu-cts/ts_sources.txt index 866365b..2fa63cf 100644 --- a/third_party/webgpu-cts/ts_sources.txt +++ b/third_party/webgpu-cts/ts_sources.txt
@@ -146,6 +146,7 @@ src/unittests/texture_ok.spec.ts src/webgpu/examples.spec.ts src/webgpu/listing.ts +src/webgpu/multisample_info.ts src/webgpu/api/operation/labels.spec.ts src/webgpu/api/operation/onSubmittedWorkDone.spec.ts src/webgpu/api/operation/reflection.spec.ts @@ -348,8 +349,9 @@ src/webgpu/compat/api/validation/render_pipeline/vertex_state.spec.ts src/webgpu/compat/api/validation/texture/createTexture.spec.ts src/webgpu/compat/api/validation/texture/cubeArray.spec.ts -src/webgpu/idl/exposed.html.ts src/webgpu/idl/idl_test.ts +src/webgpu/idl/constructable.spec.ts +src/webgpu/idl/exposed.html.ts src/webgpu/idl/constants/flags.spec.ts src/webgpu/shader/types.ts src/webgpu/shader/values.ts @@ -647,6 +649,7 @@ src/webgpu/shader/execution/memory_model/coherence.spec.ts src/webgpu/shader/execution/memory_model/weak.spec.ts src/webgpu/shader/execution/shader_io/compute_builtins.spec.ts +src/webgpu/shader/execution/shader_io/fragment_builtins.spec.ts src/webgpu/shader/execution/shader_io/shared_structs.spec.ts src/webgpu/shader/execution/statement/increment_decrement.spec.ts src/webgpu/shader/validation/shader_validation_test.ts
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 2b9bf5b..f632df73 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -26914,6 +26914,8 @@ <int value="-1520952503" label="SearchReadyOmnibox:enabled"/> <int value="-1520901408" label="FuseBoxDebug:disabled"/> <int value="-1520855274" label="PWAFullCodeCache:disabled"/> + <int value="-1520821533" + label="HoldingSpaceWallpaperNudgeForceEligibility:disabled"/> <int value="-1520645293" label="InterestFeedNoticeCardAutoDismiss:disabled"/> <int value="-1520630395" label="DefaultPassthroughCommandDecoder:disabled"/> <int value="-1517929127" label="DelegatedCompositing:enabled"/> @@ -28035,6 +28037,8 @@ label="ExperimentalAccessibilityColorEnhancementSettings:disabled"/> <int value="-1002537430" label="HudDisplayForPerformanceMetrics:disabled"/> <int value="-1002494650" label="WebviewTagMPArchBehavior:disabled"/> + <int value="-1002421482" + label="HoldingSpaceWallpaperNudgeForceEligibility:enabled"/> <int value="-1001837588" label="EnableAppReinstallZeroState:enabled"/> <int value="-1000695123" label="AccessibilitySelectToSpeakPageMigration:disabled"/> @@ -30953,6 +30957,7 @@ <int value="370486304" label="enable-origin-chip-on-srp"/> <int value="370926002" label="FirmwareUpdateUIV2:enabled"/> <int value="371268743" label="OmniboxUIExperimentVerticalMargin:disabled"/> + <int value="371496127" label="HoldingSpaceWallpaperNudge:enabled"/> <int value="372460068" label="QuickUnlockFingerprint:disabled"/> <int value="373177941" label="DockedMagnifier:enabled"/> <int value="373193557" label="LongPressBackNewDesign:enabled"/> @@ -31948,6 +31953,7 @@ <int value="845659238" label="DevicePosture:enabled"/> <int value="846887449" label="BluetoothFlossTelephony:disabled"/> <int value="846951416" label="CopylessPaste:enabled"/> + <int value="847000540" label="HoldingSpaceWallpaperNudge:disabled"/> <int value="848005486" label="WebViewLegacyTlsSupport:disabled"/> <int value="848324390" label="enable-lock-screen-apps"/> <int value="849235409" label="Prerender2InNewTab:enabled"/>
diff --git a/ui/aura/gestures/gesture_recognizer_unittest.cc b/ui/aura/gestures/gesture_recognizer_unittest.cc index c319b27..f8e2c8d 100644 --- a/ui/aura/gestures/gesture_recognizer_unittest.cc +++ b/ui/aura/gestures/gesture_recognizer_unittest.cc
@@ -4343,7 +4343,7 @@ ui::TouchEvent move1( ui::ET_TOUCH_MOVED, gfx::Point(397, 149), tes.LeapForward(50), ui::PointerDetails(ui::EventPointerType::kTouch, kTouchId)); - move1.set_flags(992); + move1.SetFlags(992); DispatchEventUsingWindowDispatcher(&move1); EXPECT_NE(default_flags, delegate->flags());
diff --git a/ui/aura/window_event_dispatcher.cc b/ui/aura/window_event_dispatcher.cc index a63e34b..ab5f160 100644 --- a/ui/aura/window_event_dispatcher.cc +++ b/ui/aura/window_event_dispatcher.cc
@@ -899,7 +899,7 @@ int flags = event->flags(); if (IsNonClientLocation(target, event->location())) flags |= ui::EF_IS_NON_CLIENT; - event->set_flags(flags); + event->SetFlags(flags); if (!is_dispatched_held_event(*event) && (event->IsMouseEvent() || event->IsScrollEvent()) &&
diff --git a/ui/events/ash/event_rewriter_ash.cc b/ui/events/ash/event_rewriter_ash.cc index 807a6740..7f94e05 100644 --- a/ui/events/ash/event_rewriter_ash.cc +++ b/ui/events/ash/event_rewriter_ash.cc
@@ -1469,7 +1469,7 @@ if (sticky_keys_controller_) { KeyEvent tmp_event = key_event; tmp_event.set_key_code(state.key_code); - tmp_event.set_flags(state.flags); + tmp_event.SetFlags(state.flags); std::unique_ptr<Event> output_event; status = sticky_keys_controller_->RewriteEvent(tmp_event, &output_event); if (status == EVENT_REWRITE_REWRITTEN || @@ -1527,7 +1527,7 @@ EventRewriteStatus status = EVENT_REWRITE_CONTINUE; if (sticky_keys_controller_) { MouseEvent tmp_event = mouse_event; - tmp_event.set_flags(flags); + tmp_event.SetFlags(flags); std::unique_ptr<Event> output_event; status = sticky_keys_controller_->RewriteEvent(tmp_event, &output_event); if (status == EVENT_REWRITE_REWRITTEN || @@ -1545,7 +1545,7 @@ } std::unique_ptr<Event> rewritten_event = mouse_event.Clone(); - rewritten_event->set_flags(flags); + rewritten_event->SetFlags(flags); if (changed_button != EF_NONE) { static_cast<MouseEvent*>(rewritten_event.get()) ->set_changed_button_flags(changed_button); @@ -1572,7 +1572,7 @@ const int flags = RewriteLocatedEvent(wheel_event); MouseWheelEvent tmp_event = wheel_event; - tmp_event.set_flags(flags); + tmp_event.SetFlags(flags); return sticky_keys_controller_->RewriteEvent(tmp_event, continuation); } @@ -1584,7 +1584,7 @@ return SendEvent(continuation, &touch_event); } TouchEvent rewritten_touch_event(touch_event); - rewritten_touch_event.set_flags(flags); + rewritten_touch_event.SetFlags(flags); return SendEventFinally(continuation, &rewritten_touch_event); }
diff --git a/ui/events/event.cc b/ui/events/event.cc index e636a2a1..b40b117 100644 --- a/ui/events/event.cc +++ b/ui/events/event.cc
@@ -299,6 +299,11 @@ result_ = static_cast<EventResult>(result_ | ER_CONSUMED | ER_SKIPPED); } +void Event::SetFlags(int flags) { + flags_ = flags; + OnFlagsUpdated(); +} + std::string Event::ToString() const { return base::StrCat( {GetName(), " time_stamp=", @@ -589,7 +594,7 @@ f |= EF_IS_TRIPLE_CLICK; break; } - set_flags(f); + SetFlags(f); } std::string MouseEvent::ToString() const { @@ -942,7 +947,7 @@ // Check if this is a key repeat. This must be called before initial flags // processing, e.g: NormalizeFlags(), to avoid issues like crbug.com/1069690. if (synthesize_key_repeat_enabled_ && IsRepeated(GetLastKeyEvent())) - set_flags(flags() | EF_IS_REPEAT); + SetFlags(flags() | EF_IS_REPEAT); #if BUILDFLAG(IS_LINUX) NormalizeFlags(); @@ -950,11 +955,11 @@ // Only Windows has native character events. if (is_char_) { key_ = DomKey::FromCharacter(static_cast<int32_t>(native_event().wParam)); - set_flags(PlatformKeyMap::ReplaceControlAndAltWithAltGraph(flags())); + SetFlags(PlatformKeyMap::ReplaceControlAndAltWithAltGraph(flags())); } else { int adjusted_flags = flags(); key_ = PlatformKeyMap::DomKeyFromKeyboardCode(key_code(), &adjusted_flags); - set_flags(adjusted_flags); + SetFlags(adjusted_flags); } #endif } @@ -1046,7 +1051,7 @@ if (is_repeat) { last->set_time_stamp(time_stamp()); - last->set_flags(last->flags() | EF_IS_REPEAT); + last->SetFlags(last->flags() | EF_IS_REPEAT); return true; } @@ -1158,9 +1163,9 @@ return; } if (type() == ET_KEY_PRESSED) - set_flags(flags() | mask); + SetFlags(flags() | mask); else - set_flags(flags() & ~mask); + SetFlags(flags() & ~mask); } std::string KeyEvent::ToString() const {
diff --git a/ui/events/event.h b/ui/events/event.h index f05e45e6..135b2a3 100644 --- a/ui/events/event.h +++ b/ui/events/event.h
@@ -88,10 +88,7 @@ // This is only intended to be used externally by classes that are modifying // events in an EventRewriter. - void set_flags(int flags) { - flags_ = flags; - OnFlagsUpdated(); - } + void SetFlags(int flags); EventTarget* target() const { return target_; } EventPhase phase() const { return phase_; } @@ -478,7 +475,7 @@ movement_(model.movement_), pointer_details_(model.pointer_details_) { SetType(type); - set_flags(flags); + SetFlags(flags); } // Note: Use the ctor for MouseWheelEvent if type is ET_MOUSEWHEEL. @@ -516,7 +513,7 @@ // TODO(eirage): convert this to builder pattern. void set_movement(const gfx::Vector2dF& movement) { event_->movement_ = movement; - event_->set_flags(event_->flags() | EF_UNADJUSTED_MOUSE); + event_->SetFlags(event_->flags() | EF_UNADJUSTED_MOUSE); } private:
diff --git a/ui/events/gestures/motion_event_aura_unittest.cc b/ui/events/gestures/motion_event_aura_unittest.cc index 3228a4e1..69a08e6 100644 --- a/ui/events/gestures/motion_event_aura_unittest.cc +++ b/ui/events/gestures/motion_event_aura_unittest.cc
@@ -446,12 +446,12 @@ MotionEventAura event; TouchEvent press0 = TouchWithType(ET_TOUCH_PRESSED, ids[0]); - press0.set_flags(EF_CONTROL_DOWN); + press0.SetFlags(EF_CONTROL_DOWN); EXPECT_TRUE(event.OnTouch(press0)); EXPECT_EQ(EF_CONTROL_DOWN, event.GetFlags()); TouchEvent press1 = TouchWithType(ET_TOUCH_PRESSED, ids[1]); - press1.set_flags(EF_CONTROL_DOWN | EF_CAPS_LOCK_ON); + press1.SetFlags(EF_CONTROL_DOWN | EF_CAPS_LOCK_ON); EXPECT_TRUE(event.OnTouch(press1)); EXPECT_EQ(EF_CONTROL_DOWN | EF_CAPS_LOCK_ON, event.GetFlags()); }
diff --git a/ui/events/win/media_keyboard_hook_win.cc b/ui/events/win/media_keyboard_hook_win.cc index 8436668..485710e 100644 --- a/ui/events/win/media_keyboard_hook_win.cc +++ b/ui/events/win/media_keyboard_hook_win.cc
@@ -107,7 +107,7 @@ std::unique_ptr<KeyEvent> key_event = std::make_unique<KeyEvent>(KeyEventFromMSG(msg)); if (is_repeat) - key_event->set_flags(key_event->flags() | EF_IS_REPEAT); + key_event->SetFlags(key_event->flags() | EF_IS_REPEAT); ForwardCapturedKeyEvent(key_event.get()); // If the event is handled, don't propagate to the OS.
diff --git a/ui/events/win/modifier_keyboard_hook_win.cc b/ui/events/win/modifier_keyboard_hook_win.cc index de4d2c3..800585d5 100644 --- a/ui/events/win/modifier_keyboard_hook_win.cc +++ b/ui/events/win/modifier_keyboard_hook_win.cc
@@ -272,7 +272,7 @@ std::unique_ptr<KeyEvent> key_event = std::make_unique<KeyEvent>(KeyEventFromMSG(msg)); if (is_repeat) - key_event->set_flags(key_event->flags() | EF_IS_REPEAT); + key_event->SetFlags(key_event->flags() | EF_IS_REPEAT); ForwardCapturedKeyEvent(key_event.get()); return true;
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_tap_handler_unittest.js b/ui/file_manager/file_manager/foreground/js/ui/file_tap_handler_unittest.ts similarity index 76% rename from ui/file_manager/file_manager/foreground/js/ui/file_tap_handler_unittest.js rename to ui/file_manager/file_manager/foreground/js/ui/file_tap_handler_unittest.ts index 0915dd3d..6efc6ff 100644 --- a/ui/file_manager/file_manager/foreground/js/ui/file_tap_handler_unittest.js +++ b/ui/file_manager/file_manager/foreground/js/ui/file_tap_handler_unittest.ts
@@ -6,38 +6,23 @@ import {FileTapHandler, TapEvent} from './file_tap_handler.js'; -/** @type {!FileTapHandler} handler the handler. */ -let handler; +let handler: FileTapHandler; -/** - * @type {!Element} - */ -let dummyTarget; +let dummyTarget: Element; -/** - * @type {!Array<!Object>} - */ -let events; +let events: Array<{index: number, eventType: TapEvent}>; -/** - * @type {function(!Event, number, !TapEvent):boolean} - */ -// @ts-ignore: error TS6133: 'e' is declared but its value is never read. -const handleTap = (e, index, eventType) => { - events.push({index: index, eventType: eventType}); - return false; -}; +const handleTap = + (_e: TouchEvent, index: number, eventType: TapEvent): boolean => { + events.push({index, eventType}); + return false; + }; -/** - * @param {number} identifier - * @param {number} clientX - * @param {number} clientY - */ -function createTouch(identifier, clientX, clientY) { +function createTouch(identifier: number, clientX: number, clientY: number) { return new Touch({ - identifier: identifier, - clientX: clientX, - clientY: clientY, + identifier, + clientX, + clientY, target: dummyTarget, }); } @@ -70,11 +55,8 @@ // A tap event should be emitted for a single tap. assertEquals(1, events.length); - // @ts-ignore: error TS2339: Property 'eventType' does not exist on type - // 'Object'. - assertEquals(TapEvent.TAP, events[0].eventType); - // @ts-ignore: error TS2339: Property 'index' does not exist on type 'Object'. - assertEquals(0, events[0].index); + assertEquals(TapEvent.TAP, events[0]!.eventType); + assertEquals(0, events[0]!.index); } export function testTapMoveTolerance() { @@ -129,12 +111,8 @@ }); // A long press should be emitted if there was no movement. assertEquals(1, events.length); - // @ts-ignore: error TS2339: Property 'eventType' does not exist on type - // 'Object'. - assertEquals(TapEvent.LONG_PRESS, events[0].eventType); - // @ts-ignore: error TS2339: Property 'index' does not exist on type - // 'Object'. - assertEquals(0, events[0].index); + assertEquals(TapEvent.LONG_PRESS, events[0]!.eventType); + assertEquals(0, events[0]!.index); handler.handleTouchEvents( new TouchEvent('touchend', { cancelable: true, @@ -145,12 +123,8 @@ 1, handleTap); // A long tap should be emitted if there was no movement. assertEquals(2, events.length); - // @ts-ignore: error TS2339: Property 'eventType' does not exist on type - // 'Object'. - assertEquals(TapEvent.LONG_TAP, events[1].eventType); - // @ts-ignore: error TS2339: Property 'index' does not exist on type - // 'Object'. - assertEquals(0, events[1].index); + assertEquals(TapEvent.LONG_TAP, events[1]!.eventType); + assertEquals(0, events[1]!.index); } export async function testLongTapMoveTolerance() { @@ -244,11 +218,8 @@ // A two-finger tap event should be emitted, allowing for slight movement. assertEquals(1, events.length); - // @ts-ignore: error TS2339: Property 'eventType' does not exist on type - // 'Object'. - assertEquals(TapEvent.TWO_FINGER_TAP, events[0].eventType); - // @ts-ignore: error TS2339: Property 'index' does not exist on type 'Object'. - assertEquals(0, events[0].index); + assertEquals(TapEvent.TWO_FINGER_TAP, events[0]!.eventType); + assertEquals(0, events[0]!.index); // case 2: Release the first touch point first. handler.handleTouchEvents( @@ -286,9 +257,6 @@ // A two-finger tap event should be emitted. assertEquals(2, events.length); - // @ts-ignore: error TS2339: Property 'eventType' does not exist on type - // 'Object'. - assertEquals(TapEvent.TWO_FINGER_TAP, events[1].eventType); - // @ts-ignore: error TS2339: Property 'index' does not exist on type 'Object'. - assertEquals(10, events[1].index); + assertEquals(TapEvent.TWO_FINGER_TAP, events[1]!.eventType); + assertEquals(10, events[1]!.index); }
diff --git a/ui/file_manager/file_names.gni b/ui/file_manager/file_names.gni index e731ded..effb7fa8 100644 --- a/ui/file_manager/file_names.gni +++ b/ui/file_manager/file_names.gni
@@ -534,6 +534,7 @@ "file_manager/foreground/js/ui/file_manager_dialog_base_unittest.ts", "file_manager/foreground/js/ui/file_table_list_unittest.ts", "file_manager/foreground/js/ui/file_table_unittest.ts", + "file_manager/foreground/js/ui/file_tap_handler_unittest.ts", "file_manager/foreground/js/ui/grid_unittest.ts", "file_manager/foreground/js/ui/install_linux_package_dialog_unittest.ts", "file_manager/foreground/js/ui/menu_unittest.ts", @@ -627,7 +628,6 @@ # Test files: unittest_files = [ # Foreground: - "file_manager/foreground/js/ui/file_tap_handler_unittest.js", "file_manager/foreground/js/ui/directory_tree_unittest.js", "file_manager/foreground/js/navigation_list_model_unittest.js",
diff --git a/ui/platform_window/win/win_window.cc b/ui/platform_window/win/win_window.cc index 605e36b..fad36c24 100644 --- a/ui/platform_window/win/win_window.cc +++ b/ui/platform_window/win/win_window.cc
@@ -257,7 +257,7 @@ {CR_GET_X_LPARAM(l_param), CR_GET_Y_LPARAM(l_param)}}; std::unique_ptr<Event> event = EventFromNative(msg); if (IsMouseEventFromTouch(message)) - event->set_flags(event->flags() | EF_FROM_TOUCH); + event->SetFlags(event->flags() | EF_FROM_TOUCH); if (!(event->flags() & ui::EF_IS_NON_CLIENT)) delegate_->DispatchEvent(event.get()); SetMsgHandled(event->handled());
diff --git a/ui/views/controls/textfield/textfield_unittest.cc b/ui/views/controls/textfield/textfield_unittest.cc index 269eb44..345a78e 100644 --- a/ui/views/controls/textfield/textfield_unittest.cc +++ b/ui/views/controls/textfield/textfield_unittest.cc
@@ -3437,7 +3437,7 @@ ui::MouseEvent press_2(ui::ET_MOUSE_PRESSED, point_2, point_2, ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); - press_2.set_flags(press_2.flags() | ui::EF_SHIFT_DOWN); + press_2.SetFlags(press_2.flags() | ui::EF_SHIFT_DOWN); textfield_->OnMousePressed(press_2); ui::MouseEvent release_2(ui::ET_MOUSE_RELEASED, point_2, point_2, ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
diff --git a/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.cc b/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.cc index 2e69d7e0..a5c8ab5 100644 --- a/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.cc +++ b/ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.cc
@@ -364,7 +364,7 @@ auto event = std::make_unique<ui::DropTargetEvent>( *data_to_drop_, target_location, gfx::PointF(root_location), last_drop_operation_); - event->set_flags(modifiers); + event->SetFlags(modifiers); if (delegate_has_changed) drag_drop_delegate_->OnDragEntered(*event); return event;
diff --git a/ui/views/widget/desktop_aura/desktop_drop_target_win.cc b/ui/views/widget/desktop_aura/desktop_drop_target_win.cc index 0d13d59..bcabe6e 100644 --- a/ui/views/widget/desktop_aura/desktop_drop_target_win.cc +++ b/ui/views/widget/desktop_aura/desktop_drop_target_win.cc
@@ -151,7 +151,7 @@ *event = std::make_unique<ui::DropTargetEvent>( *(data->get()), gfx::PointF(location), gfx::PointF(root_location), ui::DragDropTypes::DropEffectToDragOperation(effect)); - (*event)->set_flags(ConvertKeyStateToAuraEventFlags(key_state)); + (*event)->SetFlags(ConvertKeyStateToAuraEventFlags(key_state)); if (target_window_changed) (*delegate)->OnDragEntered(*event->get()); }
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.cc index 9dbf82a..cb1601b 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.cc +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_linux.cc
@@ -204,7 +204,7 @@ gfx::ToRoundedPoint(location_in_dip)); if (hit_test_code != HTCLIENT && hit_test_code != HTNOWHERE) flags |= ui::EF_IS_NON_CLIENT; - located_event->set_flags(flags); + located_event->SetFlags(flags); } // While we unset the urgency hint when we gain focus, we also must remove
diff --git a/ui/views/widget/root_view.cc b/ui/views/widget/root_view.cc index 9478b2d4..1b398ba 100644 --- a/ui/views/widget/root_view.cc +++ b/ui/views/widget/root_view.cc
@@ -481,7 +481,7 @@ // Remove the double-click flag if the handler is different than the // one which got the first click part of the double-click. if (mouse_pressed_handler_ != last_click_handler_) - mouse_pressed_event.set_flags(event.flags() & ~ui::EF_IS_DOUBLE_CLICK); + mouse_pressed_event.SetFlags(event.flags() & ~ui::EF_IS_DOUBLE_CLICK); drag_info_.Reset(); ui::EventDispatchDetails dispatch_details =
diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc index 8044dca..36a6e980 100644 --- a/ui/views/win/hwnd_message_handler.cc +++ b/ui/views/win/hwnd_message_handler.cc
@@ -3191,7 +3191,7 @@ {CR_GET_X_LPARAM(l_param), CR_GET_Y_LPARAM(l_param)}}; ui::MouseEvent event(msg); if (IsSynthesizedMouseMessage(message, message_time, l_param)) - event.set_flags(event.flags() | ui::EF_FROM_TOUCH); + event.SetFlags(event.flags() | ui::EF_FROM_TOUCH); if (event.type() == ui::ET_MOUSE_MOVED && !HasCapture() && track_mouse) { // Windows only fires WM_MOUSELEAVE events if the application begins @@ -3500,7 +3500,7 @@ ui::TouchEvent event(event_type, point, time_stamp, ui::PointerDetails(ui::EventPointerType::kTouch, id)); - event.set_flags(ui::GetModifiersFromKeyState()); + event.SetFlags(ui::GetModifiersFromKeyState()); event.latency()->AddLatencyNumberWithTimestamp( ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, time_stamp);
diff --git a/ui/webui/resources/cr_elements/cr_a11y_announcer/cr_a11y_announcer.ts b/ui/webui/resources/cr_elements/cr_a11y_announcer/cr_a11y_announcer.ts index 89b7d92..99359428 100644 --- a/ui/webui/resources/cr_elements/cr_a11y_announcer/cr_a11y_announcer.ts +++ b/ui/webui/resources/cr_elements/cr_a11y_announcer/cr_a11y_announcer.ts
@@ -3,7 +3,7 @@ // found in the LICENSE file. import {assert} from '//resources/js/assert.js'; -import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {CustomElement} from '//resources/js/custom_element.js'; import {getTemplate} from './cr_a11y_announcer.html.js'; @@ -50,20 +50,19 @@ return instance; } -export class CrA11yAnnouncerElement extends PolymerElement { +export class CrA11yAnnouncerElement extends CustomElement { static get is() { return 'cr-a11y-announcer'; } - static get template() { + static override get template() { return getTemplate(); } private currentTimeout_: number|null = null; private messages_: string[] = []; - override disconnectedCallback() { - super.disconnectedCallback(); + disconnectedCallback() { if (this.currentTimeout_ !== null) { clearTimeout(this.currentTimeout_); this.currentTimeout_ = null;
diff --git a/ui/wm/core/compound_event_filter_unittest.cc b/ui/wm/core/compound_event_filter_unittest.cc index 4feb7a7..de4cfed 100644 --- a/ui/wm/core/compound_event_filter_unittest.cc +++ b/ui/wm/core/compound_event_filter_unittest.cc
@@ -74,13 +74,13 @@ // Synthesized mouse event should not show the cursor. ui::MouseEvent enter(ui::ET_MOUSE_ENTERED, gfx::Point(10, 10), gfx::Point(10, 10), ui::EventTimeForNow(), 0, 0); - enter.set_flags(enter.flags() | ui::EF_IS_SYNTHESIZED); + enter.SetFlags(enter.flags() | ui::EF_IS_SYNTHESIZED); DispatchEventUsingWindowDispatcher(&enter); EXPECT_FALSE(cursor_client.IsCursorVisible()); ui::MouseEvent move(ui::ET_MOUSE_MOVED, gfx::Point(10, 10), gfx::Point(10, 10), ui::EventTimeForNow(), 0, 0); - move.set_flags(enter.flags() | ui::EF_IS_SYNTHESIZED); + move.SetFlags(enter.flags() | ui::EF_IS_SYNTHESIZED); DispatchEventUsingWindowDispatcher(&move); EXPECT_FALSE(cursor_client.IsCursorVisible()); @@ -107,7 +107,7 @@ // Mouse synthesized exit event should not show the cursor. ui::MouseEvent exit(ui::ET_MOUSE_EXITED, gfx::Point(10, 10), gfx::Point(10, 10), ui::EventTimeForNow(), 0, 0); - exit.set_flags(enter.flags() | ui::EF_IS_SYNTHESIZED); + exit.SetFlags(enter.flags() | ui::EF_IS_SYNTHESIZED); DispatchEventUsingWindowDispatcher(&exit); EXPECT_FALSE(cursor_client.IsCursorVisible()); @@ -245,12 +245,12 @@ ui::MouseEvent mouse0(ui::ET_MOUSE_MOVED, gfx::Point(10, 10), gfx::Point(10, 10), ui::EventTimeForNow(), 0, 0); - mouse0.set_flags(mouse0.flags() | ui::EF_FROM_TOUCH); + mouse0.SetFlags(mouse0.flags() | ui::EF_FROM_TOUCH); DispatchEventUsingWindowDispatcher(&mouse0); EXPECT_FALSE(cursor_client.IsMouseEventsEnabled()); - mouse0.set_flags(mouse0.flags() & ~ui::EF_FROM_TOUCH); + mouse0.SetFlags(mouse0.flags() & ~ui::EF_FROM_TOUCH); DispatchEventUsingWindowDispatcher(&mouse0); EXPECT_TRUE(cursor_client.IsMouseEventsEnabled());