diff --git a/DEPS b/DEPS index 1544d02..5484766 100644 --- a/DEPS +++ b/DEPS
@@ -272,7 +272,7 @@ # reclient CIPD package 'reclient_package': 'infra/rbe/client/', # reclient CIPD package version - 'reclient_version': 're_client_version:0.124.1.13f78cc-gomaip', + 'reclient_version': 're_client_version:0.125.0.f3883c2-gomaip', # The path of the sysroots.json file. # This is used by vendor builds like Electron. @@ -299,15 +299,15 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'src_internal_revision': 'eff5a4585a80e2b59b057dd145e5931c768ebc6d', + 'src_internal_revision': '2f4e35e9c81b8c737b0a03b3d28d374831d66aff', # 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': '4170fba2d89fc0319aad5702a15acdee4470f606', + 'skia_revision': '79f23e8d8b5d3c602bc2a1081ddb39d3f8085c9e', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': 'c392ada3b4a1af3a7a8be6ecd2dd45300cbd7a4f', + 'v8_revision': '279e0319cb5e66dbed2cdd32ed1699a3b64a9695', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. @@ -374,11 +374,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': '396204ce89dcd51eaeba6f41116acb736ef22007', + 'catapult_revision': '2298e6389913688b2fee8100c4535053d627ef8c', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling chromium_variations # and whatever else without interference from each other. - 'chromium_variations_revision': '968947731e36aa16182c769c0d52620517260473', + 'chromium_variations_revision': '709c9fa43a4003a7fd787b22d540b4fb9de25e30', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling CrossBench # and whatever else without interference from each other. @@ -470,7 +470,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'libcxxabi_revision': '6bd25883ff3cef44ae402ed5c62b4dac21235ada', + 'libcxxabi_revision': 'c7c5649e8badcb31e66f188f5cf7933f9a8f8287', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -818,7 +818,7 @@ 'src/clank': { 'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' + - '07b69327abd1eddebf899b035e18a6b00af12dd6', + '08918f0ace2c32ab3dcc42c3ada371c7de65943e', 'condition': 'checkout_android and checkout_src_internal', }, @@ -1190,13 +1190,13 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '5ce8e010db12629c396c80a24713fc801cceeb22', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '390005586bde14be9b55fde71ca4ae2107021ac9', 'src/third_party/devtools-frontend/src': Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), 'src/third_party/devtools-frontend-internal': { - 'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + 'de0f5812708a5cfa7606ac1792d5c8dcc054d2ac', + 'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + '9a50858ef92b662c0f264a32b6a94c189da5e945', 'condition': 'checkout_src_internal', }, @@ -1459,7 +1459,7 @@ Var('chromium_git') + '/external/libaddressinput.git' + '@' + 'e8712e415627f22d0b00ebee8db99547077f39bd', 'src/third_party/libaom/source/libaom': - Var('aomedia_git') + '/aom.git' + '@' + 'e1b78c57e41b332d2345b3f85ad84956002468e9', + Var('aomedia_git') + '/aom.git' + '@' + '77657197c709017246e15ae4074eb9108d3b62c8', 'src/third_party/libavif/src': Var('chromium_git') + '/external/github.com/AOMediaCodec/libavif.git' + '@' + Var('libavif_revision'), @@ -1661,7 +1661,7 @@ Var('pdfium_git') + '/pdfium.git' + '@' + Var('pdfium_revision'), 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + '3cee91476cdf8bb14facf7b8208fe2ba6a2ad5d8', + Var('android_git') + '/platform/external/perfetto.git' + '@' + 'd6dd1afcbdccd18eff2a5992ad7eedaef4a6b4c6', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3', @@ -1695,7 +1695,7 @@ }, 'src/third_party/re2/src': - Var('chromium_git') + '/external/github.com/google/re2.git' + '@' + '9d0b5bf57cf0dc5388568127bcf079812d3f989e', + Var('chromium_git') + '/external/github.com/google/re2.git' + '@' + 'c21710327d0330cd933cf52ca89482e845824269', 'src/third_party/r8': { 'packages': [ @@ -1846,7 +1846,7 @@ Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'cd9505da1d631c46cc38b7218c54a4598a4fd802', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '6f0f158af0290f928a4597cdacdc065ccd39d1fe', + Var('webrtc_git') + '/src.git' + '@' + '3ba809d6a6bc20931adde485bb04586a6556db11', # Wuffs' canonical repository is at github.com/google/wuffs, but we use # Skia's mirror of Wuffs, the same as in upstream Skia's DEPS file. @@ -3949,7 +3949,7 @@ 'src/components/optimization_guide/internal': { 'url': Var('chrome_git') + '/chrome/components/optimization_guide.git' + '@' + - '59cb0f75d907dfe078b70c4eb1504bca1d77a112', + '173f05847ba29e71a934e10d0b8dcc97584e1b1b', 'condition': 'checkout_src_internal', }, @@ -4003,7 +4003,7 @@ 'src/ios_internal': { 'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' + - '8d8296d300748fa61c52dd36c7e95da202e42329', + '3803d9c28df7c8d5121cbc7d09c60a5a5c0c558c', 'condition': 'checkout_ios and checkout_src_internal', }, @@ -5112,12 +5112,9 @@ 'pattern': '.', 'condition': 'checkout_fuchsia_internal and checkout_src_internal', 'action': ['python3', - 'src/build/fuchsia/update_images.py', - '--default-bucket', 'fuchsia-sdk', - '--image-root-dir', - 'src/third_party/fuchsia-sdk/images-internal', - '--boot-images', '{checkout_fuchsia_internal_images}' - ], + 'src/build/fuchsia/update_product_bundles.py', + '{checkout_fuchsia_internal_images}', + '--internal'], }, {
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java index f6a2164a..812fa911 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwContents.java +++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -15,7 +15,6 @@ import android.graphics.Color; import android.graphics.Paint; import android.graphics.Picture; -import android.graphics.Point; import android.graphics.Rect; import android.net.Uri; import android.net.http.SslCertificate; @@ -888,7 +887,7 @@ } @Override - public void onScrollUpdateGestureConsumed(Point rootScrollOffset) { + public void onScrollUpdateGestureConsumed() { mScrollAccessibilityHelper.postViewScrolledAccessibilityEventCallback(); mZoomControls.invokeZoomPicker(); }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AndroidScrollIntegrationTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AndroidScrollIntegrationTest.java index 31ab40eb..075748f7 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/AndroidScrollIntegrationTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/AndroidScrollIntegrationTest.java
@@ -8,7 +8,6 @@ import android.annotation.SuppressLint; import android.content.Context; -import android.graphics.Point; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; @@ -831,7 +830,7 @@ int scrollOffsetY, int scrollExtentY, boolean isDirectionUp) {} @Override - public void onScrollUpdateGestureConsumed(Point rootScrollOffset) { + public void onScrollUpdateGestureConsumed() { mOnScrollUpdateGestureConsumedHelper.notifyCalled(); } }
diff --git a/android_webview/test/BUILD.gn b/android_webview/test/BUILD.gn index f48fe0f..4cc80c9 100644 --- a/android_webview/test/BUILD.gn +++ b/android_webview/test/BUILD.gn
@@ -442,14 +442,6 @@ data_deps += [ "//clank/build/bot/filters:webview_instrumentation_test_apk_filters" ] } - - # We only want to bother including these on bots set up for VR testing - if (include_vr_data) { - data += [ - "//chrome/android/shared_preference_files/test/", - "//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk", - ] - } } android_library("webview_instrumentation_test_mock_services_java") {
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc index 34a0b51..6374e06 100644 --- a/ash/constants/ash_features.cc +++ b/ash/constants/ash_features.cc
@@ -780,7 +780,7 @@ // When enabled, it will make login WebUI loaded only before showing it. BASE_FEATURE(kEnableLazyLoginWebUILoading, "EnableLazyLoginWebUILoading", - base::FEATURE_DISABLED_BY_DEFAULT); + base::FEATURE_ENABLED_BY_DEFAULT); // Enables LocalSearchService to be initialized. BASE_FEATURE(kEnableLocalSearchService,
diff --git a/ash/keyboard/ui/keyboard_ui_model.cc b/ash/keyboard/ui/keyboard_ui_model.cc index ab551af2..704f3dd 100644 --- a/ash/keyboard/ui/keyboard_ui_model.cc +++ b/ash/keyboard/ui/keyboard_ui_model.cc
@@ -42,19 +42,6 @@ } } -// Records a state transition for metrics. -void RecordStateTransition(KeyboardUIState prev, KeyboardUIState next) { - const bool valid_transition = IsAllowedStateTransition(prev, next); - - // Use negative hash values to indicate invalid transitions. - const int hash = GetStateTransitionHash(prev, next); - base::UmaHistogramSparse("VirtualKeyboard.ControllerStateTransition", - valid_transition ? hash : -hash); - - DCHECK(valid_transition) << "State: " << StateToStr(prev) << " -> " - << StateToStr(next) << " Unexpected transition"; -} - } // namespace std::string StateToStr(KeyboardUIState state) { @@ -77,7 +64,9 @@ KeyboardUIModel::KeyboardUIModel() = default; void KeyboardUIModel::ChangeState(KeyboardUIState new_state) { - RecordStateTransition(state_, new_state); + DCHECK(IsAllowedStateTransition(state_, new_state)) + << "State: " << StateToStr(state_) << " -> " << StateToStr(new_state) + << " Unexpected transition"; if (new_state == state_) return;
diff --git a/ash/keyboard/ui/keyboard_ui_model_unittest.cc b/ash/keyboard/ui/keyboard_ui_model_unittest.cc index 1649328..12c4193d 100644 --- a/ash/keyboard/ui/keyboard_ui_model_unittest.cc +++ b/ash/keyboard/ui/keyboard_ui_model_unittest.cc
@@ -4,40 +4,29 @@ #include "ash/keyboard/ui/keyboard_ui_model.h" +#include "base/test/gtest_util.h" #include "base/test/metrics/histogram_tester.h" #include "testing/gtest/include/gtest/gtest.h" namespace keyboard { -TEST(KeyboardUIModelTest, ChangeToValidStateRecordsPositiveHistogram) { +TEST(KeyboardUIModelTest, ChangeToValidState) { base::HistogramTester histogram_tester; KeyboardUIModel model; ASSERT_EQ(KeyboardUIState::kInitial, model.state()); model.ChangeState(KeyboardUIState::kLoading); - histogram_tester.ExpectUniqueSample( - "VirtualKeyboard.ControllerStateTransition", - GetStateTransitionHash(KeyboardUIState::kInitial, - KeyboardUIState::kLoading), - 1); } // Test fails DCHECK when the state transition is invalid. This is expected. -#if !DCHECK_IS_ON() -TEST(KeyboardUIModelTest, ChangeToInvalidStateRecordsNegativeHistogram) { +TEST(KeyboardUIModelTest, ChangeToInvalidStateDCHECKs) { base::HistogramTester histogram_tester; KeyboardUIModel model; ASSERT_EQ(KeyboardUIState::kInitial, model.state()); - model.ChangeState(KeyboardUIState::kShown); - histogram_tester.ExpectUniqueSample( - "VirtualKeyboard.ControllerStateTransition", - -GetStateTransitionHash(KeyboardUIState::kInitial, - KeyboardUIState::kShown), - 1); + EXPECT_DCHECK_DEATH(model.ChangeState(KeyboardUIState::kShown)); } -#endif } // namespace keyboard
diff --git a/ash/public/cpp/window_properties.cc b/ash/public/cpp/window_properties.cc index b679d5e..38388df 100644 --- a/ash/public/cpp/window_properties.cc +++ b/ash/public/cpp/window_properties.cc
@@ -38,6 +38,7 @@ DEFINE_UI_CLASS_PROPERTY_KEY(bool, kCanConsumeSystemKeysKey, false) DEFINE_UI_CLASS_PROPERTY_KEY(int32_t, kClientAccessibilityIdKey, -1) DEFINE_UI_CLASS_PROPERTY_KEY(bool, kExcludeInMruKey, false) +DEFINE_UI_CLASS_PROPERTY_KEY(bool, kExcludeFromTransientTreeTransformKey, false) DEFINE_UI_CLASS_PROPERTY_KEY(bool, kFrameRateThrottleKey, false) DEFINE_UI_CLASS_PROPERTY_KEY(bool, kHideInOverviewKey, false) DEFINE_UI_CLASS_PROPERTY_KEY(bool, kHideInShelfKey, false)
diff --git a/ash/public/cpp/window_properties.h b/ash/public/cpp/window_properties.h index 17e8a6e7..a93f8c1 100644 --- a/ash/public/cpp/window_properties.h +++ b/ash/public/cpp/window_properties.h
@@ -81,6 +81,10 @@ ASH_PUBLIC_EXPORT extern const aura::WindowProperty<bool>* const kHideInOverviewKey; +// A property key to exclude the window in the transient tree iterator. +ASH_PUBLIC_EXPORT extern const aura::WindowProperty<bool>* const + kExcludeFromTransientTreeTransformKey; + // A property key to indicate whether we should hide this window in the shelf. ASH_PUBLIC_EXPORT extern const aura::WindowProperty<bool>* const kHideInShelfKey;
diff --git a/ash/resources/vector_icons/BUILD.gn b/ash/resources/vector_icons/BUILD.gn index c2cf776..bff0e09 100644 --- a/ash/resources/vector_icons/BUILD.gn +++ b/ash/resources/vector_icons/BUILD.gn
@@ -266,6 +266,7 @@ "notification_center_settings.icon", "notification_charging_usb_c.icon", "notification_chromevox.icon", + "notification_close_control_button.icon", "notification_help_app.icon", "notification_keyboard.icon", "notification_linux.icon", @@ -273,6 +274,7 @@ "notification_monitor_warning.icon", "notification_multi_device_setup.icon", "notification_screen.icon", + "notification_settings_control_button.icon", "notification_sms_sync.icon", "notification_snooze_button.icon", "notification_stylus_battery_warning.icon",
diff --git a/ash/resources/vector_icons/notification_close_control_button.icon b/ash/resources/vector_icons/notification_close_control_button.icon new file mode 100644 index 0000000..680297b --- /dev/null +++ b/ash/resources/vector_icons/notification_close_control_button.icon
@@ -0,0 +1,19 @@ +// 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. + +CANVAS_DIMENSIONS, 16, +MOVE_TO, 12.8f, 4.33f, +LINE_TO, 11.67f, 3.2f, +LINE_TO, 8, 6.87f, +LINE_TO, 4.33f, 3.2f, +LINE_TO, 3.2f, 4.33f, +LINE_TO, 6.87f, 8, +LINE_TO, 3.2f, 11.67f, +LINE_TO, 4.33f, 12.8f, +LINE_TO, 8, 9.13f, +R_LINE_TO, 3.67f, 3.67f, +R_LINE_TO, 1.13f, -1.13f, +LINE_TO, 9.13f, 8, +LINE_TO, 12.8f, 4.33f, +CLOSE
diff --git a/ash/resources/vector_icons/notification_settings_control_button.icon b/ash/resources/vector_icons/notification_settings_control_button.icon new file mode 100644 index 0000000..ac2c961 --- /dev/null +++ b/ash/resources/vector_icons/notification_settings_control_button.icon
@@ -0,0 +1,88 @@ +// 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. + +CANVAS_DIMENSIONS, 16, +MOVE_TO, 9.18f, 14.4f, +H_LINE_TO, 6.82f, +R_ARC_TO, 0.92f, 0.92f, 0, 0, 1, -0.93f, -0.79f, +R_LINE_TO, -0.17f, -1.18f, +R_ARC_TO, 5.81f, 5.81f, 0, 0, 1, -0.51f, -0.29f, +R_LINE_TO, -1.15f, 0.45f, +R_CUBIC_TO, -0.45f, 0.16f, -0.94f, -0.02f, -1.16f, -0.41f, +R_LINE_TO, -1.17f, -1.98f, +R_CUBIC_TO, -0.22f, -0.41f, -0.13f, -0.9f, 0.23f, -1.17f, +R_LINE_TO, 0.98f, -0.74f, +R_ARC_TO, 4.13f, 4.13f, 0, 0, 1, -0.01f, -0.29f, +R_CUBIC_TO, 0, -0.09f, 0.01f, -0.19f, 0.01f, -0.29f, +R_LINE_TO, -0.97f, -0.74f, +R_ARC_TO, 0.89f, 0.89f, 0, 0, 1, -0.24f, -1.17f, +R_LINE_TO, 1.18f, -1.99f, +R_ARC_TO, 0.93f, 0.93f, 0, 0, 1, 1.15f, -0.39f, +R_LINE_TO, 1.16f, 0.46f, +R_CUBIC_TO, 0.17f, -0.11f, 0.33f, -0.2f, 0.5f, -0.29f, +R_LINE_TO, 0.17f, -1.19f, +R_CUBIC_TO, 0.06f, -0.44f, 0.45f, -0.78f, 0.92f, -0.78f, +R_H_LINE_TO, 2.37f, +R_ARC_TO, 0.92f, 0.92f, 0, 0, 1, 0.93f, 0.79f, +R_LINE_TO, 0.17f, 1.18f, +R_ARC_TO, 5.8f, 5.8f, 0, 0, 1, 0.51f, 0.29f, +R_LINE_TO, 1.15f, -0.45f, +R_CUBIC_TO, 0.45f, -0.16f, 0.95f, 0.02f, 1.16f, 0.41f, +R_LINE_TO, 1.18f, 1.99f, +R_CUBIC_TO, 0.23f, 0.41f, 0.13f, 0.9f, -0.23f, 1.18f, +R_LINE_TO, -0.97f, 0.74f, +R_CUBIC_TO, 0.01f, 0.09f, 0.01f, 0.19f, 0.01f, 0.29f, +R_CUBIC_TO, 0, 0.1f, -0.01f, 0.19f, -0.01f, 0.29f, +R_LINE_TO, 0.97f, 0.74f, +R_CUBIC_TO, 0.36f, 0.28f, 0.46f, 0.77f, 0.24f, 1.16f, +R_LINE_TO, -1.19f, 2.01f, +R_CUBIC_TO, -0.22f, 0.39f, -0.71f, 0.56f, -1.15f, 0.39f, +R_LINE_TO, -1.15f, -0.45f, +R_CUBIC_TO, -0.17f, 0.11f, -0.33f, 0.2f, -0.5f, 0.29f, +R_LINE_TO, -0.17f, 1.19f, +R_CUBIC_TO, -0.06f, 0.43f, -0.46f, 0.76f, -0.93f, 0.76f, +CLOSE, +R_MOVE_TO, -2.02f, -1.6f, +R_H_LINE_TO, 1.69f, +R_LINE_TO, 0.23f, -1.48f, +R_LINE_TO, 0.33f, -0.13f, +R_CUBIC_TO, 0.27f, -0.1f, 0.54f, -0.26f, 0.82f, -0.45f, +R_LINE_TO, 0.28f, -0.2f, +R_LINE_TO, 1.46f, 0.56f, +LINE_TO, 12.8f, 9.7f, +R_LINE_TO, -1.24f, -0.92f, +R_LINE_TO, 0.04f, -0.32f, +R_CUBIC_TO, 0.02f, -0.15f, 0.04f, -0.3f, 0.04f, -0.45f, +R_CUBIC_TO, 0, -0.16f, -0.02f, -0.31f, -0.04f, -0.45f, +R_LINE_TO, -0.04f, -0.33f, +R_LINE_TO, 1.24f, -0.92f, +R_LINE_TO, -0.85f, -1.4f, +R_LINE_TO, -1.46f, 0.56f, +R_LINE_TO, -0.28f, -0.2f, +R_ARC_TO, 3.7f, 3.7f, 0, 0, 0, -0.81f, -0.45f, +R_LINE_TO, -0.32f, -0.13f, +LINE_TO, 8.85f, 3.2f, +H_LINE_TO, 7.16f, +LINE_TO, 6.93f, 4.68f, +R_LINE_TO, -0.32f, 0.12f, +R_CUBIC_TO, -0.27f, 0.11f, -0.54f, 0.26f, -0.82f, 0.46f, +R_LINE_TO, -0.28f, 0.19f, +R_LINE_TO, -1.46f, -0.55f, +R_LINE_TO, -0.85f, 1.39f, +R_LINE_TO, 1.24f, 0.92f, +R_LINE_TO, -0.04f, 0.33f, +R_ARC_TO, 2.78f, 2.78f, 0, 0, 0, 0, 0.91f, +R_LINE_TO, 0.04f, 0.33f, +R_LINE_TO, -1.24f, 0.92f, +R_LINE_TO, 0.85f, 1.4f, +R_LINE_TO, 1.46f, -0.56f, +R_LINE_TO, 0.28f, 0.2f, +R_CUBIC_TO, 0.26f, 0.19f, 0.53f, 0.34f, 0.82f, 0.45f, +R_LINE_TO, 0.33f, 0.13f, +R_LINE_TO, 0.23f, 1.48f, +CLOSE, +MOVE_TO, 8, 10, +R_ARC_TO, 2, 2, 0, 1, 0, 0, -4, +R_ARC_TO, 2, 2, 0, 0, 0, 0, 4, +CLOSE
diff --git a/ash/shelf/drag_window_from_shelf_controller.cc b/ash/shelf/drag_window_from_shelf_controller.cc index 737e7be..665b365 100644 --- a/ash/shelf/drag_window_from_shelf_controller.cc +++ b/ash/shelf/drag_window_from_shelf_controller.cc
@@ -610,7 +610,7 @@ 0, (bounds.bottom() - transformed_bounds.bottom()) / scale); } - SetTransform(window_, transform); + window_util::SetTransform(window_, transform); if (other_window_copy_) { // When we have dragged 1/8th of the display height, the copy should be
diff --git a/ash/system/message_center/ash_notification_view.cc b/ash/system/message_center/ash_notification_view.cc index cb4ed17..40ab7fc6 100644 --- a/ash/system/message_center/ash_notification_view.cc +++ b/ash/system/message_center/ash_notification_view.cc
@@ -42,7 +42,6 @@ #include "base/ranges/algorithm.h" #include "base/strings/strcat.h" #include "base/time/time.h" -#include "components/vector_icons/vector_icons.h" #include "ui/base/dragdrop/os_exchange_data.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/metadata/metadata_impl_macros.h" @@ -174,6 +173,10 @@ // The horizontal spacing between control button icons. constexpr int kControlButtonsHorizontalSpacing = 6; +// The size of an icon within a control button. Note that this is not the size +// of a control button itself. +constexpr int kControlButtonsIconSize = 14; + // Helpers --------------------------------------------------------------------- // Configure the style for labels in notification view. `is_color_primary` @@ -548,11 +551,11 @@ .SetBetweenButtonSpacing( kControlButtonsHorizontalSpacing) .SetCloseButtonIcon( - vector_icons:: - kCloseChromeRefreshIcon) + kNotificationCloseControlButtonIcon) .SetSettingsButtonIcon( - vector_icons:: - kSettingsOutlineIcon) + kNotificationSettingsControlButtonIcon) + .SetButtonIconSize( + kControlButtonsIconSize) .SetButtonIconColors( AshColorProvider::Get() ->GetContentLayerColor(
diff --git a/ash/system/message_center/ash_notification_view_pixeltest.cc b/ash/system/message_center/ash_notification_view_pixeltest.cc index 5faa43f6..8522633 100644 --- a/ash/system/message_center/ash_notification_view_pixeltest.cc +++ b/ash/system/message_center/ash_notification_view_pixeltest.cc
@@ -124,7 +124,7 @@ EXPECT_TRUE(close_button->HasFocus()); EXPECT_EQ(control_buttons_layer->opacity(), 1); EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen( - "close_button_focused", /*revision_number=*/3, notification_view)); + "close_button_focused", /*revision_number=*/4, notification_view)); } // Regression test for http://b/267195370. Tests that a notification with no @@ -188,7 +188,7 @@ // Verify with a pixel test that the close control button is visible and has // the proper placement. EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen( - "close_control_button", /*revision_number=*/2, notification_view)); + "close_control_button", /*revision_number=*/3, notification_view)); } // Tests the control buttons UI for the case of a notification with both the @@ -210,7 +210,7 @@ // Verify with a pixel test that the control buttons are visible and have // proper spacing between them. EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen( - "settings_and_close_control_buttons", /*revision_number=*/2, + "settings_and_close_control_buttons", /*revision_number=*/3, notification_view)); } @@ -306,7 +306,7 @@ // Verify the spacing with a pixel test. EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen( - "elided_text_spacing", /*revision_number=*/1, notification_view)); + "elided_text_spacing", /*revision_number=*/2, notification_view)); } class ScreenCaptureNotificationPixelTest
diff --git a/ash/system/time/calendar_model.cc b/ash/system/time/calendar_model.cc index 34b76a6..6127dc97 100644 --- a/ash/system/time/calendar_model.cc +++ b/ash/system/time/calendar_model.cc
@@ -59,10 +59,11 @@ std::list<CalendarEvent> same_day_events; for (const CalendarEvent& event : list) { - if (event.all_day_event() || ash::calendar_utils::IsMultiDayEvent(&event)) + if (event.all_day_event() || ash::calendar_utils::IsMultiDayEvent(&event)) { multi_day_events.push_back(std::move(event)); - else + } else { same_day_events.push_back(std::move(event)); + } } return std::make_tuple(std::move(multi_day_events), @@ -80,16 +81,6 @@ }); } -bool EventStartsInTenMins(const CalendarEvent& event, - const base::Time& now_local) { - const int start_time_difference_in_mins = - (ash::calendar_utils::GetStartTimeAdjusted(&event) - now_local) - .InMinutes(); - - return (0 <= start_time_difference_in_mins && - start_time_difference_in_mins <= 10); -} - bool EventStartedLessThanOneHourAgo(const CalendarEvent& event, const base::Time& now_local) { const int start_time_difference_in_mins = @@ -103,23 +94,6 @@ start_time_difference_in_mins >= -60); } -// Returns events that start in 10 minutes time, or events that are in progress -// and started less than one hour ago. -auto FilterEventsStartingSoonOrRecentlyInProgress( - const ash::SingleDayEventList& list, - const base::Time& now_local) { - std::list<CalendarEvent> result; - - for (const CalendarEvent& event : list) { - if (EventStartsInTenMins(event, now_local) || - EventStartedLessThanOneHourAgo(event, now_local)) { - result.emplace_back(event); - } - } - - return result; -} - auto FilterTheNextEventsOrEventsRecentlyInProgress( const ash::SingleDayEventList& list, const base::Time& now_local) { @@ -181,13 +155,15 @@ } void CalendarModel::AddObserver(Observer* observer) { - if (observer) + if (observer) { observers_.AddObserver(observer); + } } void CalendarModel::RemoveObserver(Observer* observer) { - if (observer) + if (observer) { observers_.RemoveObserver(observer); + } } void CalendarModel::PromoteMonth(base::Time start_of_month) { @@ -197,15 +173,17 @@ } // If start_of_month is already most-recently-used, nothing to do. - if (!mru_months_.empty() && mru_months_.front() == start_of_month) + if (!mru_months_.empty() && mru_months_.front() == start_of_month) { return; + } // Remove start_of_month from the queue if it's present. - for (auto it = mru_months_.begin(); it != mru_months_.end(); ++it) + for (auto it = mru_months_.begin(); it != mru_months_.end(); ++it) { if (*it == start_of_month) { mru_months_.erase(it); break; } + } // start_of_month is now the most-recently-used. mru_months_.push_front(start_of_month); @@ -213,16 +191,19 @@ void CalendarModel::AddNonPrunableMonth(const base::Time& month) { // Early-return if `month` is present, to avoid the limits-check below. - if (base::Contains(non_prunable_months_, month)) + if (base::Contains(non_prunable_months_, month)) { return; + } - if (non_prunable_months_.size() < calendar_utils::kMaxNumNonPrunableMonths) + if (non_prunable_months_.size() < calendar_utils::kMaxNumNonPrunableMonths) { non_prunable_months_.emplace(month); + } } void CalendarModel::AddNonPrunableMonths(const std::set<base::Time>& months) { - for (auto& month : months) + for (auto& month : months) { AddNonPrunableMonth(month); + } } void CalendarModel::ClearAllCachedEvents() { @@ -264,14 +245,16 @@ void CalendarModel::FetchEvents(base::Time start_of_month) { // Early return if it's not a valid user/user-session. - if (!calendar_utils::ShouldFetchEvents()) + if (!calendar_utils::ShouldFetchEvents()) { return; + } // Bail out early if there is no CalendarClient. This will be the case in // most unit tests. CalendarClient* client = Shell::Get()->calendar_controller()->GetClient(); - if (!client) + if (!client) { return; + } // Bail out early if this is a prunable month that's already been fetched. if (!base::Contains(non_prunable_months_, start_of_month) && @@ -312,8 +295,9 @@ SingleDayEventList* events) { const SingleDayEventList& list = FindEvents(day); - if (list.empty()) + if (list.empty()) { return 0; + } // There are events, and the destination should be empty. if (events) { @@ -337,8 +321,9 @@ // `kNever` to stop the loading animation displaying. // TODO(https://crbug.com/1298187): Possibly respond further based on the // specific error code, retry in some cases, etc. - for (auto& observer : observers_) + for (auto& observer : observers_) { observer.OnEventsFetched(kNever, start_of_month, events); + } return; } @@ -358,9 +343,9 @@ } else { // Store the incoming events. for (const auto& event : events->items()) { - if (calendar_utils::IsMultiDayEvent(event.get())) + if (calendar_utils::IsMultiDayEvent(event.get())) { InsertMultiDayEvent(event.get(), start_of_month); - else { + } else { base::Time start_time_midnight = calendar_utils::GetStartTimeMidnightAdjusted(event.get()); InsertEventInMonth( @@ -372,8 +357,9 @@ } // Notify observers. - for (auto& observer : observers_) + for (auto& observer : observers_) { observer.OnEventsFetched(kSuccess, start_of_month, events); + } // Month has officially been fetched. months_fetched_.emplace(start_of_month); @@ -396,13 +382,15 @@ // stop the loading animation displaying. // TODO(https://crbug.com/1298187): May need to respond further based on the // specific error code, retry in some cases, etc. - for (auto& observer : observers_) + for (auto& observer : observers_) { observer.OnTimeout(start_of_month); + } } bool CalendarModel::ShouldInsertEvent(const CalendarEvent* event) const { - if (!event) + if (!event) { return false; + } return base::Contains(kAllowedEventStatuses, event->status()) && base::Contains(kAllowedResponseStatuses, @@ -456,10 +444,11 @@ .UTCMidnight(); // If the event ends at midnight we don't add it to that last day. - if (end_time == end_time_midnight) + if (end_time == end_time_midnight) { last_day_midnight = (last_day_midnight - calendar_utils::kDurationForGettingPreviousDay) .UTCMidnight(); + } while (current_day_midnight <= last_day_midnight) { InsertEventInMonth(event, start_of_month, current_day_midnight); @@ -501,8 +490,9 @@ const google_apis::calendar::CalendarEvent* event, const base::Time start_time_midnight) { DCHECK(event); - if (!ShouldInsertEvent(event)) + if (!ShouldInsertEvent(event)) { return; + } auto it = month.find(start_time_midnight); if (it == month.end()) { @@ -548,41 +538,28 @@ std::list<CalendarEvent> CalendarModel::FindUpcomingEvents( base::Time now_local) const { - // First get today's events for `now_local`. auto upcoming_events = FindEvents(now_local); - - // For Glanceables, the candidate event list should be today's event list. - if (features::AreGlanceablesV2Enabled() && - features::IsGlanceablesV2CalendarViewEnabled()) { - return FilterTheNextEventsOrEventsRecentlyInProgress(upcoming_events, - now_local); - } - - const base::Time now_in_ten_mins = now_local + base::Minutes(10); - // If `now_in_ten_mins` is the subsequent day, include its events. - if (now_in_ten_mins.UTCMidnight() != now_local.UTCMidnight()) { - auto tomorrows_events = FindEvents(now_local + base::Days(1)); - upcoming_events.splice(upcoming_events.end(), tomorrows_events); - } - - return FilterEventsStartingSoonOrRecentlyInProgress(upcoming_events, - now_local); + return FilterTheNextEventsOrEventsRecentlyInProgress(upcoming_events, + now_local); } CalendarModel::FetchingStatus CalendarModel::FindFetchingStatus( base::Time start_time) const { - if (!calendar_utils::ShouldFetchEvents()) + if (!calendar_utils::ShouldFetchEvents()) { return kNa; + } if (pending_fetches_.count(start_time)) { - if (event_months_.count(start_time)) + if (event_months_.count(start_time)) { return kRefetching; + } return kFetching; } - if (event_months_.count(start_time)) + if (event_months_.count(start_time)) { return kSuccess; + } return kNever; }
diff --git a/ash/system/time/calendar_model_unittest.cc b/ash/system/time/calendar_model_unittest.cc index 3bdcee1f..c1a4cd34 100644 --- a/ash/system/time/calendar_model_unittest.cc +++ b/ash/system/time/calendar_model_unittest.cc
@@ -13,7 +13,6 @@ #include "ash/calendar/calendar_client.h" #include "ash/calendar/calendar_controller.h" -#include "ash/constants/ash_features.h" #include "ash/constants/ash_pref_names.h" #include "ash/public/cpp/session/session_controller.h" #include "ash/public/cpp/session/session_types.h" @@ -27,7 +26,6 @@ #include "base/ranges/algorithm.h" #include "base/run_loop.h" #include "base/test/metrics/histogram_tester.h" -#include "base/test/scoped_feature_list.h" #include "base/time/time.h" #include "chromeos/ash/components/settings/scoped_timezone_settings.h" #include "components/user_manager/user_type.h" @@ -153,16 +151,10 @@ EXPECT_TRUE(base::Contains(months, start_of_next_month_3)); } -class CalendarModelTest - : public AshTestBase, - public testing::WithParamInterface</*glanceables_v2_enabled=*/bool> { +class CalendarModelTest : public AshTestBase { public: CalendarModelTest() - : AshTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME) { - scoped_feature_list_.InitWithFeatureStates( - {{features::kGlanceablesV2, AreGlanceablesV2Enabled()}, - {features::kGlanceablesV2CalendarView, AreGlanceablesV2Enabled()}}); - } + : AshTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {} CalendarModelTest(const CalendarModelTest& other) = delete; CalendarModelTest& operator=(const CalendarModelTest& other) = delete; @@ -192,8 +184,6 @@ AshTestBase::TearDown(); } - bool AreGlanceablesV2Enabled() { return GetParam(); } - int EventsNumberOfDay(const char* day, SingleDayEventList* events) { base::Time day_base = calendar_test_utils::GetTimeFromString(day); @@ -355,15 +345,12 @@ std::unique_ptr<base::subtle::ScopedTimeClockOverrides> time_overrides_; - base::test::ScopedFeatureList scoped_feature_list_; std::unique_ptr<CalendarModel> calendar_model_; std::unique_ptr<calendar_test_utils::CalendarClientTestImpl> calendar_client_; base::Time now_; }; -INSTANTIATE_TEST_SUITE_P(GlanceablesV2, CalendarModelTest, testing::Bool()); - -TEST_P(CalendarModelTest, FetchingSuccessfullyWithOneEvent) { +TEST_F(CalendarModelTest, FetchingSuccessfullyWithOneEvent) { // All events will be distributed by the system timezone. If no timezone is // set, the test will run with the local default timezone which might cause a // test failure. So here sets the timezone to "GMT", and the same for all the @@ -420,7 +407,7 @@ calendar_model()->FindFetchingStatus(start_of_month)); } -TEST_P(CalendarModelTest, FetchingSuccessfullyWithMultiEvents) { +TEST_F(CalendarModelTest, FetchingSuccessfullyWithMultiEvents) { // Sets the timezone to "GMT". ash::system::ScopedTimezoneSettings timezone_settings(u"GMT"); @@ -513,7 +500,7 @@ calendar_model()->FindFetchingStatus(start_of_month0)); } -TEST_P(CalendarModelTest, ChangeTimeDifference) { +TEST_F(CalendarModelTest, ChangeTimeDifference) { // Sets the timezone to "America/Los_Angeles". ash::system::ScopedTimezoneSettings timezone_settings(u"America/Los_Angeles"); calendar_test_utils::ScopedLibcTimeZone scoped_libc_timezone( @@ -621,7 +608,7 @@ } // Test for pruning of events. -TEST_P(CalendarModelTest, PruneEvents) { +TEST_F(CalendarModelTest, PruneEvents) { // Sets the timezone to "GMT". ash::system::ScopedTimezoneSettings timezone_settings(u"GMT"); @@ -694,7 +681,7 @@ EXPECT_EQ((int)event_months().size(), kNumEvents + 1); } -TEST_P(CalendarModelTest, RecordFetchResultHistogram_Success) { +TEST_F(CalendarModelTest, RecordFetchResultHistogram_Success) { // Sets the timezone to "GMT". ash::system::ScopedTimezoneSettings timezone_settings(u"GMT"); @@ -721,7 +708,7 @@ /*expected_count=*/calendar_utils::kMaxNumNonPrunableMonths); } -TEST_P(CalendarModelTest, RecordFetchResultHistogram_Failure) { +TEST_F(CalendarModelTest, RecordFetchResultHistogram_Failure) { // Sets the timezone to "GMT". ash::system::ScopedTimezoneSettings timezone_settings(u"GMT"); @@ -770,7 +757,7 @@ /*expected_count=*/2); } -TEST_P(CalendarModelTest, SessionStateChange) { +TEST_F(CalendarModelTest, SessionStateChange) { // Sets the timezone to "GMT". ash::system::ScopedTimezoneSettings timezone_settings(u"GMT"); @@ -807,7 +794,7 @@ EXPECT_TRUE(events.empty()); } -TEST_P(CalendarModelTest, ActiveUserChange) { +TEST_F(CalendarModelTest, ActiveUserChange) { // Sets the timezone to "GMT". ash::system::ScopedTimezoneSettings timezone_settings(u"GMT"); @@ -854,7 +841,7 @@ EXPECT_TRUE(event_months().empty()); } -TEST_P(CalendarModelTest, ActiveChildUserChange) { +TEST_F(CalendarModelTest, ActiveChildUserChange) { // Sets the timezone to "GMT". ash::system::ScopedTimezoneSettings timezone_settings(u"GMT"); @@ -901,7 +888,7 @@ EXPECT_TRUE(event_months().empty()); } -TEST_P(CalendarModelTest, ClearEvents) { +TEST_F(CalendarModelTest, ClearEvents) { // Sets the timezone to "GMT". ash::system::ScopedTimezoneSettings timezone_settings(u"GMT"); @@ -976,7 +963,7 @@ // Test for filtering of events based on their statuses. Cancelled or declined // events shouldn't be inserted in a month. -TEST_P(CalendarModelTest, ShouldFilterEvents) { +TEST_F(CalendarModelTest, ShouldFilterEvents) { // Sets the timezone to "GMT". ash::system::ScopedTimezoneSettings timezone_settings(u"GMT"); @@ -1039,7 +1026,7 @@ "confirmed+needs_action", "confirmed+tentative"})); } -TEST_P(CalendarModelTest, EdgeOfMonthEvent) { +TEST_F(CalendarModelTest, EdgeOfMonthEvent) { // Will add event that's in the same month as kNow using PDT (UTC-7), // so the times will translate to next day (and month) on UTC. ash::system::ScopedTimezoneSettings timezone_settings(u"America/Los_Angeles"); @@ -1086,7 +1073,7 @@ EXPECT_TRUE(next_month_map->second.empty()); } -TEST_P(CalendarModelTest, MultiDayEvents) { +TEST_F(CalendarModelTest, MultiDayEvents) { // Set timezone and fake now. const char* kNow = "10 Nov 2022 13:00 GMT"; ash::system::ScopedTimezoneSettings timezone_settings(u"GMT"); @@ -1160,7 +1147,7 @@ TestMultiDayEvent(events, kMultiYearStartTime, kMultiYearEndTime); } -TEST_P(CalendarModelTest, MultiAllDayEvents) { +TEST_F(CalendarModelTest, MultiAllDayEvents) { // Set timezone and fake now. We set this to be GMT+n as we previously // had a bug where all day events overflowed into the day after they were set // to end for GMT+ timezones. @@ -1209,7 +1196,7 @@ EXPECT_EQ(0, EventsNumberOfDay(kMultiAllDayEventEndTime, &events)); } -TEST_P(CalendarModelTest, FindFetchingStatus) { +TEST_F(CalendarModelTest, FindFetchingStatus) { // Sets the timezone to "GMT". ash::system::ScopedTimezoneSettings timezone_settings(u"GMT"); @@ -1277,7 +1264,7 @@ calendar_utils::GetStartOfMonthUTC(fetching_date))); } -TEST_P(CalendarModelTest, FindEventsSplitByMultiDayAndSameDay) { +TEST_F(CalendarModelTest, FindEventsSplitByMultiDayAndSameDay) { // Set timezone and fake now. const char* kNow = "10 Nov 2022 13:00 GMT+5"; ash::system::ScopedTimezoneSettings timezone_settings(u"GMT+5"); @@ -1319,7 +1306,7 @@ EXPECT_EQ(same_day_events.back().id(), kSameDayId); } -TEST_P(CalendarModelTest, FindUpcomingEvents_SameDay) { +TEST_F(CalendarModelTest, FindUpcomingEvents_SameDay) { // Set timezone and fake now. const char* kNow = "10 Nov 2022 13:00 GMT"; ash::system::ScopedTimezoneSettings timezone_settings(u"GMT"); @@ -1394,10 +1381,11 @@ } // If time now is 23:55 and we have an upcoming event starting at 00:05 the -// following day, then we should also get upcoming events from the next day -// back. -// For GlanceablesV2: we should only show today's events. -TEST_P(CalendarModelTest, FindUpcomingEvents_NextDay) { +// following day, we should only show today's events. This test is needed after +// we made the change to the logic of showing the up next view. Before the +// change, we would show the events starting in 10 mins even if it's in the next +// day. Now it shouldn't be shown. +TEST_F(CalendarModelTest, FindUpcomingEvents_NextDay) { // Set timezone and fake now. const char* kNow = "10 Nov 2022 23:55 GMT"; ash::system::ScopedTimezoneSettings timezone_settings(u"GMT"); @@ -1426,19 +1414,13 @@ return base::Contains(event_list, id, &CalendarEvent::id); }; - if (AreGlanceablesV2Enabled()) { - EXPECT_EQ(events.size(), size_t(0)); - EXPECT_FALSE( - event_list_contains(events, kEventStartingInTenMinsTomorrowId)); - } else { - EXPECT_EQ(events.size(), size_t(1)); - EXPECT_TRUE(event_list_contains(events, kEventStartingInTenMinsTomorrowId)); - } + EXPECT_EQ(events.size(), size_t(0)); + EXPECT_FALSE(event_list_contains(events, kEventStartingInTenMinsTomorrowId)); } // If time now is 00:10 and we have an event that started <1 hour ago, then we // should get in progress events from the previous day back. -TEST_P(CalendarModelTest, FindUpcomingEvents_PreviousDay) { +TEST_F(CalendarModelTest, FindUpcomingEvents_PreviousDay) { // Set timezone and fake now. const char* kNow = "10 Nov 2022 00:10 GMT"; ash::system::ScopedTimezoneSettings timezone_settings(u"GMT"); @@ -1471,10 +1453,9 @@ EXPECT_TRUE(event_list_contains(events, kEventInProgressStartedYesterdayId)); } -// If the next event doesn't start in the next 10 mins, do not show it. -// For GlanceablesV2: we'll show the next event for today even if it starts -// later than 10 mins away. -TEST_P(CalendarModelTest, FindUpcomingEvents_ShowTheNextEvent) { +// If the next event doesn't start in the next 10 mins, we'll still show it. +// This is needed after we changed the logic of showing the up next view. +TEST_F(CalendarModelTest, FindUpcomingEvents_ShowTheNextEvent) { // Set timezone and fake now. const char* kNow = "10 Nov 2022 13:00 GMT"; ash::system::ScopedTimezoneSettings timezone_settings(u"GMT"); @@ -1504,21 +1485,15 @@ return base::Contains(event_list, id, &CalendarEvent::id); }; - // For GlanceablesV2: we should show the event starting in thirty mins. - if (AreGlanceablesV2Enabled()) { - EXPECT_EQ(events.size(), size_t(1)); - EXPECT_TRUE(event_list_contains(events, kEventStartingInThirtyMinsId)); - } else { - EXPECT_EQ(events.size(), size_t(0)); - EXPECT_FALSE(event_list_contains(events, kEventStartingInThirtyMinsId)); - } + EXPECT_EQ(events.size(), size_t(1)); + EXPECT_TRUE(event_list_contains(events, kEventStartingInThirtyMinsId)); } // If two events start at the same time, show the one finishing earlier first. // Returns: // First event: 13:00 - 13:45 // Second event: 13:00 - 14:00 -TEST_P(CalendarModelTest, EventsSortingWithSameStartTime) { +TEST_F(CalendarModelTest, EventsSortingWithSameStartTime) { // Set timezone and fake now. const char* kNow = "10 Nov 2022 13:00 GMT"; ash::system::ScopedTimezoneSettings timezone_settings(u"GMT"); @@ -1555,14 +1530,9 @@ EXPECT_EQ(kSecondEventId, events.back().id()); } -// If one event starts later but finishes earlier than another, show the one -// that started earlier first. -// Returns: -// Second event: 13:00 - 14:00 -// First event: 13:05 - 13:45 -// For GlanceablesV2: only show the kSecondEventId since this one is the next -// event. -TEST_P(CalendarModelTest, EventsSortingWithDifferentStartTime) { +// If one event starts later but finishes earlier than another, only show the +// kSecondEventId since this one is the next event. +TEST_F(CalendarModelTest, EventsSortingWithDifferentStartTime) { // Set timezone and fake now. const char* kNow = "10 Nov 2022 13:00 GMT"; ash::system::ScopedTimezoneSettings timezone_settings(u"GMT"); @@ -1598,14 +1568,8 @@ return base::Contains(event_list, id, &CalendarEvent::id); }; - if (AreGlanceablesV2Enabled()) { - EXPECT_EQ(events.size(), size_t(1)); - EXPECT_TRUE(event_list_contains(events, kSecondEventId)); - } else { - EXPECT_EQ(events.size(), size_t(2)); - EXPECT_EQ(kSecondEventId, events.front().id()); - EXPECT_EQ(kFirstEventId, events.back().id()); - } + EXPECT_EQ(events.size(), size_t(1)); + EXPECT_TRUE(event_list_contains(events, kSecondEventId)); } } // namespace ash
diff --git a/ash/system/time/calendar_view_unittest.cc b/ash/system/time/calendar_view_unittest.cc index 49dafd82..88aaa4ed 100644 --- a/ash/system/time/calendar_view_unittest.cc +++ b/ash/system/time/calendar_view_unittest.cc
@@ -2390,10 +2390,9 @@ calendar_utils::GetStartOfMonthUTC(date), CreateMockEventListWithEventStartTimeMoreThanTwoHoursAway()); - // When fetched events are more than two hours away, then up next shouldn't - // have been created. + // Fetch an event starting more than two hours away, up next should show. bool is_showing_up_next_view = up_next_view(); - EXPECT_FALSE(is_showing_up_next_view); + EXPECT_TRUE(is_showing_up_next_view); } TEST_F(CalendarViewWithJellyEnabledTest, ShouldShowUpNextView) { @@ -2528,7 +2527,7 @@ TEST_F( CalendarViewWithJellyEnabledTest, - GivenUpNextIsShown_WhenNewEventsMoreThanTwoHoursAwayAreFetched_ThenUpNextViewShouldNotBeShown) { + GivenUpNextIsShown_WhenNewEventsMoreThanTwoHoursAwayAreFetched_UpNextViewShouldStillBeShown) { base::Time date; ASSERT_TRUE(base::Time::FromString("18 Nov 2021 10:00 GMT", &date)); // Set time override. @@ -2549,9 +2548,9 @@ calendar_utils::GetStartOfMonthUTC(date), CreateMockEventListWithEventStartTimeMoreThanTwoHoursAway()); - // When fetched events are now more than two hours away, then up next - // should have been destroyed. - EXPECT_FALSE((up_next_view() && up_next_view()->GetVisible())); + // When fetched events are now more than two hours away, the up next should + // still show. + EXPECT_TRUE((up_next_view() && up_next_view()->GetVisible())); } // Tests the following: @@ -2674,7 +2673,7 @@ calendar_utils::GetStartOfMonthUTC(date), CreateMockEventListWithEventStartTimeMoreThanTwoHoursAway()); - EXPECT_FALSE(up_next_view()); + EXPECT_TRUE(up_next_view()); // Open the event list view for today. ASSERT_EQ(u"18", @@ -2884,14 +2883,16 @@ } // Tests an upcoming event that starts at 00:05 but "now" is 23:55. In this case -// we should open the event list for the subsequent day if a user presses the -// show todays events button. -TEST_F( - CalendarViewWithJellyEnabledTest, - ShouldShowTheFollowingDay_WhenPressingTheShowTodaysEventsButton_AndUpcomingEventStartsNextDay) { +// the up next view shouldn't be shown. +TEST_F(CalendarViewWithJellyEnabledTest, + ShouldNotShowUpNextView_WhenNextEventStartsTomorrow) { base::Time date; ASSERT_TRUE(base::Time::FromString("18 Nov 2021 23:55 GMT", &date)); - // Set time override. + + // Sets the timezone to GMT. + ash::system::ScopedTimezoneSettings timezone_settings(u"GMT"); + + // Sets time override. SetFakeNow(date); base::subtle::ScopedTimeClockOverrides time_override( &CalendarViewTest::FakeTimeNow, /*time_ticks_override=*/nullptr, @@ -2902,25 +2903,8 @@ MockEventsFetched(calendar_utils::GetStartOfMonthUTC(date), CreateMockEventListStartingFivePastMidnight()); - // Up next view should be shown. - ASSERT_TRUE(up_next_view()); - - LeftClickOn(up_next_todays_events_button()); - - // Event list should be open with the following day selected. - EXPECT_TRUE(event_list_view()); - base::Time expected_selected_date; - ASSERT_TRUE( - base::Time::FromString("19 Nov 2021 00:05 GMT", &expected_selected_date)); - EXPECT_EQ(expected_selected_date, selected_date().value()); - - // Calendar should be reset back to today. - EXPECT_EQ(u"October", GetPreviousLabelText()); - EXPECT_EQ(u"November", GetCurrentLabelText()); - EXPECT_EQ(u"December", GetNextLabelText()); - EXPECT_EQ(u"January", GetNextNextLabelText()); - EXPECT_EQ(u"November", month_header()->GetText()); - EXPECT_EQ(u"2021", header_year()->GetText()); + // Up next view should not be shown. + ASSERT_FALSE(up_next_view()); } TEST_F( @@ -3194,10 +3178,11 @@ widget()->SetFullscreen(false); widget()->SetSize(gfx::Size(kTrayMenuWidth, 350)); - // Fetch an event that starts in 11 mins so up next isn't showing. + // Fetch an event that starts in 11 mins and up next will show. MockEventsFetched(calendar_utils::GetStartOfMonthUTC(date), CreateUpcomingEvents(date + base::Minutes(6))); - EXPECT_FALSE(calendar_view()->up_next_view()); + WaitUntilFetched(); + EXPECT_TRUE(calendar_view()->up_next_view()->GetVisible()); // Scroll up a bit so that today is off the screen. ScrollUpOneMonth(); @@ -3207,9 +3192,9 @@ const int initial_scroll_position = scroll_view()->GetVisibleRect().y(); // Now advance time so that our upcoming meeting is about to start and up next - // should not appear since the user has scrolled. + // should be invisible since the user has scrolled. task_environment()->FastForwardBy(base::Minutes(5)); - EXPECT_FALSE(calendar_view()->up_next_view()); + EXPECT_FALSE(calendar_view()->up_next_view()->GetVisible()); // The scroll view should not have moved as the user has previously interacted // with the scroll view. @@ -3230,10 +3215,10 @@ widget()->SetFullscreen(false); widget()->SetSize(gfx::Size(kTrayMenuWidth, 350)); - // Fetch an event that starts in 11 mins so up next isn't showing. + // Fetch an event that starts in 11 mins and up next will show. MockEventsFetched(calendar_utils::GetStartOfMonthUTC(date), CreateUpcomingEvents(date + base::Minutes(6))); - EXPECT_FALSE(calendar_view()->up_next_view()); + EXPECT_TRUE(calendar_view()->up_next_view()); ui::LayerAnimationStoppedWaiter animation_waiter; animation_waiter.Wait(current_month()->layer()); @@ -3263,10 +3248,11 @@ widget()->SetFullscreen(false); widget()->SetSize(gfx::Size(kTrayMenuWidth, 350)); - // Fetch an event that starts in 11 mins so up next isn't showing. + // Fetch an event that starts in 11 mins and up next view will be shown. MockEventsFetched(calendar_utils::GetStartOfMonthUTC(date), CreateUpcomingEvents(date + base::Minutes(6))); - EXPECT_FALSE(calendar_view()->up_next_view()); + WaitUntilFetched(); + EXPECT_TRUE(calendar_view()->up_next_view()->GetVisible()); // Scrolls 4 months so that todays date cell is null. ScrollUpOneMonth(); @@ -3283,7 +3269,7 @@ // shouldn't show since the user has scrolled, and the scroll view should not // have moved as well. task_environment()->FastForwardBy(base::Minutes(5)); - EXPECT_FALSE(calendar_view()->up_next_view()); + EXPECT_FALSE(calendar_view()->up_next_view()->GetVisible()); EXPECT_EQ(initial_scroll_position, scroll_view()->GetVisibleRect().y()); }
diff --git a/ash/webui/common/resources/shortcut_input_ui/shortcut_input.ts b/ash/webui/common/resources/shortcut_input_ui/shortcut_input.ts index 1fee035..4f7e411 100644 --- a/ash/webui/common/resources/shortcut_input_ui/shortcut_input.ts +++ b/ash/webui/common/resources/shortcut_input_ui/shortcut_input.ts
@@ -152,22 +152,28 @@ } if (this.updateOnKeyPress) { - // If the key released is not a modifier and is the same as the previously - // released key, remove it from the `keyDisplay`. - if (this.pendingKeyEvent!.keyDisplay === keyEvent.keyDisplay && - !ModifierKeyCodes.includes(keyEvent.vkey as number)) { - this.pendingKeyEvent!.keyDisplay = ''; + console.log('keyevent', keyEvent); + + + const updatedKeyEvent = {...keyEvent}; + const updatedPrerewrittenKeyEvent = {...prerewrittenKeyEvent}; + + // If the key released is not a modifier, reset keyDisplay. + if (!ModifierKeyCodes.includes(updatedKeyEvent.vkey as number)) { + updatedKeyEvent.keyDisplay = ''; } - if (this.pendingPrerewrittenKeyEvent!.keyDisplay === - prerewrittenKeyEvent.keyDisplay && - !ModifierKeyCodes.includes(prerewrittenKeyEvent.vkey as number)) { - this.pendingPrerewrittenKeyEvent!.keyDisplay = ''; + if (!ModifierKeyCodes.includes( + updatedPrerewrittenKeyEvent.vkey as number)) { + updatedPrerewrittenKeyEvent.keyDisplay = ''; } - this.pendingKeyEvent!.modifiers = keyEvent.modifiers; - this.pendingPrerewrittenKeyEvent!.modifiers = - prerewrittenKeyEvent.modifiers; + // Update pending events with the modifications made to the key events + // above. + this.pendingKeyEvent = updatedKeyEvent; + // console.log('pendingKeyEvent', pendingKeyEvent.keyDisplay); + + this.pendingPrerewrittenKeyEvent = updatedPrerewrittenKeyEvent; } else { // Only update the UI if the released key is the last key pressed OR if // its a modifier. @@ -181,12 +187,10 @@ prerewrittenKeyEvent.modifiers; return; } - } - this.pendingKeyEvent = keyEvent; - this.pendingPrerewrittenKeyEvent = prerewrittenKeyEvent; + this.pendingKeyEvent = keyEvent; + this.pendingPrerewrittenKeyEvent = prerewrittenKeyEvent; - if (!this.updateOnKeyPress) { this.dispatchEvent(new CustomEvent('shortcut-input-event', { bubbles: true, composed: true,
diff --git a/ash/wm/overview/overview_item.cc b/ash/wm/overview/overview_item.cc index 9b0e2f0..9349d178a 100644 --- a/ash/wm/overview/overview_item.cc +++ b/ash/wm/overview/overview_item.cc
@@ -797,7 +797,7 @@ } else { gfx::Transform transform = gfx::Tween::TransformValueBetween( scroll_ratio, gfx::Transform(), target_transform); - SetTransform(window, transform); + window_util::SetTransform(window, transform); } } @@ -1187,7 +1187,7 @@ // window. gfx::Transform initial_transform = target_transform; initial_transform.Scale(kInitialScaler, kInitialScaler); - SetTransform(window, initial_transform); + window_util::SetTransform(window, initial_transform); transform_window_.SetOpacity(kInitialScaler); ScopedOverviewTransformWindow::ScopedAnimationSettings animation_settings; @@ -1204,7 +1204,7 @@ base::BindOnce(&OverviewItem::OnItemSpawnedAnimationCompleted, weak_ptr_factory_.GetWeakPtr())}); } - SetTransform(window, target_transform); + window_util::SetTransform(window, target_transform); transform_window_.SetOpacity(kTargetScaler); if (cannot_snap_widget_) { @@ -1264,7 +1264,7 @@ base::BindOnce(&OverviewItem::OnItemBoundsAnimationEnded, weak_ptr_factory_.GetWeakPtr())}); } - SetTransform(window, transform); + window_util::SetTransform(window, transform); transform_window_.SetClipping(clip_rect); }
diff --git a/ash/wm/overview/overview_utils.cc b/ash/wm/overview/overview_utils.cc index 1ff9998..1bbb1a2 100644 --- a/ash/wm/overview/overview_utils.cc +++ b/ash/wm/overview/overview_utils.cc
@@ -151,22 +151,6 @@ return bounds; } -void SetTransform(aura::Window* window, const gfx::Transform& transform) { - const gfx::PointF target_origin( - GetUnionScreenBoundsForWindow(window).origin()); - for (auto* window_iter : - window_util::GetVisibleTransientTreeIterator(window)) { - aura::Window* parent_window = window_iter->parent(); - gfx::RectF original_bounds(window_iter->GetTargetBounds()); - ::wm::TranslateRectToScreen(parent_window, &original_bounds); - const gfx::Transform new_transform = TransformAboutPivot( - gfx::PointF(target_origin.x() - original_bounds.x(), - target_origin.y() - original_bounds.y()), - transform); - window_iter->SetTransform(new_transform); - } -} - void MaximizeIfSnapped(aura::Window* window) { auto* window_state = WindowState::Get(window); if (window_state && window_state->IsSnapped()) {
diff --git a/ash/wm/overview/overview_utils.h b/ash/wm/overview/overview_utils.h index fd1aedd..7e8233a 100644 --- a/ash/wm/overview/overview_utils.h +++ b/ash/wm/overview/overview_utils.h
@@ -19,7 +19,6 @@ namespace gfx { class Rect; -class Transform; } // namespace gfx namespace views { @@ -65,12 +64,6 @@ // window's transient hierarchy. gfx::RectF GetUnionScreenBoundsForWindow(aura::Window* window); -// Applies the `transform` to `window` and all of its transient children. Note -// `transform` is the transform that is applied to `window` and needs to be -// adjusted for the transient child windows. -ASH_EXPORT void SetTransform(aura::Window* window, - const gfx::Transform& transform); - // Maximize the window if it is snapped without animation. void MaximizeIfSnapped(aura::Window* window);
diff --git a/ash/wm/overview/scoped_overview_transform_window.cc b/ash/wm/overview/scoped_overview_transform_window.cc index 93a25a5..d16f3ae 100644 --- a/ash/wm/overview/scoped_overview_transform_window.cc +++ b/ash/wm/overview/scoped_overview_transform_window.cc
@@ -281,7 +281,7 @@ // from the shelf. ScopedOverviewAnimationSettings animation_settings(OVERVIEW_ANIMATION_NONE, window_); - SetTransform(window_, gfx::Transform()); + window_util::SetTransform(window_, gfx::Transform()); SetClipping(gfx::Rect(original_clip_rect_.size())); return; } @@ -301,7 +301,7 @@ // Use identity transform directly to reset window's transform when exiting // overview. - SetTransform(window_, gfx::Transform()); + window_util::SetTransform(window_, gfx::Transform()); // Add requests to cache render surface and perform trilinear filtering for // the exit animation of overview mode. The requests will be removed when
diff --git a/ash/wm/overview/scoped_overview_transform_window_unittest.cc b/ash/wm/overview/scoped_overview_transform_window_unittest.cc index 6fec0b37..ee8ac25 100644 --- a/ash/wm/overview/scoped_overview_transform_window_unittest.cc +++ b/ash/wm/overview/scoped_overview_transform_window_unittest.cc
@@ -8,6 +8,7 @@ #include "ash/test/ash_test_base.h" #include "ash/wm/overview/overview_utils.h" #include "ash/wm/window_state.h" +#include "ash/wm/window_util.h" #include "base/numerics/safe_conversions.h" #include "ui/aura/window.h" #include "ui/compositor/layer.h" @@ -263,7 +264,7 @@ EXPECT_FALSE(child2->IsVisible()); auto transform = gfx::Transform::MakeTranslation(10.f, 10.f); - SetTransform(window.get(), transform); + window_util::SetTransform(window.get(), transform); EXPECT_EQ(transform, window->transform()); EXPECT_EQ(transform, child->transform()); EXPECT_TRUE(child2->transform().IsIdentity());
diff --git a/ash/wm/splitview/split_view_controller.cc b/ash/wm/splitview/split_view_controller.cc index 08d764e..070a12a 100644 --- a/ash/wm/splitview/split_view_controller.cc +++ b/ash/wm/splitview/split_view_controller.cc
@@ -2377,7 +2377,7 @@ left_or_top_transform.Translate(horizontal ? distance : 0, horizontal ? 0 : distance); } - SetTransform(left_or_top_window, left_or_top_transform); + window_util::SetTransform(left_or_top_window, left_or_top_transform); } gfx::Transform right_or_bottom_transform; @@ -2390,18 +2390,20 @@ right_or_bottom_transform.Translate(horizontal ? -distance : 0, horizontal ? 0 : -distance); } - SetTransform(right_or_bottom_window, right_or_bottom_transform); + window_util::SetTransform(right_or_bottom_window, + right_or_bottom_transform); } } void SplitViewController::RestoreWindowsTransformAfterResizing() { DCHECK(InSplitViewMode()); if (primary_window_) - SetTransform(primary_window_, gfx::Transform()); + window_util::SetTransform(primary_window_, gfx::Transform()); if (secondary_window_) - SetTransform(secondary_window_, gfx::Transform()); - if (black_scrim_layer_.get()) + window_util::SetTransform(secondary_window_, gfx::Transform()); + if (black_scrim_layer_.get()) { black_scrim_layer_->SetTransform(gfx::Transform()); + } } void SplitViewController::SetTransformWithAnimation(
diff --git a/ash/wm/splitview/split_view_divider.cc b/ash/wm/splitview/split_view_divider.cc index 3ac3329f..11f6047 100644 --- a/ash/wm/splitview/split_view_divider.cc +++ b/ash/wm/splitview/split_view_divider.cc
@@ -8,6 +8,7 @@ #include <memory> #include "ash/display/screen_orientation_controller.h" +#include "ash/public/cpp/window_properties.h" #include "ash/screen_util.h" #include "ash/shell.h" #include "ash/wm/desks/desks_util.h" @@ -50,6 +51,23 @@ window); } +// Returns the widget init params needed to create the widget. +views::Widget::InitParams CreateWidgetInitParams( + aura::Window* parent_window, + const std::string& widget_name) { + views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); + params.opacity = views::Widget::InitParams::WindowOpacity::kOpaque; + params.activatable = views::Widget::InitParams::Activatable::kNo; + params.parent = parent_window; + params.init_properties_container.SetProperty(kHideInDeskMiniViewKey, true); + // Exclude the divider from getting transformed with its transient parent + // window when we are resizing. The divider will set its own transforms. + params.init_properties_container.SetProperty( + kExcludeFromTransientTreeTransformKey, true); + params.name = widget_name; + return params; +} + } // namespace SplitViewDivider::SplitViewDivider(LayoutDividerController* controller,
diff --git a/ash/wm/splitview/split_view_utils.cc b/ash/wm/splitview/split_view_utils.cc index 5e33f3e..56d140b8 100644 --- a/ash/wm/splitview/split_view_utils.cc +++ b/ash/wm/splitview/split_view_utils.cc
@@ -743,18 +743,6 @@ : HTLEFT; } -views::Widget::InitParams CreateWidgetInitParams( - aura::Window* parent_window, - const std::string& widget_name) { - views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); - params.opacity = views::Widget::InitParams::WindowOpacity::kOpaque; - params.activatable = views::Widget::InitParams::Activatable::kNo; - params.parent = parent_window; - params.init_properties_container.SetProperty(kHideInDeskMiniViewKey, true); - params.name = widget_name; - return params; -} - ASH_EXPORT std::string BuildWindowLayoutCompleteOnSessionExitHistogram() { std::string histogram_name(kHistogramPrefix); histogram_name.append(kWindowLayoutCompleteOnSessionExitRootWord);
diff --git a/ash/wm/splitview/split_view_utils.h b/ash/wm/splitview/split_view_utils.h index 63f21b31..e68f09c 100644 --- a/ash/wm/splitview/split_view_utils.h +++ b/ash/wm/splitview/split_view_utils.h
@@ -230,11 +230,6 @@ // current screen orientation for resizing purpose. int GetWindowComponentForResize(aura::Window* window); -// Returns the widget init params needed to create the widget. -views::Widget::InitParams CreateWidgetInitParams( - aura::Window* parent_window, - const std::string& widget_name); - // Builds the full histogram that records whether the window layout completes on // `SplitViewOverviewSession` exit. The full histogram is shown in the example // below:
diff --git a/ash/wm/window_util.cc b/ash/wm/window_util.cc index fa0e767b..5ff6b2e 100644 --- a/ash/wm/window_util.cc +++ b/ash/wm/window_util.cc
@@ -573,6 +573,25 @@ return GetTransientTreeIterator(window, base::BindRepeating(hide_predicate)); } +void SetTransform(aura::Window* window, const gfx::Transform& transform) { + const gfx::PointF target_origin( + GetUnionScreenBoundsForWindow(window).origin()); + for (auto* window_iter : + window_util::GetVisibleTransientTreeIterator(window)) { + if (window_iter->GetProperty(kExcludeFromTransientTreeTransformKey)) { + continue; + } + aura::Window* parent_window = window_iter->parent(); + gfx::RectF original_bounds(window_iter->GetTargetBounds()); + ::wm::TranslateRectToScreen(parent_window, &original_bounds); + const gfx::Transform new_transform = TransformAboutPivot( + gfx::PointF(target_origin.x() - original_bounds.x(), + target_origin.y() - original_bounds.y()), + transform); + window_iter->SetTransform(new_transform); + } +} + gfx::RectF GetTransformedBounds(aura::Window* transformed_window, int top_inset) { gfx::RectF bounds; @@ -597,7 +616,7 @@ header_bounds = new_transform.MapRect(header_bounds); window_bounds.Inset(gfx::InsetsF::TLBR(header_bounds.height(), 0, 0, 0)); } - ::wm::TranslateRectToScreen(window->parent(), &window_bounds); + wm::TranslateRectToScreen(window->parent(), &window_bounds); bounds.Union(window_bounds); } return bounds;
diff --git a/ash/wm/window_util.h b/ash/wm/window_util.h index 6500473..1fcb7e9 100644 --- a/ash/wm/window_util.h +++ b/ash/wm/window_util.h
@@ -153,6 +153,13 @@ WindowTransientDescendantIteratorRange GetVisibleTransientTreeIterator( aura::Window* window); +// Applies the `transform` to `window` and all of its transient children, +// except those with `kExcludeFromTransientTreeTransformKey` set to true. +// Note `transform` is the transform that is applied to `window` and needs to be +// adjusted for the transient child windows. +ASH_EXPORT void SetTransform(aura::Window* window, + const gfx::Transform& transform); + // Calculates the bounds of the |transformed_window|. Those bounds are a union // of all regular (normal and panel) windows in the |transformed_window|'s // transient hierarchy. The returned Rect is in screen coordinates. The returned
diff --git a/base/android/java/src/org/chromium/base/library_loader/LibraryPrefetcher.java b/base/android/java/src/org/chromium/base/library_loader/LibraryPrefetcher.java index 6fbab7e..15d5cc1 100644 --- a/base/android/java/src/org/chromium/base/library_loader/LibraryPrefetcher.java +++ b/base/android/java/src/org/chromium/base/library_loader/LibraryPrefetcher.java
@@ -11,7 +11,6 @@ import org.chromium.base.ContextUtils; import org.chromium.base.SysUtils; import org.chromium.base.TraceEvent; -import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.task.PostTask; import org.chromium.base.task.TaskTraits; @@ -68,12 +67,6 @@ // process. boolean prefetch = coldStart && percentage < 90; if (prefetch) LibraryPrefetcherJni.get().forkAndPrefetchNativeLibrary(); - if (percentage != -1) { - String histogram = - "LibraryLoader.PercentageOfResidentCodeBeforePrefetch" - + (coldStart ? ".ColdStartup" : ".WarmStartup"); - RecordHistogram.recordPercentageHistogram(histogram, percentage); - } } // Removes a dead flag, don't remove the removal code before M77 at least. ContextUtils.getAppSharedPreferences()
diff --git a/base/feature_list_unittest.cc b/base/feature_list_unittest.cc index 1195cd5f..e3ad4b6 100644 --- a/base/feature_list_unittest.cc +++ b/base/feature_list_unittest.cc
@@ -697,7 +697,7 @@ auto early_access_feature_list = std::make_unique<FeatureList>(); early_access_feature_list->InitFromCommandLine("OffByDefault", "OnByDefault"); FeatureList::SetEarlyAccessInstance(std::move(early_access_feature_list), - {"OnByDefault"}); + {"DcheckIsFatal", "OnByDefault"}); EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault)); EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault)); EXPECT_EQ(&kFeatureOffByDefault, @@ -711,8 +711,9 @@ auto early_access_feature_list = std::make_unique<FeatureList>(); early_access_feature_list->InitFromCommandLine("OffByDefault", "OnByDefault"); - FeatureList::SetEarlyAccessInstance(std::move(early_access_feature_list), - {"OffByDefault", "OnByDefault"}); + FeatureList::SetEarlyAccessInstance( + std::move(early_access_feature_list), + {"DcheckIsFatal", "OffByDefault", "OnByDefault"}); EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault)); EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
diff --git a/base/metrics/sample_vector.cc b/base/metrics/sample_vector.cc index 596e6738..8c45ddb 100644 --- a/base/metrics/sample_vector.cc +++ b/base/metrics/sample_vector.cc
@@ -7,6 +7,7 @@ #include <ostream> #include "base/check_op.h" +#include "base/compiler_specific.h" #include "base/debug/crash_logging.h" #include "base/lazy_instance.h" #include "base/memory/ptr_util.h" @@ -160,14 +161,17 @@ } // Handle the multi-sample case. - Count new_value = + Count new_bucket_count = subtle::NoBarrier_AtomicIncrement(&counts()[bucket_index], count); IncreaseSumAndCount(strict_cast<int64_t>(count) * value, count); // TODO(bcwhite) Remove after crbug.com/682680. - Count old_value = new_value - count; - if ((new_value >= 0) != (old_value >= 0) && count > 0) + Count old_bucket_count = new_bucket_count - count; + bool record_negative_sample = + (new_bucket_count >= 0) != (old_bucket_count >= 0) && count > 0; + if (UNLIKELY(record_negative_sample)) { RecordNegativeSample(SAMPLES_ACCUMULATE_OVERFLOW, count); + } } Count SampleVectorBase::GetCount(Sample value) const {
diff --git a/base/task/cancelable_task_tracker_unittest.cc b/base/task/cancelable_task_tracker_unittest.cc index f1fcf23b..1991385 100644 --- a/base/task/cancelable_task_tracker_unittest.cc +++ b/base/task/cancelable_task_tracker_unittest.cc
@@ -136,12 +136,6 @@ worker_thread.Stop(); } -void ExpectIsCanceled( - const CancelableTaskTracker::IsCanceledCallback& is_canceled, - bool expected_is_canceled) { - EXPECT_EQ(expected_is_canceled, is_canceled.Run()); -} - // Create a new task ID and check its status on a separate thread // before and after canceling. The is-canceled callback should be // thread-safe (i.e., nothing should blow up). @@ -155,14 +149,16 @@ Thread other_thread("other thread"); ASSERT_TRUE(other_thread.Start()); other_thread.task_runner()->PostTask( - FROM_HERE, BindOnce(&ExpectIsCanceled, is_canceled, false)); + FROM_HERE, is_canceled.Then( + BindRepeating([](bool result) { EXPECT_FALSE(result); }))); other_thread.Stop(); task_tracker_.TryCancel(task_id); ASSERT_TRUE(other_thread.Start()); other_thread.task_runner()->PostTask( - FROM_HERE, BindOnce(&ExpectIsCanceled, is_canceled, true)); + FROM_HERE, is_canceled.Then( + BindRepeating([](bool result) { EXPECT_TRUE(result); }))); other_thread.Stop(); } @@ -314,25 +310,20 @@ EXPECT_DCHECK_DEATH(std::move(fn).Run(task_tracker)); } -void PostDoNothingTask(CancelableTaskTracker* task_tracker) { - std::ignore = task_tracker->PostTask( - scoped_refptr<TestSimpleTaskRunner>(new TestSimpleTaskRunner()).get(), - FROM_HERE, DoNothing()); -} - TEST_F(CancelableTaskTrackerDeathTest, PostFromDifferentThread) { Thread bad_thread("bad thread"); ASSERT_TRUE(bad_thread.Start()); bad_thread.task_runner()->PostTask( FROM_HERE, - BindOnce(&MaybeRunDeadlyTaskTrackerMemberFunction, - Unretained(&task_tracker_), BindOnce(&PostDoNothingTask))); -} - -void TryCancel(CancelableTaskTracker::TaskId task_id, - CancelableTaskTracker* task_tracker) { - task_tracker->TryCancel(task_id); + BindOnce( + &MaybeRunDeadlyTaskTrackerMemberFunction, Unretained(&task_tracker_), + BindOnce([](CancelableTaskTracker* task_tracker) { + std::ignore = task_tracker->PostTask( + scoped_refptr<TestSimpleTaskRunner>(new TestSimpleTaskRunner()) + .get(), + FROM_HERE, DoNothing()); + }))); } TEST_F(CancelableTaskTrackerDeathTest, CancelOnDifferentThread) { @@ -347,9 +338,14 @@ EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id); bad_thread.task_runner()->PostTask( - FROM_HERE, - BindOnce(&MaybeRunDeadlyTaskTrackerMemberFunction, - Unretained(&task_tracker_), BindOnce(&TryCancel, task_id))); + FROM_HERE, BindOnce(&MaybeRunDeadlyTaskTrackerMemberFunction, + Unretained(&task_tracker_), + BindOnce( + [](CancelableTaskTracker::TaskId task_id, + CancelableTaskTracker* task_tracker) { + task_tracker->TryCancel(task_id); + }, + task_id))); test_task_runner->RunUntilIdle(); } @@ -368,7 +364,9 @@ bad_thread.task_runner()->PostTask( FROM_HERE, BindOnce(&MaybeRunDeadlyTaskTrackerMemberFunction, Unretained(&task_tracker_), - BindOnce(&CancelableTaskTracker::TryCancelAll))); + BindOnce([](CancelableTaskTracker* task_tracker) { + task_tracker->TryCancelAll(); + }))); test_task_runner->RunUntilIdle(); }
diff --git a/build/OWNERS b/build/OWNERS index 3f0dc41..78049f40 100644 --- a/build/OWNERS +++ b/build/OWNERS
@@ -5,10 +5,14 @@ brucedawson@chromium.org dpranke@google.com jochen@chromium.org +jwata@google.com +philwo@chromium.org +richardwa@google.com sdefresne@chromium.org thakis@chromium.org thomasanderson@chromium.org tikuta@chromium.org +ukai@google.com # Clang build config changes: file://tools/clang/scripts/OWNERS
diff --git a/build/fuchsia/get_auth_token.py b/build/fuchsia/get_auth_token.py index 8c293fb4..3f5569b 100755 --- a/build/fuchsia/get_auth_token.py +++ b/build/fuchsia/get_auth_token.py
@@ -19,7 +19,11 @@ def main(): luci_auth = os.path.join(find_depot_tools.DEPOT_TOOLS_PATH, 'luci-auth') - proc = subprocess.run([luci_auth, 'token'], encoding='utf-8') + proc = subprocess.run([ + luci_auth, 'token', '-scopes', + 'https://www.googleapis.com/auth/devstorage.read_only' + ], + encoding='utf-8') return proc.returncode
diff --git a/build/fuchsia/linux_internal.sdk.sha1 b/build/fuchsia/linux_internal.sdk.sha1 index 5669b0f..dc083bf75 100644 --- a/build/fuchsia/linux_internal.sdk.sha1 +++ b/build/fuchsia/linux_internal.sdk.sha1
@@ -1 +1 @@ -16.20231112.3.1 +17.20231214.4.1
diff --git a/build/fuchsia/test/common.py b/build/fuchsia/test/common.py index 10e40f7..68bd04e 100644 --- a/build/fuchsia/test/common.py +++ b/build/fuchsia/test/common.py
@@ -42,6 +42,16 @@ IMAGES_ROOT = os.path.abspath(_find_fuchsia_images_root()) + +def _find_fuchsia_internal_images_root() -> str: + """Define the root of the fuchsia images.""" + if os.environ.get('FUCHSIA_INTERNAL_IMAGES_ROOT'): + return os.environ['FUCHSIA_INTERNAL_IMAGES_ROOT'] + return IMAGES_ROOT + '-internal' + + +INTERNAL_IMAGES_ROOT = os.path.abspath(_find_fuchsia_internal_images_root()) + REPO_ALIAS = 'fuchsia.com'
diff --git a/build/fuchsia/test/common_unittests.py b/build/fuchsia/test/common_unittests.py index 4e419c90..abab1a9 100755 --- a/build/fuchsia/test/common_unittests.py +++ b/build/fuchsia/test/common_unittests.py
@@ -49,6 +49,14 @@ os.path.join(tmp_dir, 'images', 'workstation-product', 'images')) + def test_images_root_should_not_end_with_path_sep(self): + """INTERNAL_IMAGES_ROOT appends -internal at the end of the IMAGES_ROOT, + so the later one should not end with a /, otherwise the folder name will + become 'images/-internal'.""" + # Avoid the logic being bypassed. + self.assertIsNone(os.environ.get('FUCHSIA_INTERNAL_IMAGES_ROOT')) + self.assertFalse(common.IMAGES_ROOT.endswith(os.path.sep)) + if __name__ == '__main__': unittest.main()
diff --git a/build/fuchsia/test/compatible_utils.py b/build/fuchsia/test/compatible_utils.py index 39e1ac1..b59fbbd 100644 --- a/build/fuchsia/test/compatible_utils.py +++ b/build/fuchsia/test/compatible_utils.py
@@ -3,18 +3,14 @@ # found in the LICENSE file. """Functions used in both v1 and v2 scripts.""" +import json import os import platform -import re import stat from typing import Iterable, List, Tuple -# File indicating version of an image downloaded to the host -_BUILD_ARGS = "buildargs.gn" -_ARGS_FILE = 'args.gn' - _FILTER_DIR = 'testing/buildbot/filters' _SSH_KEYS = os.path.expanduser('~/.ssh/fuchsia_authorized_keys') @@ -129,41 +125,16 @@ return '/pkg/' + filter_file[filter_file.index(_FILTER_DIR):] +# TODO(crbug.com/1496426): Rename to get_product_version. def get_sdk_hash(system_image_dir: str) -> Tuple[str, str]: """Read version of hash in pre-installed package directory. Returns: Tuple of (product, version) of image to be installed. - Raises: - VersionNotFoundError: if contents of buildargs.gn cannot be found or the - version number cannot be extracted. """ - # TODO(crbug.com/1261961): Stop processing buildargs.gn directly. - args_file = os.path.join(system_image_dir, _BUILD_ARGS) - if not os.path.exists(args_file): - args_file = os.path.join(system_image_dir, _ARGS_FILE) - - if not os.path.exists(args_file): - raise VersionNotFoundError( - f'Dir {system_image_dir} did not contain {_BUILD_ARGS} or ' - f'{_ARGS_FILE}') - - with open(args_file) as f: - contents = f.readlines() - if not contents: - raise VersionNotFoundError('Could not retrieve %s' % args_file) - version_key = 'build_info_version' - product_key = 'build_info_product' - info_keys = [product_key, version_key] - version_info = {} - for line in contents: - for key in info_keys: - match = re.match(r'%s = "(.*)"' % key, line) - if match: - version_info[key] = match.group(1) - if not (version_key in version_info and product_key in version_info): - raise VersionNotFoundError( - 'Could not extract version info from %s. Contents: %s' % - (args_file, contents)) - - return (version_info[product_key], version_info[version_key]) + with open(os.path.join(system_image_dir, + 'product_bundle.json')) as product: + # The product_name in the json file does not match the name of the image + # flashed to the device. + return (os.path.basename(os.path.normpath(system_image_dir)), + json.load(product)['product_version'])
diff --git a/build/fuchsia/test/compatible_utils_unittests.py b/build/fuchsia/test/compatible_utils_unittests.py index fa2a713..e06287b3 100755 --- a/build/fuchsia/test/compatible_utils_unittests.py +++ b/build/fuchsia/test/compatible_utils_unittests.py
@@ -5,6 +5,7 @@ """File for testing compatible_utils.py.""" import io +import json import os import stat import tempfile @@ -85,57 +86,34 @@ compatible_utils.map_filter_file_to_package_file( 'foo/testing/buildbot/filters/some.filter')) - def test_get_sdk_hash_fallsback_to_args_file_if_buildargs_dne(self - ) -> None: - """Test |get_sdk_hash| checks if buildargs.gn exists. + def test_get_sdk_hash_success(self) -> None: + """Test |get_sdk_hash| reads product_bundle.json.""" + with mock.patch('builtins.open', + return_value=io.StringIO( + json.dumps({'product_version': '12345'}))): + self.assertEqual( + compatible_utils.get_sdk_hash( + 'third_party/fuchsia-sdk/images-internal/sherlock-release/' + 'smart_display_max_eng_arrested/'), + ('smart_display_max_eng_arrested', '12345')) - If it does not, fallsback to args.gn. This should raise an exception - as it does not exist. + def test_get_sdk_hash_normalize_path(self) -> None: + """Test |get_sdk_hash| uses path as product.""" + with mock.patch('builtins.open', + return_value=io.StringIO( + json.dumps({'product_version': '23456'}))): + self.assertEqual( + compatible_utils.get_sdk_hash( + 'third_party/fuchsia-sdk/images-internal/sherlock-release/' + 'smart_display_max_eng_arrested'), + ('smart_display_max_eng_arrested', '23456')) + + def test_get_sdk_hash_not_found(self) -> None: + """Test |get_sdk_hash| fails if the product_bundle.json does not exist. """ - with mock.patch('os.path.exists', return_value=False) as mock_exists, \ - self.assertRaises(compatible_utils.VersionNotFoundError): - compatible_utils.get_sdk_hash('some/image/dir') - mock_exists.assert_has_calls([ - mock.call('some/image/dir/buildargs.gn'), - mock.call('some/image/dir/args.gn') - ]) - - def test_get_sdk_hash_parse_contents_of_args_file(self) -> None: - """Test |get_sdk_hash| parses buildargs contents correctly.""" - build_args_test_contents = """ -build_info_board = "chromebook-x64" -build_info_product = "workstation_eng" -build_info_version = "10.20221114.2.1" -universe_package_labels += [] -""" - with mock.patch('os.path.exists', return_value=True), \ - mock.patch('builtins.open', - return_value=io.StringIO(build_args_test_contents)): - self.assertEqual(compatible_utils.get_sdk_hash('some/dir'), - ('workstation_eng', '10.20221114.2.1')) - - def test_get_sdk_hash_raises_error_if_keys_missing(self) -> None: - """Test |get_sdk_hash| raises VersionNotFoundError if missing keys""" - build_args_test_contents = """ -import("//boards/chromebook-x64.gni") -import("//products/workstation_eng.gni") -cxx_rbe_enable = true -host_labels += [ "//bundles/infra/build" ] -universe_package_labels += [] -""" - with mock.patch('os.path.exists', return_value=True), \ - mock.patch( - 'builtins.open', - return_value=io.StringIO(build_args_test_contents)), \ - self.assertRaises(compatible_utils.VersionNotFoundError): - compatible_utils.get_sdk_hash('some/dir') - - def test_get_sdk_hash_raises_error_if_contents_empty(self) -> None: - """Test |get_sdk_hash| raises VersionNotFoundError if no contents.""" - with mock.patch('os.path.exists', return_value=True), \ - mock.patch('builtins.open', return_value=io.StringIO("")), \ - self.assertRaises(compatible_utils.VersionNotFoundError): - compatible_utils.get_sdk_hash('some/dir') + with mock.patch('builtins.open', side_effect=IOError()): + self.assertRaises(IOError, compatible_utils.get_sdk_hash, + 'some/image/dir') def test_install_symbols(self): """Test |install_symbols|."""
diff --git a/build/fuchsia/test/flash_device.py b/build/fuchsia/test/flash_device.py index 829a592d..6ead9b5 100755 --- a/build/fuchsia/test/flash_device.py +++ b/build/fuchsia/test/flash_device.py
@@ -80,7 +80,7 @@ def _run_flash_command(system_image_dir: str, target_id: Optional[str]): """Helper function for running `ffx target flash`.""" logging.info('Flashing %s to %s', system_image_dir, target_id) - manifest = os.path.join(system_image_dir, 'flash-manifest.manifest') + product_bundle = os.path.join(system_image_dir, 'product_bundle.json') configs = [ 'fastboot.usb.disabled=true', 'ffx.fastboot.inline_target=true', @@ -99,7 +99,8 @@ with lock(_FF_LOCK, timeout=_FF_LOCK_ACQ_TIMEOUT): logging.info( 'Flash result %s', - common.run_ffx_command(cmd=('target', 'flash', manifest, + common.run_ffx_command(cmd=('target', 'flash', '-b', + product_bundle, '--no-bootloader-reboot'), target_id=target_id, capture_output=True,
diff --git a/build/fuchsia/update_images.py b/build/fuchsia/update_images.py index cacf84e3..b606b97 100755 --- a/build/fuchsia/update_images.py +++ b/build/fuchsia/update_images.py
@@ -4,7 +4,11 @@ # found in the LICENSE file. """Updates the Fuchsia images to the given revision. Should be used in a 'hooks_os' entry so that it only runs when .gclient's target_os includes -'fuchsia'.""" +'fuchsia'. Note, for a smooth transition, this file automatically adds +'-release' at the end of the image gcs file name to eliminate the difference +between product bundle v2 and gce files.""" + +# TODO(crbug.com/1496426): Remove this file. import argparse import itertools @@ -225,6 +229,13 @@ if not args.boot_images: return 0 + for index, item in enumerate(args.boot_images): + # The gclient configuration is in the src-internal and cannot be changed + # atomically with the test script in src. So the update_images.py needs to + # support both scenarios before being fully deprecated for older milestones. + if not item.endswith('-release'): + args.boot_images[index] = item + '-release' + # Check whether there's Fuchsia support for this platform. get_host_os() image_info = GetImageLocationInfo(args.default_bucket, args.allow_override)
diff --git a/build/fuchsia/update_images_test.py b/build/fuchsia/update_images_test.py index f5be774c..430c4bc1 100755 --- a/build/fuchsia/update_images_test.py +++ b/build/fuchsia/update_images_test.py
@@ -3,6 +3,8 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +# TODO(crbug.com/1496426): Remove this file. + import unittest from unittest import mock
diff --git a/build/fuchsia/update_product_bundles.py b/build/fuchsia/update_product_bundles.py index 5a2bdb68..1919d89 100755 --- a/build/fuchsia/update_product_bundles.py +++ b/build/fuchsia/update_product_bundles.py
@@ -17,17 +17,29 @@ import common import update_sdk +from compatible_utils import running_unattended # TODO(crbug/1361089): Remove when the old scripts have been deprecated. _IMAGE_TO_PRODUCT_BUNDLE = { - 'core.x64-dfv2-release': 'core.x64-dfv2', - 'qemu.arm64': 'terminal.qemu-arm64', - 'qemu.x64': 'terminal.x64', + 'core.x64-dfv2-release': + 'core.x64-dfv2', + 'qemu.arm64': + 'terminal.qemu-arm64', + 'qemu.x64': + 'terminal.x64', 'workstation_eng.chromebook-x64-dfv2-release': 'workstation_eng.chromebook-x64-dfv2', - 'workstation_eng.chromebook-x64-release': 'workstation_eng.chromebook-x64', - 'workstation_eng.qemu-x64-release': 'workstation_eng.qemu-x64', + 'workstation_eng.chromebook-x64-release': + 'workstation_eng.chromebook-x64', + 'workstation_eng.qemu-x64-release': + 'workstation_eng.qemu-x64', + 'smart_display_eng_arrested.astro-release': + 'smart_display_eng_arrested.astro', + 'smart_display_max_eng_arrested.sherlock-release': + 'smart_display_max_eng_arrested.sherlock', + 'smart_display_m3_latest_eng_paused.nelson-release': + 'smart_display_m3_latest_eng_paused.nelson', } @@ -109,6 +121,14 @@ return None +# VisibleForTesting +def internal_hash(): + hash_filename = os.path.join(os.path.dirname(__file__), + 'linux_internal.sdk.sha1') + return (open(hash_filename, 'r').read().strip() + if os.path.exists(hash_filename) else '') + + def main(): parser = argparse.ArgumentParser() parser.add_argument('--verbose', @@ -120,9 +140,11 @@ type=str, help='List of product bundles to download, represented as a comma ' 'separated list.') - parser.add_argument('--auth', - action='store_true', - help='Enable additional authorization for ffx product') + parser.add_argument( + '--internal', + action='store_true', + help='Whether the images are coming from internal, it impacts version ' + 'file, bucket and download location.') args = parser.parse_args() logging.basicConfig(level=logging.DEBUG if args.verbose else logging.INFO) @@ -134,20 +156,36 @@ logging.info('Searching for the following products: %s', str(new_products)) logging.debug('Getting new SDK hash') - new_sdk_hash = common.get_hash_from_sdk() + if args.internal: + new_hash = internal_hash() + else: + new_hash = common.get_hash_from_sdk() auth_args = [ '--auth', os.path.join(os.path.dirname(__file__), 'get_auth_token.py') - ] if args.auth else [] - + ] if args.internal and running_unattended() else [] + if args.internal and not running_unattended(): + print('*** product bundle v2 requires authentication with your account and ' + 'it should already open a browser window to do it if you have not ' + 'granted the permission yet.') for product in new_products: prod, board = product.split('.', 1) - image_dir = os.path.join(common.IMAGES_ROOT, prod, board) - + if prod.startswith('smart_display'): + # This is a hacky way of keeping the files into the folders matching + # the original image name, since the definition is unfortunately in + # src-internal. Likely we can download two copies for a smooth + # transition, but it would be easier to keep it as-is during the ffx + # product v2 migration. + # TODO(crbug.com/1496426): Migrate the image download folder away from the + # following hack. + prod, board = board + '-release', prod + image_dir = os.path.join( + common.INTERNAL_IMAGES_ROOT if args.internal else common.IMAGES_ROOT, + prod, board) curr_signature = get_current_signature(image_dir) - if curr_signature != new_sdk_hash: + if curr_signature != new_hash: common.make_clean_directory(image_dir) logging.debug('Checking for override file') override_file = os.path.join(os.path.dirname(__file__), @@ -155,12 +193,13 @@ if os.path.isfile(override_file): base_url = update_sdk.GetSDKOverrideGCSPath().replace('/sdk', '') else: - base_url = f'gs://fuchsia/development/{new_sdk_hash}' - download_url = common.run_ffx_command(cmd=[ - 'product', 'lookup', product, new_sdk_hash, '--base-url', base_url - ] + auth_args, - check=True, - capture_output=True).stdout.strip() + bucket = 'fuchsia-sdk' if args.internal else 'fuchsia' + base_url = f'gs://{bucket}/development/{new_hash}' + download_url = common.run_ffx_command( + cmd=['product', 'lookup', product, new_hash, '--base-url', base_url] + + auth_args, + check=True, + capture_output=True).stdout.strip() logging.info(f'Downloading {product} from {base_url}.') common.run_ffx_command( cmd=['product', 'download', download_url, image_dir] + auth_args,
diff --git a/build/fuchsia/update_product_bundles_test.py b/build/fuchsia/update_product_bundles_test.py index 7271e33..0540b27 100755 --- a/build/fuchsia/update_product_bundles_test.py +++ b/build/fuchsia/update_product_bundles_test.py
@@ -97,10 +97,10 @@ check=True) ]) - @mock.patch('common.get_hash_from_sdk', return_value='abc') + @mock.patch('update_product_bundles.running_unattended', return_value=True) # Disallow reading sdk_override. @mock.patch('os.path.isfile', return_value=False) - def testLookupAndDownloadWithAuth(self, get_hash_mock, isfile_mock): + def testLookupAndDownloadWithAuth(self, *_): try: common.get_host_os() except: @@ -110,20 +110,22 @@ auth_file = os.path.abspath( os.path.join(os.path.dirname(__file__), 'get_auth_token.py')) self._ffx_mock.return_value.stdout = 'http://download-url' - with mock.patch('sys.argv', - ['update_product_bundles.py', 'terminal.x64', '--auth']): + with mock.patch( + 'sys.argv', + ['update_product_bundles.py', 'terminal.x64', '--internal']): update_product_bundles.main() + new_hash = update_product_bundles.internal_hash() self._ffx_mock.assert_has_calls([ mock.call(cmd=[ - 'product', 'lookup', 'terminal.x64', 'abc', '--base-url', - 'gs://fuchsia/development/abc', '--auth', auth_file + 'product', 'lookup', 'terminal.x64', new_hash, '--base-url', + f'gs://fuchsia-sdk/development/{new_hash}', '--auth', auth_file ], - capture_output=True, - check=True), + check=True, + capture_output=True), mock.call(cmd=[ 'product', 'download', 'http://download-url', - os.path.join(common.IMAGES_ROOT, 'terminal', 'x64'), '--auth', - auth_file + os.path.join(common.INTERNAL_IMAGES_ROOT, 'terminal', 'x64'), + '--auth', auth_file ], check=True) ])
diff --git a/buildtools/OWNERS b/buildtools/OWNERS index f0ebe27b..d5089af 100644 --- a/buildtools/OWNERS +++ b/buildtools/OWNERS
@@ -1,6 +1,11 @@ set noparent +jwata@google.com +philwo@chromium.org +richardwa@google.com thakis@chromium.org thomasanderson@chromium.org +tikuta@chromium.org +ukai@google.com # For the libc++ autoroller. per-file deps_revisions.gni=*
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index f603fd71..83e06e5 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -972,7 +972,6 @@ "//chrome/browser/download/android:java", "//chrome/browser/download/android:junit_tests", "//chrome/browser/download/internal/android:junit", - "//chrome/browser/endpoint_fetcher:java", "//chrome/browser/enterprise/util:java", "//chrome/browser/enterprise/util:junit", "//chrome/browser/feature_engagement:java", @@ -1436,7 +1435,6 @@ "//chrome/browser/download/android:download_java_tests", "//chrome/browser/download/android:file_provider_java", "//chrome/browser/download/android:java", - "//chrome/browser/endpoint_fetcher:java", "//chrome/browser/feature_engagement:java", "//chrome/browser/first_run/android:java", "//chrome/browser/flags:java", @@ -1605,7 +1603,6 @@ "//chrome/browser/device_reauth/android:java", "//chrome/browser/download/android:file_provider_java", "//chrome/browser/download/android:java", - "//chrome/browser/endpoint_fetcher:java", "//chrome/browser/enterprise/util:java", "//chrome/browser/enterprise/util:test_support_java", "//chrome/browser/feature_engagement:java", @@ -2007,10 +2004,6 @@ "//ui/android:ui_java", ] - if (enable_gvr_services) { - chrome_test_xr_java_deps += [ "//chrome/android/features/vr:java" ] - } - # Files used for both VR and AR testing android_library("chrome_test_xr_java") { testonly = true @@ -2074,36 +2067,6 @@ "//ui/android:ui_java_test_support", ] - if (enable_gvr_services) { - sources += [ - "javatests/src/org/chromium/chrome/browser/vr/EmulatedGvrController.java", - "javatests/src/org/chromium/chrome/browser/vr/GvrDaydreamReadyModuleInstallTest.java", - "javatests/src/org/chromium/chrome/browser/vr/GvrInstallUpdateMessageTest.java", - "javatests/src/org/chromium/chrome/browser/vr/TestVrShellDelegate.java", - - # TODO(https://crbug.com/1429384): Modify these tests to run on non-GVR runtimes. - "javatests/src/org/chromium/chrome/browser/vr/WebXrGvrDeviceTest.java", - "javatests/src/org/chromium/chrome/browser/vr/WebXrGvrInputTest.java", - "javatests/src/org/chromium/chrome/browser/vr/WebXrGvrPermissionTest.java", - "javatests/src/org/chromium/chrome/browser/vr/WebXrGvrTabTest.java", - "javatests/src/org/chromium/chrome/browser/vr/WebXrGvrTestFramework.java", - "javatests/src/org/chromium/chrome/browser/vr/WebXrGvrTransitionTest.java", - "javatests/src/org/chromium/chrome/browser/vr/mock/MockGvrVrCoreVersionChecker.java", - "javatests/src/org/chromium/chrome/browser/vr/mock/MockGvrVrDaydreamApi.java", - "javatests/src/org/chromium/chrome/browser/vr/rules/ChromeTabbedActivityGvrTestRule.java", - "javatests/src/org/chromium/chrome/browser/vr/rules/CustomTabActivityGvrTestRule.java", - "javatests/src/org/chromium/chrome/browser/vr/rules/WebappActivityGvrTestRule.java", - "javatests/src/org/chromium/chrome/browser/vr/util/GvrTestRuleUtils.java", - "javatests/src/org/chromium/chrome/browser/vr/util/GvrTransitionUtils.java", - "javatests/src/org/chromium/chrome/browser/vr/util/VrShellDelegateUtils.java", - ] - - deps += [ - "//third_party/gvr-android-sdk:controller_test_api_java", - "//third_party/gvr-android-sdk:gvr_common_java", - ] - } - if (enable_cardboard) { sources += [ "javatests/src/org/chromium/chrome/browser/vr/WebXrVrCardboardDeviceTest.java", @@ -2118,11 +2081,6 @@ "javatests/src/org/chromium/chrome/browser/vr/util/VrCardboardTestRuleUtils.java", ] } - - data = [ - "//chrome/android/shared_preference_files/test/", - "//third_party/gvr-android-sdk/test-apks/", - ] } }
diff --git a/chrome/android/chrome_test_java_sources.gni b/chrome/android/chrome_test_java_sources.gni index 273f944..191754e 100644 --- a/chrome/android/chrome_test_java_sources.gni +++ b/chrome/android/chrome_test_java_sources.gni
@@ -435,6 +435,7 @@ "javatests/src/org/chromium/chrome/browser/signin/SigninManagerIntegrationTest.java", "javatests/src/org/chromium/chrome/browser/signin/SigninSignoutIntegrationTest.java", "javatests/src/org/chromium/chrome/browser/signin/SyncConsentFragmentTest.java", + "javatests/src/org/chromium/chrome/browser/site_settings/AllSiteSettingsTest.java", "javatests/src/org/chromium/chrome/browser/site_settings/ChromeSiteSettingsDelegateTest.java", "javatests/src/org/chromium/chrome/browser/site_settings/CookieControlsBridgeTest.java", "javatests/src/org/chromium/chrome/browser/site_settings/CookieControlsServiceBridgeTest.java",
diff --git a/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinatorUnitTest.java b/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinatorUnitTest.java index 7bca8635..e536fca 100644 --- a/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinatorUnitTest.java +++ b/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinatorUnitTest.java
@@ -49,7 +49,7 @@ /** Tests for {@link StartSurfaceCoordinator}. */ @RunWith(BaseRobolectricTestRunner.class) @Config(manifest = Config.NONE) -@DisableFeatures({ChromeFeatureList.WEB_FEED, ChromeFeatureList.SHOPPING_LIST}) +@DisableFeatures({ChromeFeatureList.WEB_FEED}) public class StartSurfaceCoordinatorUnitTest { private static final String START_SURFACE_TIME_SPENT = "StartSurface.TimeSpent"; private static final String HISTOGRAM_START_SURFACE_MODULE_CLICK = "StartSurface.Module.Click";
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/LargeMessageCardView.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/LargeMessageCardView.java index 3ddfdde..d647be2 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/LargeMessageCardView.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/LargeMessageCardView.java
@@ -18,7 +18,6 @@ import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.tab.state.ShoppingPersistedTabData; import org.chromium.chrome.browser.util.ChromeAccessibilityUtil; import org.chromium.chrome.tab_ui.R; @@ -279,16 +278,12 @@ * @param isIncognito Whether the resource is used for incognito mode. */ private void setBackground(boolean isIncognito) { - final int elevationDimenId = - ChromeFeatureList.sBaselineGm3SurfaceColors.isEnabled() - ? R.dimen.default_elevation_2 - : R.dimen.card_elevation; - ColorStateList backgroundTint = ColorStateList.valueOf( (isIncognito) ? mContext.getColor(R.color.incognito_card_bg_color) - : ChromeColors.getSurfaceColor(mContext, elevationDimenId)); + : ChromeColors.getSurfaceColor( + mContext, R.dimen.default_elevation_2)); mMaterialCardViewNoShadow.setBackgroundTintList(backgroundTint); } }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MessageCardView.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MessageCardView.java index e1a83462..9e0dde9 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MessageCardView.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MessageCardView.java
@@ -13,7 +13,6 @@ import android.widget.LinearLayout; import org.chromium.base.Callback; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.tab_ui.R; import org.chromium.components.browser_ui.styles.ChromeColors; import org.chromium.components.browser_ui.widget.text.TemplatePreservingTextView; @@ -164,12 +163,9 @@ return; } // Set dynamic color. - final int elevationDimenId = - ChromeFeatureList.sBaselineGm3SurfaceColors.isEnabled() - ? R.dimen.default_elevation_2 - : R.dimen.card_elevation; GradientDrawable gradientDrawable = (GradientDrawable) getBackground(); - gradientDrawable.setColor(ChromeColors.getSurfaceColor(getContext(), elevationDimenId)); + gradientDrawable.setColor( + ChromeColors.getSurfaceColor(getContext(), R.dimen.default_elevation_2)); } /**
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListEditorCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListEditorCoordinator.java index c585df6b..a3974f6 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListEditorCoordinator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListEditorCoordinator.java
@@ -8,7 +8,6 @@ import static org.chromium.chrome.browser.tasks.tab_management.TabListModel.CardProperties.CARD_TYPE; import static org.chromium.chrome.browser.tasks.tab_management.TabListModel.CardProperties.ModelType.OTHERS; -import android.app.Activity; import android.content.Context; import android.view.LayoutInflater; import android.view.ViewGroup; @@ -132,7 +131,7 @@ } } - private final Activity mActivity; + private final Context mContext; private final ViewGroup mParentView; private final BrowserControlsStateProvider mBrowserControlsStateProvider; private final @NonNull ObservableSupplier<TabModelFilter> mCurrentTabModelFilterSupplier; @@ -146,7 +145,7 @@ private MultiThumbnailCardProvider mMultiThumbnailCardProvider; public TabListEditorCoordinator( - Activity activity, + Context context, ViewGroup parentView, BrowserControlsStateProvider browserControlsStateProvider, @NonNull ObservableSupplier<TabModelFilter> currentTabModelFilterSupplier, @@ -159,7 +158,7 @@ SnackbarManager snackbarManager, @UiType int itemType) { try (TraceEvent e = TraceEvent.scoped("TabListEditorCoordinator.constructor")) { - mActivity = activity; + mContext = context; mParentView = parentView; mBrowserControlsStateProvider = browserControlsStateProvider; mCurrentTabModelFilterSupplier = currentTabModelFilterSupplier; @@ -168,7 +167,7 @@ || mode == TabListCoordinator.TabListMode.LIST; mTabListEditorLayout = - LayoutInflater.from(activity) + LayoutInflater.from(context) .inflate(R.layout.tab_list_editor_layout, parentView, false) .findViewById(R.id.selectable_list); @@ -182,7 +181,7 @@ mTabListCoordinator = new TabListCoordinator( mode, - activity, + context, mBrowserControlsStateProvider, currentTabModelFilterSupplier, regularTabModelSupplier, @@ -292,7 +291,7 @@ // parentViews in a stack to avoid contention and using new snackbar managers. mTabListEditorMediator = new TabListEditorMediator( - mActivity, + mContext, mCurrentTabModelFilterSupplier, mTabListCoordinator, resetHandler, @@ -344,7 +343,7 @@ if (displayGroups) { mMultiThumbnailCardProvider = new MultiThumbnailCardProvider( - mActivity, + mContext, mBrowserControlsStateProvider, tabContentManager, mCurrentTabModelFilterSupplier);
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListEditorManager.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListEditorManager.java new file mode 100644 index 0000000..bbbf0d6dc --- /dev/null +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListEditorManager.java
@@ -0,0 +1,177 @@ +// 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. + +package org.chromium.chrome.browser.tasks.tab_management; + +import android.app.Activity; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import org.chromium.base.supplier.ObservableSupplier; +import org.chromium.base.supplier.ObservableSupplierImpl; +import org.chromium.base.supplier.Supplier; +import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider; +import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager; +import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.tabmodel.TabList; +import org.chromium.chrome.browser.tabmodel.TabModel; +import org.chromium.chrome.browser.tabmodel.TabModelFilter; +import org.chromium.chrome.browser.tasks.tab_management.TabListCoordinator.TabListMode; +import org.chromium.chrome.browser.tasks.tab_management.TabListEditorAction.ButtonType; +import org.chromium.chrome.browser.tasks.tab_management.TabListEditorAction.IconPosition; +import org.chromium.chrome.browser.tasks.tab_management.TabListEditorAction.ShowMode; +import org.chromium.chrome.browser.tasks.tab_management.TabListEditorCoordinator.TabListEditorController; +import org.chromium.chrome.browser.tasks.tab_management.TabListEditorCoordinator.TabListEditorNavigationProvider; +import org.chromium.chrome.browser.tasks.tab_management.TabUiMetricsHelper.TabListEditorOpenMetricGroups; +import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager; + +import java.util.ArrayList; +import java.util.List; + +/** + * Manages the {@link TabListEditorCoordinator} and related components for a {@link TabSwitcher}. + */ +public class TabListEditorManager { + private final @NonNull Activity mActivity; + private final @NonNull ViewGroup mCoordinatorView; + private final @NonNull ViewGroup mRootView; + private final @NonNull SnackbarManager mSnackbarManager; + private final @NonNull BrowserControlsStateProvider mBrowserControlsStateProvider; + private final @NonNull ObservableSupplier<TabModelFilter> mCurrentTabModelFilterSupplier; + private final @NonNull Supplier<TabModel> mRegularTabModelSupplier; + private final @NonNull TabContentManager mTabContentManager; + private final @NonNull TabListCoordinator mTabListCoordinator; + private final @TabListMode int mMode; + private final @NonNull ObservableSupplierImpl<TabListEditorController> mControllerSupplier = + new ObservableSupplierImpl<>(); + + private @Nullable TabListEditorCoordinator mTabListEditorCoordinator; + private @Nullable List<TabListEditorAction> mTabListEditorActions; + + /** + * @param activity The current activity. + * @param coordinatorView The overlay view to attach the editor to. + * @param rootView The root view to attach the snackbar to. + * @param browserControlsStateProvider The browser controls state provider. + * @param currentTabModelFilterSupplier The supplier of the current {@link TabModelFilter}. + * @param regularTabModelSupplier The supplier of the regular {@link TabModel}. + * @param tabContentManager The {@link TabContentManager} for thumbnails. + * @param tabListCoordinator The parent {@link TabListCoordinator}. + * @param mode The {@link TabListMode} of the tab list (grid, list, etc.). + */ + public TabListEditorManager( + @NonNull Activity activity, + @NonNull ViewGroup coordinatorView, + @NonNull ViewGroup rootView, + @NonNull BrowserControlsStateProvider browserControlsStateProvider, + @NonNull ObservableSupplier<TabModelFilter> currentTabModelFilterSupplier, + @NonNull Supplier<TabModel> regularTabModelSupplier, + @NonNull TabContentManager tabContentManager, + @NonNull TabListCoordinator tabListCoordinator, + @TabListMode int mode) { + mActivity = activity; + mCoordinatorView = coordinatorView; + mRootView = rootView; + mCurrentTabModelFilterSupplier = currentTabModelFilterSupplier; + mRegularTabModelSupplier = regularTabModelSupplier; + mBrowserControlsStateProvider = browserControlsStateProvider; + mTabContentManager = tabContentManager; + mTabListCoordinator = tabListCoordinator; + mMode = mode; + + // The snackbarManager used by mTabListEditorCoordinator. The rootView is the default + // default parent view of the snackbar. When shown this will be re-parented inside the + // TabListCoordinator's SelectableListLayout. + mSnackbarManager = new SnackbarManager(activity, rootView, null); + } + + /** Destroys the tab list editor. */ + public void destroy() { + if (mTabListEditorCoordinator != null) { + mTabListEditorCoordinator.destroy(); + } + } + + /** Initializes the tab list editor. */ + public void initTabListEditor() { + // TODO(crbug.com/1504606): Permit a method of switching between selectable and closable + // modes (or create separate instances). + if (mTabListEditorCoordinator == null) { + mTabListEditorCoordinator = + new TabListEditorCoordinator( + mActivity, + mCoordinatorView, + mBrowserControlsStateProvider, + mCurrentTabModelFilterSupplier, + mRegularTabModelSupplier, + mTabContentManager, + mTabListCoordinator::setRecyclerViewPosition, + mMode, + mRootView, + /* displayGroups= */ true, + mSnackbarManager, + TabProperties.UiType.SELECTABLE); + mControllerSupplier.set(mTabListEditorCoordinator.getController()); + } + } + + /** Shows the tab list editor with the default list of actions. */ + public void showTabListEditor() { + initTabListEditor(); + if (mTabListEditorActions == null) { + mTabListEditorActions = new ArrayList<>(); + mTabListEditorActions.add( + TabListEditorSelectionAction.createAction( + mActivity, + ShowMode.MENU_ONLY, + ButtonType.ICON_AND_TEXT, + IconPosition.END)); + mTabListEditorActions.add( + TabListEditorCloseAction.createAction( + mActivity, + ShowMode.MENU_ONLY, + ButtonType.ICON_AND_TEXT, + IconPosition.START)); + mTabListEditorActions.add( + TabListEditorGroupAction.createAction( + mActivity, + ShowMode.MENU_ONLY, + ButtonType.ICON_AND_TEXT, + IconPosition.START)); + mTabListEditorActions.add( + TabListEditorBookmarkAction.createAction( + mActivity, + ShowMode.MENU_ONLY, + ButtonType.ICON_AND_TEXT, + IconPosition.START)); + mTabListEditorActions.add( + TabListEditorShareAction.createAction( + mActivity, + ShowMode.MENU_ONLY, + ButtonType.ICON_AND_TEXT, + IconPosition.START)); + } + + var controller = mControllerSupplier.get(); + controller.configureToolbarWithMenuItems( + mTabListEditorActions, new TabListEditorNavigationProvider(mActivity, controller)); + + List<Tab> tabs = new ArrayList<>(); + TabList list = mCurrentTabModelFilterSupplier.get(); + for (int i = 0; i < list.getCount(); i++) { + tabs.add(list.getTabAt(i)); + } + controller.show( + tabs, /* preSelectedTabCount= */ 0, mTabListCoordinator.getRecyclerViewPosition()); + TabUiMetricsHelper.recordSelectionEditorOpenMetrics( + TabListEditorOpenMetricGroups.OPEN_FROM_GRID, mActivity); + } + + /** Returns a supplier for {@link TabListEditorController}. */ + public ObservableSupplier<TabListEditorController> getControllerSupplier() { + return mControllerSupplier; + } +}
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegate.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegate.java index bc399ff..e2c6398 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegate.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegate.java
@@ -27,9 +27,7 @@ import org.chromium.chrome.browser.multiwindow.MultiWindowModeStateDispatcher; import org.chromium.chrome.browser.tabmodel.IncognitoStateProvider; import org.chromium.chrome.browser.tabmodel.TabCreatorManager; -import org.chromium.chrome.browser.tabmodel.TabModel; import org.chromium.chrome.browser.tabmodel.TabModelSelector; -import org.chromium.chrome.browser.tasks.tab_management.suggestions.TabSuggestions; import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; import org.chromium.components.browser_ui.widget.MenuOrKeyboardActionController; @@ -159,16 +157,4 @@ @NonNull TabCreatorManager tabCreatorManager, @NonNull OneshotSupplier<LayoutStateProvider> layoutStateProviderSupplier, @NonNull SnackbarManager snackbarManager); - - /** - * Create a {@link TabSuggestions} for the given {@link Activity} - * @param context The activity context. - * @param tabModelSelector Allows access to the current set of {@link TabModel}. - * @param activityLifecycleDispatcher Allows observation of the activity lifecycle. - * @return the {@link TabSuggestions} for the activity - */ - TabSuggestions createTabSuggestions( - @NonNull Context context, - @NonNull TabModelSelector tabModelSelector, - @NonNull ActivityLifecycleDispatcher activityLifecycleDispatcher); }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegateImpl.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegateImpl.java index 2c28838..bc69a11 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegateImpl.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegateImpl.java
@@ -27,8 +27,6 @@ import org.chromium.chrome.browser.tabmodel.IncognitoStateProvider; import org.chromium.chrome.browser.tabmodel.TabCreatorManager; import org.chromium.chrome.browser.tabmodel.TabModelSelector; -import org.chromium.chrome.browser.tasks.tab_management.suggestions.TabSuggestions; -import org.chromium.chrome.browser.tasks.tab_management.suggestions.TabSuggestionsOrchestrator; import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; import org.chromium.components.browser_ui.widget.MenuOrKeyboardActionController; @@ -137,13 +135,4 @@ layoutStateProviderSupplier, snackbarManager); } - - @Override - public TabSuggestions createTabSuggestions( - @NonNull Context context, - @NonNull TabModelSelector tabModelSelector, - @NonNull ActivityLifecycleDispatcher activityLifecycleDispatcher) { - return new TabSuggestionsOrchestrator( - context, tabModelSelector, activityLifecycleDispatcher); - } }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSuggestionMessageService.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSuggestionMessageService.java index 77a79a3..ea928ce4 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSuggestionMessageService.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSuggestionMessageService.java
@@ -19,8 +19,9 @@ import org.chromium.base.supplier.Supplier; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.tabmodel.TabModel; import org.chromium.chrome.browser.tabmodel.TabModelFilter; -import org.chromium.chrome.browser.tabmodel.TabModelSelector; +import org.chromium.chrome.browser.tabmodel.TabModelUtils; import org.chromium.chrome.browser.tasks.tab_management.suggestions.TabContext; import org.chromium.chrome.browser.tasks.tab_management.suggestions.TabSuggestion; import org.chromium.chrome.browser.tasks.tab_management.suggestions.TabSuggestionFeedback; @@ -115,7 +116,7 @@ } private final Context mContext; - private final TabModelSelector mTabModelSelector; + private final Supplier<TabModelFilter> mCurrentTabModelFilterSupplier; private final Supplier<TabListEditorCoordinator.TabListEditorController> mTabListEditorControllerSupplier; private final CustomMessageCardProvider mCustomMessageCardProvider; @@ -123,25 +124,25 @@ public TabSuggestionMessageService( Context context, - TabModelSelector tabModelSelector, + Supplier<TabModelFilter> currentTabModelFilterSupplier, Supplier<TabListEditorCoordinator.TabListEditorController> tabListEditorControllerSupplier) { this( context, - tabModelSelector, + currentTabModelFilterSupplier, tabListEditorControllerSupplier, LayoutInflater.from(context).inflate(R.layout.declutter_message_card_layout, null)); } protected TabSuggestionMessageService( Context context, - TabModelSelector tabModelSelector, + Supplier<TabModelFilter> currentTabModelFilterSupplier, Supplier<TabListEditorCoordinator.TabListEditorController> tabListEditorControllerSupplier, View customCardView) { super(MessageType.TAB_SUGGESTION); mContext = context; - mTabModelSelector = tabModelSelector; + mCurrentTabModelFilterSupplier = currentTabModelFilterSupplier; mTabListEditorControllerSupplier = tabListEditorControllerSupplier; mCustomMessageCardProvider = this; mCustomCardView = customCardView; @@ -188,7 +189,7 @@ @Override public void preProcessSelectedTabs(List<Tab> selectedTabs) { int totalTabCountBeforeProcess = - mTabModelSelector.getCurrentModel().getCount(); + mCurrentTabModelFilterSupplier.get().getTabModel().getCount(); List<Integer> selectedTabIds = new ArrayList<>(); for (int i = 0; i < selectedTabs.size(); i++) { selectedTabIds.add(selectedTabs.get(i).getId()); @@ -224,9 +225,14 @@ Set<Integer> suggestedTabIds = new HashSet<>(); List<TabContext.TabInfo> suggestedTabInfo = tabSuggestion.getTabsInfo(); + TabModel model = mCurrentTabModelFilterSupplier.get().getTabModel(); for (int i = 0; i < suggestedTabInfo.size(); i++) { - suggestedTabIds.add(suggestedTabInfo.get(i).id); - tabs.add(mTabModelSelector.getTabById(suggestedTabInfo.get(i).id)); + int tabId = suggestedTabInfo.get(i).id; + Tab tab = TabModelUtils.getTabById(model, tabId); + if (tab == null) continue; + + suggestedTabIds.add(tabId); + tabs.add(tab); } tabs.addAll(getNonSuggestedTabs(suggestedTabIds)); @@ -235,9 +241,8 @@ private List<Tab> getNonSuggestedTabs(Set<Integer> suggestedTabIds) { List<Tab> tabs = new ArrayList<>(); - TabModelFilter tabModelFilter = - mTabModelSelector.getTabModelFilterProvider().getCurrentTabModelFilter(); - List<Tab> filteredTab = tabModelFilter.getTabsWithNoOtherRelatedTabs(); + List<Tab> filteredTab = + mCurrentTabModelFilterSupplier.get().getTabsWithNoOtherRelatedTabs(); for (int i = 0; i < filteredTab.size(); i++) { Tab tab = filteredTab.get(i); @@ -278,7 +283,7 @@ new TabSuggestionMessageData( tabSuggestion, tabSuggestionFeedback, - mTabModelSelector.getModel(false).getProfile(), + Profile.getLastUsedRegularProfile(), mCustomMessageCardProvider)); } }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java index f7d5a98f5..3a2e3fb 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java
@@ -45,7 +45,6 @@ import org.chromium.chrome.browser.price_tracking.PriceTrackingUtilities; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.profiles.ProfileManager; -import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tabmodel.TabCreatorManager; import org.chromium.chrome.browser.tabmodel.TabList; import org.chromium.chrome.browser.tabmodel.TabModelSelector; @@ -54,11 +53,6 @@ import org.chromium.chrome.browser.tasks.pseudotab.TabAttributeCache; import org.chromium.chrome.browser.tasks.tab_management.PriceMessageService.PriceMessageType; import org.chromium.chrome.browser.tasks.tab_management.TabListCoordinator.TabListMode; -import org.chromium.chrome.browser.tasks.tab_management.TabListEditorAction.ButtonType; -import org.chromium.chrome.browser.tasks.tab_management.TabListEditorAction.IconPosition; -import org.chromium.chrome.browser.tasks.tab_management.TabListEditorAction.ShowMode; -import org.chromium.chrome.browser.tasks.tab_management.TabListEditorCoordinator.TabListEditorNavigationProvider; -import org.chromium.chrome.browser.tasks.tab_management.TabUiMetricsHelper.TabListEditorOpenMetricGroups; import org.chromium.chrome.browser.tasks.tab_management.suggestions.TabSuggestionsOrchestrator; import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager; import org.chromium.chrome.tab_ui.R; @@ -72,7 +66,6 @@ import org.chromium.ui.modelutil.PropertyModelChangeProcessor; import org.chromium.ui.resources.dynamics.DynamicResourceLoader; -import java.util.ArrayList; import java.util.List; /** @@ -114,8 +107,7 @@ private final Supplier<DynamicResourceLoader> mDynamicResourceLoaderSupplier; private final SnackbarManager mSnackbarManager; private final ModalDialogManager mModalDialogManager; - @Nullable private TabListEditorCoordinator mTabListEditorCoordinator; - @Nullable private List<TabListEditorAction> mTabListEditorActions; + private final TabListEditorManager mTabListEditorManager; private TabSuggestionsOrchestrator mTabSuggestionsOrchestrator; private TabSuggestionMessageService mTabSuggestionMessageService; private TabAttributeCache mTabAttributeCache; @@ -139,7 +131,6 @@ mTabSwitcherMenuActionHandler; private TabGridIphDialogCoordinator mTabGridIphDialogCoordinator; private TabSwitcherCustomViewManager mTabSwitcherCustomViewManager; - private SnackbarManager mTabListEditorSnackbarManager; /** {@see TabManagementDelegate#createCarouselTabSwitcher} */ // Suppress to observe SharedPreferences, which is discouraged; use another messaging channel @@ -180,11 +171,6 @@ mSnackbarManager = snackbarManager; mModalDialogManager = modalDialogManager; - // The snackbarManager for the TabListEditor from the tab switcher side, with the - // rootView as the default parentView. The parentView will be re-parented on show, - // inside the selection editor mediator using its layout. - mTabListEditorSnackbarManager = new SnackbarManager(activity, mRootView, null); - PropertyModel containerViewModel = new PropertyModel.Builder(TabListContainerProperties.ALL_KEYS) .with( @@ -277,6 +263,7 @@ emptySubheadingStringResId); mTabListCoordinator.setOnLongPressTabItemEventListener(this); + mContainerViewChangeProcessor = PropertyModelChangeProcessor.create( containerViewModel, @@ -287,6 +274,20 @@ "Android.TabSwitcher.SetupRecyclerView.Time", SystemClock.uptimeMillis() - startTimeMs); + mTabListEditorManager = + new TabListEditorManager( + activity, + mCoordinatorView, + rootView, + browserControls, + currentTabModelFilterSupplier, + () -> mTabModelSelector.getModel(false), + tabContentManager, + mTabListCoordinator, + mode); + mMediator.setTabListEditorControllerSupplier( + mTabListEditorManager.getControllerSupplier()); + mMessageCardProviderCoordinator = new MessageCardProviderCoordinator( activity, @@ -362,7 +363,7 @@ @Override public boolean handleMenuOrKeyboardAction(int id, boolean fromMenu) { if (id == R.id.menu_select_tabs) { - showTabListEditor(); + mTabListEditorManager.showTabListEditor(); RecordUserAction.record("MobileMenuSelectTabs"); return true; } @@ -445,16 +446,23 @@ if (mMode == TabListCoordinator.TabListMode.GRID) { if (ChromeFeatureList.sArchiveTabService.isEnabled()) { + var currentTabModelFilterSupplier = + mTabModelSelector + .getTabModelFilterProvider() + .getCurrentTabModelFilterSupplier(); mTabSuggestionsOrchestrator = new TabSuggestionsOrchestrator( - mActivity, mTabModelSelector, mLifecycleDispatcher); + mActivity, currentTabModelFilterSupplier); mTabSuggestionMessageService = new TabSuggestionMessageService( mActivity, - mTabModelSelector, + currentTabModelFilterSupplier, () -> { - initTabListEditor(/* isItemTypeSelectable= */ false); - return mTabListEditorCoordinator.getController(); + // TODO(crbug/1504606): Migrate to a separate manager + // instance that uses closable tabs and make this method + // private. + mTabListEditorManager.initTabListEditor(); + return mTabListEditorManager.getControllerSupplier().get(); }); mTabSuggestionsOrchestrator.addObserver(mTabSuggestionMessageService); mMessageCardProviderCoordinator.subscribeMessageService( @@ -497,97 +505,6 @@ } } - private void initTabListEditor(boolean isItemTypeSelectable) { - // TODO(crbug.com/1504606): Ensure the lifecycle of the mTabListEditorCoordinator is - // properly destroyed between the closable and selectable variations that lazily instantiate - // it. - if (mTabListEditorCoordinator == null) { - int selectionEditorItemType = - isItemTypeSelectable - ? TabProperties.UiType.SELECTABLE - : TabProperties.UiType.CLOSABLE; - var currentTabModelFilterSupplier = - mTabModelSelector - .getTabModelFilterProvider() - .getCurrentTabModelFilterSupplier(); - mTabListEditorCoordinator = - new TabListEditorCoordinator( - mActivity, - mCoordinatorView, - mBrowserControlsStateProvider, - currentTabModelFilterSupplier, - () -> mTabModelSelector.getModel(false), - mTabContentManager, - mTabListCoordinator::setRecyclerViewPosition, - mMode, - mRootView, - /* displayGroups= */ true, - mTabListEditorSnackbarManager, - selectionEditorItemType); - mMediator.setTabListEditorController(mTabListEditorCoordinator.getController()); - } - } - - private void showTabListEditor() { - // Lazy initialize if required. - initTabListEditor(/* isItemTypeSelectable= */ true); - - if (mTabListEditorActions == null) { - mTabListEditorActions = new ArrayList<>(); - mTabListEditorActions.add( - TabListEditorSelectionAction.createAction( - mActivity, - ShowMode.MENU_ONLY, - ButtonType.ICON_AND_TEXT, - IconPosition.END)); - mTabListEditorActions.add( - TabListEditorCloseAction.createAction( - mActivity, - ShowMode.MENU_ONLY, - ButtonType.ICON_AND_TEXT, - IconPosition.START)); - mTabListEditorActions.add( - TabListEditorGroupAction.createAction( - mActivity, - ShowMode.MENU_ONLY, - ButtonType.ICON_AND_TEXT, - IconPosition.START)); - mTabListEditorActions.add( - TabListEditorBookmarkAction.createAction( - mActivity, - ShowMode.MENU_ONLY, - ButtonType.ICON_AND_TEXT, - IconPosition.START)); - mTabListEditorActions.add( - TabListEditorShareAction.createAction( - mActivity, - ShowMode.MENU_ONLY, - ButtonType.ICON_AND_TEXT, - IconPosition.START)); - } - - mTabListEditorCoordinator - .getController() - .configureToolbarWithMenuItems( - mTabListEditorActions, - new TabListEditorNavigationProvider( - mActivity, mTabListEditorCoordinator.getController())); - - List<Tab> tabs = new ArrayList<>(); - TabList list = mTabModelSelector.getTabModelFilterProvider().getCurrentTabModelFilter(); - for (int i = 0; i < list.getCount(); i++) { - tabs.add(list.getTabAt(i)); - } - mTabListEditorCoordinator - .getController() - .show( - tabs, - /* preSelectedTabCount= */ 0, - mTabListCoordinator.getRecyclerViewPosition()); - TabUiMetricsHelper.recordSelectionEditorOpenMetrics( - TabListEditorOpenMetricGroups.OPEN_FROM_GRID, mActivity); - } - private void setUpPriceTracking(Context context, ModalDialogManager modalDialogManager) { if (PriceTrackingFeatures.isPriceTrackingEnabled(Profile.getLastUsedRegularProfile())) { PriceDropNotificationManager notificationManager = @@ -831,7 +748,7 @@ // OnLongPressTabItemEventListener implementation @Override public void onLongPressEvent(int tabId) { - showTabListEditor(); + mTabListEditorManager.showTabListEditor(); RecordUserAction.record("TabMultiSelectV2.OpenLongPressInGrid"); } @@ -962,9 +879,7 @@ mTabGridIphDialogCoordinator.destroy(); } mMultiThumbnailCardProvider.destroy(); - if (mTabListEditorCoordinator != null) { - mTabListEditorCoordinator.destroy(); - } + mTabListEditorManager.destroy(); mMediator.destroy(); mLifecycleDispatcher.unregister(this); if (mTabAttributeCache != null) {
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediator.java index 0953fb5..80497aa3 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediator.java
@@ -38,6 +38,7 @@ import org.chromium.base.supplier.ObservableSupplier; import org.chromium.base.supplier.ObservableSupplierImpl; import org.chromium.base.supplier.OneshotSupplier; +import org.chromium.base.supplier.TransitiveObservableSupplier; import org.chromium.chrome.browser.back_press.BackPressManager; import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider; import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager; @@ -64,6 +65,7 @@ import org.chromium.chrome.browser.tasks.ReturnToChromeUtil; import org.chromium.chrome.browser.tasks.pseudotab.PseudoTab; import org.chromium.chrome.browser.tasks.tab_management.TabListCoordinator.TabListMode; +import org.chromium.chrome.browser.tasks.tab_management.TabListEditorCoordinator.TabListEditorController; import org.chromium.chrome.browser.tasks.tab_management.TabManagementDelegate.TabSwitcherType; import org.chromium.chrome.browser.tasks.tab_management.TabSwitcher.TabSwitcherViewObserver; import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager; @@ -153,7 +155,9 @@ }; private CallbackController mCallbackController; - private TabListEditorCoordinator.TabListEditorController mTabListEditorController; + private @Nullable ObservableSupplier<TabListEditorController> mTabListEditorControllerSupplier; + private @Nullable TransitiveObservableSupplier<TabListEditorController, Boolean> + mCurrentTabListEditorControllerBackSupplier; private TabSwitcher.OnTabSelectingListener mOnTabSelectingListener; private PriceMessageService mPriceMessageService; @@ -590,18 +594,21 @@ } /** - * Initialization of the {@link TabListEditorCoordinator}. - * - * @param controller the controller to use. + * @param tabListEditorControllerSupplier The supllier for the controller of the tab list + * editor. */ - public void setTabListEditorController( - @Nullable TabListEditorCoordinator.TabListEditorController tabListEditorController) { - if (tabListEditorController != null) { - mTabListEditorController = tabListEditorController; - mTabListEditorController - .getHandleBackPressChangedSupplier() - .addObserver(mNotifyBackPressedCallback); - } + public void setTabListEditorControllerSupplier( + @NonNull ObservableSupplier<TabListEditorController> tabListEditorControllerSupplier) { + assert mTabListEditorControllerSupplier == null + : "setTabListEditorControllerSupplier should be called only once."; + mTabListEditorControllerSupplier = tabListEditorControllerSupplier; + mCurrentTabListEditorControllerBackSupplier = + new TransitiveObservableSupplier<>( + tabListEditorControllerSupplier, + tabListEditorController -> { + return tabListEditorController.getHandleBackPressChangedSupplier(); + }); + mCurrentTabListEditorControllerBackSupplier.addObserver(mNotifyBackPressedCallback); } private void setVisibility(boolean isVisible) { @@ -881,7 +888,8 @@ private boolean onBackPressedInternal() { // The TabListEditor dialog can be shown on the Start surface without showing the Grid // Tab switcher, so skip the check of visibility of mContainerViewModel here. - if (mTabListEditorController != null && mTabListEditorController.handleBackPressed()) { + TabListEditorController editorController = getTabListEditorController(); + if (editorController != null && editorController.handleBackPressed()) { return true; } @@ -937,7 +945,8 @@ @Override public boolean isDialogVisible() { - if (mTabListEditorController != null && mTabListEditorController.isVisible()) { + TabListEditorController editorController = getTabListEditorController(); + if (editorController != null && editorController.isVisible()) { return true; } @@ -1068,10 +1077,8 @@ /** Destroy any members that needs clean up. */ public void destroy() { - if (mTabListEditorController != null) { - mTabListEditorController - .getHandleBackPressChangedSupplier() - .removeObserver(mNotifyBackPressedCallback); + if (mCurrentTabListEditorControllerBackSupplier != null) { + mCurrentTabListEditorControllerBackSupplier.removeObserver(mNotifyBackPressedCallback); } if (mTabGridDialogControllerSupplier.hasValue()) { @@ -1250,4 +1257,10 @@ public void setLastActiveLayoutTypeForTesting(@LayoutType int lastActiveLayoutType) { mLastActiveLayoutType = lastActiveLayoutType; } + + private TabListEditorController getTabListEditorController() { + return mTabListEditorControllerSupplier == null + ? null + : mTabListEditorControllerSupplier.get(); + } }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabContext.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabContext.java index bc200c64..17ff0d6 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabContext.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabContext.java
@@ -6,10 +6,11 @@ import android.text.TextUtils; +import androidx.annotation.Nullable; + import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tabmodel.TabModelFilter; -import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.components.site_engagement.SiteEngagementService; import java.util.ArrayList; @@ -173,19 +174,19 @@ } /** - * Creates an instance of TabContext based on the provided {@link TabModelSelector}. - * @param tabModelSelector TabModelSelector for which the TabContext will be derived + * Creates an instance of TabContext based on the provided {@link TabModelFilter}. + * + * @param tabModelFilter The TabModelFilter for which the TabContext will be derived * @return an instance of TabContext */ - public static TabContext createCurrentContext(TabModelSelector tabModelSelector) { - TabModelFilter tabModelFilter = - tabModelSelector.getTabModelFilterProvider().getCurrentTabModelFilter(); + public static TabContext createCurrentContext(@Nullable TabModelFilter tabModelFilter) { List<TabInfo> ungroupedTabs = new ArrayList<>(); List<TabGroupInfo> existingGroups = new ArrayList<>(); // Examine each tab in the current model and either add it to the list of ungrouped tabs or // add it to a group it belongs to. - for (int i = 0; i < tabModelFilter.getCount(); i++) { + int count = tabModelFilter == null ? 0 : tabModelFilter.getCount(); + for (int i = 0; i < count; i++) { Tab currentTab = tabModelFilter.getTabAt(i); assert currentTab != null : "currentTab should not be null";
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionsOrchestrator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionsOrchestrator.java index 291ecc8..a63d790 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionsOrchestrator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionsOrchestrator.java
@@ -17,10 +17,9 @@ import org.chromium.base.ResettersForTesting; import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.metrics.RecordUserAction; +import org.chromium.base.supplier.Supplier; import org.chromium.chrome.browser.flags.ChromeFeatureList; -import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; -import org.chromium.chrome.browser.lifecycle.DestroyObserver; -import org.chromium.chrome.browser.tabmodel.TabModelSelector; +import org.chromium.chrome.browser.tabmodel.TabModelFilter; import org.chromium.chrome.browser.tasks.tab_management.suggestions.TabSuggestion.TabSuggestionAction; import java.util.Collections; @@ -31,10 +30,10 @@ import java.util.concurrent.TimeUnit; /** - * Represents the entry point for the TabSuggestions component. Responsible for - * registering and invoking the different {@link TabSuggestionsFetcher}. + * Represents the entry point for the TabSuggestions component. Responsible for registering and + * invoking the different {@link TabSuggestionsFetcher}. */ -public class TabSuggestionsOrchestrator implements TabSuggestions, DestroyObserver { +public class TabSuggestionsOrchestrator implements TabSuggestions { public static final String TAB_SUGGESTIONS_UMA_PREFIX = "TabSuggestionsOrchestrator"; private static final String LAST_TIMESTAMP_KEY = "LastTimestamp"; private static final String BACKOFF_COUNT_KEY = "BackoffCountKey"; @@ -57,25 +56,21 @@ private static final int MIN_TIME_BETWEEN_PREFETCHES_DEFAULT_MS = 30000; protected TabSuggestionFeedback mTabSuggestionFeedback; - private final ActivityLifecycleDispatcher mActivityLifecycleDispatcher; private final SharedPreferences mSharedPreferences; private List<TabSuggestionsFetcher> mTabSuggestionsFetchers; private List<TabSuggestion> mPrefetchedResults = new LinkedList<>(); private TabContext mPrefetchedTabContext; - private TabModelSelector mTabModelSelector; + private Supplier<TabModelFilter> mCurrentTabModelFilterSupplier; private ObserverList<TabSuggestionsObserver> mTabSuggestionsObservers; private int mRemainingFetchers; private long mNextPrefetchTime; private int mMinTimeBetweenPrefetchesMs = MIN_TIME_BETWEEN_PREFETCHES_DEFAULT_MS; public TabSuggestionsOrchestrator( - Context context, - TabModelSelector selector, - ActivityLifecycleDispatcher activityLifecycleDispatcher) { + Context context, Supplier<TabModelFilter> currentTabModelFilterSupplier) { this( context, - selector, - activityLifecycleDispatcher, + currentTabModelFilterSupplier, ContextUtils.getApplicationContext() .getSharedPreferences(SHARED_PREFERENCES_ID, Context.MODE_PRIVATE)); } @@ -83,15 +78,12 @@ @VisibleForTesting TabSuggestionsOrchestrator( Context context, - TabModelSelector selector, - ActivityLifecycleDispatcher activityLifecycleDispatcher, + Supplier<TabModelFilter> currentTabModelFilterSupplier, SharedPreferences sharedPreferences) { - mTabModelSelector = selector; + mCurrentTabModelFilterSupplier = currentTabModelFilterSupplier; mTabSuggestionsFetchers = new LinkedList<>(); mTabSuggestionsFetchers.add(new TabSuggestionsClientFetcher()); mTabSuggestionsObservers = new ObserverList<>(); - mActivityLifecycleDispatcher = activityLifecycleDispatcher; - activityLifecycleDispatcher.register(this); mSharedPreferences = sharedPreferences; } @@ -122,11 +114,6 @@ return aggregated; } - @Override - public void onDestroy() { - mActivityLifecycleDispatcher.unregister(this); - } - /** * Acquire suggestions and store so suggestions are available for the UI * thread on demand. @@ -150,7 +137,8 @@ @VisibleForTesting protected void performPrefetch() { - TabContext tabContext = TabContext.createCurrentContext(mTabModelSelector); + TabContext tabContext = + TabContext.createCurrentContext(mCurrentTabModelFilterSupplier.get()); synchronized (mPrefetchedResults) { mRemainingFetchers = 0; mPrefetchedTabContext = tabContext;
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherTabletTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherTabletTest.java index 5a55a1a..9b03d369 100644 --- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherTabletTest.java +++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherTabletTest.java
@@ -507,13 +507,26 @@ } private void retrieveTabListDelegate() { - Layout layout = sActivityTestRule.getActivity().getLayoutManager().getOverviewLayout(); - assertTrue(layout instanceof TabSwitcherAndStartSurfaceLayout); - TabSwitcherAndStartSurfaceLayout mTabSwitcherAndStartSurfaceLayout = - (TabSwitcherAndStartSurfaceLayout) layout; + Layout overviewLayout = + sActivityTestRule.getActivity().getLayoutManager().getOverviewLayout(); + + if (overviewLayout == null) { + Layout tabSwitcherLayout = + sActivityTestRule.getActivity().getLayoutManager().getTabSwitcherLayoutForTesting(); + assertTrue("Layout not instance of TabSwitcherLayout -" + tabSwitcherLayout, + tabSwitcherLayout instanceof TabSwitcherLayout); + mTabListDelegate = + ((TabSwitcherLayout) tabSwitcherLayout) + .getTabSwitcherForTesting() + .getTabListDelegate(); + return; + } + + assertTrue("Layout not instance of TabSwitcherAndStartSurfaceLayout" + overviewLayout, + overviewLayout instanceof TabSwitcherAndStartSurfaceLayout); mTabListDelegate = - mTabSwitcherAndStartSurfaceLayout + ((TabSwitcherAndStartSurfaceLayout) overviewLayout) .getStartSurfaceForTesting() .getGridTabListDelegate(); }
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabThumbnailViewRenderTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabThumbnailViewRenderTest.java index 54b0351..f10206e 100644 --- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabThumbnailViewRenderTest.java +++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabThumbnailViewRenderTest.java
@@ -63,7 +63,7 @@ public final ChromeRenderTestRule mRenderTestRule = ChromeRenderTestRule.Builder.withPublicCorpus() .setBugComponent(RenderTestRule.Component.UI_BROWSER_MOBILE_TAB_SWITCHER_GRID) - .setRevision(3) + .setRevision(4) .build(); @Rule
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java index 58e52ca..f63f2bca5 100644 --- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java +++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java
@@ -21,7 +21,6 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.contains; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; @@ -92,9 +91,6 @@ import org.chromium.base.test.util.JniMocker; import org.chromium.build.BuildConfig; import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager; -import org.chromium.chrome.browser.endpoint_fetcher.EndpointFetcher; -import org.chromium.chrome.browser.endpoint_fetcher.EndpointFetcherJni; -import org.chromium.chrome.browser.endpoint_fetcher.EndpointResponse; import org.chromium.chrome.browser.feature_engagement.TrackerFactory; import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.optimization_guide.OptimizationGuideBridge; @@ -271,7 +267,6 @@ ArgumentCaptor<TemplateUrlService.TemplateUrlServiceObserver> mTemplateUrlServiceObserver; @Captor ArgumentCaptor<RecyclerView.OnScrollListener> mOnScrollListenerCaptor; - @Mock EndpointFetcher.Natives mEndpointFetcherJniMock; @Mock private Resources mResources; private final ObservableSupplierImpl<TabModelFilter> mCurrentTabModelFilterSupplier = @@ -302,7 +297,6 @@ public void setUp() { MockitoAnnotations.initMocks(this); mMocker.mock(UrlUtilitiesJni.TEST_HOOKS, mUrlUtilitiesJniMock); - mMocker.mock(EndpointFetcherJni.TEST_HOOKS, mEndpointFetcherJniMock); mMocker.mock(OptimizationGuideBridgeJni.TEST_HOOKS, mOptimizationGuideBridgeJniMock); // Ensure native pointer is initialized doReturn(1L).when(mOptimizationGuideBridgeJniMock).init(); @@ -3251,32 +3245,6 @@ } } - private void mockEndpointResponse(Map<String, String> responses) { - for (Map.Entry<String, String> entry : responses.entrySet()) { - doAnswer( - new Answer<Void>() { - @Override - public Void answer(InvocationOnMock invocation) { - Callback callback = (Callback) invocation.getArguments()[8]; - callback.onResult(new EndpointResponse(entry.getValue())); - return null; - } - }) - .when(mEndpointFetcherJniMock) - .nativeFetchOAuth( - any(Profile.class), - anyString(), - contains(entry.getKey()), - anyString(), - anyString(), - any(String[].class), - anyString(), - anyLong(), - anyInt(), - any(Callback.class)); - } - } - private void mockOptimizationGuideResponse( @OptimizationGuideDecision int decision, Map<GURL, Any> responses) { for (Map.Entry<GURL, Any> responseEntry : responses.entrySet()) {
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabSuggestionMessageServiceUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabSuggestionMessageServiceUnitTest.java index 130f85c..67c5bce 100644 --- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabSuggestionMessageServiceUnitTest.java +++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabSuggestionMessageServiceUnitTest.java
@@ -13,7 +13,6 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; import static org.chromium.chrome.browser.tasks.tab_management.suggestions.TabSuggestionFeedback.TabSuggestionResponse.ACCEPTED; import static org.chromium.chrome.browser.tasks.tab_management.suggestions.TabSuggestionFeedback.TabSuggestionResponse.DISMISSED; @@ -42,8 +41,6 @@ import org.chromium.chrome.browser.profiles.ProfileJni; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tabmodel.TabModel; -import org.chromium.chrome.browser.tabmodel.TabModelFilterProvider; -import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tasks.tab_groups.TabGroupModelFilter; import org.chromium.chrome.browser.tasks.tab_management.TabListEditorAction.ActionDelegate; import org.chromium.chrome.browser.tasks.tab_management.suggestions.TabContext; @@ -81,9 +78,8 @@ @Mock public Profile.Natives mMockProfileNatives; Context mContext; - @Mock TabModelSelector mTabModelSelector; + @Mock Profile mProfile; @Mock TabModel mTabModel; - @Mock TabModelFilterProvider mTabModelFilterProvider; @Mock TabGroupModelFilter mTabGroupModelFilter; @Mock TabListEditorCoordinator.TabListEditorController mTabListEditorController; @Mock Callback<TabSuggestionFeedback> mTabSuggestionFeedbackCallback; @@ -108,12 +104,6 @@ mTab2 = TabUiUnitTestUtils.prepareTab(TAB2_ID, TAB2_ROOT_ID, ""); mTab3 = TabUiUnitTestUtils.prepareTab(TAB3_ID, TAB3_ROOT_ID, ""); - // Set up TabModelSelector. - doReturn(mTabModel).when(mTabModelSelector).getCurrentModel(); - doReturn(mTab1).when(mTabModelSelector).getTabById(TAB1_ID); - doReturn(mTab2).when(mTabModelSelector).getTabById(TAB2_ID); - doReturn(mTab3).when(mTabModelSelector).getTabById(TAB3_ID); - // Set up TabModel. doReturn(3).when(mTabModel).getCount(); doReturn(mTab1).when(mTabModel).getTabAt(POSITION1); @@ -121,8 +111,6 @@ doReturn(mTab3).when(mTabModel).getTabAt(POSITION3); // Set up TabModelFilter. - doReturn(mTabModelFilterProvider).when(mTabModelSelector).getTabModelFilterProvider(); - doReturn(mTabGroupModelFilter).when(mTabModelFilterProvider).getCurrentTabModelFilter(); doReturn(mTabModel).when(mTabGroupModelFilter).getTabModel(); // Set up MessageService.MessageObserver @@ -132,10 +120,12 @@ mMessageService = new TabSuggestionMessageService( mContext, - mTabModelSelector, + () -> mTabGroupModelFilter, () -> mTabListEditorController, mCustomCardView); mMessageService.addObserver(mMessageObserver); + + Profile.setLastUsedProfileForTesting(mProfile); } // Tests for Close suggestions. @@ -165,7 +155,7 @@ TabSuggestion tabSuggestion = prepareTabSuggestion(suggestedTabs, TabSuggestion.TabSuggestionAction.CLOSE); - assertEquals(3, mTabModelSelector.getCurrentModel().getCount()); + assertEquals(3, mTabModel.getCount()); LinkedHashSet<Integer> tabSet = new LinkedHashSet<>(); tabSet.add(TAB1_ID); @@ -243,7 +233,6 @@ TabSuggestion tabSuggestion = prepareTabSuggestion( Arrays.asList(mTab1, mTab2), TabSuggestion.TabSuggestionAction.CLOSE); - when(mTabModelSelector.getModel(false)).thenReturn(mTabModel); mMessageService.onNewSuggestion( Arrays.asList(tabSuggestion), mTabSuggestionFeedbackCallback); inOrder.verify(mMessageObserver).messageReady(anyInt(), any());
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediatorUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediatorUnitTest.java index 70e67aa5..4f1dc01 100644 --- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediatorUnitTest.java +++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediatorUnitTest.java
@@ -9,6 +9,8 @@ import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; @@ -33,6 +35,7 @@ import androidx.test.filters.SmallTest; +import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Rule; @@ -70,6 +73,7 @@ import org.chromium.chrome.browser.tabmodel.TabModelObserver; import org.chromium.chrome.browser.tabmodel.TabModelSelectorImpl; import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver; +import org.chromium.chrome.browser.tasks.tab_management.TabListEditorCoordinator.TabListEditorController; import org.chromium.chrome.browser.tasks.tab_management.TabSwitcher.TabSwitcherViewObserver; import org.chromium.chrome.tab_ui.R; import org.chromium.chrome.test.util.browser.Features; @@ -113,44 +117,48 @@ private LazyOneshotSupplier<TabGridDialogMediator.DialogController> mTabGridDialogControllerSupplier; - @Mock TabSwitcherMediator.ResetHandler mResetHandler; - @Mock Runnable mTabSwitcherVisibilityDelegate; - @Mock TabContentManager mTabContentManager; - @Mock TabModelSelectorImpl mTabModelSelector; - @Mock TabModel mTabModel; - @Mock TabModelFilter mTabModelFilter; - @Mock TabModelFilterProvider mTabModelFilterProvider; - @Mock Context mContext; - @Mock Resources mResources; - @Mock BrowserControlsStateProvider mBrowserControlsStateProvider; - @Mock PropertyObservable.PropertyObserver<PropertyKey> mPropertyObserver; - @Mock TabSwitcherViewObserver mTabSwitcherViewObserver; - @Mock CompositorViewHolder mCompositorViewHolder; - @Mock TabSwitcher.OnTabSelectingListener mOnTabSelectingListener; - @Mock TabGridDialogMediator.DialogController mTabGridDialogController; - @Mock TabSwitcherMediator.MessageItemsController mMessageItemsController; - @Mock TabSwitcherMediator.PriceWelcomeMessageController mPriceWelcomeMessageController; - @Mock MultiWindowModeStateDispatcher mMultiWindowModeStateDispatcher; - @Mock PriceMessageService mPriceMessageService; - @Mock IncognitoReauthController mIncognitoReauthController; - @Mock View mCustomViewMock; + @Mock private TabSwitcherMediator.ResetHandler mResetHandler; + @Mock private Runnable mTabSwitcherVisibilityDelegate; + @Mock private TabContentManager mTabContentManager; + @Mock private TabModelSelectorImpl mTabModelSelector; + @Mock private TabModel mTabModel; + @Mock private TabModelFilter mTabModelFilter; + @Mock private TabModelFilterProvider mTabModelFilterProvider; + @Mock private Context mContext; + @Mock private Resources mResources; + @Mock private BrowserControlsStateProvider mBrowserControlsStateProvider; + @Mock private PropertyObservable.PropertyObserver<PropertyKey> mPropertyObserver; + @Mock private TabSwitcherViewObserver mTabSwitcherViewObserver; + @Mock private CompositorViewHolder mCompositorViewHolder; + @Mock private TabSwitcher.OnTabSelectingListener mOnTabSelectingListener; + @Mock private TabGridDialogMediator.DialogController mTabGridDialogController; + @Mock private TabSwitcherMediator.MessageItemsController mMessageItemsController; + @Mock private TabSwitcherMediator.PriceWelcomeMessageController mPriceWelcomeMessageController; + @Mock private MultiWindowModeStateDispatcher mMultiWindowModeStateDispatcher; + @Mock private PriceMessageService mPriceMessageService; + @Mock private IncognitoReauthController mIncognitoReauthController; + @Mock private View mCustomViewMock; + @Mock private TabListEditorController mEditorController; - @Captor ArgumentCaptor<TabModelObserver> mTabModelObserverCaptor; - @Captor ArgumentCaptor<TabModelSelectorObserver> mTabModelSelectorObserverCaptor; + @Captor private ArgumentCaptor<TabModelObserver> mTabModelObserverCaptor; + @Captor private ArgumentCaptor<TabModelSelectorObserver> mTabModelSelectorObserverCaptor; @Captor private ArgumentCaptor<BrowserControlsStateProvider.Observer> mBrowserControlsStateProviderObserverCaptor; @Captor - ArgumentCaptor<MultiWindowModeStateDispatcher.MultiWindowModeObserver> + private ArgumentCaptor<MultiWindowModeStateDispatcher.MultiWindowModeObserver> mMultiWindowModeObserverCaptor; @Captor private ArgumentCaptor<IncognitoReauthManager.IncognitoReauthCallback> mIncognitoReauthCallbackArgumentCaptor; - @Mock private TabListEditorCoordinator.TabListEditorController mEditorController; + private final ObservableSupplierImpl<Boolean> mEditorControllerBackPressChangedSupplier = + new ObservableSupplierImpl<>(); + private final ObservableSupplierImpl<TabListEditorController> mEditorControllerSupplier = + new ObservableSupplierImpl<>(); private Tab mTab1; private Tab mTab2; @@ -212,7 +220,7 @@ doReturn(true) .when(mMultiWindowModeStateDispatcher) .addObserver(mMultiWindowModeObserverCaptor.capture()); - doReturn(new ObservableSupplierImpl<Boolean>()) + doReturn(mEditorControllerBackPressChangedSupplier) .when(mEditorController) .getHandleBackPressChangedSupplier(); doReturn(new ObservableSupplierImpl<Boolean>()) @@ -246,11 +254,21 @@ null); mMediator.initWithNative(null); - mMediator.setTabListEditorController(mEditorController); + mEditorControllerSupplier.set(mEditorController); + mMediator.setTabListEditorControllerSupplier(mEditorControllerSupplier); mMediator.addTabSwitcherViewObserver(mTabSwitcherViewObserver); mMediator.setOnTabSelectingListener(mOnTabSelectingListener); verify(mIncognitoReauthController, times(1)) .addIncognitoReauthCallback(mIncognitoReauthCallbackArgumentCaptor.capture()); + assertTrue(mEditorControllerSupplier.hasObservers()); + assertTrue(mEditorControllerBackPressChangedSupplier.hasObservers()); + } + + @After + public void tearDown() { + mMediator.destroy(); + assertFalse(mEditorControllerSupplier.hasObservers()); + assertFalse(mEditorControllerBackPressChangedSupplier.hasObservers()); } @Test @@ -1245,6 +1263,15 @@ equalTo(TAB_MODEL_FILTER_INDEX)); } + @Test + @SmallTest + public void testChangeEditorController() { + mEditorControllerSupplier.set(null); + assertFalse(mEditorControllerBackPressChangedSupplier.hasObservers()); + mEditorControllerSupplier.set(mEditorController); + assertTrue(mEditorControllerBackPressChangedSupplier.hasObservers()); + } + private void initAndAssertAllProperties() { assertThat( mModel.get(TabListContainerProperties.VISIBILITY_LISTENER),
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabContextTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabContextTest.java index 9654400..c51df5b 100644 --- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabContextTest.java +++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabContextTest.java
@@ -24,8 +24,6 @@ import org.chromium.chrome.browser.profiles.ProfileJni; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tabmodel.TabModelFilter; -import org.chromium.chrome.browser.tabmodel.TabModelFilterProvider; -import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.test.util.browser.Features; import org.chromium.content_public.browser.WebContents; import org.chromium.url.GURL; @@ -51,10 +49,6 @@ @Mock public Profile.Natives mMockProfileNatives; - @Mock private TabModelSelector mTabModelSelector; - - @Mock private TabModelFilterProvider mTabModelFilterProvider; - @Mock private TabModelFilter mTabModelFilter; private Tab mTab0 = @@ -86,8 +80,6 @@ public void setUp() { MockitoAnnotations.initMocks(this); mocker.mock(ProfileJni.TEST_HOOKS, mMockProfileNatives); - doReturn(mTabModelFilterProvider).when(mTabModelSelector).getTabModelFilterProvider(); - doReturn(mTabModelFilter).when(mTabModelFilterProvider).getCurrentTabModelFilter(); } private static Tab mockTab( @@ -113,7 +105,7 @@ doReturn(Arrays.asList(mTab0, mRelatedTab0, mRelatedTab1)) .when(mTabModelFilter) .getRelatedTabList(eq(TAB_0_ID)); - TabContext tabContext = TabContext.createCurrentContext(mTabModelSelector); + TabContext tabContext = TabContext.createCurrentContext(mTabModelFilter); Assert.assertEquals(tabContext.getUngroupedTabs().size(), 0); List<TabContext.TabGroupInfo> tabGroupInfo = tabContext.getTabGroups(); Assert.assertEquals(1, tabGroupInfo.size()); @@ -130,7 +122,7 @@ doReturn(mTab0).when(mTabModelFilter).getTabAt(eq(TAB_0_ID)); doReturn(1).when(mTabModelFilter).getCount(); doReturn(Arrays.asList(mTab0)).when(mTabModelFilter).getRelatedTabList(eq(TAB_0_ID)); - TabContext tabContext = TabContext.createCurrentContext(mTabModelSelector); + TabContext tabContext = TabContext.createCurrentContext(mTabModelFilter); Assert.assertEquals(tabContext.getUngroupedTabs().size(), 1); List<TabContext.TabGroupInfo> tabGroups = tabContext.getTabGroups(); Assert.assertEquals(0, tabGroups.size()); @@ -155,20 +147,27 @@ doReturn(Arrays.asList(newTab1)).when(mTabModelFilter).getRelatedTabList(eq(NEW_TAB_1_ID)); doReturn(Arrays.asList(newTab2)).when(mTabModelFilter).getRelatedTabList(eq(NEW_TAB_2_ID)); - TabContext tabContext = TabContext.createCurrentContext(mTabModelSelector); + TabContext tabContext = TabContext.createCurrentContext(mTabModelFilter); Assert.assertEquals(2, tabContext.getUngroupedTabs().size()); Assert.assertEquals(1, tabContext.getTabGroups().size()); Assert.assertEquals(3, tabContext.getTabGroups().get(0).tabs.size()); // close newTab1 doReturn(true).when(newTab1).isClosing(); - tabContext = TabContext.createCurrentContext(mTabModelSelector); + tabContext = TabContext.createCurrentContext(mTabModelFilter); Assert.assertEquals(1, tabContext.getUngroupedTabs().size()); // close mTab0 doReturn(true).when(mTab0).isClosing(); - tabContext = TabContext.createCurrentContext(mTabModelSelector); + tabContext = TabContext.createCurrentContext(mTabModelFilter); Assert.assertEquals(1, tabContext.getTabGroups().size()); Assert.assertEquals(2, tabContext.getTabGroups().get(0).tabs.size()); } + + @Test + public void testNoCrashOnNullFilter() { + TabContext tabContext = TabContext.createCurrentContext(null); + Assert.assertEquals(0, tabContext.getUngroupedTabs().size()); + Assert.assertEquals(0, tabContext.getTabGroups().size()); + } }
diff --git a/chrome/android/features/tab_ui/tab_management_java_sources.gni b/chrome/android/features/tab_ui/tab_management_java_sources.gni index 804c4cb6..c5361551 100644 --- a/chrome/android/features/tab_ui/tab_management_java_sources.gni +++ b/chrome/android/features/tab_ui/tab_management_java_sources.gni
@@ -81,6 +81,7 @@ "//chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListEditorGroupAction.java", "//chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListEditorLayout.java", "//chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListEditorLayoutBinder.java", + "//chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListEditorManager.java", "//chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListEditorMediator.java", "//chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListEditorMenu.java", "//chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListEditorMenuAdapter.java",
diff --git a/chrome/android/java/res/layout/context_menu_header.xml b/chrome/android/java/res/layout/context_menu_header.xml index c515f1d..1f62c9b 100644 --- a/chrome/android/java/res/layout/context_menu_header.xml +++ b/chrome/android/java/res/layout/context_menu_header.xml
@@ -28,7 +28,7 @@ <!-- Circle background for when we have a favicon or monogram --> <View android:id="@+id/circle_background" - android:background="?attr/tileViewIconBackgroundModern" + android:background="@drawable/tile_view_icon_background_modern" android:layout_width="@dimen/context_menu_header_circle_bg_diameter" android:layout_height="@dimen/context_menu_header_circle_bg_diameter" android:layout_margin="@dimen/context_menu_header_circle_bg_margin"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeBaseAppCompatActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeBaseAppCompatActivity.java index 243a82d..307d9b5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeBaseAppCompatActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeBaseAppCompatActivity.java
@@ -43,7 +43,6 @@ import org.chromium.chrome.R; import org.chromium.chrome.browser.base.ServiceTracingProxyProvider; import org.chromium.chrome.browser.base.SplitChromeApplication; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.language.GlobalAppLocaleController; import org.chromium.chrome.browser.metrics.UmaSessionStats; import org.chromium.chrome.browser.night_mode.GlobalNightModeStateProviderHolder; @@ -310,10 +309,6 @@ /** Apply theme overlay to this activity class. */ @CallSuper protected void applyThemeOverlays() { - if (ChromeFeatureList.sBaselineGm3SurfaceColors.isEnabled()) { - getTheme().applyStyle(R.style.SurfaceColorsThemeOverlay, /* force= */ true); - mThemeResIds.add(R.style.SurfaceColorsThemeOverlay); - } DynamicColors.applyToActivityIfAvailable(this); DeferredStartupHandler.getInstance()
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java index 6183dac..30f6d98 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -1112,6 +1112,9 @@ } mInactivityTracker.setLastVisibleTimeMsAndRecord(System.currentTimeMillis()); + + getSnackbarManager() + .setEdgeToEdgeSupplier(mRootUiCoordinator.getEdgeToEdgeController()); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java index f348a08c..faf1e80 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
@@ -710,8 +710,8 @@ mBottomContainer = (BottomContainer) findViewById(R.id.bottom_container); - // TODO(crbug.com/1199776): Move this to the RootUiCoordinator. mSnackbarManager = new SnackbarManager(this, mBottomContainer, getWindowAndroid()); + mInsetObserverViewSupplier.get().addObserver(mSnackbarManager); SnackbarManagerProvider.attach(getWindowAndroid(), mSnackbarManager); // Make the activity listen to policy change events @@ -1747,7 +1747,11 @@ mStylusWritingCoordinator = null; } - // Destroy spare tab on activitiy destruction. + if (mInsetObserverViewSupplier.get() != null) { + mInsetObserverViewSupplier.get().removeObserver(mSnackbarManager); + } + + // Destroy spare tab on activity destruction. WarmupManager warmupManager = WarmupManager.getInstance(); warmupManager.destroySpareTab();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkBridge.java index c30dc97..b6752248 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkBridge.java
@@ -53,7 +53,7 @@ private @Nullable BookmarkId mMobileFolderId; private @Nullable BookmarkId mOtherFolderId; private @Nullable BookmarkId mDesktopFolderId; - private @Nullable BookmarkId mReadingListFolderId; + private @Nullable BookmarkId mLocalOrSyncableReadingListFolderId; /** * Handler to fetch the bookmarks, titles, urls and folder hierarchy. @@ -232,18 +232,32 @@ return result; } - /** Returns the synthetic reading list folder. */ - // TODO(crbug.com/1501998): Add split account/local functions. + /** Returns the local/syncable synthetic reading list folder. */ public BookmarkId getLocalOrSyncableReadingListFolder() { ThreadUtils.assertOnUiThread(); if (mNativeBookmarkBridge == 0) return null; assert mIsNativeBookmarkModelLoaded; - if (mReadingListFolderId == null) { - mReadingListFolderId = + if (mLocalOrSyncableReadingListFolderId == null) { + mLocalOrSyncableReadingListFolderId = BookmarkBridgeJni.get() .getLocalOrSyncableReadingListFolder(mNativeBookmarkBridge); } - return mReadingListFolderId; + return mLocalOrSyncableReadingListFolderId; + } + + /** + * Returns the account synthetic reading list folder. Function will return null if the required + * conditions to use account-bound data aren't satisfied: - The user is signed-in and not + * syncing. - The user has the kReadingList sync data type enabled. + */ + public BookmarkId getAccountReadingListFolder() { + ThreadUtils.assertOnUiThread(); + if (mNativeBookmarkBridge == 0) return null; + assert mIsNativeBookmarkModelLoaded; + + // Note: The account reading list folder isn't cached because the availability can change + // during runtime. + return BookmarkBridgeJni.get().getAccountReadingListFolder(mNativeBookmarkBridge); } public BookmarkId getDefaultReadingListFolder() { @@ -825,6 +839,13 @@ return BookmarkBridgeJni.get().getUnreadCount(mNativeBookmarkBridge, readingListParentId); } + /** Returns whether the given {@link BookmarkId} belongs to the account. */ + public boolean isAccountBookmark(BookmarkId id) { + ThreadUtils.assertOnUiThread(); + if (mNativeBookmarkBridge == 0) return false; + return BookmarkBridgeJni.get().isAccountBookmark(mNativeBookmarkBridge, id); + } + /** * Checks whether supplied URL has already been bookmarked. * @@ -1005,6 +1026,8 @@ BookmarkId getLocalOrSyncableReadingListFolder(long nativeBookmarkBridge); + BookmarkId getAccountReadingListFolder(long nativeBookmarkBridge); + BookmarkId getDefaultReadingListFolder(long nativeBookmarkBridge); void getAllFoldersWithDepths( @@ -1071,6 +1094,8 @@ int getUnreadCount(long nativeBookmarkBridge, BookmarkId id); + boolean isAccountBookmark(long nativeBookmarkBridge, BookmarkId id); + void undo(long nativeBookmarkBridge); void startGroupingUndos(long nativeBookmarkBridge);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java index 13508679..ca0cf653 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java
@@ -10,9 +10,7 @@ import com.google.android.material.color.DynamicColors; import org.chromium.base.TraceEvent; -import org.chromium.chrome.R; import org.chromium.chrome.browser.LaunchIntentDispatcher; -import org.chromium.chrome.browser.flags.ChromeFeatureList; /** * Dispatches incoming intents to the appropriate activity based on the current configuration and @@ -50,11 +48,6 @@ } private void applyThemeOverlays() { - // The effect of this activity's theme is currently limited to CCTs, so we should only apply - // dynamic colors when we enable them everywhere. - if (ChromeFeatureList.sBaselineGm3SurfaceColors.isEnabled()) { - getTheme().applyStyle(R.style.SurfaceColorsThemeOverlay, /* force= */ true); - } DynamicColors.applyToActivityIfAvailable(this); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java index 8e1fd97..29377359 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
@@ -356,11 +356,8 @@ return; } - final int elevationDimenId = - ChromeFeatureList.sBaselineGm3SurfaceColors.isEnabled() - ? R.dimen.default_elevation_4 - : R.dimen.toolbar_text_box_elevation; - final int searchBoxColor = ChromeColors.getSurfaceColor(getContext(), elevationDimenId); + final int searchBoxColor = + ChromeColors.getSurfaceColor(getContext(), R.dimen.default_elevation_4); final ColorStateList colorStateList = ColorStateList.valueOf(searchBoxColor); findViewById(R.id.search_box).setBackgroundTintList(colorStateList); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/segmentation_platform/ContextualPageActionControllerUnitTest.java b/chrome/android/java/src/org/chromium/chrome/browser/segmentation_platform/ContextualPageActionControllerUnitTest.java index 0b4dedc..1d69933 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/segmentation_platform/ContextualPageActionControllerUnitTest.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/segmentation_platform/ContextualPageActionControllerUnitTest.java
@@ -48,7 +48,6 @@ @EnableFeatures({ ChromeFeatureList.CONTEXTUAL_PAGE_ACTIONS, ChromeFeatureList.CONTEXTUAL_PAGE_ACTION_PRICE_TRACKING, - ChromeFeatureList.SHOPPING_LIST }) public class ContextualPageActionControllerUnitTest { private ObservableSupplierImpl<Profile> mProfileSupplier; @@ -154,7 +153,6 @@ ChromeFeatureList.CONTEXTUAL_PAGE_ACTIONS, "enable_ui", "false"); testValues.addFeatureFlagOverride( ChromeFeatureList.CONTEXTUAL_PAGE_ACTION_PRICE_TRACKING, true); - testValues.addFeatureFlagOverride(ChromeFeatureList.SHOPPING_LIST, true); FeatureList.setTestValues(testValues); createContextualPageActionController();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java index 4b58b59..40cd5136 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java
@@ -32,7 +32,6 @@ import org.chromium.base.task.SequencedTaskRunner; import org.chromium.base.task.TaskRunner; import org.chromium.base.task.TaskTraits; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.preferences.ChromePreferenceKeys; import org.chromium.chrome.browser.preferences.ChromeSharedPreferences; import org.chromium.chrome.browser.tab.Tab; @@ -193,8 +192,7 @@ @Override public void onFinishingMultipleTabClosure(List<Tab> tabs) { - if (!mTabModelSelector.isIncognitoSelected() - && ChromeFeatureList.sCloseTabSaveTabList.isEnabled()) { + if (!mTabModelSelector.isIncognitoSelected()) { saveTabListAsynchronously(); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java index 15ee19d39..979fc43 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java
@@ -1791,6 +1791,13 @@ } /** + * @return The {@link EdgeToEdgeController} controlling the edge-to-edge state. + */ + public @Nullable EdgeToEdgeController getEdgeToEdgeController() { + return mE2eController; + } + + /** * @return {@link ComposedBrowserControlsVisibilityDelegate} object for tabbed activity. */ public ComposedBrowserControlsVisibilityDelegate getAppBrowserControlsVisibilityDelegate() { @@ -1802,8 +1809,9 @@ /** * Gets the browser controls manager, creates it unless already created. + * * @deprecated Instead, inject this directly to your constructor. If that's not possible, then - * use {@link BrowserControlsManagerSupplier}. + * use {@link BrowserControlsManagerSupplier}. */ @NonNull @Deprecated
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/app/bookmarks/BookmarkTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/app/bookmarks/BookmarkTest.java index d634f2a..285ff4a7 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/app/bookmarks/BookmarkTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/app/bookmarks/BookmarkTest.java
@@ -677,7 +677,6 @@ @Test @MediumTest - @DisableFeatures({ChromeFeatureList.SHOPPING_LIST}) public void testSearchBookmarks_DeleteFolderWithChildrenInResults() throws Exception { BookmarkPromoHeader.forcePromoStateForTesting(SyncPromoState.NO_PROMO); BookmarkId testFolder = addFolder(TEST_FOLDER_TITLE); @@ -1423,7 +1422,6 @@ @Test @MediumTest - @DisableFeatures({ChromeFeatureList.SHOPPING_LIST}) public void testTopLevelFolderUpdateAfterSync() throws Exception { // Set up the test and open the bookmark manager to the Mobile Bookmarks folder. BookmarkTestUtil.readPartnerBookmarks(mActivityTestRule);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/app/edge_to_edge/EdgeToEdgeInstrumentationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/app/edge_to_edge/EdgeToEdgeInstrumentationTest.java index 8962cdc..95822c2 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/app/edge_to_edge/EdgeToEdgeInstrumentationTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/app/edge_to_edge/EdgeToEdgeInstrumentationTest.java
@@ -16,8 +16,10 @@ import android.view.View; import androidx.test.filters.MediumTest; +import androidx.test.platform.app.InstrumentationRegistry; import org.junit.After; +import org.junit.Assert; import org.junit.Before; import org.junit.ClassRule; import org.junit.Rule; @@ -36,11 +38,15 @@ import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.ui.edge_to_edge.EdgeToEdgeControllerImpl; import org.chromium.chrome.browser.ui.edge_to_edge.EdgeToEdgeOSWrapperImpl; +import org.chromium.chrome.browser.ui.messages.snackbar.Snackbar; +import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.chrome.test.ChromeTabbedActivityTestRule; import org.chromium.chrome.test.batch.BlankCTATabInitialStateRule; import org.chromium.chrome.test.util.ActivityTestUtils; import org.chromium.chrome.test.util.browser.Features.EnableFeatures; +import org.chromium.content_public.browser.test.util.TestThreadUtils; +import org.chromium.content_public.browser.test.util.UiUtils; import org.chromium.net.test.EmbeddedTestServer; import org.chromium.ui.test.util.DeviceRestriction; import org.chromium.ui.test.util.UiRestriction; @@ -238,4 +244,51 @@ TO_EDGE_PADDING, mTestOsWrapper.getNextPadding()); } + + @Test + @MediumTest + public void testSnackbar() throws InterruptedException { + activateFeatureToEdge(); + goToNormal(); + var snackbarManager = mActivity.getSnackbarManager(); + snackbarManager.setEdgeToEdgeSupplier(mEdgeToEdgeController); + TestThreadUtils.runOnUiThreadBlocking( + () -> { + snackbarManager.showSnackbar( + Snackbar.make( + "Test", + new SnackbarManager.SnackbarController() {}, + Snackbar.TYPE_PERSISTENT, + Snackbar.UMA_TEST_SNACKBAR)); + }); + + UiUtils.settleDownUI(InstrumentationRegistry.getInstrumentation()); + + var adjuster = + snackbarManager + .getCurrentSnackbarViewForTesting() + .getEdgeToEdgePadAdjusterForTesting(); + Assert.assertNotNull("Pad Adjuster should be created", adjuster); + + int heightOnAuto = + snackbarManager.getCurrentSnackbarViewForTesting().getViewForTesting().getHeight(); + int padding = mTestOsWrapper.getNextPadding(); + + goToEdge(); + int heightOnCover = + snackbarManager.getCurrentSnackbarViewForTesting().getViewForTesting().getHeight(); + + Assert.assertEquals( + "New padding has been added when viewport-fit=cover.", + padding, + heightOnCover - heightOnAuto); + + goToNormal(); + heightOnAuto = + snackbarManager.getCurrentSnackbarViewForTesting().getViewForTesting().getHeight(); + Assert.assertEquals( + "Padding has been removed when viewport-fit=auto.", + padding, + heightOnCover - heightOnAuto); + } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillSaveCardBottomSheetRenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillSaveCardBottomSheetRenderTest.java index 6fbef6e..f6c825c 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillSaveCardBottomSheetRenderTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillSaveCardBottomSheetRenderTest.java
@@ -60,7 +60,7 @@ @Rule public final RenderTestRule mRenderTestRule = RenderTestRule.Builder.withPublicCorpus() - .setRevision(0) + .setRevision(1) .setBugComponent(Component.UI_BROWSER_AUTOFILL) .build();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderPickerRenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderPickerRenderTest.java index 9a574d7..244da19 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderPickerRenderTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderPickerRenderTest.java
@@ -94,7 +94,7 @@ @Rule public final ChromeRenderTestRule mRenderTestRule = ChromeRenderTestRule.Builder.withPublicCorpus() - .setRevision(2) + .setRevision(3) .setBugComponent(ChromeRenderTestRule.Component.UI_BROWSER_BOOKMARKS) .build();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkSaveFlowTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkSaveFlowTest.java index ba1fe1b9..467803b 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkSaveFlowTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkSaveFlowTest.java
@@ -47,7 +47,6 @@ import org.chromium.chrome.test.util.BookmarkTestUtil; import org.chromium.chrome.test.util.ChromeRenderTestRule; import org.chromium.chrome.test.util.browser.Features.DisableFeatures; -import org.chromium.chrome.test.util.browser.Features.EnableFeatures; import org.chromium.components.bookmarks.BookmarkId; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; import org.chromium.components.browser_ui.bottomsheet.BottomSheetTestSupport; @@ -65,7 +64,6 @@ /** Tests for the bookmark save flow. */ @RunWith(ChromeJUnit4ClassRunner.class) @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) -@EnableFeatures(ChromeFeatureList.SHOPPING_LIST) @DisableFeatures(ChromeFeatureList.ANDROID_IMPROVED_BOOKMARKS) public class BookmarkSaveFlowTest { @Rule
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkFolderViewRenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkFolderViewRenderTest.java index de35d4f..c9f75c1 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkFolderViewRenderTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkFolderViewRenderTest.java
@@ -83,6 +83,7 @@ public ChromeRenderTestRule mRenderTestRule = ChromeRenderTestRule.Builder.withPublicCorpus() .setBugComponent(ChromeRenderTestRule.Component.UI_BROWSER_BOOKMARKS) + .setRevision(1) .build(); @Rule public TestRule mProcessor = new Features.JUnitProcessor();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkRowRenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkRowRenderTest.java index 353c5df3d..da241b8 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkRowRenderTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkRowRenderTest.java
@@ -88,7 +88,7 @@ @Rule public ChromeRenderTestRule mRenderTestRule = ChromeRenderTestRule.Builder.withPublicCorpus() - .setRevision(2) + .setRevision(3) .setBugComponent(ChromeRenderTestRule.Component.UI_BROWSER_BOOKMARKS) .build();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkSaveFlowRenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkSaveFlowRenderTest.java index 3ece2ef..42028172 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkSaveFlowRenderTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/ImprovedBookmarkSaveFlowRenderTest.java
@@ -63,7 +63,7 @@ @Rule public ChromeRenderTestRule mRenderTestRule = ChromeRenderTestRule.Builder.withPublicCorpus() - .setRevision(1) + .setRevision(2) .setBugComponent(ChromeRenderTestRule.Component.UI_BROWSER_BOOKMARKS) .build();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/PowerBookmarkShoppingItemRowRenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/PowerBookmarkShoppingItemRowRenderTest.java index d63e2ac..9edc648f 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/PowerBookmarkShoppingItemRowRenderTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/PowerBookmarkShoppingItemRowRenderTest.java
@@ -69,6 +69,7 @@ public ChromeRenderTestRule mRenderTestRule = ChromeRenderTestRule.Builder.withPublicCorpus() .setBugComponent(ChromeRenderTestRule.Component.UI_BROWSER_BOOKMARKS) + .setRevision(1) .build(); @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/ShoppingAccessoryViewRenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/ShoppingAccessoryViewRenderTest.java index 982337f2..201c4c9 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/ShoppingAccessoryViewRenderTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/ShoppingAccessoryViewRenderTest.java
@@ -70,6 +70,7 @@ public ChromeRenderTestRule mRenderTestRule = ChromeRenderTestRule.Builder.withPublicCorpus() .setBugComponent(ChromeRenderTestRule.Component.UI_BROWSER_BOOKMARKS) + .setRevision(1) .build(); @Rule public TestRule mProcessor = new Features.JUnitProcessor();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuRenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuRenderTest.java index 2a8ef2aa..f79127f 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuRenderTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuRenderTest.java
@@ -54,6 +54,7 @@ public ChromeRenderTestRule mRenderTestRule = ChromeRenderTestRule.Builder.withPublicCorpus() .setBugComponent(ChromeRenderTestRule.Component.UI_BROWSER_MOBILE_CONTEXT_MENU) + .setRevision(1) .build(); private ModelListAdapter mAdapter;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityAppMenuTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityAppMenuTest.java index 704f42ec..832993a4 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityAppMenuTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityAppMenuTest.java
@@ -54,6 +54,7 @@ import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.JniMocker; import org.chromium.base.test.util.PackageManagerWrapper; +import org.chromium.base.test.util.Restriction; import org.chromium.chrome.browser.app.metrics.LaunchCauseMetrics; import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider; import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider.CustomTabsUiType; @@ -76,6 +77,7 @@ import org.chromium.content_public.browser.test.util.TestThreadUtils; import org.chromium.ui.modelutil.MVCListAdapter.ModelList; import org.chromium.ui.modelutil.PropertyModel; +import org.chromium.ui.test.util.DeviceRestriction; import java.util.ArrayList; import java.util.List; @@ -439,6 +441,7 @@ /** Tests if the default share item can be shown in the app menu. */ @Test @SmallTest + @Restriction(DeviceRestriction.RESTRICTION_TYPE_NON_AUTO) public void testShareMenuItem() throws Exception { Intent intent = createMinimalCustomTabIntent(); intent.putExtra(CustomTabsIntent.EXTRA_DEFAULT_SHARE_MENU_ITEM, true);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/modaldialog/ModalDialogViewRenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/modaldialog/ModalDialogViewRenderTest.java index 011fd8cf..b6f685fb 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/modaldialog/ModalDialogViewRenderTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/modaldialog/ModalDialogViewRenderTest.java
@@ -72,7 +72,7 @@ @Rule public RenderTestRule mRenderTestRule = RenderTestRule.Builder.withPublicCorpus() - .setRevision(1) + .setRevision(2) .setBugComponent(RenderTestRule.Component.UI_BROWSER_MOBILE_MESSAGES) .build();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SyncConsentFragmentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SyncConsentFragmentTest.java index 77bcc9e..e9a59a6 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SyncConsentFragmentTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SyncConsentFragmentTest.java
@@ -31,7 +31,6 @@ import androidx.test.platform.app.InstrumentationRegistry; import androidx.test.runner.lifecycle.Stage; -import org.chromium.base.BuildInfo; import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -42,6 +41,7 @@ import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; +import org.chromium.base.BuildInfo; import org.chromium.base.test.BaseActivityTestRule; import org.chromium.base.test.util.ApplicationTestUtils; import org.chromium.base.test.util.CommandLineFlags; @@ -86,7 +86,7 @@ @RunWith(ChromeJUnit4ClassRunner.class) @Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) public class SyncConsentFragmentTest { - private static final int RENDER_REVISION = 1; + private static final int RENDER_REVISION = 2; private static final String RENDER_DESCRIPTION = "Change button style"; private static final String NEW_ACCOUNT_NAME = "new.account@gmail.com"; // TODO(https://crbug.com/1414078): Use ALL_SELECTABLE_TYPES defined in {@link SyncServiceImpl}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/AllSiteSettingsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/AllSiteSettingsTest.java new file mode 100644 index 0000000..6ebb4d7 --- /dev/null +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/AllSiteSettingsTest.java
@@ -0,0 +1,132 @@ +// 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. + +package org.chromium.chrome.browser.site_settings; + +import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.withText; + +import static org.hamcrest.CoreMatchers.containsString; + +import static org.chromium.ui.test.util.ViewUtils.onViewWaiting; + +import android.view.View; + +import androidx.preference.PreferenceFragmentCompat; +import androidx.test.filters.SmallTest; + +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; + +import org.chromium.base.test.util.Batch; +import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.base.test.util.Feature; +import org.chromium.base.test.util.JniMocker; +import org.chromium.chrome.browser.flags.ChromeSwitches; +import org.chromium.chrome.browser.permissions.PermissionTestRule; +import org.chromium.chrome.browser.privacy_sandbox.FakeTrackingProtectionBridge; +import org.chromium.chrome.browser.privacy_sandbox.TrackingProtectionBridgeJni; +import org.chromium.chrome.browser.profiles.Profile; +import org.chromium.chrome.browser.settings.SettingsActivity; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; +import org.chromium.chrome.test.batch.BlankCTATabInitialStateRule; +import org.chromium.chrome.test.util.ChromeRenderTestRule; +import org.chromium.components.browser_ui.site_settings.SiteSettingsCategory; +import org.chromium.components.browser_ui.site_settings.WebsitePreferenceBridge; +import org.chromium.components.content_settings.ContentSettingValues; +import org.chromium.components.content_settings.ContentSettingsType; +import org.chromium.content_public.browser.BrowserContextHandle; +import org.chromium.content_public.browser.test.util.TestThreadUtils; +import org.chromium.ui.test.util.RenderTestRule; +import org.chromium.ui.test.util.RenderTestRule.Component; + +import java.util.concurrent.TimeoutException; + +@RunWith(ChromeJUnit4ClassRunner.class) +@Batch(AllSiteSettingsTest.TEST_BATCH_NAME) +@CommandLineFlags.Add(ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE) +public class AllSiteSettingsTest { + public static final String TEST_BATCH_NAME = "AllSiteSettingsTest"; + + @Rule + public RenderTestRule mRenderTestRule = + RenderTestRule.Builder.withPublicCorpus() + .setBugComponent(Component.UI_BROWSER_MOBILE_SETTINGS) + .build(); + + @ClassRule public static PermissionTestRule mPermissionRule = new PermissionTestRule(true); + + @Rule + public BlankCTATabInitialStateRule mBlankCTATabInitialStateRule = + new BlankCTATabInitialStateRule(mPermissionRule, false); + + @Rule public JniMocker mocker = new JniMocker(); + + private FakeTrackingProtectionBridge mFakeTrackingProtectionBridge; + + private static BrowserContextHandle getBrowserContextHandle() { + return Profile.getLastUsedRegularProfile(); + } + + @Before + public void setUp() throws TimeoutException { + SiteSettingsTestUtils.cleanUpCookiesAndPermissions(); + MockitoAnnotations.initMocks(this); + mFakeTrackingProtectionBridge = new FakeTrackingProtectionBridge(); + mocker.mock(TrackingProtectionBridgeJni.TEST_HOOKS, mFakeTrackingProtectionBridge); + } + + @Test + @SmallTest + @Feature({"Preferences", "RenderTest"}) + public void testAllSitesViewEmpty() throws Exception { + SettingsActivity settingsActivity = + SiteSettingsTestUtils.startAllSitesSettings(SiteSettingsCategory.Type.ALL_SITES); + onViewWaiting(withText(containsString("Clear browsing"))).check(matches(isDisplayed())); + View view = + TestThreadUtils.runOnUiThreadBlocking( + () -> { + PreferenceFragmentCompat preferenceFragment = + (PreferenceFragmentCompat) settingsActivity.getMainFragment(); + return preferenceFragment.getView(); + }); + ChromeRenderTestRule.sanitize(view); + mRenderTestRule.render(view, "site_settings_all_sites_empty"); + settingsActivity.finish(); + } + + @Test + @SmallTest + @Feature({"Preferences", "RenderTest"}) + public void testAllSitesViewSingleDomain() throws Exception { + TestThreadUtils.runOnUiThreadBlocking( + () -> { + WebsitePreferenceBridge.setContentSettingCustomScope( + getBrowserContextHandle(), + ContentSettingsType.COOKIES, + "google.com", + "*", + ContentSettingValues.ALLOW); + }); + + SettingsActivity settingsActivity = + SiteSettingsTestUtils.startAllSitesSettings(SiteSettingsCategory.Type.ALL_SITES); + onViewWaiting(withText(containsString("Clear browsing"))).check(matches(isDisplayed())); + View view = + TestThreadUtils.runOnUiThreadBlocking( + () -> { + PreferenceFragmentCompat preferenceFragment = + (PreferenceFragmentCompat) settingsActivity.getMainFragment(); + return preferenceFragment.getView(); + }); + ChromeRenderTestRule.sanitize(view); + mRenderTestRule.render(view, "site_settings_all_sites_single_domain"); + settingsActivity.finish(); + } +}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SiteSettingsTestUtils.java b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SiteSettingsTestUtils.java index e790fa5..7c9ede7 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SiteSettingsTestUtils.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SiteSettingsTestUtils.java
@@ -11,6 +11,10 @@ import androidx.test.core.app.ApplicationProvider; import androidx.test.platform.app.InstrumentationRegistry; +import org.chromium.base.test.util.CallbackHelper; +import org.chromium.chrome.browser.browsing_data.BrowsingDataBridge; +import org.chromium.chrome.browser.browsing_data.BrowsingDataType; +import org.chromium.chrome.browser.browsing_data.TimePeriod; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.settings.SettingsActivity; import org.chromium.chrome.browser.settings.SettingsLauncherImpl; @@ -31,6 +35,8 @@ import org.chromium.components.content_settings.CookieControlsMode; import org.chromium.content_public.browser.test.util.TestThreadUtils; +import java.util.concurrent.TimeoutException; + /** Util functions for testing SiteSettings functionality. */ public class SiteSettingsTestUtils { public static SettingsActivity startSiteSettingsMenu(String category) { @@ -135,4 +141,19 @@ return ((RadioButtonWithDescriptionAndAuxButton) button); } + + public static void cleanUpCookiesAndPermissions() throws TimeoutException { + CallbackHelper helper = new CallbackHelper(); + TestThreadUtils.runOnUiThreadBlocking( + () -> { + BrowsingDataBridge.getInstance() + .clearBrowsingData( + helper::notifyCalled, + new int[] { + BrowsingDataType.COOKIES, BrowsingDataType.SITE_SETTINGS + }, + TimePeriod.ALL_TIME); + }); + helper.waitForCallback(0); + } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabDataTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabDataTest.java index afa1667..8bc0dd9 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabDataTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabDataTest.java
@@ -30,8 +30,6 @@ import org.chromium.base.test.util.CallbackHelper; import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.JniMocker; -import org.chromium.chrome.browser.endpoint_fetcher.EndpointFetcher; -import org.chromium.chrome.browser.endpoint_fetcher.EndpointFetcherJni; import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.optimization_guide.OptimizationGuideBridge; @@ -71,7 +69,6 @@ @Rule public TestRule mProcessor = new Features.InstrumentationProcessor(); - @Mock protected EndpointFetcher.Natives mEndpointFetcherJniMock; @Mock protected OptimizationGuideBridge.Natives mOptimizationGuideBridgeJniMock; @@ -87,7 +84,6 @@ @Before public void setUp() { MockitoAnnotations.initMocks(this); - mMocker.mock(EndpointFetcherJni.TEST_HOOKS, mEndpointFetcherJniMock); mMocker.mock(OptimizationGuideBridgeJni.TEST_HOOKS, mOptimizationGuideBridgeJniMock); // Ensure native pointer is initialized doReturn(1L).when(mOptimizationGuideBridgeJniMock).init(); @@ -1116,9 +1112,6 @@ @SmallTest @Test public void testShoppingPersistedTabDataSupportedForMaintenance() { - MockTab mockTab = - MockTab.createAndInitialize(ShoppingPersistedTabDataTestUtils.TAB_ID, mProfileMock); - ShoppingPersistedTabData shoppingPersistedTabData = new ShoppingPersistedTabData(mockTab); Assert.assertTrue( PersistedTabData.getSupportedMaintenanceClassesForTesting() .contains(ShoppingPersistedTabData.class));
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabDataTestUtils.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabDataTestUtils.java index ff0adaa..35fd26e 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabDataTestUtils.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabDataTestUtils.java
@@ -7,7 +7,6 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.times; @@ -21,9 +20,7 @@ import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; -import org.chromium.base.Callback; import org.chromium.base.supplier.ObservableSupplierImpl; -import org.chromium.chrome.browser.endpoint_fetcher.EndpointFetcher; import org.chromium.chrome.browser.optimization_guide.OptimizationGuideBridge; import org.chromium.chrome.browser.optimization_guide.OptimizationGuideBridge.OptimizationGuideCallback; import org.chromium.chrome.browser.profiles.Profile; @@ -472,20 +469,6 @@ anyLong(), any(GURL.class), anyInt(), any(OptimizationGuideCallback.class)); } - static void verifyEndpointFetcherCalled(EndpointFetcher.Natives endpointFetcher, int numTimes) { - verify(endpointFetcher, times(numTimes)) - .nativeFetchChromeAPIKey( - any(Profile.class), - anyString(), - anyString(), - anyString(), - anyString(), - anyLong(), - any(String[].class), - anyInt(), - any(Callback.class)); - } - static void verifyPriceTrackingOptimizationTypeCalled( OptimizationGuideBridge.Natives optimizationGuideJni, int numTimes) { verify(optimizationGuideJni, times(numTimes))
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/EmulatedGvrController.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/EmulatedGvrController.java deleted file mode 100644 index 34b980c..0000000 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/EmulatedGvrController.java +++ /dev/null
@@ -1,244 +0,0 @@ -// 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. - -package org.chromium.chrome.browser.vr; - -import android.content.Context; -import android.os.SystemClock; - -import androidx.annotation.IntDef; - -import com.google.vr.testframework.controller.ControllerTestApi; - -import org.junit.Assert; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.concurrent.TimeUnit; - -/** - * Wrapper for the ControllerTestApi class to handle more complex actions such as clicking and - * dragging. - * - * <p>Requires that VrCore's settings file is modified to use the test API: - - * UseAutomatedController: true - PairedControllerDriver: "DRIVER_AUTOMATED" - - * PairedControllerAddress: "FOO" - */ -public class EmulatedGvrController { - @IntDef({ScrollDirection.UP, ScrollDirection.DOWN, ScrollDirection.LEFT, ScrollDirection.RIGHT}) - @Retention(RetentionPolicy.SOURCE) - public @interface ScrollDirection { - int UP = 0; - int DOWN = 1; - int LEFT = 2; - int RIGHT = 3; - } - - private static final int FIRST_INPUT_DELAY_MS = 1000; - private final ControllerTestApi mApi; - private boolean mHaveSentInputSinceEnteringVr; - - public EmulatedGvrController(Context context) { - mApi = new ControllerTestApi(context); - } - - public ControllerTestApi getApi() { - // We flakily disconnect and reconnect the controller immediately after VR entry, which can - // cause controller input to get eaten. Sleeping a bit after VR entry fixes this, so instead - // of adding a bunch of sleeps everywhere, sleep for a bit before sending the first input - // after VR entry. - // TODO(https://crbug.com/870031): Remove this sleep if/when the controller disconnect/ - // reconnect issue caused by DON flow skipping that flakily eats controller input is - // resolved. - if (!mHaveSentInputSinceEnteringVr) { - SystemClock.sleep(FIRST_INPUT_DELAY_MS); - mHaveSentInputSinceEnteringVr = true; - } - return mApi; - } - - /** - * Resets the flag used to keep track of whether we have sent input since entering VR. Should be - * called anytime the emulated controller is used and a test re-enters VR. - */ - public void resetFirstInputFlag() { - mHaveSentInputSinceEnteringVr = false; - } - - /** Touch and release the touchpad to perform a controller click. */ - public void performControllerClick() { - // pressReleaseTouchpadButton() appears to be flaky for clicking on things, as sometimes - // it happens too fast for Chrome to register. So, manually press and release with a delay - sendClickButtonToggleEvent(); - SystemClock.sleep(50); - sendClickButtonToggleEvent(); - } - - /** - * Either presses or releases the Daydream controller's touchpad button depending on whether the - * button is currently pressed or not. - */ - public void sendClickButtonToggleEvent() { - getApi().buttonEvent.sendClickButtonToggleEvent(); - } - - /** - * Presses and quickly releases the Daydream controller's touchpad button. Or, if the button is - * already pressed, releases and quickly presses again. - */ - public void pressReleaseTouchpadButton() { - getApi().buttonEvent.sendClickButtonEvent(); - } - - /** - * Either presses or releases the Daydream controller's app button depending on whether the - * button is currently pressed or not. - */ - public void sendAppButtonToggleEvent() { - getApi().buttonEvent.sendAppButtonToggleEvent(); - } - - /** - * Presses and quickly releases the Daydream controller's app button. Or, if the button is - * already pressed, releases and quickly presses again. - */ - public void pressReleaseAppButton() { - getApi().buttonEvent.sendAppButtonEvent(); - } - - /** - * Holds the home button to recenter the view using an arbitrary, but valid orientation - * quaternion. - */ - public void recenterView() { - getApi().buttonEvent.sendHomeButtonToggleEvent(); - // Need to "hold" the button long enough to trigger a view recenter instead of just a button - // press - half a second is sufficient and non-flaky. - SystemClock.sleep(500); - getApi().buttonEvent.sendHomeButtonToggleEvent(); - } - - /** Performs a short home button press/release, which launches the Daydream Home app. */ - public void goToDaydreamHome() { - getApi().buttonEvent.sendShortHomeButtonEvent(); - } - - /** - * Performs an swipe on the touchpad in order to scroll in the specified direction while in the - * VR browser. Note that scrolling this way is not consistent, i.e. scrolling down then - * scrolling up at the same speed won't necessarily scroll back to the exact starting position - * on the page. - * - * @param direction the ScrollDirection to scroll with. - * @param steps the number of intermediate steps to send while scrolling. - * @param speed how long to wait between steps in the scroll, with higher numbers resulting in a - * faster scroll. - */ - public void scroll(@ScrollDirection int direction, int steps, int speed) { - float startX; - float startY; - float endX; - float endY; - startX = startY = endX = endY = 0.5f; - switch (direction) { - case ScrollDirection.UP: - startY = 0.1f; - endY = 0.9f; - break; - case ScrollDirection.DOWN: - startY = 0.9f; - endY = 0.1f; - break; - case ScrollDirection.LEFT: - startX = 0.1f; - endX = 0.9f; - break; - case ScrollDirection.RIGHT: - startX = 0.9f; - endX = 0.1f; - break; - default: - Assert.fail("Unknown scroll direction enum given"); - } - performLinearTouchpadMovement(startX, startY, endX, endY, steps, speed); - } - - /** Touches then releases the touchpad to cancel fling scroll. */ - public void cancelFlingScroll() { - // Arbitrary amount of delay to both ensure that the touchpad press is properly registered - // and long enough that we don't accidentally trigger any functionality bound to quick - // touchpad taps if there is any. - int delay = 500; - long simulatedDelay = TimeUnit.MILLISECONDS.toNanos(delay); - long timestamp = mApi.touchEvent.startTouchSequence(0.5f, 0.5f, simulatedDelay, delay); - getApi().touchEvent.endTouchSequence(0.5f, 0.5f, timestamp, simulatedDelay, delay); - } - - /** - * Simulates a touch down-drag-touch up sequence on the touchpad between two points. - * - * @param xStart the x coordinate to start the touch sequence at, in range [0.0f, 1.0f]. - * @param yStart the y coordinate to start the touch sequence at, in range [0.0f, 1.0f]. - * @param xEnd the x coordinate to end the touch sequence at, in range [0.0f, 1.0f]. - * @param yEnd the y coordinate to end the touch sequence at, in range [0.0f, 1.0f]. - * @param steps the number of steps the drag will have. - * @param speed how long to wait between steps in the sequence. Generally, higher numbers result - * in faster movement, e.g. when used for scrolling, a higher number results in faster - * scrolling. - */ - public void performLinearTouchpadMovement( - float xStart, float yStart, float xEnd, float yEnd, int steps, int speed) { - // Touchpad events have timestamps attached to them in nanoseconds - for smooth scrolling, - // the timestamps should increase at a similar rate to the amount of time we actually wait - // between sending events, which is determined by the given speed. - long simulatedDelay = TimeUnit.MILLISECONDS.toNanos(speed); - long timestamp = mApi.touchEvent.startTouchSequence(xStart, yStart, simulatedDelay, speed); - timestamp = - mApi.touchEvent.dragFromTo( - xStart, yStart, xEnd, yEnd, steps, timestamp, simulatedDelay, speed); - getApi().touchEvent.endTouchSequence(xEnd, yEnd, timestamp, simulatedDelay, speed); - } - - public void setTouchpadPosition(float xPos, float yPos) { - getApi().touchEvent.sendRawTouchEvent(xPos, yPos, 0, 0, 0); - } - - public void stopTouchingTouchpad(float xPos, float yPos) { - getApi().touchEvent.endTouchSequence(xPos, yPos, 0, 0, 0); - } - - /** - * Instantly moves the controller to the specified quaternion coordinates. - * - * @param x the x component of the quaternion. - * @param y the y component of the quaternion. - * @param z the z component of the quaternion. - * @param w the w component of the quaternion. - */ - public void moveControllerInstant(float x, float y, float z, float w) { - getApi().moveEvent.sendMoveEvent(x, y, z, w, 0); - } - - /** - * Moves the controller from one position to another over a period of time. - * - * @param startAngles the x/y/z angles to start the controller at, in radians. - * @param endAngles the x/y/z angles to end the controller at, in radians. - * @param steps the number of steps the controller will take moving between the positions. - * @param delayBetweenSteps how long to sleep between positions. - */ - public void moveControllerInterpolated( - float[] startAngles, float[] endAngles, int steps, int delayBetweenSteps) { - if (startAngles.length != 3 || endAngles.length != 3) { - throw new IllegalArgumentException("Angle arrays must be length 3"); - } - getApi().moveEvent - .sendMoveEvent( - new float[] {startAngles[0], endAngles[0]}, - new float[] {startAngles[1], endAngles[1]}, - new float[] {startAngles[2], endAngles[2]}, - steps, - delayBetweenSteps); - } -}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/GvrDaydreamReadyModuleInstallTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/GvrDaydreamReadyModuleInstallTest.java deleted file mode 100644 index ff2f9ddc..0000000 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/GvrDaydreamReadyModuleInstallTest.java +++ /dev/null
@@ -1,103 +0,0 @@ -// Copyright 2019 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.vr; - -import static org.chromium.chrome.test.util.ChromeRestriction.RESTRICTION_TYPE_DEVICE_DAYDREAM; - -import androidx.test.filters.MediumTest; - -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExternalResource; -import org.junit.rules.RuleChain; -import org.junit.runner.RunWith; - -import org.chromium.base.test.params.ParameterAnnotations.ClassParameter; -import org.chromium.base.test.params.ParameterAnnotations.UseRunnerDelegate; -import org.chromium.base.test.params.ParameterSet; -import org.chromium.base.test.params.ParameterizedRunner; -import org.chromium.base.test.util.CommandLineFlags; -import org.chromium.base.test.util.Restriction; -import org.chromium.chrome.browser.flags.ChromeSwitches; -import org.chromium.chrome.browser.vr.rules.VrModuleNotInstalled; -import org.chromium.chrome.browser.vr.rules.XrActivityRestriction; -import org.chromium.chrome.browser.vr.util.GvrTestRuleUtils; -import org.chromium.chrome.test.ChromeActivityTestRule; -import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate; -import org.chromium.components.module_installer.engine.InstallEngine; - -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.concurrent.Callable; - -/** - * End-to-end tests for installing the VR DFM on Daydream-ready phones on startup. - * - * <p>TODO(agrieve): This test may be better as a robolectric test. - */ -@RunWith(ParameterizedRunner.class) -@UseRunnerDelegate(ChromeJUnit4RunnerDelegate.class) -@CommandLineFlags.Add({ - ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, - "enable-features=LogJsConsoleMessages" -}) -public class GvrDaydreamReadyModuleInstallTest { - @ClassParameter - private static List<ParameterSet> sClassParams = - GvrTestRuleUtils.generateDefaultTestRuleParameters(); - - @Rule public RuleChain mRuleChain; - - private final Set<String> mModulesRequestedDeferred = new HashSet<>(); - - public GvrDaydreamReadyModuleInstallTest(Callable<ChromeActivityTestRule> callable) - throws Exception { - mRuleChain = - RuleChain.outerRule(new VrModuleInstallerRule()) - .around( - GvrTestRuleUtils.wrapRuleInActivityRestrictionRule( - callable.call())); - } - - /** Tests that the install is requested deferred. */ - @Test - @MediumTest - @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL}) - @Restriction({RESTRICTION_TYPE_DEVICE_DAYDREAM}) - @VrModuleNotInstalled - public void testDeferredRequestOnStartup() { - Assert.assertTrue( - "VR module should have been deferred installed at startup", - mModulesRequestedDeferred.contains("vr")); - } - - private class VrModuleInstallerRule extends ExternalResource { - private final InstallEngine mOldModuleInstaller; - private final InstallEngine mStubModuleInstaller; - - public VrModuleInstallerRule() { - mStubModuleInstaller = - new InstallEngine() { - @Override - public void installDeferred(String moduleName) { - mModulesRequestedDeferred.add(moduleName); - } - }; - mOldModuleInstaller = VrModule.getInstallEngine(); - } - - @Override - protected void before() { - VrModule.setInstallEngine(mStubModuleInstaller); - } - - @Override - protected void after() { - VrModule.setInstallEngine(mOldModuleInstaller); - } - } -}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/GvrInstallUpdateMessageTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/GvrInstallUpdateMessageTest.java deleted file mode 100644 index 5d1e59c..0000000 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/GvrInstallUpdateMessageTest.java +++ /dev/null
@@ -1,189 +0,0 @@ -// 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. - -package org.chromium.chrome.browser.vr; - -import android.content.Context; - -import androidx.test.filters.MediumTest; - -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.RuleChain; -import org.junit.runner.RunWith; - -import org.chromium.base.ContextUtils; -import org.chromium.base.test.params.ParameterAnnotations.ClassParameter; -import org.chromium.base.test.params.ParameterAnnotations.UseRunnerDelegate; -import org.chromium.base.test.params.ParameterSet; -import org.chromium.base.test.params.ParameterizedRunner; -import org.chromium.base.test.util.CommandLineFlags; -import org.chromium.chrome.browser.flags.ChromeSwitches; -import org.chromium.chrome.browser.vr.mock.MockGvrVrCoreVersionChecker; -import org.chromium.chrome.browser.vr.rules.XrActivityRestriction; -import org.chromium.chrome.browser.vr.util.GvrTestRuleUtils; -import org.chromium.chrome.browser.vr.util.VrMessageUtils; -import org.chromium.chrome.test.ChromeActivityTestRule; -import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate; -import org.chromium.chrome.vr.R; -import org.chromium.components.messages.MessageBannerProperties; -import org.chromium.content_public.browser.test.util.TestThreadUtils; -import org.chromium.ui.modelutil.PropertyModel; - -import java.util.List; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; - -/** - * End-to-end tests for the message that prompts the user to update or install VrCore (VR Services) - * when attempting to use a VR feature with an outdated or entirely missing version or other - * VR-related update prompts. - */ -@RunWith(ParameterizedRunner.class) -@UseRunnerDelegate(ChromeJUnit4RunnerDelegate.class) -@CommandLineFlags.Add({ - ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, - "enable-features=LogJsConsoleMessages" -}) -public class GvrInstallUpdateMessageTest { - @ClassParameter - private static List<ParameterSet> sClassParams = - GvrTestRuleUtils.generateDefaultTestRuleParameters(); - - @Rule public RuleChain mRuleChain; - - private ChromeActivityTestRule mVrTestRule; - - public GvrInstallUpdateMessageTest(Callable<ChromeActivityTestRule> callable) throws Exception { - mVrTestRule = callable.call(); - mRuleChain = GvrTestRuleUtils.wrapRuleInActivityRestrictionRule(mVrTestRule); - } - - /** - * Creates and sets a MockGvrVrCoreVersionCheckerImpl as the VrShellDelegate's - * VrCoreVersionChecker instance. - * - * @param compatibility An int corresponding to a VrCoreCompatibility value that the mock - * version checker will return. - * @return The MockGvrVrCoreVersionCheckerImpl that was set as VrShellDelegate's - * VrCoreVersionChecker instance. - */ - private static MockGvrVrCoreVersionChecker setVrCoreCompatibility(int compatibility) { - final MockGvrVrCoreVersionChecker mockChecker = new MockGvrVrCoreVersionChecker(); - mockChecker.setMockReturnValue(compatibility); - TestThreadUtils.runOnUiThreadBlocking( - () -> { - VrCoreInstallUtils.overrideVrCoreVersionChecker(mockChecker); - }); - Assert.assertEquals( - "Overriding VrCoreVersionChecker failed", - compatibility, - mockChecker.getLastReturnValue()); - return mockChecker; - } - - /** - * Helper function to run the tests checking for the upgrade/install message being present since - * all that differs is the value returned by VrCoreVersionChecker and a couple asserts. - * - * @param checkerReturnCompatibility The compatibility to have the VrCoreVersionChecker return. - */ - private void messageTestHelper(final int checkerReturnCompatibility) throws ExecutionException { - VrCoreInstallUtils vrCoreInstallUtils = VrCoreInstallUtils.create(0); - setVrCoreCompatibility(checkerReturnCompatibility); - TestThreadUtils.runOnUiThreadBlocking( - () -> { - vrCoreInstallUtils.requestInstallVrCore( - mVrTestRule.getActivity().getCurrentWebContents()); - }); - if (checkerReturnCompatibility == VrCoreVersionChecker.VrCoreCompatibility.VR_READY) { - VrMessageUtils.expectMessagePresent(mVrTestRule, false); - } else if (checkerReturnCompatibility - == VrCoreVersionChecker.VrCoreCompatibility.VR_OUT_OF_DATE - || checkerReturnCompatibility - == VrCoreVersionChecker.VrCoreCompatibility.VR_NOT_AVAILABLE) { - // Out of date and missing cases are the same, but with different text - String expectedTitle; - String expectedButton; - Context context = ContextUtils.getApplicationContext(); - if (checkerReturnCompatibility - == VrCoreVersionChecker.VrCoreCompatibility.VR_OUT_OF_DATE) { - expectedTitle = context.getString(R.string.vr_services_check_message_update_title); - expectedButton = - context.getString(R.string.vr_services_check_message_update_button); - } else { - expectedTitle = context.getString(R.string.vr_services_check_message_install_title); - expectedButton = - context.getString(R.string.vr_services_check_message_install_button); - } - PropertyModel message = VrMessageUtils.getVrInstallUpdateMessage(mVrTestRule); - Assert.assertNotNull("VR install/update message should be present.", message); - - Assert.assertEquals( - "VR install/update message text did not match expectation.", - expectedTitle, - message.get(MessageBannerProperties.TITLE)); - Assert.assertEquals( - "VR install/update message description did not match expectation.", - context.getString(R.string.vr_services_check_message_description), - message.get(MessageBannerProperties.DESCRIPTION)); - Assert.assertEquals( - "VR install/update message button text did not match expectation.", - expectedButton, - message.get(MessageBannerProperties.PRIMARY_BUTTON_TEXT)); - } else if (checkerReturnCompatibility - == VrCoreVersionChecker.VrCoreCompatibility.VR_NOT_SUPPORTED) { - VrMessageUtils.expectMessagePresent(mVrTestRule, false); - } else { - Assert.fail( - "Invalid VrCoreVersionChecker compatibility: " + checkerReturnCompatibility); - } - VrCoreInstallUtils.overrideVrCoreVersionChecker(null); - } - - /** - * Tests that the upgrade/install VR Services message is not present when VR Services is - * installed and up to date. - */ - @Test - @MediumTest - @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL}) - public void testMessageNotPresentWhenVrServicesCurrent() throws ExecutionException { - messageTestHelper(VrCoreVersionChecker.VrCoreCompatibility.VR_READY); - } - - /** Tests that the upgrade VR Services message is present when VR Services is outdated. */ - @Test - @MediumTest - @XrActivityRestriction({ - XrActivityRestriction.SupportedActivity.CTA, - XrActivityRestriction.SupportedActivity.CCT - }) - public void testMessagePresentWhenVrServicesOutdated() throws ExecutionException { - messageTestHelper(VrCoreVersionChecker.VrCoreCompatibility.VR_OUT_OF_DATE); - } - - /** Tests that the install VR Services message is present when VR Services is missing. */ - @Test - @MediumTest - @XrActivityRestriction({ - XrActivityRestriction.SupportedActivity.CTA, - XrActivityRestriction.SupportedActivity.CCT - }) - public void testMessagePresentWhenVrServicesMissing() throws ExecutionException { - messageTestHelper(VrCoreVersionChecker.VrCoreCompatibility.VR_NOT_AVAILABLE); - } - - /** - * Tests that the install VR Services message is not present when VR is not supported on the - * device. - */ - @Test - @MediumTest - @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL}) - public void testMessageNotPresentWhenVrServicesNotSupported() throws ExecutionException { - messageTestHelper(VrCoreVersionChecker.VrCoreCompatibility.VR_NOT_SUPPORTED); - } -}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/README.md b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/README.md index 01cafcae..7be567d 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/README.md +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/README.md
@@ -3,20 +3,18 @@ ## TL;DR For Most Local Repros 1. Get a rooted Pixel device of some sort. -2. Make sure "VR Services" is up to date in the Playstore. -3. Set lock screen timeout to at least 5 minutes. If screen is locked or device +2. Set lock screen timeout to at least 5 minutes. If screen is locked or device goes to sleep while tests are still running, they will fail. -4. Run `ninja -C out/Debug chrome_public_test_vr_apk +3. Run `ninja -C out/Debug chrome_public_test_vr_apk && out/Debug/bin/run_chrome_public_test_vr_apk --num-retries=0 - --shared-prefs-file=//chrome/android/shared_preference_files/test/vr_ddview_skipdon_setupcomplete.json --test-filter=<failing test case>` Don't touch phone while the tests are running. If you are reproducing an issue with the AR tests, run `export DOWNLOAD_XR_TEST_APKS=1 && gclient runhooks` in order to get the playback datasets that are necessary. This requires authentication, run -`gsutil.py config` [documentation](https://chromium.googlesource.com/chromiumos/docs/+/main/gsutil.md) +`gsutil.py config` [documentation](https://chromium.googlesource.com/chromiumos/docs/+/main/gsutil.md) to set this up if necessary. **NOTE** The message "Main Unable to find package info for org.chromium.chrome" @@ -39,7 +37,6 @@ ### Subdirectories -* `mock/` - Contains all the classes for mock implementations of XR classes. * `rules/` - Contains all the XR-specific JUnit4 rules for handling functionality such as running tests multiple times in different activities and handling the fake VR pose tracker service. @@ -48,18 +45,8 @@ ### Other Directories -* [`//chrome/android/shared_preferences_files/test`][shared_prefs_dir] - -Contains the VrCore settings files for running VR instrumentation tests (see the -"Building and Running" section for more information). * [`//chrome/test/data/xr/e2e_test_files/`][html_dir] - Contains the JavaScript and HTML files for XR instrumentation tests. -* [`//third_party/gvr-android-sdk/test-apks`][vr_test_apks] - Contains the VR -APKs used for testing, such as VrCore. You must have `DOWNLOAD_XR_TEST_APKS` set -as an environment variable when you run gclient runhooks in order to actually -download these from storage. -* [`//third_party/gvr-android-sdk/test-libraries`][vr_test_libraries] - Contains -third party VR testing libraries. Currently, only has the Daydream controller -test library used for sending controller events to VrCore using intents. * [`//third_party/arcore-android-sdk/test-apks`][ar_test_apks] - Contains the AR APKs used for testing, such as ArCore. You must have `DOWNLOAD_XR_TEST_APKS` set as an environment variable when you run gclient runhooks in order to actually @@ -96,19 +83,10 @@ Installs the specified APK before running the tests. No-ops if the provided APK is already installed on the device and their versions match. -For VR tests, you'll likely want to use `--additional-apk -third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk` to -ensure that the VrCore version used is the one used for automated testing at -whatever your current git revision is. +**NOTE** Using this argument for pre-installed system apps will fail. This can +be dealt with in the following ways: -**NOTE** Using this argument for VR on most Pixel devices will fail, as VrCore -is pre-installed as a system app. This can be dealt with in the following ways: - -* Remove VrCore as a system app by following the instructions - [here](go/vrcore/building-and-running). This will permanently solve the issue - unless you reflash your device. -* Use `--replace-system-package - //third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk` +* Use `--replace-system-package path/to/apk/to/install` instead. This will take significantly longer, as it requires rebooting, and must be done every time you run the tests. * Skip this argument entirely and just ensure that the VrCore version on the @@ -147,44 +125,12 @@ is 0, resulting in only one iteration. Usually used to repeat a test many times in order to check for or reproduce flakiness. -### VR-Specific Arguments - -#### shared-prefs-file - -`--shared-prefs-file path/to/preference/json/file` - -Configures VrCore according to the provided file, e.g. changing the paired -headset. The currently supported files are: - -* `//chrome/android/shared_preference_files/test/vr_cardboard_skipdon_setupcomplete.json` - will cause all cardboard-compatible tests to run. This will pair the device - with a Cardboard headset and disable controller emulation. -* `//chrome/android/shared_preference_files/test/vr_ddview_skipdon_setupcomplete.json` - will cause most Daydream View-compatible tests to run, with the exception of - those that require the DON flow to be enabled. This will pair the device with - a Daydream View headset, set the DON flow to be skipped, and enable controller - emulation. -* `//chrome/android/shared_preference_files/test/vr_ddview_don_setupcomplete.json` - combined with the extra `--vr-don-enabled` and - `--annotation=Restriction=VR_DON_Enabled` flags will cause all tests that - are using the `RESTRICTION_TYPE_VR_DON_ENABLED` restriction to run. This runs - tests that expect to have the DON flow enabled. - -The test runner will automatically revert any changed settings back to their -pre-test values after the test suite has completed. If for whatever reason you -want to manually apply settings outside of a test, you can do so with -`//build/android/apply_shared_preference_file.py`. - ## Adding New Tests See [adding_new_tests.md][adding_new_tests]. [webxr_spec]: https://immersive-web.github.io/webxr-samples/explainer.html -[shared_prefs_dir]: -https://chromium.googlesource.com/chromium/src/+/main/chrome/android/shared_preference_files/test [html_dir]: https://chromium.googlesource.com/chromium/src/+/main/chrome/test/data/xr/e2e_test_files -[vr_test_apks]: https://chromium.googlesource.com/chromium/src/+/main/third_party/gvr-android-sdk/test-apks -[vr_test_libraries]: https://chromium.googlesource.com/chromium/src/+/main/third_party/gvr-android-sdk/test-libraries [ar_test_apks]: https://chromium.googlesource.com/chromium/src/+/main/third_party/arcore-android-sdk/test-apks [adding_new_tests]: https://chromium.googlesource.com/chromium/src/+/main/chrome/android/javatests/src/org/chromium/chrome/browser/vr/adding_new_tests.md
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/TestVrShellDelegate.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/TestVrShellDelegate.java deleted file mode 100644 index efca24d2..0000000 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/TestVrShellDelegate.java +++ /dev/null
@@ -1,97 +0,0 @@ -// 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. - -package org.chromium.chrome.browser.vr; - -import org.junit.runner.Description; - -import org.chromium.chrome.browser.app.ChromeActivity; -import org.chromium.chrome.browser.vr.rules.VrModuleNotInstalled; -import org.chromium.content_public.browser.test.util.TestThreadUtils; - -/** - * Class for accessing VrShellDelegate internals for testing purposes. This does two things: - - * Prevents us from needing @VisibleForTesting annotations everywhere in production code. - Allows - * us to have test-specific behavior if necessary without changing production code. - */ -public class TestVrShellDelegate extends VrShellDelegate { - private Runnable mOnVSyncPausedCallback; - private static TestVrShellDelegate sInstance; - private static Description sTestDescription; - private boolean mExpectingBroadcast; - private boolean mExpectingIntent; - private Boolean mAllow2dIntents; - - public static void createTestVrShellDelegate(final ChromeActivity activity) { - // Cannot make VrShellDelegate if we are faking that the VR module is not installed. - if (sTestDescription.getAnnotation(VrModuleNotInstalled.class) != null) return; - if (sInstance != null) return; - TestThreadUtils.runOnUiThreadBlocking( - () -> { - sInstance = new TestVrShellDelegate(activity); - }); - } - - // TODO(bsheedy): Maybe remove this and switch to setting a VrShellDelegateFactory instead. - public static void setDescription(Description desc) { - sTestDescription = desc; - } - - public static TestVrShellDelegate getInstance() { - return sInstance; - } - - public static VrShell getVrShellForTesting() { - return TestVrShellDelegate.getInstance().getVrShell(); - } - - public static void enableTestVrShellDelegateOnStartupForTesting() { - VrShellDelegate.enableTestVrShellDelegateOnStartupForTesting(); - } - - protected TestVrShellDelegate(ChromeActivity activity) { - super(activity); - } - - public void overrideDaydreamApiForTesting(VrDaydreamApi api) { - super.overrideDaydreamApi(api); - } - - @Override - public boolean isVrEntryComplete() { - return super.isVrEntryComplete(); - } - - public void setVrShellOnVSyncPausedCallback(Runnable callback) { - mOnVSyncPausedCallback = callback; - } - - /** - * The same as the production onResume, except that we set a boolean to avoid cancelling VR - * entry when we think we're in the DON flow. This is caused by crbug.com/762724. TODO(bsheedy): - * Remove this when the root cause is fixed. - */ - @Override - protected void onResume() { - if (mExpectingIntent || mExpectingBroadcast) { - mTestWorkaroundDontCancelVrEntryOnResume = true; - } - super.onResume(); - mTestWorkaroundDontCancelVrEntryOnResume = false; - } - - /** - * If we need to know when the normal VSync gets paused, we have a small window between when the - * VrShell is created and we actually enter VR to set the callback. So, do it immediately after - * creation here. - */ - @Override - protected boolean createVrShell() { - boolean result = super.createVrShell(); - if (result && mOnVSyncPausedCallback != null) { - getVrShellForTesting().setOnVSyncPausedForTesting(mOnVSyncPausedCallback); - } - return result; - } -}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrGvrDeviceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrGvrDeviceTest.java deleted file mode 100644 index c3769d2..0000000 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrGvrDeviceTest.java +++ /dev/null
@@ -1,73 +0,0 @@ -// 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. - -package org.chromium.chrome.browser.vr; - -import static org.chromium.chrome.browser.vr.XrTestFramework.PAGE_LOAD_TIMEOUT_S; - -import androidx.test.filters.MediumTest; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.RuleChain; -import org.junit.runner.RunWith; - -import org.chromium.base.test.params.ParameterAnnotations.ClassParameter; -import org.chromium.base.test.params.ParameterAnnotations.UseRunnerDelegate; -import org.chromium.base.test.params.ParameterSet; -import org.chromium.base.test.params.ParameterizedRunner; -import org.chromium.base.test.util.CommandLineFlags; -import org.chromium.chrome.browser.flags.ChromeSwitches; -import org.chromium.chrome.browser.vr.rules.XrActivityRestriction; -import org.chromium.chrome.browser.vr.util.GvrTestRuleUtils; -import org.chromium.chrome.test.ChromeActivityTestRule; -import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate; - -import java.util.List; -import java.util.concurrent.Callable; - -/** - * End-to-end tests for WebXR where the choice of test device has a greater impact than the usual - * Daydream-ready vs. non-Daydream-ready effect. - */ -@RunWith(ParameterizedRunner.class) -@UseRunnerDelegate(ChromeJUnit4RunnerDelegate.class) -@CommandLineFlags.Add({ - ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, - "enable-features=LogJsConsoleMessages", - "force-webxr-runtime=gvr" -}) -public class WebXrGvrDeviceTest { - @ClassParameter - private static List<ParameterSet> sClassParams = - GvrTestRuleUtils.generateDefaultTestRuleParameters(); - - @Rule public RuleChain mRuleChain; - - private ChromeActivityTestRule mTestRule; - private WebXrGvrTestFramework mWebXrVrTestFramework; - - public WebXrGvrDeviceTest(Callable<ChromeActivityTestRule> callable) throws Exception { - mTestRule = callable.call(); - mRuleChain = GvrTestRuleUtils.wrapRuleInActivityRestrictionRule(mTestRule); - } - - @Before - public void setUp() { - mWebXrVrTestFramework = new WebXrGvrTestFramework(mTestRule); - } - - /** Tests that reported WebXR capabilities match expectations. */ - @Test - @MediumTest - @CommandLineFlags.Add({"enable-features=WebXR"}) - @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL}) - public void testWebXrCapabilities() { - mWebXrVrTestFramework.loadFileAndAwaitInitialization( - "test_webxr_capabilities", PAGE_LOAD_TIMEOUT_S); - mWebXrVrTestFramework.executeStepAndWait("stepCheckCapabilities()"); - mWebXrVrTestFramework.endTest(); - } -}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrGvrInputTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrGvrInputTest.java deleted file mode 100644 index e70eca6..0000000 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrGvrInputTest.java +++ /dev/null
@@ -1,427 +0,0 @@ -// 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. - -package org.chromium.chrome.browser.vr; - -import static org.chromium.chrome.browser.vr.XrTestFramework.PAGE_LOAD_TIMEOUT_S; -import static org.chromium.chrome.browser.vr.XrTestFramework.POLL_TIMEOUT_LONG_MS; -import static org.chromium.chrome.browser.vr.XrTestFramework.POLL_TIMEOUT_SHORT_MS; -import static org.chromium.chrome.test.util.ChromeRestriction.RESTRICTION_TYPE_VIEWER_DAYDREAM; -import static org.chromium.chrome.test.util.ChromeRestriction.RESTRICTION_TYPE_VIEWER_NON_DAYDREAM; - -import android.os.Build; -import android.os.Build.VERSION_CODES; -import android.os.SystemClock; -import android.view.MotionEvent; -import android.view.View; - -import androidx.test.filters.MediumTest; - -import org.junit.Assert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.RuleChain; -import org.junit.runner.RunWith; - -import org.chromium.base.test.params.ParameterAnnotations.ClassParameter; -import org.chromium.base.test.params.ParameterAnnotations.UseRunnerDelegate; -import org.chromium.base.test.params.ParameterSet; -import org.chromium.base.test.params.ParameterizedRunner; -import org.chromium.base.test.util.CommandLineFlags; -import org.chromium.base.test.util.DisableIf; -import org.chromium.base.test.util.Restriction; -import org.chromium.chrome.browser.flags.ChromeSwitches; -import org.chromium.chrome.browser.vr.rules.XrActivityRestriction; -import org.chromium.chrome.browser.vr.util.GvrTestRuleUtils; -import org.chromium.chrome.test.ChromeActivityTestRule; -import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate; -import org.chromium.content_public.browser.test.util.TestThreadUtils; -import org.chromium.content_public.browser.test.util.TouchCommon; - -import java.util.List; -import java.util.Locale; -import java.util.concurrent.Callable; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -/** End-to-end tests for sending input while using WebXR. */ -@RunWith(ParameterizedRunner.class) -@UseRunnerDelegate(ChromeJUnit4RunnerDelegate.class) -// TODO(crbug.com/1192004): Remove --allow-pre-commit-input once the root cause of the -// failures has been fixed. -@CommandLineFlags.Add({ - ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, - "enable-features=LogJsConsoleMessages", - "allow-pre-commit-input", - "force-webxr-runtime=gvr" -}) -public class WebXrGvrInputTest { - @ClassParameter - private static List<ParameterSet> sClassParams = - GvrTestRuleUtils.generateDefaultTestRuleParameters(); - - @Rule public RuleChain mRuleChain; - - private ChromeActivityTestRule mTestRule; - private WebXrGvrTestFramework mWebXrVrTestFramework; - - public WebXrGvrInputTest(Callable<ChromeActivityTestRule> callable) throws Exception { - mTestRule = callable.call(); - mRuleChain = GvrTestRuleUtils.wrapRuleInActivityRestrictionRule(mTestRule); - } - - @Before - public void setUp() { - mWebXrVrTestFramework = new WebXrGvrTestFramework(mTestRule); - } - - private void assertAppButtonEffect(boolean shouldHaveExited, WebXrGvrTestFramework framework) { - Assert.assertEquals( - "App button effect matched expectation", - shouldHaveExited, - mWebXrVrTestFramework.pollJavaScriptBoolean( - "sessionInfos[sessionTypes.IMMERSIVE].currentSession == null", - POLL_TIMEOUT_SHORT_MS)); - } - - /** - * Tests that screen touches are not registered when in an immersive session. Disabled on - * standalones because they don't have touchscreens. - */ - @Test - @MediumTest - @CommandLineFlags.Add({"enable-features=WebXR"}) - @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL}) - @DisableIf.Build( - sdk_is_less_than = Build.VERSION_CODES.O, - message = "https://crbug.com/1409794") - public void testScreenTapsNotRegistered_WebXr() throws InterruptedException { - screenTapsNotRegisteredImpl("webxr_test_screen_taps_not_registered", mWebXrVrTestFramework); - } - - private void screenTapsNotRegisteredImpl(String url, final WebXrGvrTestFramework framework) - throws InterruptedException { - framework.loadFileAndAwaitInitialization(url, PAGE_LOAD_TIMEOUT_S); - framework.executeStepAndWait("stepVerifyNoInitialTaps()"); - framework.enterSessionWithUserGestureOrFail(); - // Wait on VrShell to say that its parent consumed the touch event. - // Set to 2 because there's an ACTION_DOWN followed by ACTION_UP - final CountDownLatch touchRegisteredLatch = new CountDownLatch(2); - TestVrShellDelegate.getVrShellForTesting() - .setOnDispatchTouchEventForTesting( - new OnDispatchTouchEventCallback() { - @Override - public void onDispatchTouchEvent(boolean parentConsumed) { - if (!parentConsumed) Assert.fail("Parent did not consume event"); - touchRegisteredLatch.countDown(); - } - }); - TouchCommon.singleClickView(mTestRule.getActivity().getWindow().getDecorView()); - Assert.assertTrue( - "VrShell did not dispatch touches", - touchRegisteredLatch.await(POLL_TIMEOUT_LONG_MS * 10, TimeUnit.MILLISECONDS)); - framework.executeStepAndWait("stepVerifyNoAdditionalTaps()"); - framework.endTest(); - } - - /** Tests that Daydream controller clicks are registered as XR input in an immersive session. */ - @Test - @MediumTest - @Restriction(RESTRICTION_TYPE_VIEWER_DAYDREAM) - @CommandLineFlags.Add({"enable-features=WebXR"}) - @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL}) - @DisableIf.Build( - sdk_is_greater_than = VERSION_CODES.P, - sdk_is_less_than = VERSION_CODES.R, - message = "Flaky on android-10-arm64-rel, crbug.com/1455242") - public void testControllerClicksRegisteredOnDaydream_WebXr() { - EmulatedGvrController controller = new EmulatedGvrController(mTestRule.getActivity()); - mWebXrVrTestFramework.loadFileAndAwaitInitialization( - "test_webxr_input", PAGE_LOAD_TIMEOUT_S); - mWebXrVrTestFramework.enterSessionWithUserGestureOrFail(); - - int numIterations = 10; - mWebXrVrTestFramework.runJavaScriptOrFail( - "stepSetupListeners(" + String.valueOf(numIterations) + ")", POLL_TIMEOUT_SHORT_MS); - - // Click the touchpad a bunch of times and make sure they're all registered. - for (int i = 0; i < numIterations; i++) { - controller.sendClickButtonToggleEvent(); - controller.sendClickButtonToggleEvent(); - // The controller emulation can sometimes deliver controller input at weird times such - // that we only register 8 or 9 of the 10 press/release pairs. So, send a press/release - // and wait for it to register before doing another. - mWebXrVrTestFramework.waitOnJavaScriptStep(); - } - - mWebXrVrTestFramework.endTest(); - } - - /** - * Tests that Daydream controller is exposed as a Gamepad on an XRInputSource in an immersive - * session and that button clicks and touchpad movements are registered. - */ - @Test - @MediumTest - @Restriction(RESTRICTION_TYPE_VIEWER_DAYDREAM) - @CommandLineFlags.Add({"enable-features=WebXR"}) - @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL}) - @DisableIf.Build( - sdk_is_greater_than = VERSION_CODES.P, - sdk_is_less_than = VERSION_CODES.R, - message = "https://crbug.com/1420205") - public void testControllerExposedAsGamepadOnDaydream_WebXr() { - EmulatedGvrController controller = new EmulatedGvrController(mTestRule.getActivity()); - mWebXrVrTestFramework.loadFileAndAwaitInitialization( - "test_webxr_gamepad_support", PAGE_LOAD_TIMEOUT_S); - mWebXrVrTestFramework.enterSessionWithUserGestureOrFail(); - - // There must be interaction with the controller before an XRInputSource - // is recognized. Wait for JS to register the select event to avoid a - // race condition. - mWebXrVrTestFramework.runJavaScriptOrFail("stepSetupListeners()", POLL_TIMEOUT_SHORT_MS); - controller.sendClickButtonToggleEvent(); - controller.sendClickButtonToggleEvent(); - mWebXrVrTestFramework.pollJavaScriptBooleanOrFail("selectCount > 0", POLL_TIMEOUT_SHORT_MS); - - // Daydream controller should not be 'xr-standard' mapping since it does - // not meet the requirements. - mWebXrVrTestFramework.pollJavaScriptBooleanOrFail( - "isMappingEqualTo('')", POLL_TIMEOUT_SHORT_MS); - - // Daydream controller should only expose a single button and set of - // input axes (the pressable touchpad). It should not expose any of the - // platform buttons such as "home" or "back". - mWebXrVrTestFramework.pollJavaScriptBooleanOrFail( - "isButtonCountEqualTo(1)", POLL_TIMEOUT_SHORT_MS); - mWebXrVrTestFramework.pollJavaScriptBooleanOrFail( - "isAxisPairCountEqualTo(1)", POLL_TIMEOUT_SHORT_MS); - - // Initially, the touchpad should not be touched. - validateTouchpadNotTouched(); - - // Make sure pressing the touchpad button works. - controller.sendClickButtonToggleEvent(); - mWebXrVrTestFramework.pollJavaScriptBooleanOrFail( - "isButtonPressedEqualTo(0, true)", POLL_TIMEOUT_SHORT_MS); - controller.sendClickButtonToggleEvent(); - mWebXrVrTestFramework.pollJavaScriptBooleanOrFail( - "isButtonPressedEqualTo(0, false)", POLL_TIMEOUT_SHORT_MS); - - // Make sure setting the touchpad position works. - setAndValidateTouchpadPosition(controller, 0.0f, 1.0f); - setAndValidateTouchpadPosition(controller, 1.0f, 0.0f); - setAndValidateTouchpadPosition(controller, 0.5f, 0.5f); - - controller.stopTouchingTouchpad(0.5f, 0.5f); - validateTouchpadNotTouched(); - - mWebXrVrTestFramework.runJavaScriptOrFail("done()", POLL_TIMEOUT_SHORT_MS); - mWebXrVrTestFramework.endTest(); - } - - // When touchpad is not touched, it should not be reported as pressed - // either. The input axis values should be at the origin: (0, 0). - private void validateTouchpadNotTouched() { - mWebXrVrTestFramework.pollJavaScriptBooleanOrFail( - "isButtonTouchedEqualTo(0, false)", POLL_TIMEOUT_SHORT_MS); - mWebXrVrTestFramework.pollJavaScriptBooleanOrFail( - "isButtonPressedEqualTo(0, false)", POLL_TIMEOUT_SHORT_MS); - mWebXrVrTestFramework.pollJavaScriptBooleanOrFail( - "areAxesValuesEqualTo(0, 0.0, 0.0)", POLL_TIMEOUT_SHORT_MS); - } - - // Device code reports touchpad position in range [0.0, 1.0]. - // WebXR reports Gamepad input axis position in range [-1.0, 1.0]. - private float rawToWebXRTouchpadPosition(float raw) { - return (raw * 2.0f) - 1.0f; - } - - private void setAndValidateTouchpadPosition( - EmulatedGvrController controller, float x, float y) { - controller.setTouchpadPosition(x, y); - float xExpected = rawToWebXRTouchpadPosition(x); - float yExpected = rawToWebXRTouchpadPosition(y); - String js = - String.format(Locale.US, "areAxesValuesEqualTo(0, %f, %f)", xExpected, yExpected); - mWebXrVrTestFramework.pollJavaScriptBooleanOrFail(js, POLL_TIMEOUT_SHORT_MS); - mWebXrVrTestFramework.pollJavaScriptBooleanOrFail( - "isButtonTouchedEqualTo(0, true)", POLL_TIMEOUT_SHORT_MS); - } - - private long sendScreenTouchDown(final View view, final int x, final int y) { - long downTime = SystemClock.uptimeMillis(); - TestThreadUtils.runOnUiThreadBlocking( - () -> { - view.dispatchTouchEvent( - MotionEvent.obtain( - downTime, downTime, MotionEvent.ACTION_DOWN, x, y, 0)); - }); - return downTime; - } - - private void sendScreenTouchUp(final View view, final int x, final int y, final long downTime) { - TestThreadUtils.runOnUiThreadBlocking( - () -> { - long now = SystemClock.uptimeMillis(); - view.dispatchTouchEvent( - MotionEvent.obtain(downTime, now, MotionEvent.ACTION_UP, x, y, 0)); - }); - } - - private void spamScreenTaps(final View view, final int x, final int y, final int iterations) { - // Tap the screen a bunch of times. - // Android doesn't seem to like sending touch events too quickly, so have a short delay - // between events. - for (int i = 0; i < iterations; i++) { - sendScreenTap(view, x, y); - } - } - - private void sendScreenTap(final View view, final int x, final int y) { - long downTime = sendScreenTouchDown(view, x, y); - SystemClock.sleep(100); - sendScreenTouchUp(view, x, y, downTime); - SystemClock.sleep(100); - } - - /** - * Tests that screen touches are registered as XR input in immersive sessions, when the viewer - * is Cardboard. - */ - @Test - @MediumTest - @Restriction(RESTRICTION_TYPE_VIEWER_NON_DAYDREAM) - @CommandLineFlags.Add({"enable-features=WebXR"}) - @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL}) - public void testScreenTapsRegisteredOnCardboard_WebXr() { - mWebXrVrTestFramework.loadFileAndAwaitInitialization( - "test_webxr_input", PAGE_LOAD_TIMEOUT_S); - mWebXrVrTestFramework.enterSessionWithUserGestureOrFail(); - - // TODO(mthiesse, https://crbug.com/758374): Injecting touch events into the root GvrLayout - // (VrShell) is flaky. Sometimes the events just don't get routed to the presentation - // view for no apparent reason. We should figure out why this is and see if it's fixable. - // Note that we only use 5 iterations, vs the 10 used in the inline test, because it seems - // that on M, we get enough memory pressure that the yet-to-be-processed taps get GC'd. - // See https://crbug.com/1194906 for more details. - testScreenTapsRegisteredOnCardboardImpl( - TestVrShellDelegate.getVrShellForTesting().getPresentationViewForTesting(), 5); - } - - /** - * Tests that screen touches are registered as transient XR input in inline sessions, when the - * viewer is Cardboard. - */ - @Test - @MediumTest - @Restriction(RESTRICTION_TYPE_VIEWER_NON_DAYDREAM) - @CommandLineFlags.Add({"enable-features=WebXR"}) - @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL}) - public void testTransientScreenTapsRegisteredOnCardboard_WebXr() { - mWebXrVrTestFramework.loadFileAndAwaitInitialization( - "test_webxr_transient_input", PAGE_LOAD_TIMEOUT_S); - - testScreenTapsRegisteredOnCardboardImpl(mWebXrVrTestFramework.getCurrentContentView(), 10); - } - - // Note that the page should load the appropriate test page and enter any relevant session - // before calling this. - private void testScreenTapsRegisteredOnCardboardImpl(View presentationView, int numIterations) { - mWebXrVrTestFramework.runJavaScriptOrFail( - "stepSetupListeners(" + String.valueOf(numIterations) + ")", POLL_TIMEOUT_SHORT_MS); - - int x = presentationView.getWidth() / 2; - int y = presentationView.getHeight() / 2; - - // Tap the screen a bunch of times and make sure that they're all registered. Ideally, we - // shouldn't have to ack each one, but it's possible for inputs to get eaten by garbage - // collection if there are multiple in flight, so only send one at a time. - for (int i = 0; i < numIterations; i++) { - sendScreenTap(presentationView, x, y); - mWebXrVrTestFramework.waitOnJavaScriptStep(); - } - - mWebXrVrTestFramework.endTest(); - } - - /** - * Tests that focus is locked to the device with an immersive session for the purposes of VR - * input. - */ - @Test - @MediumTest - @CommandLineFlags.Add({"enable-features=WebXR"}) - @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL}) - public void testPresentationLocksFocus_WebXr() { - presentationLocksFocusImpl("webxr_test_presentation_locks_focus", mWebXrVrTestFramework); - } - - private void presentationLocksFocusImpl(String url, WebXrGvrTestFramework framework) { - framework.loadFileAndAwaitInitialization(url, PAGE_LOAD_TIMEOUT_S); - framework.enterSessionWithUserGestureOrFail(); - framework.executeStepAndWait("stepSetupFocusLoss()"); - framework.endTest(); - } - - /** - * Verifies that a Gamepad API gamepad is returned on the XRSession's input source instead of - * the navigator array when using WebXR and a Daydream headset. - */ - @Test - @MediumTest - @Restriction(RESTRICTION_TYPE_VIEWER_DAYDREAM) - @CommandLineFlags.Add({"enable-features=WebXR"}) - @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL}) - public void testWebXrInputSourceHasGamepad() { - webxrGamepadSupportImpl(/* daydream= */ true); - } - - /** - * Verifies that the XRSession has an input source when using WebXR and Cardboard. There should - * be no gamepads on the input source or navigator array. - */ - @Test - @MediumTest - @Restriction(RESTRICTION_TYPE_VIEWER_NON_DAYDREAM) - @CommandLineFlags.Add({"enable-features=WebXR"}) - @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL}) - public void testWebXrInputSourceWithoutGamepad_Cardboard() { - webxrGamepadSupportImpl(/* daydream= */ false); - } - - private void webxrGamepadSupportImpl(boolean daydream) { - mWebXrVrTestFramework.loadFileAndAwaitInitialization( - "test_webxr_gamepad_support", PAGE_LOAD_TIMEOUT_S); - mWebXrVrTestFramework.enterSessionWithUserGestureOrFail(); - - // Spam input to make sure the Gamepad API registers the gamepad if it should. - int numIterations = 10; - if (daydream) { - EmulatedGvrController controller = new EmulatedGvrController(mTestRule.getActivity()); - for (int i = 0; i < numIterations; i++) { - controller.performControllerClick(); - } - - // Verify that there is a gamepad on the XRInputSource and that it - // has the expected mapping of '' (the Daydream controller does not - // meet the 'xr-standard' mapping requirements). - mWebXrVrTestFramework.pollJavaScriptBooleanOrFail( - "isMappingEqualTo('')", POLL_TIMEOUT_SHORT_MS); - } else { - int x = mWebXrVrTestFramework.getCurrentContentView().getWidth() / 2; - int y = mWebXrVrTestFramework.getCurrentContentView().getHeight() / 2; - View presentationView = - TestVrShellDelegate.getVrShellForTesting().getPresentationViewForTesting(); - spamScreenTaps(presentationView, x, y, numIterations); - - mWebXrVrTestFramework.pollJavaScriptBooleanOrFail( - "inputSourceHasNoGamepad()", POLL_TIMEOUT_SHORT_MS); - } - - mWebXrVrTestFramework.runJavaScriptOrFail("done()", POLL_TIMEOUT_SHORT_MS); - mWebXrVrTestFramework.endTest(); - } -}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrGvrPermissionTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrGvrPermissionTest.java deleted file mode 100644 index d6d4aee..0000000 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrGvrPermissionTest.java +++ /dev/null
@@ -1,147 +0,0 @@ -// Copyright 2019 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.vr; - -import static org.chromium.chrome.browser.vr.XrTestFramework.PAGE_LOAD_TIMEOUT_S; -import static org.chromium.chrome.browser.vr.XrTestFramework.POLL_TIMEOUT_LONG_MS; -import static org.chromium.chrome.browser.vr.XrTestFramework.POLL_TIMEOUT_SHORT_MS; - -import android.os.Build.VERSION_CODES; - -import androidx.test.filters.MediumTest; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.RuleChain; -import org.junit.runner.RunWith; - -import org.chromium.base.test.params.ParameterAnnotations.ClassParameter; -import org.chromium.base.test.params.ParameterAnnotations.UseRunnerDelegate; -import org.chromium.base.test.params.ParameterSet; -import org.chromium.base.test.params.ParameterizedRunner; -import org.chromium.base.test.util.CommandLineFlags; -import org.chromium.base.test.util.DisableIf; -import org.chromium.chrome.browser.flags.ChromeSwitches; -import org.chromium.chrome.browser.vr.rules.XrActivityRestriction; -import org.chromium.chrome.browser.vr.util.GvrTestRuleUtils; -import org.chromium.chrome.test.ChromeActivityTestRule; -import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate; - -import java.util.List; -import java.util.concurrent.Callable; - -/** End-to-end tests for various scenarios around when the permission prompt is expected. */ -@RunWith(ParameterizedRunner.class) -@UseRunnerDelegate(ChromeJUnit4RunnerDelegate.class) -// TODO(crbug.com/1192004): Remove --allow-pre-commit-input once the root cause of the -// failures has been fixed. -@CommandLineFlags.Add({ - ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, - "enable-features=WebXR,LogJsConsoleMessages", - "allow-pre-commit-input", - "force-webxr-runtime=gvr" -}) -@DisableIf.Build( - sdk_is_greater_than = VERSION_CODES.P, - sdk_is_less_than = VERSION_CODES.R, - message = "Flaky on android-10-arm64-rel, crbug.com/1455244") -public class WebXrGvrPermissionTest { - @ClassParameter - private static List<ParameterSet> sClassParams = - GvrTestRuleUtils.generateDefaultTestRuleParameters(); - - @Rule public RuleChain mRuleChain; - - private ChromeActivityTestRule mTestRule; - private WebXrVrPermissionTestFramework mWebXrVrPermissionTestFramework; - - public WebXrGvrPermissionTest(Callable<ChromeActivityTestRule> callable) throws Exception { - mTestRule = callable.call(); - mRuleChain = GvrTestRuleUtils.wrapRuleInActivityRestrictionRule(mTestRule); - } - - @Before - public void setUp() { - mWebXrVrPermissionTestFramework = new WebXrVrPermissionTestFramework(mTestRule); - } - - /** Tests that denying permission blocks the session from being created. */ - @Test - @MediumTest - @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL}) - public void testPermissionDenyFailsSessionCreation() { - mWebXrVrPermissionTestFramework.setPermissionPromptAction( - WebXrVrTestFramework.PERMISSION_PROMPT_ACTION_DENY); - mWebXrVrPermissionTestFramework.setPermissionPromptExpected(true); - - mWebXrVrPermissionTestFramework.loadFileAndAwaitInitialization( - "test_webxr_permission", PAGE_LOAD_TIMEOUT_S); - - mWebXrVrPermissionTestFramework.enterSessionWithUserGesture(); - mWebXrVrPermissionTestFramework.pollJavaScriptBooleanOrFail( - "sessionInfos[sessionTypes.IMMERSIVE].error != null", POLL_TIMEOUT_LONG_MS); - mWebXrVrPermissionTestFramework.runJavaScriptOrFail( - "verifyPermissionDeniedError(sessionTypes.IMMERSIVE)", POLL_TIMEOUT_SHORT_MS); - mWebXrVrPermissionTestFramework.assertNoJavaScriptErrors(); - } - - /** - * Tests that attempting to enter a session that requires the same permission level/type does - * not reprompt. - */ - @Test - @MediumTest - @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL}) - public void testVrPermissionPersistance() { - mWebXrVrPermissionTestFramework.loadFileAndAwaitInitialization( - "generic_webxr_page", PAGE_LOAD_TIMEOUT_S); - mWebXrVrPermissionTestFramework.enterSessionWithUserGestureOrFail(); - mWebXrVrPermissionTestFramework.endSession(); - - mWebXrVrPermissionTestFramework.setPermissionPromptExpected(false); - - mWebXrVrPermissionTestFramework.enterSessionWithUserGestureOrFail(); - } - - /** - * Tests that attempting to enter an inline session with no special features does not require - * permission. - */ - @Test - @MediumTest - @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL}) - public void testPermissionNotNeededForInline() { - mWebXrVrPermissionTestFramework.setPermissionPromptExpected(false); - - mWebXrVrPermissionTestFramework.loadFileAndAwaitInitialization( - "test_webxr_permission", PAGE_LOAD_TIMEOUT_S); - - mWebXrVrPermissionTestFramework.runJavaScriptOrFail( - "requestMagicWindowSession()", POLL_TIMEOUT_SHORT_MS); - mWebXrVrPermissionTestFramework.pollJavaScriptBooleanOrFail( - "sessionInfos[sessionTypes.MAGIC_WINDOW].currentSession != null", - POLL_TIMEOUT_LONG_MS); - } - - /** Tests that granted permissions persist after a page reload. */ - @Test - @MediumTest - @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL}) - public void testPermissionPersistsAfterReload() { - mWebXrVrPermissionTestFramework.loadFileAndAwaitInitialization( - "generic_webxr_page", PAGE_LOAD_TIMEOUT_S); - - mWebXrVrPermissionTestFramework.enterSessionWithUserGestureOrFail(); - mWebXrVrPermissionTestFramework.endSession(); - - mWebXrVrPermissionTestFramework.loadFileAndAwaitInitialization( - "generic_webxr_page", PAGE_LOAD_TIMEOUT_S); - - mWebXrVrPermissionTestFramework.setPermissionPromptExpected(false); - - mWebXrVrPermissionTestFramework.enterSessionWithUserGestureOrFail(); - } -}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrGvrTabTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrGvrTabTest.java deleted file mode 100644 index 47700eff..0000000 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrGvrTabTest.java +++ /dev/null
@@ -1,82 +0,0 @@ -// 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. - -package org.chromium.chrome.browser.vr; - -import static org.chromium.chrome.browser.vr.XrTestFramework.PAGE_LOAD_TIMEOUT_S; - -import androidx.test.filters.MediumTest; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.RuleChain; -import org.junit.runner.RunWith; - -import org.chromium.base.test.params.ParameterAnnotations.ClassParameter; -import org.chromium.base.test.params.ParameterAnnotations.UseRunnerDelegate; -import org.chromium.base.test.params.ParameterSet; -import org.chromium.base.test.params.ParameterizedRunner; -import org.chromium.base.test.util.CommandLineFlags; -import org.chromium.chrome.browser.flags.ChromeSwitches; -import org.chromium.chrome.browser.vr.util.GvrTestRuleUtils; -import org.chromium.chrome.test.ChromeActivityTestRule; -import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate; -import org.chromium.content_public.browser.WebContents; - -import java.util.List; -import java.util.concurrent.Callable; - -/** End-to-end tests for WebXR's behavior when multiple tabs are involved. */ -@RunWith(ParameterizedRunner.class) -@UseRunnerDelegate(ChromeJUnit4RunnerDelegate.class) -@CommandLineFlags.Add({ - ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, - "enable-features=LogJsConsoleMessages", - "force-webxr-runtime=gvr" -}) -public class WebXrGvrTabTest { - @ClassParameter - private static List<ParameterSet> sClassParams = - GvrTestRuleUtils.generateDefaultTestRuleParameters(); - - @Rule public RuleChain mRuleChain; - - private ChromeActivityTestRule mTestRule; - private WebXrGvrTestFramework mWebXrVrTestFramework; - - public WebXrGvrTabTest(Callable<ChromeActivityTestRule> callable) throws Exception { - mTestRule = callable.call(); - mRuleChain = GvrTestRuleUtils.wrapRuleInActivityRestrictionRule(mTestRule); - } - - @Before - public void setUp() { - mWebXrVrTestFramework = new WebXrGvrTestFramework(mTestRule); - } - - /** - * Tests that non-focused tabs don't get WebXR rAFs called. Disabled on standalones because they - * will always be in the VR Browser, and thus shouldn't be getting inline poses even if the tab - * is focused. - */ - @Test - @MediumTest - @CommandLineFlags.Add({"enable-features=WebXR"}) - public void testPoseDataUnfocusedTab_WebXr() { - testPoseDataUnfocusedTabImpl("webxr_test_pose_data_unfocused_tab", mWebXrVrTestFramework); - } - - private void testPoseDataUnfocusedTabImpl(String url, WebXrGvrTestFramework framework) { - framework.loadFileAndAwaitInitialization(url, PAGE_LOAD_TIMEOUT_S); - framework.executeStepAndWait("stepCheckFrameDataWhileFocusedTab()"); - WebContents firstTabContents = framework.getCurrentWebContents(); - - mTestRule.loadUrlInNewTab("about:blank"); - - WebXrGvrTestFramework.executeStepAndWait( - "stepCheckFrameDataWhileNonFocusedTab()", firstTabContents); - WebXrGvrTestFramework.endTest(firstTabContents); - } -}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrGvrTestFramework.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrGvrTestFramework.java deleted file mode 100644 index cdc1c23f..0000000 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrGvrTestFramework.java +++ /dev/null
@@ -1,17 +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. - -package org.chromium.chrome.browser.vr; - -import org.junit.Assert; - -import org.chromium.chrome.test.ChromeActivityTestRule; - -/** Extension of WebXrGvrTestFramework containing WebXR for Gvr-specific functionality. */ -public class WebXrGvrTestFramework extends WebXrVrTestFramework { - public WebXrGvrTestFramework(ChromeActivityTestRule rule) { - super(rule); - Assert.assertFalse("Test started in VR", VrShellDelegate.isInVr()); - } -}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrGvrTransitionTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrGvrTransitionTest.java deleted file mode 100644 index 4aa268a..0000000 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrGvrTransitionTest.java +++ /dev/null
@@ -1,244 +0,0 @@ -// 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. - -package org.chromium.chrome.browser.vr; - -import static org.chromium.chrome.browser.vr.XrTestFramework.PAGE_LOAD_TIMEOUT_S; -import static org.chromium.chrome.browser.vr.XrTestFramework.POLL_CHECK_INTERVAL_SHORT_MS; -import static org.chromium.chrome.browser.vr.XrTestFramework.POLL_TIMEOUT_LONG_MS; -import static org.chromium.chrome.browser.vr.XrTestFramework.POLL_TIMEOUT_SHORT_MS; -import static org.chromium.chrome.test.util.ChromeRestriction.RESTRICTION_TYPE_DEVICE_DAYDREAM; -import static org.chromium.chrome.test.util.ChromeRestriction.RESTRICTION_TYPE_VR_DON_ENABLED; - -import androidx.test.filters.MediumTest; -import androidx.test.platform.app.InstrumentationRegistry; -import androidx.test.uiautomator.UiDevice; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.RuleChain; -import org.junit.runner.RunWith; - -import org.chromium.base.test.params.ParameterAnnotations.ClassParameter; -import org.chromium.base.test.params.ParameterAnnotations.UseRunnerDelegate; -import org.chromium.base.test.params.ParameterSet; -import org.chromium.base.test.params.ParameterizedRunner; -import org.chromium.base.test.util.CommandLineFlags; -import org.chromium.base.test.util.CriteriaHelper; -import org.chromium.base.test.util.DisabledTest; -import org.chromium.base.test.util.Restriction; -import org.chromium.chrome.browser.flags.ChromeSwitches; -import org.chromium.chrome.browser.vr.rules.XrActivityRestriction; -import org.chromium.chrome.browser.vr.util.GvrTestRuleUtils; -import org.chromium.chrome.browser.vr.util.GvrTransitionUtils; -import org.chromium.chrome.browser.vr.util.PermissionUtils; -import org.chromium.chrome.test.ChromeActivityTestRule; -import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate; - -import java.util.List; -import java.util.concurrent.Callable; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -/** End-to-end tests for transitioning between WebXR's magic window and presentation modes. */ -@RunWith(ParameterizedRunner.class) -@UseRunnerDelegate(ChromeJUnit4RunnerDelegate.class) -@CommandLineFlags.Add({ - ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, - "enable-features=LogJsConsoleMessages", - "force-webxr-runtime=gvr" -}) -public class WebXrGvrTransitionTest { - @ClassParameter - private static List<ParameterSet> sClassParams = - GvrTestRuleUtils.generateDefaultTestRuleParameters(); - - @Rule public RuleChain mRuleChain; - - private ChromeActivityTestRule mTestRule; - private WebXrGvrTestFramework mWebXrVrTestFramework; - - public WebXrGvrTransitionTest(Callable<ChromeActivityTestRule> callable) throws Exception { - mTestRule = callable.call(); - mRuleChain = GvrTestRuleUtils.wrapRuleInActivityRestrictionRule(mTestRule); - } - - @Before - public void setUp() { - mWebXrVrTestFramework = new WebXrGvrTestFramework(mTestRule); - } - - /** - * Tests that WebXR is not exposed if the flag is not on and the page does not have an origin - * trial token. - */ - @Test - @MediumTest - @CommandLineFlags.Add({"disable-features=WebXR"}) - @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL}) - public void testWebXrDisabledWithoutFlagSet() { - apiDisabledWithoutFlagSetImpl( - "test_webxr_disabled_without_flag_set", mWebXrVrTestFramework); - } - - private void apiDisabledWithoutFlagSetImpl(String url, WebXrGvrTestFramework framework) { - framework.loadFileAndAwaitInitialization(url, PAGE_LOAD_TIMEOUT_S); - framework.waitOnJavaScriptStep(); - framework.endTest(); - } - - /** Tests that the immersive session promise is rejected if the DON flow is canceled. */ - @Test - @MediumTest - @Restriction({RESTRICTION_TYPE_DEVICE_DAYDREAM, RESTRICTION_TYPE_VR_DON_ENABLED}) - @CommandLineFlags.Add({"enable-features=WebXR"}) - @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL}) - public void testPresentationPromiseRejectedIfDonCanceled_WebXr() { - presentationPromiseRejectedIfDonCanceledImpl( - "webxr_test_presentation_promise_rejected_if_don_canceled", mWebXrVrTestFramework); - } - - private void presentationPromiseRejectedIfDonCanceledImpl( - String url, WebXrGvrTestFramework framework) { - framework.loadFileAndAwaitInitialization(url, PAGE_LOAD_TIMEOUT_S); - final UiDevice uiDevice = - UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); - framework.enterSessionWithUserGesture(); - // Wait until the DON flow appears to be triggered - // TODO(bsheedy): Make this less hacky if there's ever an explicit way to check if the - // DON flow is currently active https://crbug.com/758296 - CriteriaHelper.pollUiThread( - () -> { - String currentPackageName = uiDevice.getCurrentPackageName(); - return currentPackageName != null - && currentPackageName.equals("com.google.vr.vrcore"); - }, - "DON flow did not start", - POLL_TIMEOUT_LONG_MS, - POLL_CHECK_INTERVAL_SHORT_MS); - uiDevice.pressBack(); - framework.waitOnJavaScriptStep(); - framework.endTest(); - } - - /** Tests that the omnibox reappears after exiting an immersive session. */ - @Test - @MediumTest - @CommandLineFlags.Add({"enable-features=WebXR"}) - @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL}) - @DisabledTest(message = "crbug.com/1229236") - public void testControlsVisibleAfterExitingVr_WebXr() throws InterruptedException { - controlsVisibleAfterExitingVrImpl("generic_webxr_page", mWebXrVrTestFramework); - } - - private void controlsVisibleAfterExitingVrImpl( - String url, final WebXrGvrTestFramework framework) throws InterruptedException { - framework.loadFileAndAwaitInitialization(url, PAGE_LOAD_TIMEOUT_S); - framework.enterSessionWithUserGestureOrFail(); - GvrTransitionUtils.forceExitVr(); - // The hiding of the controls may only propagate after VR has exited, so give it a chance - // to propagate. In the worst case this test will erroneously pass, but should never - // erroneously fail, and should only be flaky if omnibox showing is broken. - Thread.sleep(100); - CriteriaHelper.pollUiThread( - () -> - framework - .getRule() - .getActivity() - .getBrowserControlsManager() - .getBrowserControlHiddenRatio() - == 0.0, - "Browser controls did not unhide after exiting VR", - POLL_TIMEOUT_SHORT_MS, - POLL_CHECK_INTERVAL_SHORT_MS); - framework.assertNoJavaScriptErrors(); - } - - /** - * Tests that window.requestAnimationFrame stops firing while in a WebXR immersive session, but - * resumes afterwards. - */ - @Test - @MediumTest - @CommandLineFlags.Add({"enable-features=WebXR"}) - @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL}) - public void testWindowRafStopsFiringWhilePresenting_WebXr() throws InterruptedException { - windowRafStopsFiringWhilePresentingImpl( - "webxr_test_window_raf_stops_firing_during_immersive_session", - mWebXrVrTestFramework); - } - - private void windowRafStopsFiringWhilePresentingImpl( - String url, WebXrGvrTestFramework framework) throws InterruptedException { - framework.loadFileAndAwaitInitialization(url, PAGE_LOAD_TIMEOUT_S); - framework.executeStepAndWait("stepVerifyBeforePresent()"); - // Pausing of window.rAF is done asynchronously, so wait until that's done. - final CountDownLatch vsyncPausedLatch = new CountDownLatch(1); - TestVrShellDelegate.getInstance() - .setVrShellOnVSyncPausedCallback( - () -> { - vsyncPausedLatch.countDown(); - }); - framework.enterSessionWithUserGestureOrFail(); - vsyncPausedLatch.await(POLL_TIMEOUT_SHORT_MS, TimeUnit.MILLISECONDS); - framework.executeStepAndWait("stepVerifyDuringPresent()"); - GvrTransitionUtils.forceExitVr(); - framework.executeStepAndWait("stepVerifyAfterPresent()"); - framework.endTest(); - } - - /** Tests that window.rAF continues to fire when we have a non-immersive session. */ - @Test - @MediumTest - @CommandLineFlags.Add({"enable-features=WebXR"}) - @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL}) - public void testWindowRafFiresDuringNonImmersiveSession() { - mWebXrVrTestFramework.loadFileAndAwaitInitialization( - "test_window_raf_fires_during_non_immersive_session", PAGE_LOAD_TIMEOUT_S); - mWebXrVrTestFramework.waitOnJavaScriptStep(); - mWebXrVrTestFramework.endTest(); - } - - /** - * Tests that non-immersive sessions stop receiving rAFs during an immersive session, but resume - * once the immersive session ends. - */ - @Test - @MediumTest - @CommandLineFlags.Add({"enable-features=WebXR"}) - @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL}) - @DisabledTest(message = "https://crbug.com/1229236") - public void testNonImmersiveStopsDuringImmersive() { - mWebXrVrTestFramework.loadFileAndAwaitInitialization( - "test_non_immersive_stops_during_immersive", PAGE_LOAD_TIMEOUT_S); - mWebXrVrTestFramework.executeStepAndWait("stepBeforeImmersive()"); - mWebXrVrTestFramework.enterSessionWithUserGestureOrFail(); - mWebXrVrTestFramework.executeStepAndWait("stepDuringImmersive()"); - GvrTransitionUtils.forceExitVr(); - mWebXrVrTestFramework.executeStepAndWait("stepAfterImmersive()"); - mWebXrVrTestFramework.endTest(); - } - - /** - * Tests that a permission prompt dismisses by itself when the page navigates away from the - * current page. - */ - @Test - @MediumTest - @CommandLineFlags.Add({"enable-features=WebXR"}) - // TODO(crbug.com/1250492): Re-enable this test on all activity types once - // WAA/CCT versions no longer fail consistently. - // @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL}) - public void testConsentDialogIsDismissedWhenPageNavigatesAwayInMainFrame() { - mWebXrVrTestFramework.setPermissionPromptAction( - WebXrVrTestFramework.PERMISSION_PROMPT_ACTION_DO_NOTHING); - mWebXrVrTestFramework.loadFileAndAwaitInitialization( - "generic_webxr_page", PAGE_LOAD_TIMEOUT_S); - mWebXrVrTestFramework.enterSessionWithUserGesture(); - mWebXrVrTestFramework.runJavaScriptOrFail( - "window.location.href = 'https://google.com'", POLL_TIMEOUT_SHORT_MS); - PermissionUtils.waitForPermissionPromptDismissal(); - } -}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/mock/MockGvrVrCoreVersionChecker.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/mock/MockGvrVrCoreVersionChecker.java deleted file mode 100644 index d4ed7f1..0000000 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/mock/MockGvrVrCoreVersionChecker.java +++ /dev/null
@@ -1,33 +0,0 @@ -// 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. - -package org.chromium.chrome.browser.vr.mock; - -import org.chromium.chrome.browser.vr.VrCoreVersionChecker; - -/** Mock version of VrCoreVersionCheckerImpl that allows setting of the return value. */ -public class MockGvrVrCoreVersionChecker extends VrCoreVersionChecker { - private boolean mUseActualImplementation; - private @VrCoreCompatibility int mMockReturnValue = VrCoreCompatibility.VR_READY; - private @VrCoreCompatibility int mLastReturnValue; - - @Override - public @VrCoreCompatibility int getVrCoreCompatibility() { - mLastReturnValue = - mUseActualImplementation ? super.getVrCoreCompatibility() : mMockReturnValue; - return mLastReturnValue; - } - - public @VrCoreCompatibility int getLastReturnValue() { - return mLastReturnValue; - } - - public void setMockReturnValue(@VrCoreCompatibility int value) { - mMockReturnValue = value; - } - - public void setUseActualImplementation(boolean useActual) { - mUseActualImplementation = useActual; - } -}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/mock/MockGvrVrDaydreamApi.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/mock/MockGvrVrDaydreamApi.java deleted file mode 100644 index 5609cae..0000000 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/mock/MockGvrVrDaydreamApi.java +++ /dev/null
@@ -1,68 +0,0 @@ -// Copyright 2016 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.vr.mock; - -import android.app.Activity; -import android.app.PendingIntent; -import android.content.Intent; - -import org.chromium.chrome.browser.vr.VrDaydreamApi; - -// TODO(bsheedy): Make Mockito work in instrumentation tests and replace uses of this class with -// Mockito spies. -/** - * "Mock" implementation of VR Shell's VrDaydreamApi that mostly does the same thing as the normal - * VrDaydreamApiImpl, but allows checking whether methods were called and modifying return values. - */ -public class MockGvrVrDaydreamApi extends VrDaydreamApi { - private boolean mLaunchInVrCalled; - private boolean mExitFromVrCalled; - private boolean mLaunchVrHomescreenCalled; - private boolean mDoNotForwardLaunchRequests; - private Boolean mExitFromVrReturnValue; - - @Override - public boolean launchInVr(final PendingIntent pendingIntent) { - mLaunchInVrCalled = true; - if (mDoNotForwardLaunchRequests) return true; - return super.launchInVr(pendingIntent); - } - - @Override - public boolean launchInVr(final Intent intent) { - mLaunchInVrCalled = true; - if (mDoNotForwardLaunchRequests) return true; - return super.launchInVr(intent); - } - - public boolean getLaunchInVrCalled() { - return mLaunchInVrCalled; - } - - @Override - public boolean launchVrHomescreen() { - mLaunchVrHomescreenCalled = true; - return super.launchVrHomescreen(); - } - - public boolean getLaunchVrHomescreenCalled() { - return mLaunchVrHomescreenCalled; - } - - @Override - public boolean exitFromVr(Activity activity, int requestCode, final Intent intent) { - mExitFromVrCalled = true; - if (mExitFromVrReturnValue == null) return super.exitFromVr(activity, requestCode, intent); - return mExitFromVrReturnValue.booleanValue(); - } - - public boolean getExitFromVrCalled() { - return mExitFromVrCalled; - } - - public void setExitFromVrReturnValue(Boolean value) { - mExitFromVrReturnValue = value; - } -}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/rules/ChromeTabbedActivityGvrTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/rules/ChromeTabbedActivityGvrTestRule.java deleted file mode 100644 index 4a7c3c9..0000000 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/rules/ChromeTabbedActivityGvrTestRule.java +++ /dev/null
@@ -1,52 +0,0 @@ -// Copyright 2018 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.vr.rules; - -import org.junit.runner.Description; -import org.junit.runners.model.Statement; - -import org.chromium.base.CommandLine; -import org.chromium.chrome.browser.vr.TestVrShellDelegate; -import org.chromium.chrome.browser.vr.rules.XrActivityRestriction.SupportedActivity; -import org.chromium.chrome.browser.vr.util.GvrTestRuleUtils; -import org.chromium.chrome.test.ChromeTabbedActivityTestRule; - -/** - * VR extension of ChromeTabbedActivityTestRule. Applies ChromeTabbedActivityTestRule then opens up - * a ChromeTabbedActivity to a blank page while performing some additional VR-only setup. - */ -public class ChromeTabbedActivityGvrTestRule extends ChromeTabbedActivityTestRule - implements VrTestRule { - private boolean mDonEnabled; - - @Override - public Statement apply(final Statement base, final Description desc) { - return super.apply( - new Statement() { - @Override - public void evaluate() throws Throwable { - GvrTestRuleUtils.evaluateVrTestRuleImpl( - base, - desc, - ChromeTabbedActivityGvrTestRule.this, - () -> { - startMainActivityOnBlankPage(); - TestVrShellDelegate.createTestVrShellDelegate(getActivity()); - }); - } - }, - desc); - } - - @Override - public @SupportedActivity int getRestriction() { - return SupportedActivity.CTA; - } - - @Override - public boolean isDonEnabled() { - return CommandLine.getInstance().hasSwitch("vr-don-enabled"); - } -}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/rules/CustomTabActivityGvrTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/rules/CustomTabActivityGvrTestRule.java deleted file mode 100644 index 8757922d..0000000 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/rules/CustomTabActivityGvrTestRule.java +++ /dev/null
@@ -1,57 +0,0 @@ -// Copyright 2018 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.vr.rules; - -import androidx.test.core.app.ApplicationProvider; - -import org.junit.runner.Description; -import org.junit.runners.model.Statement; - -import org.chromium.base.CommandLine; -import org.chromium.chrome.browser.customtabs.CustomTabActivityTestRule; -import org.chromium.chrome.browser.customtabs.CustomTabsIntentTestUtils; -import org.chromium.chrome.browser.vr.TestVrShellDelegate; -import org.chromium.chrome.browser.vr.rules.XrActivityRestriction.SupportedActivity; -import org.chromium.chrome.browser.vr.util.GvrTestRuleUtils; - -/** - * VR extension of CustomTabActivityTestRule. Applies CustomTabActivityTestRule then opens up a - * CustomTabActivity to a blank page while performing some additional VR-only setup. - */ -public class CustomTabActivityGvrTestRule extends CustomTabActivityTestRule implements VrTestRule { - private boolean mDonEnabled; - - @Override - public Statement apply(final Statement base, final Description desc) { - return super.apply( - new Statement() { - @Override - public void evaluate() throws Throwable { - GvrTestRuleUtils.evaluateVrTestRuleImpl( - base, - desc, - CustomTabActivityGvrTestRule.this, - () -> { - startCustomTabActivityWithIntent( - CustomTabsIntentTestUtils.createMinimalCustomTabIntent( - ApplicationProvider.getApplicationContext(), - "about:blank")); - TestVrShellDelegate.createTestVrShellDelegate(getActivity()); - }); - } - }, - desc); - } - - @Override - public @SupportedActivity int getRestriction() { - return SupportedActivity.CCT; - } - - @Override - public boolean isDonEnabled() { - return CommandLine.getInstance().hasSwitch("vr-don-enabled"); - } -}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/rules/WebappActivityGvrTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/rules/WebappActivityGvrTestRule.java deleted file mode 100644 index c78c40cd..0000000 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/rules/WebappActivityGvrTestRule.java +++ /dev/null
@@ -1,51 +0,0 @@ -// Copyright 2018 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.vr.rules; - -import org.junit.runner.Description; -import org.junit.runners.model.Statement; - -import org.chromium.base.CommandLine; -import org.chromium.chrome.browser.vr.TestVrShellDelegate; -import org.chromium.chrome.browser.vr.rules.XrActivityRestriction.SupportedActivity; -import org.chromium.chrome.browser.vr.util.GvrTestRuleUtils; -import org.chromium.chrome.browser.webapps.WebappActivityTestRule; - -/** - * VR extension of WebappActivityTestRule. Applies WebappActivityTestRule then opens up a - * WebappActivity to a blank page while performing some additional VR-only setup. - */ -public class WebappActivityGvrTestRule extends WebappActivityTestRule implements VrTestRule { - private boolean mDonEnabled; - - @Override - public Statement apply(final Statement base, final Description desc) { - return super.apply( - new Statement() { - @Override - public void evaluate() throws Throwable { - GvrTestRuleUtils.evaluateVrTestRuleImpl( - base, - desc, - WebappActivityGvrTestRule.this, - () -> { - startWebappActivity(); - TestVrShellDelegate.createTestVrShellDelegate(getActivity()); - }); - } - }, - desc); - } - - @Override - public @SupportedActivity int getRestriction() { - return SupportedActivity.WAA; - } - - @Override - public boolean isDonEnabled() { - return CommandLine.getInstance().hasSwitch("vr-don-enabled"); - } -}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/GvrTestRuleUtils.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/GvrTestRuleUtils.java deleted file mode 100644 index 55d44b03..0000000 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/GvrTestRuleUtils.java +++ /dev/null
@@ -1,142 +0,0 @@ -// Copyright 2018 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.vr.util; - -import android.os.SystemClock; - -import androidx.test.platform.app.InstrumentationRegistry; -import androidx.test.uiautomator.UiDevice; - -import org.junit.Assert; -import org.junit.rules.RuleChain; -import org.junit.rules.TestRule; -import org.junit.runner.Description; -import org.junit.runners.model.Statement; - -import org.chromium.base.BundleUtils; -import org.chromium.base.test.BundleTestRule; -import org.chromium.base.test.params.ParameterSet; -import org.chromium.chrome.browser.vr.TestVrShellDelegate; -import org.chromium.chrome.browser.vr.rules.ChromeTabbedActivityGvrTestRule; -import org.chromium.chrome.browser.vr.rules.VrTestRule; -import org.chromium.chrome.browser.vr.rules.WebappActivityGvrTestRule; - -import java.util.ArrayList; -import java.util.concurrent.Callable; - -/** - * Utility class for interacting with VR-specific Rules, i.e. ChromeActivityTestRules that implement - * the VrTestRule interface. - */ -public class GvrTestRuleUtils extends XrTestRuleUtils { - // VrCore waits this amount of time after exiting VR before actually unregistering a registered - // Daydream intent, meaning that it still thinks VR is active until this amount of time has - // passed. - private static final int VRCORE_UNREGISTER_DELAY_MS = 500; - - /** - * Helper method to apply a VrTestRule/ChromeActivityTestRule combination. The only difference - * between various classes that implement VrTestRule is how they start their activity, so the - * common boilerplate code can be kept here so each VrTestRule only has to provide a way to - * launch Chrome. - * - * @param base The Statement passed to the calling ChromeActivityTestRule's apply() method. - * @param desc The Description passed to the calling ChromeActivityTestRule's apply() method. - * @param rule The calling VrTestRule. - * @param launcher A ChromeLaunchMethod whose launch() contains the code snippet to start Chrome - * in the calling ChromeActivityTestRule's activity type. - */ - public static void evaluateVrTestRuleImpl( - final Statement base, - final Description desc, - final VrTestRule rule, - final ChromeLaunchMethod launcher) - throws Throwable { - TestVrShellDelegate.setDescription(desc); - - GvrTestRuleUtils.ensureNoVrActivitiesDisplayed(); - launcher.launch(); - - base.evaluate(); - } - - /** - * Creates the list of VrTestRules that are currently supported for use in test - * parameterization. - * - * @return An ArrayList of ParameterSets, with each ParameterSet containing a callable to create - * a VrTestRule for a supported ChromeActivity. - */ - public static ArrayList<ParameterSet> generateDefaultTestRuleParameters() { - ArrayList<ParameterSet> parameters = new ArrayList<ParameterSet>(); - parameters.add( - new ParameterSet() - .value( - new Callable<ChromeTabbedActivityGvrTestRule>() { - @Override - public ChromeTabbedActivityGvrTestRule call() { - return new ChromeTabbedActivityGvrTestRule(); - } - }) - .name("ChromeTabbedActivity")); - // TODO(https://crbug.com/989117): Re-enable testing in CCT once we've migrated to using - // cardboard libraries instead of Daydream. - // parameters.add(new ParameterSet() - // .value(new Callable<CustomTabActivityGvrTestRule>() { - // @Override - // public CustomTabActivityGvrTestRule call() { - // return new CustomTabActivityGvrTestRule(); - // } - // }) - // .name("CustomTabActivity")); - - parameters.add( - new ParameterSet() - .value( - new Callable<WebappActivityGvrTestRule>() { - @Override - public WebappActivityGvrTestRule call() { - return new WebappActivityGvrTestRule(); - } - }) - .name("WebappActivity")); - - return parameters; - } - - /** - * Creates a RuleChain that applies the XrActivityRestrictionRule before the given VrTestRule. - * - * <p>Also enforces that {@link BundleUtils#isBundle()} returns true for vr to be initialized. - * - * @param rule The TestRule to wrap in an XrActivityRestrictionRule. - * @return A RuleChain that ensures an XrActivityRestrictionRule is applied before the provided - * TestRule. - */ - public static RuleChain wrapRuleInActivityRestrictionRule(TestRule rule) { - Assert.assertTrue("Given rule is not an VrTestRule", rule instanceof VrTestRule); - return RuleChain.outerRule(new BundleTestRule()) - .around(XrTestRuleUtils.wrapRuleInActivityRestrictionRule(rule)); - } - - /** - * Ensures that no VR-related activity is currently being displayed. This is meant to be used by - * TestRules before starting any activities. Having a VR activity in the foreground (e.g. - * Daydream Home) has the potential to affect test results, as it often means that we are in VR - * at the beginning of the test, which we don't want. This is most commonly caused by VrCore - * automatically launching Daydream Home when Chrome gets closed after a test, but can happen - * for other reasons as well. - */ - public static void ensureNoVrActivitiesDisplayed() { - UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); - String currentPackageName = uiDevice.getCurrentPackageName(); - if (currentPackageName != null && currentPackageName.contains("vr")) { - uiDevice.pressHome(); - // Chrome startup would likely be slow enough that this sleep is unnecessary, but sleep - // to be sure since this will be hit relatively infrequently. - SystemClock.sleep(VRCORE_UNREGISTER_DELAY_MS); - } - } -}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/GvrTransitionUtils.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/GvrTransitionUtils.java deleted file mode 100644 index d236c52..0000000 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/GvrTransitionUtils.java +++ /dev/null
@@ -1,47 +0,0 @@ -// Copyright 2018 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.vr.util; - -import static org.chromium.chrome.browser.vr.XrTestFramework.POLL_CHECK_INTERVAL_SHORT_MS; - -import org.chromium.base.test.util.CriteriaHelper; -import org.chromium.chrome.browser.vr.VrShellDelegate; -import org.chromium.content_public.browser.test.util.TestThreadUtils; - -/** - * Class containing utility functions for transitioning between different states in VR, such as - * fullscreen, WebVR presentation, and the VR browser. - * - * <p>Methods in this class are applicable to any form of VR, e.g. they will work for both WebXR for - * VR and the VR Browser. - * - * <p>All the transitions in this class are performed directly through Chrome, as opposed to NFC tag - * simulation which involves receiving an intent from an outside application (VR Services). - */ -public class GvrTransitionUtils { - /** Forces Chrome out of VR mode. */ - public static void forceExitVr() { - TestThreadUtils.runOnUiThreadBlocking( - () -> { - VrShellDelegate.forceExitVrImmediately(); - }); - } - - /** - * Waits until Chrome believes it is in VR. - * - * @param timeout How long to wait for VR entry before timing out and failing. - */ - public static void waitForVrEntry(final int timeout) { - // Relatively long timeout because sometimes GVR takes a while to enter VR - CriteriaHelper.pollUiThread( - () -> { - return VrShellDelegateUtils.getDelegateInstance().isVrEntryComplete(); - }, - "VR not entered in allotted time", - timeout, - POLL_CHECK_INTERVAL_SHORT_MS); - } -}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/VrShellDelegateUtils.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/VrShellDelegateUtils.java deleted file mode 100644 index dfc333f3..0000000 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/VrShellDelegateUtils.java +++ /dev/null
@@ -1,30 +0,0 @@ -// 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. - -package org.chromium.chrome.browser.vr.util; - -import org.chromium.chrome.browser.vr.TestVrShellDelegate; -import org.chromium.content_public.browser.test.util.TestThreadUtils; - -import java.util.concurrent.atomic.AtomicReference; - -/** Class containing utility functions for interacting with VrShellDelegate during tests. */ -public class VrShellDelegateUtils { - /** - * Retrieves the current VrShellDelegate instance from the UI thread. This is necessary in case - * acquiring the instance causes the delegate to be constructed, which must happen on the UI - * thread. - * - * @return The TestVrShellDelegate instance currently in use. - */ - public static TestVrShellDelegate getDelegateInstance() { - final AtomicReference<TestVrShellDelegate> delegate = - new AtomicReference<TestVrShellDelegate>(); - TestThreadUtils.runOnUiThreadBlocking( - () -> { - delegate.set(TestVrShellDelegate.getInstance()); - }); - return delegate.get(); - } -}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerMediatorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerMediatorTest.java index ef215e16..56ece8f 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerMediatorTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/bookmarks/BookmarkManagerMediatorTest.java
@@ -139,9 +139,6 @@ @Batch(Batch.UNIT_TESTS) @RunWith(BaseRobolectricTestRunner.class) @Config(shadows = {ShadowPostTask.class}) -@EnableFeatures({ - ChromeFeatureList.SHOPPING_LIST, -}) public class BookmarkManagerMediatorTest { private static final GURL EXAMPLE_URL = JUnitTestGURLs.EXAMPLE_URL; private static final String EXAMPLE_URL_FORMATTED =
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/RealtimeEngagementSignalObserverUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/RealtimeEngagementSignalObserverUnitTest.java index 6cfd2a5..bf3deee2 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/RealtimeEngagementSignalObserverUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/RealtimeEngagementSignalObserverUnitTest.java
@@ -24,7 +24,6 @@ import static org.chromium.chrome.browser.customtabs.content.RealtimeEngagementSignalObserver.DEFAULT_AFTER_SCROLL_END_THRESHOLD_MS; import static org.chromium.chrome.browser.customtabs.content.RealtimeEngagementSignalObserver.REAL_VALUES; -import android.graphics.Point; import android.os.Bundle; import android.os.SystemClock; @@ -269,9 +268,7 @@ // Scroll down to 55%. when(mRenderCoordinatesImpl.getScrollYPixInt()).thenReturn(55); listener.onScrollOffsetOrExtentChanged(55, SCROLL_EXTENT); - listener.onScrollUpdateGestureConsumed(new Point(0, 55)); // Scroll up to 30%. - listener.onScrollUpdateGestureConsumed(new Point(0, 30)); when(mRenderCoordinatesImpl.getScrollYPixInt()).thenReturn(30); listener.onScrollOffsetOrExtentChanged(30, SCROLL_EXTENT); @@ -294,7 +291,6 @@ // Start by scrolling down. listener.onScrollStarted(0, SCROLL_EXTENT, false); // Scroll down to 3%. - listener.onScrollUpdateGestureConsumed(new Point(0, 3)); when(mRenderCoordinatesImpl.getScrollYPixInt()).thenReturn(3); listener.onScrollOffsetOrExtentChanged(3, SCROLL_EXTENT); // End scrolling. @@ -306,7 +302,6 @@ // Start scrolling down again. listener.onScrollStarted(3, SCROLL_EXTENT, false); // Scroll down to 8%. - listener.onScrollUpdateGestureConsumed(new Point(0, 8)); when(mRenderCoordinatesImpl.getScrollYPixInt()).thenReturn(8); listener.onScrollOffsetOrExtentChanged(8, SCROLL_EXTENT); // End scrolling. @@ -318,7 +313,6 @@ // Start scrolling down again. listener.onScrollStarted(8, SCROLL_EXTENT, false); // Scroll down to 94%. - listener.onScrollUpdateGestureConsumed(new Point(0, 94)); when(mRenderCoordinatesImpl.getScrollYPixInt()).thenReturn(94); listener.onScrollOffsetOrExtentChanged(94, SCROLL_EXTENT); // End scrolling. @@ -336,7 +330,6 @@ // Start by scrolling down. listener.onScrollStarted(0, SCROLL_EXTENT, false); // Scroll down to 63%. - listener.onScrollUpdateGestureConsumed(new Point(0, 63)); when(mRenderCoordinatesImpl.getScrollYPixInt()).thenReturn(63); listener.onScrollOffsetOrExtentChanged(63, SCROLL_EXTENT); // End scrolling. @@ -349,7 +342,6 @@ // Now scroll back up. listener.onScrollStarted(63, SCROLL_EXTENT, true); // Scroll up to 30%. - listener.onScrollUpdateGestureConsumed(new Point(0, 30)); when(mRenderCoordinatesImpl.getScrollYPixInt()).thenReturn(30); listener.onScrollOffsetOrExtentChanged(30, SCROLL_EXTENT); // End scrolling. @@ -368,7 +360,6 @@ // Start by scrolling down. listener.onScrollStarted(0, SCROLL_EXTENT, false); // Scroll down to 50%. - listener.onScrollUpdateGestureConsumed(new Point(0, 50)); when(mRenderCoordinatesImpl.getScrollYPixInt()).thenReturn(50); listener.onScrollOffsetOrExtentChanged(50, SCROLL_EXTENT); // End scrolling. @@ -377,11 +368,9 @@ // Now scroll up, then back down to 50%. listener.onScrollStarted(50, SCROLL_EXTENT, true); // Scroll up to 30%. - listener.onScrollUpdateGestureConsumed(new Point(0, 30)); when(mRenderCoordinatesImpl.getScrollYPixInt()).thenReturn(30); listener.onScrollOffsetOrExtentChanged(30, SCROLL_EXTENT); // Back down to 50%. - listener.onScrollUpdateGestureConsumed(new Point(0, 50)); when(mRenderCoordinatesImpl.getScrollYPixInt()).thenReturn(50); listener.onScrollOffsetOrExtentChanged(50, SCROLL_EXTENT); // End scrolling. @@ -400,7 +389,6 @@ // Scroll down to 50%. gestureStateListener.onScrollStarted(0, SCROLL_EXTENT, false); - gestureStateListener.onScrollUpdateGestureConsumed(new Point(0, 50)); when(mRenderCoordinatesImpl.getScrollYPixInt()).thenReturn(50); gestureStateListener.onScrollOffsetOrExtentChanged(50, SCROLL_EXTENT); gestureStateListener.onScrollEnded(50, SCROLL_EXTENT); @@ -422,7 +410,6 @@ // Scroll down to 10%. gestureStateListener.onScrollStarted(0, SCROLL_EXTENT, false); - gestureStateListener.onScrollUpdateGestureConsumed(new Point(0, 10)); when(mRenderCoordinatesImpl.getScrollYPixInt()).thenReturn(10); gestureStateListener.onScrollOffsetOrExtentChanged(10, SCROLL_EXTENT); gestureStateListener.onScrollEnded(10, SCROLL_EXTENT); @@ -440,7 +427,6 @@ // Scroll down to 30%. gestureStateListener.onScrollStarted(0, SCROLL_EXTENT, false); - gestureStateListener.onScrollUpdateGestureConsumed(new Point(0, 30)); when(mRenderCoordinatesImpl.getScrollYPixInt()).thenReturn(30); gestureStateListener.onScrollOffsetOrExtentChanged(30, SCROLL_EXTENT); gestureStateListener.onScrollEnded(30, SCROLL_EXTENT); @@ -462,7 +448,6 @@ // Scroll down to 10%. gestureStateListener.onScrollStarted(0, SCROLL_EXTENT, false); - gestureStateListener.onScrollUpdateGestureConsumed(new Point(0, 10)); when(mRenderCoordinatesImpl.getScrollYPixInt()).thenReturn(10); gestureStateListener.onScrollOffsetOrExtentChanged(10, SCROLL_EXTENT); gestureStateListener.onScrollEnded(10, SCROLL_EXTENT); @@ -480,7 +465,6 @@ // Scroll down to 90%. gestureStateListener.onScrollStarted(0, SCROLL_EXTENT, false); - gestureStateListener.onScrollUpdateGestureConsumed(new Point(0, 90)); when(mRenderCoordinatesImpl.getScrollYPixInt()).thenReturn(90); gestureStateListener.onScrollOffsetOrExtentChanged(90, SCROLL_EXTENT); gestureStateListener.onScrollEnded(90, SCROLL_EXTENT); @@ -502,7 +486,6 @@ // Scroll down to 50%. gestureStateListener.onScrollStarted(0, SCROLL_EXTENT, false); - gestureStateListener.onScrollUpdateGestureConsumed(new Point(0, 50)); when(mRenderCoordinatesImpl.getScrollYPixInt()).thenReturn(50); gestureStateListener.onScrollOffsetOrExtentChanged(50, SCROLL_EXTENT); gestureStateListener.onScrollEnded(50, SCROLL_EXTENT); @@ -519,7 +502,6 @@ // Scroll down to 50%. gestureStateListener.onScrollStarted(0, SCROLL_EXTENT, false); - gestureStateListener.onScrollUpdateGestureConsumed(new Point(0, 50)); when(mRenderCoordinatesImpl.getScrollYPixInt()).thenReturn(50); gestureStateListener.onScrollOffsetOrExtentChanged(50, SCROLL_EXTENT); gestureStateListener.onScrollEnded(50, SCROLL_EXTENT); @@ -534,7 +516,6 @@ // Scroll down to 10%. gestureStateListener.onScrollStarted(0, SCROLL_EXTENT, false); - gestureStateListener.onScrollUpdateGestureConsumed(new Point(0, 10)); when(mRenderCoordinatesImpl.getScrollYPixInt()).thenReturn(10); gestureStateListener.onScrollOffsetOrExtentChanged(10, SCROLL_EXTENT); gestureStateListener.onScrollEnded(10, SCROLL_EXTENT); @@ -577,7 +558,6 @@ // Start by scrolling down. listener.onScrollStarted(0, SCROLL_EXTENT, false); // Scroll down to 3%. - listener.onScrollUpdateGestureConsumed(new Point(0, 3)); when(mRenderCoordinatesImpl.getScrollYPixInt()).thenReturn(3); listener.onScrollOffsetOrExtentChanged(3, SCROLL_EXTENT); // End scrolling. @@ -589,7 +569,6 @@ // Start scrolling down again. listener.onScrollStarted(3, SCROLL_EXTENT, false); // Scroll down to 8%. - listener.onScrollUpdateGestureConsumed(new Point(0, 8)); when(mRenderCoordinatesImpl.getScrollYPixInt()).thenReturn(8); listener.onScrollOffsetOrExtentChanged(8, SCROLL_EXTENT); // End scrolling. @@ -601,7 +580,6 @@ // Start scrolling down again. listener.onScrollStarted(8, SCROLL_EXTENT, false); // Scroll down to 94%. - listener.onScrollUpdateGestureConsumed(new Point(0, 94)); when(mRenderCoordinatesImpl.getScrollYPixInt()).thenReturn(94); listener.onScrollOffsetOrExtentChanged(94, SCROLL_EXTENT); // End scrolling. @@ -970,7 +948,6 @@ private void verifyNoMemoryLeakForGestureStateListener(GestureStateListener listener) { listener.onScrollStarted(0, 1, false); - listener.onScrollUpdateGestureConsumed(new Point(1, 1)); listener.onVerticalScrollDirectionChanged(false, 0.1f); listener.onScrollEnded(1, 0); }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegateUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegateUnitTest.java index 6e4edaec..ccc1fca4 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegateUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegateUnitTest.java
@@ -72,7 +72,6 @@ import org.chromium.chrome.browser.ui.appmenu.AppMenuDelegate; import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager; import org.chromium.chrome.test.util.browser.Features; -import org.chromium.chrome.test.util.browser.Features.DisableFeatures; import org.chromium.chrome.test.util.browser.Features.EnableFeatures; import org.chromium.components.browser_ui.accessibility.PageZoomCoordinator; import org.chromium.components.browser_ui.site_settings.WebsitePreferenceBridge; @@ -98,7 +97,6 @@ ChromeFeatureList.WEB_FEED, UiAccessibilityFeatures.START_SURFACE_ACCESSIBILITY_CHECK }) -@DisableFeatures({ChromeFeatureList.SHOPPING_LIST}) public class TabbedAppMenuPropertiesDelegateUnitTest { // Constants defining flags that determines multi-window menu items visibility. private static final boolean TAB_M = true; // multiple tabs
diff --git a/chrome/android/profiles/arm.newest.txt b/chrome/android/profiles/arm.newest.txt index a46b0be..e666ff0 100644 --- a/chrome/android/profiles/arm.newest.txt +++ b/chrome/android/profiles/arm.newest.txt
@@ -1 +1 @@ -chromeos-chrome-arm-122.0.6179.0_rc-r1-merged.afdo.bz2 +chromeos-chrome-arm-122.0.6184.0_rc-r1-merged.afdo.bz2
diff --git a/chrome/android/shared_preference_files/OWNERS b/chrome/android/shared_preference_files/OWNERS deleted file mode 100644 index 63d94f7..0000000 --- a/chrome/android/shared_preference_files/OWNERS +++ /dev/null
@@ -1,3 +0,0 @@ -bsheedy@chromium.org - -per-file *.json=*
diff --git a/chrome/android/shared_preference_files/test/vr_cardboard_skipdon_setupcomplete.json b/chrome/android/shared_preference_files/test/vr_cardboard_skipdon_setupcomplete.json deleted file mode 100644 index 3c36564f..0000000 --- a/chrome/android/shared_preference_files/test/vr_cardboard_skipdon_setupcomplete.json +++ /dev/null
@@ -1,16 +0,0 @@ -[ - { - "package": "com.google.vr.vrcore", - "filename": "VrCoreSettings.xml", - "supports_encrypted_path": true, - "set": { - "VrSkipDon": true, - "DaydreamSetupComplete": true, - "VrDeviceParams": "CgZHb29nbGUSCUNhcmRib2FyZB0J-SA9JQHegj0qEAAAcEIAAHBCAABwQgAAcEI1KVwPPToIV_GrPmKxDT9QAFgAYAM", - "UseAutomatedController": false, - "GvrPlatformLibraryPref": false, - "EnableVrCoreHeadTracking": false, - "EnableDeveloperService": false - } - } -]
diff --git a/chrome/android/shared_preference_files/test/vr_ddview_don_setupcomplete.json b/chrome/android/shared_preference_files/test/vr_ddview_don_setupcomplete.json deleted file mode 100644 index ecfb927..0000000 --- a/chrome/android/shared_preference_files/test/vr_ddview_don_setupcomplete.json +++ /dev/null
@@ -1,16 +0,0 @@ -[ - { - "package": "com.google.vr.vrcore", - "filename": "VrCoreSettings.xml", - "supports_encrypted_path": true, - "set": { - "VrSkipDon": false, - "DaydreamSetupComplete": true, - "VrDeviceParams": "CgxHb29nbGUsIEluYy4SDURheWRyZWFtIFZpZXcdCfkgPSUB3oI9KhAAAFxCAABcQgAAXEIAAFxCNd9PDT06CLgexT7Zzhc_WABgAJqRYBoIARIKDQAAAAAV9P3UPBIKDQAAAAAV9P3UvA", - "UseAutomatedController": false, - "PairedControllerDriver": "DRIVER_P6", - "PairedControllerAddress": "AA:AA:AA:AA:AA:AA", - "EnableVrCoreHeadTracking": false - } - } -]
diff --git a/chrome/android/shared_preference_files/test/vr_ddview_skipdon_setupcomplete.json b/chrome/android/shared_preference_files/test/vr_ddview_skipdon_setupcomplete.json deleted file mode 100644 index 062695e7..0000000 --- a/chrome/android/shared_preference_files/test/vr_ddview_skipdon_setupcomplete.json +++ /dev/null
@@ -1,20 +0,0 @@ -[ - { - "package": "com.google.vr.vrcore", - "filename": "VrCoreSettings.xml", - "supports_encrypted_path": true, - "set": { - "VrSkipDon": true, - "DaydreamSetupComplete": true, - "VrDeviceParams": "CgxHb29nbGUsIEluYy4SDURheWRyZWFtIFZpZXcdCfkgPSUB3oI9KhAAAExCAAA0QgAAMEIAAFRCNd9PDT06CLgexT7Zzhc_WABgAJqRYBAIARIKDQAAAAAV9P3UPBgA", - "UseAutomatedController": true, - "PairedControllerDriver": "DRIVER_AUTOMATED", - "PairedControllerAddress": "FOO", - "GvrPlatformLibraryPref": false, - "EnableVrCoreHeadTracking": false, - "EnableDeveloperService": false, - "gConfigFlags:enable_screen_capture": true, - "EnableAdbRecording": true - } - } -]
diff --git a/chrome/android/shared_preference_files/test/vr_ddview_skipdon_setupcomplete_o2.json b/chrome/android/shared_preference_files/test/vr_ddview_skipdon_setupcomplete_o2.json deleted file mode 100644 index 700e6d5..0000000 --- a/chrome/android/shared_preference_files/test/vr_ddview_skipdon_setupcomplete_o2.json +++ /dev/null
@@ -1,15 +0,0 @@ -[ - { - "package": "com.google.vr.vrcore", - "filename": "VrCoreSettings.xml", - "set": { - "VrSkipDon": true, - "DaydreamSetupComplete": true, - "VrDeviceParams": "CgxHb29nbGUsIEluYy4SDURheWRyZWFtIFZpZXcdCfkgPSUB3oI9KhAAAFxCAABcQgAAXEIAAFxCNd9PDT06CLgexT7Zzhc_WABgAJqRYBoIARIKDQAAAAAV9P3UPBIKDQAAAAAV9P3UvA", - "UseAutomatedController": true, - "PairedControllerDriver": "DRIVER_AUTOMATED", - "PairedControllerAddress": "FOO", - "GvrPlatformLibraryPref": true - } - } -]
diff --git a/chrome/android/shared_preference_files/test/vr_enable_vr_settings_service.json b/chrome/android/shared_preference_files/test/vr_enable_vr_settings_service.json deleted file mode 100644 index 6ed1172..0000000 --- a/chrome/android/shared_preference_files/test/vr_enable_vr_settings_service.json +++ /dev/null
@@ -1,10 +0,0 @@ -[ - { - "package": "com.google.vr.vrcore", - "filename": "VrCoreSettings.xml", - "supports_encrypted_path": true, - "set": { - "EnableDeveloperService": true - } - } -]
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 6f2f5e0..6efea0b 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -7965,6 +7965,15 @@ <message name="IDS_LEARN_MORE_ABOUT_FEATURE_A11Y_LABEL" desc="Accessibility label for a link labeled 'Learn more' that links to a help article about creating themes with AI."> Learn more about creating themes with AI. </message> + <message name="IDS_THUMBS_DOWN_OPENS_FEEDBACK_FORM_A11Y_LABEL" desc="Accessibility label for thumbs down button that opens a feedback form when pressed."> + Thumbs down opens a form for submitting detailed feedback on why you dislike these results. + </message> + <message name="IDS_THUMBS_UP_RESULTS_A11Y_LABEL" desc="Accessibility label for thumbs up button that submits feedback for results."> + Thumbs up submits feedback that you like these results. + </message> + <message name="IDS_NTP_WALLPAPER_SEARCH_INSPIRATION_HEADER" desc="Header for the wallpaper search section for showing example results."> + Inspiration + </message> <!-- NTP Modules --> <message name="IDS_NTP_MODULES_INFO_BUTTON_TITLE" desc="Text shown in tooltip of info button of an NTP module."> @@ -16113,8 +16122,8 @@ <message name="IDS_ACCOUNT_SELECTION_DATA_SHARING_CONSENT" desc="The consent text shown to the user before sign up."> To continue, <ph name="IDENTITY_PROVIDER_ETLD_PLUS_ONE">$1<ex>idp.com</ex></ph> will share your name, email address, and profile picture with this site. See this site's <ph name="BEGIN_LINK1">$2</ph>privacy policy<ph name="END_LINK1">$3</ph> and <ph name="BEGIN_LINK2">$4</ph>terms of service<ph name="END_LINK2">$5</ph>. </message> - <message name="IDS_ACCOUNT_SELECTION_ADD_ACCOUNT" desc="Title of the button that lets the user sign in to an additional account" translateable="false"> - Add Account + <message name="IDS_ACCOUNT_SELECTION_USE_OTHER_ACCOUNT" desc="Title of the button that lets the user log in to a different account" translateable="false"> + Use a different account </message> <message name="IDS_IDP_SIGNIN_STATUS_MISMATCH_DIALOG_TITLE" desc="Header for mismatch dialog which is shown to the user when their sign in status is signed in but they are not signed in to any account." translateable="false"> Failed signing in to <ph name="SITE_ETLD_PLUS_ONE">$1<ex>rp.example</ex></ph> with <ph name="IDENTITY_PROVIDER_ETLD_PLUS_ONE">$2<ex>idp.example</ex></ph> @@ -16645,11 +16654,11 @@ </message> <!-- Common WebUI elements. --> - <message name="IDS_THUMBS_DOWN" desc="Accessibility label for a thumbs down icon that a user can click to provide negative feedback about a feature." translateable="false"> - Thumbs down + <message name="IDS_THUMBS_DOWN" desc="Accessibility label for a thumbs down icon that a user can click to provide negative feedback about a feature."> + Thumbs down submits feedback that you dislike this. </message> - <message name="IDS_THUMBS_UP" desc="Accessibility label for a thumbs up icon that a user can click to provide positive feedback about a feature." translateable="false"> - Thumbs up + <message name="IDS_THUMBS_UP" desc="Accessibility label for a thumbs up icon that a user can click to provide positive feedback about a feature."> + Thumbs up submits feedback that you like this. </message> <message name="IDS_EXPERIMENTAL_FEATURE_DISCLAIMER" desc="Text used for experimental features."> This is an experimental AI feature.
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_INSPIRATION_HEADER.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_INSPIRATION_HEADER.png.sha1 new file mode 100644 index 0000000..a0e1e52 --- /dev/null +++ b/chrome/app/generated_resources_grd/IDS_NTP_WALLPAPER_SEARCH_INSPIRATION_HEADER.png.sha1
@@ -0,0 +1 @@ +86ead1e17b05451b5c078b12861adecc3da29875 \ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_THUMBS_DOWN.png.sha1 b/chrome/app/generated_resources_grd/IDS_THUMBS_DOWN.png.sha1 new file mode 100644 index 0000000..121031f4 --- /dev/null +++ b/chrome/app/generated_resources_grd/IDS_THUMBS_DOWN.png.sha1
@@ -0,0 +1 @@ +d5dbda1727707936a6f3be26d5735f5b48f57a4e \ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_THUMBS_DOWN_OPENS_FEEDBACK_FORM_A11Y_LABEL.png.sha1 b/chrome/app/generated_resources_grd/IDS_THUMBS_DOWN_OPENS_FEEDBACK_FORM_A11Y_LABEL.png.sha1 new file mode 100644 index 0000000..04592b6 --- /dev/null +++ b/chrome/app/generated_resources_grd/IDS_THUMBS_DOWN_OPENS_FEEDBACK_FORM_A11Y_LABEL.png.sha1
@@ -0,0 +1 @@ +7c7145ed5ba18856c2c239ece4a768894debd5b1 \ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_THUMBS_UP.png.sha1 b/chrome/app/generated_resources_grd/IDS_THUMBS_UP.png.sha1 new file mode 100644 index 0000000..25986a9 --- /dev/null +++ b/chrome/app/generated_resources_grd/IDS_THUMBS_UP.png.sha1
@@ -0,0 +1 @@ +8336fea79afe5823bf490615759ec6ca482ac282 \ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_THUMBS_UP_RESULTS_A11Y_LABEL.png.sha1 b/chrome/app/generated_resources_grd/IDS_THUMBS_UP_RESULTS_A11Y_LABEL.png.sha1 new file mode 100644 index 0000000..6137c645 --- /dev/null +++ b/chrome/app/generated_resources_grd/IDS_THUMBS_UP_RESULTS_A11Y_LABEL.png.sha1
@@ -0,0 +1 @@ +7c4f32afd6613df32396ef9b8faf90331416459f \ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 909d202..7ca5480 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -3070,7 +3070,6 @@ "download/android/service/download_task_scheduler.h", "download/android/string_utils.cc", "download/download_crx_util_android.cc", - "endpoint_fetcher/endpoint_fetcher_android.cc", "enterprise/reporting/browser_report_generator_android.cc", "enterprise/reporting/browser_report_generator_android.h", "enterprise/reporting/profile_report_generator_android.cc", @@ -3405,7 +3404,6 @@ "//chrome/browser/consent_auditor/android:jni_headers", "//chrome/browser/device_reauth/android:jni_headers", "//chrome/browser/download/internal/android", - "//chrome/browser/endpoint_fetcher:jni_headers", "//chrome/browser/feed/android:jni_headers", "//chrome/browser/feedback/android", "//chrome/browser/feedback/android:jni_headers",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index a57cdc9e..bb24dd6 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -497,10 +497,6 @@ {flag_descriptions::kWebXrRuntimeChoiceCardboard, switches::kWebXrForceRuntime, switches::kWebXrRuntimeCardboard}, #endif -#if BUILDFLAG(ENABLE_GVR_SERVICES) - {flag_descriptions::kWebXrRuntimeChoiceGVR, switches::kWebXrForceRuntime, - switches::kWebXrRuntimeGVR}, -#endif #if BUILDFLAG(ENABLE_OPENXR) {flag_descriptions::kWebXrRuntimeChoiceOpenXR, switches::kWebXrForceRuntime, switches::kWebXrRuntimeOpenXr}, @@ -7120,11 +7116,6 @@ flag_descriptions::kTabStripStartupRefactoringDescription, kOsAndroid, FEATURE_VALUE_TYPE(chrome::android::kTabStripStartupRefactoring)}, - {"enable-baseline-gm3-surface-colors", - flag_descriptions::kBaselineGM3SurfaceColorsName, - flag_descriptions::kBaselineGM3SurfaceColorsDescription, kOsAndroid, - FEATURE_VALUE_TYPE(chrome::android::kBaselineGM3SurfaceColors)}, - {"enable-delay-temp-strip-removal", flag_descriptions::kDelayTempStripRemovalName, flag_descriptions::kDelayTempStripRemovalDescription, kOsAndroid, @@ -9309,13 +9300,6 @@ flag_descriptions::kSkiaGraphiteDescription, kOsAll, FEATURE_VALUE_TYPE(features::kSkiaGraphite)}, -#if BUILDFLAG(IS_ANDROID) - {"bookmarks-improved-save-flow", - flag_descriptions::kBookmarksImprovedSaveFlowName, - flag_descriptions::kBookmarksImprovedSaveFlowDescription, kOsAndroid, - FEATURE_VALUE_TYPE(chrome::android::kBookmarksImprovedSaveFlow)}, -#endif - {"enable-tab-audio-muting", flag_descriptions::kTabAudioMutingName, flag_descriptions::kTabAudioMutingDescription, kOsDesktop, FEATURE_VALUE_TYPE(media::kEnableTabMuting)}, @@ -9352,6 +9336,14 @@ flag_descriptions::kCustomizeChromeWallpaperSearchDescription, kOsDesktop, FEATURE_VALUE_TYPE(ntp_features::kCustomizeChromeWallpaperSearch)}, + {"customize-chrome-wallpaper-search-inspiration-card", + flag_descriptions::kCustomizeChromeWallpaperSearchInspirationCardName, + flag_descriptions:: + kCustomizeChromeWallpaperSearchInspirationCardDescription, + kOsDesktop, + FEATURE_VALUE_TYPE( + ntp_features::kCustomizeChromeWallpaperSearchInspirationCard)}, + {"wallpaper-search-settings-visibility", flag_descriptions::kWallpaperSearchSettingsVisibilityName, flag_descriptions::kWallpaperSearchSettingsVisibilityDescription,
diff --git a/chrome/browser/apps/app_service/publishers/guest_os_apps.cc b/chrome/browser/apps/app_service/publishers/guest_os_apps.cc index f53a125..9d26d46 100644 --- a/chrome/browser/apps/app_service/publishers/guest_os_apps.cc +++ b/chrome/browser/apps/app_service/publishers/guest_os_apps.cc
@@ -190,6 +190,18 @@ app->intent_filters = CreateIntentFilterForAppService(mime_types_service, registration); + app->SetExtraField("vm_name", registration.VmName()); + app->SetExtraField("container_name", registration.ContainerName()); + app->SetExtraField("desktop_file_id", registration.DesktopFileId()); + app->SetExtraField("exec", registration.Exec()); + app->SetExtraField("executable_file_name", registration.ExecutableFileName()); + app->SetExtraField("no_display", registration.NoDisplay()); + app->SetExtraField("terminal", registration.Terminal()); + app->SetExtraField("scaled", registration.IsScaled()); + app->SetExtraField("package_id", registration.PackageId()); + app->SetExtraField("startup_wm_class", registration.StartupWmClass()); + app->SetExtraField("startup_notify", registration.StartupNotify()); + // Allow subclasses of GuestOSApps to modify app. CreateAppOverrides(registration, app.get());
diff --git a/chrome/browser/apps/app_service/publishers/guest_os_apps_unittest.cc b/chrome/browser/apps/app_service/publishers/guest_os_apps_unittest.cc index 7ad66e5..a863b09 100644 --- a/chrome/browser/apps/app_service/publishers/guest_os_apps_unittest.cc +++ b/chrome/browser/apps/app_service/publishers/guest_os_apps_unittest.cc
@@ -176,6 +176,20 @@ EXPECT_TRUE(update.ShowInLauncher()); EXPECT_TRUE(update.ShowInSearch()); EXPECT_TRUE(update.ShowInShelf()); + EXPECT_EQ(bruschetta::kBruschettaVmName, + *update.Extra()->FindString("vm_name")); + EXPECT_EQ("test_container", + *update.Extra()->FindString("container_name")); + EXPECT_EQ("desktop_file_id", + *update.Extra()->FindString("desktop_file_id")); + EXPECT_EQ("", *update.Extra()->FindString("exec")); + EXPECT_EQ("", *update.Extra()->FindString("executable_file_name")); + EXPECT_FALSE(update.Extra()->FindBool("no_display").value()); + EXPECT_FALSE(update.Extra()->FindBool("terminal").value()); + EXPECT_FALSE(update.Extra()->FindBool("scaled").value()); + EXPECT_EQ("", *update.Extra()->FindString("package_id")); + EXPECT_EQ("", *update.Extra()->FindString("startup_wm_class")); + EXPECT_FALSE(update.Extra()->FindBool("startup_notify").value()); }); EXPECT_TRUE(seen) << "Couldn't find test app in registry."; }
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc index 99bcb2e5..90ff0e58 100644 --- a/chrome/browser/apps/guest_view/web_view_browsertest.cc +++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
@@ -20,6 +20,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/task/single_thread_task_runner.h" #include "base/test/bind.h" +#include "base/test/run_until.h" #include "base/test/scoped_feature_list.h" #include "base/test/test_mock_time_task_runner.h" #include "base/test/test_timeouts.h" @@ -44,7 +45,6 @@ #include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/browser_dialogs.h" #include "chrome/browser/ui/login/login_handler.h" -#include "chrome/browser/ui/login/login_handler_test_utils.h" #include "chrome/browser/usb/usb_browser_test_utils.h" #include "chrome/browser/usb/usb_chooser_context.h" #include "chrome/browser/usb/usb_chooser_context_factory.h" @@ -4018,10 +4018,6 @@ LoadAppWithGuest("web_view/simple"); const GURL auth_url = embedded_test_server()->GetURL("/auth-basic"); - content::NavigationController* guest_controller = - &GetGuestView()->GetController(); - WindowedAuthNeededObserver auth_needed(guest_controller); - WindowedAuthSuppliedObserver auth_supplied(guest_controller); // There are two navigations occurring here. The first fails due to the need // for auth. After it's supplied, a second navigation will succeed. content::TestNavigationObserver nav_observer(GetGuestWebContents(), 2); @@ -4031,12 +4027,12 @@ EXPECT_TRUE( content::ExecJs(GetGuestRenderFrameHost(), content::JsReplace("location.href = $1;", auth_url))); - auth_needed.Wait(); + ASSERT_TRUE(base::test::RunUntil( + []() { return LoginHandler::GetAllLoginHandlersForTest().size() == 1; })); LoginHandler* login_handler = LoginHandler::GetAllLoginHandlersForTest().front(); login_handler->SetAuth(u"basicuser", u"secret"); - auth_supplied.Wait(); nav_observer.WaitForNavigationFinished(); } @@ -4045,13 +4041,8 @@ LoadAppWithGuest("web_view/simple"); const GURL auth_url = embedded_test_server()->GetURL("/auth-basic"); - content::NavigationController* guest_controller = - &GetGuestView()->GetController(); content::NavigationController* tab_controller = &browser()->tab_strip_model()->GetActiveWebContents()->GetController(); - WindowedAuthNeededObserver guest_auth_needed(guest_controller); - WindowedAuthNeededObserver tab_auth_needed(tab_controller); - WindowedAuthSuppliedObserver guest_auth_supplied(guest_controller); // There are two navigations occurring here. The first fails due to the need // for auth. After it's supplied, a second navigation will succeed. content::TestNavigationObserver guest_nav_observer(GetGuestWebContents(), 2); @@ -4061,13 +4052,15 @@ EXPECT_TRUE( content::ExecJs(GetGuestRenderFrameHost(), content::JsReplace("location.href = $1;", auth_url))); - guest_auth_needed.Wait(); + ASSERT_TRUE(base::test::RunUntil( + []() { return LoginHandler::GetAllLoginHandlersForTest().size() == 1; })); // While the login UI is showing for the app, navigate a tab to the same URL // requiring auth. tab_controller->LoadURL(auth_url, content::Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - tab_auth_needed.Wait(); + ASSERT_TRUE(base::test::RunUntil( + []() { return LoginHandler::GetAllLoginHandlersForTest().size() == 2; })); // Both the guest and the tab should be prompting for credentials and the auth // challenge should be the same. Normally, the login code de-duplicates @@ -4085,7 +4078,6 @@ tab_login_handler->auth_info())); guest_login_handler->SetAuth(u"basicuser", u"secret"); - guest_auth_supplied.Wait(); guest_nav_observer.WaitForNavigationFinished(); // The tab should still be prompting for credentials.
diff --git a/chrome/browser/ash/BUILD.gn b/chrome/browser/ash/BUILD.gn index 768d43e7..6bdb0e1b 100644 --- a/chrome/browser/ash/BUILD.gn +++ b/chrome/browser/ash/BUILD.gn
@@ -126,6 +126,8 @@ "app_mode/arc/arc_kiosk_app_service_factory.cc", "app_mode/arc/arc_kiosk_app_service_factory.h", "app_mode/cancellable_job.h", + "app_mode/certificate_manager_dialog.cc", + "app_mode/certificate_manager_dialog.h", "app_mode/crash_recovery_launcher.cc", "app_mode/crash_recovery_launcher.h", "app_mode/kiosk_app.cc",
diff --git a/chrome/browser/ash/accessibility/automation_test_utils.cc b/chrome/browser/ash/accessibility/automation_test_utils.cc index 36b014aa..4e23a21 100644 --- a/chrome/browser/ash/accessibility/automation_test_utils.cc +++ b/chrome/browser/ash/accessibility/automation_test_utils.cc
@@ -13,6 +13,7 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" #include "base/strings/stringprintf.h" +#include "base/strings/to_string.h" #include "base/threading/thread_restrictions.h" #include "chrome/browser/ash/accessibility/accessibility_manager.h" #include "chrome/browser/ash/accessibility/accessibility_test_utils.h" @@ -125,6 +126,16 @@ ExecuteScriptInExtensionPage(script); } +void AutomationTestUtils::WaitForNumTabsWithRegexName(int num, + const std::string& name) { + std::string script = + base::StringPrintf(R"( + globalThis.automationTestSupport.waitForNumTabsWithName(%s, %s); + )", + base::ToString(num).c_str(), name.c_str()); + ExecuteScriptInExtensionPage(script); +} + std::string AutomationTestUtils::GetValueForNodeWithClassName( const std::string& class_name) { std::string script = base::StringPrintf(R"( @@ -134,6 +145,16 @@ return ExecuteScriptInExtensionPage(script); } +void AutomationTestUtils::WaitForNodeWithClassNameAndValue( + const std::string& class_name, + const std::string& value) { + std::string script = base::StringPrintf(R"( + globalThis.automationTestSupport.waitForNodeWithClassNameAndValue( + `%s`, `%s`);)", + class_name.c_str(), value.c_str()); + ExecuteScriptInExtensionPage(script); +} + std::string AutomationTestUtils::ExecuteScriptInExtensionPage( const std::string& script) { // Note SpokenFeedbackTest uses ExecuteScriptInBackgroundPageDeprecated.
diff --git a/chrome/browser/ash/accessibility/automation_test_utils.h b/chrome/browser/ash/accessibility/automation_test_utils.h index 6d83b456..8dff5ce 100644 --- a/chrome/browser/ash/accessibility/automation_test_utils.h +++ b/chrome/browser/ash/accessibility/automation_test_utils.h
@@ -38,6 +38,10 @@ // Gets the value of the node with the given `class_name`. std::string GetValueForNodeWithClassName(const std::string& class_name); + // Waits for the node with the given `class_name` to have the value `value`. + void WaitForNodeWithClassNameAndValue(const std::string& class_name, + const std::string& value); + // Gets the bounds of the automation node with the given // `name` and `role` in density-independent pixels. Will wait // for the node to exist if it does not exist already. @@ -72,6 +76,9 @@ // on the desktop node. void WaitForChildrenChangedEvent(); + // Waits for there to be `num` tabs in the tabstrip with regex name `name`. + void WaitForNumTabsWithRegexName(int num, const std::string& name); + private: std::string ExecuteScriptInExtensionPage(const std::string& script); std::string extension_id_;
diff --git a/chrome/browser/ash/accessibility/sticky_keys_browsertest.cc b/chrome/browser/ash/accessibility/sticky_keys_browsertest.cc index e3c3762..7cd8309 100644 --- a/chrome/browser/ash/accessibility/sticky_keys_browsertest.cc +++ b/chrome/browser/ash/accessibility/sticky_keys_browsertest.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include <stddef.h> +#include <memory> #include "ash/accessibility/sticky_keys/sticky_keys_controller.h" #include "ash/accessibility/sticky_keys/sticky_keys_overlay.h" @@ -11,27 +12,33 @@ #include "ash/system/status_area_widget.h" #include "ash/system/unified/unified_system_tray.h" #include "base/run_loop.h" +#include "chrome/browser/ash/accessibility/accessibility_feature_browsertest.h" #include "chrome/browser/ash/accessibility/accessibility_manager.h" +#include "chrome/browser/ash/accessibility/automation_test_utils.h" +#include "chrome/browser/ash/accessibility/select_to_speak_test_utils.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_window.h" -#include "chrome/browser/ui/location_bar/location_bar.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/view_ids.h" +#include "chrome/common/extensions/extension_constants.h" #include "chrome/common/pref_names.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/interactive_test_utils.h" #include "chrome/test/base/ui_test_utils.h" -#include "components/omnibox/browser/omnibox_view.h" #include "components/prefs/pref_service.h" +#include "components/user_prefs/user_prefs.h" #include "content/public/test/browser_test.h" #include "ui/aura/window_event_dispatcher.h" #include "ui/events/keycodes/keyboard_codes.h" +#include "ui/events/keycodes/keyboard_codes_posix.h" +#include "ui/events/test/event_generator.h" #include "ui/gfx/native_widget_types.h" namespace ash { -class StickyKeysBrowserTest : public InProcessBrowserTest { +class StickyKeysBrowserTest : public AccessibilityFeatureBrowserTest { protected: StickyKeysBrowserTest() = default; @@ -40,6 +47,21 @@ ~StickyKeysBrowserTest() override = default; + void SetUpOnMainThread() override { + aura::Window* root_window = Shell::Get()->GetPrimaryRootWindow(); + generator_ = std::make_unique<ui::test::EventGenerator>(root_window); + Profile* profile = ProfileManager::GetActiveUserProfile(); + + AccessibilityFeatureBrowserTest::SetUpOnMainThread(); + // Load Select to Speak so we have a Javascript context with access to the + // Automation API to inject AutomationTestUtils. Select to Speak doesn't do + // any work unless it is triggered, so this does not impact the test. + sts_test_utils::TurnOnSelectToSpeakForTest(profile); + utils_ = std::make_unique<AutomationTestUtils>( + extension_misc::kSelectToSpeakExtensionId); + utils_->SetUpTestSupport(); + } + void SetStickyKeysEnabled(bool enabled) { AccessibilityManager::Get()->EnableStickyKeys(enabled); // Spin the message loop to ensure ash sees the change. @@ -63,11 +85,14 @@ } void SendKeyPress(ui::KeyboardCode key) { - EXPECT_TRUE(ui_test_utils::SendKeyPressSync(browser(), key, false, false, - false, false)); + ui::test::EmulateFullKeyPressReleaseSequence( + generator_.get(), key, + /*control=*/false, /*shift=*/false, /*alt=*/false, /*command=*/false); } content::NotificationRegistrar registrar_; + std::unique_ptr<ui::test::EventGenerator> generator_; + std::unique_ptr<AutomationTestUtils> utils_; }; IN_PROC_BROWSER_TEST_F(StickyKeysBrowserTest, OpenTrayMenu) { @@ -102,25 +127,26 @@ SendKeyPress(ui::VKEY_CONTROL); // In the locked state, pressing 't' should open a new tab each time. - TabStripModel* tab_strip_model = browser()->tab_strip_model(); - int tab_count = 1; + // Note Lacros starts with a "New Tab" tab, whereas Ash does not. + int tab_count = IsLacrosRunning() ? 2 : 1; for (; tab_count < 5; ++tab_count) { - EXPECT_EQ(tab_count, tab_strip_model->count()); SendKeyPress(ui::VKEY_T); + utils_->WaitForNumTabsWithRegexName(tab_count, "/New Tab*/"); } // Unlock the modifier key and shortcut should no longer activate. + // Instead, the omnibox is populated with the letter 't'. SendKeyPress(ui::VKEY_CONTROL); SendKeyPress(ui::VKEY_T); - EXPECT_EQ(tab_count, tab_strip_model->count()); - EXPECT_EQ(tab_count - 1, tab_strip_model->active_index()); + utils_->WaitForNodeWithClassNameAndValue("OmniboxViewViews", "t"); // Shortcut should not work after disabling sticky keys. + // Instead, another 't' is typed in the omnibox. SetStickyKeysEnabled(false); SendKeyPress(ui::VKEY_CONTROL); SendKeyPress(ui::VKEY_CONTROL); SendKeyPress(ui::VKEY_T); - EXPECT_EQ(tab_count, tab_strip_model->count()); + utils_->WaitForNodeWithClassNameAndValue("OmniboxViewViews", "tt"); } IN_PROC_BROWSER_TEST_F(StickyKeysBrowserTest, CtrlClickHomeButton) { @@ -159,39 +185,30 @@ IN_PROC_BROWSER_TEST_F(StickyKeysBrowserTest, SearchLeftOmnibox) { SetStickyKeysEnabled(true); - OmniboxView* omnibox = - browser()->window()->GetLocationBar()->GetOmniboxView(); + // Give omnibox focus by opening a new tab with ctrl+t. + SendKeyPress(ui::VKEY_CONTROL); + SendKeyPress(ui::VKEY_T); - // Give the omnibox focus. - omnibox->SetFocus(/*is_user_initiated=*/true); - - // Make sure that the AppList is not erroneously displayed and the omnibox - // doesn't lose focus. - EXPECT_TRUE(omnibox->GetNativeView()->HasFocus()); + utils_->WaitForNumTabsWithRegexName(IsLacrosRunning() ? 2 : 1, "/New Tab*/"); // Type 'foo'. SendKeyPress(ui::VKEY_F); SendKeyPress(ui::VKEY_O); SendKeyPress(ui::VKEY_O); - // Verify the location of the caret. - size_t start, end; - omnibox->GetSelectionBounds(&start, &end); - ASSERT_EQ(3U, start); - ASSERT_EQ(3U, end); - - EXPECT_TRUE(omnibox->GetNativeView()->HasFocus()); + utils_->WaitForNodeWithClassNameAndValue("OmniboxViewViews", "foo"); // Hit Home by sequencing Search (left Windows) and Left (arrow). SendKeyPress(ui::VKEY_LWIN); SendKeyPress(ui::VKEY_LEFT); - EXPECT_TRUE(omnibox->GetNativeView()->HasFocus()); + // Verify caret moved to the beginning by typing something else, this + // should appear before "foo" in the omnibox. + SendKeyPress(ui::VKEY_B); + SendKeyPress(ui::VKEY_A); + SendKeyPress(ui::VKEY_R); - // Verify caret moved to the beginning. - omnibox->GetSelectionBounds(&start, &end); - ASSERT_EQ(0U, start); - ASSERT_EQ(0U, end); + utils_->WaitForNodeWithClassNameAndValue("OmniboxViewViews", "barfoo"); } IN_PROC_BROWSER_TEST_F(StickyKeysBrowserTest, OverlayShown) { @@ -230,10 +247,6 @@ } IN_PROC_BROWSER_TEST_F(StickyKeysBrowserTest, OpenIncognitoWindow) { - ui_test_utils::BrowserChangeObserver browser_change_observer( - /*browser=*/nullptr, - ui_test_utils::BrowserChangeObserver::ChangeType::kAdded); - SetStickyKeysEnabled(true); StickyKeysOverlay* overlay = Shell::Get()->sticky_keys_controller()->GetOverlayForTest(); @@ -246,24 +259,41 @@ SendKeyPress(ui::VKEY_CONTROL); EXPECT_TRUE(overlay->is_visible()); SendKeyPress(ui::VKEY_N); + EXPECT_FALSE(overlay->is_visible()); - Browser* incognito_browser = browser_change_observer.Wait(); - EXPECT_TRUE(incognito_browser->profile()->IsIncognitoProfile()); + utils_->WaitForNumTabsWithRegexName(1, "/New Incognito Tab*/"); } IN_PROC_BROWSER_TEST_F(StickyKeysBrowserTest, CyclesWindows) { - Browser* browser2 = CreateBrowser(browser()->profile()); - browser2->window()->Activate(); - EXPECT_TRUE(browser2->window()->IsActive()); - EXPECT_FALSE(browser()->window()->IsActive()); - SetStickyKeysEnabled(true); + // Ensure there is a normal browser window open with ctrl+t. + SendKeyPress(ui::VKEY_CONTROL); + SendKeyPress(ui::VKEY_T); + int expected_tabs = IsLacrosRunning() ? 2 : 1; + utils_->WaitForNumTabsWithRegexName(expected_tabs, "/New Tab*/"); + + // Open an incognito browser. + SendKeyPress(ui::VKEY_SHIFT); + SendKeyPress(ui::VKEY_CONTROL); + SendKeyPress(ui::VKEY_N); + utils_->WaitForNumTabsWithRegexName(1, "/New Incognito Tab*/"); + + // Ctrl+t opens another incognito tab because the incognito window is focused. + SendKeyPress(ui::VKEY_CONTROL); + SendKeyPress(ui::VKEY_T); + utils_->WaitForNumTabsWithRegexName(2, "/New Incognito Tab*/"); + + // Cycle between windows. SendKeyPress(ui::VKEY_MENU); // alt key. SendKeyPress(ui::VKEY_TAB); - EXPECT_TRUE(browser()->window()->IsActive()); - EXPECT_FALSE(browser2->window()->IsActive()); + // Ctrl+t opens another non-incognito tab now, because the normal browser + // window is focused. + SendKeyPress(ui::VKEY_CONTROL); + SendKeyPress(ui::VKEY_T); + expected_tabs++; + utils_->WaitForNumTabsWithRegexName(expected_tabs, "/New Tab*/"); } } // namespace ash
diff --git a/chrome/browser/ash/app_mode/certificate_manager_dialog.cc b/chrome/browser/ash/app_mode/certificate_manager_dialog.cc new file mode 100644 index 0000000..93433c0 --- /dev/null +++ b/chrome/browser/ash/app_mode/certificate_manager_dialog.cc
@@ -0,0 +1,46 @@ +// Copyright 2014 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/ash/app_mode/certificate_manager_dialog.h" + +#include "base/strings/utf_string_conversions.h" +#include "chrome/browser/ash/login/helper.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/browser_dialogs.h" +#include "chrome/common/url_constants.h" +#include "chrome/grit/generated_resources.h" +#include "content/public/browser/browser_thread.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/size.h" +#include "ui/views/controls/webview/web_dialog_view.h" + +namespace { + +// The width matches the Settings UI width. +const int kDefaultWidth = 640; +const int kDefaultHeight = 480; + +} // namespace + +namespace ash { + +CertificateManagerDialog::CertificateManagerDialog(Profile* profile, + gfx::NativeWindow window) + : LoginWebDialog(profile, + window, + std::u16string(), + GURL(chrome::kChromeUICertificateManagerDialogURL)) {} + +CertificateManagerDialog::~CertificateManagerDialog() = default; + +std::u16string CertificateManagerDialog::GetDialogTitle() const { + return l10n_util::GetStringUTF16(IDS_CERTIFICATE_MANAGER_TITLE); +} + +void CertificateManagerDialog::GetDialogSize(gfx::Size* size) const { + size->SetSize(kDefaultWidth, kDefaultHeight); +} + +} // namespace ash
diff --git a/chrome/browser/ash/app_mode/certificate_manager_dialog.h b/chrome/browser/ash/app_mode/certificate_manager_dialog.h new file mode 100644 index 0000000..e6d38cb --- /dev/null +++ b/chrome/browser/ash/app_mode/certificate_manager_dialog.h
@@ -0,0 +1,30 @@ +// Copyright 2014 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_ASH_APP_MODE_CERTIFICATE_MANAGER_DIALOG_H_ +#define CHROME_BROWSER_ASH_APP_MODE_CERTIFICATE_MANAGER_DIALOG_H_ + +#include "chrome/browser/ash/login/ui/login_web_dialog.h" +#include "ui/gfx/native_widget_types.h" + +class Profile; + +namespace ash { + +// This dialog is used to manage user certificates from the kiosk launch screen. +class CertificateManagerDialog : public LoginWebDialog { + public: + CertificateManagerDialog(Profile* profile, gfx::NativeWindow window); + CertificateManagerDialog(const CertificateManagerDialog&) = delete; + CertificateManagerDialog& operator=(const CertificateManagerDialog&) = delete; + ~CertificateManagerDialog() override; + + // ui::WebDialogDelegate + std::u16string GetDialogTitle() const override; + void GetDialogSize(gfx::Size* size) const override; +}; + +} // namespace ash + +#endif // CHROME_BROWSER_ASH_APP_MODE_CERTIFICATE_MANAGER_DIALOG_H_
diff --git a/chrome/browser/ash/file_manager/file_manager_browsertest.cc b/chrome/browser/ash/file_manager/file_manager_browsertest.cc index ff45d150..067ac4c 100644 --- a/chrome/browser/ash/file_manager/file_manager_browsertest.cc +++ b/chrome/browser/ash/file_manager/file_manager_browsertest.cc
@@ -1925,9 +1925,7 @@ Recents, /* recents.js */ FilesAppBrowserTest, ::testing::Values( -#if !defined(ADDRESS_SANITIZER) && !defined(LEAK_SANITIZER) TestCase("recentsNested").NewDirectoryTree(), -#endif TestCase("recentsFilterResetToAll").NewDirectoryTree(), TestCase("recentsA11yMessages") .NewDirectoryTree()
diff --git a/chrome/browser/ash/guest_os/guest_os_registry_service.cc b/chrome/browser/ash/guest_os/guest_os_registry_service.cc index 7b006b4f..0fc7174 100644 --- a/chrome/browser/ash/guest_os/guest_os_registry_service.cc +++ b/chrome/browser/ash/guest_os/guest_os_registry_service.cc
@@ -447,6 +447,14 @@ return GetBool(guest_os::prefs::kAppScaledKey); } +std::string GuestOsRegistryService::Registration::StartupWmClass() const { + return GetString(guest_os::prefs::kAppStartupWMClassKey); +} + +bool GuestOsRegistryService::Registration::StartupNotify() const { + return GetBool(guest_os::prefs::kAppStartupNotifyKey); +} + std::string GuestOsRegistryService::Registration::GetString( base::StringPiece key) const { return GetStringKey(pref_, key);
diff --git a/chrome/browser/ash/guest_os/guest_os_registry_service.h b/chrome/browser/ash/guest_os/guest_os_registry_service.h index 6c7124b..1d0f5389 100644 --- a/chrome/browser/ash/guest_os/guest_os_registry_service.h +++ b/chrome/browser/ash/guest_os/guest_os_registry_service.h
@@ -117,6 +117,9 @@ guest_os::GuestId ToGuestId() const; + std::string StartupWmClass() const; + bool StartupNotify() const; + private: std::string GetString(base::StringPiece key) const; bool GetBool(base::StringPiece key) const;
diff --git a/chrome/browser/ash/login/saml/saml_browsertest.cc b/chrome/browser/ash/login/saml/saml_browsertest.cc index 4616129..92a11a2 100644 --- a/chrome/browser/ash/login/saml/saml_browsertest.cc +++ b/chrome/browser/ash/login/saml/saml_browsertest.cc
@@ -22,6 +22,7 @@ #include "base/test/bind.h" #include "base/test/gmock_callback_support.h" #include "base/test/metrics/histogram_tester.h" +#include "base/test/run_until.h" #include "base/test/scoped_feature_list.h" #include "base/test/test_future.h" #include "base/values.h" @@ -58,7 +59,6 @@ #include "chrome/browser/profiles/profile_key.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/login/login_handler.h" -#include "chrome/browser/ui/login/login_handler_test_utils.h" #include "chrome/browser/ui/webui/ash/login/gaia_screen_handler.h" #include "chrome/browser/ui/webui/ash/login/saml_challenge_key_handler.h" #include "chrome/browser/ui/webui/ash/login/saml_confirm_password_handler.h" @@ -511,16 +511,9 @@ extensions::WebViewGuest* gaia_guest = signin::GetAuthWebViewGuest( GetLoginUI()->GetWebContents(), gaia_frame_parent_); ASSERT_TRUE(gaia_guest); - content::NavigationController* gaia_frame_navigation_controller = - &gaia_guest->GetController(); // Start observing before initiating SAML sign-in. content::DOMMessageQueue message_queue(GetLoginUI()->GetWebContents()); - LoginPromptBrowserTestObserver login_prompt_observer; - login_prompt_observer.Register(content::Source<content::NavigationController>( - gaia_frame_navigation_controller)); - WindowedAuthNeededObserver auth_needed_waiter( - gaia_frame_navigation_controller); SetupAuthFlowChangeListener(); LoginDisplayHost::default_host() @@ -529,9 +522,9 @@ ->ShowSigninScreenForTest(saml_test_users::kFirstUserCorpExampleComEmail, "", "[]"); - auth_needed_waiter.Wait(); - ASSERT_FALSE(login_prompt_observer.handlers().empty()); - LoginHandler* handler = *login_prompt_observer.handlers().begin(); + ASSERT_TRUE(base::test::RunUntil( + []() { return LoginHandler::GetAllLoginHandlersForTest().size() == 1; })); + LoginHandler* handler = LoginHandler::GetAllLoginHandlersForTest().front(); // Note that the actual credentials don't matter because `fake_saml_idp()` // doesn't check those (only that something has been provided). handler->SetAuth(u"user", u"pwd");
diff --git a/chrome/browser/ash/login/screens/error_screen.cc b/chrome/browser/ash/login/screens/error_screen.cc index f680bdb..5ca71ab 100644 --- a/chrome/browser/ash/login/screens/error_screen.cc +++ b/chrome/browser/ash/login/screens/error_screen.cc
@@ -16,12 +16,12 @@ #include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/apps/app_service/browser_app_launcher.h" +#include "chrome/browser/ash/app_mode/certificate_manager_dialog.h" #include "chrome/browser/ash/login/auth/chrome_login_performer.h" #include "chrome/browser/ash/login/chrome_restart_request.h" #include "chrome/browser/ash/login/ui/captive_portal_window_proxy.h" #include "chrome/browser/ash/login/ui/login_display_host.h" #include "chrome/browser/ash/login/ui/login_display_host_mojo.h" -#include "chrome/browser/ash/login/ui/login_web_dialog.h" #include "chrome/browser/ash/login/ui/webui_login_view.h" #include "chrome/browser/ash/login/wizard_controller.h" #include "chrome/browser/ash/settings/cros_settings.h" @@ -35,14 +35,12 @@ #include "chrome/browser/ui/webui/ash/login/network_state_informer.h" #include "chrome/browser/ui/webui/ash/login/offline_login_screen_handler.h" #include "chrome/grit/browser_resources.h" -#include "chrome/grit/generated_resources.h" #include "chromeos/ash/components/network/network_connection_handler.h" #include "chromeos/ash/components/network/network_handler.h" #include "chromeos/ash/components/network/network_state_handler.h" #include "chromeos/dbus/power/power_manager_client.h" #include "components/web_modal/web_contents_modal_dialog_manager.h" #include "third_party/cros_system_api/dbus/service_constants.h" -#include "ui/base/l10n/l10n_util.h" #include "ui/gfx/native_widget_types.h" namespace ash { @@ -382,12 +380,8 @@ void ErrorScreen::OnConfigureCerts() { gfx::NativeWindow native_window = LoginDisplayHost::default_host()->GetNativeWindow(); - LoginWebDialog* dialog = new LoginWebDialog( - GetAppProfile(), native_window, - l10n_util::GetStringUTF16(IDS_CERTIFICATE_MANAGER_TITLE), - GURL(chrome::kChromeUICertificateManagerDialogURL)); - // The width matches the Settings UI width. - dialog->set_dialog_size(gfx::Size{640, 480}); + CertificateManagerDialog* dialog = + new CertificateManagerDialog(GetAppProfile(), native_window); dialog->Show(); }
diff --git a/chrome/browser/ash/login/ui/login_web_dialog.cc b/chrome/browser/ash/login/ui/login_web_dialog.cc index ab4aa1bf..bef0c12 100644 --- a/chrome/browser/ash/login/ui/login_web_dialog.cc +++ b/chrome/browser/ash/login/ui/login_web_dialog.cc
@@ -33,6 +33,12 @@ base::LazyInstance<base::circular_deque<WebContents*>>::DestructorAtExit g_web_contents_stack = LAZY_INSTANCE_INITIALIZER; +// Returns the accelerator which is mapped as hangup button on Chrome OS CFM +// remote controller to close the dialog. +ui::Accelerator GetCloseAccelerator() { + return ui::Accelerator(ui::VKEY_BROWSER_BACK, ui::EF_SHIFT_DOWN); +} + } // namespace /////////////////////////////////////////////////////////////////////////////// @@ -42,24 +48,14 @@ gfx::NativeWindow parent_window, const std::u16string& title, const GURL& url) - : browser_context_(browser_context), parent_window_(parent_window) { + : browser_context_(browser_context), + parent_window_(parent_window), + title_(title), + url_(url) { if (!parent_window_ && LoginDisplayHost::default_host()) parent_window_ = LoginDisplayHost::default_host()->GetNativeWindow(); LOG_IF(WARNING, !parent_window_) << "No parent window. Dialog sizes could be wrong"; - - RegisterAccelerator(ui::Accelerator(ui::VKEY_BROWSER_BACK, ui::EF_SHIFT_DOWN), - base::BindRepeating(&LoginWebDialog::MaybeCloseWindow, - base::Unretained(this))); - RegisterOnDialogClosedCallback( - base::BindOnce(&LoginWebDialog::OnDialogClosing, base::Unretained(this))); - set_dialog_modal_type(ui::MODAL_TYPE_SYSTEM); - set_dialog_content_url(url); - set_minimum_dialog_size(kMinSize); - set_dialog_title(title); - set_show_dialog_title(true); - set_allow_default_context_menu(false); - set_allow_web_contents_creation(false); } LoginWebDialog::~LoginWebDialog() {} @@ -69,9 +65,25 @@ chrome::ShowWebDialog(parent_window_, browser_context_, this); } +void LoginWebDialog::SetDialogTitle(const std::u16string& title) { + title_ = title; +} + /////////////////////////////////////////////////////////////////////////////// // LoginWebDialog, protected: +ui::ModalType LoginWebDialog::GetDialogModalType() const { + return ui::MODAL_TYPE_SYSTEM; +} + +std::u16string LoginWebDialog::GetDialogTitle() const { + return title_; +} + +GURL LoginWebDialog::GetDialogContentURL() const { + return url_; +} + void LoginWebDialog::GetDialogSize(gfx::Size* size) const { // TODO(https://crbug.com/1022774): Fix for the lock screen. if (!parent_window_) { @@ -85,6 +97,14 @@ size->SetToMax(kMinSize); } +void LoginWebDialog::GetMinimumDialogSize(gfx::Size* size) const { + *size = kMinSize; +} + +std::string LoginWebDialog::GetDialogArgs() const { + return std::string(); +} + // static. WebContents* LoginWebDialog::GetCurrentWebContents() { auto& stack = g_web_contents_stack.Get(); @@ -95,8 +115,9 @@ g_web_contents_stack.Pointer()->push_front(webui->GetWebContents()); } -void LoginWebDialog::OnDialogClosing(const std::string& json_retval) { +void LoginWebDialog::OnDialogClosed(const std::string& json_retval) { dialog_window_ = nullptr; + delete this; } void LoginWebDialog::OnCloseContents(WebContents* source, @@ -105,6 +126,19 @@ if (GetCurrentWebContents() == source) g_web_contents_stack.Pointer()->pop_front(); + // Else: TODO(pkotwicz): Investigate if the else case should ever be hit. + // http://crbug.com/419837 +} + +bool LoginWebDialog::ShouldShowDialogTitle() const { + return true; +} + +bool LoginWebDialog::HandleContextMenu( + content::RenderFrameHost& render_frame_host, + const content::ContextMenuParams& params) { + // Disable context menu. + return true; } bool LoginWebDialog::HandleOpenURLFromTab(WebContents* source, @@ -119,13 +153,24 @@ return (source && !chrome::FindBrowserWithTab(source)); } -bool LoginWebDialog::MaybeCloseWindow(WebDialogDelegate& delegate, - const ui::Accelerator& accelerator) { +bool LoginWebDialog::HandleShouldOverrideWebContentsCreation() { + return true; +} + +std::vector<ui::Accelerator> LoginWebDialog::GetAccelerators() { + return {GetCloseAccelerator()}; +} + +bool LoginWebDialog::AcceleratorPressed(const ui::Accelerator& accelerator) { if (!dialog_window_) return false; - views::Widget::GetWidgetForNativeWindow(dialog_window_)->Close(); - return true; + if (GetCloseAccelerator() == accelerator) { + views::Widget::GetWidgetForNativeWindow(dialog_window_)->Close(); + return true; + } + + return false; } } // namespace ash
diff --git a/chrome/browser/ash/login/ui/login_web_dialog.h b/chrome/browser/ash/login/ui/login_web_dialog.h index 14c06b0..443a79e 100644 --- a/chrome/browser/ash/login/ui/login_web_dialog.h +++ b/chrome/browser/ash/login/ui/login_web_dialog.h
@@ -37,6 +37,9 @@ void Show(); + // Overrides dialog title. + void SetDialogTitle(const std::u16string& title); + static content::WebContents* GetCurrentWebContents(); // Returns `dialog_window_` instance for test, can be NULL if dialog is not @@ -47,22 +50,34 @@ protected: // ui::WebDialogDelegate implementation. + ui::ModalType GetDialogModalType() const override; + std::u16string GetDialogTitle() const override; + GURL GetDialogContentURL() const override; void GetDialogSize(gfx::Size* size) const override; + void GetMinimumDialogSize(gfx::Size* size) const override; + std::string GetDialogArgs() const override; void OnDialogShown(content::WebUI* webui) override; + // NOTE: This function deletes this object at the end. + void OnDialogClosed(const std::string& json_retval) override; void OnCloseContents(content::WebContents* source, bool* out_close_dialog) override; + bool ShouldShowDialogTitle() const override; + bool HandleContextMenu(content::RenderFrameHost& render_frame_host, + const content::ContextMenuParams& params) override; bool HandleOpenURLFromTab(content::WebContents* source, const content::OpenURLParams& params, content::WebContents** out_new_contents) override; + bool HandleShouldOverrideWebContentsCreation() override; + std::vector<ui::Accelerator> GetAccelerators() override; + bool AcceleratorPressed(const ui::Accelerator& accelerator) override; private: - bool MaybeCloseWindow(ui::WebDialogDelegate& delegate, - const ui::Accelerator& accelerator); - void OnDialogClosing(const std::string& json_retval); - const raw_ptr<content::BrowserContext, ExperimentalAsh> browser_context_; gfx::NativeWindow parent_window_; gfx::NativeWindow dialog_window_; + + std::u16string title_; + const GURL url_; }; } // namespace ash
diff --git a/chrome/browser/ash/login/ui/simple_web_view_dialog_browsertest.cc b/chrome/browser/ash/login/ui/simple_web_view_dialog_browsertest.cc index c8db1478..97bc968 100644 --- a/chrome/browser/ash/login/ui/simple_web_view_dialog_browsertest.cc +++ b/chrome/browser/ash/login/ui/simple_web_view_dialog_browsertest.cc
@@ -6,9 +6,10 @@ #include <memory> +#include "base/test/run_until.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_finder.h" -#include "chrome/browser/ui/login/login_handler_test_utils.h" +#include "chrome/browser/ui/login/login_handler.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/views/chrome_test_widget.h" #include "content/public/browser/web_contents.h" @@ -40,9 +41,8 @@ dialog->Init(); // Wait for http auth login view to show up. No crash should happen. - content::WebContents* contents = dialog->GetActiveWebContents(); - content::NavigationController* controller = &contents->GetController(); - WindowedAuthNeededObserver(controller).Wait(); + ASSERT_TRUE(base::test::RunUntil( + []() { return LoginHandler::GetAllLoginHandlersForTest().size() == 1; })); } } // namespace ash
diff --git a/chrome/browser/ash/net/system_proxy_manager_browsertest.cc b/chrome/browser/ash/net/system_proxy_manager_browsertest.cc index 8337bf5..8d60c63 100644 --- a/chrome/browser/ash/net/system_proxy_manager_browsertest.cc +++ b/chrome/browser/ash/net/system_proxy_manager_browsertest.cc
@@ -15,6 +15,7 @@ #include "base/task/current_thread.h" #include "base/test/bind.h" #include "base/test/gtest_tags.h" +#include "base/test/run_until.h" #include "chrome/browser/ash/login/test/device_state_mixin.h" #include "chrome/browser/ash/notifications/request_system_proxy_credentials_view.h" #include "chrome/browser/ash/policy/affiliation/affiliation_test_helper.h" @@ -23,7 +24,6 @@ #include "chrome/browser/notifications/notification_display_service_tester.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/login/login_handler.h" -#include "chrome/browser/ui/login/login_handler_test_utils.h" #include "chrome/common/pref_names.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/testing_browser_process.h" @@ -677,19 +677,14 @@ // login dialog with `username` and `password`. void LoginWithDialog(const std::u16string& username, const std::u16string& password) { - LoginPromptBrowserTestObserver login_observer; - login_observer.Register(content::Source<content::NavigationController>( - &GetWebContents()->GetController())); - WindowedAuthNeededObserver auth_needed(&GetWebContents()->GetController()); ASSERT_TRUE( ui_test_utils::NavigateToURL(browser(), GetServerUrl("/simple.html"))); - auth_needed.Wait(); - WindowedAuthSuppliedObserver auth_supplied( - &GetWebContents()->GetController()); - LoginHandler* login_handler = login_observer.handlers().front(); + ASSERT_TRUE(base::test::RunUntil([]() { + return LoginHandler::GetAllLoginHandlersForTest().size() == 1; + })); + LoginHandler* login_handler = + LoginHandler::GetAllLoginHandlersForTest().front(); login_handler->SetAuth(username, password); - auth_supplied.Wait(); - EXPECT_EQ(1, login_observer.auth_supplied_count()); } void CheckEntryInHttpAuthCache(const std::string& auth_scheme,
diff --git a/chrome/browser/bookmarks/android/bookmark_bridge.cc b/chrome/browser/bookmarks/android/bookmark_bridge.cc index ba72796..2b906c7 100644 --- a/chrome/browser/bookmarks/android/bookmark_bridge.cc +++ b/chrome/browser/bookmarks/android/bookmark_bridge.cc
@@ -25,6 +25,7 @@ #include "base/i18n/string_compare.h" #include "base/logging.h" #include "base/memory/raw_ptr.h" +#include "base/notreached.h" #include "base/strings/utf_string_conversions.h" #include "base/uuid.h" #include "chrome/android/chrome_jni_headers/BookmarkBridge_jni.h" @@ -50,6 +51,7 @@ #include "components/power_bookmarks/core/proto/power_bookmark_meta.pb.h" #include "components/prefs/pref_service.h" #include "components/query_parser/query_parser.h" +#include "components/reading_list/core/dual_reading_list_model.h" #include "components/signin/public/identity_manager/identity_manager.h" #include "components/undo/bookmark_undo_service.h" #include "components/undo/undo_manager.h" @@ -139,14 +141,26 @@ model->GetUserData(kBookmarkBridgeUserDataKey)); if (!bookmark_bridge) { + auto reading_list_id_generation_func = + base::BindRepeating([](int64_t* id) { return (*id)++; }, + base::Owned(std::make_unique<int64_t>(0))); + auto* dual_reading_list = + ReadingListModelFactory::GetAsDualReadingListForBrowserContext(profile); + std::unique_ptr<ReadingListManagerImpl> account_reading_list_manager = + nullptr; + auto* account_model = dual_reading_list->GetAccountModelIfSyncing(); + if (account_model) { + account_reading_list_manager = std::make_unique<ReadingListManagerImpl>( + account_model, reading_list_id_generation_func); + } bookmark_bridge = new BookmarkBridge( profile, model, ManagedBookmarkServiceFactory::GetForProfile(profile), PartnerBookmarksShim::BuildForBrowserContext( chrome::GetBrowserContextRedirectedInIncognito(profile)), std::make_unique<ReadingListManagerImpl>( - ReadingListModelFactory::GetForBrowserContext(profile), - base::BindRepeating([](int64_t* id) { return (*id)++; }, - base::Owned(std::make_unique<int64_t>(0)))), + dual_reading_list->GetLocalOrSyncableModel(), + reading_list_id_generation_func), + std::move(account_reading_list_manager), page_image_service::ImageServiceFactory::GetForBrowserContext(profile)); model->SetUserData(kBookmarkBridgeUserDataKey, base::WrapUnique(bookmark_bridge)); @@ -155,24 +169,34 @@ return ScopedJavaLocalRef(bookmark_bridge->GetJavaBookmarkModel()); } +// TODO(crbug.com/1510547): Support the account reading list availability +// changing at runtime. BookmarkBridge::BookmarkBridge( Profile* profile, BookmarkModel* model, bookmarks::ManagedBookmarkService* managed_bookmark_service, PartnerBookmarksShim* partner_bookmarks_shim, - std::unique_ptr<ReadingListManager> reading_list_manager, + std::unique_ptr<ReadingListManager> local_or_syncable_reading_list_manager, + std::unique_ptr<ReadingListManager> account_reading_list_manager, page_image_service::ImageService* image_service) : profile_(profile), bookmark_model_(model), managed_bookmark_service_(managed_bookmark_service), partner_bookmarks_shim_(partner_bookmarks_shim), - local_or_syncable_reading_list_manager_(std::move(reading_list_manager)), + local_or_syncable_reading_list_manager_( + std::move(local_or_syncable_reading_list_manager)), + account_reading_list_manager_(std::move(account_reading_list_manager)), image_service_(image_service), weak_ptr_factory_(this) { - profile_observation_.Observe(profile_.get()); - bookmark_model_->AddObserver(this); - partner_bookmarks_shim_->AddObserver(this); - local_or_syncable_reading_list_manager_->AddObserver(this); + profile_observation_.Observe(profile_); + bookmark_model_observation_.Observe(bookmark_model_); + partner_bookmarks_shim_observation_.Observe(partner_bookmarks_shim_); + reading_list_manager_observations_.AddObservation( + local_or_syncable_reading_list_manager_.get()); + if (account_reading_list_manager_) { + reading_list_manager_observations_.AddObservation( + account_reading_list_manager_.get()); + } pref_change_registrar_.Init(profile_->GetPrefs()); pref_change_registrar_.Add( @@ -193,14 +217,10 @@ } BookmarkBridge::~BookmarkBridge() { - if (profile_) { - DCHECK(profile_observation_.IsObservingSource(profile_.get())); - profile_observation_.Reset(); - } - bookmark_model_->RemoveObserver(this); - if (partner_bookmarks_shim_) - partner_bookmarks_shim_->RemoveObserver(this); - local_or_syncable_reading_list_manager_->RemoveObserver(this); + reading_list_manager_observations_.RemoveAllObservations(); + partner_bookmarks_shim_observation_.Reset(); + bookmark_model_observation_.Reset(); + profile_observation_.Reset(); } void BookmarkBridge::Destroy(JNIEnv*) { @@ -232,17 +252,35 @@ const JavaParamRef<jobject>& j_url) { DCHECK_CURRENTLY_ON(BrowserThread::UI); std::unique_ptr<GURL> url = url::GURLAndroid::ToNativeGURL(env, j_url); + CHECK(url); + const BookmarkNode* node = GetMostRecentlyAddedUserBookmarkIdForUrlImpl(*url); + if (node) { + return JavaBookmarkIdCreateBookmarkId(env, node->id(), + GetBookmarkType(node)); + } + return nullptr; +} + +const bookmarks::BookmarkNode* +BookmarkBridge::GetMostRecentlyAddedUserBookmarkIdForUrlImpl(const GURL& url) { std::vector<const bookmarks::BookmarkNode*> nodes; const auto* reading_list_node = - local_or_syncable_reading_list_manager_->Get(*url); + local_or_syncable_reading_list_manager_->Get(url); if (reading_list_node) { nodes.push_back(reading_list_node); } + if (account_reading_list_manager_) { + reading_list_node = account_reading_list_manager_->Get(url); + if (reading_list_node) { + nodes.push_back(reading_list_node); + } + } + // Get all the nodes for |url| from BookmarkModel and sort them by date added. std::vector<const bookmarks::BookmarkNode*> bookmarkModelResult = - BookmarkModelFactory::GetForBrowserContext(profile_)->GetNodesByURL(*url); + BookmarkModelFactory::GetForBrowserContext(profile_)->GetNodesByURL(url); nodes.insert(nodes.end(), bookmarkModelResult.begin(), bookmarkModelResult.end()); std::sort(nodes.begin(), nodes.end(), &bookmarks::MoreRecentlyAdded); @@ -252,8 +290,7 @@ } // Return the first node matching the search criteria. - return JavaBookmarkIdCreateBookmarkId(env, nodes.front()->id(), - GetBookmarkType(nodes.front())); + return nodes.front(); } jboolean BookmarkBridge::IsEditBookmarksEnabled(JNIEnv* env) { @@ -360,8 +397,18 @@ } std::vector<const BookmarkNode*> BookmarkBridge::GetTopLevelFolderIdsImpl() { std::vector<const BookmarkNode*> top_level_folders; - // Query the root node for: + // Query for the top-level folders: // bookmarks bar, mobile node, other node, and managed node (if it exists). + // Account bookmarks come first, and local bookmarks after. + + // TODO(crbug.com/1509189): Include account bookmarks when they're available. + // TODO(crbug.com/1509189): Hide empty local folders by default and add + // another function to get all top level folders to use when moving. + if (account_reading_list_manager_ && + account_reading_list_manager_->GetRoot()) { + top_level_folders.push_back(account_reading_list_manager_->GetRoot()); + } + for (const auto& root_child : bookmark_model_->root_node()->children()) { if (!root_child->IsVisible()) { continue; @@ -437,6 +484,19 @@ return folder_id_obj; } +base::android::ScopedJavaLocalRef<jobject> +BookmarkBridge::GetAccountReadingListFolder(JNIEnv* env) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + if (!account_reading_list_manager_) { + return nullptr; + } + + const BookmarkNode* root_node = account_reading_list_manager_->GetRoot(); + ScopedJavaLocalRef<jobject> folder_id_obj = JavaBookmarkIdCreateBookmarkId( + env, root_node->id(), GetBookmarkType(root_node)); + return folder_id_obj; +} + // TODO(crbug.com/1501998): Add logic to determine when to use account/local. base::android::ScopedJavaLocalRef<jobject> BookmarkBridge::GetDefaultReadingListFolder(JNIEnv* env) { @@ -567,6 +627,9 @@ } else if (local_or_syncable_reading_list_manager_->IsReadingListBookmark( bookmark)) { local_or_syncable_reading_list_manager_->SetTitle(bookmark->url(), title); + } else if (account_reading_list_manager_ && + account_reading_list_manager_->IsReadingListBookmark(bookmark)) { + account_reading_list_manager_->SetTitle(bookmark->url(), title); } else { bookmark_model_->SetTitle(bookmark, title, bookmarks::metrics::BookmarkEditSource::kUser); @@ -810,8 +873,10 @@ if (partner_bookmarks_shim_->IsPartnerBookmark(node)) { partner_bookmarks_shim_->RemoveBookmark(node); } else if (type == BookmarkType::BOOKMARK_TYPE_READING_LIST) { - const BookmarkNode* reading_list_parent = - local_or_syncable_reading_list_manager_->GetRoot(); + const BookmarkNode* reading_list_parent = node->parent(); + ReadingListManager* reading_list_manager = + GetReadingListManagerFromParentNode(reading_list_parent); + size_t index = reading_list_parent->GetIndexOf(node).value(); // Intentionally left empty. std::set<GURL> removed_urls; @@ -825,7 +890,7 @@ // ReadingListModelImpl::RemoveEntryByURLImpl. To avoid the // heap-use-after-free, make a copy of node->url() and use it. GURL url(node->url()); - local_or_syncable_reading_list_manager_->Delete(url); + reading_list_manager->Delete(url); } else { bookmark_model_->Remove(node, bookmarks::metrics::BookmarkEditSource::kUser); @@ -931,6 +996,23 @@ return count; } +jboolean BookmarkBridge::IsAccountBookmark(JNIEnv* env, + const JavaParamRef<jobject>& j_id) { + return IsAccountBookmarkImpl(GetNodeByID(JavaBookmarkIdGetId(env, j_id), + JavaBookmarkIdGetType(env, j_id))); +} + +bool BookmarkBridge::IsAccountBookmarkImpl(const BookmarkNode* node) { + if (account_reading_list_manager_ && + account_reading_list_manager_->IsReadingListBookmark(node)) { + return true; + } + + // TODO(crbug.com/1509189): Also check the bookmark model for account-ness + // when it's ready. + return false; +} + void BookmarkBridge::Undo(JNIEnv* env) { DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK(IsLoaded()); @@ -984,7 +1066,11 @@ int type = GetBookmarkType(node); bool read = false; - if (local_or_syncable_reading_list_manager_->IsReadingListBookmark(node)) { + if (account_reading_list_manager_ && + account_reading_list_manager_->IsReadingListBookmark(node)) { + read = account_reading_list_manager_->GetReadStatus(node); + } else if (local_or_syncable_reading_list_manager_->IsReadingListBookmark( + node)) { read = local_or_syncable_reading_list_manager_->GetReadStatus(node); } @@ -1009,13 +1095,22 @@ } const BookmarkNode* BookmarkBridge::GetNodeByID(long node_id, int type) { - const BookmarkNode* node; + const BookmarkNode* node = nullptr; DCHECK_CURRENTLY_ON(BrowserThread::UI); if (type == BookmarkType::BOOKMARK_TYPE_PARTNER) { node = partner_bookmarks_shim_->GetNodeByID(static_cast<int64_t>(node_id)); } else if (type == BookmarkType::BOOKMARK_TYPE_READING_LIST) { - node = local_or_syncable_reading_list_manager_->GetNodeByID( - static_cast<int64_t>(node_id)); + // First check the account reading list if it's available. + if (account_reading_list_manager_) { + node = account_reading_list_manager_->GetNodeByID( + static_cast<int64_t>(node_id)); + } + + // If there were no results, check the local/syncable reading list. + if (!node) { + node = local_or_syncable_reading_list_manager_->GetNodeByID( + static_cast<int64_t>(node_id)); + } } else { node = bookmarks::GetBookmarkNodeByID(bookmark_model_, static_cast<int64_t>(node_id)); @@ -1058,11 +1153,16 @@ } if (!IsEditBookmarksEnabled() || bookmark_model_->is_permanent_node(node)) return false; - if (partner_bookmarks_shim_->IsPartnerBookmark(node)) + if (partner_bookmarks_shim_->IsPartnerBookmark(node)) { return partner_bookmarks_shim_->IsEditable(node); + } if (local_or_syncable_reading_list_manager_->IsReadingListBookmark(node)) { return local_or_syncable_reading_list_manager_->GetRoot() != node; } + if (account_reading_list_manager_ && + account_reading_list_manager_->IsReadingListBookmark(node)) { + return account_reading_list_manager_->GetRoot() != node; + } return !managed_bookmark_service_->IsNodeManaged(node); } @@ -1080,6 +1180,10 @@ if (node == local_or_syncable_reading_list_manager_->GetRoot()) { return bookmark_model_->root_node(); } + if (account_reading_list_manager_ && + node == account_reading_list_manager_->GetRoot()) { + return bookmark_model_->root_node(); + } return node->parent(); } @@ -1095,6 +1199,11 @@ local_or_syncable_reading_list_manager_->IsReadingListBookmark(node)) { return BookmarkType::BOOKMARK_TYPE_READING_LIST; } + if (account_reading_list_manager_ && + account_reading_list_manager_->IsLoaded() && + account_reading_list_manager_->IsReadingListBookmark(node)) { + return BookmarkType::BOOKMARK_TYPE_READING_LIST; + } return BookmarkType::BOOKMARK_TYPE_NORMAL; } @@ -1107,7 +1216,9 @@ bool BookmarkBridge::IsLoaded() const { return (bookmark_model_->loaded() && partner_bookmarks_shim_->IsLoaded() && - local_or_syncable_reading_list_manager_->IsLoaded()); + local_or_syncable_reading_list_manager_->IsLoaded() && + (!account_reading_list_manager_ || + account_reading_list_manager_->IsLoaded())); } bool BookmarkBridge::IsFolderAvailable(const BookmarkNode* folder) const { @@ -1326,10 +1437,13 @@ } ReadingListManager* BookmarkBridge::GetReadingListManagerFromParentNode( - const BookmarkNode* node) { - if (node == local_or_syncable_reading_list_manager_->GetRoot()) { + const bookmarks::BookmarkNode* node) { + if (account_reading_list_manager_ && + node == account_reading_list_manager_->GetRoot()) { + return account_reading_list_manager_.get(); + } else if (node == local_or_syncable_reading_list_manager_->GetRoot()) { return local_or_syncable_reading_list_manager_.get(); - } else { - NOTREACHED_NORETURN(); } + + NOTREACHED_NORETURN(); }
diff --git a/chrome/browser/bookmarks/android/bookmark_bridge.h b/chrome/browser/bookmarks/android/bookmark_bridge.h index 8961f90..eab791f7 100644 --- a/chrome/browser/bookmarks/android/bookmark_bridge.h +++ b/chrome/browser/bookmarks/android/bookmark_bridge.h
@@ -15,6 +15,7 @@ #include "base/gtest_prod_util.h" #include "base/memory/raw_ptr.h" #include "base/memory/weak_ptr.h" +#include "base/scoped_multi_source_observation.h" #include "base/scoped_observation.h" #include "base/strings/utf_string_conversions.h" #include "base/supports_user_data.h" @@ -38,24 +39,32 @@ // hierarchy. // The life cycle of the bridge is controlled by the BookmarkModel through the // user data pattern. Native side of the bridge owns its Java counterpart. -class BookmarkBridge : public bookmarks::BaseBookmarkModelObserver, +class BookmarkBridge : public ProfileObserver, + public bookmarks::BaseBookmarkModelObserver, public PartnerBookmarksShim::Observer, public ReadingListManager::Observer, - public ProfileObserver, public base::SupportsUserData::Data { public: - BookmarkBridge(Profile* profile, - bookmarks::BookmarkModel* model, - bookmarks::ManagedBookmarkService* managed_bookmark_service, - PartnerBookmarksShim* partner_bookmarks_shim, - std::unique_ptr<ReadingListManager> reading_list_manager, - page_image_service::ImageService* image_service); + BookmarkBridge( + Profile* profile, + bookmarks::BookmarkModel* model, + bookmarks::ManagedBookmarkService* managed_bookmark_service, + PartnerBookmarksShim* partner_bookmarks_shim, + std::unique_ptr<ReadingListManager> local_or_synable_reading_list_manager, + std::unique_ptr<ReadingListManager> account_reading_list_manager, + page_image_service::ImageService* image_service); BookmarkBridge(const BookmarkBridge&) = delete; BookmarkBridge& operator=(const BookmarkBridge&) = delete; ~BookmarkBridge() override; + // Destroy the native object from Java. void Destroy(JNIEnv*); + // Gets a reference to Java portion of the bridge. + base::android::ScopedJavaGlobalRef<jobject> GetJavaBookmarkModel(); + int GetBookmarkType(const bookmarks::BookmarkNode* node); + const bookmarks::BookmarkNode* GetParentNode( + const bookmarks::BookmarkNode* node); void GetImageUrlForBookmark( JNIEnv* env, @@ -66,6 +75,8 @@ GetMostRecentlyAddedUserBookmarkIdForUrl( JNIEnv* env, const base::android::JavaParamRef<jobject>& j_url); + const bookmarks::BookmarkNode* GetMostRecentlyAddedUserBookmarkIdForUrlImpl( + const GURL& url); bool IsDoingExtensiveChanges(JNIEnv* env); @@ -97,6 +108,8 @@ base::android::ScopedJavaLocalRef<jobject> GetPartnerFolderId(JNIEnv* env); base::android::ScopedJavaLocalRef<jobject> GetLocalOrSyncableReadingListFolder(JNIEnv* env); + base::android::ScopedJavaLocalRef<jobject> GetAccountReadingListFolder( + JNIEnv* env); base::android::ScopedJavaLocalRef<jobject> GetDefaultReadingListFolder( JNIEnv* env); @@ -109,6 +122,8 @@ jlong id, jint type, const base::android::JavaParamRef<jobject>& j_result_obj); + std::vector<const bookmarks::BookmarkNode*> GetChildIdsImpl( + const bookmarks::BookmarkNode* parent); jint GetChildCount(JNIEnv* env, jlong id, @@ -218,6 +233,10 @@ jint GetUnreadCount(JNIEnv* env, const base::android::JavaParamRef<jobject>& j_id); + jboolean IsAccountBookmark(JNIEnv* env, + const base::android::JavaParamRef<jobject>& j_id); + bool IsAccountBookmarkImpl(const bookmarks::BookmarkNode* node); + void Undo(JNIEnv* env); void StartGroupingUndos(JNIEnv* env); @@ -232,14 +251,7 @@ // ProfileObserver override void OnProfileWillBeDestroyed(Profile* profile) override; - // Gets a reference to Java portion of the bridge. - base::android::ScopedJavaGlobalRef<jobject> GetJavaBookmarkModel(); - private: - FRIEND_TEST_ALL_PREFIXES(BookmarkBridgeTest, GetChildIdsMobileShowsPartner); - - std::vector<const bookmarks::BookmarkNode*> GetChildIdsImpl( - const bookmarks::BookmarkNode* parent); base::android::ScopedJavaLocalRef<jobject> CreateJavaBookmark( const bookmarks::BookmarkNode* node); void ExtractBookmarkNodeInformation( @@ -254,9 +266,6 @@ bool IsEditable(const bookmarks::BookmarkNode* node) const; // Returns whether |node| is a managed bookmark. bool IsManaged(const bookmarks::BookmarkNode* node) const; - const bookmarks::BookmarkNode* GetParentNode( - const bookmarks::BookmarkNode* node); - int GetBookmarkType(const bookmarks::BookmarkNode* node); bool IsReachable(const bookmarks::BookmarkNode* node) const; bool IsLoaded() const; bool IsFolderAvailable(const bookmarks::BookmarkNode* folder) const; @@ -318,7 +327,7 @@ void DestroyJavaObject(); - raw_ptr<Profile> profile_; + raw_ptr<Profile> profile_; // weak base::android::ScopedJavaGlobalRef<jobject> java_bookmark_model_; raw_ptr<bookmarks::BookmarkModel> bookmark_model_; // weak raw_ptr<bookmarks::ManagedBookmarkService> managed_bookmark_service_; // weak @@ -333,11 +342,22 @@ // Holds reading list data as an in-memory BookmarkNode tree. const std::unique_ptr<ReadingListManager> local_or_syncable_reading_list_manager_; + // Holds account reading list data, similar to above. Only non-null if the + // account reading list is available. + const std::unique_ptr<ReadingListManager> account_reading_list_manager_; raw_ptr<page_image_service::ImageService> image_service_; // weak // Observes the profile destruction and creation. base::ScopedObservation<Profile, ProfileObserver> profile_observation_{this}; + base::ScopedObservation<bookmarks::BookmarkModel, + bookmarks::BaseBookmarkModelObserver> + bookmark_model_observation_{this}; + base::ScopedObservation<PartnerBookmarksShim, PartnerBookmarksShim::Observer> + partner_bookmarks_shim_observation_{this}; + base::ScopedMultiSourceObservation<ReadingListManager, + ReadingListManager::Observer> + reading_list_manager_observations_{this}; // Weak pointers for creating callbacks that won't call into a destroyed // object.
diff --git a/chrome/browser/bookmarks/android/bookmark_bridge_unittest.cc b/chrome/browser/bookmarks/android/bookmark_bridge_unittest.cc index 56c3c36..138eacf3 100644 --- a/chrome/browser/bookmarks/android/bookmark_bridge_unittest.cc +++ b/chrome/browser/bookmarks/android/bookmark_bridge_unittest.cc
@@ -27,8 +27,10 @@ #include "components/page_image_service/image_service.h" #include "components/reading_list/core/fake_reading_list_model_storage.h" #include "components/reading_list/core/reading_list_model_impl.h" +#include "components/sync/base/features.h" #include "components/sync/base/storage_type.h" -#include "components/sync/service/sync_service.h" +#include "components/sync/base/user_selectable_type.h" +#include "components/sync/test/test_sync_user_settings.h" #include "content/public/test/browser_task_environment.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" @@ -55,6 +57,10 @@ return local_or_syncable_reading_list_manager_.get(); } + ReadingListManager* account_reading_list_manager() { + return account_reading_list_manager_.get(); + } + const BookmarkNode* AddURL(const BookmarkNode* parent, size_t index, const std::u16string& title, @@ -63,51 +69,65 @@ /*meta_info=*/nullptr, clock_.Now()); } + void CreateBookmarkBridge(bool account_reading_list_enabled) { + bookmark_bridge_.reset(); + ReadingListManagerImpl::IdGenerationFunction rl_id_gen_func = + base::BindRepeating([](int64_t* id) { return (*id)++; }, + base::Owned(std::make_unique<int64_t>(0))); + + local_or_syncable_reading_list_model_ = + CreateReadingListModel(syncer::StorageType::kUnspecified); + auto local_or_syncable_reading_list_manager = + std::make_unique<ReadingListManagerImpl>( + local_or_syncable_reading_list_model_.get(), rl_id_gen_func); + local_or_syncable_reading_list_manager_ = + local_or_syncable_reading_list_manager.get(); + account_reading_list_model_ = + CreateReadingListModel(syncer::StorageType::kAccount); + std::unique_ptr<ReadingListManagerImpl> account_reading_list_manager = + nullptr; + if (account_reading_list_enabled) { + account_reading_list_manager = std::make_unique<ReadingListManagerImpl>( + account_reading_list_model_.get(), rl_id_gen_func); + account_reading_list_manager_ = account_reading_list_manager.get(); + } + + // TODO(crbug.com/1503231): Add image_service once a mock is available. + bookmark_bridge_ = std::make_unique<BookmarkBridge>( + profile_, bookmark_model_, managed_bookmark_service_, + partner_bookmarks_shim_, + std::move(local_or_syncable_reading_list_manager), + std::move(account_reading_list_manager), /*image_service=*/nullptr); + + bookmark_bridge_->LoadEmptyPartnerBookmarkShimForTesting( + AttachCurrentThread()); + partner_bookmarks_shim_->SetPartnerBookmarksRoot( + PartnerBookmarksReader::CreatePartnerBookmarksRootForTesting()); + } + protected: // testing::Test void SetUp() override { + // Setup the profile, and service factories. profile_manager_ = std::make_unique<TestingProfileManager>( TestingBrowserProcess::GetGlobal()); ASSERT_TRUE(profile_manager_->SetUp()); - Profile* profile = profile_manager_->CreateTestingProfile( + profile_ = profile_manager_->CreateTestingProfile( "BookmarkBridgeTest", /*testing_factories=*/{ {BookmarkModelFactory::GetInstance(), BookmarkModelFactory::GetDefaultFactory()}, {ManagedBookmarkServiceFactory::GetInstance(), ManagedBookmarkServiceFactory::GetDefaultFactory()}}); - bookmark_model_ = BookmarkModelFactory::GetForBrowserContext(profile); + // Setup bookmark sources from their factories. + bookmark_model_ = BookmarkModelFactory::GetForBrowserContext(profile_); bookmarks::test::WaitForBookmarkModelToLoad(bookmark_model_); managed_bookmark_service_ = - ManagedBookmarkServiceFactory::GetForProfile(profile); + ManagedBookmarkServiceFactory::GetForProfile(profile_); partner_bookmarks_shim_ = - PartnerBookmarksShim::BuildForBrowserContext(profile); - auto storage = std::make_unique<FakeReadingListModelStorage>(); - base::WeakPtr<FakeReadingListModelStorage> storage_ptr = - storage->AsWeakPtr(); - reading_list_model_ = std::make_unique<ReadingListModelImpl>( - std::move(storage), syncer::StorageType::kUnspecified, - syncer::WipeModelUponSyncDisabledBehavior::kNever, &clock_); - EXPECT_TRUE(storage_ptr->TriggerLoadCompletion()); - // TODO(crbug.com/1501998): Add account reading list manager support. - auto local_or_syncable_reading_list_manager = - std::make_unique<ReadingListManagerImpl>( - reading_list_model_.get(), - base::BindRepeating([](int64_t* id) { return (*id)++; }, - base::Owned(std::make_unique<int64_t>(0)))); - local_or_syncable_reading_list_manager_ = - local_or_syncable_reading_list_manager.get(); + PartnerBookmarksShim::BuildForBrowserContext(profile_); - // TODO(crbug.com/1503231): Add image_service once a mock is available. - bookmark_bridge_ = std::make_unique<BookmarkBridge>( - profile, bookmark_model_, managed_bookmark_service_, - partner_bookmarks_shim_, - std::move(local_or_syncable_reading_list_manager), nullptr); - - bookmark_bridge_->LoadEmptyPartnerBookmarkShimForTesting( - AttachCurrentThread()); - partner_bookmarks_shim_->SetPartnerBookmarksRoot( - PartnerBookmarksReader::CreatePartnerBookmarksRootForTesting()); + CreateBookmarkBridge(/*account_reading_list_enabled=*/false); } void TearDown() override { @@ -116,21 +136,49 @@ profile_manager_.reset(); } + std::unique_ptr<ReadingListModel> CreateReadingListModel( + syncer::StorageType storage_type) { + auto storage = std::make_unique<FakeReadingListModelStorage>(); + base::WeakPtr<FakeReadingListModelStorage> storage_ptr = + storage->AsWeakPtr(); + auto reading_list_model = std::make_unique<ReadingListModelImpl>( + std::move(storage), storage_type, + syncer::WipeModelUponSyncDisabledBehavior::kNever, &clock_); + EXPECT_TRUE(storage_ptr->TriggerLoadCompletion()); + return std::move(reading_list_model); + } + base::SimpleTestClock clock_; std::unique_ptr<TestingProfileManager> profile_manager_; + raw_ptr<Profile> profile_; raw_ptr<BookmarkModel> bookmark_model_; raw_ptr<ManagedBookmarkService> managed_bookmark_service_; raw_ptr<PartnerBookmarksShim> partner_bookmarks_shim_; - std::unique_ptr<ReadingListModel> reading_list_model_; + + std::unique_ptr<ReadingListModel> account_reading_list_model_; + raw_ptr<ReadingListManager> account_reading_list_manager_; + + std::unique_ptr<ReadingListModel> local_or_syncable_reading_list_model_; raw_ptr<ReadingListManager> local_or_syncable_reading_list_manager_; + std::unique_ptr<BookmarkBridge> bookmark_bridge_; content::BrowserTaskEnvironment task_environment_; }; TEST_F(BookmarkBridgeTest, TestGetMostRecentlyAddedUserBookmarkIdForUrl) { + JNIEnv* const env = AttachCurrentThread(); GURL url = GURL("http://foo.com"); + auto java_url = url::GURLAndroid::FromNativeGURL(env, url); + + // The first call will have no result. + ASSERT_EQ(nullptr, bookmark_bridge() + ->GetMostRecentlyAddedUserBookmarkIdForUrl( + env, JavaParamRef<jobject>(env, java_url.obj())) + .obj()); + + // Verify that the last bookmark that was added is the result. AddURL(bookmark_model()->other_node(), 0, u"first", url); clock_.Advance(base::Seconds(1)); AddURL(bookmark_model()->other_node(), 0, u"second", url); @@ -139,9 +187,6 @@ AddURL(bookmark_model()->other_node(), 0, u"third", url); clock_.Advance(base::Seconds(1)); - // Verify that the last bookmark that was added is the result. - JNIEnv* const env = AttachCurrentThread(); - auto java_url = url::GURLAndroid::FromNativeGURL(env, url); auto java_id = bookmark_bridge()->GetMostRecentlyAddedUserBookmarkIdForUrl( env, JavaParamRef<jobject>(env, java_url.obj())); ASSERT_EQ(JavaBookmarkIdGetId(env, java_id), recently_added->id()); @@ -158,19 +203,50 @@ bookmark_bridge()->GetTopLevelFolderIdsImpl(); // The 2 folders should be: mobile bookmarks, reading list. - ASSERT_EQ(2u, folders.size()); - ASSERT_EQ(u"Mobile bookmarks", folders[0]->GetTitle()); - ASSERT_EQ(u"Reading list", folders[1]->GetTitle()); + EXPECT_EQ(2u, folders.size()); + EXPECT_EQ(u"Mobile bookmarks", folders[0]->GetTitle()); + EXPECT_EQ(u"Reading list", folders[1]->GetTitle()); // Adding a bookmark to the bookmark bar will include it in the top level // folders that are returned. AddURL(bookmark_model()->bookmark_bar_node(), 0, u"first", GURL("http://foo.com")); folders = bookmark_bridge()->GetTopLevelFolderIdsImpl(); - ASSERT_EQ(3u, folders.size()); - ASSERT_EQ(u"Mobile bookmarks", folders[0]->GetTitle()); - ASSERT_EQ(u"Bookmarks bar", folders[1]->GetTitle()); - ASSERT_EQ(u"Reading list", folders[2]->GetTitle()); + EXPECT_EQ(3u, folders.size()); + EXPECT_EQ(u"Mobile bookmarks", folders[0]->GetTitle()); + EXPECT_EQ(u"Bookmarks bar", folders[1]->GetTitle()); + EXPECT_EQ(u"Reading list", folders[2]->GetTitle()); +} + +// TODO(crbug.com/1509189): Also enable bookmark account folders here. +TEST_F(BookmarkBridgeTest, TestGetTopLevelFolderIdsAccountActive) { + CreateBookmarkBridge(/*account_reading_list_enabled=*/true); + std::vector<const BookmarkNode*> folders = + bookmark_bridge()->GetTopLevelFolderIdsImpl(); + + // The 2 folders should be: mobile bookmarks, reading list. + EXPECT_EQ(3u, folders.size()); + EXPECT_EQ(u"Reading list", folders[0]->GetTitle()); + EXPECT_TRUE(bookmark_bridge()->IsAccountBookmarkImpl(folders[0])); + EXPECT_EQ(u"Mobile bookmarks", folders[1]->GetTitle()); + EXPECT_FALSE(bookmark_bridge()->IsAccountBookmarkImpl(folders[1])); + EXPECT_EQ(u"Reading list", folders[2]->GetTitle()); + EXPECT_FALSE(bookmark_bridge()->IsAccountBookmarkImpl(folders[2])); + + // Adding a bookmark to the bookmark bar will include it in the top level + // folders that are returned. + AddURL(bookmark_model()->bookmark_bar_node(), 0, u"first", + GURL("http://foo.com")); + folders = bookmark_bridge()->GetTopLevelFolderIdsImpl(); + EXPECT_EQ(4u, folders.size()); + EXPECT_EQ(u"Reading list", folders[0]->GetTitle()); + EXPECT_TRUE(bookmark_bridge()->IsAccountBookmarkImpl(folders[0])); + EXPECT_EQ(u"Mobile bookmarks", folders[1]->GetTitle()); + EXPECT_FALSE(bookmark_bridge()->IsAccountBookmarkImpl(folders[1])); + EXPECT_EQ(u"Bookmarks bar", folders[2]->GetTitle()); + EXPECT_FALSE(bookmark_bridge()->IsAccountBookmarkImpl(folders[2])); + EXPECT_EQ(u"Reading list", folders[3]->GetTitle()); + EXPECT_FALSE(bookmark_bridge()->IsAccountBookmarkImpl(folders[3])); } TEST_F(BookmarkBridgeTest, GetChildIdsMobileShowsPartner) { @@ -207,3 +283,32 @@ ->GetLocalOrSyncableReadingListFolder(env) .obj()))); } + +// Test that the correct type, parent node, etc are returned for account +// reading list nodes. +TEST_F(BookmarkBridgeTest, TestAccountReadingListNodes) { + CreateBookmarkBridge(/*account_reading_list_enabled=*/true); + + GURL url = GURL("http://foo.com"); + + local_or_syncable_reading_list_manager()->Add(url, "foo"); + const BookmarkNode* local_rl_node = + bookmark_bridge()->GetMostRecentlyAddedUserBookmarkIdForUrlImpl(url); + EXPECT_EQ(bookmarks::BOOKMARK_TYPE_READING_LIST, + bookmark_bridge()->GetBookmarkType(local_rl_node)); + EXPECT_EQ(local_or_syncable_reading_list_manager()->GetRoot(), + local_rl_node->parent()); + EXPECT_EQ(local_rl_node->parent(), + bookmark_bridge()->GetParentNode(local_rl_node)); + clock_.Advance(base::Seconds(1)); + + account_reading_list_manager()->Add(url, "foo"); + const BookmarkNode* account_rl_node = + bookmark_bridge()->GetMostRecentlyAddedUserBookmarkIdForUrlImpl(url); + EXPECT_EQ(bookmarks::BOOKMARK_TYPE_READING_LIST, + bookmark_bridge()->GetBookmarkType(account_rl_node)); + EXPECT_EQ(account_reading_list_manager()->GetRoot(), + account_rl_node->parent()); + EXPECT_EQ(account_rl_node->parent(), + bookmark_bridge()->GetParentNode(account_rl_node)); +}
diff --git a/chrome/browser/chrome_browser_main_extra_parts_nacl_deprecation.cc b/chrome/browser/chrome_browser_main_extra_parts_nacl_deprecation.cc index 336362a..fb83932 100644 --- a/chrome/browser/chrome_browser_main_extra_parts_nacl_deprecation.cc +++ b/chrome/browser/chrome_browser_main_extra_parts_nacl_deprecation.cc
@@ -19,10 +19,12 @@ #if BUILDFLAG(ENABLE_NACL) bool ShouldNaClBeAllowed() { // Enabled by policy. +#if BUILDFLAG(IS_CHROMEOS) if (g_browser_process->local_state()->GetBoolean( prefs::kNativeClientForceAllowed)) { return true; } +#endif // BUILDFLAG(IS_CHROMEOS) return base::FeatureList::IsEnabled(kNaclAllow); } #endif
diff --git a/chrome/browser/chrome_browser_main_extra_parts_nacl_deprecation_browsertest.cc b/chrome/browser/chrome_browser_main_extra_parts_nacl_deprecation_browsertest.cc index 1670967..5d7510eb 100644 --- a/chrome/browser/chrome_browser_main_extra_parts_nacl_deprecation_browsertest.cc +++ b/chrome/browser/chrome_browser_main_extra_parts_nacl_deprecation_browsertest.cc
@@ -27,6 +27,7 @@ EXPECT_FALSE(IsNaclAllowed()); } +#if BUILDFLAG(IS_CHROMEOS) class ChromeBrowserMainExtraPartsNaclDeprecationWithPolicyTest : public policy::PolicyTest { public: @@ -45,4 +46,6 @@ PolicyOverridesFieldTrial) { EXPECT_TRUE(IsNaclAllowed()); } +#endif // BUILDFLAG(IS_CHROMEOS) + } // namespace
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index d3d67d83..c484f16c 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -2418,11 +2418,6 @@ return true; } #endif -#if BUILDFLAG(IS_CHROMEOS_ASH) - if (lock_url == chrome::kChromeUIUntrustedTerminalURL) { - return true; - } -#endif #if BUILDFLAG(ENABLE_EXTENSIONS) if (ChromeContentBrowserClientExtensionsPart::AreExtensionsDisabledForProfile(
diff --git a/chrome/browser/commerce/price_change/android/BUILD.gn b/chrome/browser/commerce/price_change/android/BUILD.gn index e9e9bf0..5110d4c 100644 --- a/chrome/browser/commerce/price_change/android/BUILD.gn +++ b/chrome/browser/commerce/price_change/android/BUILD.gn
@@ -24,6 +24,7 @@ "//components/browser_ui/util/android:java", "//components/embedder_support/android:simple_factory_key_java", "//components/embedder_support/android:util_java", + "//components/image_fetcher:java", "//content/public/android:content_full_java", "//third_party/androidx:androidx_annotation_annotation_java", "//third_party/androidx:androidx_core_core_java", @@ -70,6 +71,7 @@ "//chrome/browser/ui/android/favicon:java", "//chrome/test/android:chrome_java_unit_test_support", "//components/embedder_support/android:util_java", + "//components/image_fetcher:java", "//content/public/android:content_full_java", "//third_party/android_deps:robolectric_all_java", "//third_party/androidx:androidx_core_core_java",
diff --git a/chrome/browser/commerce/price_change/android/DEPS b/chrome/browser/commerce/price_change/android/DEPS new file mode 100644 index 0000000..4db40d0 --- /dev/null +++ b/chrome/browser/commerce/price_change/android/DEPS
@@ -0,0 +1,3 @@ +include_rules = [ + "+components/image_fetcher", +] \ No newline at end of file
diff --git a/chrome/browser/commerce/price_change/android/java/src/org/chromium/chrome/browser/price_change/PriceChangeModuleCoordinator.java b/chrome/browser/commerce/price_change/android/java/src/org/chromium/chrome/browser/price_change/PriceChangeModuleCoordinator.java index c53287c3..e486489 100644 --- a/chrome/browser/commerce/price_change/android/java/src/org/chromium/chrome/browser/price_change/PriceChangeModuleCoordinator.java +++ b/chrome/browser/commerce/price_change/android/java/src/org/chromium/chrome/browser/price_change/PriceChangeModuleCoordinator.java
@@ -9,6 +9,9 @@ import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.ui.favicon.FaviconHelper; +import org.chromium.components.browser_ui.util.GlobalDiscardableReferencePool; +import org.chromium.components.image_fetcher.ImageFetcherConfig; +import org.chromium.components.image_fetcher.ImageFetcherFactory; import org.chromium.ui.modelutil.PropertyModel; import org.chromium.ui.modelutil.PropertyModelChangeProcessor; @@ -30,7 +33,15 @@ PropertyModelChangeProcessor.create(model, view, new PriceChangeModuleViewBinder()); mMediator = new PriceChangeModuleMediator( - view.getContext(), model, profile, tabModelSelector, new FaviconHelper()); + view.getContext(), + model, + profile, + tabModelSelector, + new FaviconHelper(), + ImageFetcherFactory.createImageFetcher( + ImageFetcherConfig.IN_MEMORY_WITH_DISK_CACHE, + profile.getProfileKey(), + GlobalDiscardableReferencePool.getReferencePool())); } /** Show price change module. */
diff --git a/chrome/browser/commerce/price_change/android/java/src/org/chromium/chrome/browser/price_change/PriceChangeModuleMediator.java b/chrome/browser/commerce/price_change/android/java/src/org/chromium/chrome/browser/price_change/PriceChangeModuleMediator.java index 335f573..ae09b56 100644 --- a/chrome/browser/commerce/price_change/android/java/src/org/chromium/chrome/browser/price_change/PriceChangeModuleMediator.java +++ b/chrome/browser/commerce/price_change/android/java/src/org/chromium/chrome/browser/price_change/PriceChangeModuleMediator.java
@@ -12,11 +12,13 @@ import org.chromium.chrome.browser.preferences.ChromeSharedPreferences; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.tab.state.ShoppingPersistedTabData; import org.chromium.chrome.browser.tab.state.ShoppingPersistedTabDataService; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tabmodel.TabModelUtils; import org.chromium.chrome.browser.ui.favicon.FaviconHelper; import org.chromium.components.embedder_support.util.UrlUtilities; +import org.chromium.components.image_fetcher.ImageFetcher; import org.chromium.ui.modelutil.PropertyModel; import java.util.HashSet; @@ -33,19 +35,22 @@ private final PropertyModel mModel; private final int mFaviconSize; private final Profile mProfile; + private final ImageFetcher mImageFetcher; PriceChangeModuleMediator( Context context, PropertyModel model, Profile profile, TabModelSelector tabModelSelector, - FaviconHelper faviconHelper) { + FaviconHelper faviconHelper, + ImageFetcher imageFetcher) { mModel = model; mProfile = profile; mShoppingPersistedTabDataService = ShoppingPersistedTabDataService.getForProfile(profile); mFaviconHelper = faviconHelper; mTabModelSelector = tabModelSelector; mFaviconSize = context.getResources().getDimensionPixelSize(R.dimen.default_favicon_size); + mImageFetcher = imageFetcher; } /** Show the price change module. */ @@ -68,15 +73,16 @@ if (res.size() == 0) { return; } + ShoppingPersistedTabData data = res.get(0).getData(); mModel.set( PriceChangeModuleProperties.MODULE_PRODUCT_NAME_STRING, - res.get(0).getData().getProductTitle()); + data.getProductTitle()); mModel.set( PriceChangeModuleProperties.MODULE_CURRENT_PRICE_STRING, - res.get(0).getData().getPriceDrop().price); + data.getPriceDrop().price); mModel.set( PriceChangeModuleProperties.MODULE_PREVIOUS_PRICE_STRING, - res.get(0).getData().getPriceDrop().previousPrice); + data.getPriceDrop().previousPrice); mModel.set( PriceChangeModuleProperties.MODULE_DOMAIN_STRING, UrlUtilities.getDomainAndRegistry( @@ -90,6 +96,18 @@ mModel.set( PriceChangeModuleProperties.MODULE_FAVICON_BITMAP, image); }); + + ImageFetcher.Params params = + ImageFetcher.Params.create( + data.getProductImageUrl(), + ImageFetcher.PRICE_CHANGE_MODULE_NAME); + mImageFetcher.fetchImage( + params, + image -> { + mModel.set( + PriceChangeModuleProperties.MODULE_PRODUCT_IMAGE_BITMAP, + image); + }); }); } }
diff --git a/chrome/browser/commerce/price_change/android/java/src/org/chromium/chrome/browser/price_change/PriceChangeModuleProperties.java b/chrome/browser/commerce/price_change/android/java/src/org/chromium/chrome/browser/price_change/PriceChangeModuleProperties.java index 8b99415..1b961a90 100644 --- a/chrome/browser/commerce/price_change/android/java/src/org/chromium/chrome/browser/price_change/PriceChangeModuleProperties.java +++ b/chrome/browser/commerce/price_change/android/java/src/org/chromium/chrome/browser/price_change/PriceChangeModuleProperties.java
@@ -21,6 +21,8 @@ new PropertyModel.WritableObjectPropertyKey<>(); PropertyModel.WritableObjectPropertyKey<String> MODULE_CURRENT_PRICE_STRING = new PropertyModel.WritableObjectPropertyKey<>(); + PropertyModel.WritableObjectPropertyKey<Bitmap> MODULE_PRODUCT_IMAGE_BITMAP = + new PropertyModel.WritableObjectPropertyKey<>(); PropertyKey[] ALL_KEYS = new PropertyKey[] { @@ -28,6 +30,7 @@ MODULE_PRODUCT_NAME_STRING, MODULE_DOMAIN_STRING, MODULE_PREVIOUS_PRICE_STRING, - MODULE_CURRENT_PRICE_STRING + MODULE_CURRENT_PRICE_STRING, + MODULE_PRODUCT_IMAGE_BITMAP, }; }
diff --git a/chrome/browser/commerce/price_change/android/java/src/org/chromium/chrome/browser/price_change/PriceChangeModuleViewBinder.java b/chrome/browser/commerce/price_change/android/java/src/org/chromium/chrome/browser/price_change/PriceChangeModuleViewBinder.java index 17e4b727d..c0c5ef7 100644 --- a/chrome/browser/commerce/price_change/android/java/src/org/chromium/chrome/browser/price_change/PriceChangeModuleViewBinder.java +++ b/chrome/browser/commerce/price_change/android/java/src/org/chromium/chrome/browser/price_change/PriceChangeModuleViewBinder.java
@@ -30,6 +30,9 @@ } else if (PriceChangeModuleProperties.MODULE_DOMAIN_STRING == propertyKey) { moduleView.setPriceChangeDomain( model.get(PriceChangeModuleProperties.MODULE_DOMAIN_STRING)); + } else if (PriceChangeModuleProperties.MODULE_PRODUCT_IMAGE_BITMAP == propertyKey) { + moduleView.setProductImage( + model.get(PriceChangeModuleProperties.MODULE_PRODUCT_IMAGE_BITMAP)); } else { assert false : "Unhandled property detected in PriceChangeModuleViewBinder!"; }
diff --git a/chrome/browser/commerce/price_change/android/junit/src/org/chromium/chrome/browser/price_change/PriceChangeModuleBinderTest.java b/chrome/browser/commerce/price_change/android/junit/src/org/chromium/chrome/browser/price_change/PriceChangeModuleBinderTest.java index 2a47c03..49c1a7a 100644 --- a/chrome/browser/commerce/price_change/android/junit/src/org/chromium/chrome/browser/price_change/PriceChangeModuleBinderTest.java +++ b/chrome/browser/commerce/price_change/android/junit/src/org/chromium/chrome/browser/price_change/PriceChangeModuleBinderTest.java
@@ -124,4 +124,15 @@ assertEquals(PRODUCT_URL_DOMAIN, domainView.getText()); } + + @Test + @SmallTest + public void testSetProductImage() { + ImageView productImageView = mView.findViewById(R.id.product_image); + assertNull(productImageView.getDrawable()); + + mModel.set(PriceChangeModuleProperties.MODULE_PRODUCT_IMAGE_BITMAP, mBitmap); + + assertNotNull(productImageView.getDrawable()); + } }
diff --git a/chrome/browser/commerce/price_change/android/junit/src/org/chromium/chrome/browser/price_change/PriceChangeModuleMediatorUnitTest.java b/chrome/browser/commerce/price_change/android/junit/src/org/chromium/chrome/browser/price_change/PriceChangeModuleMediatorUnitTest.java index 192fa47..1c8ca59 100644 --- a/chrome/browser/commerce/price_change/android/junit/src/org/chromium/chrome/browser/price_change/PriceChangeModuleMediatorUnitTest.java +++ b/chrome/browser/commerce/price_change/android/junit/src/org/chromium/chrome/browser/price_change/PriceChangeModuleMediatorUnitTest.java
@@ -56,6 +56,8 @@ import org.chromium.chrome.browser.ui.favicon.FaviconHelper.FaviconImageCallback; import org.chromium.components.embedder_support.util.UrlUtilities; import org.chromium.components.embedder_support.util.UrlUtilitiesJni; +import org.chromium.components.image_fetcher.ImageFetcher; +import org.chromium.components.image_fetcher.ImageFetcher.Params; import org.chromium.ui.modelutil.PropertyModel; import org.chromium.url.GURL; @@ -85,6 +87,8 @@ @Mock private FaviconHelper mFaviconHelper; @Mock private UrlUtilities.Natives mUrlUtilitiesJniMock; @Mock private Bitmap mFaviconBitmap; + @Mock private Bitmap mProductImageBitmap; + @Mock private ImageFetcher mImageFetcher; private PriceChangeModuleMediator mMediator; private SharedPreferencesManager mSharedPreferenceManager; @@ -112,7 +116,12 @@ mModel = new PropertyModel(PriceChangeModuleProperties.ALL_KEYS); mMediator = new PriceChangeModuleMediator( - mContext, mModel, mProfile, mTabModelSelector, mFaviconHelper); + mContext, + mModel, + mProfile, + mTabModelSelector, + mFaviconHelper, + mImageFetcher); mSharedPreferenceManager = ChromeSharedPreferences.getInstance(); Map<String, Boolean> featureOverride = new HashMap<>(); @@ -195,5 +204,15 @@ faviconCallbackCaptor.getValue().onFaviconAvailable(mFaviconBitmap, new GURL("")); assertEquals(mFaviconBitmap, mModel.get(PriceChangeModuleProperties.MODULE_FAVICON_BITMAP)); + + // Mock return value of ImageFetcher. + ArgumentCaptor<Callback<Bitmap>> productImageCallbackCaptor = + ArgumentCaptor.forClass(Callback.class); + verify(mImageFetcher).fetchImage(any(Params.class), productImageCallbackCaptor.capture()); + productImageCallbackCaptor.getValue().onResult(mProductImageBitmap); + + assertEquals( + mProductImageBitmap, + mModel.get(PriceChangeModuleProperties.MODULE_PRODUCT_IMAGE_BITMAP)); } }
diff --git a/chrome/browser/commerce/subscriptions/android/BUILD.gn b/chrome/browser/commerce/subscriptions/android/BUILD.gn index e694f0a..410edd6 100644 --- a/chrome/browser/commerce/subscriptions/android/BUILD.gn +++ b/chrome/browser/commerce/subscriptions/android/BUILD.gn
@@ -17,7 +17,6 @@ "//chrome/browser/android/lifecycle:java", "//chrome/browser/commerce/android:java", "//chrome/browser/commerce/price_tracking/android:java", - "//chrome/browser/endpoint_fetcher:java", "//chrome/browser/flags:java", "//chrome/browser/preferences:java", "//chrome/browser/profiles/android:java",
diff --git a/chrome/browser/commerce/subscriptions/test/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsServiceFactoryUnitTest.java b/chrome/browser/commerce/subscriptions/test/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsServiceFactoryUnitTest.java index 7569104..5ccf9cc 100644 --- a/chrome/browser/commerce/subscriptions/test/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsServiceFactoryUnitTest.java +++ b/chrome/browser/commerce/subscriptions/test/android/java/src/org/chromium/chrome/browser/subscriptions/CommerceSubscriptionsServiceFactoryUnitTest.java
@@ -21,8 +21,6 @@ import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.base.test.util.JniMocker; import org.chromium.chrome.browser.commerce.ShoppingServiceFactory; -import org.chromium.chrome.browser.endpoint_fetcher.EndpointFetcher; -import org.chromium.chrome.browser.endpoint_fetcher.EndpointFetcherJni; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.test.util.browser.Features; import org.chromium.components.commerce.core.ShoppingService; @@ -39,8 +37,6 @@ @Mock private Profile mProfileTwo; - @Mock EndpointFetcher.Natives mEndpointFetcherJniMock; - @Mock ShoppingService mShoppingService; @Before @@ -48,7 +44,6 @@ MockitoAnnotations.initMocks(this); doReturn(false).when(mProfileOne).isOffTheRecord(); doReturn(false).when(mProfileTwo).isOffTheRecord(); - mMocker.mock(EndpointFetcherJni.TEST_HOOKS, mEndpointFetcherJniMock); ShoppingServiceFactory.setShoppingServiceForTesting(mShoppingService); }
diff --git a/chrome/browser/download/download_danger_prompt.cc b/chrome/browser/download/download_danger_prompt.cc index 8dc335d7..9ff01091 100644 --- a/chrome/browser/download/download_danger_prompt.cc +++ b/chrome/browser/download/download_danger_prompt.cc
@@ -4,65 +4,13 @@ #include "chrome/browser/download/download_danger_prompt.h" -#include "base/metrics/histogram_functions.h" -#include "base/strings/stringprintf.h" -#include "chrome/browser/browser_process.h" #include "chrome/browser/download/download_item_warning_data.h" #include "chrome/browser/safe_browsing/download_protection/download_protection_service.h" -#include "chrome/browser/safe_browsing/download_protection/download_protection_util.h" #include "chrome/browser/safe_browsing/safe_browsing_service.h" -#include "components/download/public/common/download_danger_type.h" #include "components/download/public/common/download_item.h" -#include "components/safe_browsing/content/browser/web_ui/safe_browsing_ui.h" -#include "components/safe_browsing/content/common/file_type_policies.h" -#include "components/safe_browsing/core/common/proto/csd.pb.h" -#include "content/public/browser/browser_task_traits.h" -#include "content/public/browser/browser_thread.h" #include "content/public/browser/download_item_utils.h" -using safe_browsing::ClientDownloadResponse; -using safe_browsing::ClientSafeBrowsingReportRequest; - -namespace { -const char kDownloadDangerPromptPrefix[] = "Download.DownloadDangerPrompt"; -} // namespace - -void DownloadDangerPrompt::SendSafeBrowsingDownloadReport( - ClientSafeBrowsingReportRequest::ReportType report_type, - bool did_proceed, - download::DownloadItem* download) { - ClientDownloadResponse::Verdict download_verdict = - safe_browsing::DownloadProtectionService::GetDownloadProtectionVerdict( - download); - if (download_verdict == ClientDownloadResponse::SAFE) { - // Don't send report if the verdict is SAFE. - return; - } - g_browser_process->safe_browsing_service()->SendDownloadReport( - download, report_type, did_proceed, - /*show_download_in_folder=*/absl::nullopt); -} - -void DownloadDangerPrompt::RecordDownloadDangerPrompt( - bool did_proceed, - const download::DownloadItem& download) { - int64_t file_type_uma_value = - safe_browsing::FileTypePolicies::GetInstance()->UmaValueForFile( - download.GetTargetFilePath()); - download::DownloadDangerType danger_type = download.GetDangerType(); - - base::UmaHistogramSparse( - base::StringPrintf("%s.%s.Shown", kDownloadDangerPromptPrefix, - download::GetDownloadDangerTypeString(danger_type)), - file_type_uma_value); - if (did_proceed) { - base::UmaHistogramSparse( - base::StringPrintf("%s.%s.Proceed", kDownloadDangerPromptPrefix, - download::GetDownloadDangerTypeString(danger_type)), - file_type_uma_value); - } -} - +// static void DownloadDangerPrompt::RecordDownloadWarningEvent( Action action, download::DownloadItem* download) {
diff --git a/chrome/browser/download/download_danger_prompt.h b/chrome/browser/download/download_danger_prompt.h index ffacd0f..44821d2 100644 --- a/chrome/browser/download/download_danger_prompt.h +++ b/chrome/browser/download/download_danger_prompt.h
@@ -23,6 +23,10 @@ // to accept a dangerous download from script without user intervention. This // step is necessary to prevent a malicious script form abusing such a // privilege. +// After ImprovedDownloadPageWarnings: +// This is only used for extensions API downloads. The chrome://downloads page +// prompt is implemented in WebUI. +// TODO(chlily): Clean up this comment. class DownloadDangerPrompt { public: // Actions resulting from showing the danger prompt. @@ -53,23 +57,7 @@ // respective button click handler. virtual void InvokeActionForTesting(Action action) = 0; - // Sends download recovery report to safe browsing backend. - // Since it only records download url (DownloadItem::GetURL()), user's - // action (click through or not) and its download danger type, it isn't gated - // by user's extended reporting preference (i.e. - // prefs::kSafeBrowsingExtendedReportingEnabled). We should not put any extra - // information in this report. - static void SendSafeBrowsingDownloadReport( - safe_browsing::ClientSafeBrowsingReportRequest::ReportType report_type, - bool did_proceed, - download::DownloadItem* download); - protected: - // Records UMA stats for a download danger prompt event. - static void RecordDownloadDangerPrompt( - bool did_proceed, - const download::DownloadItem& download); - // Records warning action event consumed by Safe Browsing reports. static void RecordDownloadWarningEvent(Action action, download::DownloadItem* download);
diff --git a/chrome/browser/download/download_item_warning_data.h b/chrome/browser/download/download_item_warning_data.h index 6c8facff9f..a94e30cc 100644 --- a/chrome/browser/download/download_item_warning_data.h +++ b/chrome/browser/download/download_item_warning_data.h
@@ -30,7 +30,11 @@ // Applicable actions: PROCEED, DISCARD, DISMISS, CLOSE, BACK, // PROCEED_DEEP_SCAN, OPEN_LEARN_MORE_LINK BUBBLE_SUBPAGE = 2, - // Applicable actions: DISCARD, KEEP + // Applicable actions: DISCARD, KEEP, PROCEED + // Under ImprovedDownloadPageWarnings: + // PROCEED on the downloads page indicates saving a "suspicious" download + // directly, without going through the prompt. In contrast, KEEP indicates + // opening the prompt, for a "dangerous" download. DOWNLOADS_PAGE = 3, // Applicable actions: PROCEED, CANCEL, CLOSE DOWNLOAD_PROMPT = 4,
diff --git a/chrome/browser/download/download_ui_safe_browsing_util.cc b/chrome/browser/download/download_ui_safe_browsing_util.cc index b0c7195..2af903e 100644 --- a/chrome/browser/download/download_ui_safe_browsing_util.cc +++ b/chrome/browser/download/download_ui_safe_browsing_util.cc
@@ -4,13 +4,37 @@ #include "chrome/browser/download/download_ui_safe_browsing_util.h" -#include "components/safe_browsing/buildflags.h" +#include "base/metrics/histogram_functions.h" +#include "base/strings/stringprintf.h" +#include "components/download/public/common/download_item.h" +#include "components/safe_browsing/content/common/file_type_policies.h" #include "components/safe_browsing/core/common/safe_browsing_prefs.h" #if BUILDFLAG(FULL_SAFE_BROWSING) +#include "chrome/browser/browser_process.h" #include "chrome/browser/safe_browsing/download_protection/download_protection_service.h" +#include "chrome/browser/safe_browsing/safe_browsing_service.h" #endif +namespace { + +#if BUILDFLAG(FULL_SAFE_BROWSING) +using safe_browsing::ClientDownloadResponse; +using safe_browsing::ClientSafeBrowsingReportRequest; +#endif + +std::string GetDangerPromptHistogramName(const std::string& suffix, + const download::DownloadItem& item) { + const char kPrefix[] = "Download.DownloadDangerPrompt"; + download::DownloadDangerType danger_type = item.GetDangerType(); + return base::StringPrintf("%s.%s.%s", kPrefix, + download::GetDownloadDangerTypeString(danger_type), + // "Proceed" or "Shown". + suffix.c_str()); +} + +} // namespace + bool WasSafeBrowsingVerdictObtained(const download::DownloadItem* item) { #if BUILDFLAG(FULL_SAFE_BROWSING) return item && @@ -37,3 +61,34 @@ return false; #endif } + +void RecordDownloadDangerPromptHistogram( + const std::string& proceed_or_shown_suffix, + const download::DownloadItem& item) { + int64_t file_type_uma_value = + safe_browsing::FileTypePolicies::GetInstance()->UmaValueForFile( + item.GetTargetFilePath()); + base::UmaHistogramSparse( + GetDangerPromptHistogramName(proceed_or_shown_suffix, item), + file_type_uma_value); +} + +#if BUILDFLAG(FULL_SAFE_BROWSING) +void SendSafeBrowsingDownloadReport( + ClientSafeBrowsingReportRequest::ReportType report_type, + bool did_proceed, + download::DownloadItem* item) { + ClientDownloadResponse::Verdict download_verdict = + safe_browsing::DownloadProtectionService::GetDownloadProtectionVerdict( + item); + if (download_verdict == ClientDownloadResponse::SAFE) { + return; + } + safe_browsing::SafeBrowsingService* sb_service = + g_browser_process->safe_browsing_service(); + if (sb_service) { + sb_service->SendDownloadReport(item, report_type, did_proceed, + /*show_download_in_folder=*/absl::nullopt); + } +} +#endif // BUILDFLAG(FULL_SAFE_BROWSING)
diff --git a/chrome/browser/download/download_ui_safe_browsing_util.h b/chrome/browser/download/download_ui_safe_browsing_util.h index 667138ec..f6ab536e 100644 --- a/chrome/browser/download/download_ui_safe_browsing_util.h +++ b/chrome/browser/download/download_ui_safe_browsing_util.h
@@ -5,6 +5,14 @@ #ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_UI_SAFE_BROWSING_UTIL_H_ #define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_UI_SAFE_BROWSING_UTIL_H_ +#include "components/safe_browsing/buildflags.h" + +#include <string> + +#if BUILDFLAG(FULL_SAFE_BROWSING) +#include "components/safe_browsing/core/common/proto/csd.pb.h" +#endif + class Profile; namespace download { @@ -27,4 +35,26 @@ // controlled by a policy. bool CanUserTurnOnSafeBrowsing(Profile* profile); +// Utilities for recording actions taken on Safe Browsing-flagged downloads. + +// Records UMA metrics for taking an action on the chrome://downloads warning +// bypass prompt. Logs to Download.DownloadDangerPrompt with the suffix, which +// can be "Proceed" or "Shown". +void RecordDownloadDangerPromptHistogram( + const std::string& proceed_or_shown_suffix, + const download::DownloadItem& item); + +#if BUILDFLAG(FULL_SAFE_BROWSING) +// Sends download recovery report to safe browsing backend. +// Since it only records download url (DownloadItem::GetURL()), user's +// action (click through or not) and its download danger type, it isn't gated +// by user's extended reporting preference (i.e. +// prefs::kSafeBrowsingExtendedReportingEnabled). We should not put any extra +// information in this report. +void SendSafeBrowsingDownloadReport( + safe_browsing::ClientSafeBrowsingReportRequest::ReportType report_type, + bool did_proceed, + download::DownloadItem* item); +#endif // BUILDFLAG(FULL_SAFE_BROWSING) + #endif // CHROME_BROWSER_DOWNLOAD_DOWNLOAD_UI_SAFE_BROWSING_UTIL_H_
diff --git a/chrome/browser/endpoint_fetcher/BUILD.gn b/chrome/browser/endpoint_fetcher/BUILD.gn deleted file mode 100644 index 3e972f5..0000000 --- a/chrome/browser/endpoint_fetcher/BUILD.gn +++ /dev/null
@@ -1,30 +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. - -import("//build/config/android/rules.gni") -import("//third_party/jni_zero/jni_zero.gni") - -android_library("java") { - deps = [ - ":jni_headers", - "//base:base_java", - "//build/android:build_java", - "//chrome/browser/profiles/android:java", - "//net/android:net_java", - "//third_party/androidx:androidx_annotation_annotation_java", - "//third_party/jni_zero:jni_zero_java", - ] - srcjar_deps = [ ":jni_headers" ] - sources = [ - "java/src/org/chromium/chrome/browser/endpoint_fetcher/EndpointFetcher.java", - "java/src/org/chromium/chrome/browser/endpoint_fetcher/EndpointResponse.java", - ] -} - -generate_jni("jni_headers") { - sources = [ - "java/src/org/chromium/chrome/browser/endpoint_fetcher/EndpointFetcher.java", - "java/src/org/chromium/chrome/browser/endpoint_fetcher/EndpointResponse.java", - ] -}
diff --git a/chrome/browser/endpoint_fetcher/DEPS b/chrome/browser/endpoint_fetcher/DEPS deleted file mode 100644 index a4c57a2..0000000 --- a/chrome/browser/endpoint_fetcher/DEPS +++ /dev/null
@@ -1,3 +0,0 @@ -include_rules = [ - "+components/endpoint_fetcher", -]
diff --git a/chrome/browser/endpoint_fetcher/OWNERS b/chrome/browser/endpoint_fetcher/OWNERS deleted file mode 100644 index dcc7ea70..0000000 --- a/chrome/browser/endpoint_fetcher/OWNERS +++ /dev/null
@@ -1 +0,0 @@ -file://chrome/browser/complex_tasks/OWNERS
diff --git a/chrome/browser/endpoint_fetcher/endpoint_fetcher_android.cc b/chrome/browser/endpoint_fetcher/endpoint_fetcher_android.cc deleted file mode 100644 index a6c7802..0000000 --- a/chrome/browser/endpoint_fetcher/endpoint_fetcher_android.cc +++ /dev/null
@@ -1,133 +0,0 @@ -// Copyright 2019 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/endpoint_fetcher/endpoint_fetcher.h" - -#include "base/android/callback_android.h" -#include "base/android/jni_array.h" -#include "base/android/jni_string.h" -#include "chrome/browser/endpoint_fetcher/jni_headers/EndpointFetcher_jni.h" -#include "chrome/browser/endpoint_fetcher/jni_headers/EndpointResponse_jni.h" -#include "chrome/browser/profiles/profile_android.h" -#include "chrome/browser/signin/identity_manager_factory.h" -#include "chrome/common/channel_info.h" -#include "components/signin/public/base/consent_level.h" -#include "components/version_info/channel.h" -#include "content/public/browser/storage_partition.h" - -namespace { -static void OnEndpointFetcherComplete( - const base::android::JavaRef<jobject>& jcaller, - // Passing the endpoint_fetcher ensures the endpoint_fetcher's - // lifetime extends to the callback and is not destroyed - // prematurely (which would result in cancellation of the request). - std::unique_ptr<EndpointFetcher> endpoint_fetcher, - std::unique_ptr<EndpointResponse> endpoint_response) { - base::android::RunObjectCallbackAndroid( - jcaller, Java_EndpointResponse_createEndpointResponse( - base::android::AttachCurrentThread(), - base::android::ConvertUTF8ToJavaString( - base::android::AttachCurrentThread(), - std::move(endpoint_response->response)))); -} -} // namespace - -// TODO(crbug.com/1077537) Create a KeyProvider so -// we can have one centralized API. - -static void JNI_EndpointFetcher_NativeFetchOAuth( - JNIEnv* env, - const base::android::JavaParamRef<jobject>& jprofile, - const base::android::JavaParamRef<jstring>& joauth_consumer_name, - const base::android::JavaParamRef<jstring>& jurl, - const base::android::JavaParamRef<jstring>& jhttps_method, - const base::android::JavaParamRef<jstring>& jcontent_type, - const base::android::JavaParamRef<jobjectArray>& jscopes, - const base::android::JavaParamRef<jstring>& jpost_data, - jlong jtimeout, - jint jannotation_hash_code, - const base::android::JavaParamRef<jobject>& jcallback) { - std::vector<std::string> scopes; - base::android::AppendJavaStringArrayToStringVector(env, jscopes, &scopes); - auto endpoint_fetcher = std::make_unique<EndpointFetcher>( - ProfileAndroid::FromProfileAndroid(jprofile) - ->GetDefaultStoragePartition() - ->GetURLLoaderFactoryForBrowserProcess(), - base::android::ConvertJavaStringToUTF8(env, joauth_consumer_name), - GURL(base::android::ConvertJavaStringToUTF8(env, jurl)), - base::android::ConvertJavaStringToUTF8(env, jhttps_method), - base::android::ConvertJavaStringToUTF8(env, jcontent_type), scopes, - jtimeout, base::android::ConvertJavaStringToUTF8(env, jpost_data), - net::NetworkTrafficAnnotationTag::FromJavaAnnotation( - jannotation_hash_code), - IdentityManagerFactory::GetForProfile( - ProfileAndroid::FromProfileAndroid(jprofile)), - // TODO(crbug.com/1466445): ConsentLevel::kSync is deprecated and should - // be removed. See ConsentLevel::kSync documentation for details. - signin::ConsentLevel::kSync); - auto* const endpoint_fetcher_ptr = endpoint_fetcher.get(); - endpoint_fetcher_ptr->Fetch( - base::BindOnce(&OnEndpointFetcherComplete, - base::android::ScopedJavaGlobalRef<jobject>(jcallback), - // unique_ptr endpoint_fetcher is passed until the callback - // to ensure its lifetime across the request. - std::move(endpoint_fetcher))); -} - -static void JNI_EndpointFetcher_NativeFetchChromeAPIKey( - JNIEnv* env, - const base::android::JavaParamRef<jobject>& jprofile, - const base::android::JavaParamRef<jstring>& jurl, - const base::android::JavaParamRef<jstring>& jhttps_method, - const base::android::JavaParamRef<jstring>& jcontent_type, - const base::android::JavaParamRef<jstring>& jpost_data, - jlong jtimeout, - const base::android::JavaParamRef<jobjectArray>& jheaders, - jint jannotation_hash_code, - const base::android::JavaParamRef<jobject>& jcallback) { - std::vector<std::string> headers; - base::android::AppendJavaStringArrayToStringVector(env, jheaders, &headers); - auto endpoint_fetcher = std::make_unique<EndpointFetcher>( - ProfileAndroid::FromProfileAndroid(jprofile) - ->GetDefaultStoragePartition() - ->GetURLLoaderFactoryForBrowserProcess(), - GURL(base::android::ConvertJavaStringToUTF8(env, jurl)), - base::android::ConvertJavaStringToUTF8(env, jhttps_method), - base::android::ConvertJavaStringToUTF8(env, jcontent_type), jtimeout, - base::android::ConvertJavaStringToUTF8(env, jpost_data), headers, - net::NetworkTrafficAnnotationTag::FromJavaAnnotation( - jannotation_hash_code), - chrome::GetChannel() == version_info::Channel::STABLE); - auto* const endpoint_fetcher_ptr = endpoint_fetcher.get(); - endpoint_fetcher_ptr->PerformRequest( - base::BindOnce(&OnEndpointFetcherComplete, - base::android::ScopedJavaGlobalRef<jobject>(jcallback), - // unique_ptr endpoint_fetcher is passed until the callback - // to ensure its lifetime across the request. - std::move(endpoint_fetcher)), - nullptr); -} - -static void JNI_EndpointFetcher_NativeFetchWithNoAuth( - JNIEnv* env, - const base::android::JavaParamRef<jobject>& jprofile, - const base::android::JavaParamRef<jstring>& jurl, - jint jannotation_hash_code, - const base::android::JavaParamRef<jobject>& jcallback) { - auto endpoint_fetcher = std::make_unique<EndpointFetcher>( - ProfileAndroid::FromProfileAndroid(jprofile) - ->GetDefaultStoragePartition() - ->GetURLLoaderFactoryForBrowserProcess(), - GURL(base::android::ConvertJavaStringToUTF8(env, jurl)), - net::NetworkTrafficAnnotationTag::FromJavaAnnotation( - jannotation_hash_code)); - auto* const endpoint_fetcher_ptr = endpoint_fetcher.get(); - endpoint_fetcher_ptr->PerformRequest( - base::BindOnce(&OnEndpointFetcherComplete, - base::android::ScopedJavaGlobalRef<jobject>(jcallback), - // unique_ptr endpoint_fetcher is passed until the callback - // to ensure its lifetime across the request. - std::move(endpoint_fetcher)), - nullptr); -}
diff --git a/chrome/browser/endpoint_fetcher/java/src/org/chromium/chrome/browser/endpoint_fetcher/EndpointFetcher.java b/chrome/browser/endpoint_fetcher/java/src/org/chromium/chrome/browser/endpoint_fetcher/EndpointFetcher.java deleted file mode 100644 index 859ca72..0000000 --- a/chrome/browser/endpoint_fetcher/java/src/org/chromium/chrome/browser/endpoint_fetcher/EndpointFetcher.java +++ /dev/null
@@ -1,138 +0,0 @@ -// Copyright 2019 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.endpoint_fetcher; - -import androidx.annotation.MainThread; - -import org.jni_zero.NativeMethods; - -import org.chromium.base.Callback; -import org.chromium.chrome.browser.profiles.Profile; -import org.chromium.net.NetworkTrafficAnnotationTag; - -/** - * EndpointFetcher uses native EndpointFetcher to call a HTTPS endpoint and return - * the response. The call to native EndpointFetcher is achieved over a static call - * over JNI. The native EndpointFetcher is created during the static call and - * destroyed in the callback function. - * EndpointFetcher currently doesn't support incognito mode. - * If the request times out an empty response will be returned. There will also - * be an error code indicating timeout once more detailed error messaging is added - * TODO(crbug.com/993393). - */ -public final class EndpointFetcher { - private EndpointFetcher() {} - - /** - * Calls an endpoint using OAuth and returns the response via a callback - * @param callback callback function response is returned in - * @param profile profile via which the endpoint is called - * @param oathConsumerName consumer name for OAuth - * @param url endpoint URL called - * @param httpsMethod the HTTPS method used e.g. "GET" or "POST" - * @param contentType the content type e.g. "application/json" - * @param scopes scopes used as part of authentication - * @param postData data for a "POST" request - * @param timeout time after which the request will terminate in the event a response hasn't - * been received - */ - @MainThread - public static void fetchUsingOAuth( - Callback<EndpointResponse> callback, - Profile profile, - String oathConsumerName, - String url, - String httpsMethod, - String contentType, - String[] scopes, - String postData, - long timeout, - NetworkTrafficAnnotationTag annotation) { - // EndpointFetcher currently does not support incognito mode - assert !profile.isOffTheRecord(); - EndpointFetcherJni.get() - .nativeFetchOAuth( - profile, - oathConsumerName, - url, - httpsMethod, - contentType, - scopes, - postData, - timeout, - annotation.getHashCode(), - callback); - } - - /** - * Calls an endpoint using Chrome API Key returns the response via a callback - * @param callback to pass the response back in - * @param profile via which the endpoint is called - * @param url endpoint URL called - * @param httpsMethod the HTTPS method used e.g. "GET" or "POST" - * @param contentType the content type e.g. "application/json" - * @param postData data for a "POST" request - * @param timeout time after which the request will terminate in the event a response hasn't - * been received - * @param headers headers for the request. Key/value pairs are stored sequentially in the array. - */ - @MainThread - public static void fetchUsingChromeAPIKey( - Callback<EndpointResponse> callback, - Profile profile, - String url, - String httpsMethod, - String contentType, - String postData, - long timeout, - String[] headers, - NetworkTrafficAnnotationTag annotation) { - // EndpointFetcher currently does not support incognito mode - // assert !profile.isOffTheRecord(); - EndpointFetcherJni.get() - .nativeFetchChromeAPIKey( - profile, - url, - httpsMethod, - contentType, - postData, - timeout, - headers, - annotation.getHashCode(), - callback); - } - - @NativeMethods - public interface Natives { - void nativeFetchOAuth( - Profile profile, - String oathConsumerName, - String url, - String httpsMethod, - String contentType, - String[] scopes, - String postData, - long timeout, - int annotationHashCode, - Callback<EndpointResponse> callback); - - void nativeFetchChromeAPIKey( - Profile profile, - String url, - String httpsMethod, - String contentType, - String postData, - long timeout, - String[] headers, - int annotationHashCode, - Callback<EndpointResponse> callback); - - void nativeFetchWithNoAuth( - Profile profile, - String url, - int annotationHashCode, - Callback<EndpointResponse> callback); - } -}
diff --git a/chrome/browser/endpoint_fetcher/java/src/org/chromium/chrome/browser/endpoint_fetcher/EndpointResponse.java b/chrome/browser/endpoint_fetcher/java/src/org/chromium/chrome/browser/endpoint_fetcher/EndpointResponse.java deleted file mode 100644 index e1958f1..0000000 --- a/chrome/browser/endpoint_fetcher/java/src/org/chromium/chrome/browser/endpoint_fetcher/EndpointResponse.java +++ /dev/null
@@ -1,30 +0,0 @@ -// Copyright 2019 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.endpoint_fetcher; - -import org.jni_zero.CalledByNative; - -/** Encapsulates the response from the {@Link EndpointFetcher} */ -public class EndpointResponse { - private final String mResponseString; - - /** - * Create the EndpointResponse - * @param responseString the response string acquired from the endpoint - */ - public EndpointResponse(String responseString) { - mResponseString = responseString; - } - - /** Response string acquired from calling an endpoint */ - public String getResponseString() { - return mResponseString; - } - - @CalledByNative - private static EndpointResponse createEndpointResponse(String response) { - return new EndpointResponse(response); - } -}
diff --git a/chrome/browser/extensions/api/autofill_private/autofill_private_api.cc b/chrome/browser/extensions/api/autofill_private/autofill_private_api.cc index ab4ddfa1..97879501 100644 --- a/chrome/browser/extensions/api/autofill_private/autofill_private_api.cc +++ b/chrome/browser/extensions/api/autofill_private/autofill_private_api.cc
@@ -193,7 +193,7 @@ address->fields.begin(), address->fields.end(), [](const auto& field) { return field.type == - autofill_private::ServerFieldType::kAddressHomeCountry; + autofill_private::FieldType::kAddressHomeCountry; }); it != address->fields.end()) { country_code = it->value; @@ -205,7 +205,7 @@ // TODO(crbug.com/1441904): Fields not visible for the autofill profile's // country must be reset. for (const api::autofill_private::AddressField& field : address->fields) { - if (field.type == autofill_private::ServerFieldType::kNameFull) { + if (field.type == autofill_private::FieldType::kNameFull) { profile.SetInfoWithVerificationStatus( autofill::AutofillType(autofill::NAME_FULL), base::UTF8ToUTF16(field.value),
diff --git a/chrome/browser/extensions/api/autofill_private/autofill_util.cc b/chrome/browser/extensions/api/autofill_private/autofill_util.cc index bd2fae9..a718a64 100644 --- a/chrome/browser/extensions/api/autofill_private/autofill_util.cc +++ b/chrome/browser/extensions/api/autofill_private/autofill_util.cc
@@ -72,8 +72,8 @@ autofill::GetDatabaseStoredTypesOfAutofillProfile(), back_inserter(address.fields), [&profile](auto field_type) { autofill_private::AddressField field; - field.type = autofill_private::ParseServerFieldType( - FieldTypeToStringView(field_type)); + field.type = + autofill_private::ParseFieldType(FieldTypeToStringView(field_type)); field.value = GetStringFromProfile(profile, field_type); return field; });
diff --git a/chrome/browser/extensions/api/document_scan/document_scan_api.cc b/chrome/browser/extensions/api/document_scan/document_scan_api.cc index b1cc66ad..8250512 100644 --- a/chrome/browser/extensions/api/document_scan/document_scan_api.cc +++ b/chrome/browser/extensions/api/document_scan/document_scan_api.cc
@@ -141,6 +141,29 @@ api::document_scan::CloseScanner::Results::Create(response))); } +DocumentScanSetOptionsFunction::DocumentScanSetOptionsFunction() = default; +DocumentScanSetOptionsFunction::~DocumentScanSetOptionsFunction() = default; + +ExtensionFunction::ResponseAction DocumentScanSetOptionsFunction::Run() { + auto params = api::document_scan::SetOptions::Params::Create(args()); + EXTENSION_FUNCTION_VALIDATE(params); + + DocumentScanAPIHandler::Get(browser_context()) + ->SetOptions( + extension_, std::move(params->scanner_handle), + std::move(params->options), + base::BindOnce(&DocumentScanSetOptionsFunction::OnResponseReceived, + this)); + + return did_respond() ? AlreadyResponded() : RespondLater(); +} + +void DocumentScanSetOptionsFunction::OnResponseReceived( + api::document_scan::SetOptionsResponse response) { + Respond( + ArgumentList(api::document_scan::SetOptions::Results::Create(response))); +} + DocumentScanStartScanFunction::DocumentScanStartScanFunction() = default; DocumentScanStartScanFunction::~DocumentScanStartScanFunction() = default;
diff --git a/chrome/browser/extensions/api/document_scan/document_scan_api.h b/chrome/browser/extensions/api/document_scan/document_scan_api.h index 968803e..f8b8411b 100644 --- a/chrome/browser/extensions/api/document_scan/document_scan_api.h +++ b/chrome/browser/extensions/api/document_scan/document_scan_api.h
@@ -92,6 +92,25 @@ DOCUMENTSCAN_CLOSESCANNER) }; +class DocumentScanSetOptionsFunction : public ExtensionFunction { + public: + DocumentScanSetOptionsFunction(); + DocumentScanSetOptionsFunction(const DocumentScanSetOptionsFunction&) = + delete; + DocumentScanSetOptionsFunction& operator=( + const DocumentScanSetOptionsFunction&) = delete; + + protected: + ~DocumentScanSetOptionsFunction() override; + + // ExtensionFunction: + ResponseAction Run() override; + + private: + void OnResponseReceived(api::document_scan::SetOptionsResponse response); + DECLARE_EXTENSION_FUNCTION("documentScan.setOptions", DOCUMENTSCAN_SETOPTIONS) +}; + class DocumentScanStartScanFunction : public ExtensionFunction { public: DocumentScanStartScanFunction();
diff --git a/chrome/browser/extensions/api/document_scan/document_scan_api_handler.cc b/chrome/browser/extensions/api/document_scan/document_scan_api_handler.cc index 5db8fbe..0c6c2179b 100644 --- a/chrome/browser/extensions/api/document_scan/document_scan_api_handler.cc +++ b/chrome/browser/extensions/api/document_scan/document_scan_api_handler.cc
@@ -4,6 +4,8 @@ #include "chrome/browser/extensions/api/document_scan/document_scan_api_handler.h" +#include <cmath> +#include <limits> #include <utility> #include "base/base64.h" @@ -11,6 +13,7 @@ #include "base/check_is_test.h" #include "base/containers/contains.h" #include "base/memory/ptr_util.h" +#include "base/numerics/safe_conversions.h" #include "base/unguessable_token.h" #include "build/chromeos_buildflags.h" #include "chrome/browser/extensions/api/document_scan/document_scan_type_converters.h" @@ -346,6 +349,119 @@ response.To<api::document_scan::CloseScannerResponse>()); } +void DocumentScanAPIHandler::SetOptions( + scoped_refptr<const Extension> extension, + const std::string& scanner_handle, + const std::vector<api::document_scan::OptionSetting>& options_in, + SetOptionsCallback callback) { + // Ensure this scanner is allocated to this extension. + ExtensionState& state = extension_state_[extension->id()]; + if (!base::Contains(state.scanner_handles, scanner_handle)) { + auto response = crosapi::mojom::SetOptionsResponse::New(); + response->scanner_handle = scanner_handle; + for (const auto& option : options_in) { + auto result = crosapi::mojom::SetOptionResult::New(); + result->name = option.name; + result->result = crosapi::mojom::ScannerOperationResult::kInvalid; + response->results.emplace_back(std::move(result)); + } + OnSetOptionsResponse(std::move(callback), std::move(response)); + return; + } + + std::vector<crosapi::mojom::OptionSettingPtr> options_out; + options_out.reserve(options_in.size()); + for (const auto& option_in : options_in) { + auto& option_out = options_out.emplace_back( + crosapi::mojom::OptionSetting::From(option_in)); + if (option_out->value.is_null()) { + // `option_out` has no value, so no re-mapping is needed. + continue; + } + + // `option_out` has valid field values, but value might not match type. No + // need to check for most mismatches here because they will be rejected by + // the backend. + // + // However, even if the caller passed syntactically valid numeric values in + // Javascript, the result that arrives here can contain inconsistencies in + // double vs integer. These can happen due to the inherent JS use of double + // for integers as well as quirks of how the auto-generated IDL mapping code + // decides to parse arrays for types that accept multiple list types. + // + // Detect these specific cases and move the value into the expected fixed or + // int field before passing along. All other types are assumed to be + // supplied correctly by the caller if they have made it through the JS + // bindings. + if (option_out->type == crosapi::mojom::OptionType::kFixed) { + // kFixed is the name for SANE non-integral numeric values. It is + // represented in Chrome by double. Handle getting a long or a list of + // longs instead of the expected doubles. This can happen because JS + // doesn't really have integers, so the framework maps nn.0 into nn. If + // this has happened, move the int field over into the expected fixed + // field. + if (option_out->value->is_int_value()) { + option_out->value = crosapi::mojom::OptionValue::NewFixedValue( + option_out->value->get_int_value()); + } else if (option_out->value->is_int_list()) { + option_out->value = crosapi::mojom::OptionValue::NewFixedList( + {option_out->value->get_int_list().begin(), + option_out->value->get_int_list().end()}); + } + } else if (option_out->type == crosapi::mojom::OptionType::kInt) { + // Handle getting a double or a list of doubles instead of the expected + // int(s). If the values have zero fractional parts, assume they were + // really integers that got incorrectly mapped over from JS. If they have + // non-zero fractional parts, the caller really passed a double and the + // value should not be re-mapped. + + auto int_from_double = [](double fixed_value) -> std::optional<int32_t> { + double int_part = 0.0; + if (fixed_value >= std::numeric_limits<int32_t>::min() && + fixed_value <= std::numeric_limits<int32_t>::max() && + std::modf(fixed_value, &int_part) == 0.0) { + return base::checked_cast<int32_t>(fixed_value); + } + return std::nullopt; + }; + + if (option_out->value->is_fixed_value()) { + auto converted = int_from_double(option_out->value->get_fixed_value()); + if (converted) { + option_out->value = + crosapi::mojom::OptionValue::NewIntValue(*converted); + } + } else if (option_out->value->is_fixed_list()) { + std::vector<int32_t> ints; + const auto& fixed_list = option_out->value->get_fixed_list(); + ints.reserve(fixed_list.size()); + for (const double d : fixed_list) { + auto converted = int_from_double(d); + if (!converted) { + break; // As soon as there's one non-int, no need to continue. + } + ints.push_back(*converted); + } + if (ints.size() == fixed_list.size()) { + option_out->value = crosapi::mojom::OptionValue::NewIntList( + {ints.begin(), ints.end()}); + } + } + } + } + document_scan_->SetOptions( + scanner_handle, std::move(options_out), + base::BindOnce(&DocumentScanAPIHandler::OnSetOptionsResponse, + weak_ptr_factory_.GetWeakPtr(), std::move(callback))); +} + +void DocumentScanAPIHandler::OnSetOptionsResponse( + SetOptionsCallback callback, + crosapi::mojom::SetOptionsResponsePtr response) { + std::move(callback).Run( + response.To<api::document_scan::SetOptionsResponse>()); +} + void DocumentScanAPIHandler::StartScan( gfx::NativeWindow native_window, scoped_refptr<const Extension> extension,
diff --git a/chrome/browser/extensions/api/document_scan/document_scan_api_handler.h b/chrome/browser/extensions/api/document_scan/document_scan_api_handler.h index b9f3720..1629d4b 100644 --- a/chrome/browser/extensions/api/document_scan/document_scan_api_handler.h +++ b/chrome/browser/extensions/api/document_scan/document_scan_api_handler.h
@@ -49,6 +49,8 @@ base::OnceCallback<void(api::document_scan::OpenScannerResponse)>; using CloseScannerCallback = base::OnceCallback<void(api::document_scan::CloseScannerResponse)>; + using SetOptionsCallback = + base::OnceCallback<void(api::document_scan::SetOptionsResponse)>; using StartScanCallback = base::OnceCallback<void(api::document_scan::StartScanResponse)>; using CancelScanCallback = @@ -108,6 +110,16 @@ const std::string& scanner_handle, CloseScannerCallback callback); + // Given `scanner_handle` previously returned from `OpenScanner`, sends the + // list of new option values in `options` to the backend. The backend will + // attempt to set each option in order, then will respond with a result for + // each operation and a new final set of device options. The full response + // will be passed to `callback`. + void SetOptions(scoped_refptr<const Extension> extension, + const std::string& scanner_handle, + const std::vector<api::document_scan::OptionSetting>& options, + SetOptionsCallback callback); + // If the user approves, starts a scan using scanner options previously // configured via `SetOptions`. Additionally, `options` are used to specify // scanner-framework options. Explicit approval is obtained through a Chrome @@ -202,6 +214,8 @@ crosapi::mojom::OpenScannerResponsePtr response); void OnCloseScannerResponse(CloseScannerCallback callback, crosapi::mojom::CloseScannerResponsePtr response); + void OnSetOptionsResponse(SetOptionsCallback callback, + crosapi::mojom::SetOptionsResponsePtr response); void OnStartScanResponse( std::unique_ptr<StartScanRunner> runner, StartScanCallback callback,
diff --git a/chrome/browser/extensions/api/document_scan/document_scan_api_handler_unittest.cc b/chrome/browser/extensions/api/document_scan/document_scan_api_handler_unittest.cc index 29c9e18..f387642 100644 --- a/chrome/browser/extensions/api/document_scan/document_scan_api_handler_unittest.cc +++ b/chrome/browser/extensions/api/document_scan/document_scan_api_handler_unittest.cc
@@ -12,6 +12,7 @@ #include "base/auto_reset.h" #include "base/functional/bind.h" #include "base/memory/ref_counted.h" +#include "base/strings/stringprintf.h" #include "base/test/test_future.h" #include "base/values.h" #include "chrome/browser/extensions/api/document_scan/document_scan_api.h" @@ -48,6 +49,8 @@ base::test::TestFuture<api::document_scan::OpenScannerResponse>; using CloseScannerFuture = base::test::TestFuture<api::document_scan::CloseScannerResponse>; +using SetOptionsFuture = + base::test::TestFuture<api::document_scan::SetOptionsResponse>; using StartScanFuture = base::test::TestFuture<api::document_scan::StartScanResponse>; using CancelScanFuture = @@ -574,6 +577,315 @@ api::document_scan::OperationResult::kInvalid); } +TEST_F(DocumentScanAPIHandlerTest, SetOptions_SetBeforeOpenFails) { + SetOptionsFuture future; + document_scan_api_handler_->SetOptions( + extension_, "badscanner", + CreateTestOptionSettingList(2, api::document_scan::OptionType::kInt), + future.GetCallback()); + const api::document_scan::SetOptionsResponse& response = future.Get(); + + EXPECT_EQ(response.scanner_handle, "badscanner"); + ASSERT_EQ(response.results.size(), 2U); + for (const auto& result : response.results) { + EXPECT_EQ(result.result, api::document_scan::OperationResult::kInvalid); + } + EXPECT_FALSE(response.options.has_value()); +} + +// Tests the special mappings for TYPE_FIXED options. Also indirectly tests +// getting back multiple results and an updated set of options. +TEST_F(DocumentScanAPIHandlerTest, SetOptions_FixedTypeMappings) { + std::string scanner_id = CreateScannerIdForExtension(extension_); + ASSERT_FALSE(scanner_id.empty()); + + OpenScannerFuture open_future; + document_scan_api_handler_->OpenScanner(extension_, scanner_id, + open_future.GetCallback()); + const api::document_scan::OpenScannerResponse& open_response = + open_future.Get(); + ASSERT_TRUE(open_response.scanner_handle.has_value()); + const std::string& handle = open_response.scanner_handle.value(); + + // FIXED containing no value: OK. + // FIXED containing one int: Mapped. + // FIXED containing int list: Mapped. + // FIXED containing string: Wrong type. + // FIXED containing one fixed: OK. + // FIXED containing fixed list with decimals: OK. + // FIXED containing fixed list without decimals: OK. + auto settings = + CreateTestOptionSettingList(7, api::document_scan::OptionType::kFixed); + // settings[0] has no value. + settings[1].value.emplace(); + settings[1].value->as_integer = 3; + settings[2].value.emplace(); + settings[2].value->as_integers = {3, 5}; + settings[3].value.emplace(); + settings[3].value->as_string = "oops"; + settings[4].value.emplace(); + settings[4].value->as_number = 2.5; + settings[5].value.emplace(); + settings[5].value->as_numbers = {2.5, -1.25}; + settings[6].value.emplace(); + settings[6].value->as_numbers = {2.0, -1.0}; + + SetOptionsFuture future; + document_scan_api_handler_->SetOptions( + extension_, handle, std::move(settings), future.GetCallback()); + const api::document_scan::SetOptionsResponse& response = future.Get(); + EXPECT_EQ(response.scanner_handle, handle); + ASSERT_EQ(response.results.size(), 7U); + EXPECT_EQ(response.results[0].result, + api::document_scan::OperationResult::kSuccess); + EXPECT_EQ(response.results[1].result, + api::document_scan::OperationResult::kSuccess); + EXPECT_EQ(response.results[2].result, + api::document_scan::OperationResult::kSuccess); + EXPECT_EQ(response.results[3].result, + api::document_scan::OperationResult::kWrongType); + EXPECT_EQ(response.results[4].result, + api::document_scan::OperationResult::kSuccess); + EXPECT_EQ(response.results[5].result, + api::document_scan::OperationResult::kSuccess); + EXPECT_EQ(response.results[6].result, + api::document_scan::OperationResult::kSuccess); + + // Verify that all supplied options are present, but assume the option value + // conversions have already been tested by the TypeConverter unit tests. + ASSERT_TRUE(response.options.has_value()); + for (size_t i = 1; i <= 7; i++) { + EXPECT_TRUE(response.options->additional_properties.contains( + base::StringPrintf("option%zu", i))); + } +} + +// Tests the special mappings for TYPE_INT options. +TEST_F(DocumentScanAPIHandlerTest, SetOptions_IntTypeMappings) { + std::string scanner_id = CreateScannerIdForExtension(extension_); + ASSERT_FALSE(scanner_id.empty()); + + OpenScannerFuture open_future; + document_scan_api_handler_->OpenScanner(extension_, scanner_id, + open_future.GetCallback()); + const api::document_scan::OpenScannerResponse& open_response = + open_future.Get(); + ASSERT_TRUE(open_response.scanner_handle.has_value()); + const std::string& handle = open_response.scanner_handle.value(); + + // INT containing no value: OK. + // INT containing one int: OK. + // INT containing int list: OK. + // INT containing string: Wrong type. + // INT containing one fixed with no fractional part: Mapped. + // INT containing one too-large fixed with no fractional part: Wrong type. + // INT containing one too-small fixed with no fractional part: Wrong type. + // INT containing one fixed with non-zero fractional part: Wrong type. + // INT containing fixed list with no fractional part: Mapped. + // INT containing fixed list with non-zero fractional part: Wrong type. + // INT containing fixed list with mixed fractional part: Wrong type. + // INT containing fixed list with mixed too-small part: Wrong type. + // INT containing fixed list with mixed too-large part: Wrong type. + auto settings = + CreateTestOptionSettingList(13, api::document_scan::OptionType::kInt); + // settings[0] has no value. + settings[1].value.emplace(); + settings[1].value->as_integer = 3; + settings[2].value.emplace(); + settings[2].value->as_integers = {3, 5}; + settings[3].value.emplace(); + settings[3].value->as_string = "oops"; + settings[4].value.emplace(); + settings[4].value->as_number = 2.0; + settings[5].value.emplace(); + settings[5].value->as_number = 1e300; + settings[6].value.emplace(); + settings[6].value->as_number = -1e300; + settings[7].value.emplace(); + settings[7].value->as_number = 2.5; + settings[8].value.emplace(); + settings[8].value->as_numbers = {2.0, -1.0}; + settings[9].value.emplace(); + settings[9].value->as_numbers = {2.5, -1.25}; + settings[10].value.emplace(); + settings[10].value->as_numbers = {4.0, -1.25}; + settings[11].value.emplace(); + settings[11].value->as_numbers = {4.0, -1e300}; + settings[12].value.emplace(); + settings[12].value->as_numbers = {4.0, 1e300}; + + SetOptionsFuture future; + document_scan_api_handler_->SetOptions( + extension_, handle, std::move(settings), future.GetCallback()); + const api::document_scan::SetOptionsResponse& response = future.Get(); + EXPECT_EQ(response.scanner_handle, handle); + ASSERT_EQ(response.results.size(), 13U); + EXPECT_EQ(response.results[0].result, + api::document_scan::OperationResult::kSuccess); + EXPECT_EQ(response.results[1].result, + api::document_scan::OperationResult::kSuccess); + EXPECT_EQ(response.results[2].result, + api::document_scan::OperationResult::kSuccess); + EXPECT_EQ(response.results[3].result, + api::document_scan::OperationResult::kWrongType); + EXPECT_EQ(response.results[4].result, + api::document_scan::OperationResult::kSuccess); + EXPECT_EQ(response.results[5].result, + api::document_scan::OperationResult::kWrongType); + EXPECT_EQ(response.results[6].result, + api::document_scan::OperationResult::kWrongType); + EXPECT_EQ(response.results[7].result, + api::document_scan::OperationResult::kWrongType); + EXPECT_EQ(response.results[8].result, + api::document_scan::OperationResult::kSuccess); + EXPECT_EQ(response.results[9].result, + api::document_scan::OperationResult::kWrongType); + EXPECT_EQ(response.results[10].result, + api::document_scan::OperationResult::kWrongType); + EXPECT_EQ(response.results[11].result, + api::document_scan::OperationResult::kWrongType); + EXPECT_EQ(response.results[12].result, + api::document_scan::OperationResult::kWrongType); + + // Verify that all supplied options are present, but assume the option value + // conversions have already been tested by the TypeConverter unit tests. + ASSERT_TRUE(response.options.has_value()); + for (size_t i = 1; i <= 13; i++) { + EXPECT_TRUE(response.options->additional_properties.contains( + base::StringPrintf("option%zu", i))); + } +} + +TEST_F(DocumentScanAPIHandlerTest, SetOptions_BoolTypeMappings) { + std::string scanner_id = CreateScannerIdForExtension(extension_); + ASSERT_FALSE(scanner_id.empty()); + + OpenScannerFuture open_future; + document_scan_api_handler_->OpenScanner(extension_, scanner_id, + open_future.GetCallback()); + const api::document_scan::OpenScannerResponse& open_response = + open_future.Get(); + ASSERT_TRUE(open_response.scanner_handle.has_value()); + const std::string& handle = open_response.scanner_handle.value(); + + // BOOL containing no value: OK. + // BOOL containing boolean: OK. + // BOOL containing string: Wrong type. + // BOOL containing int: Wrong type. + // BOOL containing fixed: Wrong type. + // BOOL containing int list: Wrong type. + // BOOL containing fixed list: Wrong type. + auto settings = + CreateTestOptionSettingList(7, api::document_scan::OptionType::kBool); + // settings[0] has no value. + settings[1].value.emplace(); + settings[1].value->as_boolean = false; + settings[2].value.emplace(); + settings[2].value->as_string = "oops"; + settings[3].value.emplace(); + settings[3].value->as_integer = 1; + settings[4].value.emplace(); + settings[4].value->as_number = 1.5; + settings[5].value.emplace(); + settings[5].value->as_integers = {1, 2}; + settings[6].value.emplace(); + settings[6].value->as_numbers = {1.5, 2.5}; + + SetOptionsFuture future; + document_scan_api_handler_->SetOptions( + extension_, handle, std::move(settings), future.GetCallback()); + const api::document_scan::SetOptionsResponse& response = future.Get(); + EXPECT_EQ(response.scanner_handle, handle); + ASSERT_EQ(response.results.size(), 7U); + EXPECT_EQ(response.results[0].result, + api::document_scan::OperationResult::kSuccess); + EXPECT_EQ(response.results[1].result, + api::document_scan::OperationResult::kSuccess); + EXPECT_EQ(response.results[2].result, + api::document_scan::OperationResult::kWrongType); + EXPECT_EQ(response.results[3].result, + api::document_scan::OperationResult::kWrongType); + EXPECT_EQ(response.results[4].result, + api::document_scan::OperationResult::kWrongType); + EXPECT_EQ(response.results[5].result, + api::document_scan::OperationResult::kWrongType); + EXPECT_EQ(response.results[6].result, + api::document_scan::OperationResult::kWrongType); + + // Verify that all supplied options are present, but assume the option value + // conversions have already been tested by the TypeConverter unit tests. + ASSERT_TRUE(response.options.has_value()); + for (size_t i = 1; i <= 7; i++) { + EXPECT_TRUE(response.options->additional_properties.contains( + base::StringPrintf("option%zu", i))); + } +} + +TEST_F(DocumentScanAPIHandlerTest, SetOptions_StringTypeMappings) { + std::string scanner_id = CreateScannerIdForExtension(extension_); + ASSERT_FALSE(scanner_id.empty()); + + OpenScannerFuture open_future; + document_scan_api_handler_->OpenScanner(extension_, scanner_id, + open_future.GetCallback()); + const api::document_scan::OpenScannerResponse& open_response = + open_future.Get(); + ASSERT_TRUE(open_response.scanner_handle.has_value()); + const std::string& handle = open_response.scanner_handle.value(); + + // STRING containing no value: OK. + // STRING containing string: OK. + // STRING containing boolean: Wrong type. + // STRING containing int: Wrong type. + // STRING containing fixed: Wrong type. + // STRING containing int list: Wrong type. + // STRING containing fixed list: Wrong type. + auto settings = + CreateTestOptionSettingList(7, api::document_scan::OptionType::kString); + // settings[0] has no value. + settings[1].value.emplace(); + settings[1].value->as_string = "string"; + settings[2].value.emplace(); + settings[2].value->as_boolean = true; + settings[3].value.emplace(); + settings[3].value->as_integer = 1; + settings[4].value.emplace(); + settings[4].value->as_number = 1.5; + settings[5].value.emplace(); + settings[5].value->as_integers = {1, 2}; + settings[6].value.emplace(); + settings[6].value->as_numbers = {1.5, 2.5}; + + SetOptionsFuture future; + document_scan_api_handler_->SetOptions( + extension_, handle, std::move(settings), future.GetCallback()); + const api::document_scan::SetOptionsResponse& response = future.Get(); + EXPECT_EQ(response.scanner_handle, handle); + ASSERT_EQ(response.results.size(), 7U); + EXPECT_EQ(response.results[0].result, + api::document_scan::OperationResult::kSuccess); + EXPECT_EQ(response.results[1].result, + api::document_scan::OperationResult::kSuccess); + EXPECT_EQ(response.results[2].result, + api::document_scan::OperationResult::kWrongType); + EXPECT_EQ(response.results[3].result, + api::document_scan::OperationResult::kWrongType); + EXPECT_EQ(response.results[4].result, + api::document_scan::OperationResult::kWrongType); + EXPECT_EQ(response.results[5].result, + api::document_scan::OperationResult::kWrongType); + EXPECT_EQ(response.results[6].result, + api::document_scan::OperationResult::kWrongType); + + // Verify that all supplied options are present, but assume the option value + // conversions have already been tested by the TypeConverter unit tests. + ASSERT_TRUE(response.options.has_value()); + for (size_t i = 1; i <= 7; i++) { + EXPECT_TRUE(response.options->additional_properties.contains( + base::StringPrintf("option%zu", i))); + } +} + TEST_F(DocumentScanAPIHandlerTest, StartScan_PermissionDenied) { // There is a check for a valid scanner handle even before the permissions // check, so even though this test will simulate a deny permission, there has
diff --git a/chrome/browser/extensions/api/document_scan/document_scan_test_utils.cc b/chrome/browser/extensions/api/document_scan/document_scan_test_utils.cc index c0695e8..e360cdf 100644 --- a/chrome/browser/extensions/api/document_scan/document_scan_test_utils.cc +++ b/chrome/browser/extensions/api/document_scan/document_scan_test_utils.cc
@@ -4,6 +4,8 @@ #include "chrome/browser/extensions/api/document_scan/document_scan_test_utils.h" +#include "base/strings/stringprintf.h" + namespace extensions { crosapi::mojom::ScannerInfoPtr CreateTestScannerInfo() { @@ -27,4 +29,21 @@ return option; } +std::vector<api::document_scan::OptionSetting> CreateTestOptionSettingList( + size_t num, + api::document_scan::OptionType type) { + std::vector<api::document_scan::OptionSetting> settings; + settings.reserve(num); + + // Loop from 1 to create 1-based option names. + for (size_t i = 1; i <= num; i++) { + api::document_scan::OptionSetting setting; + setting.name = base::StringPrintf("option%zu", i); + setting.type = type; + settings.emplace_back(std::move(setting)); + } + + return settings; +} + } // namespace extensions
diff --git a/chrome/browser/extensions/api/document_scan/document_scan_test_utils.h b/chrome/browser/extensions/api/document_scan/document_scan_test_utils.h index 1d8deed..28084cbc 100644 --- a/chrome/browser/extensions/api/document_scan/document_scan_test_utils.h +++ b/chrome/browser/extensions/api/document_scan/document_scan_test_utils.h
@@ -6,7 +6,9 @@ #define CHROME_BROWSER_EXTENSIONS_API_DOCUMENT_SCAN_DOCUMENT_SCAN_TEST_UTILS_H_ #include <string> +#include <vector> +#include "chrome/common/extensions/api/document_scan.h" #include "chromeos/crosapi/mojom/document_scan.mojom.h" namespace extensions { @@ -15,6 +17,9 @@ crosapi::mojom::ScannerOptionPtr CreateTestScannerOption( const std::string& name, int32_t val); +std::vector<api::document_scan::OptionSetting> CreateTestOptionSettingList( + size_t num, + api::document_scan::OptionType type); } // namespace extensions
diff --git a/chrome/browser/extensions/api/document_scan/document_scan_type_converters.cc b/chrome/browser/extensions/api/document_scan/document_scan_type_converters.cc index 00641b8..1b27144 100644 --- a/chrome/browser/extensions/api/document_scan/document_scan_type_converters.cc +++ b/chrome/browser/extensions/api/document_scan/document_scan_type_converters.cc
@@ -92,6 +92,29 @@ } template <> +struct TypeConverter<mojom::OptionType, document_scan::OptionType> { + static mojom::OptionType Convert(document_scan::OptionType input) { + switch (input) { + case document_scan::OptionType::kNone: + case document_scan::OptionType::kUnknown: + return mojom::OptionType::kUnknown; + case document_scan::OptionType::kBool: + return mojom::OptionType::kBool; + case document_scan::OptionType::kInt: + return mojom::OptionType::kInt; + case document_scan::OptionType::kFixed: + return mojom::OptionType::kFixed; + case document_scan::OptionType::kString: + return mojom::OptionType::kString; + case document_scan::OptionType::kButton: + return mojom::OptionType::kButton; + case document_scan::OptionType::kGroup: + return mojom::OptionType::kGroup; + } + } +}; + +template <> struct TypeConverter<document_scan::OptionUnit, mojom::OptionUnit> { static document_scan::OptionUnit Convert(mojom::OptionUnit input) { switch (input) { @@ -276,6 +299,37 @@ } template <> +struct TypeConverter<mojom::OptionValuePtr, + document_scan::OptionSetting::Value> { + static mojom::OptionValuePtr Convert( + const document_scan::OptionSetting::Value& input) { + if (input.as_boolean.has_value()) { + return mojom::OptionValue::NewBoolValue(input.as_boolean.value()); + } + if (input.as_integer.has_value()) { + return mojom::OptionValue::NewIntValue(input.as_integer.value()); + } + if (input.as_integers.has_value()) { + return mojom::OptionValue::NewIntList( + {input.as_integers->begin(), input.as_integers->end()}); + } + if (input.as_number.has_value()) { + return mojom::OptionValue::NewFixedValue(input.as_number.value()); + } + if (input.as_numbers.has_value()) { + return mojom::OptionValue::NewFixedList( + {input.as_numbers->begin(), input.as_numbers->end()}); + } + if (input.as_string.has_value()) { + return mojom::OptionValue::NewStringValue(input.as_string.value()); + } + + NOTREACHED(); + return {}; + } +}; + +template <> struct TypeConverter<document_scan::ScannerOption, mojom::ScannerOptionPtr> { static document_scan::ScannerOption Convert( const mojom::ScannerOptionPtr& input) { @@ -308,6 +362,18 @@ return input.To<document_scan::ScannerOption>(); } +template <> +struct TypeConverter<extensions::api::document_scan::SetOptionResult, + crosapi::mojom::SetOptionResultPtr> { + static extensions::api::document_scan::SetOptionResult Convert( + const crosapi::mojom::SetOptionResultPtr& input) { + document_scan::SetOptionResult output; + output.name = input->name; + output.result = ConvertTo<document_scan::OperationResult>(input->result); + return output; + } +}; + crosapi::mojom::ScannerEnumFilterPtr TypeConverter<crosapi::mojom::ScannerEnumFilterPtr, extensions::api::document_scan::DeviceFilter>:: @@ -369,6 +435,39 @@ return output; } +mojom::OptionSettingPtr +TypeConverter<mojom::OptionSettingPtr, + extensions::api::document_scan::OptionSetting>:: + Convert(const extensions::api::document_scan::OptionSetting& input) { + auto output = mojom::OptionSetting::New(); + output->name = input.name; + output->type = ConvertTo<mojom::OptionType>(input.type); + if (input.value.has_value()) { + output->value = mojom::OptionValue::From(input.value.value()); + } + return output; +} + +extensions::api::document_scan::SetOptionsResponse +TypeConverter<extensions::api::document_scan::SetOptionsResponse, + crosapi::mojom::SetOptionsResponsePtr>:: + Convert(const crosapi::mojom::SetOptionsResponsePtr& input) { + document_scan::SetOptionsResponse output; + output.scanner_handle = input->scanner_handle; + output.results.reserve(input->results.size()); + for (const auto& result : input->results) { + output.results.emplace_back(result.To<document_scan::SetOptionResult>()); + } + if (input->options) { + output.options = document_scan::SetOptionsResponse::Options(); + for (const auto& [name, option] : *input->options) { + output.options->additional_properties.Set( + name, option.To<document_scan::ScannerOption>().ToValue()); + } + } + return output; +} + crosapi::mojom::StartScanOptionsPtr TypeConverter<crosapi::mojom::StartScanOptionsPtr, extensions::api::document_scan::StartScanOptions>::
diff --git a/chrome/browser/extensions/api/document_scan/document_scan_type_converters.h b/chrome/browser/extensions/api/document_scan/document_scan_type_converters.h index adb531fb..e22f9bc 100644 --- a/chrome/browser/extensions/api/document_scan/document_scan_type_converters.h +++ b/chrome/browser/extensions/api/document_scan/document_scan_type_converters.h
@@ -47,6 +47,20 @@ }; template <> +struct TypeConverter<crosapi::mojom::OptionSettingPtr, + extensions::api::document_scan::OptionSetting> { + static crosapi::mojom::OptionSettingPtr Convert( + const extensions::api::document_scan::OptionSetting& input); +}; + +template <> +struct TypeConverter<extensions::api::document_scan::SetOptionsResponse, + crosapi::mojom::SetOptionsResponsePtr> { + static extensions::api::document_scan::SetOptionsResponse Convert( + const crosapi::mojom::SetOptionsResponsePtr& input); +}; + +template <> struct TypeConverter<crosapi::mojom::StartScanOptionsPtr, extensions::api::document_scan::StartScanOptions> { static crosapi::mojom::StartScanOptionsPtr Convert(
diff --git a/chrome/browser/extensions/api/document_scan/document_scan_type_converters_unittest.cc b/chrome/browser/extensions/api/document_scan/document_scan_type_converters_unittest.cc index 89da395..4302a02e 100644 --- a/chrome/browser/extensions/api/document_scan/document_scan_type_converters_unittest.cc +++ b/chrome/browser/extensions/api/document_scan/document_scan_type_converters_unittest.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/extensions/api/document_scan/document_scan_type_converters.h" #include "base/containers/contains.h" +#include "chrome/browser/extensions/api/document_scan/document_scan_test_utils.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -502,6 +503,171 @@ EXPECT_EQ(output.result, document_scan::OperationResult::kSuccess); } +TEST(DocumentScanTypeConvertersTest, OptionSetting_Empty) { + document_scan::OptionSetting input; + auto output = mojom::OptionSetting::From(input); + EXPECT_EQ(output->name, ""); + EXPECT_EQ(output->type, mojom::OptionType::kUnknown); + EXPECT_TRUE(output->value.is_null()); +} + +TEST(DocumentScanTypeConvertersTest, OptionSetting_BoolValue) { + document_scan::OptionSetting input; + input.name = "name"; + input.type = document_scan::OptionType::kBool; + input.value.emplace(); + input.value->as_boolean = true; + + auto output = mojom::OptionSetting::From(input); + EXPECT_EQ(output->name, "name"); + EXPECT_EQ(output->type, mojom::OptionType::kBool); + ASSERT_FALSE(output->value.is_null()); + ASSERT_TRUE(output->value->is_bool_value()); + EXPECT_EQ(output->value->get_bool_value(), true); +} + +TEST(DocumentScanTypeConvertersTest, OptionSetting_IntValue) { + document_scan::OptionSetting input; + input.name = "name"; + input.type = document_scan::OptionType::kInt; + input.value.emplace(); + input.value->as_integer = 42; + + auto output = mojom::OptionSetting::From(input); + EXPECT_EQ(output->name, "name"); + EXPECT_EQ(output->type, mojom::OptionType::kInt); + ASSERT_FALSE(output->value.is_null()); + ASSERT_TRUE(output->value->is_int_value()); + EXPECT_EQ(output->value->get_int_value(), 42); +} + +TEST(DocumentScanTypeConvertersTest, OptionSetting_IntList) { + document_scan::OptionSetting input; + input.name = "name"; + input.type = document_scan::OptionType::kInt; + input.value.emplace(); + input.value->as_integers = {42, 10}; + + auto output = mojom::OptionSetting::From(input); + EXPECT_EQ(output->name, "name"); + EXPECT_EQ(output->type, mojom::OptionType::kInt); + ASSERT_FALSE(output->value.is_null()); + ASSERT_TRUE(output->value->is_int_list()); + EXPECT_THAT(output->value->get_int_list(), ElementsAre(42, 10)); +} + +TEST(DocumentScanTypeConvertersTest, OptionSetting_FixedValue) { + document_scan::OptionSetting input; + input.name = "name"; + input.type = document_scan::OptionType::kFixed; + input.value.emplace(); + input.value->as_number = 42.25; + + auto output = mojom::OptionSetting::From(input); + EXPECT_EQ(output->name, "name"); + EXPECT_EQ(output->type, mojom::OptionType::kFixed); + ASSERT_FALSE(output->value.is_null()); + ASSERT_TRUE(output->value->is_fixed_value()); + EXPECT_EQ(output->value->get_fixed_value(), 42.25); +} + +TEST(DocumentScanTypeConvertersTest, OptionSetting_FixedList) { + document_scan::OptionSetting input; + input.name = "name"; + input.type = document_scan::OptionType::kFixed; + input.value.emplace(); + input.value->as_numbers = {42.5, 10.75}; + + auto output = mojom::OptionSetting::From(input); + EXPECT_EQ(output->name, "name"); + EXPECT_EQ(output->type, mojom::OptionType::kFixed); + ASSERT_FALSE(output->value.is_null()); + ASSERT_TRUE(output->value->is_fixed_list()); + EXPECT_THAT(output->value->get_fixed_list(), ElementsAre(42.5, 10.75)); +} + +TEST(DocumentScanTypeConvertersTest, OptionSetting_StringValue) { + document_scan::OptionSetting input; + input.name = "name"; + input.type = document_scan::OptionType::kString; + input.value.emplace(); + input.value->as_string = "hello"; + + auto output = mojom::OptionSetting::From(input); + EXPECT_EQ(output->name, "name"); + EXPECT_EQ(output->type, mojom::OptionType::kString); + ASSERT_FALSE(output->value.is_null()); + ASSERT_TRUE(output->value->is_string_value()); + EXPECT_EQ(output->value->get_string_value(), "hello"); +} + +TEST(DocumentScanTypeConvertersTest, OptionSetting_Group) { + document_scan::OptionSetting input; + input.name = "name"; + input.type = document_scan::OptionType::kGroup; + + auto output = mojom::OptionSetting::From(input); + EXPECT_EQ(output->name, "name"); + EXPECT_EQ(output->type, mojom::OptionType::kGroup); + EXPECT_TRUE(output->value.is_null()); +} + +TEST(DocumentScanTypeConvertersTest, OptionSetting_Button) { + document_scan::OptionSetting input; + input.name = "name"; + input.type = document_scan::OptionType::kButton; + + auto output = mojom::OptionSetting::From(input); + EXPECT_EQ(output->name, "name"); + EXPECT_EQ(output->type, mojom::OptionType::kButton); + EXPECT_TRUE(output->value.is_null()); +} + +TEST(DocumentScanTypeConvertersTest, OptionSetting_None) { + document_scan::OptionSetting input; + input.name = "name"; + input.type = document_scan::OptionType::kNone; + + auto output = mojom::OptionSetting::From(input); + EXPECT_EQ(output->name, "name"); + EXPECT_EQ(output->type, mojom::OptionType::kUnknown); + EXPECT_TRUE(output->value.is_null()); +} + +TEST(DocumentScanTypeConvertersTest, SetOptionsResponse_Empty) { + auto input = mojom::SetOptionsResponse::New(); + auto output = input.To<document_scan::SetOptionsResponse>(); + EXPECT_EQ(output.scanner_handle, ""); + EXPECT_TRUE(output.results.empty()); + EXPECT_FALSE(output.options.has_value()); +} + +TEST(DocumentScanTypeConvertersTest, SetOptionsResponse_NonEmpty) { + auto input = mojom::SetOptionsResponse::New(); + input->scanner_handle = "scanner-handle"; + input->results.emplace_back(mojom::SetOptionResult::New( + "name1", mojom::ScannerOperationResult::kWrongType)); + input->results.emplace_back(mojom::SetOptionResult::New( + "name2", mojom::ScannerOperationResult::kSuccess)); + input->options.emplace(); + input->options->try_emplace( + "option1", extensions::CreateTestScannerOption("option1", 5)); + input->options->try_emplace( + "option2", extensions::CreateTestScannerOption("option2", 10)); + + auto output = input.To<document_scan::SetOptionsResponse>(); + EXPECT_EQ(output.scanner_handle, "scanner-handle"); + ASSERT_EQ(output.results.size(), 2U); + EXPECT_EQ(output.results[0].name, "name1"); + EXPECT_EQ(output.results[0].result, + document_scan::OperationResult::kWrongType); + EXPECT_EQ(output.results[1].name, "name2"); + EXPECT_EQ(output.results[1].result, document_scan::OperationResult::kSuccess); + ASSERT_TRUE(output.options.has_value()); + EXPECT_TRUE(base::Contains(output.options->additional_properties, "option1")); + EXPECT_TRUE(base::Contains(output.options->additional_properties, "option2")); +} + TEST(DocumentScanTypeConvertersTest, StartScanOptions_Empty) { document_scan::StartScanOptions input; auto output = mojom::StartScanOptions::From(input);
diff --git a/chrome/browser/extensions/api/document_scan/fake_document_scan_ash.cc b/chrome/browser/extensions/api/document_scan/fake_document_scan_ash.cc index 2091912..a90db68b 100644 --- a/chrome/browser/extensions/api/document_scan/fake_document_scan_ash.cc +++ b/chrome/browser/extensions/api/document_scan/fake_document_scan_ash.cc
@@ -153,8 +153,126 @@ const std::string& scanner_handle, std::vector<crosapi::mojom::OptionSettingPtr> options, SetOptionsCallback callback) { - // TODO(b/299489633): Implement this when adding the extension handler. - NOTIMPLEMENTED(); + auto response = crosapi::mojom::SetOptionsResponse::New(); + response->scanner_handle = scanner_handle; + response->results.reserve(options.size()); + + if (!base::Contains(open_scanners_, scanner_handle)) { + for (const auto& setting : options) { + response->results.emplace_back(crosapi::mojom::SetOptionResult::New( + setting->name, + crosapi::mojom::ScannerOperationResult::kDeviceMissing)); + } + std::move(callback).Run(std::move(response)); + return; + } + + // Fake setting options by copying and overriding the original config that + // would have been returned for this scanner. + const auto& open_response = + open_responses_[open_scanners_[scanner_handle].connection_string]; + if (!open_response->options.has_value()) { + for (const auto& setting : options) { + response->results.emplace_back(crosapi::mojom::SetOptionResult::New( + setting->name, + crosapi::mojom::ScannerOperationResult::kInternalError)); + } + std::move(callback).Run(std::move(response)); + return; + } + response->options.emplace(); + response->options->reserve(open_response->options->size()); + for (const auto& [name, option] : open_response->options.value()) { + response->options->try_emplace(name, option.Clone()); + } + + for (const auto& setting : options) { + auto result = crosapi::mojom::SetOptionResult::New(); + result->name = setting->name; + + // Ensure the returned options contains the requested option so that callers + // can look up the value. The real backend doesn't behave this way, but + // this avoids a ton of boilerplate in tests without changing the handler + // code coverage that can be achieved with the fake. + if (!base::Contains(response->options.value(), setting->name)) { + auto option = crosapi::mojom::ScannerOption::New(); + option->name = setting->name; + option->type = setting->type; + response->options->try_emplace(setting->name, std::move(option)); + } + + if (setting->value.is_null()) { + result->result = crosapi::mojom::ScannerOperationResult::kSuccess; + } else { + // If there's a value, make sure the value type matches the option type. + // The real backend does a lot more validation, but other cases are + // handled as pass-through, so there's no need to implement everything in + // this fake. + switch (setting->type) { + case crosapi::mojom::OptionType::kBool: + if (setting->value->is_bool_value()) { + result->result = crosapi::mojom::ScannerOperationResult::kSuccess; + response->options->at(setting->name)->value = + crosapi::mojom::OptionValue::NewBoolValue( + setting->value->get_bool_value()); + } else { + result->result = crosapi::mojom::ScannerOperationResult::kWrongType; + } + break; + case crosapi::mojom::OptionType::kInt: + if (setting->value->is_int_value()) { + result->result = crosapi::mojom::ScannerOperationResult::kSuccess; + response->options->at(setting->name)->value = + crosapi::mojom::OptionValue::NewIntValue( + setting->value->get_int_value()); + } else if (setting->value->is_int_list()) { + result->result = crosapi::mojom::ScannerOperationResult::kSuccess; + response->options->at(setting->name)->value = + crosapi::mojom::OptionValue::NewIntList( + {setting->value->get_int_list().begin(), + setting->value->get_int_list().end()}); + } else { + result->result = crosapi::mojom::ScannerOperationResult::kWrongType; + } + break; + case crosapi::mojom::OptionType::kFixed: + if (setting->value->is_fixed_value()) { + result->result = crosapi::mojom::ScannerOperationResult::kSuccess; + response->options->at(setting->name)->value = + crosapi::mojom::OptionValue::NewFixedValue( + setting->value->get_fixed_value()); + } else if (setting->value->is_fixed_list()) { + result->result = crosapi::mojom::ScannerOperationResult::kSuccess; + response->options->at(setting->name)->value = + crosapi::mojom::OptionValue::NewFixedList( + {setting->value->get_fixed_list().begin(), + setting->value->get_fixed_list().end()}); + } else { + result->result = crosapi::mojom::ScannerOperationResult::kWrongType; + } + break; + case crosapi::mojom::OptionType::kString: + if (setting->value->is_string_value()) { + result->result = crosapi::mojom::ScannerOperationResult::kSuccess; + response->options->at(setting->name)->value = + crosapi::mojom::OptionValue::NewStringValue( + setting->value->get_string_value()); + } else { + result->result = crosapi::mojom::ScannerOperationResult::kWrongType; + } + break; + default: + // Claim it succeeded, but don't update the returned option value. + // This is a valid outcome for a real scanner, so the frontend has to + // account for it, anyway. + result->result = crosapi::mojom::ScannerOperationResult::kSuccess; + break; + } + } + response->results.emplace_back(std::move(result)); + } + + std::move(callback).Run(std::move(response)); } void FakeDocumentScanAsh::GetOptionGroups(const std::string& scanner_handle,
diff --git a/chrome/browser/extensions/blocklist.cc b/chrome/browser/extensions/blocklist.cc index ea6a6f3..2aa0e7d 100644 --- a/chrome/browser/extensions/blocklist.cc +++ b/chrome/browser/extensions/blocklist.cc
@@ -182,8 +182,7 @@ blocklist_->RemoveObserver(this); } -Blocklist::Blocklist(PrefService* profile_prefs) - : profile_prefs_(profile_prefs) { +Blocklist::Blocklist() { auto& lazy_database_manager = g_database_manager.Get(); // Using base::Unretained is safe because when this object goes away, the // subscription will automatically be destroyed. @@ -204,9 +203,8 @@ void Blocklist::GetBlocklistedIDs(const std::set<std::string>& ids, GetBlocklistedIDsCallback callback) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - if (ids.empty() || !GetDatabaseManager().get() || - !safe_browsing::IsSafeBrowsingExtensionProtectionAllowed( - *profile_prefs_)) { + + if (ids.empty() || !GetDatabaseManager().get()) { base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( FROM_HERE, base::BindOnce(std::move(callback), BlocklistStateMap())); return;
diff --git a/chrome/browser/extensions/blocklist.h b/chrome/browser/extensions/blocklist.h index 5948e9f..3e45689 100644 --- a/chrome/browser/extensions/blocklist.h +++ b/chrome/browser/extensions/blocklist.h
@@ -20,8 +20,6 @@ #include "components/keyed_service/core/keyed_service.h" #include "extensions/browser/blocklist_state.h" -class PrefService; - namespace content { class BrowserContext; } @@ -63,7 +61,7 @@ using DatabaseReadyCallback = base::OnceCallback<void(bool)>; - explicit Blocklist(PrefService* profile_prefs); + Blocklist(); Blocklist(const Blocklist&) = delete; Blocklist& operator=(const Blocklist&) = delete; @@ -162,8 +160,6 @@ std::list<std::pair<std::vector<std::string>, base::OnceClosure>> state_requests_; - raw_ptr<PrefService> profile_prefs_ = nullptr; - base::WeakPtrFactory<Blocklist> weak_ptr_factory_{this}; };
diff --git a/chrome/browser/extensions/blocklist_check_unittest.cc b/chrome/browser/extensions/blocklist_check_unittest.cc index 7f32f18..900dea7 100644 --- a/chrome/browser/extensions/blocklist_check_unittest.cc +++ b/chrome/browser/extensions/blocklist_check_unittest.cc
@@ -21,8 +21,7 @@ class BlocklistCheckTest : public testing::Test { public: BlocklistCheckTest() - : test_prefs_(base::SingleThreadTaskRunner::GetCurrentDefault()), - blocklist_(test_prefs_.pref_service()) {} + : test_prefs_(base::SingleThreadTaskRunner::GetCurrentDefault()) {} protected: void SetUp() override {
diff --git a/chrome/browser/extensions/blocklist_factory.cc b/chrome/browser/extensions/blocklist_factory.cc index 4184228..2fab480 100644 --- a/chrome/browser/extensions/blocklist_factory.cc +++ b/chrome/browser/extensions/blocklist_factory.cc
@@ -4,7 +4,6 @@ #include "chrome/browser/extensions/blocklist_factory.h" #include "chrome/browser/extensions/blocklist.h" -#include "chrome/browser/profiles/profile.h" #include "extensions/browser/extension_prefs.h" #include "extensions/browser/extension_prefs_factory.h" #include "extensions/browser/extensions_browser_client.h" @@ -43,8 +42,7 @@ std::unique_ptr<KeyedService> BlocklistFactory::BuildServiceInstanceForBrowserContext( BrowserContext* context) const { - return std::make_unique<Blocklist>( - Profile::FromBrowserContext(context)->GetPrefs()); + return std::make_unique<Blocklist>(); } } // namespace extensions
diff --git a/chrome/browser/extensions/blocklist_state_fetcher.cc b/chrome/browser/extensions/blocklist_state_fetcher.cc index edb026a8..365a78e5 100644 --- a/chrome/browser/extensions/blocklist_state_fetcher.cc +++ b/chrome/browser/extensions/blocklist_state_fetcher.cc
@@ -92,11 +92,6 @@ "and your device from dangerous sites' in Chromium settings under " "Privacy. This feature is enabled by default." chrome_policy { - SafeBrowsingExtensionProtectionAllowed { - SafeBrowsingExtensionProtectionAllowed: false - } - } - chrome_policy { SafeBrowsingProtectionLevel { policy_options {mode: MANDATORY} SafeBrowsingProtectionLevel: 0
diff --git a/chrome/browser/extensions/blocklist_unittest.cc b/chrome/browser/extensions/blocklist_unittest.cc index 2f19d6ad..5f79f23 100644 --- a/chrome/browser/extensions/blocklist_unittest.cc +++ b/chrome/browser/extensions/blocklist_unittest.cc
@@ -13,7 +13,6 @@ #include "chrome/browser/extensions/test_blocklist.h" #include "chrome/browser/extensions/test_blocklist_state_fetcher.h" #include "chrome/browser/extensions/test_extension_prefs.h" -#include "components/safe_browsing/core/common/safe_browsing_prefs.h" #include "content/public/test/browser_task_environment.h" #include "extensions/browser/extension_prefs.h" #include "testing/gtest/include/gtest/gtest.h" @@ -27,8 +26,6 @@ : test_prefs_(base::SingleThreadTaskRunner::GetCurrentDefault()) {} protected: - PrefService* pref_service() { return test_prefs_.pref_service(); } - std::string AddExtension(const std::string& id) { return test_prefs_.AddExtension(id)->id(); } @@ -51,7 +48,7 @@ std::string b = AddExtension("b"); std::string c = AddExtension("c"); - Blocklist blocklist(pref_service()); + Blocklist blocklist; TestBlocklist tester(&blocklist); tester.SetBlocklistState(a, BLOCKLISTED_MALWARE, false); tester.SetBlocklistState(b, BLOCKLISTED_MALWARE, false); @@ -71,7 +68,7 @@ TEST_F(BlocklistTest, SafeBrowsing) { std::string a = AddExtension("a"); - Blocklist blocklist(pref_service()); + Blocklist blocklist; TestBlocklist tester(&blocklist); tester.DisableSafeBrowsing(); @@ -92,31 +89,9 @@ EXPECT_EQ(NOT_BLOCKLISTED, tester.GetBlocklistState(a)); } -// Should mimic Safe Browsing test for extension protection specific policy -TEST_F(BlocklistTest, SafeBrowingExtensionProtectionAllowedPolicy) { - std::string a = AddExtension("a"); - - Blocklist blocklist(pref_service()); - TestBlocklist tester(&blocklist); - // Set policy to disabled - pref_service()->SetBoolean( - prefs::kSafeBrowsingExtensionProtectionAllowedByPolicy, false); - - EXPECT_EQ(NOT_BLOCKLISTED, tester.GetBlocklistState(a)); - - tester.SetBlocklistState(a, BLOCKLISTED_MALWARE, false); - // The policy is still disabled at this point, so extension won't be - // blocklisted. - EXPECT_EQ(NOT_BLOCKLISTED, tester.GetBlocklistState(a)); - // Reenable the policy - pref_service()->SetBoolean( - prefs::kSafeBrowsingExtensionProtectionAllowedByPolicy, true); - EXPECT_EQ(BLOCKLISTED_MALWARE, tester.GetBlocklistState(a)); -} - // Test getting different blocklist states from Blocklist. TEST_F(BlocklistTest, GetBlocklistStates) { - Blocklist blocklist(pref_service()); + Blocklist blocklist; TestBlocklist tester(&blocklist); std::string a = AddExtension("a"); @@ -164,7 +139,7 @@ // Test both Blocklist and BlocklistStateFetcher by requesting the blocklist // states, sending fake requests and parsing the responses. TEST_F(BlocklistTest, FetchBlocklistStates) { - Blocklist blocklist(pref_service()); + Blocklist blocklist; scoped_refptr<FakeSafeBrowsingDatabaseManager> blocklist_db( new FakeSafeBrowsingDatabaseManager(true)); ScopedDatabaseManagerForTest scoped_blocklist_db(blocklist_db);
diff --git a/chrome/browser/extensions/crx_installer_browsertest.cc b/chrome/browser/extensions/crx_installer_browsertest.cc index 0cb0209..b42eb4d 100644 --- a/chrome/browser/extensions/crx_installer_browsertest.cc +++ b/chrome/browser/extensions/crx_installer_browsertest.cc
@@ -43,7 +43,6 @@ #include "chrome/grit/generated_resources.h" #include "chrome/test/base/ui_test_utils.h" #include "components/safe_browsing/buildflags.h" -#include "components/safe_browsing/core/common/safe_browsing_prefs.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/download_manager.h" #include "content/public/browser/render_view_host.h" @@ -664,25 +663,6 @@ EXPECT_EQ(CrxInstallErrorDetail::EXTENSION_IS_BLOCKLISTED, installation_failure.install_error_detail); } - -// TODO(alexwchen): Update this test to use a non-theme crx -IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, BlocklistPolicyDisabled) { - // Disable policy which should prevent blocklist from blocking installation of - // unsafe Crx - browser()->profile()->GetPrefs()->SetBoolean( - prefs::kSafeBrowsingExtensionProtectionAllowedByPolicy, false); - - scoped_refptr<FakeSafeBrowsingDatabaseManager> blocklist_db( - base::MakeRefCounted<FakeSafeBrowsingDatabaseManager>(true)); - ScopedDatabaseManagerForTest scoped_blocklist_db(blocklist_db); - - const std::string extension_id = "gllekhaobjnhgeagipipnkpmmmpchacm"; - blocklist_db->SetUnsafe(extension_id); - - base::FilePath crx_path = test_data_dir_.AppendASCII("theme_hidpi_crx") - .AppendASCII("theme_hidpi.crx"); - EXPECT_TRUE(InstallExtension(crx_path, 1)); -} #endif IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, NonStrictManifestCheck) {
diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h index 7aa09c0..c58d673 100644 --- a/chrome/browser/extensions/extension_service.h +++ b/chrome/browser/extensions/extension_service.h
@@ -825,8 +825,6 @@ ExtensionsNotAllowlistedThenBlocklisted); FRIEND_TEST_ALL_PREFIXES(ExtensionAllowlistUnitTest, ExtensionsBlocklistedThenNotAllowlisted); - FRIEND_TEST_ALL_PREFIXES(OmahaAttributesHandlerUnitTest, - NoUnsetBlocklistWhenSBBlocklistPolicyDisabled); FRIEND_TEST_ALL_PREFIXES(SafeBrowsingVerdictHandlerUnitTest, GreylistedExtensionDisabled); FRIEND_TEST_ALL_PREFIXES(SafeBrowsingVerdictHandlerUnitTest, @@ -849,8 +847,6 @@ ExtensionUninstalledWhenBlocklisted); FRIEND_TEST_ALL_PREFIXES(SafeBrowsingVerdictHandlerUnitTest, ExtensionUninstalledWhenBlocklistFetching); - FRIEND_TEST_ALL_PREFIXES(SafeBrowsingVerdictHandlerUnitTest, - ReloadBlocklistedExtensionWhenPolicyDisabled); friend class ::BlocklistedExtensionSyncServiceTest; friend class SafeBrowsingVerdictHandlerUnitTest; friend class BlocklistStatesInteractionUnitTest;
diff --git a/chrome/browser/extensions/omaha_attributes_handler_unittest.cc b/chrome/browser/extensions/omaha_attributes_handler_unittest.cc index 10b6d04..dae0545 100644 --- a/chrome/browser/extensions/omaha_attributes_handler_unittest.cc +++ b/chrome/browser/extensions/omaha_attributes_handler_unittest.cc
@@ -8,7 +8,6 @@ #include "base/values.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_service_test_base.h" -#include "chrome/browser/extensions/test_blocklist.h" #include "chrome/browser/profiles/profile.h" #include "extensions/browser/blocklist_extension_prefs.h" #include "extensions/browser/disable_reason.h" @@ -270,32 +269,4 @@ service()->PerformActionBasedOnOmahaAttributes(kTestExtensionId, attributes); } -// Tests that an extension that was disabled through Omaha won't be re-enabled -// if Safe Browsing blocklist policy is disabled. -TEST_F(OmahaAttributesHandlerUnitTest, - NoUnsetBlocklistWhenSBBlocklistPolicyDisabled) { - TestBlocklist test_blocklist; - - InitializeGoodInstalledExtensionService(); - test_blocklist.Attach(service()->blocklist_); - service()->Init(); - - ExtensionStateTester state_tester(profile()); - EXPECT_TRUE(state_tester.ExpectEnabled(kTestExtensionId)); - - auto attributes = base::Value::Dict().Set("_malware", true); - service()->PerformActionBasedOnOmahaAttributes(kTestExtensionId, attributes); - EXPECT_TRUE(state_tester.ExpectBlocklisted(kTestExtensionId)); - - // Disable SB blocklist by policy and refresh blocklist. - profile()->GetPrefs()->SetBoolean( - prefs::kSafeBrowsingExtensionProtectionAllowedByPolicy, false); - test_blocklist.NotifyUpdate(); - task_environment()->RunUntilIdle(); - - // Disabling SB blocklist by policy should not impact extensions blocked by - // Omaha. - EXPECT_TRUE(state_tester.ExpectBlocklisted(kTestExtensionId)); -} - } // namespace extensions
diff --git a/chrome/browser/extensions/safe_browsing_verdict_handler_unittest.cc b/chrome/browser/extensions/safe_browsing_verdict_handler_unittest.cc index 326d25b..e48479a 100644 --- a/chrome/browser/extensions/safe_browsing_verdict_handler_unittest.cc +++ b/chrome/browser/extensions/safe_browsing_verdict_handler_unittest.cc
@@ -503,39 +503,6 @@ task_environment()->RunUntilIdle(); } -// Tests that blocklisted extensions should be reloaded/blocked if blocklist -// policy is changed. -TEST_F(SafeBrowsingVerdictHandlerUnitTest, - ReloadBlocklistedExtensionWhenPolicyDisabled) { - TestBlocklist test_blocklist; - - // A profile with 3 extensions installed: good0, good1, and good2. - InitializeGoodInstalledExtensionService(); - test_blocklist.Attach(service()->blocklist_); - service()->Init(); - test_blocklist.SetBlocklistState(kGood1, BLOCKLISTED_MALWARE, true); - task_environment()->RunUntilIdle(); - EXPECT_EQ(1u, registry()->blocklisted_extensions().size()); - EXPECT_EQ(2u, registry()->enabled_extensions().size()); - - profile()->GetPrefs()->SetBoolean( - prefs::kSafeBrowsingExtensionProtectionAllowedByPolicy, false); - - // Since policy is disabled, all extensions should be unblocklisted. - test_blocklist.NotifyUpdate(); - task_environment()->RunUntilIdle(); - EXPECT_EQ(0u, registry()->blocklisted_extensions().size()); - EXPECT_EQ(3u, registry()->enabled_extensions().size()); - - profile()->GetPrefs()->SetBoolean( - prefs::kSafeBrowsingExtensionProtectionAllowedByPolicy, true); - - // Since policy is enabled, good1 should be blocked again. - test_blocklist.NotifyUpdate(); - task_environment()->RunUntilIdle(); - EXPECT_EQ(1u, registry()->blocklisted_extensions().size()); - EXPECT_EQ(2u, registry()->enabled_extensions().size()); -} #endif // defined(ENABLE_BLOCKLIST_TESTS) } // namespace extensions
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index f92df9d..3e7a1939 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -1120,11 +1120,6 @@ "expiry_milestone": 120 }, { - "name": "cct-real-time-engagement-signals-alternative-impl", - "owners": ["sinansahin@google.com"], - "expiry_milestone": 120 - }, - { "name": "cct-resizable-90-maximum-height", "owners": ["jinsukkim@chromium.org", "twellington@chromium.org"], "expiry_milestone": 110 @@ -1544,6 +1539,11 @@ "expiry_milestone": 125 }, { + "name": "customize-chrome-wallpaper-search-inspiration-card", + "owners": [ "pauladedeji@google.com", "tiborg@chromium.org" ], + "expiry_milestone": 125 + }, + { "name": "cws-info-fast-check", "owners": [ "anunoy@chromium.org" @@ -2149,11 +2149,6 @@ "expiry_milestone": 86 }, { - "name": "enable-baseline-gm3-surface-colors", - "owners": ["nemco@google.com", "skavuluru@google.com"], - "expiry_milestone": 125 - }, - { "name": "enable-benchmarking", "owners": [ "//components/variations/OWNERS" ], // This is used by testers and developers to determine whether a bug is
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 14e26f2..48cee7ed 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -225,6 +225,12 @@ const char kCustomizeChromeWallpaperSearchDescription[] = "Enables wallpaper search in Customize Chrome Side Panel."; +const char kCustomizeChromeWallpaperSearchInspirationCardName[] = + "Customize Chrome Wallpaper Search Inspiration Card"; +const char kCustomizeChromeWallpaperSearchInspirationCardDescription[] = + "Shows inspiration card in Customize Chrome Side Panel Wallpaper Search. " + "Requires #customize-chrome-wallpaper-search to be enabled too."; + const char kWallpaperSearchSettingsVisibilityName[] = "Wallpaper Search Settings Visibility"; const char kWallpaperSearchSettingsVisibilityDescription[] = @@ -2849,10 +2855,6 @@ const char kPowerBookmarkBackendDescription[] = "Enables storing additional metadata to support power bookmark features."; -const char kBookmarksImprovedSaveFlowName[] = "Improved bookmarks save flow"; -const char kBookmarksImprovedSaveFlowDescription[] = - "Enabled an improved save flow for bookmarks."; - const char kSpeculationRulesPrerenderingTargetHintName[] = "Speculation Rules API target hint"; const char kSpeculationRulesPrerenderingTargetHintDescription[] = @@ -3723,7 +3725,6 @@ const char kWebXrRuntimeChoiceNone[] = "No Runtime"; const char kWebXrRuntimeChoiceCardboard[] = "Cardboard"; -const char kWebXrRuntimeChoiceGVR[] = "Google VR Services"; const char kWebXrRuntimeChoiceOpenXR[] = "OpenXR"; const char kWebXrIncubationsName[] = "WebXR Incubations"; @@ -4515,10 +4516,6 @@ "tabs before the tab strip is initialized to prevent " "jank (tabs seeming to quickly flicker / scroll)."; -const char kBaselineGM3SurfaceColorsName[] = "Baseline GM3 Surface Colors"; -const char kBaselineGM3SurfaceColorsDescription[] = - "Updates baseline surface colors to match the GM3 formula."; - const char kDelayTempStripRemovalName[] = "Delay temp tab strip removal on startup"; const char kDelayTempStripRemovalDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index e431fff..c059ce00 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -161,6 +161,9 @@ extern const char kCustomizeChromeWallpaperSearchName[]; extern const char kCustomizeChromeWallpaperSearchDescription[]; +extern const char kCustomizeChromeWallpaperSearchInspirationCardName[]; +extern const char kCustomizeChromeWallpaperSearchInspirationCardDescription[]; + extern const char kWallpaperSearchSettingsVisibilityName[]; extern const char kWallpaperSearchSettingsVisibilityDescription[]; @@ -1609,9 +1612,6 @@ extern const char kPdfXfaFormsName[]; extern const char kPdfXfaFormsDescription[]; -extern const char kBookmarksImprovedSaveFlowName[]; -extern const char kBookmarksImprovedSaveFlowDescription[]; - extern const char kAutoWebContentsDarkModeName[]; extern const char kAutoWebContentsDarkModeDescription[]; @@ -1934,9 +1934,6 @@ extern const char kTabStripStartupRefactoringName[]; extern const char kTabStripStartupRefactoringDescription[]; -extern const char kBaselineGM3SurfaceColorsName[]; -extern const char kBaselineGM3SurfaceColorsDescription[]; - extern const char kDelayTempStripRemovalName[]; extern const char kDelayTempStripRemovalDescription[]; @@ -2136,7 +2133,6 @@ extern const char kWebXrRuntimeChoiceNone[]; extern const char kWebXrRuntimeChoiceCardboard[]; -extern const char kWebXrRuntimeChoiceGVR[]; extern const char kWebXrRuntimeChoiceOpenXR[]; extern const char kWebXrIncubationsName[];
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc index f0e025ec..4531bea 100644 --- a/chrome/browser/flags/android/chrome_feature_list.cc +++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -113,7 +113,6 @@ &features::kBlockMidiByDefault, &features::kBoardingPassDetector, &features::kNetworkServiceInProcess, - &shared_highlighting::kPreemptiveLinkToTextGeneration, &features::kElasticOverscroll, &features::kPrivacyGuideAndroid, &features::kPrivacyGuideAndroid3, @@ -179,12 +178,10 @@ &kBackGestureRefactorActivityAndroid, &kBackGestureRefactorAndroid, &kBackgroundThreadPool, - &kBaselineGM3SurfaceColors, &kBlockIntentsWhileLocked, &kCacheActivityTaskID, &kCastDeviceFilter, &kClearOmniboxFocusAfterNavigation, - &kCloseTabSaveTabList, &kCreateNewTabInitializeRenderer, &kCCTBrandTransparency, &kCCTBrandTransparencyMemoryImprovement, @@ -247,7 +244,6 @@ &kPreconnectOnTabCreation, &kPriceChangeModule, &kPwaRestoreUi, - &kBookmarksImprovedSaveFlow, &kOmahaMinSdkVersionAndroid, &kShortCircuitUnfocusAnimation, &kOmniboxNoopEditUrlSuggestionClicks, @@ -496,10 +492,6 @@ "BackgroundThreadPool", base::FEATURE_DISABLED_BY_DEFAULT); -BASE_FEATURE(kBaselineGM3SurfaceColors, - "BaselineGM3SurfaceColors", - base::FEATURE_ENABLED_BY_DEFAULT); - BASE_FEATURE(kBlockIntentsWhileLocked, "BlockIntentsWhileLocked", base::FEATURE_DISABLED_BY_DEFAULT); @@ -517,10 +509,6 @@ "ClearOmniboxFocusAfterNavigation", base::FEATURE_ENABLED_BY_DEFAULT); -BASE_FEATURE(kCloseTabSaveTabList, - "CloseTabSaveTabList", - base::FEATURE_ENABLED_BY_DEFAULT); - BASE_FEATURE(kCreateNewTabInitializeRenderer, "CreateNewTabInitializeRenderer", base::FEATURE_DISABLED_BY_DEFAULT); @@ -762,10 +750,6 @@ BASE_FEATURE(kPwaRestoreUi, "PwaRestoreUi", base::FEATURE_DISABLED_BY_DEFAULT); -BASE_FEATURE(kBookmarksImprovedSaveFlow, - "BookmarksImprovedSaveFlow", - base::FEATURE_DISABLED_BY_DEFAULT); - BASE_FEATURE(kBackGestureActivityTabProvider, "BackGestureActivityTabProvider", base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h index e57608cc..e70ada3 100644 --- a/chrome/browser/flags/android/chrome_feature_list.h +++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -39,11 +39,9 @@ BASE_DECLARE_FEATURE(kBackGestureRefactorActivityAndroid); BASE_DECLARE_FEATURE(kBackGestureRefactorAndroid); BASE_DECLARE_FEATURE(kBackgroundThreadPool); -BASE_DECLARE_FEATURE(kBaselineGM3SurfaceColors); BASE_DECLARE_FEATURE(kBlockIntentsWhileLocked); BASE_DECLARE_FEATURE(kCacheActivityTaskID); BASE_DECLARE_FEATURE(kClearOmniboxFocusAfterNavigation); -BASE_DECLARE_FEATURE(kCloseTabSaveTabList); BASE_DECLARE_FEATURE(kCreateNewTabInitializeRenderer); BASE_DECLARE_FEATURE(kCastDeviceFilter); BASE_DECLARE_FEATURE(kCCTBrandTransparency); @@ -121,7 +119,6 @@ BASE_DECLARE_FEATURE(kPreconnectOnTabCreation); BASE_DECLARE_FEATURE(kPriceChangeModule); BASE_DECLARE_FEATURE(kPwaRestoreUi); -BASE_DECLARE_FEATURE(kBookmarksImprovedSaveFlow); BASE_DECLARE_FEATURE(kPartnerCustomizationsUma); BASE_DECLARE_FEATURE(kProbabilisticCryptidRenderer); BASE_DECLARE_FEATURE(kQuickDeleteForAndroid);
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java index 3586154e..4d7d4805 100644 --- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java +++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -168,7 +168,6 @@ public static final String BACK_GESTURE_REFACTOR = "BackGestureRefactorAndroid"; public static final String BACK_GESTURE_REFACTOR_ACTIVITY = "BackGestureRefactorActivityAndroid"; - public static final String BASELINE_GM3_SURFACE_COLORS = "BaselineGM3SurfaceColors"; public static final String BLOCK_INTENTS_WHILE_LOCKED = "BlockIntentsWhileLocked"; public static final String BOARDING_PASS_DETECTOR = "BoardingPassDetector"; public static final String CACHE_ACTIVITY_TASKID = "CacheActivityTaskID"; @@ -199,7 +198,6 @@ public static final String CHROME_SURVEY_NEXT_ANDROID = "ChromeSurveyNextAndroid"; public static final String CLEAR_OMNIBOX_FOCUS_AFTER_NAVIGATION = "ClearOmniboxFocusAfterNavigation"; - public static final String CLOSE_TAB_SAVE_TAB_LIST = "CloseTabSaveTabList"; public static final String COLLECT_ANDROID_FRAME_TIMELINE_METRICS = "CollectAndroidFrameTimelineMetrics"; public static final String COMMAND_LINE_ON_NON_ROOTED = "CommandLineOnNonRooted"; @@ -346,8 +344,6 @@ public static final String PLUS_ADDRESSES_ENABLED = "PlusAddressesEnabled"; public static final String PORTALS = "Portals"; public static final String PORTALS_CROSS_ORIGIN = "PortalsCrossOrigin"; - public static final String PREEMPTIVE_LINK_TO_TEXT_GENERATION = - "PreemptiveLinkToTextGeneration"; public static final String PRERENDER2 = "Prerender2"; public static final String PRECONNECT_ON_TAB_CREATION = "PreconnectOnTabCreation"; public static final String PRICE_CHANGE_MODULE = "PriceChangeModule"; @@ -416,7 +412,6 @@ public static final String SEED_ACCOUNTS_REVAMP = "SeedAccountsRevamp"; public static final String SHARE_SHEET_MIGRATION_ANDROID = "ShareSheetMigrationAndroid"; public static final String SEND_TAB_TO_SELF_V2 = "SendTabToSelfV2"; - public static final String SHOPPING_LIST = "ShoppingList"; public static final String SHOW_NTP_AT_STARTUP_ANDROID = "ShowNtpAtStartupAndroid"; public static final String SHOW_SCROLLABLE_MVT_ON_NTP_ANDROID = "ShowScrollableMVTOnNTPAndroid"; public static final String SHOW_SCROLLABLE_MVT_ON_NTP_PHONE_ANDROID = @@ -501,8 +496,6 @@ new CachedFlag(BACK_GESTURE_REFACTOR_ACTIVITY, false); public static final CachedFlag sBackGestureRefactorAndroid = new CachedFlag(BACK_GESTURE_REFACTOR, false); - public static final CachedFlag sBaselineGm3SurfaceColors = - new CachedFlag(BASELINE_GM3_SURFACE_COLORS, true); public static final CachedFlag sBlockIntentsWhileLocked = new CachedFlag(BLOCK_INTENTS_WHILE_LOCKED, false); public static final CachedFlag sCctAutoTranslate = new CachedFlag(CCT_AUTO_TRANSLATE, true); @@ -523,8 +516,6 @@ public static final CachedFlag sCctResizableSideSheetForThirdParties = new CachedFlag(CCT_RESIZABLE_SIDE_SHEET_FOR_THIRD_PARTIES, true); public static final CachedFlag sCctTabModalDialog = new CachedFlag(CCT_TAB_MODAL_DIALOG, true); - public static final CachedFlag sCloseTabSaveTabList = - new CachedFlag(CLOSE_TAB_SAVE_TAB_LIST, true); public static final CachedFlag sCollectAndroidFrameTimelineMetrics = new CachedFlag(COLLECT_ANDROID_FRAME_TIMELINE_METRICS, false); public static final CachedFlag sCommandLineOnNonRooted = @@ -633,7 +624,6 @@ sBackGestureActivityTabProvider, sBackGestureRefactorActivityAndroid, sBackGestureRefactorAndroid, - sBaselineGm3SurfaceColors, sBlockIntentsWhileLocked, sCctAutoTranslate, sCctBrandTransparencyMemoryImprovement, @@ -646,7 +636,6 @@ sCctResizableSideSheet, sCctResizableSideSheetForThirdParties, sCctTabModalDialog, - sCloseTabSaveTabList, sCollectAndroidFrameTimelineMetrics, sCommandLineOnNonRooted, sDeferTabSwitcherLayoutCreation,
diff --git a/chrome/browser/net/websocket_browsertest.cc b/chrome/browser/net/websocket_browsertest.cc index e780c585..9e5b4e7 100644 --- a/chrome/browser/net/websocket_browsertest.cc +++ b/chrome/browser/net/websocket_browsertest.cc
@@ -18,6 +18,7 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/test/bind.h" +#include "base/test/run_until.h" #include "base/test/scoped_feature_list.h" #include "base/test/test_future.h" #include "build/build_config.h" @@ -26,7 +27,6 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/login/login_handler.h" -#include "chrome/browser/ui/login/login_handler_test_utils.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" @@ -420,11 +420,9 @@ &browser()->tab_strip_model()->GetActiveWebContents()->GetController(); AutoLogin auto_login("test", "test", navigation_controller); - WindowedAuthNeededObserver auth_needed_waiter(navigation_controller); NavigateToHTTP("connect_check.html"); - auth_needed_waiter.Wait(); - EXPECT_TRUE(auto_login.logged_in()); + ASSERT_TRUE(base::test::RunUntil([&]() { return auto_login.logged_in(); })); EXPECT_EQ("PASS", WaitAndGetTitle()); }
diff --git a/chrome/browser/platform_util_mac.mm b/chrome/browser/platform_util_mac.mm index 56b7f6da..418516c0 100644 --- a/chrome/browser/platform_util_mac.mm +++ b/chrome/browser/platform_util_mac.mm
@@ -92,7 +92,7 @@ // https://crbug.com/1504165 static auto* const crash_key = base::debug::AllocateCrashKeyString( - "platform_util::OpenExternal()", base::debug::CrashKeySize::Size64); + "platform_util_OpenExternal()", base::debug::CrashKeySize::Size64); NSUInteger length = [ns_url absoluteString].length; NSString* lengthString = [NSString stringWithFormat:@"%lu", length]; base::debug::ScopedCrashKeyString(crash_key,
diff --git a/chrome/browser/plugins/plugin_response_interceptor_url_loader_throttle.cc b/chrome/browser/plugins/plugin_response_interceptor_url_loader_throttle.cc index 2ede3f2..45dacba 100644 --- a/chrome/browser/plugins/plugin_response_interceptor_url_loader_throttle.cc +++ b/chrome/browser/plugins/plugin_response_interceptor_url_loader_throttle.cc
@@ -20,7 +20,6 @@ #include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_attach_helper.h" #include "extensions/common/constants.h" #include "extensions/common/extension.h" -#include "extensions/common/manifest_handlers/mime_types_handler.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/remote.h" @@ -141,8 +140,6 @@ ClearAllButFrameAncestors(response_head); } - MimeTypesHandler::ReportUsedHandler(extension_id); - // TODO(mcnee): Could this id just be an int instead? This is only used // internally. const std::string stream_id =
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc index 95d04c4..1153b338 100644 --- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc +++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -1864,9 +1864,6 @@ { key::kRemoteAccessHostAllowEnterpriseRemoteSupportConnections, prefs::kRemoteAccessHostAllowEnterpriseRemoteSupportConnections, base::Value::Type::BOOLEAN }, - { key::kSafeBrowsingExtensionProtectionAllowed, - prefs::kSafeBrowsingExtensionProtectionAllowedByPolicy, - base::Value::Type::BOOLEAN }, // We avoid checking for BUILDFLAG(ENABLE_NACL) since we may want the policy // to exist (deprecated) even if NACL is no longer being built. { key::kNativeClientForceAllowed,
diff --git a/chrome/browser/privacy_budget/privacy_budget_browsertest.cc b/chrome/browser/privacy_budget/privacy_budget_browsertest.cc index aaeadcc..e1f8e70e 100644 --- a/chrome/browser/privacy_budget/privacy_budget_browsertest.cc +++ b/chrome/browser/privacy_budget/privacy_budget_browsertest.cc
@@ -518,14 +518,12 @@ recorder().SetOnAddEntryCallback( ukm::builders::Identifiability::kEntryName, base::BindLambdaForTesting([this, &run_loop]() { - // (kCanvasReadback | input_digest << kTypeBits) = one of the - // merged_entries. If the value of the relevant merged entry changes, - // input_digest needs to change. The new input_digest can be calculated - // by: new_input_digest = new_ukm_entry >> kTypeBits; - constexpr uint64_t input_digest = UINT64_C(33457614533296512); + // Key of the entry metric to look for. + constexpr uint64_t input_digest = UINT64_C(3701609392929341475); const uint64_t canvas_key = blink::IdentifiableSurface::FromTypeAndToken( - blink::IdentifiableSurface::Type::kCanvasReadback, input_digest) + blink::IdentifiableSurface::Type::kCanvasReadback, + input_digest >> blink::IdentifiableSurface::kTypeBits) .ToUkmMetricHash(); for (const ukm::mojom::UkmEntry* entry : recorder().GetEntriesByName(
diff --git a/chrome/browser/readaloud/android/BUILD.gn b/chrome/browser/readaloud/android/BUILD.gn index 86e618d9..4e64d61d 100644 --- a/chrome/browser/readaloud/android/BUILD.gn +++ b/chrome/browser/readaloud/android/BUILD.gn
@@ -286,6 +286,7 @@ "//chrome/browser/tab:java", "//chrome/browser/ui/android/layouts:java", "//components/browser_ui/bottomsheet/android:java", + "//components/browser_ui/styles/android:java", "//components/prefs/android:java", "//third_party/androidx:androidx_appcompat_appcompat_java", "//third_party/androidx:androidx_interpolator_interpolator_java",
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerLayoutUnitTest.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerLayoutUnitTest.java index a5387f8..845aa721 100644 --- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerLayoutUnitTest.java +++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/mini/MiniPlayerLayoutUnitTest.java
@@ -38,6 +38,7 @@ import org.chromium.chrome.browser.readaloud.player.InteractionHandler; import org.chromium.chrome.browser.readaloud.player.R; import org.chromium.chrome.modules.readaloud.PlaybackListener; +import org.chromium.components.browser_ui.styles.ChromeColors; /** Unit tests for {@link PlayerCoordinator}. */ @RunWith(BaseRobolectricTestRunner.class) @@ -328,8 +329,9 @@ public void testDarkModeBackgroundColor() { View spyBackdrop = replaceWithSpy(R.id.backdrop); mLayout.onFinishInflate(); - verify(spyBackdrop).setBackgroundColor(eq(0xff343435)); - verify(mMediator).onBackgroundColorUpdated(eq(0xff343435)); + int bg = ChromeColors.getSurfaceColor(mActivity, R.dimen.default_elevation_4); + verify(spyBackdrop).setBackgroundColor(eq(bg)); + verify(mMediator).onBackgroundColorUpdated(eq(bg)); } private View replaceWithSpy(int childId) {
diff --git a/chrome/browser/reading_list/reading_list_model_factory.cc b/chrome/browser/reading_list/reading_list_model_factory.cc index d644c6a..316aedde 100644 --- a/chrome/browser/reading_list/reading_list_model_factory.cc +++ b/chrome/browser/reading_list/reading_list_model_factory.cc
@@ -69,6 +69,16 @@ GetInstance()->GetServiceForBrowserContext(context, true)); } +#if BUILDFLAG(IS_ANDROID) +// static +reading_list::DualReadingListModel* +ReadingListModelFactory::GetAsDualReadingListForBrowserContext( + content::BrowserContext* context) { + return static_cast<reading_list::DualReadingListModel*>( + GetInstance()->GetServiceForBrowserContext(context, true)); +} +#endif + // static ReadingListModelFactory* ReadingListModelFactory::GetInstance() { static base::NoDestructor<ReadingListModelFactory> instance;
diff --git a/chrome/browser/reading_list/reading_list_model_factory.h b/chrome/browser/reading_list/reading_list_model_factory.h index 1971170..5551333 100644 --- a/chrome/browser/reading_list/reading_list_model_factory.h +++ b/chrome/browser/reading_list/reading_list_model_factory.h
@@ -5,15 +5,17 @@ #ifndef CHROME_BROWSER_READING_LIST_READING_LIST_MODEL_FACTORY_H_ #define CHROME_BROWSER_READING_LIST_READING_LIST_MODEL_FACTORY_H_ +#include "build/build_config.h" #include "chrome/browser/profiles/profile_keyed_service_factory.h" +#include "components/reading_list/core/dual_reading_list_model.h" +#include "components/reading_list/core/reading_list_model.h" +#include "content/public/browser/browser_context.h" namespace base { template <typename T> class NoDestructor; } -class ReadingListModel; - // Singleton that owns all ReadingListModels and associates them with // BrowserContexts. class ReadingListModelFactory : public ProfileKeyedServiceFactory { @@ -22,7 +24,12 @@ ReadingListModelFactory& operator=(const ReadingListModelFactory&) = delete; static ReadingListModel* GetForBrowserContext( - content::BrowserContext* browser_context); + content::BrowserContext* context); + +#if BUILDFLAG(IS_ANDROID) + static reading_list::DualReadingListModel* + GetAsDualReadingListForBrowserContext(content::BrowserContext* context); +#endif static ReadingListModelFactory* GetInstance();
diff --git a/chrome/browser/recent_tabs/internal/android/java/src/org/chromium/chrome/browser/recent_tabs/RestoreTabsUiRenderTest.java b/chrome/browser/recent_tabs/internal/android/java/src/org/chromium/chrome/browser/recent_tabs/RestoreTabsUiRenderTest.java index a26c3636..8b716c7 100644 --- a/chrome/browser/recent_tabs/internal/android/java/src/org/chromium/chrome/browser/recent_tabs/RestoreTabsUiRenderTest.java +++ b/chrome/browser/recent_tabs/internal/android/java/src/org/chromium/chrome/browser/recent_tabs/RestoreTabsUiRenderTest.java
@@ -79,7 +79,7 @@ public final ChromeRenderTestRule mRenderTestRule = ChromeRenderTestRule.Builder.withPublicCorpus() .setBugComponent(RenderTestRule.Component.UI_BROWSER_MOBILE_RECENT_TABS) - .setRevision(3) + .setRevision(4) .build(); @Rule
diff --git a/chrome/browser/renderer_context_menu/accessibility_labels_menu_observer.cc b/chrome/browser/renderer_context_menu/accessibility_labels_menu_observer.cc index 7ea45a6..b69028d 100644 --- a/chrome/browser/renderer_context_menu/accessibility_labels_menu_observer.cc +++ b/chrome/browser/renderer_context_menu/accessibility_labels_menu_observer.cc
@@ -121,8 +121,14 @@ void AccessibilityLabelsMenuObserver::ShowConfirmBubble(Profile* profile, bool enable_always) { content::WebContents* web_contents = proxy_->GetWebContents(); + // We use the web contents' primary main frame here rather than getting the + // view from the local render frame host because we want to ensure that it is + // non-null (proxy_->GetRenderFrameHost() can return nullptr if the frame goes + // away). In these cases, the spelling preference changes are still valid + // (tied to the BrowsingContext / WebContents) so we still want to show the + // confirmation bubble. content::RenderWidgetHostView* view = - proxy_->GetRenderViewHost()->GetWidget()->GetView(); + web_contents->GetPrimaryMainFrame()->GetRenderWidgetHost()->GetView(); gfx::Rect rect = view->GetViewBounds(); auto model = std::make_unique<AccessibilityLabelsBubbleModel>( profile, web_contents, enable_always);
diff --git a/chrome/browser/renderer_context_menu/mock_render_view_context_menu.cc b/chrome/browser/renderer_context_menu/mock_render_view_context_menu.cc index 363b573..1abcdabae 100644 --- a/chrome/browser/renderer_context_menu/mock_render_view_context_menu.cc +++ b/chrome/browser/renderer_context_menu/mock_render_view_context_menu.cc
@@ -245,7 +245,8 @@ #endif // BUILDFLAG(ENABLE_SCREEN_AI_SERVICE) } -content::RenderViewHost* MockRenderViewContextMenu::GetRenderViewHost() const { +content::RenderFrameHost* MockRenderViewContextMenu::GetRenderFrameHost() + const { return nullptr; }
diff --git a/chrome/browser/renderer_context_menu/mock_render_view_context_menu.h b/chrome/browser/renderer_context_menu/mock_render_view_context_menu.h index d951eed..010fc5b 100644 --- a/chrome/browser/renderer_context_menu/mock_render_view_context_menu.h +++ b/chrome/browser/renderer_context_menu/mock_render_view_context_menu.h
@@ -80,7 +80,7 @@ void AddSpellCheckServiceItem(bool is_checked) override; void AddAccessibilityLabelsServiceItem(bool is_checked) override; void AddPdfOcrMenuItem() override; - content::RenderViewHost* GetRenderViewHost() const override; + content::RenderFrameHost* GetRenderFrameHost() const override; content::BrowserContext* GetBrowserContext() const override; content::WebContents* GetWebContents() const override;
diff --git a/chrome/browser/renderer_context_menu/spelling_menu_observer.cc b/chrome/browser/renderer_context_menu/spelling_menu_observer.cc index 1098a3c..3ee6bc8b 100644 --- a/chrome/browser/renderer_context_menu/spelling_menu_observer.cc +++ b/chrome/browser/renderer_context_menu/spelling_menu_observer.cc
@@ -338,13 +338,20 @@ true); } } else if (!integrate_spelling_service_.GetValue()) { - content::RenderViewHost* rvh = proxy_->GetRenderViewHost(); - gfx::Rect rect = rvh->GetWidget()->GetView()->GetViewBounds(); + // We use the web contents' primary main frame here rather than getting + // the view from the local render frame host because we want to ensure + // that it is non-null (proxy_->GetRenderFrameHost() can return nullptr if + // the frame goes away). In these cases, the spelling preference changes + // are still valid (tied to the BrowsingContext / WebContents) so we still + // want to show the confirmation bubble. + content::RenderFrameHost* rfh = + proxy_->GetWebContents()->GetPrimaryMainFrame(); + gfx::Rect rect = rfh->GetRenderWidgetHost()->GetView()->GetViewBounds(); std::unique_ptr<SpellingBubbleModel> model( new SpellingBubbleModel(profile, proxy_->GetWebContents())); chrome::ShowConfirmBubble( proxy_->GetWebContents()->GetTopLevelNativeWindow(), - rvh->GetWidget()->GetView()->GetNativeView(), + rfh->GetRenderWidgetHost()->GetView()->GetNativeView(), gfx::Point(rect.CenterPoint().x(), rect.y()), std::move(model)); } else { if (profile) {
diff --git a/chrome/browser/resources/bookmarks/actions.ts b/chrome/browser/resources/bookmarks/actions.ts index 3dbf2c7..232dcc2 100644 --- a/chrome/browser/resources/bookmarks/actions.ts +++ b/chrome/browser/resources/bookmarks/actions.ts
@@ -3,10 +3,10 @@ // found in the LICENSE file. import {assert} from 'chrome://resources/js/assert.js'; -import {Action} from 'chrome://resources/js/store.js'; +import type {Action} from 'chrome://resources/js/store.js'; import {IncognitoAvailability, ROOT_NODE_ID} from './constants.js'; -import {BookmarkNode, BookmarksPageState, NodeMap} from './types.js'; +import type {BookmarkNode, BookmarksPageState, NodeMap} from './types.js'; import {getDescendants, getDisplayedList, normalizeNode} from './util.js'; /**
diff --git a/chrome/browser/resources/bookmarks/api_listener.ts b/chrome/browser/resources/bookmarks/api_listener.ts index 1686a5e..f3e1f92 100644 --- a/chrome/browser/resources/bookmarks/api_listener.ts +++ b/chrome/browser/resources/bookmarks/api_listener.ts
@@ -4,11 +4,11 @@ import {assert} from 'chrome://resources/js/assert.js'; import {addWebUiListener, removeWebUiListener} from 'chrome://resources/js/cr.js'; -import {Action} from 'chrome://resources/js/store.js'; +import type {Action} from 'chrome://resources/js/store.js'; import {createBookmark, editBookmark, moveBookmark, refreshNodes, removeBookmark, reorderChildren, setCanEditBookmarks, setIncognitoAvailability} from './actions.js'; import {BrowserProxyImpl} from './browser_proxy.js'; -import {IncognitoAvailability} from './constants.js'; +import type {IncognitoAvailability} from './constants.js'; import {Debouncer} from './debouncer.js'; import {Store} from './store.js'; import {normalizeNodes} from './util.js';
diff --git a/chrome/browser/resources/bookmarks/app.ts b/chrome/browser/resources/bookmarks/app.ts index 6fde599..84ff615 100644 --- a/chrome/browser/resources/bookmarks/app.ts +++ b/chrome/browser/resources/bookmarks/app.ts
@@ -16,8 +16,9 @@ import './command_manager.js'; import './toolbar.js'; -import {CrSplitterElement} from 'chrome://resources/cr_elements/cr_splitter/cr_splitter.js'; -import {FindShortcutMixin, FindShortcutMixinInterface} from 'chrome://resources/cr_elements/find_shortcut_mixin.js'; +import type {CrSplitterElement} from 'chrome://resources/cr_elements/cr_splitter/cr_splitter.js'; +import type {FindShortcutMixinInterface} from 'chrome://resources/cr_elements/find_shortcut_mixin.js'; +import {FindShortcutMixin} from 'chrome://resources/cr_elements/find_shortcut_mixin.js'; import {EventTracker} from 'chrome://resources/js/event_tracker.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; import {IronScrollTargetBehavior} from 'chrome://resources/polymer/v3_0/iron-scroll-target-behavior/iron-scroll-target-behavior.js'; @@ -29,11 +30,13 @@ import {BookmarksApiProxyImpl} from './bookmarks_api_proxy.js'; import {LOCAL_STORAGE_FOLDER_STATE_KEY, LOCAL_STORAGE_TREE_WIDTH_KEY, ROOT_NODE_ID} from './constants.js'; import {DndManager} from './dnd_manager.js'; -import {MouseFocusMixin, MouseFocusMixinInterface} from './mouse_focus_behavior.js'; +import type {MouseFocusMixinInterface} from './mouse_focus_behavior.js'; +import {MouseFocusMixin} from './mouse_focus_behavior.js'; import {Store} from './store.js'; -import {StoreClientMixin, StoreClientMixinInterface} from './store_client_mixin.js'; -import {BookmarksToolbarElement} from './toolbar.js'; -import {BookmarksPageState, FolderOpenState} from './types.js'; +import type {StoreClientMixinInterface} from './store_client_mixin.js'; +import {StoreClientMixin} from './store_client_mixin.js'; +import type {BookmarksToolbarElement} from './toolbar.js'; +import type {BookmarksPageState, FolderOpenState} from './types.js'; import {createEmptyState, normalizeNodes} from './util.js'; const BookmarksAppElementBase =
diff --git a/chrome/browser/resources/bookmarks/bookmark_manager_api_proxy.ts b/chrome/browser/resources/bookmarks/bookmark_manager_api_proxy.ts index c4bb082..aa4c350c 100644 --- a/chrome/browser/resources/bookmarks/bookmark_manager_api_proxy.ts +++ b/chrome/browser/resources/bookmarks/bookmark_manager_api_proxy.ts
@@ -1,7 +1,7 @@ // Copyright 2023 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import {ChromeEvent} from '/tools/typescript/definitions/chrome_event.js'; +import type {ChromeEvent} from '/tools/typescript/definitions/chrome_event.js'; export interface BookmarkManagerApiProxy { onDragEnter:
diff --git a/chrome/browser/resources/bookmarks/browser_proxy.ts b/chrome/browser/resources/bookmarks/browser_proxy.ts index b03709a..d3027d5 100644 --- a/chrome/browser/resources/bookmarks/browser_proxy.ts +++ b/chrome/browser/resources/bookmarks/browser_proxy.ts
@@ -4,7 +4,7 @@ import {sendWithPromise} from 'chrome://resources/js/cr.js'; -import {IncognitoAvailability} from './constants.js'; +import type {IncognitoAvailability} from './constants.js'; export interface BrowserProxy { getIncognitoAvailability(): Promise<IncognitoAvailability>;
diff --git a/chrome/browser/resources/bookmarks/command_manager.ts b/chrome/browser/resources/bookmarks/command_manager.ts index 3d91270..46e8b719 100644 --- a/chrome/browser/resources/bookmarks/command_manager.ts +++ b/chrome/browser/resources/bookmarks/command_manager.ts
@@ -16,9 +16,9 @@ import './strings.m.js'; import './edit_dialog.js'; -import {CrActionMenuElement} from 'chrome://resources/cr_elements/cr_action_menu/cr_action_menu.js'; -import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js'; -import {CrLazyRenderElement} from 'chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render.js'; +import type {CrActionMenuElement} from 'chrome://resources/cr_elements/cr_action_menu/cr_action_menu.js'; +import type {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js'; +import type {CrLazyRenderElement} from 'chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render.js'; import {getToastManager} from 'chrome://resources/cr_elements/cr_toast/cr_toast_manager.js'; import {assert, assertNotReached} from 'chrome://resources/js/assert.js'; import {EventTracker} from 'chrome://resources/js/event_tracker.js'; @@ -32,13 +32,14 @@ import {deselectItems, selectAll, selectFolder} from './actions.js'; import {highlightUpdatedItems, trackUpdatedItems} from './api_listener.js'; import {BookmarkManagerApiProxyImpl} from './bookmark_manager_api_proxy.js'; -import {BrowserProxy, BrowserProxyImpl} from './browser_proxy.js'; +import type {BrowserProxy} from './browser_proxy.js'; +import {BrowserProxyImpl} from './browser_proxy.js'; import {getTemplate} from './command_manager.html.js'; import {Command, IncognitoAvailability, MenuSource, OPEN_CONFIRMATION_LIMIT, ROOT_NODE_ID} from './constants.js'; import {DialogFocusManager} from './dialog_focus_manager.js'; -import {BookmarksEditDialogElement} from './edit_dialog.js'; +import type {BookmarksEditDialogElement} from './edit_dialog.js'; import {StoreClientMixin} from './store_client_mixin.js'; -import {BookmarkNode, OpenCommandMenuDetail} from './types.js'; +import type {BookmarkNode, OpenCommandMenuDetail} from './types.js'; import {canEditNode, canReorderChildren, getDisplayedList} from './util.js'; const BookmarksCommandManagerElementBase = StoreClientMixin(PolymerElement);
diff --git a/chrome/browser/resources/bookmarks/debouncer.ts b/chrome/browser/resources/bookmarks/debouncer.ts index a483004..8a7357c 100644 --- a/chrome/browser/resources/bookmarks/debouncer.ts +++ b/chrome/browser/resources/bookmarks/debouncer.ts
@@ -5,7 +5,7 @@ import {assert} from 'chrome://resources/js/assert.js'; import {PromiseResolver} from 'chrome://resources/js/promise_resolver.js'; -import {TimerProxy} from './types.js'; +import type {TimerProxy} from './types.js'; /** * @fileoverview A debouncer which fires the given callback after a delay. The
diff --git a/chrome/browser/resources/bookmarks/dialog_focus_manager.ts b/chrome/browser/resources/bookmarks/dialog_focus_manager.ts index 2229508..239bcd3 100644 --- a/chrome/browser/resources/bookmarks/dialog_focus_manager.ts +++ b/chrome/browser/resources/bookmarks/dialog_focus_manager.ts
@@ -4,7 +4,7 @@ import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js'; -import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js'; +import type {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js'; import {assert} from 'chrome://resources/js/assert.js'; /**
diff --git a/chrome/browser/resources/bookmarks/dnd_manager.ts b/chrome/browser/resources/bookmarks/dnd_manager.ts index 2a7db54..0998689 100644 --- a/chrome/browser/resources/bookmarks/dnd_manager.ts +++ b/chrome/browser/resources/bookmarks/dnd_manager.ts
@@ -13,9 +13,9 @@ import {BookmarkManagerApiProxyImpl} from './bookmark_manager_api_proxy.js'; import {DropPosition, ROOT_NODE_ID} from './constants.js'; import {Debouncer} from './debouncer.js'; -import {BookmarksFolderNodeElement} from './folder_node.js'; +import type {BookmarksFolderNodeElement} from './folder_node.js'; import {Store} from './store.js'; -import {BookmarkElement, BookmarkNode, DragData, DropDestination, NodeMap, ObjectMap, TimerProxy} from './types.js'; +import type {BookmarkElement, BookmarkNode, DragData, DropDestination, NodeMap, ObjectMap, TimerProxy} from './types.js'; import {canEditNode, canReorderChildren, getDisplayedList, hasChildFolders, isShowingSearch, normalizeNode} from './util.js'; interface NormalizedDragData {
diff --git a/chrome/browser/resources/bookmarks/edit_dialog.ts b/chrome/browser/resources/bookmarks/edit_dialog.ts index b5de1e0..b8f099d0 100644 --- a/chrome/browser/resources/bookmarks/edit_dialog.ts +++ b/chrome/browser/resources/bookmarks/edit_dialog.ts
@@ -8,8 +8,8 @@ import 'chrome://resources/cr_elements/cr_shared_style.css.js'; import './strings.m.js'; -import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js'; -import {CrInputElement} from 'chrome://resources/cr_elements/cr_input/cr_input.js'; +import type {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js'; +import type {CrInputElement} from 'chrome://resources/cr_elements/cr_input/cr_input.js'; import {assert} from 'chrome://resources/js/assert.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; @@ -18,7 +18,7 @@ import {BookmarksApiProxyImpl} from './bookmarks_api_proxy.js'; import {DialogFocusManager} from './dialog_focus_manager.js'; import {getTemplate} from './edit_dialog.html.js'; -import {BookmarkNode} from './types.js'; +import type {BookmarkNode} from './types.js'; export interface BookmarksEditDialogElement { $: {
diff --git a/chrome/browser/resources/bookmarks/folder_node.ts b/chrome/browser/resources/bookmarks/folder_node.ts index 775ee13..9aa68b8 100644 --- a/chrome/browser/resources/bookmarks/folder_node.ts +++ b/chrome/browser/resources/bookmarks/folder_node.ts
@@ -19,7 +19,7 @@ import {FOLDER_OPEN_BY_DEFAULT_DEPTH, MenuSource, ROOT_NODE_ID} from './constants.js'; import {getTemplate} from './folder_node.html.js'; import {StoreClientMixin} from './store_client_mixin.js'; -import {BookmarkNode} from './types.js'; +import type {BookmarkNode} from './types.js'; import {hasChildFolders, isShowingSearch} from './util.js'; const BookmarksFolderNodeElementBase = StoreClientMixin(PolymerElement);
diff --git a/chrome/browser/resources/bookmarks/item.ts b/chrome/browser/resources/bookmarks/item.ts index 53c57a3..5237ae7 100644 --- a/chrome/browser/resources/bookmarks/item.ts +++ b/chrome/browser/resources/bookmarks/item.ts
@@ -8,12 +8,12 @@ import './shared_style.css.js'; import './strings.m.js'; -import {CrIconButtonElement} from 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js'; +import type {CrIconButtonElement} from 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js'; import {assert} from 'chrome://resources/js/assert.js'; -import {isMac} from 'chrome://resources/js/platform.js'; import {focusWithoutInk} from 'chrome://resources/js/focus_without_ink.js'; import {getFaviconForPageURL} from 'chrome://resources/js/icon.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; +import {isMac} from 'chrome://resources/js/platform.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {selectItem} from './actions.js'; @@ -21,7 +21,7 @@ import {Command, MenuSource} from './constants.js'; import {getTemplate} from './item.html.js'; import {StoreClientMixin} from './store_client_mixin.js'; -import {BookmarkNode} from './types.js'; +import type {BookmarkNode} from './types.js'; const BookmarksItemElementBase = StoreClientMixin(PolymerElement);
diff --git a/chrome/browser/resources/bookmarks/list.ts b/chrome/browser/resources/bookmarks/list.ts index 5778620..59cd78b 100644 --- a/chrome/browser/resources/bookmarks/list.ts +++ b/chrome/browser/resources/bookmarks/list.ts
@@ -16,16 +16,16 @@ import {isMac} from 'chrome://resources/js/platform.js'; import {PluralStringProxyImpl} from 'chrome://resources/js/plural_string_proxy.js'; import {getDeepActiveElement} from 'chrome://resources/js/util.js'; -import {IronListElement} from 'chrome://resources/polymer/v3_0/iron-list/iron-list.js'; +import type {IronListElement} from 'chrome://resources/polymer/v3_0/iron-list/iron-list.js'; import {microTask, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {deselectItems, selectAll, selectItem, updateAnchor} from './actions.js'; import {BookmarksCommandManagerElement} from './command_manager.js'; import {MenuSource} from './constants.js'; -import {BookmarksItemElement} from './item.js'; +import type {BookmarksItemElement} from './item.js'; import {getTemplate} from './list.html.js'; import {StoreClientMixin} from './store_client_mixin.js'; -import {OpenCommandMenuDetail} from './types.js'; +import type {OpenCommandMenuDetail} from './types.js'; import {canReorderChildren, getDisplayedList} from './util.js'; const BookmarksListElementBase =
diff --git a/chrome/browser/resources/bookmarks/mouse_focus_behavior.ts b/chrome/browser/resources/bookmarks/mouse_focus_behavior.ts index c896b6b..d060c809 100644 --- a/chrome/browser/resources/bookmarks/mouse_focus_behavior.ts +++ b/chrome/browser/resources/bookmarks/mouse_focus_behavior.ts
@@ -2,7 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import {dedupingMixin, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import type {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {dedupingMixin} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; export const HIDE_FOCUS_RING_ATTRIBUTE = 'hide-focus-ring';
diff --git a/chrome/browser/resources/bookmarks/reducers.ts b/chrome/browser/resources/bookmarks/reducers.ts index 76b7e97..a39cfe3 100644 --- a/chrome/browser/resources/bookmarks/reducers.ts +++ b/chrome/browser/resources/bookmarks/reducers.ts
@@ -10,10 +10,10 @@ */ import {assert} from 'chrome://resources/js/assert.js'; -import {Action} from 'chrome://resources/js/store.js'; +import type {Action} from 'chrome://resources/js/store.js'; -import {ChangeFolderOpenAction, CreateBookmarkAction, EditBookmarkAction, FinishSearchAction, MoveBookmarkAction, RefreshNodesAction, RemoveBookmarkAction, ReorderChildrenAction, SelectFolderAction, SelectItemsAction, SetPrefAction, StartSearchAction, UpdateAnchorAction} from './actions.js'; -import {BookmarkNode, BookmarksPageState, FolderOpenState, NodeMap, PreferencesState, SearchState, SelectionState} from './types.js'; +import type {ChangeFolderOpenAction, CreateBookmarkAction, EditBookmarkAction, FinishSearchAction, MoveBookmarkAction, RefreshNodesAction, RemoveBookmarkAction, ReorderChildrenAction, SelectFolderAction, SelectItemsAction, SetPrefAction, StartSearchAction, UpdateAnchorAction} from './actions.js'; +import type {BookmarkNode, BookmarksPageState, FolderOpenState, NodeMap, PreferencesState, SearchState, SelectionState} from './types.js'; import {removeIdsFromMap, removeIdsFromObject, removeIdsFromSet} from './util.js'; function selectItems(
diff --git a/chrome/browser/resources/bookmarks/store.ts b/chrome/browser/resources/bookmarks/store.ts index dfb4e7e..310b191 100644 --- a/chrome/browser/resources/bookmarks/store.ts +++ b/chrome/browser/resources/bookmarks/store.ts
@@ -5,7 +5,7 @@ import {Store as CrUiStore} from 'chrome://resources/js/store.js'; import {reduceAction} from './reducers.js'; -import {BookmarksPageState} from './types.js'; +import type {BookmarksPageState} from './types.js'; import {createEmptyState} from './util.js'; /**
diff --git a/chrome/browser/resources/bookmarks/store_client_mixin.ts b/chrome/browser/resources/bookmarks/store_client_mixin.ts index 5f79a55..2706710 100644 --- a/chrome/browser/resources/bookmarks/store_client_mixin.ts +++ b/chrome/browser/resources/bookmarks/store_client_mixin.ts
@@ -2,11 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import {makeStoreClientMixin, StoreClientInterface} from 'chrome://resources/cr_elements/store_client/store_client.js'; -import {Action} from 'chrome://resources/js/store.js'; +import type {StoreClientInterface} from 'chrome://resources/cr_elements/store_client/store_client.js'; +import {makeStoreClientMixin} from 'chrome://resources/cr_elements/store_client/store_client.js'; +import type {Action} from 'chrome://resources/js/store.js'; import {Store} from './store.js'; -import {BookmarksPageState} from './types.js'; +import type {BookmarksPageState} from './types.js'; // A Bookmarks specific specialization of `StoreClientInterface`. export interface StoreClientMixinInterface extends
diff --git a/chrome/browser/resources/bookmarks/toolbar.ts b/chrome/browser/resources/bookmarks/toolbar.ts index d1487cd..580d2d9 100644 --- a/chrome/browser/resources/bookmarks/toolbar.ts +++ b/chrome/browser/resources/bookmarks/toolbar.ts
@@ -10,8 +10,8 @@ import 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar.js'; import 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar_search_field.js'; -import {CrToolbarElement} from 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar.js'; -import {CrToolbarSearchFieldElement} from 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar_search_field.js'; +import type {CrToolbarElement} from 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar.js'; +import type {CrToolbarSearchFieldElement} from 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar_search_field.js'; import {assert} from 'chrome://resources/js/assert.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
diff --git a/chrome/browser/resources/bookmarks/types.ts b/chrome/browser/resources/bookmarks/types.ts index 49273e2a..dc29243 100644 --- a/chrome/browser/resources/bookmarks/types.ts +++ b/chrome/browser/resources/bookmarks/types.ts
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import {DropPosition, IncognitoAvailability, MenuSource} from './constants.js'; +import type {DropPosition, IncognitoAvailability, MenuSource} from './constants.js'; /** * @fileoverview Closure typedefs for Bookmarks.
diff --git a/chrome/browser/resources/bookmarks/util.ts b/chrome/browser/resources/bookmarks/util.ts index 34596e96..047916a 100644 --- a/chrome/browser/resources/bookmarks/util.ts +++ b/chrome/browser/resources/bookmarks/util.ts
@@ -5,7 +5,7 @@ import {assert} from 'chrome://resources/js/assert.js'; import {BOOKMARKS_BAR_ID, IncognitoAvailability, ROOT_NODE_ID} from './constants.js'; -import {BookmarkNode, BookmarksPageState, NodeMap, ObjectMap} from './types.js'; +import type {BookmarkNode, BookmarksPageState, NodeMap, ObjectMap} from './types.js'; /** * @fileoverview Utility functions for the Bookmarks page.
diff --git a/chrome/browser/resources/chromeos/BUILD.gn b/chrome/browser/resources/chromeos/BUILD.gn index 6556447..adb59a3 100644 --- a/chrome/browser/resources/chromeos/BUILD.gn +++ b/chrome/browser/resources/chromeos/BUILD.gn
@@ -99,7 +99,6 @@ "emulator:closure_compile", "gaia_action_buttons:closure_compile", "internet_config_dialog:closure_compile", - "internet_detail_dialog:closure_compile", "login:closure_compile", "multidevice_internals:closure_compile", "multidevice_setup:closure_compile",
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/accessibility_common/BUILD.gn index f743649..44e5b42c 100644 --- a/chrome/browser/resources/chromeos/accessibility/accessibility_common/BUILD.gn +++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/BUILD.gn
@@ -20,10 +20,12 @@ accessibility_common_dir = "$root_out_dir/resources/chromeos/accessibility/accessibility_common" tsc_out_dir = "$target_gen_dir/tsc" -common_tsc_out_dir = "$target_gen_dir/../common/tsc" +common_tsc_out_dir = "$target_gen_dir/../common/tsc/common" +accessibility_common_tsc_out_dir = "$tsc_out_dir/accessibility_common" # TS files to build. ts_modules = [ + "accessibility_common_loader.ts", "autoclick/autoclick.ts", "dictation/context_checker.ts", "dictation/dictation.ts", @@ -50,20 +52,18 @@ "facegaze/camera_stream.ts", ] -# TS files needed from ../common/. -common_ts_modules = [ "instance_checker.ts" ] - # JS files needed by the TS compiler. js_deps = [] -# Root dir must be the parent directory so it can reach common. ts_library("ts_build") { + # Root dir must be the parent directory so it can reach common. root_dir = "../" out_dir = tsc_out_dir definitions = [ "../definitions/accessibility_private_mv2.d.ts", "../definitions/audio.d.ts", "../definitions/automation.d.ts", + "../definitions/command_line_private.d.ts", "../definitions/extensions.d.ts", "../definitions/extension_types.d.ts", "../definitions/input_ime.d.ts", @@ -74,6 +74,8 @@ "../definitions/settings_private_mv2.d.ts", "../definitions/speech_recognition_private.d.ts", "../definitions/tabs.d.ts", + "../definitions/settings_private_mv2.d.ts", + "../definitions/accessibility_features_mv2.d.ts", "//tools/typescript/definitions/i18n.d.ts", "//tools/typescript/definitions/windows.d.ts", ] @@ -103,10 +105,10 @@ dest_dir = accessibility_common_dir deps = [ ":ts_build", + "../common:accessibility_common_copied_files", "../common:ts_build", ] sources = [ - "accessibility_common_loader.js", "background.html", "dictation/earcons/audio_end.wav", "dictation/earcons/audio_initiate.wav", @@ -123,17 +125,13 @@ ] foreach(_ts_file, ts_modules) { - sources += [ "$tsc_out_dir/accessibility_common/" + + sources += [ "$accessibility_common_tsc_out_dir/" + get_path_info(_ts_file, "dir") + "/" + get_path_info(_ts_file, "name") + ".js" ] } - foreach(_ts_file, common_ts_modules) { - sources += [ "$common_tsc_out_dir/" + get_path_info(_ts_file, "dir") + "/" + - get_path_info(_ts_file, "name") + ".js" ] - } rewrite_rules = [ - rebase_path("$tsc_out_dir/accessibility_common", root_build_dir) + ":", + rebase_path(accessibility_common_tsc_out_dir, root_build_dir) + ":", rebase_path(common_tsc_out_dir, root_build_dir) + ":", rebase_path(".", root_build_dir) + ":", rebase_path(closure_library_dir, root_build_dir) + ":closure", @@ -204,6 +202,7 @@ # The test base classes generate C++ code with these deps. deps = [ + ":ts_build", "//ash", "//ash/keyboard/ui", "//base",
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/accessibility_common_loader.js b/chrome/browser/resources/chromeos/accessibility/accessibility_common/accessibility_common_loader.ts similarity index 80% rename from chrome/browser/resources/chromeos/accessibility/accessibility_common/accessibility_common_loader.js rename to chrome/browser/resources/chromeos/accessibility/accessibility_common/accessibility_common_loader.ts index c9a8801..171f469 100644 --- a/chrome/browser/resources/chromeos/accessibility/accessibility_common/accessibility_common_loader.js +++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/accessibility_common_loader.ts
@@ -10,57 +10,55 @@ import {FaceGaze} from './facegaze/facegaze.js'; import {Magnifier} from './magnifier/magnifier.js'; +declare global { + var accessibilityCommon: AccessibilityCommon; +} + /** * Class to manage loading resources depending on which Accessibility features * are enabled. */ export class AccessibilityCommon { + private autoclick_: Autoclick|null = null; + private magnifier_: Magnifier|null = null; + private dictation_: Dictation|null = null; + private faceGaze_: FaceGaze|null = null; + + // For tests. + private autoclickLoadCallbackForTest_: Function|null = null; + // TODO(b:315990318): Migrate these callbacks to Function after + // setOnLoadDesktopCallbackForTest() is migrated to typescript. + private magnifierLoadCallbackForTest_: (() => void)|null = null; + private dictationLoadCallbackForTest_: Function|null = null; + + static readonly FACEGAZE_PREF_NAME = 'settings.a11y.face_gaze.enabled'; + + constructor() { - /** @private {Autoclick} */ - this.autoclick_ = null; - /** @private {Magnifier} */ - this.magnifier_ = null; - /** @private {Dictation} */ - this.dictation_ = null; - /** @private {FaceGaze} */ - this.faceGaze_ = null; - - // For tests. - /** @private {?function()} */ - this.autoclickLoadCallbackForTest_ = null; - /** @private {?function()} */ - this.magnifierLoadCallbackForTest_ = null; - /** @private {?function()} */ - this.dictationLoadCallbackForTest_ = null; - this.init_(); } - static async init() { + static async init(): Promise<void> { await Flags.init(); globalThis.accessibilityCommon = new AccessibilityCommon(); } - /** @return {Autoclick} */ - getAutoclickForTest() { + getAutoclickForTest(): Autoclick|null { return this.autoclick_; } - /** @return {FaceGaze} */ - getFaceGazeForTest() { + getFaceGazeForTest(): FaceGaze|null { return this.faceGaze_; } - /** @return {Magnifier} */ - getMagnifierForTest() { + getMagnifierForTest(): Magnifier|null { return this.magnifier_; } /** * Initializes the AccessibilityCommon extension. - * @private */ - init_() { + private init_(): void { chrome.accessibilityFeatures.autoclick.get( {}, details => this.onAutoclickUpdated_(details)); chrome.accessibilityFeatures.autoclick.onChange.addListener( @@ -114,10 +112,9 @@ /** * Called when the autoclick feature is enabled or disabled. - * @param {*} details - * @private */ - onAutoclickUpdated_(details) { + private onAutoclickUpdated_( + details: chrome.accessibilityFeatures.ChromeSettingsResponse): void { if (details.value && !this.autoclick_) { // Initialize the Autoclick extension. this.autoclick_ = new Autoclick(); @@ -136,10 +133,8 @@ /** * Called when the FaceGaze feature is fetched enabled or disabled. - * @param {*} details - * @private */ - onFaceGazeUpdated_(details) { + private onFaceGazeUpdated_(details: chrome.settingsPrivate.PrefObject): void { if (details.value && !this.faceGaze_) { // Initialize the FaceGaze extension. this.faceGaze_ = new FaceGaze(); @@ -150,11 +145,11 @@ } /** - * @param {!Magnifier.Type} type - * @param {*} details - * @private + * Called when the magnifier feature is fetched enabled or disabled. */ - onMagnifierUpdated_(type, details) { + private onMagnifierUpdated_( + type: Magnifier.Type, + details: chrome.accessibilityFeatures.ChromeSettingsResponse): void { if (details.value && !this.magnifier_) { this.magnifier_ = new Magnifier(type); if (this.magnifierLoadCallbackForTest_) { @@ -171,10 +166,9 @@ /** * Called when the dictation feature is enabled or disabled. - * @param {*} details - * @private */ - onDictationUpdated_(details) { + private onDictationUpdated_( + details: chrome.accessibilityFeatures.ChromeSettingsResponse): void { if (details.value && !this.dictation_) { this.dictation_ = new Dictation(); if (this.dictationLoadCallbackForTest_) { @@ -190,10 +184,8 @@ /** * Used by C++ tests to ensure a feature load is completed. * Set on AccessibilityCommon in case the feature has not started up yet. - * @param {string} feature The feature name. - * @param {!function()} callback Callback for feature JS load complete. */ - setFeatureLoadCallbackForTest(feature, callback) { + setFeatureLoadCallbackForTest(feature: string, callback: () => void): void { if (feature === 'autoclick') { if (!this.autoclick_) { this.autoclickLoadCallbackForTest_ = callback; @@ -219,7 +211,6 @@ } } -AccessibilityCommon.FACEGAZE_PREF_NAME = 'settings.a11y.face_gaze.enabled'; InstanceChecker.closeExtraInstances(); // Initialize the AccessibilityCommon extension.
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/tsconfig.json b/chrome/browser/resources/chromeos/accessibility/accessibility_common/tsconfig.json index 46625dc..047098d7 100644 --- a/chrome/browser/resources/chromeos/accessibility/accessibility_common/tsconfig.json +++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/tsconfig.json
@@ -7,6 +7,11 @@ "include": [ ".", "../common", - "../definitions" + "../definitions", + "../../../../../../tools/typescript/definitions" + ], + "exclude": [ + "../../../../../../tools/typescript/definitions/i18n.d.ts", + "../../../../../../tools/typescript/definitions/accessibility_features.d.ts" ] -} \ No newline at end of file +}
diff --git a/chrome/browser/resources/chromeos/accessibility/common/automation_test_support.js b/chrome/browser/resources/chromeos/accessibility/common/automation_test_support.js index 78fa2b0..0c0a589f 100644 --- a/chrome/browser/resources/chromeos/accessibility/common/automation_test_support.js +++ b/chrome/browser/resources/chromeos/accessibility/common/automation_test_support.js
@@ -115,27 +115,40 @@ } /** - * Finds the automation node with the given `findParams``. Waits + * Finds the automation node with the given `findParams`. Waits * for the node to exist if it does not yet. * @param {chrome.automation.FindParams} findParams * @return {chrome.automation.AutomationNode} * @private */ async findNode_(findParams) { - const node = this.desktop_.find(findParams); - if (node) { - return node; + const nodes = await this.findNumNodes_(findParams, 1); + return nodes[0]; + } + + /** + * Finds at least `minToFind` of the automation nodes matching the given + * `findParams`. + * @param {chrome.automation.FindParams} findParams + * @param {Number} minToFind + * @return {!Array<!chrome.automation.AutomationNode} + * @private + */ + async findNumNodes_(findParams, minToFind) { + const nodes = this.desktop_.findAll(findParams); + if (nodes && nodes.length >= minToFind) { + return nodes; } - // If it wasn't found yet, wait for it to show up. + // If there weren't enough found yet, wait for them to show up. return await new Promise(resolve => { const listener = event => { - const node = this.desktop_.find(findParams); - if (node) { + const nodes = this.desktop_.findAll(findParams); + if (nodes && nodes.length >= minToFind) { this.desktop_.removeEventListener( chrome.automation.EventType.LOAD_COMPLETE, listener, true); this.desktop_.removeEventListener( chrome.automation.EventType.CHILDREN_CHANGED, listener, true); - resolve(node); + resolve(nodes); } }; this.desktop_.addEventListener( @@ -172,17 +185,23 @@ } /** - * @param {chrome.automation.EventType} event - * @private + * Waits for the browser to have `num` tabs with name `name`. */ - async waitForEventHelper_(event) { - const desktop = await new Promise(resolve => { - chrome.automation.getDesktop(d => resolve(d)); - }); - await new Promise(resolve => { - desktop.addEventListener(event, resolve); - }); - this.notifyCcTests_('ready'); + async waitForNumTabsWithName(num, name) { + const findParams = { + role: 'tab', + attributes: {name, className: 'Tab'}, + }; + // This will not return until it finds at least num. + const nodes = await this.findNumNodes_(findParams, num); + if (nodes.length > num) { + // Fail if we've found too many. + console.error( + 'Error: found ' + nodes.length + ' tabs with name ' + name + + ', expected only ' + num); + } else { + this.notifyCcTests_('ready'); + } } /** @param {string} className */ @@ -197,6 +216,30 @@ } /** + * @param {string} className + * @param {string} value + */ + async waitForNodeWithClassNameAndValue(className, value) { + const findParams = {attributes: {className, value}}; + const node = await this.findNode_(findParams); + this.notifyCcTests_('ready'); + } + + /** + * @param {chrome.automation.EventType} event + * @private + */ + async waitForEventHelper_(event) { + const desktop = await new Promise(resolve => { + chrome.automation.getDesktop(d => resolve(d)); + }); + await new Promise(resolve => { + desktop.addEventListener(event, resolve); + }); + this.notifyCcTests_('ready'); + } + + /** * @param {string} The result to send to the C++ tests. * @private */
diff --git a/chrome/browser/resources/chromeos/accessibility/definitions/accessibility_features_mv2.d.ts b/chrome/browser/resources/chromeos/accessibility/definitions/accessibility_features_mv2.d.ts new file mode 100644 index 0000000..c09e1b9 --- /dev/null +++ b/chrome/browser/resources/chromeos/accessibility/definitions/accessibility_features_mv2.d.ts
@@ -0,0 +1,47 @@ +// 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. + +/** @fileoverview Definitions for chrome.accessibilityFeatures API. */ +// TODO(crbug.com/1203307): Auto-generate this file +// from chrome/common/extensions/api/accessibility_features.json. + +// This file exists because MV3 supports promises and MV2 does not. +// TODO(b/260590502): Delete this after MV3 migration. + +import {ChromeEvent} from '../../../../../../tools/typescript/definitions/chrome_event.js'; + +declare global { + export namespace chrome { + export namespace accessibilityFeatures { + + export interface ChromeSettingParams { + name?: string; + } + + export interface ChromeSettingsResponse { + value: boolean; + } + + export interface ChromeSetting { + get(details: ChromeSettingParams, + callback: (details: ChromeSettingsResponse) => void): void; + onChange: ChromeEvent<(details: ChromeSettingsResponse) => void>; + } + + export const autoclick: ChromeSetting; + + export const dictation: ChromeSetting; + + export const spokenFeedback: ChromeSetting; + + export const selectToSpeak: ChromeSetting; + + export const switchAccess: ChromeSetting; + + export const screenMagnifier: ChromeSetting; + + export const dockedMagnifier: ChromeSetting; + } + } +}
diff --git a/chrome/browser/resources/chromeos/emoji_picker/BUILD.gn b/chrome/browser/resources/chromeos/emoji_picker/BUILD.gn index d83711fa..ed7bd9b5 100644 --- a/chrome/browser/resources/chromeos/emoji_picker/BUILD.gn +++ b/chrome/browser/resources/chromeos/emoji_picker/BUILD.gn
@@ -69,16 +69,11 @@ ":copy_fuse", ":copy_fuse_dts", "//ash/webui/common/resources:generate_definitions", + "//chromeos/ash/components/emoji:resources", ] - extra_grdp_deps = [ - ":build_fuse_grdp", - ":generate_json_files", - ] - extra_grdp_files = [ - "$target_gen_dir/fuse_resources.grdp", - "emoji_ordering.grdp", - ] + extra_grdp_deps = [ ":build_fuse_grdp" ] + extra_grdp_files = [ "$target_gen_dir/fuse_resources.grdp" ] optimize = optimize_webui if (optimize) { optimize_webui_host = "emoji-picker" @@ -104,117 +99,3 @@ sources = [ "//third_party/fusejs/dist/fuse.d.ts" ] outputs = [ "$preprocess_folder/fuse.d.ts" ] } - -# Generate json files listed in emoji_ordering.grdp. -group("generate_json_files") { - deps = [ - ":emoji_data", - ":emoji_data_remaining", - ":emoticon_data", - ":symbol_data", - ":symbol_test_data", - ] -} - -action_foreach("emoji_data") { - script = "tools/emoji_data.py" - - metadata_json = [ - "//third_party/emoji-metadata/src/emoji_15_0_ordering.json", - "./emoji_test_ordering.json", - ] - keyword_xmls = [ - # later keywords will override earlier keywords for a particular emoji. - "//third_party/cldr/src/common/annotations/en.xml", - "//third_party/cldr/src/common/annotations/en_001.xml", - "//third_party/cldr/src/common/annotationsDerived/en.xml", - "//third_party/cldr/src/common/annotationsDerived/en_001.xml", - ] - merged_json = "$target_gen_dir/{{source_name_part}}_start.json" - - sources = metadata_json - inputs = keyword_xmls - outputs = [ merged_json ] - args = [ - "--firstgroup", - "True", - "--metadata", - "{{source}}", - "--output", - rebase_path(merged_json, root_build_dir), - "--keywords", - ] + rebase_path(keyword_xmls, root_build_dir) -} - -action_foreach("emoji_data_remaining") { - script = "tools/emoji_data.py" - - metadata_json = [ - "//third_party/emoji-metadata/src/emoji_15_0_ordering.json", - "./emoji_test_ordering.json", - ] - keyword_xmls = [ - # later keywords will override earlier keywords for a particular emoji. - "//third_party/cldr/src/common/annotations/en.xml", - "//third_party/cldr/src/common/annotations/en_001.xml", - "//third_party/cldr/src/common/annotationsDerived/en.xml", - "//third_party/cldr/src/common/annotationsDerived/en_001.xml", - ] - merged_json = "$target_gen_dir/{{source_name_part}}_remaining.json" - - sources = metadata_json - inputs = keyword_xmls - outputs = [ merged_json ] - args = [ - "--firstgroup", - "False", - "--metadata", - "{{source}}", - "--output", - rebase_path(merged_json, root_build_dir), - "--keywords", - ] + rebase_path(keyword_xmls, root_build_dir) -} - -action_foreach("emoticon_data") { - script = "tools/emoticon_data.py" - merged_json = "$target_gen_dir/{{source_name_part}}.json" - - sources = [ - "./emoticon_test_ordering.json", - "//third_party/emoji-metadata/src/emoticon_ordering.json", - ] - - outputs = [ merged_json ] - args = [ - "--metadata", - "{{source}}", - "--output", - rebase_path(merged_json, root_build_dir), - ] -} - -action("symbol_data") { - script = "tools/symbol_data.py" - - outputs = [ "$target_gen_dir/symbol_ordering.json" ] - - deps = [ - ":emoji_data", - ":emoji_data_remaining", - ] - - args = [ - "--output", - rebase_path(outputs[0], root_build_dir), - ] - args += - [ "--filter-data-paths" ] + - rebase_path(get_target_outputs(":emoji_data"), root_build_dir) + - rebase_path(get_target_outputs(":emoji_data_remaining"), root_build_dir) -} - -copy("symbol_test_data") { - sources = [ "./symbol_test_ordering.json" ] - outputs = [ "$target_gen_dir/symbol_test_ordering.json" ] -}
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_ordering.grdp b/chrome/browser/resources/chromeos/emoji_picker/emoji_ordering.grdp deleted file mode 100644 index 0aa2eb1..0000000 --- a/chrome/browser/resources/chromeos/emoji_picker/emoji_ordering.grdp +++ /dev/null
@@ -1,11 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<grit-part> - <include name="IDR_EMOJI_PICKER_EMOJI_15_0_ORDERING_JSON_START" compress="gzip" file="${root_gen_dir}/chrome/browser/resources/chromeos/emoji_picker/emoji_15_0_ordering_start.json" resource_path="emoji_15_0_ordering_start.json" use_base_dir="false" type="chrome_html" /> - <include name="IDR_EMOJI_PICKER_EMOJI_15_0_ORDERING_JSON_REMAINING" compress="gzip" file="${root_gen_dir}/chrome/browser/resources/chromeos/emoji_picker/emoji_15_0_ordering_remaining.json" resource_path="emoji_15_0_ordering_remaining.json" use_base_dir="false" type="chrome_html" /> - <include name="IDR_EMOJI_PICKER_EMOJI_TEST_ORDERING_JSON_START" compress="gzip" file="${root_gen_dir}/chrome/browser/resources/chromeos/emoji_picker/emoji_test_ordering_start.json" resource_path="emoji_test_ordering_start.json" use_base_dir="false" type="chrome_html" /> - <include name="IDR_EMOJI_PICKER_EMOJI_TEST_ORDERING_JSON_REMAINING" compress="gzip" file="${root_gen_dir}/chrome/browser/resources/chromeos/emoji_picker/emoji_test_ordering_remaining.json" resource_path="emoji_test_ordering_remaining.json" use_base_dir="false" type="chrome_html" /> - <include name="IDR_EMOJI_PICKER_EMOTICON_ORDERING_JSON" compress="gzip" file="${root_gen_dir}/chrome/browser/resources/chromeos/emoji_picker/emoticon_ordering.json" resource_path="emoticon_ordering.json" use_base_dir="false" type="chrome_html" /> - <include name="IDR_EMOJI_PICKER_EMOTICON_TEST_ORDERING_JSON" compress="gzip" file="${root_gen_dir}/chrome/browser/resources/chromeos/emoji_picker/emoticon_test_ordering.json" resource_path="emoticon_test_ordering.json" use_base_dir="false" type="chrome_html" /> - <include name="IDR_EMOJI_PICKER_SYMBOL_ORDERING_JSON" compress="gzip" file="${root_gen_dir}/chrome/browser/resources/chromeos/emoji_picker/symbol_ordering.json" resource_path="symbol_ordering.json" use_base_dir="false" type="chrome_html" /> - <include name="IDR_EMOJI_PICKER_SYMBOL_TEST_ORDERING_JSON" compress="gzip" file="${root_gen_dir}/chrome/browser/resources/chromeos/emoji_picker/symbol_test_ordering.json" resource_path="symbol_test_ordering.json" use_base_dir="false" type="chrome_html" /> -</grit-part>
diff --git a/chrome/browser/resources/chromeos/internet_detail_dialog/BUILD.gn b/chrome/browser/resources/chromeos/internet_detail_dialog/BUILD.gn index aeef207f..eebb1b09 100644 --- a/chrome/browser/resources/chromeos/internet_detail_dialog/BUILD.gn +++ b/chrome/browser/resources/chromeos/internet_detail_dialog/BUILD.gn
@@ -3,130 +3,26 @@ # found in the LICENSE file. import("//chrome/common/features.gni") -import("//third_party/closure_compiler/compile_js.gni") -import("//tools/grit/grit_rule.gni") -import("//tools/grit/preprocess_if_expr.gni") -import("//tools/polymer/html_to_js.gni") -import("//ui/webui/resources/tools/generate_grd.gni") -import("//ui/webui/resources/tools/optimize_webui.gni") +import("//ui/webui/resources/tools/build_webui.gni") -preprocess_folder = "preprocessed" -preprocess_manifest = "preprocessed_manifest.json" -preprocess_gen_manifest = "preprocessed_gen_manifest.json" +build_webui("build") { + static_files = [ "internet_detail_dialog_container.html" ] -if (optimize_webui) { - build_manifest = "build_manifest.json" + # Files holding a Polymer element definition AND have an equivalent .html file. + web_component_files = [ "internet_detail_dialog.ts" ] - optimize_webui("build") { - host = "internet-detail-dialog" - js_module_in_files = [ "internet_detail_dialog_container.js" ] - input = rebase_path("$target_gen_dir/$preprocess_folder", root_build_dir) + non_web_component_files = [ "internet_detail_dialog_browser_proxy.ts" ] - out_manifest = "$target_gen_dir/$build_manifest" - excludes = [ - "chrome://resources/mojo/chromeos/services/network_config/public/mojom/cros_network_config.mojom-webui.js", - "chrome://resources/mojo/chromeos/services/network_config/public/mojom/network_types.mojom-webui.js", - "chrome://resources/mojo/services/network/public/mojom/ip_address.mojom-webui.js", - "chrome://resources/ash/common/network/mojo_interface_provider.js", - "chrome://resources/ash/common/hotspot/cros_hotspot_config.mojom-webui.js", - ] + ts_definitions = [ "//tools/typescript/definitions/chrome_send.d.ts" ] - deps = [ - ":preprocess", - ":preprocess_generated", - "//ash/webui/common/resources:css_wrapper_files", - "//ash/webui/common/resources:html_wrapper_files", - "//ash/webui/common/resources:preprocess", - "//ui/webui/resources/cr_components/color_change_listener:build_ts", - "//ui/webui/resources/cr_components/localized_link:build_ts", - "//ui/webui/resources/cr_elements:build_ts", - "//ui/webui/resources/mojo:build_ts", - ] - } -} + ts_deps = [ + "//ash/webui/common/resources:build_ts", + "//third_party/polymer/v3_0:library", + "//ui/webui/resources/cr_components/color_change_listener:build_ts", + "//ui/webui/resources/cr_elements:build_ts", + "//ui/webui/resources/js:build_ts", + "//ui/webui/resources/mojo:build_ts", + ] -generate_grd("build_grd") { - input_files = [ "internet_detail_dialog_container.html" ] - input_files_base_dir = rebase_path(".", "//") - if (optimize_webui) { - deps = [ ":build" ] - resource_path_rewrites = [ "internet_detail_dialog_container.rollup.js|internet_detail_dialog_container.js" ] - manifest_files = [ "$target_gen_dir/$build_manifest" ] - } else { - deps = [ - ":preprocess", - ":preprocess_generated", - ] - manifest_files = [ - "$target_gen_dir/$preprocess_manifest", - "$target_gen_dir/$preprocess_gen_manifest", - ] - } grd_prefix = "internet_detail_dialog" - out_grd = "$target_gen_dir/${grd_prefix}_resources.grd" -} - -preprocess_if_expr("preprocess") { - out_folder = "$target_gen_dir/$preprocess_folder" - out_manifest = "$target_gen_dir/$preprocess_manifest" - in_files = [ - "internet_detail_dialog_browser_proxy.js", - "internet_detail_dialog_container.js", - ] -} - -preprocess_if_expr("preprocess_generated") { - deps = [ ":web_components" ] - in_folder = target_gen_dir - out_folder = "$target_gen_dir/$preprocess_folder" - out_manifest = "$target_gen_dir/$preprocess_gen_manifest" - in_files = [ "internet_detail_dialog.js" ] -} - -js_type_check("closure_compile") { - is_polymer3 = true - closure_flags = default_closure_args + mojom_js_args - deps = [ - ":internet_detail_dialog", - ":internet_detail_dialog_browser_proxy", - ] -} - -js_library("internet_detail_dialog") { - deps = [ - "//ash/webui/common/resources:assert", - "//ash/webui/common/resources:i18n_behavior", - "//ash/webui/common/resources/network:apn_list", - "//ash/webui/common/resources/network:cr_policy_network_behavior_mojo", - "//ash/webui/common/resources/network:network_listener_behavior", - "//ash/webui/common/resources/network:onc_mojo", - "//third_party/polymer/v3_0/components-chromium/iron-collapse:iron-collapse", - ] - externs_list = [ "$externs_path/chrome_send.js" ] -} - -js_library("internet_detail_dialog_browser_proxy") { - deps = [ "//ash/webui/common/resources:cr_deprecated" ] - externs_list = [ "$externs_path/chrome_send.js" ] -} - -html_to_js("web_components") { - js_files = [ "internet_detail_dialog.js" ] -} - -grit("resources") { - defines = chrome_grit_defines - - # These arguments are needed since the grd is generated at build time. - enable_input_discovery_for_gn_analyze = false - source = "$target_gen_dir/internet_detail_dialog_resources.grd" - deps = [ ":build_grd" ] - - outputs = [ - "grit/internet_detail_dialog_resources.h", - "grit/internet_detail_dialog_resources_map.cc", - "grit/internet_detail_dialog_resources_map.h", - "internet_detail_dialog_resources.pak", - ] - output_dir = "$root_gen_dir/chrome" }
diff --git a/chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog.html b/chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog.html index 523c0849..4fba6ec 100644 --- a/chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog.html +++ b/chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog.html
@@ -80,13 +80,13 @@ warning$="[[showRestrictedConnectivity_(managedProperties_)]]"> [[getStateText_(managedProperties_)]] </div> - <cr-button class="signin-button" id="signinButton" on-click="onSigninTap_" + <cr-button class="signin-button" id="signinButton" on-click="onSigninClicked_" hidden$="[[!showSignin_(managedProperties_)]]" disabled="[[disableSignin_(managedProperties_, disabled_)]]"> <div class="signin-icon cr-icon icon-external"></div> $i18n{networkButtonSignin} </cr-button> - <cr-button on-click="onForgetTap_" + <cr-button on-click="onForgetClicked_" hidden$="[[!showForget_(managedProperties_)]]" disabled="[[disabled_]]"> $i18n{networkButtonForget} @@ -201,7 +201,7 @@ <!-- IP Config --> <div class="cr-row"> <network-ip-config class="flex" - editable on-ip-change="onIPConfigChange_" + editable on-ip-change="onIpConfigChange_" managed-properties="[[managedProperties_]]" disabled="[[disabled_]]"> </network-ip-config> @@ -210,7 +210,7 @@ <!-- Nameservers --> <div class="cr-row"> <network-nameservers class="flex" editable - on-nameservers-change="onIPConfigChange_" + on-nameservers-change="onIpConfigChange_" managed-properties="[[managedProperties_]]" disabled="[[disabled_]]"> </network-nameservers>
diff --git a/chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog.js b/chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog.ts similarity index 60% rename from chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog.js rename to chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog.ts index b0168b1..cdbe3bf 100644 --- a/chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog.js +++ b/chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog.ts
@@ -21,21 +21,25 @@ import 'chrome://resources/cr_elements/chromeos/cros_color_overrides.css.js'; import 'chrome://resources/polymer/v3_0/iron-collapse/iron-collapse.js'; import 'chrome://resources/ash/common/network/apn_list.js'; +import 'chrome://resources/cr_elements/policy/cr_policy_indicator_mixin.js'; import './strings.m.js'; -import {assert} from 'chrome://resources/ash/common/assert.js'; -import {I18nBehavior} from 'chrome://resources/ash/common/i18n_behavior.js'; import {loadTimeData} from 'chrome://resources/ash/common/load_time_data.m.js'; +import {ApnList} from 'chrome://resources/ash/common/network/apn_list.js'; import {getApnDisplayName, isActiveSim} from 'chrome://resources/ash/common/network/cellular_utils.js'; -import {CrPolicyNetworkBehaviorMojo} from 'chrome://resources/ash/common/network/cr_policy_network_behavior_mojo.js'; +import {CrPolicyNetworkBehaviorMojo, CrPolicyNetworkBehaviorMojoInterface} from 'chrome://resources/ash/common/network/cr_policy_network_behavior_mojo.js'; import {MojoInterfaceProviderImpl} from 'chrome://resources/ash/common/network/mojo_interface_provider.js'; -import {NetworkListenerBehavior} from 'chrome://resources/ash/common/network/network_listener_behavior.js'; +import {NetworkListenerBehavior, NetworkListenerBehaviorInterface} from 'chrome://resources/ash/common/network/network_listener_behavior.js'; import {OncMojo} from 'chrome://resources/ash/common/network/onc_mojo.js'; import {ColorChangeUpdater} from 'chrome://resources/cr_components/color_change_listener/colors_css_updater.js'; -import {ApnProperties, ConfigProperties, CrosNetworkConfigInterface, GlobalPolicy, IPConfigProperties, ManagedProperties, MAX_NUM_CUSTOM_APNS, NetworkStateProperties, ProxySettings, StartConnectResult} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/cros_network_config.mojom-webui.js'; +import {CrToastElement} from 'chrome://resources/cr_elements/cr_toast/cr_toast.js'; +import {I18nMixin, I18nMixinInterface} from 'chrome://resources/cr_elements/i18n_mixin.js'; +import {assert} from 'chrome://resources/js/assert.js'; +import {ApnProperties, ConfigProperties, CrosNetworkConfigInterface, GlobalPolicy, IPConfigProperties, ManagedProperties, MAX_NUM_CUSTOM_APNS, ProxySettings, StartConnectResult} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/cros_network_config.mojom-webui.js'; import {ConnectionStateType, NetworkType, OncSource, PortalState} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/network_types.mojom-webui.js'; -import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {getTemplate} from './internet_detail_dialog.html.js'; import {InternetDetailDialogBrowserProxy, InternetDetailDialogBrowserProxyImpl} from './internet_detail_dialog_browser_proxy.js'; /** @@ -44,157 +48,164 @@ * internet details and allow configuration of proxy, IP, and nameservers. */ -Polymer({ - is: 'internet-detail-dialog', +const InternetDetailDialogElementBase = + mixinBehaviors( + [NetworkListenerBehavior, CrPolicyNetworkBehaviorMojo], + I18nMixin(PolymerElement)) as { + new (): PolymerElement & I18nMixinInterface & + NetworkListenerBehaviorInterface & + CrPolicyNetworkBehaviorMojoInterface, + }; - _template: html`{__html_template__}`, +export class InternetDetailDialogElement extends + InternetDetailDialogElementBase { + static get is() { + return 'internet-detail-dialog' as const; + } - behaviors: [ - NetworkListenerBehavior, - CrPolicyNetworkBehaviorMojo, - I18nBehavior, - ], + static get template() { + return getTemplate(); + } - properties: { - /** The network GUID to display details for. */ - guid: String, + static get properties() { + return { + /** The network GUID to display details for. */ + guid: String, - /** @private {!ManagedProperties|undefined} */ - managedProperties_: { - type: Object, - observer: 'managedPropertiesChanged_', - }, - - /** @private {?OncMojo.DeviceStateProperties} */ - deviceState_: { - type: Object, - value: null, - }, - - /** - * Whether to show technology badge on mobile network icons. - * @private - */ - showTechnologyBadge_: { - type: Boolean, - value() { - return loadTimeData.valueExists('showTechnologyBadge') && - loadTimeData.getBoolean('showTechnologyBadge'); + managedProperties_: { + type: Object, + observer: 'managedPropertiesChanged_', }, - }, - /** - * Whether network configuration properties sections should be shown. The - * advanced section is not controlled by this property. - * @private - */ - showConfigurableSections_: { - type: Boolean, - value: true, - computed: `computeShowConfigurableSections_(deviceState_.*, - managedProperties_.*)`, - }, - - /** - * When true, all inputs that allow state to be changed (e.g., toggles, - * inputs) are disabled. - */ - disabled_: { - type: Boolean, - value: false, - computed: 'computeDisabled_(deviceState_.*)', - }, - - /** @private {!GlobalPolicy|undefined} */ - globalPolicy_: Object, - - /** @private */ - apnExpanded_: Boolean, - - /** - * Return true if apnRevamp feature flag is enabled. - * @private - */ - isApnRevampEnabled_: { - type: Boolean, - value() { - return loadTimeData.valueExists('apnRevamp') && - loadTimeData.getBoolean('apnRevamp'); + deviceState_: { + type: Object, + value: null, }, - }, - /** - * Return true if Jelly feature flag is enabled. - * @private - */ - isJellyEnabled_: { - type: Boolean, - readOnly: true, - value() { - return loadTimeData.valueExists('isJellyEnabled') && - loadTimeData.getBoolean('isJellyEnabled'); + /** + * Whether to show technology badge on mobile network icons. + */ + showTechnologyBadge_: { + type: Boolean, + value() { + return loadTimeData.valueExists('showTechnologyBadge') && + loadTimeData.getBoolean('showTechnologyBadge'); + }, }, - }, - /** - * Return true if custom APNs limit is reached. - * @private - */ - isNumCustomApnsLimitReached_: { - type: Boolean, - notify: true, - value: false, - computed: 'computeIsNumCustomApnsLimitReached_(managedProperties_)', - }, + /** + * Whether network configuration properties sections should be shown. The + * advanced section is not controlled by this property. + */ + showConfigurableSections_: { + type: Boolean, + value: true, + computed: `computeShowConfigurableSections_(deviceState_.*, + managedProperties_.*)`, + }, - /** - * The message to be displayed in the error toast when shown. - * @private - */ - errorToastMessage_: { - type: String, - value: '', - }, - }, + /** + * When true, all inputs that allow state to be changed (e.g., toggles, + * inputs) are disabled. + */ + disabled_: { + type: Boolean, + value: false, + computed: 'computeDisabled_(deviceState_.*)', + }, - /** - * Set to true once the action button has been focused. - * @private {boolean} - */ - didSetFocus_: false, + globalPolicy_: Object, + apnExpanded_: Boolean, + + /** + * Return true if apnRevamp feature flag is enabled. + */ + isApnRevampEnabled_: { + type: Boolean, + value() { + return loadTimeData.valueExists('apnRevamp') && + loadTimeData.getBoolean('apnRevamp'); + }, + }, + + /** + * Return true if Jelly feature flag is enabled. + */ + isJellyEnabled_: { + type: Boolean, + readOnly: true, + value() { + return loadTimeData.valueExists('isJellyEnabled') && + loadTimeData.getBoolean('isJellyEnabled'); + }, + }, + + /** + * Return true if custom APNs limit is reached. + */ + isNumCustomApnsLimitReached_: { + type: Boolean, + notify: true, + value: false, + computed: 'computeIsNumCustomApnsLimitReached_(managedProperties_)', + }, + + /** + * The message to be displayed in the error toast when shown. + */ + errorToastMessage_: { + type: String, + value: '', + }, + + }; + } + + guid: string; + private managedProperties_: ManagedProperties; + private deviceState_: OncMojo.DeviceStateProperties|null; + private showTechnologyBadge_: boolean; + private showConfigurableSections_: boolean; + private disabled_: boolean; + private globalPolicy_: GlobalPolicy; + private apnExpanded_: boolean; + private isApnRevampEnabled_: boolean; + private isJellyEnabled_: boolean; + private isNumCustomApnsLimitReached_: boolean; + private errorToastMessage_: string; + private didSetFocus_: boolean = false; /** * Set to true to once the initial properties have been received. This * prevents setProperties from being called when setting default properties. - * @private {boolean} */ - propertiesReceived_: false, - - /** @private {?CrosNetworkConfigInterface} */ - networkConfig_: null, - - /** @private {?InternetDetailDialogBrowserProxy} */ - browserProxy_: null, + private propertiesReceived_: boolean = false; + private networkConfig_: CrosNetworkConfigInterface; + private browserProxy_: InternetDetailDialogBrowserProxy; /** @override */ - created() { + constructor() { + super(); + this.networkConfig_ = MojoInterfaceProviderImpl.getInstance().getMojoServiceRemote(); window.CrPolicyStrings = { controlledSettingPolicy: loadTimeData.getString('controlledSettingPolicy'), }; - }, + } - /** @override */ - ready() { + override ready() { + super.ready(); + this.addEventListener('show-error-toast', (event) => { - this.onShowErrorToast_(event); + this.onShowErrorToast_(event as CustomEvent); }); - }, + } - /** @override */ - attached() { + override connectedCallback() { + super.connectedCallback(); + this.browserProxy_ = InternetDetailDialogBrowserProxyImpl.getInstance(); const dialogArgs = this.browserProxy_.getDialogArguments(); if (this.isJellyEnabled_) { @@ -203,7 +214,6 @@ link.href = 'chrome://theme/colors.css?sets=legacy,sys'; document.head.appendChild(link); document.body.classList.add('jelly-enabled'); - /** @suppress {checkTypes} */ (function() { ColorChangeUpdater.forDocument().start(); })(); @@ -237,43 +247,36 @@ // Fetch global policies. this.onPoliciesApplied(/*userhash=*/ ''); - }, + } - /** @private */ - managedPropertiesChanged_() { + private managedPropertiesChanged_() { assert(this.managedProperties_); // Focus the action button once the initial state is set. if (!this.didSetFocus_ && this.showConnectDisconnect_(this.managedProperties_)) { - const button = this.$$('#title .action-button:not([hidden])'); + const button = this.shadowRoot!.querySelector<HTMLElement>( + '#title .action-button:not([hidden])'); if (button) { button.focus(); this.didSetFocus_ = true; } } - }, + } - /** @private */ - close_() { + private close_() { this.browserProxy_.closeDialog(); - }, + } - /** - * CrosNetworkConfigObserver impl - * @param {!string} userhash - */ - onPoliciesApplied(userhash) { + /** CrosNetworkConfigObserver impl */ + override onPoliciesApplied(_userhash: string) { this.networkConfig_.getGlobalPolicy().then(response => { this.globalPolicy_ = response.result; }); - }, + } - /** - * CrosNetworkConfigObserver impl - * @param {!Array<OncMojo.NetworkStateProperties>} networks - */ - onActiveNetworksChanged(networks) { + /** CrosNetworkConfigObserver impl */ + override onActiveNetworksChanged(networks: OncMojo.NetworkStateProperties[]) { if (!this.guid || !this.managedProperties_) { return; } @@ -283,32 +286,28 @@ networks.find(network => network.guid == this.guid)) { this.getNetworkDetails_(); } - }, + } - /** - * CrosNetworkConfigObserver impl - * @param {!NetworkStateProperties} network - */ - onNetworkStateChanged(network) { + /** CrosNetworkConfigObserver impl */ + override onNetworkStateChanged(network: OncMojo.NetworkStateProperties) { if (!this.guid || !this.managedProperties_) { return; } if (network.guid == this.guid) { this.getNetworkDetails_(); } - }, + } /** CrosNetworkConfigObserver impl */ - onDeviceStateListChanged() { + override onDeviceStateListChanged() { if (!this.guid || !this.managedProperties_) { return; } this.getDeviceState_(); this.getNetworkDetails_(); - }, + } - /** @private */ - getNetworkDetails_() { + private getNetworkDetails_() { assert(this.guid); this.networkConfig_.getManagedProperties(this.guid).then(response => { if (!response.result) { @@ -322,10 +321,9 @@ this.getDeviceState_(); } }); - }, + } - /** @private */ - getDeviceState_() { + private getDeviceState_() { if (!this.managedProperties_) { return; } @@ -341,29 +339,18 @@ this.close_(); } }); - }, + } - /** - * @param {!ManagedProperties} managedProperties - * @return {!OncMojo.NetworkStateProperties} - */ - getNetworkState_(managedProperties) { + private getNetworkState_(managedProperties: ManagedProperties): + OncMojo.NetworkStateProperties { return OncMojo.managedPropertiesToNetworkState(managedProperties); - }, + } - /** - * @return {!ConfigProperties} - * @private - */ - getDefaultConfigProperties_() { + private getDefaultConfigProperties_(): ConfigProperties { return OncMojo.getDefaultConfigProperties(this.managedProperties_.type); - }, + } - /** - * @param {!ConfigProperties} config - * @private - */ - setMojoNetworkProperties_(config) { + private setMojoNetworkProperties_(config: ConfigProperties) { if (!this.propertiesReceived_ || !this.guid) { return; } @@ -375,14 +362,9 @@ this.getNetworkDetails_(); } }); - }, + } - /** - * @param {!ManagedProperties} managedProperties - * @return {string} - * @private - */ - getStateText_(managedProperties) { + private getStateText_(managedProperties: ManagedProperties): string { if (!managedProperties) { return ''; } @@ -401,114 +383,78 @@ return this.i18n( OncMojo.getConnectionStateString(managedProperties.connectionState)); - }, + } - /** - * @param {!ManagedProperties} managedProperties - * @return {string} - * @private - */ - getNameText_(managedProperties) { + private getNameText_(managedProperties: ManagedProperties): string { return OncMojo.getNetworkNameUnsafe(managedProperties); - }, + } /** - * @param {!ManagedProperties|undefined} managedProperties - * @return {boolean} True if the network is connected. - * @private + * @return True if the network is connected. */ - isConnectedState_(managedProperties) { + private isConnectedState_(managedProperties: (ManagedProperties|undefined)): + boolean { return !!managedProperties && OncMojo.connectionStateIsConnected(managedProperties.connectionState); - }, + } /** - * @param {!ManagedProperties|undefined} - * managedProperties - * @return {boolean} True if the network is restricted. - * @private + * @return True if the network is restricted. */ - isRestrictedConnectivity_(managedProperties) { + private isRestrictedConnectivity_(managedProperties: (ManagedProperties| + undefined)): boolean { return !!managedProperties && OncMojo.isRestrictedConnectivity(managedProperties.portalState); - }, + } /** - * @param {!ManagedProperties|undefined} - * managedProperties - * @return {boolean} True if the network is connected to have connected color + * @return True if the network is connected to have connected color * for state. - * @private */ - showConnectedState_(managedProperties) { + private showConnectedState_(managedProperties: (ManagedProperties|undefined)): + boolean { return this.isConnectedState_(managedProperties) && !this.isRestrictedConnectivity_(managedProperties); - }, + } /** - * @param {!ManagedProperties|undefined} - * managedProperties - * @return {boolean} True if the network is restricted to have warning color + * @return True if the network is restricted to have warning color * for state. - * @private */ - showRestrictedConnectivity_(managedProperties) { + private showRestrictedConnectivity_(managedProperties: (ManagedProperties| + undefined)): boolean { if (!managedProperties) { return false; } // State must be connected and restricted. return this.isConnectedState_(managedProperties) && this.isRestrictedConnectivity_(managedProperties); - }, + } - /** - * @param {!ManagedProperties} managedProperties - * @return {boolean} - * @private - */ - isRemembered_(managedProperties) { + private isRemembered_(managedProperties: ManagedProperties): boolean { return managedProperties.source != OncSource.kNone; - }, + } - /** - * @param {!ManagedProperties} managedProperties - * @return {boolean} - * @private - */ - isRememberedOrConnected_(managedProperties) { + private isRememberedOrConnected_(managedProperties: ManagedProperties): + boolean { return this.isRemembered_(managedProperties) || this.isConnectedState_(managedProperties); - }, + } - /** - * @param {!ManagedProperties} managedProperties - * @return {boolean} - * @private - */ - shouldShowApnList_(managedProperties) { + private shouldShowApnList_(managedProperties: ManagedProperties): boolean { return !this.isApnRevampEnabled_ && managedProperties.type == NetworkType.kCellular; - }, + } - /** - * @return {boolean} - * @private - */ - shouldShowApnSection_(managedProperties) { + private shouldShowApnSection_(managedProperties: ManagedProperties): boolean { return this.isApnRevampEnabled_ && managedProperties.type === NetworkType.kCellular; - }, + } - /** - * @param {!ManagedProperties|undefined} - * managedProperties - * @param {boolean} apnExpanded - * @return {string} - * @private - */ - getApnRowSublabel_(managedProperties, apnExpanded) { + private getApnRowSublabel_( + managedProperties: ManagedProperties, apnExpanded: boolean): string { if (managedProperties.type !== NetworkType.kCellular || - !managedProperties.typeProperties.cellular.connectedApn) { + !managedProperties.typeProperties.cellular!.connectedApn) { return ''; } // Don't show the connected APN if the section has been expanded. @@ -517,44 +463,29 @@ } return getApnDisplayName( this.i18n.bind(this), - managedProperties.typeProperties.cellular.connectedApn); - }, + managedProperties.typeProperties.cellular!.connectedApn); + } - /** - * @param {!ManagedProperties} managedProperties - * @return {boolean} - * @private - */ - showCellularSim_(managedProperties) { + private showCellularSim_(managedProperties: ManagedProperties): boolean { return managedProperties.type == NetworkType.kCellular && - managedProperties.typeProperties.cellular.family != 'CDMA'; - }, + managedProperties.typeProperties.cellular!.family != 'CDMA'; + } - /** - * @param {!ManagedProperties} managedProperties - * @return {boolean} - * @private - */ - showCellularChooseNetwork_(managedProperties) { + private showCellularChooseNetwork_(managedProperties: ManagedProperties): + boolean { return managedProperties.type == NetworkType.kCellular && - managedProperties.typeProperties.cellular.supportNetworkScan; - }, + managedProperties.typeProperties.cellular!.supportNetworkScan; + } - /** - * @param {!ManagedProperties} managedProperties - * @return {boolean} - * @private - */ - showForget_(managedProperties) { + private showForget_(managedProperties: ManagedProperties): boolean { if (!managedProperties || managedProperties.type != NetworkType.kWiFi) { return false; } return managedProperties.source != OncSource.kNone && !this.isPolicySource(managedProperties.source); - }, + } - /** @private */ - onForgetTap_() { + private onForgetClicked_() { this.networkConfig_.forgetNetwork(this.guid).then(response => { if (!response.success) { console.error('Forget network failed for: ' + this.guid); @@ -562,15 +493,10 @@ // A forgotten network no longer has a valid GUID, close the dialog. this.close_(); }); - }, + } - /** - * @param {!ManagedProperties|undefined} - * managedProperties - * @return {boolean} - * @private - */ - showSignin_(managedProperties) { + private showSignin_(managedProperties: (ManagedProperties|undefined)): + boolean { if (!managedProperties) { return false; } @@ -579,14 +505,9 @@ return true; } return false; - }, + } - /** - * @param {!ManagedProperties} managedProperties - * @return {boolean} - * @private - */ - disableSignin_(managedProperties) { + private disableSignin_(managedProperties: ManagedProperties): boolean { if (this.disabled_ || !managedProperties) { return true; } @@ -595,83 +516,55 @@ return true; } return !this.isPortalState_(managedProperties.portalState); - }, + } - /** @private */ - onSigninTap_() { + private onSigninClicked_() { this.browserProxy_.showPortalSignin(this.guid); - }, + } - /** - * @param {!ManagedProperties} managedProperties - * @return {string} - * @private - */ - getConnectDisconnectText_(managedProperties) { + private getConnectDisconnectText_(managedProperties: ManagedProperties): + string { if (this.showConnect_(managedProperties)) { return this.i18n('networkButtonConnect'); } return this.i18n('networkButtonDisconnect'); - }, + } - /** - * @param {!ManagedProperties|undefined} - * managedProperties - * @return {boolean} - * @private - */ - showConnectDisconnect_(managedProperties) { + private showConnectDisconnect_(managedProperties: (ManagedProperties| + undefined)): boolean { return this.showConnect_(managedProperties) || this.showDisconnect_(managedProperties); - }, + } - /** - * @param {!ManagedProperties|undefined} - * managedProperties - * @return {boolean} - * @private - */ - showConnect_(managedProperties) { + private showConnect_(managedProperties: (ManagedProperties|undefined)): + boolean { if (!managedProperties) { return false; } return managedProperties.connectable && managedProperties.type != NetworkType.kEthernet && managedProperties.connectionState == ConnectionStateType.kNotConnected; - }, + } - /** - * @param {!ManagedProperties|undefined} - * managedProperties - * @return {boolean} - * @private - */ - showDisconnect_(managedProperties) { + private showDisconnect_(managedProperties: (ManagedProperties|undefined)): + boolean { if (!managedProperties) { return false; } return managedProperties.type != NetworkType.kEthernet && managedProperties.connectionState != ConnectionStateType.kNotConnected; - }, + } - /** - * @param {!ManagedProperties} managedProperties - * @return {boolean} - * @private - */ - shouldShowProxyPolicyIndicator_(managedProperties) { + private shouldShowProxyPolicyIndicator_(managedProperties: ManagedProperties): + boolean { if (!managedProperties.proxySettings) { return false; } return this.isNetworkPolicyEnforced(managedProperties.proxySettings.type); - }, + } - /** - * @param {!ManagedProperties} managedProperties - * @return {boolean} - * @private - */ - enableConnectDisconnect_(managedProperties) { + private enableConnectDisconnect_(managedProperties: ManagedProperties): + boolean { if (this.disabled_) { return false; } @@ -684,19 +577,16 @@ } return true; - }, + } /** - * @param {!ManagedProperties} managedProperties - * @return {boolean} Whether or not to enable the network connect button. - * @private + * @return Whether or not to enable the network connect button. */ - enableConnect_(managedProperties) { + private enableConnect_(managedProperties: ManagedProperties): boolean { return this.showConnect_(managedProperties); - }, + } - /** @private */ - onConnectDisconnectClick_() { + private onConnectDisconnectClick_() { if (!this.managedProperties_) { return; } @@ -724,32 +614,29 @@ break; } }); - }, + } - /** - * @param {!CustomEvent<!ApnProperties>} event - * @private - */ - onApnChange_(event) { + private onApnChange_(event: CustomEvent<ApnProperties>) { if (!this.propertiesReceived_) { return; } const config = this.getDefaultConfigProperties_(); const apn = event.detail; - config.typeConfig.cellular = {apn: apn}; + config.typeConfig.cellular = { + apn: apn, + roaming: undefined, + textMessageAllowState: undefined, + }; this.setMojoNetworkProperties_(config); - }, + } /** * Event triggered when the IP Config or NameServers element changes. - * @param {!CustomEvent<!{ - * field: string, - * value: (string|!IPConfigProperties| - * !Array<string>) - * }>} event The network-ip-config or network-nameservers change event. - * @private + * @param event The network-ip-config or network-nameservers change event. */ - onIPConfigChange_(event) { + private onIpConfigChange_( + event: CustomEvent< + {field: string, value: string|IPConfigProperties|string[]}>) { if (!this.managedProperties_) { return; } @@ -758,49 +645,37 @@ if (config) { this.setMojoNetworkProperties_(config); } - }, + } /** * Event triggered when the Proxy configuration element changes. - * @param {!CustomEvent<!ProxySettings>} event - * @private */ - onProxyChange_(event) { + private onProxyChange_(event: CustomEvent<ProxySettings>) { if (!this.propertiesReceived_) { return; } const config = this.getDefaultConfigProperties_(); config.proxySettings = event.detail; this.setMojoNetworkProperties_(config); - }, + } - /** - * @param {!Array<string>} fields - * @return {boolean} - * @private - */ - hasVisibleFields_(fields) { + private hasVisibleFields_(fields: string[]): boolean { return fields.some((field) => { const key = OncMojo.getManagedPropertyKey(field); const value = this.get(key, this.managedProperties_); return value !== undefined && value !== ''; }); - }, + } - /** - * @return {boolean} - * @private - */ - hasInfoFields_() { + private hasInfoFields_(): boolean { return this.hasVisibleFields_(this.getInfoFields_()); - }, + } /** - * @return {!Array<string>} The fields to display in the info section. - * @private + * @return The fields to display in the info section. */ - getInfoFields_() { - /** @type {!Array<string>} */ const fields = []; + private getInfoFields_(): string[] { + const fields: string[] = []; const type = this.managedProperties_.type; if (type == NetworkType.kCellular) { fields.push( @@ -821,13 +696,9 @@ 'cellular.min'); } return fields; - }, + } - /** - * @return {boolean} - * @private - */ - computeShowConfigurableSections_() { + private computeShowConfigurableSections_(): boolean { if (!this.managedProperties_ || !this.deviceState_) { return true; } @@ -840,13 +711,9 @@ OncMojo.managedPropertiesToNetworkState(this.managedProperties_); assert(networkState); return isActiveSim(networkState, this.deviceState_); - }, + } - /** - * @return {boolean} - * @private - */ - computeDisabled_() { + private computeDisabled_(): boolean { if (!this.deviceState_ || this.deviceState_.type !== NetworkType.kCellular) { return false; @@ -854,39 +721,31 @@ // If this is a cellular device and inhibited, state cannot be changed, so // the dialog's inputs should be disabled. return OncMojo.deviceIsInhibited(this.deviceState_); - }, + } /** * Return true if portalState is either kPortal or kProxyAuthRequired. - * @param {!PortalState} portalState - * @return {boolean} - * @private */ - isPortalState_(portalState) { + private isPortalState_(portalState: PortalState): boolean { return portalState === PortalState.kPortal || portalState === PortalState.kProxyAuthRequired; - }, + } /** * Handles UI requests to add new APN. - * @private */ - onCreateCustomApnClicked_() { + private onCreateCustomApnClicked_() { if (this.isNumCustomApnsLimitReached_) { return; } assert(!!this.guid); - const apnList = this.$$('#apnList'); - assert(!!apnList); + const apnList = this.shadowRoot!.querySelector<ApnList>('#apnList'); + assert(apnList); apnList.openApnDetailDialogInCreateMode(); - }, + } - /** - * @return {boolean} - * @private - */ - computeIsNumCustomApnsLimitReached_() { + private computeIsNumCustomApnsLimitReached_(): boolean { if (!this.managedProperties_ || this.managedProperties_.type !== NetworkType.kCellular || !this.managedProperties_.typeProperties || @@ -897,26 +756,30 @@ const customApnList = this.managedProperties_.typeProperties.cellular.customApnList; return !!customApnList && customApnList.length >= MAX_NUM_CUSTOM_APNS; - }, + } - /** - * @param {!Event} event - * @private - */ - onShowErrorToast_(event) { + private onShowErrorToast_(event: CustomEvent<string>) { if (!this.isApnRevampEnabled_) { return; } this.errorToastMessage_ = event.detail; - this.shadowRoot.querySelector('#errorToast').show(); - }, + const errorToast = + this.shadowRoot!.querySelector<CrToastElement>('#errorToast'); + assert(errorToast); + errorToast.show(); + } - /** - * @param {string} macAddress - * @return {boolean} - */ - shouldShowMacAddress_(macAddress) { + private shouldShowMacAddress_(macAddress: string): boolean { return !!macAddress && macAddress.length > 0 && macAddress !== '00:00:00:00:00:00'; - }, -}); + } +} + +declare global { + interface HTMLElementTagNameMap { + [InternetDetailDialogElement.is]: InternetDetailDialogElement; + } +} + +customElements.define( + InternetDetailDialogElement.is, InternetDetailDialogElement);
diff --git a/chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog_browser_proxy.js b/chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog_browser_proxy.js deleted file mode 100644 index b315637..0000000 --- a/chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog_browser_proxy.js +++ /dev/null
@@ -1,62 +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. - - -/** - * @fileoverview A helper object used from the internet detail dialog - * to interact with the browser. - */ - -/** @interface */ -export class InternetDetailDialogBrowserProxy { - /** - * Returns the guid and network type as a JSON string. - * @return {?string} - */ - getDialogArguments() {} - - /** - * Signals C++ that the dialog is closed. - */ - closeDialog() {} - - /** - * Shows the Portal Signin. - * @param {string} guid - */ - showPortalSignin(guid) {} -} - -/** - * @implements {InternetDetailDialogBrowserProxy} - */ -export class InternetDetailDialogBrowserProxyImpl { - /** @override */ - getDialogArguments() { - return chrome.getVariableValue('dialogArguments'); - } - - /** @override */ - showPortalSignin(guid) { - chrome.send('showPortalSignin', [guid]); - } - - /** @override */ - closeDialog() { - chrome.send('dialogClose'); - } - - /** @return {!InternetDetailDialogBrowserProxy} */ - static getInstance() { - return instance || (instance = new InternetDetailDialogBrowserProxyImpl()); - } - - /** @param {!InternetDetailDialogBrowserProxy} obj */ - static setInstance(obj) { - instance = obj; - } -} - -/** @type {?InternetDetailDialogBrowserProxy} */ -let instance = null;
diff --git a/chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog_browser_proxy.ts b/chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog_browser_proxy.ts new file mode 100644 index 0000000..849e00e --- /dev/null +++ b/chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog_browser_proxy.ts
@@ -0,0 +1,51 @@ +// 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 A helper object used from the internet detail dialog + * to interact with the browser. + */ + +export interface InternetDetailDialogBrowserProxy { + /** + * @return The guid and network type as a JSON string. + */ + getDialogArguments(): string; + + /** + * Signals C++ that the dialog is closed. + */ + closeDialog(): void; + + /** + * Shows the Portal Signin. + */ + showPortalSignin(guid: string): void; +} + +export class InternetDetailDialogBrowserProxyImpl implements + InternetDetailDialogBrowserProxy { + getDialogArguments() { + return chrome.getVariableValue('dialogArguments'); + } + + showPortalSignin(guid: string) { + chrome.send('showPortalSignin', [guid]); + } + + closeDialog() { + chrome.send('dialogClose'); + } + + static getInstance(): InternetDetailDialogBrowserProxy { + return instance || (instance = new InternetDetailDialogBrowserProxyImpl()); + } + + static setInstance(obj: InternetDetailDialogBrowserProxy) { + instance = obj; + } +} + +let instance: InternetDetailDialogBrowserProxy|null = null;
diff --git a/chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog_container.html b/chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog_container.html index cf9c63b1..35446005 100644 --- a/chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog_container.html +++ b/chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog_container.html
@@ -40,7 +40,7 @@ <body> <div id="content"> <internet-detail-dialog></internet-detail-dialog> - <script type="module" src="internet_detail_dialog_container.js"></script> + <script type="module" src="internet_detail_dialog.js"></script> </div> </body> </html> \ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog_container.js b/chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog_container.js deleted file mode 100644 index 59deea9..0000000 --- a/chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog_container.js +++ /dev/null
@@ -1,7 +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 './internet_detail_dialog.js'; - -export {InternetDetailDialogBrowserProxyImpl} from './internet_detail_dialog_browser_proxy.js'; \ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/login/components/behaviors/login_screen_behavior.js b/chrome/browser/resources/chromeos/login/components/behaviors/login_screen_behavior.js index f6fbc387..04d97cc 100644 --- a/chrome/browser/resources/chromeos/login/components/behaviors/login_screen_behavior.js +++ b/chrome/browser/resources/chromeos/login/components/behaviors/login_screen_behavior.js
@@ -135,4 +135,9 @@ get EXTERNAL_API() {} /** @return {Object} */ get defaultControl() {} + /** @param {boolean} isInTabletMode */ + setTabletModeState(isInTabletMode) {} + updateLocalizedContent() {} + /** @param {!OobeTypes.OobeConfiguration} configuration */ + updateOobeConfiguration(configuration) {} }
diff --git a/chrome/browser/resources/chromeos/login/login.gni b/chrome/browser/resources/chromeos/login/login.gni index 65e8608..a9cfea16 100644 --- a/chrome/browser/resources/chromeos/login/login.gni +++ b/chrome/browser/resources/chromeos/login/login.gni
@@ -94,7 +94,7 @@ oobe_screens_js_files = [ "screens/oobe/auto_enrollment_check.js", "screens/oobe/consumer_update.js", - "screens/oobe/demo_preferences.js", + "screens/oobe/demo_preferences.ts", "screens/oobe/demo_setup.js", "screens/oobe/enable_debugging.js", "screens/oobe/enterprise_enrollment.js", @@ -108,12 +108,18 @@ oobe_screens_html_files = [] foreach(f, oobe_screens_js_files) { - oobe_screens_html_files += [ string_replace(f, ".js", ".html") ] + # TODO(b/314762334): remove this check once all screens are migrated. + extension = get_path_info(f, "extension") + if (extension == "js") { + oobe_screens_html_files += [ string_replace(f, ".js", ".html") ] + } else { + oobe_screens_html_files += [ string_replace(f, ".ts", ".html") ] + } } oobe_screens_html_wrapped_files = [] -foreach(f, oobe_screens_js_files) { - oobe_screens_html_wrapped_files += [ string_replace(f, ".js", ".html.js") ] +foreach(f, oobe_screens_html_files) { + oobe_screens_html_wrapped_files += [ string_replace(f, ".html", ".html.js") ] } common_screens_js_files = [ @@ -166,6 +172,7 @@ common_screens_html_files = [] foreach(f, common_screens_js_files) { + # TODO(b/314761865): remove this check once all screens are migrated. extension = get_path_info(f, "extension") if (extension == "js") { common_screens_html_files += [ string_replace(f, ".js", ".html") ]
diff --git a/chrome/browser/resources/chromeos/login/screens/oobe/BUILD.gn b/chrome/browser/resources/chromeos/login/screens/oobe/BUILD.gn index 5f9bf05..70b4460e 100644 --- a/chrome/browser/resources/chromeos/login/screens/oobe/BUILD.gn +++ b/chrome/browser/resources/chromeos/login/screens/oobe/BUILD.gn
@@ -19,7 +19,6 @@ deps = [ ":auto_enrollment_check", ":consumer_update", - ":demo_preferences", ":demo_setup", ":enable_debugging", ":enterprise_enrollment", @@ -59,18 +58,6 @@ extra_deps = [ ":web_components" ] } -js_library("demo_preferences") { - sources = [ "$root_gen_dir/chrome/browser/resources/chromeos/login/screens/oobe/demo_preferences.js" ] - deps = [ - "../../components/behaviors:login_screen_behavior", - "../../components/behaviors:oobe_dialog_host_behavior", - "../../components/behaviors:oobe_i18n_behavior", - "../../components/dialogs:oobe_adaptive_dialog", - "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", - ] - extra_deps = [ ":web_components" ] -} - js_library("demo_setup") { sources = [ "$root_gen_dir/chrome/browser/resources/chromeos/login/screens/oobe/demo_setup.js" ] deps = [
diff --git a/chrome/browser/resources/chromeos/login/screens/oobe/demo_preferences.html b/chrome/browser/resources/chromeos/login/screens/oobe/demo_preferences.html index 529e764..77e3549 100644 --- a/chrome/browser/resources/chromeos/login/screens/oobe/demo_preferences.html +++ b/chrome/browser/resources/chromeos/login/screens/oobe/demo_preferences.html
@@ -28,10 +28,10 @@ :host-context(.jelly-enabled) #store-number-input-display-text { color: var(--oobe-subheader-text-color); } - :host([store_number_input_invalid_]) #store-number-input-display-text { + :host([storeNumberInputInvalid]) #store-number-input-display-text { color: var(--cros-textfield-label-color-error); } - :host-context(.jelly-enabled):host([store_number_input_invalid_]) + :host-context(.jelly-enabled):host([storeNumberInputInvalid]) #store-number-input-display-text { color: var(--cros-sys-error); } @@ -72,7 +72,7 @@ <cr-input class="language-selection-title layout horizontal center-justified" slot="input" id="retailerNameInput" - value="{{retailer_name_input_}}" + value="{{retailerNameInput}}" on-keydown="onInputKeyDown_" placeholder= "[[i18nDynamic(locale, 'retailerNameInputPlaceholder')]]" @@ -89,7 +89,7 @@ <cr-input class="language-selection-title layout horizontal center-justified" slot="input" id="storeNumberInput" - value="{{store_number_input_}}" + value="{{storeNumberInput}}" on-keydown="onInputKeyDown_" placeholder= "[[i18nDynamic(locale, 'storeNumberInputPlaceholder')]]" @@ -106,7 +106,7 @@ </div> <div slot="bottom-buttons"> <oobe-text-button id="nextButton" inverse on-click="onNextClicked_" - disabled="[[!user_can_continue_]]" + disabled="[[!userCanContinue]]" text-key="demoPreferencesNextButtonLabel"> </oobe-text-button> </div>
diff --git a/chrome/browser/resources/chromeos/login/screens/oobe/demo_preferences.js b/chrome/browser/resources/chromeos/login/screens/oobe/demo_preferences.js deleted file mode 100644 index 862d1a3..0000000 --- a/chrome/browser/resources/chromeos/login/screens/oobe/demo_preferences.js +++ /dev/null
@@ -1,277 +0,0 @@ -// Copyright 2018 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import '//resources/cr_elements/chromeos/cros_color_overrides.css.js'; -import '//resources/polymer/v3_0/paper-styles/color.js'; -import '//resources/polymer/v3_0/iron-icon/iron-icon.js'; -import '../../components/oobe_icons.html.js'; -import '../../components/oobe_i18n_dropdown.js'; -import '../../components/buttons/oobe_back_button.js'; -import '../../components/buttons/oobe_text_button.js'; -import '../../components/common_styles/oobe_common_styles.css.js'; -import '../../components/common_styles/oobe_dialog_host_styles.css.js'; -import '../../components/dialogs/oobe_adaptive_dialog.js'; - -import {assert} from '//resources/ash/common/assert.js'; -import {I18nBehavior} from '//resources/ash/common/i18n_behavior.js'; -import {loadTimeData} from '//resources/ash/common/load_time_data.m.js'; -import {mixinBehaviors, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; - -import {LoginScreenBehavior, LoginScreenBehaviorInterface} from '../../components/behaviors/login_screen_behavior.js'; -import {OobeDialogHostBehavior} from '../../components/behaviors/oobe_dialog_host_behavior.js'; -import {OobeI18nBehavior, OobeI18nBehaviorInterface} from '../../components/behaviors/oobe_i18n_behavior.js'; -import {OobeTypes} from '../../components/oobe_types.js'; -import {Oobe} from '../../cr_ui.js'; - -import {getTemplate} from './demo_preferences.html.js'; - - -/** - * @constructor - * @extends {PolymerElement} - * @implements {LoginScreenBehaviorInterface} - * @implements {OobeI18nBehaviorInterface} - */ -const DemoPreferencesScreenBase = mixinBehaviors( - [OobeI18nBehavior, OobeDialogHostBehavior, LoginScreenBehavior], - PolymerElement); - -/** - * @polymer - */ -class DemoPreferencesScreen extends DemoPreferencesScreenBase { - static get is() { - return 'demo-preferences-element'; - } - - static get template() { - return getTemplate(); - } - - static get properties() { - return { - /** - * List of languages for language selector dropdown. - * @type {!Array<!OobeTypes.LanguageDsc>} - */ - languages: { - type: Array, - }, - - /** - * List of countries for country selector dropdown. - * @type {!Array<!OobeTypes.DemoCountryDsc>} - */ - countries: { - type: Array, - }, - - /** - * Indicate whether a country has been selected. - * @private {boolean} - */ - is_country_selected_: { - type: Boolean, - value: false, - }, - - /** - * Indicates whether the next button is enabled and the user can continue. - * @private {boolean} - */ - user_can_continue_: { - type: Boolean, - value: false, - reflectToAttribute: true, - computed: `userCanContinue_(retailer_name_input_, - store_number_input_, - is_country_selected_)`, - }, - - retailer_name_input_: { - type: String, - value: '', - }, - - store_number_input_: { - type: String, - value: '', - }, - - /** - * Indicates whether the string entered for store_number_input_ is - * invalid. Note that we have to use a negative boolean here so that we - * can style the helper text based on this value. - * @private {boolean} - */ - store_number_input_invalid_: { - type: Boolean, - value: false, - reflectToAttribute: true, - computed: 'isStoreNumberInputInvalid_(store_number_input_)', - }, - }; - } - - constructor() { - super(); - - /** - * Flag that ensures that OOBE configuration is applied only once. - * @private {boolean} - */ - this.configuration_applied_ = false; - - /** - * Country id of the option if no real country is selected. - * @private {string} - */ - this.country_not_selected_id_ = 'N/A'; - } - - /** @override */ - ready() { - super.ready(); - this.initializeLoginScreen('DemoPreferencesScreen'); - this.updateLocalizedContent(); - } - - /** Overridden from LoginScreenBehavior. */ - // clang-format off - get EXTERNAL_API() { - return []; - } - // clang-format on - - /** Returns a control which should receive an initial focus. */ - get defaultControl() { - return this.$.demoPreferencesDialog; - } - - /** Called when dialog is shown */ - onBeforeShow() { - window.setTimeout(this.applyOobeConfiguration_.bind(this), 0); - } - - /** Called when dialog is shown for the first time */ - applyOobeConfiguration_() { - if (this.configuration_applied_) { - return; - } - const configuration = Oobe.getInstance().getOobeConfiguration(); - if (!configuration) { - return; - } - if (configuration.demoPreferencesNext) { - this.onNextClicked_(); - } - this.configuration_applied_ = true; - } - - /** Called after resources are updated. */ - updateLocalizedContent() { - assert(loadTimeData); - const languageList = /** @type {!Array<OobeTypes.LanguageDsc>} */ ( - loadTimeData.getValue('languageList')); - this.setLanguageList_(languageList); - - const countryList = /** @type {!Array<OobeTypes.DemoCountryDsc>} */ ( - loadTimeData.getValue('demoModeCountryList')); - this.setCountryList_(countryList); - - this.i18nUpdateLocale(); - } - - /** - * Sets language list. - * @param {!Array<!OobeTypes.LanguageDsc>} languages - * @private - */ - setLanguageList_(languages) { - this.languages = languages; - } - - /** - * Sets country list. - * @param {!Array<!OobeTypes.DemoCountryDsc>} countries - * @private - */ - setCountryList_(countries) { - this.countries = countries; - this.$.countryDropdownContainer.hidden = countries.length == 0; - for (let i = 0; i < countries.length; ++i) { - const country = countries[i]; - if (country.selected && country.value !== this.country_not_selected_id_) { - this.is_country_selected_ = true; - return; - } - } - } - - /** - * Determines whether the Next button is enabled and the user may continue. - * Based on the country, retailer name, and store number preferences being - * correctly set. - * - * @private - */ - userCanContinue_( - retailer_name_input_, store_number_input_, is_country_selected_) { - return retailer_name_input_ && - RegExp('^[0-9]+$').test(store_number_input_) && is_country_selected_; - } - - /** - * Validates store number input for styling the input helper text. Note we - * only consider the input invalid if it's nonempty, thus the different - * pattern than in {@link userCanContinue_} - * - * @private - */ - isStoreNumberInputInvalid_(store_number_input_) { - return !RegExp('^[0-9]*$').test(store_number_input_); - } - - /** - * Handle country selection. - * @param {!CustomEvent<!OobeTypes.DemoCountryDsc>} event - * @private - */ - onCountrySelected_(event) { - this.userActed(['set-demo-mode-country', event.detail.value]); - this.is_country_selected_ = - event.detail.value !== this.country_not_selected_id_; - } - - onInputKeyDown_(e) { - if (e.key == 'Enter' && - this.userCanContinue_( - this.retailer_name_input_, this.store_number_input_, - this.is_country_selected_)) { - this.onNextClicked_(); - } - } - - /** - * Back button click handler. - * @private - */ - onBackClicked_() { - this.userActed('close-setup'); - } - - /** - * Next button click handler. - * @private - */ - onNextClicked_() { - this.userActed([ - 'continue-setup', - this.retailer_name_input_, - this.store_number_input_, - ]); - } -} - -customElements.define(DemoPreferencesScreen.is, DemoPreferencesScreen);
diff --git a/chrome/browser/resources/chromeos/login/screens/oobe/demo_preferences.ts b/chrome/browser/resources/chromeos/login/screens/oobe/demo_preferences.ts new file mode 100644 index 0000000..f86b3fb --- /dev/null +++ b/chrome/browser/resources/chromeos/login/screens/oobe/demo_preferences.ts
@@ -0,0 +1,269 @@ +// Copyright 2018 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import '//resources/cr_elements/chromeos/cros_color_overrides.css.js'; +import '//resources/polymer/v3_0/paper-styles/color.js'; +import '//resources/polymer/v3_0/iron-icon/iron-icon.js'; +import '../../components/oobe_icons.html.js'; +import '../../components/oobe_i18n_dropdown.js'; +import '../../components/buttons/oobe_back_button.js'; +import '../../components/buttons/oobe_text_button.js'; +import '../../components/common_styles/oobe_common_styles.css.js'; +import '../../components/common_styles/oobe_dialog_host_styles.css.js'; +import '../../components/dialogs/oobe_adaptive_dialog.js'; + +import {assert} from '//resources/js/assert.js'; +import {loadTimeData} from '//resources/js/load_time_data.js'; +import {PolymerElementProperties} from '//resources/polymer/v3_0/polymer/interfaces.js'; +import {mixinBehaviors, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; + +import {LoginScreenBehavior, LoginScreenBehaviorInterface} from '../../components/behaviors/login_screen_behavior.js'; +import {OobeDialogHostBehavior, OobeDialogHostBehaviorInterface} from '../../components/behaviors/oobe_dialog_host_behavior.js'; +import {OobeI18nBehavior, OobeI18nBehaviorInterface} from '../../components/behaviors/oobe_i18n_behavior.js'; +import type {OobeTypes} from '../../components/oobe_types.js'; +import {Oobe} from '../../cr_ui.js'; + +import {getTemplate} from './demo_preferences.html.js'; + +const DemoPreferencesScreenBase = + mixinBehaviors( + [OobeI18nBehavior, OobeDialogHostBehavior, LoginScreenBehavior], + PolymerElement) as { + new (): PolymerElement & OobeI18nBehaviorInterface & + OobeDialogHostBehaviorInterface & LoginScreenBehaviorInterface, + }; + +export class DemoPreferencesScreen extends DemoPreferencesScreenBase { + static get is() { + return 'demo-preferences-element' as const; + } + + static get template(): HTMLTemplateElement { + return getTemplate(); + } + + static get properties(): PolymerElementProperties { + return { + /** + * List of languages for language selector dropdown. + */ + languages: { + type: Array, + }, + + /** + * List of countries for country selector dropdown. + */ + countries: { + type: Array, + }, + + /** + * Indicate whether a country has been selected. + */ + isCountrySelected: { + type: Boolean, + value: false, + }, + + /** + * Indicates whether the next button is enabled and the user can continue. + */ + userCanContinue: { + type: Boolean, + value: false, + reflectToAttribute: true, + computed: `userCanContinue_(retailerNameInput, + storeNumberInput, + isCountrySelected)`, + }, + + retailerNameInput: { + type: String, + value: '', + }, + + storeNumberInput: { + type: String, + value: '', + }, + + /** + * Indicates whether the string entered for storeNumberInput is + * invalid. Note that we have to use a negative boolean here so that we + * can style the helper text based on this value. + */ + storeNumberInputInvalid: { + type: Boolean, + value: false, + reflectToAttribute: true, + computed: 'isStoreNumberInputInvalid_(storeNumberInput)', + }, + }; + } + + languages: OobeTypes.LanguageDsc[]; + countries: OobeTypes.DemoCountryDsc[]; + private isCountrySelected: boolean; + private userCanContinue: boolean; + retailerNameInput: string; + storeNumberInput: string; + private storeNumberInputInvalid: boolean; + private configurationApplied: boolean; + private countryNotSelectedId: string; + + constructor() { + super(); + + /** + * Flag that ensures that OOBE configuration is applied only once. + */ + this.configurationApplied = false; + + /** + * Country id of the option if no real country is selected. + */ + this.countryNotSelectedId = 'N/A'; + } + + override ready(): void { + super.ready(); + this.initializeLoginScreen('DemoPreferencesScreen'); + this.updateLocalizedContent(); + } + + /** Overridden from LoginScreenBehavior. */ + override get EXTERNAL_API(): string[] { + return []; + } + + /** Returns a control which should receive an initial focus. */ + override get defaultControl(): HTMLElement { + return this.shadowRoot!.getElementById('demoPreferencesDialog')!; + } + + /** Called when dialog is shown */ + override onBeforeShow(): void { + window.setTimeout(this.applyOobeConfiguration_.bind(this), 0); + } + + /** Called when dialog is shown for the first time */ + private applyOobeConfiguration_(): void { + if (this.configurationApplied) { + return; + } + const configuration = Oobe.getInstance().getOobeConfiguration(); + if (!configuration) { + return; + } + if (configuration.demoPreferencesNext) { + this.onNextClicked_(); + } + this.configurationApplied = true; + } + + /** Called after resources are updated. */ + override updateLocalizedContent(): void { + assert(loadTimeData); + const languageList: OobeTypes.LanguageDsc[] = + loadTimeData.getValue('languageList'); + this.setLanguageList_(languageList); + + const countryList: OobeTypes.DemoCountryDsc[] = + loadTimeData.getValue('demoModeCountryList'); + this.setCountryList_(countryList); + + this.i18nUpdateLocale(); + } + + /** + * Sets language list. + */ + private setLanguageList_(languages: OobeTypes.LanguageDsc[]): void { + this.languages = languages; + } + + /** + * Sets country list. + */ + private setCountryList_(countries: OobeTypes.DemoCountryDsc[]): void { + this.countries = countries; + this.shadowRoot!.getElementById('countryDropdownContainer')!.hidden = + countries.length == 0; + for (let i = 0; i < countries.length; ++i) { + const country = countries[i]; + if (country.selected && country.value !== this.countryNotSelectedId) { + this.isCountrySelected = true; + return; + } + } + } + + /** + * Determines whether the Next button is enabled and the user may continue. + * Based on the country, retailer name, and store number preferences being + * correctly set. + * + */ + private userCanContinue_( + retailerNameInput: string, storeNumberInput: string, + isCountrySelected: boolean): boolean { + return !!retailerNameInput && RegExp('^[0-9]+$').test(storeNumberInput) && + isCountrySelected; + } + + /** + * Validates store number input for styling the input helper text. Note we + * only consider the input invalid if it's nonempty, thus the different + * pattern than in {@link userCanContinue_} + * + */ + private isStoreNumberInputInvalid_(storeNumberInput: string): boolean { + return !RegExp('^[0-9]*$').test(storeNumberInput); + } + + /** + * Handle country selection. + */ + private onCountrySelected_(event: CustomEvent<OobeTypes.DemoCountryDsc>): + void { + this.userActed(['set-demo-mode-country', event.detail.value]); + this.isCountrySelected = event.detail.value !== this.countryNotSelectedId; + } + + private onInputKeyDown_(e: KeyboardEvent): void { + if (e.key == 'Enter' && + this.userCanContinue_( + this.retailerNameInput, this.storeNumberInput, + this.isCountrySelected)) { + this.onNextClicked_(); + } + } + + /** + * Back button click handler. + */ + private onBackClicked_(): void { + this.userActed('close-setup'); + } + + /** + * Next button click handler. + */ + private onNextClicked_(): void { + this.userActed([ + 'continue-setup', + this.retailerNameInput, + this.storeNumberInput, + ]); + } +} + +declare global { + interface HTMLElementTagNameMap { + [DemoPreferencesScreen.is]: DemoPreferencesScreen; + } +} + +customElements.define(DemoPreferencesScreen.is, DemoPreferencesScreen);
diff --git a/chrome/browser/resources/downloads/item.ts b/chrome/browser/resources/downloads/item.ts index 95da9a4..439a5818 100644 --- a/chrome/browser/resources/downloads/item.ts +++ b/chrome/browser/resources/downloads/item.ts
@@ -931,15 +931,29 @@ } private onSaveDangerousClick_() { - if (this.improvedDownloadWarningsUx_) { - this.getMoreActionsMenu().close(); - // TODO(crbug.com/1465966): Suspicious downloads should validate directly. - if (this.displayType_ === DisplayType.DANGEROUS) { - this.notifySaveDangerousClick_(); - return; - } + if (!this.improvedDownloadWarningsUx_) { + // TODO(chlily): Clean up old paths that show the DownloadDangerPrompt. + assert(!!this.mojoHandler_); + this.mojoHandler_.saveDangerousRequiringGesture(this.data.id); + return; } - this.mojoHandler_!.saveDangerousRequiringGesture(this.data.id); + + this.getMoreActionsMenu().close(); + + if (this.displayType_ === DisplayType.DANGEROUS) { + this.notifySaveDangerousClick_(); + return; + } + + // "Suspicious" types which show up in grey can be validated directly. + const SAVED_FROM_PAGE_TYPES = [ + DisplayType.SUSPICIOUS, + DisplayType.UNVERIFIED, + DisplayType.INSECURE, + ]; + assert(SAVED_FROM_PAGE_TYPES.includes(this.displayType_)); + assert(!!this.mojoHandler_); + this.mojoHandler_.saveSuspiciousRequiringGesture(this.data.id); } private onShowClick_() {
diff --git a/chrome/browser/resources/settings/autofill_page/address_edit_dialog.ts b/chrome/browser/resources/settings/autofill_page/address_edit_dialog.ts index 93cb448..c073ef6 100644 --- a/chrome/browser/resources/settings/autofill_page/address_edit_dialog.ts +++ b/chrome/browser/resources/settings/autofill_page/address_edit_dialog.ts
@@ -45,7 +45,7 @@ type AccountInfo = chrome.autofillPrivate.AccountInfo; type AddressComponents = chrome.autofillPrivate.AddressComponents; const AddressSource = chrome.autofillPrivate.AddressSource; -const ServerFieldType = chrome.autofillPrivate.ServerFieldType; +const FieldType = chrome.autofillPrivate.FieldType; const SettingsAddressEditDialogElementBase = I18nMixin(PolymerElement); export class SettingsAddressEditDialogElement extends @@ -116,9 +116,9 @@ private validationError_?: string; private countries_: CountryEntry[]; private addressFields_: - Map<chrome.autofillPrivate.ServerFieldType, string|undefined> = new Map(); + Map<chrome.autofillPrivate.FieldType, string|undefined> = new Map(); private originalAddressFields_?: - Map<chrome.autofillPrivate.ServerFieldType, string|undefined>; + Map<chrome.autofillPrivate.FieldType, string|undefined>; private countryCode_: string|undefined; private components_: uiComponents.AddressComponentUi[][] = []; private canSave_: boolean; @@ -154,17 +154,17 @@ microTask.run(() => { const countryField = - this.addressFields_.get(ServerFieldType.ADDRESS_HOME_COUNTRY); + this.addressFields_.get(FieldType.ADDRESS_HOME_COUNTRY); if (!countryField) { assert(countryList.length > 0); // If the address is completely empty, the dialog is creating a new // address. The first address in the country list is what we suspect // the user's country is. this.addressFields_.set( - ServerFieldType.ADDRESS_HOME_COUNTRY, countryList[0].countryCode); + FieldType.ADDRESS_HOME_COUNTRY, countryList[0].countryCode); } this.countryCode_ = - this.addressFields_.get(ServerFieldType.ADDRESS_HOME_COUNTRY); + this.addressFields_.get(FieldType.ADDRESS_HOME_COUNTRY); }); }); @@ -193,12 +193,11 @@ this.components_ = []; for (const row of format.components) { // If this is the name field, add a honorific title row before it. - if (row.row[0].field === ServerFieldType.NAME_FULL && - this.showHonorific_) { + if (row.row[0].field === FieldType.NAME_FULL && this.showHonorific_) { this.components_.push([new uiComponents.AddressComponentUi( this.addressFields_, this.originalAddressFields_, - ServerFieldType.NAME_HONORIFIC_PREFIX, - this.i18n('honorificLabel'), 'long')]); + FieldType.NAME_HONORIFIC_PREFIX, this.i18n('honorificLabel'), + 'long')]); } this.components_.push(row.row.map( @@ -206,7 +205,7 @@ this.addressFields_, this.originalAddressFields_, component.field, component.fieldName, component.isLongField ? 'long' : '', - component.field === ServerFieldType.ADDRESS_HOME_STREET_ADDRESS, + component.field === FieldType.ADDRESS_HOME_STREET_ADDRESS, skipValidation, component.isRequired))); } @@ -215,11 +214,11 @@ this.components_.push([ new uiComponents.AddressComponentUi( this.addressFields_, this.originalAddressFields_, - ServerFieldType.PHONE_HOME_WHOLE_NUMBER, this.i18n('addressPhone'), + FieldType.PHONE_HOME_WHOLE_NUMBER, this.i18n('addressPhone'), 'last-row'), new uiComponents.AddressComponentUi( this.addressFields_, this.originalAddressFields_, - ServerFieldType.EMAIL_ADDRESS, this.i18n('addressEmail'), + FieldType.EMAIL_ADDRESS, this.i18n('addressEmail'), 'long last-row'), ]); @@ -406,7 +405,7 @@ */ private onCountryCodeSelectChange_(): void { this.addressFields_.set( - ServerFieldType.ADDRESS_HOME_COUNTRY, this.$.country.value); + FieldType.ADDRESS_HOME_COUNTRY, this.$.country.value); this.countryCode_ = this.$.country.value; } }
diff --git a/chrome/browser/resources/settings/autofill_page/address_edit_dialog_components.ts b/chrome/browser/resources/settings/autofill_page/address_edit_dialog_components.ts index 934bc4c..3eb1427 100644 --- a/chrome/browser/resources/settings/autofill_page/address_edit_dialog_components.ts +++ b/chrome/browser/resources/settings/autofill_page/address_edit_dialog_components.ts
@@ -11,12 +11,12 @@ * property, which is how interface controls (e.g. input) communicate with it. */ export class AddressComponentUi { - private readonly fieldType_: chrome.autofillPrivate.ServerFieldType; + private readonly fieldType_: chrome.autofillPrivate.FieldType; private readonly originalValue_?: string; private readonly existingAddress_: boolean; private readonly skipValidation_: boolean; private addressFields_: - Map<chrome.autofillPrivate.ServerFieldType, string|undefined>; + Map<chrome.autofillPrivate.FieldType, string|undefined>; private isValidatable_: boolean; readonly isTextarea: boolean; readonly isRequired: boolean; @@ -24,12 +24,10 @@ readonly additionalClassName: string; constructor( - addressFields: - Map<chrome.autofillPrivate.ServerFieldType, string|undefined>, - originalFields: - Map<chrome.autofillPrivate.ServerFieldType, string|undefined>| + addressFields: Map<chrome.autofillPrivate.FieldType, string|undefined>, + originalFields: Map<chrome.autofillPrivate.FieldType, string|undefined>| undefined, - fieldType: chrome.autofillPrivate.ServerFieldType, + fieldType: chrome.autofillPrivate.FieldType, label: string, additionalClassName: string = '', isTextarea: boolean = false, @@ -96,7 +94,7 @@ return !isValueEmpty(this.value); } - get fieldType(): chrome.autofillPrivate.ServerFieldType { + get fieldType(): chrome.autofillPrivate.FieldType { return this.fieldType_; }
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.ts b/chrome/browser/resources/settings/privacy_page/privacy_page.ts index 6b201f1..eb41ce6d 100644 --- a/chrome/browser/resources/settings/privacy_page/privacy_page.ts +++ b/chrome/browser/resources/settings/privacy_page/privacy_page.ts
@@ -431,7 +431,8 @@ private onTrackingProtectionClick_() { this.interactedWithPage_(); - + this.metricsBrowserProxy_.recordAction( + 'Settings.TrackingProtection.OpenedFromPrivacyPage'); Router.getInstance().navigateTo(routes.TRACKING_PROTECTION); }
diff --git a/chrome/browser/resources/side_panel/bookmarks/commerce/shopping_list.ts b/chrome/browser/resources/side_panel/bookmarks/commerce/shopping_list.ts index 0dc98fec..7a7b458 100644 --- a/chrome/browser/resources/side_panel/bookmarks/commerce/shopping_list.ts +++ b/chrome/browser/resources/side_panel/bookmarks/commerce/shopping_list.ts
@@ -9,7 +9,7 @@ import 'chrome://resources/cr_elements/cr_toast/cr_toast.js'; import './icons.html.js'; -import {ShoppingListApiProxy, ShoppingListApiProxyImpl} from '//bookmarks-side-panel.top-chrome/shared/commerce/shopping_list_api_proxy.js'; +import {ShoppingServiceApiProxy, ShoppingServiceApiProxyImpl} from '//bookmarks-side-panel.top-chrome/shared/commerce/shopping_service_api_proxy.js'; import {BookmarkProductInfo} from '//bookmarks-side-panel.top-chrome/shared/shopping_list.mojom-webui.js'; import {CrToastElement} from 'chrome://resources/cr_elements/cr_toast/cr_toast.js'; import {getFaviconForPageURL} from 'chrome://resources/js/icon.js'; @@ -67,15 +67,15 @@ private open_: boolean; private bookmarksApi_: BookmarksApiProxy = BookmarksApiProxyImpl.getInstance(); - private shoppingListApi_: ShoppingListApiProxy = - ShoppingListApiProxyImpl.getInstance(); + private shoppingServiceApi_: ShoppingServiceApiProxy = + ShoppingServiceApiProxyImpl.getInstance(); private listenerIds_: number[] = []; private retryOperationCallback_: () => void; override connectedCallback() { super.connectedCallback(); - const callbackRouter = this.shoppingListApi_.getCallbackRouter(); + const callbackRouter = this.shoppingServiceApi_.getCallbackRouter(); this.listenerIds_.push( callbackRouter.priceTrackedForBookmark.addListener( (product: BookmarkProductInfo) => @@ -100,7 +100,7 @@ super.disconnectedCallback(); this.listenerIds_.forEach( - id => this.shoppingListApi_.getCallbackRouter().removeListener(id)); + id => this.shoppingServiceApi_.getCallbackRouter().removeListener(id)); } private getFaviconUrl_(url: string): string { @@ -178,12 +178,12 @@ if (this.untrackedItems_.includes(event.model.item)) { const index = this.untrackedItems_.indexOf(event.model.item); this.splice('untrackedItems_', index, 1); - this.shoppingListApi_.trackPriceForBookmark(bookmarkId); + this.shoppingServiceApi_.trackPriceForBookmark(bookmarkId); chrome.metricsPrivate.recordUserAction( 'Commerce.PriceTracking.SidePanel.Track.BellButton'); } else { this.push('untrackedItems_', event.model.item); - this.shoppingListApi_.untrackPriceForBookmark(bookmarkId); + this.shoppingServiceApi_.untrackPriceForBookmark(bookmarkId); chrome.metricsPrivate.recordUserAction( 'Commerce.PriceTracking.SidePanel.Untrack.BellButton'); } @@ -259,9 +259,9 @@ product: BookmarkProductInfo, attemptedTrack: boolean) { this.retryOperationCallback_ = () => { if (attemptedTrack) { - this.shoppingListApi_.trackPriceForBookmark(product.bookmarkId); + this.shoppingServiceApi_.trackPriceForBookmark(product.bookmarkId); } else { - this.shoppingListApi_.untrackPriceForBookmark(product.bookmarkId); + this.shoppingServiceApi_.untrackPriceForBookmark(product.bookmarkId); } }; this.$.errorToast.show();
diff --git a/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_context_menu.ts b/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_context_menu.ts index 0ecd01b..ffbd735 100644 --- a/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_context_menu.ts +++ b/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_context_menu.ts
@@ -9,7 +9,7 @@ import '//resources/cr_elements/cr_icon_button/cr_icon_button.js'; import '//resources/cr_elements/icons.html.js'; -import {ShoppingListApiProxy, ShoppingListApiProxyImpl} from '//bookmarks-side-panel.top-chrome/shared/commerce/shopping_list_api_proxy.js'; +import {ShoppingServiceApiProxy, ShoppingServiceApiProxyImpl} from '//bookmarks-side-panel.top-chrome/shared/commerce/shopping_service_api_proxy.js'; import {CrActionMenuElement} from '//resources/cr_elements/cr_action_menu/cr_action_menu.js'; import {assert} from 'chrome://resources/js/assert.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; @@ -63,8 +63,8 @@ private bookmarksApi_: BookmarksApiProxy = BookmarksApiProxyImpl.getInstance(); - private shoppingListApi_: ShoppingListApiProxy = - ShoppingListApiProxyImpl.getInstance(); + private shoppingServiceApi_: ShoppingServiceApiProxy = + ShoppingServiceApiProxyImpl.getInstance(); private bookmarks_: chrome.bookmarks.BookmarkTreeNode[] = []; private priceTracked_: boolean; private priceTrackingEligible_: boolean; @@ -316,12 +316,12 @@ this.dispatchDisabledFeatureEvent_(); } else { if (this.priceTracked_) { - this.shoppingListApi_.untrackPriceForBookmark( + this.shoppingServiceApi_.untrackPriceForBookmark( BigInt(this.bookmarks_[0]!.id)); chrome.metricsPrivate.recordUserAction( 'Commerce.PriceTracking.SidePanel.Untrack.ContextMenu'); } else { - this.shoppingListApi_.trackPriceForBookmark( + this.shoppingServiceApi_.trackPriceForBookmark( BigInt(this.bookmarks_[0]!.id)); chrome.metricsPrivate.recordUserAction( 'Commerce.PriceTracking.SidePanel.Track.ContextMenu');
diff --git a/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_list.ts b/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_list.ts index 897919f0..e5c4ee2 100644 --- a/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_list.ts +++ b/chrome/browser/resources/side_panel/bookmarks/power_bookmarks_list.ts
@@ -27,7 +27,7 @@ import '//resources/cr_elements/icons.html.js'; import '//resources/polymer/v3_0/iron-list/iron-list.js'; -import {ShoppingListApiProxy, ShoppingListApiProxyImpl} from '//bookmarks-side-panel.top-chrome/shared/commerce/shopping_list_api_proxy.js'; +import {ShoppingServiceApiProxy, ShoppingServiceApiProxyImpl} from '//bookmarks-side-panel.top-chrome/shared/commerce/shopping_service_api_proxy.js'; import {BookmarkProductInfo} from '//bookmarks-side-panel.top-chrome/shared/shopping_list.mojom-webui.js'; import {SpEmptyStateElement} from '//bookmarks-side-panel.top-chrome/shared/sp_empty_state.js'; import {ColorChangeUpdater} from '//resources/cr_components/color_change_listener/colors_css_updater.js'; @@ -250,8 +250,8 @@ private bookmarksApi_: BookmarksApiProxy = BookmarksApiProxyImpl.getInstance(); - private shoppingListApi_: ShoppingListApiProxy = - ShoppingListApiProxyImpl.getInstance(); + private shoppingServiceApi_: ShoppingServiceApiProxy = + ShoppingServiceApiProxyImpl.getInstance(); private shoppingListenerIds_: number[] = []; private displayLists_: chrome.bookmarks.BookmarkTreeNode[][]; private trackedProductInfos_ = new Map<string, BookmarkProductInfo>(); @@ -297,18 +297,18 @@ }); this.focusOutlineManager_ = FocusOutlineManager.forDocument(document); this.bookmarksService_.startListening(); - this.shoppingListApi_.getAllPriceTrackedBookmarkProductInfo().then(res => { + this.shoppingServiceApi_.getAllPriceTrackedBookmarkProductInfo().then(res => { res.productInfos.forEach( product => this.set( `trackedProductInfos_.${product.bookmarkId.toString()}`, product)); }); - this.shoppingListApi_.getAllShoppingBookmarkProductInfo().then(res => { + this.shoppingServiceApi_.getAllShoppingBookmarkProductInfo().then(res => { res.productInfos.forEach( product => this.setAvailableProductInfo_(product)); }); this.updateShoppingCollectionFolderId_(); - const callbackRouter = this.shoppingListApi_.getCallbackRouter(); + const callbackRouter = this.shoppingServiceApi_.getCallbackRouter(); this.shoppingListenerIds_.push( callbackRouter.priceTrackedForBookmark.addListener( (product: BookmarkProductInfo) => @@ -333,7 +333,7 @@ override disconnectedCallback() { this.bookmarksService_.stopListening(); this.shoppingListenerIds_.forEach( - id => this.shoppingListApi_.getCallbackRouter().removeListener(id)); + id => this.shoppingServiceApi_.getCallbackRouter().removeListener(id)); if (this.shownBookmarksResizeObserver_) { this.shownBookmarksResizeObserver_.disconnect(); @@ -706,7 +706,7 @@ } private updateShoppingCollectionFolderId_(): void { - this.shoppingListApi_.getShoppingCollectionBookmarkFolderId().then(res => { + this.shoppingServiceApi_.getShoppingCollectionBookmarkFolderId().then(res => { this.shoppingCollectionFolderId_ = res.collectionId.toString(); }); } @@ -767,7 +767,7 @@ private updateShoppingData_() { this.availableProductInfos_.clear(); - this.shoppingListApi_.getAllShoppingBookmarkProductInfo().then(res => { + this.shoppingServiceApi_.getAllShoppingBookmarkProductInfo().then(res => { res.productInfos.forEach( product => this.setAvailableProductInfo_(product)); });
diff --git a/chrome/browser/resources/side_panel/commerce/app.ts b/chrome/browser/resources/side_panel/commerce/app.ts index 1c8a786..e10cf76 100644 --- a/chrome/browser/resources/side_panel/commerce/app.ts +++ b/chrome/browser/resources/side_panel/commerce/app.ts
@@ -17,7 +17,7 @@ import {loadTimeData} from '//resources/js/load_time_data.js'; import {listenOnce} from '//resources/js/util.js'; import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -import {ShoppingListApiProxy, ShoppingListApiProxyImpl} from '//shopping-insights-side-panel.top-chrome/shared/commerce/shopping_list_api_proxy.js'; +import {ShoppingServiceApiProxy, ShoppingServiceApiProxyImpl} from '//shopping-insights-side-panel.top-chrome/shared/commerce/shopping_service_api_proxy.js'; import {PriceInsightsInfo, ProductInfo} from '//shopping-insights-side-panel.top-chrome/shared/shopping_list.mojom-webui.js'; import {getTemplate} from './app.html.js'; @@ -51,8 +51,8 @@ productInfo: ProductInfo; priceInsightsInfo: PriceInsightsInfo; private isProductTrackable_: boolean; - private shoppingApi_: ShoppingListApiProxy = - ShoppingListApiProxyImpl.getInstance(); + private shoppingApi_: ShoppingServiceApiProxy = + ShoppingServiceApiProxyImpl.getInstance(); constructor() { super();
diff --git a/chrome/browser/resources/side_panel/commerce/catalog_attributes_row.ts b/chrome/browser/resources/side_panel/commerce/catalog_attributes_row.ts index f6a7568..b0f1857 100644 --- a/chrome/browser/resources/side_panel/commerce/catalog_attributes_row.ts +++ b/chrome/browser/resources/side_panel/commerce/catalog_attributes_row.ts
@@ -9,7 +9,7 @@ import '//resources/polymer/v3_0/iron-icon/iron-icon.js'; import '../strings.m.js'; -import {ShoppingListApiProxy, ShoppingListApiProxyImpl} from '//shopping-insights-side-panel.top-chrome/shared/commerce/shopping_list_api_proxy.js'; +import {ShoppingServiceApiProxy, ShoppingServiceApiProxyImpl} from '//shopping-insights-side-panel.top-chrome/shared/commerce/shopping_service_api_proxy.js'; import {PriceInsightsInfo, PriceInsightsInfo_PriceBucket} from '//shopping-insights-side-panel.top-chrome/shared/shopping_list.mojom-webui.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; @@ -31,8 +31,8 @@ } priceInsightsInfo: PriceInsightsInfo; - private shoppingApi_: ShoppingListApiProxy = - ShoppingListApiProxyImpl.getInstance(); + private shoppingApi_: ShoppingServiceApiProxy = + ShoppingServiceApiProxyImpl.getInstance(); private openJackpot_() { this.shoppingApi_.openUrlInNewTab(this.priceInsightsInfo.jackpot);
diff --git a/chrome/browser/resources/side_panel/commerce/insights_comment_row.ts b/chrome/browser/resources/side_panel/commerce/insights_comment_row.ts index a5680f52..524b7a2 100644 --- a/chrome/browser/resources/side_panel/commerce/insights_comment_row.ts +++ b/chrome/browser/resources/side_panel/commerce/insights_comment_row.ts
@@ -5,7 +5,7 @@ import '../strings.m.js'; import 'chrome://resources/cr_elements/cr_shared_vars.css.js'; -import {ShoppingListApiProxy, ShoppingListApiProxyImpl} from '//shopping-insights-side-panel.top-chrome/shared/commerce/shopping_list_api_proxy.js'; +import {ShoppingServiceApiProxy, ShoppingServiceApiProxyImpl} from '//shopping-insights-side-panel.top-chrome/shared/commerce/shopping_service_api_proxy.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; @@ -29,8 +29,8 @@ }; } - private shoppingApi_: ShoppingListApiProxy = - ShoppingListApiProxyImpl.getInstance(); + private shoppingApi_: ShoppingServiceApiProxy = + ShoppingServiceApiProxyImpl.getInstance(); private showFeedback_() { this.shoppingApi_.showFeedback();
diff --git a/chrome/browser/resources/side_panel/commerce/price_tracking_section.ts b/chrome/browser/resources/side_panel/commerce/price_tracking_section.ts index a46a3cd..1a01b7db 100644 --- a/chrome/browser/resources/side_panel/commerce/price_tracking_section.ts +++ b/chrome/browser/resources/side_panel/commerce/price_tracking_section.ts
@@ -6,7 +6,7 @@ import '../strings.m.js'; import 'chrome://resources/cr_elements/cr_toggle/cr_toggle.js'; -import {ShoppingListApiProxy, ShoppingListApiProxyImpl} from '//shopping-insights-side-panel.top-chrome/shared/commerce/shopping_list_api_proxy.js'; +import {ShoppingServiceApiProxy, ShoppingServiceApiProxyImpl} from '//shopping-insights-side-panel.top-chrome/shared/commerce/shopping_service_api_proxy.js'; import {BookmarkProductInfo, PriceInsightsInfo, PriceInsightsInfo_PriceBucket, ProductInfo} from '//shopping-insights-side-panel.top-chrome/shared/shopping_list.mojom-webui.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; import {String16} from 'chrome://resources/mojo/mojo/public/mojom/base/string16.mojom-webui.js'; @@ -56,8 +56,8 @@ private showSaveLocationText_: boolean; private folderName_: string; - private shoppingApi_: ShoppingListApiProxy = - ShoppingListApiProxyImpl.getInstance(); + private shoppingApi_: ShoppingServiceApiProxy = + ShoppingServiceApiProxyImpl.getInstance(); override connectedCallback() { super.connectedCallback();
diff --git a/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/wallpaper_search.html b/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/wallpaper_search.html index edb63f7c..6c587854 100644 --- a/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/wallpaper_search.html +++ b/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/wallpaper_search.html
@@ -481,6 +481,14 @@ </div> </div> </div> +<template is="dom-if" if="[[inspirationCardEnabled_]]"> + <hr class="sp-cards-separator"> + <div class="sp-card" id="inspirationCard"> + <sp-heading hide-back-button> + <h2 slot="heading">$i18n{wallpaperSearchInspirationHeader}</h2> + </sp-heading> + </div> +</template> <hr class="sp-cards-separator" hidden$="[[!shouldShowHistory_(history_)]]"> <div class="sp-card" id="historyCard" hidden$="[[!shouldShowHistory_(history_)]]">
diff --git a/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/wallpaper_search.ts b/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/wallpaper_search.ts index 7baca1c..00bec5e9 100644 --- a/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/wallpaper_search.ts +++ b/chrome/browser/resources/side_panel/customize_chrome/wallpaper_search/wallpaper_search.ts
@@ -140,6 +140,11 @@ value: false, }, history_: Object, + inspirationCardEnabled_: { + type: Boolean, + value: () => + loadTimeData.getBoolean('wallpaperSearchInspirationCardEnabled'), + }, resultsDescriptors_: Object, results_: Object, selectedFeedbackOption_: { @@ -183,6 +188,7 @@ private errorState_: ErrorState|null = null; private expandedCategories_: {[categoryIndex: number]: boolean} = {}; private history_: WallpaperSearchResult[] = []; + private inspirationCardEnabled_: boolean; private loading_: boolean; private results_: WallpaperSearchResult[] = []; private resultsDescriptors_: ResultsDescriptors = {};
diff --git a/chrome/browser/resources/side_panel/shared/BUILD.gn b/chrome/browser/resources/side_panel/shared/BUILD.gn index d09f43a..75d499ca 100644 --- a/chrome/browser/resources/side_panel/shared/BUILD.gn +++ b/chrome/browser/resources/side_panel/shared/BUILD.gn
@@ -17,7 +17,7 @@ "sp_list_item_badge.ts", ] - non_web_component_files = [ "commerce/shopping_list_api_proxy.ts" ] + non_web_component_files = [ "commerce/shopping_service_api_proxy.ts" ] css_files = [ "sp_shared_vars.css",
diff --git a/chrome/browser/resources/side_panel/shared/commerce/shopping_list_api_proxy.ts b/chrome/browser/resources/side_panel/shared/commerce/shopping_service_api_proxy.ts similarity index 89% rename from chrome/browser/resources/side_panel/shared/commerce/shopping_list_api_proxy.ts rename to chrome/browser/resources/side_panel/shared/commerce/shopping_service_api_proxy.ts index b9ed779dd..fcbd4ac 100644 --- a/chrome/browser/resources/side_panel/shared/commerce/shopping_list_api_proxy.ts +++ b/chrome/browser/resources/side_panel/shared/commerce/shopping_service_api_proxy.ts
@@ -2,16 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// TODO(b:283833590): Rename this file since it serves for all shopping features -// now. import {String16} from 'chrome://resources/mojo/mojo/public/mojom/base/string16.mojom-webui.js'; import {Url} from 'chrome://resources/mojo/url/mojom/url.mojom-webui.js'; import {BookmarkProductInfo, PageCallbackRouter, PriceInsightsInfo, ProductInfo, ShoppingListHandlerFactory, ShoppingListHandlerRemote} from '../shopping_list.mojom-webui.js'; -let instance: ShoppingListApiProxy|null = null; +let instance: ShoppingServiceApiProxy|null = null; -export interface ShoppingListApiProxy { +export interface ShoppingServiceApiProxy { getAllPriceTrackedBookmarkProductInfo(): Promise<{productInfos: BookmarkProductInfo[]}>; getAllShoppingBookmarkProductInfo(): @@ -33,7 +31,7 @@ getCallbackRouter(): PageCallbackRouter; } -export class ShoppingListApiProxyImpl implements ShoppingListApiProxy { +export class ShoppingServiceApiProxyImpl implements ShoppingServiceApiProxy { handler: ShoppingListHandlerRemote; callbackRouter: PageCallbackRouter; @@ -112,11 +110,11 @@ return this.callbackRouter; } - static getInstance(): ShoppingListApiProxy { - return instance || (instance = new ShoppingListApiProxyImpl()); + static getInstance(): ShoppingServiceApiProxy { + return instance || (instance = new ShoppingServiceApiProxyImpl()); } - static setInstance(obj: ShoppingListApiProxy) { + static setInstance(obj: ShoppingServiceApiProxy) { instance = obj; } }
diff --git a/chrome/browser/resources/tab_search/app.html b/chrome/browser/resources/tab_search/app.html index bbb40bd..3e1d490 100644 --- a/chrome/browser/resources/tab_search/app.html +++ b/chrome/browser/resources/tab_search/app.html
@@ -3,7 +3,12 @@ --cr-primary-text-color: var(--color-tab-search-primary-foreground); --cr-secondary-text-color: var(--color-tab-search-secondary-foreground); --cr-separator-color: var(--color-tab-search-divider); + --cr-tabs-font-size: 12px; + --cr-tabs-icon-margin-end: 4px; + --cr-tabs-icon-size: 16px; --cr-tabs-selected-color: var(--color-tab-search-selected); + --cr-tabs-selection-bar-unselected-opacity: 1; + --cr-tabs-unselected-color: var(--color-tab-search-divider); --mwb-background-color: var(--color-tab-search-background); --mwb-icon-button-fill-color: var(--color-tab-search-secondary-foreground); --mwb-list-item-hover-background-color: var(--cr-hover-background-color);
diff --git a/chrome/browser/resources/tab_search/tab_organization_in_progress.html b/chrome/browser/resources/tab_search/tab_organization_in_progress.html index 1392120..5182f31b2 100644 --- a/chrome/browser/resources/tab_search/tab_organization_in_progress.html +++ b/chrome/browser/resources/tab_search/tab_organization_in_progress.html
@@ -1,6 +1,6 @@ <style include="tab-organization-shared-style"> #loading-container { - border: solid 2px var(--color-loading-gradient-border); + border: solid 1px var(--color-loading-gradient-border); border-radius: 8px; padding: 14px; }
diff --git a/chrome/browser/resources/tab_search/tab_organization_page.html b/chrome/browser/resources/tab_search/tab_organization_page.html index f49a57e1..1eb48fd8f 100644 --- a/chrome/browser/resources/tab_search/tab_organization_page.html +++ b/chrome/browser/resources/tab_search/tab_organization_page.html
@@ -50,7 +50,7 @@ } #body { - margin: 16px var(--mwb-list-item-horizontal-margin); + margin: var(--mwb-list-item-horizontal-margin); } #contents {
diff --git a/chrome/browser/resources/tab_search/tab_organization_page.ts b/chrome/browser/resources/tab_search/tab_organization_page.ts index d292d43..8704c2d 100644 --- a/chrome/browser/resources/tab_search/tab_organization_page.ts +++ b/chrome/browser/resources/tab_search/tab_organization_page.ts
@@ -21,7 +21,7 @@ import {Tab, TabOrganization, TabOrganizationError, TabOrganizationSession, TabOrganizationState, UserFeedback} from './tab_search.mojom-webui.js'; import {TabSearchApiProxy, TabSearchApiProxyImpl} from './tab_search_api_proxy.js'; -const BODY_VERTICAL_MARGIN: number = 32; +const BODY_VERTICAL_MARGIN: number = 40; const HEIGHT_ANIMATION_LENGTH: number = 250; export interface TabOrganizationPageElement {
diff --git a/chrome/browser/resources/tab_search/tab_organization_results.html b/chrome/browser/resources/tab_search/tab_organization_results.html index 0399026d..6382fd81 100644 --- a/chrome/browser/resources/tab_search/tab_organization_results.html +++ b/chrome/browser/resources/tab_search/tab_organization_results.html
@@ -16,7 +16,7 @@ --cr-input-padding-bottom: 9px; --cr-input-padding-top: 9px; --cr-input-underline-display: none; - margin: 0 16px; + margin: 0 var(--mwb-list-item-horizontal-margin); } cr-input:focus { @@ -25,6 +25,10 @@ --cr-input-padding-top: 8px; } + tab-search-item { + --tab-search-favicon-background: var(--color-tab-search-background); + } + .button-row { display: flex; gap: 16px;
diff --git a/chrome/browser/resources/tab_search/tab_search_item.html b/chrome/browser/resources/tab_search/tab_search_item.html index b3cce32..1c8da30a 100644 --- a/chrome/browser/resources/tab_search/tab_search_item.html +++ b/chrome/browser/resources/tab_search/tab_search_item.html
@@ -155,7 +155,8 @@ :host-context([chrome-refresh-2023]) #iconContainer { align-items: center; - background: var(--color-list-item-url-favicon-background); + background: var(--tab-search-favicon-background, + var(--color-list-item-url-favicon-background)); border-radius: 8px; display: flex; flex-shrink: 0;
diff --git a/chrome/browser/safe_browsing/download_protection/check_client_download_request.cc b/chrome/browser/safe_browsing/download_protection/check_client_download_request.cc index eac8e9e..4ed0d1f 100644 --- a/chrome/browser/safe_browsing/download_protection/check_client_download_request.cc +++ b/chrome/browser/safe_browsing/download_protection/check_client_download_request.cc
@@ -72,18 +72,19 @@ case DownloadCheckResult::PROMPT_FOR_LOCAL_PASSWORD_SCANNING: case DownloadCheckResult::POTENTIALLY_UNWANTED: case DownloadCheckResult::UNCOMMON: - if (reason == REASON_DOWNLOAD_DANGEROUS) + if (reason == REASON_DOWNLOAD_DANGEROUS) { callback.Run(DownloadCheckResult::DANGEROUS); - else if (reason == REASON_DOWNLOAD_DANGEROUS_HOST) + } else if (reason == REASON_DOWNLOAD_DANGEROUS_HOST) { callback.Run(DownloadCheckResult::DANGEROUS_HOST); - else if (reason == REASON_DOWNLOAD_POTENTIALLY_UNWANTED) + } else if (reason == REASON_DOWNLOAD_POTENTIALLY_UNWANTED) { callback.Run(DownloadCheckResult::POTENTIALLY_UNWANTED); - else if (reason == REASON_DOWNLOAD_UNCOMMON) + } else if (reason == REASON_DOWNLOAD_UNCOMMON) { callback.Run(DownloadCheckResult::UNCOMMON); - else if (reason == REASON_DOWNLOAD_DANGEROUS_ACCOUNT_COMPROMISE) + } else if (reason == REASON_DOWNLOAD_DANGEROUS_ACCOUNT_COMPROMISE) { callback.Run(DownloadCheckResult::DANGEROUS_ACCOUNT_COMPROMISE); - else + } else { callback.Run(deep_scan_result); + } return; // These other results have precedence over dangerous ones because they @@ -247,21 +248,33 @@ result, upload_requested, item_, request_data, response_body); } -void CheckClientDownloadRequest::LogDeepScanningPrompt() const { - LogDeepScanEvent(item_, DeepScanEvent::kPromptShown); +void CheckClientDownloadRequest::LogDeepScanningPrompt(bool did_prompt) const { + if (did_prompt) { + LogDeepScanEvent(item_, DeepScanEvent::kPromptShown); + } + + base::UmaHistogramBoolean("SBClientDownload.ServerRequestsDeepScanningPrompt", + did_prompt); + if (DownloadItemWarningData::IsEncryptedArchive(item_)) { + base::UmaHistogramBoolean( + "SBClientDownload.ServerRequestsDeepScanningPromptPasswordProtected", + did_prompt); + } } absl::optional<enterprise_connectors::AnalysisSettings> CheckClientDownloadRequest::ShouldUploadBinary( DownloadCheckResultReason reason) { // If the download was destroyed, we can't upload it. - if (reason == REASON_DOWNLOAD_DESTROYED) + if (reason == REASON_DOWNLOAD_DESTROYED) { return absl::nullopt; + } // If the download already has a scanning response attached, there is no need // to try and upload it again. - if (item_->GetUserData(enterprise_connectors::ScanResult::kKey)) + if (item_->GetUserData(enterprise_connectors::ScanResult::kKey)) { return absl::nullopt; + } // If the download is considered dangerous, don't upload the binary to show // a warning to the user ASAP. @@ -277,8 +290,9 @@ // might still need to happen. if (settings && reason == REASON_ALLOWLISTED_URL) { settings->tags.erase("malware"); - if (settings->tags.empty()) + if (settings->tags.empty()) { return absl::nullopt; + } } return settings; @@ -318,24 +332,28 @@ bool CheckClientDownloadRequest::IsUnderAdvancedProtection( Profile* profile) const { - if (!profile) + if (!profile) { return false; + } AdvancedProtectionStatusManager* advanced_protection_status_manager = AdvancedProtectionStatusManagerFactory::GetForProfile(profile); - if (!advanced_protection_status_manager) + if (!advanced_protection_status_manager) { return false; + } return advanced_protection_status_manager->IsUnderAdvancedProtection(); } bool CheckClientDownloadRequest::ShouldPromptForDeepScanning( bool server_requests_prompt) const { - if (!server_requests_prompt) + if (!server_requests_prompt) { return false; + } // Too large uploads would fail immediately, so don't prompt in this case. if (static_cast<size_t>(item_->GetTotalBytes()) >= - BinaryUploadService::kMaxUploadSizeBytes) + BinaryUploadService::kMaxUploadSizeBytes) { return false; + } Profile* profile = Profile::FromBrowserContext(GetBrowserContext()); if (!profile) { @@ -404,8 +422,9 @@ bool CheckClientDownloadRequest::IsAllowlistedByPolicy() const { Profile* profile = Profile::FromBrowserContext(GetBrowserContext()); - if (!profile) + if (!profile) { return false; + } return MatchesEnterpriseAllowlist(*profile->GetPrefs(), item_->GetUrlChain()); }
diff --git a/chrome/browser/safe_browsing/download_protection/check_client_download_request.h b/chrome/browser/safe_browsing/download_protection/check_client_download_request.h index e71f6ad..8bf0d75 100644 --- a/chrome/browser/safe_browsing/download_protection/check_client_download_request.h +++ b/chrome/browser/safe_browsing/download_protection/check_client_download_request.h
@@ -79,7 +79,7 @@ bool server_requests_prompt) const override; bool ShouldPromptForIncorrectPassword() const override; bool ShouldShowScanFailure() const override; - void LogDeepScanningPrompt() const override; + void LogDeepScanningPrompt(bool did_prompt) const override; // Uploads the binary for deep scanning if the reason and policies indicate // it should be. ShouldUploadBinary will returns the settings to apply for
diff --git a/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.cc b/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.cc index 0e02b18..47eafea 100644 --- a/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.cc +++ b/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.cc
@@ -314,15 +314,12 @@ // Otherwise, client Safe Browsing reports may be missed when the // verdict is SAFE. See https://crbug.com/1485218. *token = response.token(); - LogDeepScanningPrompt(); } // Only record the UMA metric if we're in a population that potentially // could prompt for deep scanning. if (ShouldPromptForDeepScanning(/*server_requests_prompt=*/true)) { - base::UmaHistogramBoolean( - "SBClientDownload.ServerRequestsDeepScanningPrompt", - deep_scanning_prompt); + LogDeepScanningPrompt(deep_scanning_prompt); } }
diff --git a/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.h b/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.h index 5d01b382..3291561f 100644 --- a/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.h +++ b/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.h
@@ -165,8 +165,8 @@ // |client_download_request_| with their origin. void SanitizeRequest(); - // Called when a deep scanning prompt is about to be shown. - virtual void LogDeepScanningPrompt() const = 0; + // Called when we decide whether or not to show a deep scanning prompt + virtual void LogDeepScanningPrompt(bool did_prompt) const = 0; // Returns whether we should skip sending a ping to Safe Browsing because the // provided password was incorrect.
diff --git a/chrome/browser/safe_browsing/download_protection/check_file_system_access_write_request.cc b/chrome/browser/safe_browsing/download_protection/check_file_system_access_write_request.cc index ad14467..7b06facb 100644 --- a/chrome/browser/safe_browsing/download_protection/check_file_system_access_write_request.cc +++ b/chrome/browser/safe_browsing/download_protection/check_file_system_access_write_request.cc
@@ -148,7 +148,8 @@ return IsURLAllowlistedByPolicy(item_->frame_url, *profile->GetPrefs()); } -void CheckFileSystemAccessWriteRequest::LogDeepScanningPrompt() const { +void CheckFileSystemAccessWriteRequest::LogDeepScanningPrompt( + bool did_prompt) const { NOTREACHED(); }
diff --git a/chrome/browser/safe_browsing/download_protection/check_file_system_access_write_request.h b/chrome/browser/safe_browsing/download_protection/check_file_system_access_write_request.h index f1ec7a4..e5cbd33 100644 --- a/chrome/browser/safe_browsing/download_protection/check_file_system_access_write_request.h +++ b/chrome/browser/safe_browsing/download_protection/check_file_system_access_write_request.h
@@ -70,7 +70,7 @@ void NotifyRequestFinished(DownloadCheckResult result, DownloadCheckResultReason reason) override; bool IsAllowlistedByPolicy() const override; - void LogDeepScanningPrompt() const override; + void LogDeepScanningPrompt(bool did_prompt) const override; const std::unique_ptr<content::FileSystemAccessWriteItem> item_; std::unique_ptr<ReferrerChainData> referrer_chain_data_;
diff --git a/chrome/browser/search_engines/template_url_service_unittest.cc b/chrome/browser/search_engines/template_url_service_unittest.cc index 21074912..a122cfb 100644 --- a/chrome/browser/search_engines/template_url_service_unittest.cc +++ b/chrome/browser/search_engines/template_url_service_unittest.cc
@@ -5,7 +5,9 @@ #include <stddef.h> #include <memory> +#include <string> #include <utility> +#include <vector> #include "base/functional/bind.h" #include "base/functional/callback.h" @@ -130,15 +132,18 @@ #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \ BUILDFLAG(IS_CHROMEOS_ASH) // Creates a `TemplateURLData` corresponding to a site search engine set by -// policy, with some fake data generated from `keyword`. +// policy, with some fake data generated from `keyword` and the +// `featured_by_policy` field set according to the corresponding parameter. std::unique_ptr<TemplateURLData> CreateTestSiteSearchEntry( - const std::string& keyword) { + const std::string& keyword, + bool featured_by_policy) { auto data = std::make_unique<TemplateURLData>(); data->SetShortName(base::UTF8ToUTF16(keyword + "name")); data->SetKeyword(base::UTF8ToUTF16(keyword)); data->SetURL(std::string("https://") + keyword + ".com/q={searchTerms}"); data->created_by_policy = TemplateURLData::CreatedByPolicy::kSiteSearch; data->enforced_by_policy = false; + data->featured_by_policy = featured_by_policy; data->is_active = TemplateURLData::ActiveStatus::kTrue; data->favicon_url = GURL(std::string("https://") + keyword + ".com/favicon.ico"); @@ -147,6 +152,28 @@ data->last_modified = base::Time(); return data; } + +// Creates a `TemplateURLData` corresponding to a site search engine set by +// policy, with some fake data generated from `keyword` and +// `featured_by_policy` set as false. +std::unique_ptr<TemplateURLData> CreateTestSiteSearchEntry( + const std::string& keyword) { + return CreateTestSiteSearchEntry(keyword, /*featured_by_policy=*/false); +} + +// Creates a `TemplateURLData` with some fake data generated from `keyword` +// and with the `safe_for_autoreplace` field set according to the +// corresponding parameter. +TemplateURLData CreateTestSearchEngineWithSafeForAutoreplace( + const std::string& keyword, + bool safe_for_autoreplace) { + TemplateURLData data; + data.SetKeyword(base::UTF8ToUTF16(keyword)); + data.SetURL(std::string("https://existing-") + keyword + + ".com/q={searchTerms}"); + data.safe_for_autoreplace = safe_for_autoreplace; + return data; +} #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || // BUILDFLAG(IS_CHROMEOS_ASH) @@ -2666,16 +2693,11 @@ EXPECT_FALSE(model()->GetTemplateURLForKeyword(kKeyword4U16)); } -TEST_P(TemplateURLServiceTest, SiteSearchPolicyConflictWithExistingEngines) { +TEST_P(TemplateURLServiceTest, + NonFeaturedSiteSearchPolicyConflictWithExistingEngines) { constexpr char kKeyword1[] = "site_search_1"; constexpr char kKeyword2[] = "site_search_2"; - constexpr char16_t kKeyword1U16[] = u"site_search_1"; - constexpr char16_t kKeyword2U16[] = u"site_search_2"; - - constexpr char kUserDefinedUrl[] = - "https://www.my-search.com/q={searchTerms}"; - base::test::ScopedFeatureList scoped_feature_list; scoped_feature_list.InitAndEnableFeature(omnibox::kSiteSearchSettingsPolicy); @@ -2684,18 +2706,14 @@ test_util()->ResetModel(/*verify_load=*/true); // Create two pre-existing site search engines. - TemplateURLData data1; - data1.SetKeyword(kKeyword1U16); - data1.SetURL(kUserDefinedUrl); - data1.safe_for_autoreplace = true; - model()->Add(std::make_unique<TemplateURL>(data1)); - - TemplateURLData data2; - data2.SetKeyword(kKeyword2U16); - data2.SetURL(kUserDefinedUrl); - data2.safe_for_autoreplace = false; - TemplateURL* user_engine2 = - model()->Add(std::make_unique<TemplateURL>(data2)); + TemplateURLService::TemplateURLVector existing_engines{ + model()->Add(std::make_unique<TemplateURL>( + CreateTestSearchEngineWithSafeForAutoreplace( + kKeyword1, /*safe_for_autoreplace=*/true))), + model()->Add(std::make_unique<TemplateURL>( + CreateTestSearchEngineWithSafeForAutoreplace( + kKeyword2, /*safe_for_autoreplace=*/false))), + }; // Set a managed preference that establishes site search providers conflicting // with pre-existing search engines. @@ -2706,15 +2724,21 @@ SetManagedSiteSearchSettingsPreference(site_search_engines, test_util()->profile()); - // Ensure the search engines set by policy can be accessed. - // TODO(b/314359989): Only the user-define search engine with - // `safe_for_autoreplace` == false should be overridden - // by the policy. - for (auto& engine : site_search_engines) { + // A search engine set by the `SiteSearchSettings` policy only overrides + // an existing engine if the latter has not been manually edited by the user + // (`safe_for_autoreplace` is true). + std::vector<const TemplateURLData*> expectations_after_policy{ + // Override existing engine because `safe_for_autoreplace` is true. + site_search_engines[0].get(), + // Do not override existing engine because `safe_for_autoreplace` is + // false. + &existing_engines[1]->data(), + }; + for (auto* engine : expectations_after_policy) { const TemplateURL* actual_turl = model()->GetTemplateURLForKeyword(engine->keyword()); ASSERT_TRUE(actual_turl); - ExpectSimilar(engine.get(), &actual_turl->data()); + ExpectSimilar(engine, &actual_turl->data()); } // Reset the policy. @@ -2722,16 +2746,91 @@ EnterpriseSiteSearchManager::OwnedTemplateURLDataVector(), test_util()->profile()); - // TODO(b/314368463): Site engines with `safe_for_replacement` true should - // not be deleted. - ASSERT_FALSE(model()->GetTemplateURLForKeyword(kKeyword1U16)); + // Once the policy no longer applies, the user should be able to continue + // using the site search engines originally defined. + for (const auto* user_engine : existing_engines) { + const TemplateURL* actual_turl = + model()->GetTemplateURLForKeyword(user_engine->keyword()); + ASSERT_TRUE(actual_turl); + AssertEquals(*user_engine, *actual_turl); + } +} + +TEST_P(TemplateURLServiceTest, + FeaturedSiteSearchPolicyConflictWithExistingEngines) { + constexpr char kKeyword1[] = "site_search_1"; + constexpr char kKeywordWithAt1[] = "@site_search_1"; + constexpr char kKeyword2[] = "site_search_2"; + constexpr char kKeywordWithAt2[] = "@site_search_2"; + + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeature(omnibox::kSiteSearchSettingsPolicy); + + // Reset the model to ensure an `EnterpriseSiteSearchManager` instance is + // created (it depends on `kSiteSearchSettingsPolicy` being enabled). + test_util()->ResetModel(/*verify_load=*/true); + + // Create some pre-existing site search engines with variations of starting/ + // not starting with "@" and `safe_for_autoreplace` . + TemplateURLService::TemplateURLVector existing_engines{ + model()->Add(std::make_unique<TemplateURL>( + CreateTestSearchEngineWithSafeForAutoreplace( + kKeyword1, /*safe_for_autoreplace=*/true))), + model()->Add(std::make_unique<TemplateURL>( + CreateTestSearchEngineWithSafeForAutoreplace( + kKeywordWithAt1, /*safe_for_autoreplace=*/true))), + model()->Add(std::make_unique<TemplateURL>( + CreateTestSearchEngineWithSafeForAutoreplace( + kKeyword2, /*safe_for_autoreplace=*/false))), + model()->Add(std::make_unique<TemplateURL>( + CreateTestSearchEngineWithSafeForAutoreplace( + kKeywordWithAt2, /*safe_for_autoreplace=*/false))), + }; + + // Set a managed preference that establishes site search providers + // conflicting with pre-existing search engines. + EnterpriseSiteSearchManager::OwnedTemplateURLDataVector site_search_engines; + site_search_engines.push_back(CreateTestSiteSearchEntry(kKeyword1)); + site_search_engines.push_back( + CreateTestSiteSearchEntry(kKeywordWithAt1, /*featured_by_policy=*/true)); + site_search_engines.push_back(CreateTestSiteSearchEntry(kKeyword2)); + site_search_engines.push_back( + CreateTestSiteSearchEntry(kKeywordWithAt2, /*featured_by_policy=*/true)); + + SetManagedSiteSearchSettingsPreference(site_search_engines, + test_util()->profile()); + + std::vector<const TemplateURLData*> expectations_after_policy{ + // Override existing engine because `safe_for_autoreplace` is true. + site_search_engines[0].get(), + // Override existing engine because keyword starts with "@". + site_search_engines[1].get(), + // Do not override existing engine because `safe_for_autoreplace` is + // false. + &existing_engines[2]->data(), + // Override existing engine because keyword starts with "@". + site_search_engines[3].get(), + }; + for (auto* engine : expectations_after_policy) { + const TemplateURL* actual_turl = + model()->GetTemplateURLForKeyword(engine->keyword()); + ASSERT_TRUE(actual_turl); + ExpectSimilar(engine, &actual_turl->data()); + } + + // Reset the policy. + SetManagedSiteSearchSettingsPreference( + EnterpriseSiteSearchManager::OwnedTemplateURLDataVector(), + test_util()->profile()); // Once the policy no longer applies, the user should be able to continue - // using the site engine originally defined. - const TemplateURL* actual_turl = - model()->GetTemplateURLForKeyword(kKeyword2U16); - ASSERT_TRUE(actual_turl); - AssertEquals(*user_engine2, *actual_turl); + // using the site search engines originally defined. + for (const auto* user_engine : existing_engines) { + const TemplateURL* actual_turl = + model()->GetTemplateURLForKeyword(user_engine->keyword()); + ASSERT_TRUE(actual_turl); + AssertEquals(*user_engine, *actual_turl); + } } #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || // BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/link_to_text/LinkToTextCoordinator.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/link_to_text/LinkToTextCoordinator.java index 72703bd..617afed5 100644 --- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/link_to_text/LinkToTextCoordinator.java +++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/link_to_text/LinkToTextCoordinator.java
@@ -13,7 +13,6 @@ import org.chromium.base.task.TaskTraits; import org.chromium.blink.mojom.TextFragmentReceiver; import org.chromium.chrome.R; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.share.ChromeShareExtras; import org.chromium.chrome.browser.share.share_sheet.ChromeOptionShareCallback; import org.chromium.chrome.browser.share.share_sheet.ShareSheetLinkToggleCoordinator.LinkToggleState; @@ -170,7 +169,7 @@ } } - PostTask.postDelayedTask(TaskTraits.UI_DEFAULT, () -> timeout(), getTimeout()); + PostTask.postDelayedTask(TaskTraits.UI_DEFAULT, () -> timeout(), TIMEOUT_MS); requestSelector(); } @@ -182,7 +181,7 @@ return; } - PostTask.postDelayedTask(TaskTraits.UI_DEFAULT, () -> timeout(), getTimeout()); + PostTask.postDelayedTask(TaskTraits.UI_DEFAULT, () -> timeout(), TIMEOUT_MS); mRemoteRequestStatus = RemoteRequestStatus.REQUESTED; LinkToTextHelper.extractTextFragmentsMatches( mProducer, @@ -391,13 +390,6 @@ cleanup(); } - private int getTimeout() { - return ChromeFeatureList.getFieldTrialParamByFeatureAsInt( - ChromeFeatureList.PREEMPTIVE_LINK_TO_TEXT_GENERATION, - "TimeoutLengthMs", - TIMEOUT_MS); - } - @VisibleForTesting public String getTitle() { if (!mIncludeOriginInTitle) return mTab.getTitle();
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/link_to_text/LinkToTextHelper.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/link_to_text/LinkToTextHelper.java index f440201..634c195c 100644 --- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/link_to_text/LinkToTextHelper.java +++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/link_to_text/LinkToTextHelper.java
@@ -8,7 +8,6 @@ import org.chromium.base.Callback; import org.chromium.blink.mojom.TextFragmentReceiver; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.tab.SadTab; import org.chromium.chrome.browser.tab.Tab; import org.chromium.content_public.browser.RenderFrameHost; @@ -230,12 +229,8 @@ new TextFragmentReceiver.RequestSelector_Response() { @Override public void call(String selector, Integer error, Integer readyStatus) { - if (ChromeFeatureList.isEnabled( - ChromeFeatureList.PREEMPTIVE_LINK_TO_TEXT_GENERATION)) { - LinkToTextMetricsHelper.recordLinkToTextDiagnoseStatus( - LinkToTextMetricsHelper.LinkToTextDiagnoseStatus - .SELECTOR_RECEIVED); - } + LinkToTextMetricsHelper.recordLinkToTextDiagnoseStatus( + LinkToTextMetricsHelper.LinkToTextDiagnoseStatus.SELECTOR_RECEIVED); callback.apply(selector, error, readyStatus); } });
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetLinkToggleCoordinator.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetLinkToggleCoordinator.java index ed93c7a..d6c035ee 100644 --- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetLinkToggleCoordinator.java +++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetLinkToggleCoordinator.java
@@ -6,7 +6,6 @@ import androidx.annotation.IntDef; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.share.ChromeShareExtras; import org.chromium.chrome.browser.share.ChromeShareExtras.DetailedContentType; import org.chromium.chrome.browser.share.link_to_text.LinkToTextCoordinator; @@ -54,8 +53,7 @@ mChromeShareExtras = chromeShareExtras; mUrl = chromeShareExtras.getContentUrl(); mShouldEnableLinkToTextToggle = - ChromeFeatureList.isEnabled(ChromeFeatureList.PREEMPTIVE_LINK_TO_TEXT_GENERATION) - && mLinkToTextCoordinator != null + mLinkToTextCoordinator != null && chromeShareExtras.getDetailedContentType() == DetailedContentType.HIGHLIGHTED_TEXT; mShouldEnableGenericToggle =
diff --git a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/send_tab_to_self/SendTabToSelfBottomSheetRenderTest.java b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/send_tab_to_self/SendTabToSelfBottomSheetRenderTest.java index e0b3aef..0133b287 100644 --- a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/send_tab_to_self/SendTabToSelfBottomSheetRenderTest.java +++ b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/send_tab_to_self/SendTabToSelfBottomSheetRenderTest.java
@@ -56,7 +56,7 @@ public final RenderTestRule mRenderTestRule = RenderTestRule.Builder.withPublicCorpus() .setBugComponent(RenderTestRule.Component.UI_BROWSER_SHARING) - .setRevision(4) + .setRevision(5) .build(); @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
diff --git a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetCoordinatorTest.java b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetCoordinatorTest.java index dfe07d4df..ff342509 100644 --- a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetCoordinatorTest.java +++ b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetCoordinatorTest.java
@@ -42,7 +42,6 @@ import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.base.test.util.JniMocker; import org.chromium.chrome.browser.feature_engagement.TrackerFactory; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.share.ShareContentTypeHelper; @@ -51,7 +50,6 @@ import org.chromium.chrome.browser.share.share_sheet.ShareSheetLinkToggleMetricsHelper.LinkToggleMetricsDetails; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.test.util.browser.Features; -import org.chromium.chrome.test.util.browser.Features.EnableFeatures; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; import org.chromium.components.browser_ui.share.ShareParams; import org.chromium.components.dom_distiller.core.DomDistillerUrlUtils; @@ -70,7 +68,6 @@ /** Tests {@link ShareSheetCoordinator}. */ @RunWith(BaseRobolectricTestRunner.class) -@EnableFeatures({ChromeFeatureList.PREEMPTIVE_LINK_TO_TEXT_GENERATION}) @LooperMode(LooperMode.Mode.LEGACY) @Config(shadows = ShadowPropertyModelBuilder.class) public final class ShareSheetCoordinatorTest {
diff --git a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetLinkToggleCoordinatorTest.java b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetLinkToggleCoordinatorTest.java index 03b8bdb3..5d56031 100644 --- a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetLinkToggleCoordinatorTest.java +++ b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetLinkToggleCoordinatorTest.java
@@ -12,7 +12,6 @@ import android.text.TextUtils; -import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -20,10 +19,8 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.chromium.base.FeatureList; import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.base.test.util.JniMocker; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.share.ChromeShareExtras; import org.chromium.chrome.browser.share.ChromeShareExtras.DetailedContentType; import org.chromium.chrome.browser.share.link_to_text.LinkToTextCoordinator; @@ -63,16 +60,6 @@ .build(); when(mLinkToTextCoordinator.getShareParams(LinkToggleState.NO_LINK)) .thenReturn(shareParamsWithTextOnly); - - FeatureList.TestValues testValues = new FeatureList.TestValues(); - testValues.addFeatureFlagOverride( - ChromeFeatureList.PREEMPTIVE_LINK_TO_TEXT_GENERATION, true); - FeatureList.setTestValues(testValues); - } - - @After - public void tearDown() { - FeatureList.setTestValues(null); } @Test
diff --git a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetUsageRankingHelperTest.java b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetUsageRankingHelperTest.java index b04b052..4a3f399c 100644 --- a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetUsageRankingHelperTest.java +++ b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetUsageRankingHelperTest.java
@@ -32,7 +32,6 @@ import org.chromium.base.test.util.CallbackHelper; import org.chromium.base.test.util.JniMocker; import org.chromium.chrome.R; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.share.ChromeShareExtras.DetailedContentType; import org.chromium.chrome.browser.share.ShareContentTypeHelper; @@ -40,7 +39,6 @@ import org.chromium.chrome.browser.share.share_sheet.ShareSheetLinkToggleCoordinator.LinkToggleState; import org.chromium.chrome.browser.share.share_sheet.ShareSheetLinkToggleMetricsHelper.LinkToggleMetricsDetails; import org.chromium.chrome.test.util.browser.Features; -import org.chromium.chrome.test.util.browser.Features.EnableFeatures; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; import org.chromium.components.browser_ui.share.ShareParams; import org.chromium.components.dom_distiller.core.DomDistillerUrlUtils; @@ -59,7 +57,6 @@ /** Tests {@link ShareSheetUsageRankingHelper}. */ @RunWith(BaseRobolectricTestRunner.class) -@EnableFeatures({ChromeFeatureList.PREEMPTIVE_LINK_TO_TEXT_GENERATION}) @LooperMode(LooperMode.Mode.LEGACY) public class ShareSheetUsageRankingHelperTest { private static final String MOCK_URL = JUnitTestGURLs.EXAMPLE_URL.getSpec();
diff --git a/chrome/browser/tab/BUILD.gn b/chrome/browser/tab/BUILD.gn index 00ef73f..d0c95a13 100644 --- a/chrome/browser/tab/BUILD.gn +++ b/chrome/browser/tab/BUILD.gn
@@ -76,7 +76,6 @@ "//chrome/browser/commerce/android:java", "//chrome/browser/commerce/price_tracking/android:java", "//chrome/browser/contextmenu:java", - "//chrome/browser/endpoint_fetcher:java", "//chrome/browser/flags:java", "//chrome/browser/optimization_guide/android:java", "//chrome/browser/preferences:java",
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 12fe6da..acea119 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -1617,6 +1617,8 @@ "user_notes/user_notes_controller.h", "views/eye_dropper/eye_dropper.cc", "views/eye_dropper/eye_dropper.h", + "views/file_system_access/file_system_access_scroll_panel.cc", + "views/file_system_access/file_system_access_scroll_panel.h", "webui/access_code_cast/access_code_cast_dialog.cc", "webui/access_code_cast/access_code_cast_dialog.h", "webui/access_code_cast/access_code_cast_handler.cc", @@ -3741,6 +3743,7 @@ "//chromeos/ash/components/disks", "//chromeos/ash/components/drivefs", "//chromeos/ash/components/drivefs/mojom:mojom", + "//chromeos/ash/components/emoji:resources", "//chromeos/ash/components/fwupd", "//chromeos/ash/components/heatmap", "//chromeos/ash/components/human_presence", @@ -6800,8 +6803,6 @@ "content_settings/fake_owner.cc", "content_settings/fake_owner.h", "find_bar/find_bar_host_unittest_util.h", - "login/login_handler_test_utils.cc", - "login/login_handler_test_utils.h", ] public_deps = [ ":ui" ] deps = [
diff --git a/chrome/browser/ui/android/appmenu/internal/java/src/org/chromium/chrome/browser/ui/appmenu/AppMenuItemViewBinderRenderTest.java b/chrome/browser/ui/android/appmenu/internal/java/src/org/chromium/chrome/browser/ui/appmenu/AppMenuItemViewBinderRenderTest.java index 3dc36fca..0c36260 100644 --- a/chrome/browser/ui/android/appmenu/internal/java/src/org/chromium/chrome/browser/ui/appmenu/AppMenuItemViewBinderRenderTest.java +++ b/chrome/browser/ui/android/appmenu/internal/java/src/org/chromium/chrome/browser/ui/appmenu/AppMenuItemViewBinderRenderTest.java
@@ -64,6 +64,7 @@ public ChromeRenderTestRule mRenderTestRule = ChromeRenderTestRule.Builder.withPublicCorpus() .setBugComponent(ChromeRenderTestRule.Component.UI_BROWSER_MOBILE_APP_MENU) + .setRevision(1) .build(); private static Activity sActivity;
diff --git a/chrome/browser/ui/android/edge_to_edge/BUILD.gn b/chrome/browser/ui/android/edge_to_edge/BUILD.gn index e4b7f38..94aea7e 100644 --- a/chrome/browser/ui/android/edge_to_edge/BUILD.gn +++ b/chrome/browser/ui/android/edge_to_edge/BUILD.gn
@@ -6,7 +6,11 @@ import("//chrome/android/features/android_library_factory_tmpl.gni") android_library("java") { - sources = [ "java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeController.java" ] + sources = [ + "java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeController.java", + "java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgePadAdjuster.java", + "java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeSupplier.java", + ] deps = [ "//base:base_java", "//chrome/browser/android/lifecycle:java",
diff --git a/chrome/browser/ui/android/edge_to_edge/internal/BUILD.gn b/chrome/browser/ui/android/edge_to_edge/internal/BUILD.gn index a91b198..3800365 100644 --- a/chrome/browser/ui/android/edge_to_edge/internal/BUILD.gn +++ b/chrome/browser/ui/android/edge_to_edge/internal/BUILD.gn
@@ -16,6 +16,7 @@ "java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeControllerImpl.java", "java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeOSWrapper.java", "java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeOSWrapperImpl.java", + "java/src/org/chromium/chrome/browser/ui/edge_to_edge/SimpleEdgeToEdgePadAdjuster.java", ] deps = [ "//base:base_java",
diff --git a/chrome/browser/ui/android/edge_to_edge/internal/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeControllerFactory.java b/chrome/browser/ui/android/edge_to_edge/internal/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeControllerFactory.java index 4ce8e80b..332073d 100644 --- a/chrome/browser/ui/android/edge_to_edge/internal/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeControllerFactory.java +++ b/chrome/browser/ui/android/edge_to_edge/internal/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeControllerFactory.java
@@ -7,6 +7,7 @@ import android.app.Activity; import android.os.Build; import android.os.Build.VERSION_CODES; +import android.view.View; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -42,6 +43,10 @@ return new EdgeToEdgeControllerImpl(activity, tabObservableSupplier, null); } + public static EdgeToEdgePadAdjuster createForView(View view) { + return new SimpleEdgeToEdgePadAdjuster(view); + } + /** * @return whether the feature is enabled or not. */
diff --git a/chrome/browser/ui/android/edge_to_edge/internal/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeControllerImpl.java b/chrome/browser/ui/android/edge_to_edge/internal/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeControllerImpl.java index 63fe47d..4dbad792 100644 --- a/chrome/browser/ui/android/edge_to_edge/internal/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeControllerImpl.java +++ b/chrome/browser/ui/android/edge_to_edge/internal/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeControllerImpl.java
@@ -21,6 +21,7 @@ import androidx.core.view.WindowInsetsCompat; import org.chromium.base.Log; +import org.chromium.base.ObserverList; import org.chromium.base.supplier.ObservableSupplier; import org.chromium.blink.mojom.ViewportFit; import org.chromium.chrome.browser.flags.ChromeFeatureList; @@ -47,6 +48,7 @@ private final @NonNull Activity mActivity; private final @NonNull TabSupplierObserver mTabSupplierObserver; + private final ObserverList<EdgeToEdgePadAdjuster> mPadAdjusters = new ObserverList<>(); private final @NonNull TabObserver mTabObserver; /** Multiplier to convert from pixels to DPs. */ @@ -146,6 +148,17 @@ return wantsToEdge; } + @Override + public void registerAdjuster(EdgeToEdgePadAdjuster adjuster) { + mPadAdjusters.addObserver(adjuster); + adjuster.adjustToEdge(mIsActivityToEdge, mSystemInsets.bottom); + } + + @Override + public void unregisterAdjuster(EdgeToEdgePadAdjuster adjuster) { + mPadAdjusters.removeObserver(adjuster); + } + /** * Updates our private WebContentsObserver member to point to the given Tab's WebContents. * Destroys any previous member. @@ -254,6 +267,10 @@ mSystemInsets.right, bottomInset); + for (var adjuster : mPadAdjusters) { + adjuster.adjustToEdge(toEdge, mSystemInsets.bottom); + } + // We only make the Nav Bar transparent because it's the only thing we want to draw // underneath. // TODO(donnd): Use an appropriate background color when not transparent.
diff --git a/chrome/browser/ui/android/edge_to_edge/internal/java/src/org/chromium/chrome/browser/ui/edge_to_edge/SimpleEdgeToEdgePadAdjuster.java b/chrome/browser/ui/android/edge_to_edge/internal/java/src/org/chromium/chrome/browser/ui/edge_to_edge/SimpleEdgeToEdgePadAdjuster.java new file mode 100644 index 0000000..19c668a9f --- /dev/null +++ b/chrome/browser/ui/android/edge_to_edge/internal/java/src/org/chromium/chrome/browser/ui/edge_to_edge/SimpleEdgeToEdgePadAdjuster.java
@@ -0,0 +1,42 @@ +// 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. + +package org.chromium.chrome.browser.ui.edge_to_edge; + +import android.view.View; + +/** + * A simple implementation of {@link EdgeToEdgePadAdjuster} which can add a padding when e2e is on + * and then remove when it is off. + */ +public class SimpleEdgeToEdgePadAdjuster implements EdgeToEdgePadAdjuster { + + private final View mViewToPad; + private boolean mPadded; + + public SimpleEdgeToEdgePadAdjuster(View view) { + mViewToPad = view; + } + + @Override + public void adjustToEdge(boolean toEdge, int inset) { + if (toEdge) { + if (mPadded) return; + mViewToPad.setPadding( + mViewToPad.getPaddingLeft(), + mViewToPad.getPaddingTop(), + mViewToPad.getPaddingRight(), + mViewToPad.getPaddingBottom() + inset); + mPadded = true; + } else if (mPadded) { + // reset to normal. + mViewToPad.setPadding( + mViewToPad.getPaddingLeft(), + mViewToPad.getPaddingTop(), + mViewToPad.getPaddingRight(), + mViewToPad.getPaddingBottom() - inset); + mPadded = false; + } + } +}
diff --git a/chrome/browser/ui/android/edge_to_edge/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeController.java b/chrome/browser/ui/android/edge_to_edge/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeController.java index 7660242f..ba4b41d 100644 --- a/chrome/browser/ui/android/edge_to_edge/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeController.java +++ b/chrome/browser/ui/android/edge_to_edge/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeController.java
@@ -10,10 +10,10 @@ import org.chromium.chrome.browser.tab.Tab; /** - * Control drawing using the Android Edge to Edge Feature. - * This allows drawing under Android System Bars. + * Control drawing using the Android Edge to Edge Feature. This allows drawing under Android System + * Bars. */ -public interface EdgeToEdgeController extends Destroyable { +public interface EdgeToEdgeController extends Destroyable, EdgeToEdgeSupplier { /** * Notifies the controller that a different tab is under observation.<br> * @param tab The tab that the observer is now observing. This can be {@code null}.
diff --git a/chrome/browser/ui/android/edge_to_edge/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgePadAdjuster.java b/chrome/browser/ui/android/edge_to_edge/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgePadAdjuster.java new file mode 100644 index 0000000..e4154f58 --- /dev/null +++ b/chrome/browser/ui/android/edge_to_edge/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgePadAdjuster.java
@@ -0,0 +1,16 @@ +// 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. + +package org.chromium.chrome.browser.ui.edge_to_edge; + +/** Triggered when the edge-to-edge state is updated. */ +public interface EdgeToEdgePadAdjuster { + + /** + * @param toEdge Whether edge-to-edge is on. + * @param inset The bottom inset which is supposed to be padded to or removed from the bottom + * view. + */ + void adjustToEdge(boolean toEdge, int inset); +}
diff --git a/chrome/browser/ui/android/edge_to_edge/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeSupplier.java b/chrome/browser/ui/android/edge_to_edge/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeSupplier.java new file mode 100644 index 0000000..e989761 --- /dev/null +++ b/chrome/browser/ui/android/edge_to_edge/java/src/org/chromium/chrome/browser/ui/edge_to_edge/EdgeToEdgeSupplier.java
@@ -0,0 +1,12 @@ +// 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. + +package org.chromium.chrome.browser.ui.edge_to_edge; + +/** A supplier notifying of whether edge to edge is on and the value of the bottom inset. */ +public interface EdgeToEdgeSupplier { + void registerAdjuster(EdgeToEdgePadAdjuster adjuster); + + void unregisterAdjuster(EdgeToEdgePadAdjuster adjuster); +}
diff --git a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/SyncPromoControllerUITest.java b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/SyncPromoControllerUITest.java index bc53230..4863d1c 100644 --- a/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/SyncPromoControllerUITest.java +++ b/chrome/browser/ui/android/signin/java/src/org/chromium/chrome/browser/ui/signin/SyncPromoControllerUITest.java
@@ -74,7 +74,7 @@ @Rule public final RenderTestRule mRenderTestRule = RenderTestRule.Builder.withPublicCorpus() - .setRevision(0) + .setRevision(1) .setBugComponent(RenderTestRule.Component.SERVICES_SIGN_IN) .build();
diff --git a/chrome/browser/ui/android/theme/java/src/org/chromium/chrome/browser/theme/ThemeUtils.java b/chrome/browser/ui/android/theme/java/src/org/chromium/chrome/browser/theme/ThemeUtils.java index efaf6d1..2f47f8d 100644 --- a/chrome/browser/ui/android/theme/java/src/org/chromium/chrome/browser/theme/ThemeUtils.java +++ b/chrome/browser/ui/android/theme/java/src/org/chromium/chrome/browser/theme/ThemeUtils.java
@@ -15,7 +15,6 @@ import androidx.appcompat.content.res.AppCompatResources; import androidx.core.content.res.ResourcesCompat; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.ui.native_page.NativePage; import org.chromium.chrome.browser.ui.theme.BrandedColorScheme; @@ -90,11 +89,7 @@ // Text box color on default toolbar background in standard mode is a pre-defined // color instead of a calculated color. if (ThemeUtils.isUsingDefaultToolbarColor(context, false, color)) { - float tabElevation = - ChromeFeatureList.sBaselineGm3SurfaceColors.isEnabled() - ? context.getResources().getDimension(R.dimen.default_elevation_4) - : context.getResources() - .getDimension(R.dimen.toolbar_text_box_elevation); + float tabElevation = context.getResources().getDimension(R.dimen.default_elevation_4); return ChromeColors.getSurfaceColor(context, tabElevation); }
diff --git a/chrome/browser/ui/android/toolbar/java/res/layout/navigation_popup_item.xml b/chrome/browser/ui/android/toolbar/java/res/layout/navigation_popup_item.xml index 5289989c..73081560 100644 --- a/chrome/browser/ui/android/toolbar/java/res/layout/navigation_popup_item.xml +++ b/chrome/browser/ui/android/toolbar/java/res/layout/navigation_popup_item.xml
@@ -24,7 +24,7 @@ android:layout_width="@dimen/navigation_popup_favicon_bg_size" android:layout_height="@dimen/navigation_popup_favicon_bg_size" android:layout_gravity="center" - android:background="?attr/tileViewIconBackgroundModern" /> + android:background="@drawable/tile_view_icon_background_modern" /> <ImageView android:id="@+id/favicon_img" android:layout_width="@dimen/default_favicon_size"
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TabStripTransitionCoordinator.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TabStripTransitionCoordinator.java index 0e90a67..c4cb5667 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TabStripTransitionCoordinator.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TabStripTransitionCoordinator.java
@@ -148,6 +148,10 @@ } private void maybeUpdateTabStripVisibility(int windowWidth) { + // Invalid width will be ignored. This can happen when the mControlContainer are created + // hidden after theme changes. See crbug.com/1511599. + if (windowWidth <= 0) return; + boolean showTabStrip = windowWidth >= mTabStripTransitionThreshold; if (showTabStrip == mTabStripVisible) return;
diff --git a/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc b/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc index e1ac5b9e..0c7b3cf 100644 --- a/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc +++ b/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc
@@ -25,7 +25,6 @@ #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/location_bar/location_bar.h" #include "chrome/browser/ui/login/login_handler.h" -#include "chrome/browser/ui/login/login_handler_test_utils.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/view_ids.h" #include "chrome/common/chrome_paths.h"
diff --git a/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac.mm b/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac.mm index 6da3ea241..43c3378 100644 --- a/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac.mm +++ b/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac.mm
@@ -82,9 +82,17 @@ if (direction == base::i18n::RIGHT_TO_LEFT) command_id = IDC_WRITING_DIRECTION_RTL; - content::RenderViewHost* view_host = GetRenderViewHost(); - view_host->GetWidget()->UpdateTextDirection(direction); - view_host->GetWidget()->NotifyTextDirection(); + // Note: we get the local render frame host so that the writing mode settings + // changes apply to the correct frame. See crbug.com/1129073 for a + // description of what happens if we use the outermost frame. + content::RenderFrameHost* rfh = GetRenderFrameHost(); + // It's possible that the frame drops out from under us while the context + // menu is open. In this case, we'll not perform the action, but still record + // metrics. + if (rfh) { + rfh->GetRenderWidgetHost()->UpdateTextDirection(direction); + rfh->GetRenderWidgetHost()->NotifyTextDirection(); + } RenderViewContextMenu::RecordUsedItem(command_id); } @@ -128,7 +136,7 @@ void RenderViewContextMenuMac::LookUpInDictionary() { content::RenderWidgetHostView* view = - GetRenderViewHost()->GetWidget()->GetView(); + GetRenderFrameHost()->GetRenderWidgetHost()->GetView(); if (view) view->ShowDefinitionForSelection(); }
diff --git a/chrome/browser/ui/login/login_handler_browsertest.cc b/chrome/browser/ui/login/login_handler_browsertest.cc index d7f92b78..445d4840 100644 --- a/chrome/browser/ui/login/login_handler_browsertest.cc +++ b/chrome/browser/ui/login/login_handler_browsertest.cc
@@ -30,7 +30,6 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/browser_navigator.h" -#include "chrome/browser/ui/login/login_handler_test_utils.h" #include "chrome/browser/ui/login/login_tab_helper.h" #include "chrome/browser/ui/tabs/tab_enums.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" @@ -335,7 +334,7 @@ // Cancel, which triggers a reload to get the error page content from the // server. LoginHandler* handler = - *LoginHandler::GetAllLoginHandlersForTest().begin(); + LoginHandler::GetAllLoginHandlersForTest().front(); content::TestNavigationObserver reload_observer(contents); handler->CancelAuth(); reload_observer.Wait(); @@ -517,7 +516,7 @@ auto auth_needed_waiter = CreateAuthNeededObserver(); auto auth_supplied_waiter = CreateAuthSuppliedObserver(); LoginHandler* handler = - *LoginHandler::GetAllLoginHandlersForTest().begin(); + LoginHandler::GetAllLoginHandlersForTest().front(); ASSERT_TRUE(handler); handler->SetAuth(base::UTF8ToUTF16(bad_username_), @@ -531,7 +530,7 @@ } ASSERT_EQ(1u, LoginHandler::GetAllLoginHandlersForTest().size()); - SetAuthForAndWait(*LoginHandler::GetAllLoginHandlersForTest().begin()); + SetAuthForAndWait(LoginHandler::GetAllLoginHandlersForTest().front()); ExpectSuccessfulBasicAuthTitle(contents); } } @@ -578,7 +577,7 @@ } // Complete the authentication. - SetAuthForAndWait(*LoginHandler::GetAllLoginHandlersForTest().begin()); + SetAuthForAndWait(LoginHandler::GetAllLoginHandlersForTest().front()); ExpectSuccessfulBasicAuthTitle(contents); // Navigate away and go back again. @@ -635,7 +634,7 @@ } // Complete the authentication. - SetAuthForAndWait(*LoginHandler::GetAllLoginHandlersForTest().begin()); + SetAuthForAndWait(LoginHandler::GetAllLoginHandlersForTest().front()); content::WaitForLoadStop(contents); ASSERT_EQ(ExpectedTitleFromAuth(u"basicuser", u"secret"), content::EvalJs(contents, "subframe.contentDocument.title")); @@ -670,7 +669,7 @@ { auto auth_needed_waiter = CreateAuthNeededObserver(); auto auth_supplied_waiter = CreateAuthSuppliedObserver(); - LoginHandler* handler = *LoginHandler::GetAllLoginHandlersForTest().begin(); + LoginHandler* handler = LoginHandler::GetAllLoginHandlersForTest().front(); ASSERT_TRUE(handler); handler->SetAuth(base::UTF8ToUTF16(bad_username_), @@ -685,7 +684,7 @@ ASSERT_EQ(1u, LoginHandler::GetAllLoginHandlersForTest().size()); auto auth_supplied_waiter = CreateAuthSuppliedObserver(); - LoginHandler* handler = *LoginHandler::GetAllLoginHandlersForTest().begin(); + LoginHandler* handler = LoginHandler::GetAllLoginHandlersForTest().front(); std::u16string username(base::UTF8ToUTF16(username_digest_)); std::u16string password(base::UTF8ToUTF16(password_)); @@ -730,7 +729,7 @@ ASSERT_EQ(2u, LoginHandler::GetAllLoginHandlersForTest().size()); - LoginHandler* handler1 = *LoginHandler::GetAllLoginHandlersForTest().begin(); + LoginHandler* handler1 = LoginHandler::GetAllLoginHandlersForTest().front(); LoginHandler* handler2 = *(++(LoginHandler::GetAllLoginHandlersForTest().begin())); @@ -761,7 +760,7 @@ ui::PAGE_TRANSITION_TYPED, false)); auth_needed_waiter.Wait(); auto auth_cancelled_waiter = CreateAuthCancelledObserver(); - LoginHandler* handler = *LoginHandler::GetAllLoginHandlersForTest().begin(); + LoginHandler* handler = LoginHandler::GetAllLoginHandlersForTest().front(); ASSERT_TRUE(handler); content::TestNavigationObserver reload_observer( browser()->tab_strip_model()->GetActiveWebContents()); @@ -949,7 +948,7 @@ while (!LoginHandler::GetAllLoginHandlersForTest().empty()) { auto auth_cancelled_waiter = CreateAuthCancelledObserver(); LoginHandler* handler = - *LoginHandler::GetAllLoginHandlersForTest().begin(); + LoginHandler::GetAllLoginHandlersForTest().front(); ASSERT_TRUE(handler); handler->CancelAuth(); @@ -1008,7 +1007,7 @@ while (!LoginHandler::GetAllLoginHandlersForTest().empty()) { auto auth_cancelled_waiter = CreateAuthCancelledObserver(); LoginHandler* handler = - *LoginHandler::GetAllLoginHandlersForTest().begin(); + LoginHandler::GetAllLoginHandlersForTest().front(); ASSERT_TRUE(handler); handler->CancelAuth(); @@ -1057,7 +1056,7 @@ while (!LoginHandler::GetAllLoginHandlersForTest().empty()) { auto auth_cancelled_waiter = CreateAuthCancelledObserver(); LoginHandler* handler = - *LoginHandler::GetAllLoginHandlersForTest().begin(); + LoginHandler::GetAllLoginHandlersForTest().front(); ASSERT_TRUE(handler); handler->CancelAuth(); @@ -1124,7 +1123,7 @@ while (!LoginHandler::GetAllLoginHandlersForTest().empty()) { auto auth_cancelled_waiter = CreateAuthCancelledObserver(); LoginHandler* handler = - *LoginHandler::GetAllLoginHandlersForTest().begin(); + LoginHandler::GetAllLoginHandlersForTest().front(); ASSERT_TRUE(handler); // When a cross origin iframe displays a login prompt, the blank @@ -1180,7 +1179,7 @@ ASSERT_EQ(2U, LoginHandler::GetAllLoginHandlersForTest().size()); // Supply auth in one of the tabs. - SetAuthForAndWait(*LoginHandler::GetAllLoginHandlersForTest().begin()); + SetAuthForAndWait(LoginHandler::GetAllLoginHandlersForTest().front()); // Both tabs should be authenticated. EXPECT_EQ(2, browser_client_->auth_needed_count); @@ -1225,7 +1224,7 @@ ASSERT_EQ(2U, LoginHandler::GetAllLoginHandlersForTest().size()); // Cancel auth in one of the tabs. - LoginHandler* handler_1 = *LoginHandler::GetAllLoginHandlersForTest().begin(); + LoginHandler* handler_1 = LoginHandler::GetAllLoginHandlersForTest().front(); handler_1->CancelAuth(); // Both tabs should cancel auth. @@ -1269,7 +1268,7 @@ ASSERT_EQ(2U, LoginHandler::GetAllLoginHandlersForTest().size()); // Supply auth in regular tab, it should be authenticated. - SetAuthForAndWait(*LoginHandler::GetAllLoginHandlersForTest().begin()); + SetAuthForAndWait(LoginHandler::GetAllLoginHandlersForTest().front()); EXPECT_EQ(2, browser_client_->auth_needed_count); EXPECT_EQ(1, browser_client_->auth_supplied_count); @@ -1354,7 +1353,7 @@ { auto auth_needed_waiter = CreateAuthNeededObserver(); auto auth_supplied_waiter = CreateAuthSuppliedObserver(); - LoginHandler* handler = *LoginHandler::GetAllLoginHandlersForTest().begin(); + LoginHandler* handler = LoginHandler::GetAllLoginHandlersForTest().front(); ASSERT_TRUE(handler); handler->SetAuth(base::UTF8ToUTF16(bad_username_), @@ -1369,7 +1368,7 @@ ASSERT_EQ(1u, LoginHandler::GetAllLoginHandlersForTest().size()); auto auth_supplied_waiter = CreateAuthSuppliedObserver(); - LoginHandler* handler = *LoginHandler::GetAllLoginHandlersForTest().begin(); + LoginHandler* handler = LoginHandler::GetAllLoginHandlersForTest().front(); std::u16string username(base::UTF8ToUTF16(username_digest_)); std::u16string password(base::UTF8ToUTF16(password_)); @@ -1411,7 +1410,7 @@ ASSERT_EQ(1u, LoginHandler::GetAllLoginHandlersForTest().size()); auto auth_cancelled_waiter = CreateAuthCancelledObserver(); - LoginHandler* handler = *LoginHandler::GetAllLoginHandlersForTest().begin(); + LoginHandler* handler = LoginHandler::GetAllLoginHandlersForTest().front(); handler->CancelAuth(); auth_cancelled_waiter.Wait(); @@ -1446,7 +1445,7 @@ } ASSERT_EQ(1u, LoginHandler::GetAllLoginHandlersForTest().size()); - SetAuthForAndWait(*LoginHandler::GetAllLoginHandlersForTest().begin()); + SetAuthForAndWait(LoginHandler::GetAllLoginHandlersForTest().front()); ExpectSuccessfulBasicAuthTitle(contents); EXPECT_EQ(1, browser_client_->auth_needed_count); @@ -1479,7 +1478,7 @@ ui::PAGE_TRANSITION_TYPED, false)); auth_needed_waiter.Wait(); ASSERT_EQ(1u, LoginHandler::GetAllLoginHandlersForTest().size()); - SetAuthForAndWait(*LoginHandler::GetAllLoginHandlersForTest().begin()); + SetAuthForAndWait(LoginHandler::GetAllLoginHandlersForTest().front()); navigation_observer.Wait(); EXPECT_EQ(2, browser_client_->auth_needed_count); } @@ -1523,7 +1522,7 @@ auth_needed_waiter.Wait(); ASSERT_EQ(1u, LoginHandler::GetAllLoginHandlersForTest().size()); - SetAuthForAndWait(*LoginHandler::GetAllLoginHandlersForTest().begin()); + SetAuthForAndWait(LoginHandler::GetAllLoginHandlersForTest().front()); ExpectSuccessfulBasicAuthTitle(contents); EXPECT_EQ(1, browser_client_->auth_needed_count); @@ -1655,7 +1654,7 @@ EXPECT_EQ("www.b.com", contents->GetVisibleURL().host()); // Cancel auth dialog for www.b.com. - LoginHandler* handler = *LoginHandler::GetAllLoginHandlersForTest().begin(); + LoginHandler* handler = LoginHandler::GetAllLoginHandlersForTest().front(); handler->CancelAuth(); EXPECT_EQ("www.b.com", contents->GetVisibleURL().host()); } @@ -1699,7 +1698,7 @@ auth_needed_waiter.Wait(); ASSERT_EQ(1u, LoginHandler::GetAllLoginHandlersForTest().size()); // Cancel the auth prompt, which triggers a reload. - LoginHandler* handler = *LoginHandler::GetAllLoginHandlersForTest().begin(); + LoginHandler* handler = LoginHandler::GetAllLoginHandlersForTest().front(); content::TestNavigationObserver reload_observer(contents); handler->CancelAuth(); reload_observer.Wait(); @@ -1865,7 +1864,7 @@ ASSERT_EQ(1u, LoginHandler::GetAllLoginHandlersForTest().size()); // Test that credentials are handled correctly. - SetAuthForAndWait(*LoginHandler::GetAllLoginHandlersForTest().begin()); + SetAuthForAndWait(LoginHandler::GetAllLoginHandlersForTest().front()); ExpectSuccessfulBasicAuthTitle(contents); } @@ -1890,7 +1889,7 @@ // Enter credentials and test that the page loads. If the repost dialog is // shown, the test will hang while waiting for input. - SetAuthForAndWait(*LoginHandler::GetAllLoginHandlersForTest().begin()); + SetAuthForAndWait(LoginHandler::GetAllLoginHandlersForTest().front()); ExpectSuccessfulBasicAuthTitle(contents); } @@ -1927,7 +1926,7 @@ ASSERT_EQ(1u, LoginHandler::GetAllLoginHandlersForTest().size()); // Test that credentials are handled correctly. - SetAuthForAndWait(*LoginHandler::GetAllLoginHandlersForTest().begin()); + SetAuthForAndWait(LoginHandler::GetAllLoginHandlersForTest().front()); ExpectSuccessfulBasicAuthTitle(opened_contents); } @@ -2003,7 +2002,7 @@ auto auth_needed_waiter = CreateAuthNeededObserver(); ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), test_page)); auth_needed_waiter.Wait(); - SetAuthForAndWait(*LoginHandler::GetAllLoginHandlersForTest().begin()); + SetAuthForAndWait(LoginHandler::GetAllLoginHandlersForTest().front()); ExpectSuccessfulBasicAuthTitle(web_contents); // Now navigate to a page handled by HandleUnauthorized(), for which the @@ -2280,7 +2279,7 @@ // Cancel the auth prompt and check that the 401 response is displayed after // a reload. - LoginHandler* handler = *LoginHandler::GetAllLoginHandlersForTest().begin(); + LoginHandler* handler = LoginHandler::GetAllLoginHandlersForTest().front(); content::TestNavigationObserver reload_observer(web_contents); handler->CancelAuth(); reload_observer.Wait(); @@ -2296,7 +2295,7 @@ browser(), https_server.GetURL(kAuthBasicPage))); auth_needed_waiter.Wait(); EXPECT_FALSE(LoginHandler::GetAllLoginHandlersForTest().empty()); - SetAuthForAndWait(*LoginHandler::GetAllLoginHandlersForTest().begin()); + SetAuthForAndWait(LoginHandler::GetAllLoginHandlersForTest().front()); ExpectSuccessfulBasicAuthTitle(web_contents); } } @@ -2634,7 +2633,7 @@ ui::PAGE_TRANSITION_TYPED, false)); auth_needed_waiter.Wait(); // Complete the HTTP authentication. - SetAuthForAndWait(*LoginHandler::GetAllLoginHandlersForTest().begin()); + SetAuthForAndWait(LoginHandler::GetAllLoginHandlersForTest().front()); // The page without CCNS header should be restored from BFCache. ASSERT_TRUE(content::HistoryGoBack(contents_without_ccns)); @@ -2690,7 +2689,7 @@ ui::PAGE_TRANSITION_TYPED, false)); auth_needed_waiter.Wait(); // Complete the HTTP authentication. - SetAuthForAndWait(*LoginHandler::GetAllLoginHandlersForTest().begin()); + SetAuthForAndWait(LoginHandler::GetAllLoginHandlersForTest().front()); // The page with CCNS header should be evicted. ASSERT_TRUE(rfh_with_ccns.WaitUntilRenderFrameDeleted()); @@ -2746,7 +2745,7 @@ ui::PAGE_TRANSITION_TYPED, false)); auth_needed_waiter.Wait(); // Complete the HTTP authentication. - SetAuthForAndWait(*LoginHandler::GetAllLoginHandlersForTest().begin()); + SetAuthForAndWait(LoginHandler::GetAllLoginHandlersForTest().front()); // The page with CCNS header but with a different origin should be restored // from the BFCache.
diff --git a/chrome/browser/ui/login/login_handler_test_utils.cc b/chrome/browser/ui/login/login_handler_test_utils.cc deleted file mode 100644 index 1301d46e..0000000 --- a/chrome/browser/ui/login/login_handler_test_utils.cc +++ /dev/null
@@ -1,64 +0,0 @@ -// Copyright 2014 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/login/login_handler_test_utils.h" - -#include "base/containers/contains.h" -#include "base/ranges/algorithm.h" -#include "chrome/browser/ui/login/login_handler.h" -#include "testing/gtest/include/gtest/gtest.h" - -LoginPromptBrowserTestObserver::LoginPromptBrowserTestObserver() - : auth_needed_count_(0), auth_supplied_count_(0), auth_cancelled_count_(0) { -} - -LoginPromptBrowserTestObserver::~LoginPromptBrowserTestObserver() { -} - -void LoginPromptBrowserTestObserver::Observe( - int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) { - if (type == chrome::NOTIFICATION_AUTH_NEEDED) { - AddHandler(content::Details<LoginNotificationDetails>(details)->handler()); - auth_needed_count_++; - } else if (type == chrome::NOTIFICATION_AUTH_SUPPLIED) { - RemoveHandler(content::Details<AuthSuppliedLoginNotificationDetails>( - details)->handler()); - auth_supplied_count_++; - } else if (type == chrome::NOTIFICATION_AUTH_CANCELLED) { - RemoveHandler( - content::Details<LoginNotificationDetails>(details)->handler()); - auth_cancelled_count_++; - } -} - -void LoginPromptBrowserTestObserver::AddHandler(LoginHandler* handler) { - ASSERT_FALSE(base::Contains(handlers_, handler)); - handlers_.push_back(handler); -} - -void LoginPromptBrowserTestObserver::RemoveHandler(LoginHandler* handler) { - auto i = base::ranges::find(handlers_, handler); - // Cannot use ASSERT_NE, because gTest on Android confuses iterators with - // containers. - // - // TODO(davidben): NOTIFICATION_AUTH_SUPPLIED and NOTIFICATION_AUTH_CANCELLED - // are not quite guaranteed to come after NOTIFICATION_AUTH_NEEDED. Either - // remove this assumption from the test class or fix things so this assumption - // holds. - ASSERT_TRUE(i != handlers_.end()); - handlers_.erase(i); -} - -void LoginPromptBrowserTestObserver::Register( - const content::NotificationSource& source) { - registrar_.Add(this, chrome::NOTIFICATION_AUTH_NEEDED, source); - registrar_.Add(this, chrome::NOTIFICATION_AUTH_SUPPLIED, source); - registrar_.Add(this, chrome::NOTIFICATION_AUTH_CANCELLED, source); -} - -void LoginPromptBrowserTestObserver::UnregisterAll() { - registrar_.RemoveAll(); -}
diff --git a/chrome/browser/ui/login/login_handler_test_utils.h b/chrome/browser/ui/login/login_handler_test_utils.h deleted file mode 100644 index f2a6a31..0000000 --- a/chrome/browser/ui/login/login_handler_test_utils.h +++ /dev/null
@@ -1,90 +0,0 @@ -// Copyright 2014 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_LOGIN_LOGIN_HANDLER_TEST_UTILS_H_ -#define CHROME_BROWSER_UI_LOGIN_LOGIN_HANDLER_TEST_UTILS_H_ - -#include <list> - -#include "chrome/browser/auth_notification_types.h" -#include "content/public/browser/navigation_controller.h" -#include "content/public/browser/notification_observer.h" -#include "content/public/test/test_utils.h" - -class LoginHandler; - -// Maintains a set of LoginHandlers that are currently active and -// keeps a count of the notifications that were observed. -class LoginPromptBrowserTestObserver : public content::NotificationObserver { - public: - LoginPromptBrowserTestObserver(); - - LoginPromptBrowserTestObserver(const LoginPromptBrowserTestObserver&) = - delete; - LoginPromptBrowserTestObserver& operator=( - const LoginPromptBrowserTestObserver&) = delete; - - ~LoginPromptBrowserTestObserver() override; - - void Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) override; - - void AddHandler(LoginHandler* handler); - - void RemoveHandler(LoginHandler* handler); - - void Register(const content::NotificationSource& source); - void UnregisterAll(); - - const std::list<LoginHandler*>& handlers() const { return handlers_; } - - int auth_needed_count() const { return auth_needed_count_; } - int auth_supplied_count() const { return auth_supplied_count_; } - int auth_cancelled_count() const { return auth_cancelled_count_; } - - private: - std::list<LoginHandler*> handlers_; - - // The exact number of notifications we receive is depedent on the - // number of requests that were dispatched and is subject to a - // number of factors that we don't directly control here. The - // values below should only be used qualitatively. - int auth_needed_count_; - int auth_supplied_count_; - int auth_cancelled_count_; - - private: - content::NotificationRegistrar registrar_; -}; - -template <int T> -class WindowedNavigationObserver - : public content::WindowedNotificationObserver { - public: - explicit WindowedNavigationObserver( - content::NavigationController* controller); - - WindowedNavigationObserver(const WindowedNavigationObserver&) = delete; - WindowedNavigationObserver& operator=(const WindowedNavigationObserver&) = - delete; -}; - -template <int T> -WindowedNavigationObserver<T>::WindowedNavigationObserver( - content::NavigationController* controller) - : content::WindowedNotificationObserver( - T, content::Source<content::NavigationController>(controller)) { -} - -typedef WindowedNavigationObserver<chrome::NOTIFICATION_AUTH_NEEDED> - WindowedAuthNeededObserver; - -typedef WindowedNavigationObserver<chrome::NOTIFICATION_AUTH_CANCELLED> - WindowedAuthCancelledObserver; - -typedef WindowedNavigationObserver<chrome::NOTIFICATION_AUTH_SUPPLIED> - WindowedAuthSuppliedObserver; - -#endif // CHROME_BROWSER_UI_LOGIN_LOGIN_HANDLER_TEST_UTILS_H_
diff --git a/chrome/browser/ui/messages/android/BUILD.gn b/chrome/browser/ui/messages/android/BUILD.gn index 37906ac3..3166c22 100644 --- a/chrome/browser/ui/messages/android/BUILD.gn +++ b/chrome/browser/ui/messages/android/BUILD.gn
@@ -36,6 +36,8 @@ ":java_resources", "//base:base_java", "//build/android:build_java", + "//chrome/browser/ui/android/edge_to_edge:factory_java", + "//chrome/browser/ui/android/edge_to_edge:java", "//chrome/browser/util:java", "//components/browser_ui/styles/android:java", "//components/browser_ui/styles/android:java_resources",
diff --git a/chrome/browser/ui/messages/android/java/src/org/chromium/chrome/browser/ui/messages/snackbar/SnackbarManager.java b/chrome/browser/ui/messages/android/java/src/org/chromium/chrome/browser/ui/messages/snackbar/SnackbarManager.java index bf27dad..007f5ae 100644 --- a/chrome/browser/ui/messages/android/java/src/org/chromium/chrome/browser/ui/messages/snackbar/SnackbarManager.java +++ b/chrome/browser/ui/messages/android/java/src/org/chromium/chrome/browser/ui/messages/snackbar/SnackbarManager.java
@@ -20,20 +20,26 @@ import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.supplier.ObservableSupplier; import org.chromium.base.supplier.ObservableSupplierImpl; +import org.chromium.chrome.browser.ui.edge_to_edge.EdgeToEdgeSupplier; +import org.chromium.components.browser_ui.widget.InsetObserver; import org.chromium.ui.accessibility.AccessibilityState; import org.chromium.ui.base.WindowAndroid; /** * Manager for the snackbar showing at the bottom of activity. There should be only one * SnackbarManager and one snackbar in the activity. - * <p/> - * When action button is clicked, this manager will call {@link SnackbarController#onAction(Object)} - * in corresponding listener, and show the next entry. Otherwise if no action is taken by user - * during {@link #DEFAULT_SNACKBAR_DURATION_MS} milliseconds, it will call - * {@link SnackbarController#onDismissNoAction(Object)}. Note, snackbars of - * {@link Snackbar#TYPE_PERSISTENT} do not get automatically dismissed after a timeout. + * + * <p>When action button is clicked, this manager will call {@link + * SnackbarController#onAction(Object)} in corresponding listener, and show the next entry. + * Otherwise if no action is taken by user during {@link #DEFAULT_SNACKBAR_DURATION_MS} + * milliseconds, it will call {@link SnackbarController#onDismissNoAction(Object)}. Note, snackbars + * of {@link Snackbar#TYPE_PERSISTENT} do not get automatically dismissed after a timeout. */ -public class SnackbarManager implements OnClickListener, ActivityStateListener, UnownedUserData { +public class SnackbarManager + implements OnClickListener, + ActivityStateListener, + UnownedUserData, + InsetObserver.WindowInsetObserver { /** Interface that shows the ability to provide a snackbar manager. */ public interface SnackbarManageable { /** @@ -77,7 +83,10 @@ private boolean mIsDisabledForTesting; private ViewGroup mSnackbarParentView; private ViewGroup mSnackbarTemporaryParentView; + // Keyboard inset handling is independent of the EdgeToEdge handling. + private int mKeyboardInset; private final WindowAndroid mWindowAndroid; + private @Nullable EdgeToEdgeSupplier mEdgeToEdgeSupplier; private final Runnable mHideRunnable = new Runnable() { @Override @@ -91,10 +100,11 @@ /** * Constructs a SnackbarManager to show snackbars in the given window. + * * @param activity The embedding activity. * @param snackbarParentView The ViewGroup used to display this snackbar. * @param windowAndroid The WindowAndroid used for starting animation. If it is null, - * Animator#start is called instead. + * Animator#start is called instead. */ public SnackbarManager( Activity activity, @@ -249,6 +259,20 @@ } /** + * @param supplier The supplier publishes the changes of the edge-to-edge state and the expected + * bottom paddings when edge-to-edge is on. + */ + public void setEdgeToEdgeSupplier(@Nullable EdgeToEdgeSupplier supplier) { + mEdgeToEdgeSupplier = supplier; + } + + @Override + public void onKeyboardInsetChanged(int inset) { + mKeyboardInset = inset; + updateView(); + } + + /** * Updates the {@link SnackbarView} to reflect the value of mSnackbars.currentSnackbar(), which * may be null. This might show, change, or hide the view. */ @@ -270,7 +294,9 @@ this, currentSnackbar, mSnackbarParentView, - mWindowAndroid); + mWindowAndroid, + mEdgeToEdgeSupplier); + mView.updateKeyboardInset(mKeyboardInset); mView.show(); // If there is a temporary parent set, reparent accordingly. We override here @@ -280,6 +306,7 @@ mView.overrideParent(mSnackbarTemporaryParentView); } } else { + mView.updateKeyboardInset(mKeyboardInset); viewChanged = mView.update(currentSnackbar); }
diff --git a/chrome/browser/ui/messages/android/java/src/org/chromium/chrome/browser/ui/messages/snackbar/SnackbarView.java b/chrome/browser/ui/messages/android/java/src/org/chromium/chrome/browser/ui/messages/snackbar/SnackbarView.java index e5dd407..ed70d7e 100644 --- a/chrome/browser/ui/messages/android/java/src/org/chromium/chrome/browser/ui/messages/snackbar/SnackbarView.java +++ b/chrome/browser/ui/messages/android/java/src/org/chromium/chrome/browser/ui/messages/snackbar/SnackbarView.java
@@ -8,7 +8,6 @@ import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.app.Activity; -import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.text.TextUtils; @@ -27,8 +26,12 @@ import androidx.annotation.Nullable; import org.chromium.base.ApiCompatibilityUtils; +import org.chromium.chrome.browser.ui.edge_to_edge.EdgeToEdgeControllerFactory; +import org.chromium.chrome.browser.ui.edge_to_edge.EdgeToEdgePadAdjuster; +import org.chromium.chrome.browser.ui.edge_to_edge.EdgeToEdgeSupplier; import org.chromium.chrome.ui.messages.R; import org.chromium.components.browser_ui.styles.SemanticColorUtils; +import org.chromium.components.browser_ui.widget.InsetObserver; import org.chromium.components.browser_ui.widget.text.TemplatePreservingTextView; import org.chromium.ui.base.DeviceFormFactor; import org.chromium.ui.base.WindowAndroid; @@ -40,7 +43,7 @@ */ // TODO (jianli): Change this class and its methods back to package protected after the offline // indicator experiment is done. -public class SnackbarView { +public class SnackbarView implements InsetObserver.WindowInsetObserver { private static final int MAX_LINES = 5; private final WindowAndroid mWindowAndroid; @@ -51,16 +54,19 @@ private final ImageView mProfileImageView; private final int mAnimationDuration; private final boolean mIsTablet; + @Nullable private final EdgeToEdgeSupplier mEdgeToEdgeSupplier; + @Nullable private final EdgeToEdgePadAdjuster mEdgeToEdgePadAdjuster; private ViewGroup mOriginalParent; protected ViewGroup mParent; protected Snackbar mSnackbar; private View mRootContentView; // Variables used to calculate the virtual keyboard's height. - private Rect mCurrentVisibleRect = new Rect(); - private Rect mPreviousVisibleRect = new Rect(); - private int[] mTempLocation = new int[2]; + private int mPreviousKeyboardInset; + private int mKeyboardInset; + // Extra inset when edge to edge is on. + private int mEdgeInset; private OnLayoutChangeListener mLayoutListener = new OnLayoutChangeListener() { @Override @@ -80,13 +86,14 @@ /** * Creates an instance of the {@link SnackbarView}. + * * @param activity The activity that displays the snackbar. * @param listener An {@link OnClickListener} that will be called when the action button is - * clicked. + * clicked. * @param snackbar The snackbar to be displayed. * @param parentView The ViewGroup used to display this snackbar. * @param windowAndroid The WindowAndroid used for starting animation. If it is null, - * Animator#start is called instead. + * Animator#start is called instead. */ public SnackbarView( Activity activity, @@ -94,6 +101,29 @@ Snackbar snackbar, ViewGroup parentView, @Nullable WindowAndroid windowAndroid) { + this(activity, listener, snackbar, parentView, windowAndroid, null); + } + + /** + * Creates an instance of the {@link SnackbarView}. + * + * @param activity The activity that displays the snackbar. + * @param listener An {@link OnClickListener} that will be called when the action button is + * clicked. + * @param snackbar The snackbar to be displayed. + * @param parentView The ViewGroup used to display this snackbar. + * @param windowAndroid The WindowAndroid used for starting animation. If it is null, + * Animator#start is called instead. + * @param edgeToEdgeSupplier The supplier publishes the changes of the edge-to-edge state and + * the expected bottom paddings when edge-to-edge is on. + */ + public SnackbarView( + Activity activity, + OnClickListener listener, + Snackbar snackbar, + ViewGroup parentView, + @Nullable WindowAndroid windowAndroid, + @Nullable EdgeToEdgeSupplier edgeToEdgeSupplier) { mIsTablet = DeviceFormFactor.isNonMultiDisplayContextOnTablet(activity); mOriginalParent = parentView; mWindowAndroid = windowAndroid; @@ -111,6 +141,11 @@ mActionButtonView = (TextView) mContainerView.findViewById(R.id.snackbar_button); mActionButtonView.setOnClickListener(listener); mProfileImageView = (ImageView) mContainerView.findViewById(R.id.snackbar_profile_image); + mEdgeToEdgeSupplier = edgeToEdgeSupplier; + mEdgeToEdgePadAdjuster = + edgeToEdgeSupplier != null + ? EdgeToEdgeControllerFactory.createForView(mSnackbarView) + : null; updateInternal(snackbar, false); } @@ -131,6 +166,7 @@ int oldRight, int oldBottom) { mContainerView.removeOnLayoutChangeListener(this); + mContainerView.setTranslationY(getYPositionForMoveAnimation()); Animator animator = ObjectAnimator.ofFloat(mContainerView, View.TRANSLATION_Y, 0); @@ -139,6 +175,9 @@ startAnimatorOnSurfaceView(animator); } }); + if (mEdgeToEdgeSupplier != null) { + mEdgeToEdgeSupplier.registerAdjuster(mEdgeToEdgePadAdjuster); + } } public void dismiss() { @@ -156,17 +195,20 @@ public void onAnimationEnd(Animator animation) { mRootContentView.removeOnLayoutChangeListener(mLayoutListener); mParent.removeView(mContainerView); + } }); startAnimatorOnSurfaceView(moveAnimator); + if (mEdgeToEdgeSupplier != null) { + mEdgeToEdgeSupplier.unregisterAdjuster(mEdgeToEdgePadAdjuster); + } } /** Adjusts the position of the snackbar on top of the soft keyboard, if any. */ void adjustViewPosition() { - mParent.getWindowVisibleDisplayFrame(mCurrentVisibleRect); // Only update if the visible frame has changed, otherwise there will be a layout loop. - if (!mCurrentVisibleRect.equals(mPreviousVisibleRect)) { - mPreviousVisibleRect.set(mCurrentVisibleRect); + if (mKeyboardInset != mPreviousKeyboardInset) { + mPreviousKeyboardInset = mKeyboardInset; FrameLayout.LayoutParams lp = getLayoutParams(); @@ -184,7 +226,6 @@ lp.width = Math.min(width, mParent.getWidth() - 2 * margin); lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM; } - if (prevBottomMargin != lp.bottomMargin || prevWidth != lp.width || prevGravity != lp.gravity) { @@ -193,21 +234,28 @@ } } + void updateKeyboardInset(int inset) { + mKeyboardInset = inset; + adjustViewPosition(); + } + + void updateEdgeInset(int inset) { + mEdgeInset = inset; + adjustViewPosition(); + } + protected int getYPositionForMoveAnimation() { return mContainerView.getHeight() + getLayoutParams().bottomMargin; } protected int getBottomMarginForLayout() { - mParent.getLocationInWindow(mTempLocation); - int keyboardHeight = mParent.getHeight() + mTempLocation[1] - mCurrentVisibleRect.bottom; - return Math.max(0, keyboardHeight); + return mKeyboardInset; } /** * @see SnackbarManager#overrideParent(ViewGroup) */ void overrideParent(ViewGroup overridingParent) { - mRootContentView.removeOnLayoutChangeListener(mLayoutListener); mParent = overridingParent == null ? mOriginalParent : overridingParent; if (mContainerView.getParent() != null) { ((ViewGroup) mContainerView.getParent()).removeView(mContainerView); @@ -264,12 +312,6 @@ private void addToParent() { mParent.addView(mContainerView); - - // Why setting listener on parent? It turns out that if we force a relayout in the layout - // change listener of the view itself, the force layout flag will be reset to 0 when - // layout() returns. Therefore we have to do request layout on one level above the requested - // view. - mRootContentView.addOnLayoutChangeListener(mLayoutListener); } // TODO(fgorski): Start using color ID, to remove the view from arguments. @@ -397,4 +439,12 @@ view.setText(text); } } + + public ViewGroup getViewForTesting() { + return mSnackbarView; + } + + public EdgeToEdgePadAdjuster getEdgeToEdgePadAdjusterForTesting() { + return mEdgeToEdgePadAdjuster; + } }
diff --git a/chrome/browser/ui/quick_answers/ui/user_consent_view.cc b/chrome/browser/ui/quick_answers/ui/user_consent_view.cc index 7239df0..2b14696 100644 --- a/chrome/browser/ui/quick_answers/ui/user_consent_view.cc +++ b/chrome/browser/ui/quick_answers/ui/user_consent_view.cc
@@ -344,7 +344,7 @@ l10n_util::GetStringUTF16( IDS_QUICK_ANSWERS_USER_CONSENT_VIEW_ALLOW_BUTTON), ShouldUseCompactButtonLayout(anchor_view_bounds_.width())); - allow_button->SetProminent(true); + allow_button->SetStyle(ui::ButtonStyle::kProminent); allow_button_ = button_bar->AddChildView(std::move(allow_button)); }
diff --git a/chrome/browser/ui/side_panel/read_anything/read_anything_tab_helper.cc b/chrome/browser/ui/side_panel/read_anything/read_anything_tab_helper.cc index 9705158d..90982ad 100644 --- a/chrome/browser/ui/side_panel/read_anything/read_anything_tab_helper.cc +++ b/chrome/browser/ui/side_panel/read_anything/read_anything_tab_helper.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/ui/side_panel/read_anything/read_anything_tab_helper.h" #include "chrome/browser/ui/side_panel/read_anything/read_anything_side_panel_controller_utils.h" +#include "chrome/browser/ui/webui/side_panel/read_anything/read_anything_untrusted_page_handler.h" ReadAnythingTabHelper::ReadAnythingTabHelper(content::WebContents* web_contents) : content::WebContentsUserData<ReadAnythingTabHelper>(*web_contents), @@ -22,4 +23,16 @@ delegate_->DeregisterEntry(); } +void ReadAnythingTabHelper::AddPageHandlerAsObserver( + base::WeakPtr<ReadAnythingUntrustedPageHandler> page_handler) { + CHECK(delegate_); + delegate_->AddPageHandlerAsObserver(page_handler); +} + +void ReadAnythingTabHelper::RemovePageHandlerAsObserver( + base::WeakPtr<ReadAnythingUntrustedPageHandler> page_handler) { + CHECK(delegate_); + delegate_->RemovePageHandlerAsObserver(page_handler); +} + WEB_CONTENTS_USER_DATA_KEY_IMPL(ReadAnythingTabHelper);
diff --git a/chrome/browser/ui/side_panel/read_anything/read_anything_tab_helper.h b/chrome/browser/ui/side_panel/read_anything/read_anything_tab_helper.h index ef274bc..ac75519 100644 --- a/chrome/browser/ui/side_panel/read_anything/read_anything_tab_helper.h +++ b/chrome/browser/ui/side_panel/read_anything/read_anything_tab_helper.h
@@ -11,6 +11,8 @@ class WebContents; } // namespace content +class ReadAnythingUntrustedPageHandler; + // An observer of WebContents that facilitates the logic for the Read Anything // side panel. This per-tab class also owns the ReadAnythingSidePanelController. class ReadAnythingTabHelper @@ -22,6 +24,10 @@ public: virtual void CreateAndRegisterEntry() = 0; virtual void DeregisterEntry() = 0; + virtual void AddPageHandlerAsObserver( + base::WeakPtr<ReadAnythingUntrustedPageHandler> page_handler) = 0; + virtual void RemovePageHandlerAsObserver( + base::WeakPtr<ReadAnythingUntrustedPageHandler> page_handler) = 0; virtual ~Delegate() = default; }; @@ -36,6 +42,11 @@ // Deregisters the Read Anything side panel entry. void DeregisterEntry(); + void AddPageHandlerAsObserver( + base::WeakPtr<ReadAnythingUntrustedPageHandler> page_handler); + void RemovePageHandlerAsObserver( + base::WeakPtr<ReadAnythingUntrustedPageHandler> page_handler); + private: friend class content::WebContentsUserData<ReadAnythingTabHelper>;
diff --git a/chrome/browser/ui/side_panel/side_panel_enums.h b/chrome/browser/ui/side_panel/side_panel_enums.h index 46b14812..a2300ea 100644 --- a/chrome/browser/ui/side_panel/side_panel_enums.h +++ b/chrome/browser/ui/side_panel/side_panel_enums.h
@@ -28,7 +28,8 @@ kOpenedInNewTabFromSidePanel = 14, kReadAnythingOmniboxIcon = 15, kReadAnythingNavigationThrottle = 16, - kMaxValue = kReadAnythingNavigationThrottle, + kOverflowMenu = 17, + kMaxValue = kOverflowMenu, }; #endif // CHROME_BROWSER_UI_SIDE_PANEL_SIDE_PANEL_ENUMS_H_
diff --git a/chrome/browser/ui/tabs/organization/tab_organization_service.cc b/chrome/browser/ui/tabs/organization/tab_organization_service.cc index 9ac37a3..d090566 100644 --- a/chrome/browser/ui/tabs/organization/tab_organization_service.cc +++ b/chrome/browser/ui/tabs/organization/tab_organization_service.cc
@@ -44,7 +44,7 @@ trigger_observer_ = std::make_unique<TabOrganizationTriggerObserver>( base::BindRepeating(&TabOrganizationService::OnTriggerOccured, base::Unretained(this)), - browser_context, MakeMVPTrigger(std::move(trigger_backoff))); + browser_context, MakeTrigger(std::move(trigger_backoff))); } TabOrganizationService::~TabOrganizationService() = default;
diff --git a/chrome/browser/ui/tabs/organization/trigger.cc b/chrome/browser/ui/tabs/organization/trigger.cc index f1c42eb..fcc971bb 100644 --- a/chrome/browser/ui/tabs/organization/trigger.cc +++ b/chrome/browser/ui/tabs/organization/trigger.cc
@@ -18,8 +18,7 @@ namespace { // Just counts the number of tabs in the browser. -float MVPScoringFunction(float sensitivity_threshold, - TabStripModel* const model) { +float ScoringFunction(float sensitivity_threshold, TabStripModel* const model) { // Feature may be disabled in tests, in which case GetForProfile will CHECK. const TabOrganizationService* const service = base::FeatureList::IsEnabled(features::kTabOrganization) @@ -65,21 +64,24 @@ return policy_->ShouldTrigger(score); } -TriggerScoringFunction GetDefaultTriggerScoringFunction() { - return base::BindRepeating(&MVPScoringFunction, - GetDefaultSensitivityThreshold()); +TriggerScoringFunction GetTriggerScoringFunction() { + return base::BindRepeating(&ScoringFunction, GetSensitivityThreshold()); } -float GetDefaultTriggerScoreThreshold() { +float GetTriggerScoreThreshold() { return features::kTabOrganizationTriggerThreshold.Get(); } -float GetDefaultSensitivityThreshold() { +float GetSensitivityThreshold() { return features::kTabOrganizationTriggerSensitivityThreshold.Get(); } -std::unique_ptr<TriggerPolicy> GetDefaultTriggerPolicy( +std::unique_ptr<TriggerPolicy> GetTriggerPolicy( std::unique_ptr<BackoffLevelProvider> backoff_level_provider) { + if (features::KTabOrganizationTriggerDemoMode.Get()) { + return std::make_unique<DemoTriggerPolicy>(); + } + return std::make_unique<TargetFrequencyTriggerPolicy>( std::make_unique<UsageTickClock>(base::DefaultTickClock::GetInstance()), features::kTabOrganizationTriggerPeriod.Get(), @@ -87,9 +89,9 @@ std::move(backoff_level_provider)); } -std::unique_ptr<TabOrganizationTrigger> MakeMVPTrigger( +std::unique_ptr<TabOrganizationTrigger> MakeTrigger( std::unique_ptr<BackoffLevelProvider> backoff_level_provider) { return std::make_unique<TabOrganizationTrigger>( - GetDefaultTriggerScoringFunction(), GetDefaultTriggerScoreThreshold(), - GetDefaultTriggerPolicy(std::move(backoff_level_provider))); + GetTriggerScoringFunction(), GetTriggerScoreThreshold(), + GetTriggerPolicy(std::move(backoff_level_provider))); }
diff --git a/chrome/browser/ui/tabs/organization/trigger.h b/chrome/browser/ui/tabs/organization/trigger.h index 83a8ada..48f7db0 100644 --- a/chrome/browser/ui/tabs/organization/trigger.h +++ b/chrome/browser/ui/tabs/organization/trigger.h
@@ -45,13 +45,13 @@ std::unique_ptr<TriggerPolicy> policy_; }; -TriggerScoringFunction GetDefaultTriggerScoringFunction(); -float GetDefaultTriggerScoreThreshold(); -float GetDefaultSensitivityThreshold(); -std::unique_ptr<TriggerPolicy> GetDefaultTriggerPolicy( +TriggerScoringFunction GetTriggerScoringFunction(); +float GetTriggerScoreThreshold(); +float GetSensitivityThreshold(); +std::unique_ptr<TriggerPolicy> GetTriggerPolicy( std::unique_ptr<BackoffLevelProvider> backoff_level_provider); -std::unique_ptr<TabOrganizationTrigger> MakeMVPTrigger( +std::unique_ptr<TabOrganizationTrigger> MakeTrigger( std::unique_ptr<BackoffLevelProvider> backoff_level_provider); #endif // CHROME_BROWSER_UI_TABS_ORGANIZATION_TRIGGER_H_
diff --git a/chrome/browser/ui/tabs/organization/trigger_policies.cc b/chrome/browser/ui/tabs/organization/trigger_policies.cc index 2ffd907..e6c21c72 100644 --- a/chrome/browser/ui/tabs/organization/trigger_policies.cc +++ b/chrome/browser/ui/tabs/organization/trigger_policies.cc
@@ -132,10 +132,6 @@ backoff_level_provider_->Increment(); } -bool GreedyTriggerPolicy::ShouldTrigger(float score) { - if (has_triggered_) { - return false; - } - has_triggered_ = true; +bool DemoTriggerPolicy::ShouldTrigger(float score) { return true; }
diff --git a/chrome/browser/ui/tabs/organization/trigger_policies.h b/chrome/browser/ui/tabs/organization/trigger_policies.h index 359483ce..43c3187 100644 --- a/chrome/browser/ui/tabs/organization/trigger_policies.h +++ b/chrome/browser/ui/tabs/organization/trigger_policies.h
@@ -123,8 +123,8 @@ bool has_triggered_ = false; }; -// Trigger only first time a trigger moment occurs. -class GreedyTriggerPolicy final : public TriggerPolicy { +// Trigger every time. Very spammy, but suitable for testing or demoing. +class DemoTriggerPolicy final : public TriggerPolicy { public: bool ShouldTrigger(float score) override;
diff --git a/chrome/browser/ui/tabs/organization/trigger_unittest.cc b/chrome/browser/ui/tabs/organization/trigger_unittest.cc index 0fd9efe..1cdb6ac 100644 --- a/chrome/browser/ui/tabs/organization/trigger_unittest.cc +++ b/chrome/browser/ui/tabs/organization/trigger_unittest.cc
@@ -52,10 +52,10 @@ const std::unique_ptr<TabStripModel> tab_strip_model_; }; -TEST_F(TriggerTest, MVPTriggerHappyPath) { +TEST_F(TriggerTest, TriggerHappyPath) { auto trigger = std::make_unique<TabOrganizationTrigger>( - GetDefaultTriggerScoringFunction(), GetDefaultTriggerScoreThreshold(), - std::make_unique<GreedyTriggerPolicy>()); + GetTriggerScoringFunction(), GetTriggerScoreThreshold(), + std::make_unique<DemoTriggerPolicy>()); // Should not trigger under the score threshold. EXPECT_FALSE(trigger->ShouldTrigger(tab_strip_model())); @@ -66,6 +66,6 @@ } EXPECT_TRUE(trigger->ShouldTrigger(tab_strip_model())); - // Should trigger only once (because GreedyTriggerPolicy). - EXPECT_FALSE(trigger->ShouldTrigger(tab_strip_model())); + // Should trigger every time (because DemoTriggerPolicy). + EXPECT_TRUE(trigger->ShouldTrigger(tab_strip_model())); }
diff --git a/chrome/browser/ui/ui_features.cc b/chrome/browser/ui/ui_features.cc index 83aff85..39a628a 100644 --- a/chrome/browser/ui/ui_features.cc +++ b/chrome/browser/ui/ui_features.cc
@@ -270,6 +270,9 @@ const base::FeatureParam<double> kTabOrganizationTriggerSensitivityThreshold{ &kTabOrganization, "trigger_sensitivity_threshold", 0.5}; +const base::FeatureParam<bool> KTabOrganizationTriggerDemoMode{ + &kTabOrganization, "trigger_demo_mode", false}; + BASE_FEATURE(kTabOrganizationRefreshButton, "TabOrganizationRefreshButton", base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/chrome/browser/ui/ui_features.h b/chrome/browser/ui/ui_features.h index 1780782e..1f36a74a 100644 --- a/chrome/browser/ui/ui_features.h +++ b/chrome/browser/ui/ui_features.h
@@ -149,6 +149,10 @@ extern const base::FeatureParam<double> kTabOrganizationTriggerSensitivityThreshold; +// Enable 'demo mode' for Tab Organization triggering, which triggers much more +// predictably and frequently. +extern const base::FeatureParam<bool> KTabOrganizationTriggerDemoMode; + BASE_DECLARE_FEATURE(kTabOrganizationRefreshButton); BASE_DECLARE_FEATURE(kTabSearchChevronIcon);
diff --git a/chrome/browser/ui/views/autofill/payments/offer_notification_bubble_views.cc b/chrome/browser/ui/views/autofill/payments/offer_notification_bubble_views.cc index 26a9646..3f33838 100644 --- a/chrome/browser/ui/views/autofill/payments/offer_notification_bubble_views.cc +++ b/chrome/browser/ui/views/autofill/payments/offer_notification_bubble_views.cc
@@ -22,6 +22,7 @@ #include "components/autofill/core/common/autofill_payments_features.h" #include "components/commerce/core/commerce_feature_list.h" #include "components/strings/grit/components_strings.h" +#include "components/url_formatter/elide_url.h" #include "net/base/registry_controlled_domains/registry_controlled_domain.h" #include "ui/base/clipboard/clipboard_buffer.h" #include "ui/base/clipboard/scoped_clipboard_writer.h" @@ -155,9 +156,7 @@ SetLayoutManager(std::make_unique<views::FillLayout>()); GURL url = web_contents()->GetLastCommittedURL(); - std::string seller_domain = - net::registry_controlled_domains::GetDomainAndRegistry( - url, net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); + std::string seller_domain = url.spec(); free_listing_coupon_page_container_ = AddChildView(std::make_unique<PageSwitcherView>( @@ -377,10 +376,15 @@ AutofillOfferData offer, std::string seller_domain) { ResetPointersToFreeListingCouponOfferMainPageContent(); + auto bubble_width = views::LayoutProvider::Get()->GetDistanceMetric( + views::DISTANCE_BUBBLE_PREFERRED_WIDTH); - auto footer_message = - l10n_util::GetStringFUTF16(IDS_SELLER_TERMS_AND_CONDITIONS_DIALOG_FOOTER, - base::ASCIIToUTF16(seller_domain)); + gfx::FontList font_list = views::TypographyProvider::Get().GetFont( + views::style::CONTEXT_LABEL, views::style::STYLE_PRIMARY); + + auto footer_message = l10n_util::GetStringFUTF16( + IDS_SELLER_TERMS_AND_CONDITIONS_DIALOG_FOOTER, + url_formatter::ElideHost(GURL(seller_domain), font_list, bubble_width)); free_listing_coupon_page_container_->SwitchToPage( views::Builder<SubpageView>( std::make_unique<SubpageView>( @@ -400,13 +404,10 @@ .Build()) .SetHeaderView(nullptr) .SetFootnoteView( - // TODO(b:289240484): Need to elide the front of the seller_domain - // if needed. views::Builder<views::Label>() .SetText(footer_message) .SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT) .SetMultiLine(true) - .SetMaxLines(2) .SetAllowCharacterBreak(true) .Build()) .Build());
diff --git a/chrome/browser/ui/views/autofill/payments/save_card_offer_bubble_views.cc b/chrome/browser/ui/views/autofill/payments/save_card_offer_bubble_views.cc index b4db7fd..9f00b7b 100644 --- a/chrome/browser/ui/views/autofill/payments/save_card_offer_bubble_views.cc +++ b/chrome/browser/ui/views/autofill/payments/save_card_offer_bubble_views.cc
@@ -269,33 +269,6 @@ return view; } -std::unique_ptr<LegalMessageView> -SaveCardOfferBubbleViews::CreateLegalMessageView() { - const LegalMessageLines message_lines = controller()->GetLegalMessageLines(); - - if (message_lines.empty()) { - return nullptr; - } - - LegalMessageView::LinkClickedCallback LegalMessageCallBack = - base::BindRepeating(&SaveCardOfferBubbleViews::LinkClicked, - base::Unretained(this)); - - if (base::FeatureList::IsEnabled( - features::kAutofillEnableNewSaveCardBubbleUi) || - base::FeatureList::IsEnabled( - features::kAutofillEnableUserAvatarInSaveCardFooter)) { - return (std::make_unique<LegalMessageView>( - message_lines, base::UTF8ToUTF16(controller()->GetAccountInfo().email), - GetProfileAvatar(controller()->GetAccountInfo()), - LegalMessageCallBack)); - } - - return std::make_unique<LegalMessageView>( - message_lines, /*user_email=*/std::u16string(), - /*user_avatar=*/ui::ImageModel(), LegalMessageCallBack); -} - std::unique_ptr<views::View> SaveCardOfferBubbleViews::CreateRequestExpirationDateView() { auto expiration_date_view = std::make_unique<views::View>(); @@ -381,6 +354,33 @@ return upload_explanation_tooltip; } +std::unique_ptr<LegalMessageView> +SaveCardOfferBubbleViews::CreateLegalMessageView() { + const LegalMessageLines message_lines = controller()->GetLegalMessageLines(); + + if (message_lines.empty()) { + return nullptr; + } + + LegalMessageView::LinkClickedCallback LegalMessageCallBack = + base::BindRepeating(&SaveCardOfferBubbleViews::LinkClicked, + base::Unretained(this)); + + if (base::FeatureList::IsEnabled( + features::kAutofillEnableNewSaveCardBubbleUi) || + base::FeatureList::IsEnabled( + features::kAutofillEnableUserAvatarInSaveCardFooter)) { + return (std::make_unique<LegalMessageView>( + message_lines, base::UTF8ToUTF16(controller()->GetAccountInfo().email), + GetProfileAvatar(controller()->GetAccountInfo()), + LegalMessageCallBack)); + } + + return std::make_unique<LegalMessageView>( + message_lines, /*user_email=*/std::u16string(), + /*user_avatar=*/ui::ImageModel(), LegalMessageCallBack); +} + void SaveCardOfferBubbleViews::LinkClicked(const GURL& url) { if (controller()) controller()->OnLegalMessageLinkClicked(url);
diff --git a/chrome/browser/ui/views/download/download_danger_prompt_views.cc b/chrome/browser/ui/views/download/download_danger_prompt_views.cc index a872d2c..5801755a 100644 --- a/chrome/browser/ui/views/download/download_danger_prompt_views.cc +++ b/chrome/browser/ui/views/download/download_danger_prompt_views.cc
@@ -8,6 +8,7 @@ #include "base/strings/utf_string_conversions.h" #include "chrome/browser/download/download_danger_prompt.h" #include "chrome/browser/download/download_stats.h" +#include "chrome/browser/download/download_ui_safe_browsing_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/safe_browsing/advanced_protection_status_manager.h" #include "chrome/browser/safe_browsing/advanced_protection_status_manager_factory.h" @@ -73,6 +74,8 @@ // If show_context_ is true, this is a download confirmation dialog by // download API, otherwise it is download recovery dialog from a regular // download. + // TODO(chlily): Remove this after ImprovedDownloadPageWarnings launches, + // because then this will only ever be shown for download API. const bool show_context_; OnDone done_; }; @@ -284,7 +287,13 @@ DownloadItemWarningData::WarningAction::PROCEED); } } - RecordDownloadDangerPrompt(accept, *download_); + // Log here for "Shown" unconditionally, and for "Proceed" iff the dialog + // was accepted. This assumes the dialog cannot be dismissed once it is + // shown without taking some action on it. + RecordDownloadDangerPromptHistogram("Shown", *download_); + if (accept) { + RecordDownloadDangerPromptHistogram("Proceed", *download_); + } RecordDownloadWarningEvent(action, download_); if (!download_->GetURL().is_empty() && !content::DownloadItemUtils::GetBrowserContext(download_)
diff --git a/chrome/browser/ui/views/file_system_access/file_system_access_restore_permission_bubble_view.cc b/chrome/browser/ui/views/file_system_access/file_system_access_restore_permission_bubble_view.cc index ac8b94fb..5b674baa 100644 --- a/chrome/browser/ui/views/file_system_access/file_system_access_restore_permission_bubble_view.cc +++ b/chrome/browser/ui/views/file_system_access/file_system_access_restore_permission_bubble_view.cc
@@ -6,9 +6,8 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser_finder.h" -#include "chrome/browser/ui/color/chrome_color_id.h" #include "chrome/browser/ui/views/bubble_anchor_util_views.h" -#include "chrome/browser/ui/views/chrome_layout_provider.h" +#include "chrome/browser/ui/views/file_system_access/file_system_access_scroll_panel.h" #include "chrome/browser/ui/views/file_system_access/file_system_access_ui_helpers.h" #include "chrome/browser/ui/views/title_origin_label.h" #include "chrome/grit/generated_resources.h" @@ -20,7 +19,6 @@ #include "ui/base/ui_base_features.h" #include "ui/views/controls/button/md_text_button.h" #include "ui/views/controls/label.h" -#include "ui/views/controls/scroll_view.h" #include "ui/views/layout/box_layout.h" FileSystemAccessRestorePermissionBubbleView:: @@ -37,7 +35,6 @@ callback_(std::move(callback)) { // Initial set up. views::LayoutProvider* layout_provider = views::LayoutProvider::Get(); - ChromeLayoutProvider* chrome_layout_provider = ChromeLayoutProvider::Get(); SetLayoutManager(std::make_unique<views::BoxLayout>( views::BoxLayout::Orientation::kVertical, gfx::Insets(), DISTANCE_BUTTON_VERTICAL)); @@ -58,36 +55,12 @@ IDS_FILE_SYSTEM_ACCESS_RESTORE_PERMISSION_DESCRIPTION)); // Add file/directory list. - auto file_list_container = std::make_unique<views::View>(); - file_list_container->SetLayoutManager(std::make_unique<views::BoxLayout>( - views::BoxLayout::Orientation::kVertical, - gfx::Insets::VH(FILENAME_AREA_MARGIN, FILENAME_AREA_MARGIN), - BETWEEN_FILENAME_SPACING)); + std::vector<base::FilePath> file_paths; for (auto file : file_data) { - auto* line_container = - file_list_container->AddChildView(std::make_unique<views::View>()); - line_container->SetLayoutManager(std::make_unique<views::BoxLayout>( - views::BoxLayout::Orientation::kHorizontal, gfx::Insets(), - chrome_layout_provider->GetDistanceMetric( - DISTANCE_PERMISSION_PROMPT_HORIZONTAL_ICON_LABEL_PADDING))); - - auto* icon = line_container->AddChildView( - std::make_unique<views::ImageView>(ui::ImageModel::FromVectorIcon( - vector_icons::kFolderOpenIcon, ui::kColorIcon, FOLDER_ICON_SIZE))); - icon->SetVerticalAlignment(views::ImageView::Alignment::kCenter); - - auto* label = line_container->AddChildView(std::make_unique<views::Label>( - file_system_access_ui_helper::GetPathForDisplayAsParagraph(file.path))); - label->SetHorizontalAlignment(gfx::ALIGN_LEFT); + file_paths.push_back(file.path); } - // TODO(crbug.com/1011533): Add border radius to the scroll view, and - // determine if/how file names should be focused for accessibility. - auto scroll_view = std::make_unique<views::ScrollView>(); - scroll_view->SetDrawOverflowIndicator(false); - scroll_view->SetBackgroundThemeColorId(ui::kColorSubtleEmphasisBackground); - scroll_view->SetContents(std::move(file_list_container)); - scroll_view->ClipHeightTo(0, MAX_SCROLL_HEIGHT); - AddChildView(std::move(scroll_view)); + auto scroll_panel = FileSystemAccessScrollPanel(); + AddChildView(scroll_panel.Create(file_paths)); // Add buttons. auto allow_once_button = std::make_unique<views::MdTextButton>(
diff --git a/chrome/browser/ui/views/file_system_access/file_system_access_restore_permission_bubble_view.h b/chrome/browser/ui/views/file_system_access/file_system_access_restore_permission_bubble_view.h index aff407f..18fb4cc 100644 --- a/chrome/browser/ui/views/file_system_access/file_system_access_restore_permission_bubble_view.h +++ b/chrome/browser/ui/views/file_system_access/file_system_access_restore_permission_bubble_view.h
@@ -12,13 +12,9 @@ #include "content/public/browser/web_contents.h" #include "ui/base/metadata/metadata_header_macros.h" -// TODO(crbug.com/1011533): Re-define these temporary values in layout provider +// TODO(crbug.com/1011533): Re-define this temporary value in layout provider // once the spec is ready. Make the style GM3-compatible. constexpr int DISTANCE_BUTTON_VERTICAL = 8; -constexpr int FOLDER_ICON_SIZE = 16; -constexpr int FILENAME_AREA_MARGIN = 8; -constexpr int BETWEEN_FILENAME_SPACING = 4; -constexpr int MAX_SCROLL_HEIGHT = 96; // Bubble dialog that prompts user to restore the permission for // files/directories previously granted to.
diff --git a/chrome/browser/ui/views/file_system_access/file_system_access_scroll_panel.cc b/chrome/browser/ui/views/file_system_access/file_system_access_scroll_panel.cc new file mode 100644 index 0000000..1ef924a --- /dev/null +++ b/chrome/browser/ui/views/file_system_access/file_system_access_scroll_panel.cc
@@ -0,0 +1,52 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/views/file_system_access/file_system_access_scroll_panel.h" + +#include "base/files/file_path.h" +#include "chrome/browser/ui/color/chrome_color_id.h" +#include "chrome/browser/ui/views/chrome_layout_provider.h" +#include "chrome/browser/ui/views/file_system_access/file_system_access_ui_helpers.h" +#include "components/vector_icons/vector_icons.h" +#include "ui/base/ui_base_features.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/controls/label.h" +#include "ui/views/controls/scroll_view.h" +#include "ui/views/layout/box_layout.h" + + +std::unique_ptr<views::ScrollView> FileSystemAccessScrollPanel::Create( + const std::vector<base::FilePath>& file_paths) { + auto file_list_container = std::make_unique<views::View>(); + ChromeLayoutProvider* chrome_layout_provider = ChromeLayoutProvider::Get(); + file_list_container->SetLayoutManager(std::make_unique<views::BoxLayout>( + views::BoxLayout::Orientation::kVertical, + gfx::Insets::VH(FILENAME_AREA_MARGIN, FILENAME_AREA_MARGIN), + BETWEEN_FILENAME_SPACING)); + for (const auto& file_path : file_paths) { + auto* line_container = + file_list_container->AddChildView(std::make_unique<views::View>()); + line_container->SetLayoutManager(std::make_unique<views::BoxLayout>( + views::BoxLayout::Orientation::kHorizontal, gfx::Insets(), + chrome_layout_provider->GetDistanceMetric( + DISTANCE_PERMISSION_PROMPT_HORIZONTAL_ICON_LABEL_PADDING))); + + auto* icon = line_container->AddChildView( + std::make_unique<views::ImageView>(ui::ImageModel::FromVectorIcon( + vector_icons::kFolderOpenIcon, ui::kColorIcon, FOLDER_ICON_SIZE))); + icon->SetVerticalAlignment(views::ImageView::Alignment::kCenter); + + auto* label = line_container->AddChildView(std::make_unique<views::Label>( + file_system_access_ui_helper::GetPathForDisplayAsParagraph(file_path))); + label->SetHorizontalAlignment(gfx::ALIGN_LEFT); + } + // TODO(crbug.com/1011533): Add border radius to the scroll view, and + // determine if/how file names should be focused for accessibility. + auto scroll_view = std::make_unique<views::ScrollView>(); + scroll_view->SetDrawOverflowIndicator(false); + scroll_view->SetBackgroundThemeColorId(ui::kColorSubtleEmphasisBackground); + scroll_view->SetContents(std::move(file_list_container)); + scroll_view->ClipHeightTo(0, MAX_SCROLL_HEIGHT); + return scroll_view; +}
diff --git a/chrome/browser/ui/views/file_system_access/file_system_access_scroll_panel.h b/chrome/browser/ui/views/file_system_access/file_system_access_scroll_panel.h new file mode 100644 index 0000000..6e47277 --- /dev/null +++ b/chrome/browser/ui/views/file_system_access/file_system_access_scroll_panel.h
@@ -0,0 +1,28 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_VIEWS_FILE_SYSTEM_ACCESS_FILE_SYSTEM_ACCESS_SCROLL_PANEL_H_ +#define CHROME_BROWSER_UI_VIEWS_FILE_SYSTEM_ACCESS_FILE_SYSTEM_ACCESS_SCROLL_PANEL_H_ + +#include "base/files/file_path.h" +#include "ui/views/controls/scroll_view.h" + +// TODO(crbug.com/1011533): Re-define these temporary values in layout provider +// once the spec is ready. Make the style GM3-compatible. +constexpr int FOLDER_ICON_SIZE = 16; +constexpr int FILENAME_AREA_MARGIN = 8; +constexpr int BETWEEN_FILENAME_SPACING = 4; +constexpr int MAX_SCROLL_HEIGHT = 96; + +// Scrollable panel that displays a list of file paths, used in File System +// Access API UI surfaces. +// +// TODO(crbug.com/1011533): This UI is still in progress and missing correct +// styles, accessibility support, etc. +class FileSystemAccessScrollPanel { + public: + std::unique_ptr<views::ScrollView> Create(const std::vector<base::FilePath>& file_paths); +}; + +#endif // CHROME_BROWSER_UI_VIEWS_FILE_SYSTEM_ACCESS_FILE_SYSTEM_ACCESS_SCROLL_PANEL_H_
diff --git a/chrome/browser/ui/views/overlay/video_overlay_window_views_unittest.cc b/chrome/browser/ui/views/overlay/video_overlay_window_views_unittest.cc index db5e295..9ceeb242 100644 --- a/chrome/browser/ui/views/overlay/video_overlay_window_views_unittest.cc +++ b/chrome/browser/ui/views/overlay/video_overlay_window_views_unittest.cc
@@ -464,7 +464,8 @@ // With pillarboxing, the close button doesn't cover the video area. Make sure // hovering the button doesn't get handled like normal mouse exit events // causing the controls to hide. -TEST_F(VideoOverlayWindowViewsTest, NoMouseExitWithinWindowBounds) { +// TODO(http://crbug/1509791): Fix and re-enable. +TEST_F(VideoOverlayWindowViewsTest, DISABLED_NoMouseExitWithinWindowBounds) { overlay_window().UpdateNaturalSize({10, 400}); WaitForMove(); @@ -553,7 +554,8 @@ overlay_window().video_layer_for_testing()->size()); } -TEST_F(VideoOverlayWindowViewsTest, ControlsAreHiddenDuringMove) { +// TODO(http://crbug/1509791): Fix and re-enable. +TEST_F(VideoOverlayWindowViewsTest, DISABLED_ControlsAreHiddenDuringMove) { // Set the initial position. overlay_window().SetBounds({0, 0, 100, 100}); WaitForMove();
diff --git a/chrome/browser/ui/views/renderer_context_menu/render_view_context_menu_views.cc b/chrome/browser/ui/views/renderer_context_menu/render_view_context_menu_views.cc index 18283c80..c88a77a 100644 --- a/chrome/browser/ui/views/renderer_context_menu/render_view_context_menu_views.cc +++ b/chrome/browser/ui/views/renderer_context_menu/render_view_context_menu_views.cc
@@ -298,12 +298,20 @@ case IDC_WRITING_DIRECTION_RTL: case IDC_WRITING_DIRECTION_LTR: { - content::RenderViewHost* view_host = GetRenderViewHost(); - view_host->GetWidget()->UpdateTextDirection( - (command_id == IDC_WRITING_DIRECTION_RTL) - ? base::i18n::RIGHT_TO_LEFT - : base::i18n::LEFT_TO_RIGHT); - view_host->GetWidget()->NotifyTextDirection(); + // Note: we get the local render frame host so that the writing mode + // settings changes apply to the correct frame. See crbug.com/1129073 + // for a description of what happens if we use the outermost frame. + content::RenderFrameHost* rfh = GetRenderFrameHost(); + // It's possible that the frame drops out from under us while the context + // menu is open. In this case, we'll not perform the action, but still + // record metrics. + if (rfh) { + rfh->GetRenderWidgetHost()->UpdateTextDirection( + (command_id == IDC_WRITING_DIRECTION_RTL) + ? base::i18n::RIGHT_TO_LEFT + : base::i18n::LEFT_TO_RIGHT); + rfh->GetRenderWidgetHost()->NotifyTextDirection(); + } RenderViewContextMenu::RecordUsedItem(command_id); break; }
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_container_view.cc b/chrome/browser/ui/views/side_panel/read_anything/read_anything_container_view.cc index 3181edc..44a28b02 100644 --- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_container_view.cc +++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_container_view.cc
@@ -9,16 +9,37 @@ #include "chrome/browser/ui/views/side_panel/read_anything/read_anything_side_panel_web_view.h" #include "chrome/browser/ui/views/side_panel/read_anything/read_anything_toolbar_view.h" +#include "ui/accessibility/accessibility_features.h" #include "ui/base/metadata/metadata_impl_macros.h" #include "ui/views/background.h" #include "ui/views/controls/separator.h" #include "ui/views/layout/flex_layout.h" +// TODO(crbug.com/1439905): Remove unused constructor when the +// ReadAnythingLocalSidePanel flag is removed. ReadAnythingContainerView::ReadAnythingContainerView( ReadAnythingCoordinator* coordinator, std::unique_ptr<ReadAnythingToolbarView> toolbar, std::unique_ptr<ReadAnythingSidePanelWebView> content) : coordinator_(std::move(coordinator)) { + Init(std::move(toolbar), std::move(content)); + coordinator_->AddObserver(this); + coordinator_->AddModelObserver(this); +} + +ReadAnythingContainerView::ReadAnythingContainerView( + ReadAnythingSidePanelController* controller, + std::unique_ptr<ReadAnythingToolbarView> toolbar, + std::unique_ptr<ReadAnythingSidePanelWebView> content) + : controller_(std::move(controller)) { + Init(std::move(toolbar), std::move(content)); + controller_->AddObserver(this); + controller_->AddModelObserver(this); +} + +void ReadAnythingContainerView::Init( + std::unique_ptr<ReadAnythingToolbarView> toolbar, + std::unique_ptr<ReadAnythingSidePanelWebView> content) { // Create and set a FlexLayout LayoutManager for this view, set background. auto layout = std::make_unique<views::FlexLayout>(); layout->SetOrientation(views::LayoutOrientation::kVertical) @@ -52,9 +73,6 @@ AddChildView(std::move(toolbar)); separator_ = AddChildView(std::move(separator)); AddChildView(std::move(content)); - - coordinator_->AddObserver(this); - coordinator_->AddModelObserver(this); } void ReadAnythingContainerView::OnReadAnythingThemeChanged( @@ -76,14 +94,23 @@ coordinator_ = nullptr; } -BEGIN_METADATA(ReadAnythingContainerView, views::View) -END_METADATA +void ReadAnythingContainerView::OnSidePanelControllerDestroyed() { + // When the side panel controller that created |this| is destroyed, clean up + // pointers. + controller_ = nullptr; +} ReadAnythingContainerView::~ReadAnythingContainerView() { - // If |this| is being destroyed before the associated coordinator, then - // remove |this| as an observer. - if (coordinator_) { + // If |this| is being destroyed before the associated coordinator or side + // panel controller, then remove |this| as an observer. + if (features::IsReadAnythingLocalSidePanelEnabled() && controller_) { + controller_->RemoveObserver(this); + controller_->RemoveModelObserver(this); + } else if (coordinator_) { coordinator_->RemoveObserver(this); coordinator_->RemoveModelObserver(this); } } + +BEGIN_METADATA(ReadAnythingContainerView, views::View) +END_METADATA
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_container_view.h b/chrome/browser/ui/views/side_panel/read_anything/read_anything_container_view.h index 89e5c78..1da260d 100644 --- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_container_view.h +++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_container_view.h
@@ -9,6 +9,7 @@ #include "chrome/browser/ui/views/side_panel/read_anything/read_anything_coordinator.h" #include "chrome/browser/ui/views/side_panel/read_anything/read_anything_model.h" +#include "chrome/browser/ui/views/side_panel/read_anything/read_anything_side_panel_controller.h" #include "ui/base/metadata/metadata_header_macros.h" #include "ui/views/controls/separator.h" #include "ui/views/view.h" @@ -21,18 +22,26 @@ // // A class that holds all of the Read Anything UI. This includes a toolbar, // which is a View, and the Read Anything contents pane, which is a WebUI. -// This class is created by the ReadAnythingCoordinator and owned by the Side -// Panel View. It has the same lifetime as the Side Panel view. +// This class is either created by the ReadAnythingCoordinator (when the side +// panel is global) or the ReadAnythingSidePanelController (when the side panel +// is local) and owned by the Side Panel View. It has the same lifetime as the +// Side Panel view. // -class ReadAnythingContainerView : public views::View, - public ReadAnythingModel::Observer, - public ReadAnythingCoordinator::Observer { +class ReadAnythingContainerView + : public views::View, + public ReadAnythingModel::Observer, + public ReadAnythingCoordinator::Observer, + public ReadAnythingSidePanelController::Observer { public: METADATA_HEADER(ReadAnythingContainerView); ReadAnythingContainerView( ReadAnythingCoordinator* coordinator, std::unique_ptr<ReadAnythingToolbarView> toolbar, std::unique_ptr<ReadAnythingSidePanelWebView> content); + ReadAnythingContainerView( + ReadAnythingSidePanelController* controller, + std::unique_ptr<ReadAnythingToolbarView> toolbar, + std::unique_ptr<ReadAnythingSidePanelWebView> content); ReadAnythingContainerView(const ReadAnythingContainerView&) = delete; ReadAnythingContainerView& operator=(const ReadAnythingContainerView&) = delete; @@ -53,9 +62,15 @@ // ReadAnythingCoordinator::Observer: void OnCoordinatorDestroyed() override; + // ReadAnythingSidePanelController::Observer: + void OnSidePanelControllerDestroyed() override; private: + void Init(std::unique_ptr<ReadAnythingToolbarView> toolbar, + std::unique_ptr<ReadAnythingSidePanelWebView> content); + raw_ptr<ReadAnythingCoordinator> coordinator_; + raw_ptr<ReadAnythingSidePanelController> controller_; raw_ptr<views::Separator> separator_; }; #endif // CHROME_BROWSER_UI_VIEWS_SIDE_PANEL_READ_ANYTHING_READ_ANYTHING_CONTAINER_VIEW_H_
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_controller.cc b/chrome/browser/ui/views/side_panel/read_anything/read_anything_controller.cc index 89d108a4..f1039a0 100644 --- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_controller.cc +++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_controller.cc
@@ -14,17 +14,25 @@ #include "components/prefs/pref_service.h" #include "ui/accessibility/accessibility_features.h" +// TODO(crbug.com/1439905): Remove unused constructor when the +// ReadAnythingLocalSidePanel flag is removed. ReadAnythingController::ReadAnythingController(ReadAnythingModel* model, Browser* browser) : model_(model), browser_(browser) {} +ReadAnythingController::ReadAnythingController( + ReadAnythingModel* model, + content::WebContents* web_contents) + : model_(model), web_contents_(web_contents) {} + /////////////////////////////////////////////////////////////////////////////// // ReadAnythingFontCombobox::Delegate: /////////////////////////////////////////////////////////////////////////////// void ReadAnythingController::OnFontChoiceChanged(int new_index) { - if (!model_->GetFontModel()->IsValidFontIndex(new_index)) + if (!model_->GetFontModel()->IsValidFontIndex(new_index)) { return; + } if (!features::IsReadAnythingWebUIToolbarEnabled()) { base::UmaHistogramEnumeration( @@ -33,7 +41,7 @@ } model_->SetSelectedFontByIndex(new_index); - browser_->profile()->GetPrefs()->SetString( + GetProfile()->GetPrefs()->SetString( prefs::kAccessibilityReadAnythingFontName, model_->GetFontModel()->GetFontNameAt(new_index)); } @@ -58,12 +66,12 @@ string_constants::kSettingsChangeHistogramName, ReadAnythingSettingsChange::kFontSizeChange); } - browser_->profile()->GetPrefs()->SetDouble( + GetProfile()->GetPrefs()->SetDouble( prefs::kAccessibilityReadAnythingFontScale, model_->GetFontScale()); } void ReadAnythingController::OnColorsChanged(int new_index) { - PrefService* prefs = browser_->profile()->GetPrefs(); + PrefService* prefs = GetProfile()->GetPrefs(); if (!model_->GetColorsModel()->IsValidIndex(new_index) || prefs->GetInteger(prefs::kAccessibilityReadAnythingColorInfo) == new_index) { @@ -85,8 +93,9 @@ } void ReadAnythingController::OnLineSpacingChanged(int new_index) { - if (!model_->GetLineSpacingModel()->IsValidIndex(new_index)) + if (!model_->GetLineSpacingModel()->IsValidIndex(new_index)) { return; + } if (!features::IsReadAnythingWebUIToolbarEnabled()) { base::UmaHistogramEnumeration( @@ -99,7 +108,7 @@ // deprecated value, the drop-down indices don't correspond exactly. LineSpacing line_spacing = model_->GetLineSpacingModel()->GetLineSpacingAt(new_index); - browser_->profile()->GetPrefs()->SetInteger( + GetProfile()->GetPrefs()->SetInteger( prefs::kAccessibilityReadAnythingLineSpacing, static_cast<size_t>(line_spacing)); } @@ -109,8 +118,9 @@ } void ReadAnythingController::OnLetterSpacingChanged(int new_index) { - if (!model_->GetLetterSpacingModel()->IsValidIndex(new_index)) + if (!model_->GetLetterSpacingModel()->IsValidIndex(new_index)) { return; + } if (!features::IsReadAnythingWebUIToolbarEnabled()) { base::UmaHistogramEnumeration( @@ -123,7 +133,7 @@ // deprecated value, the drop-down indices don't correspond exactly. LetterSpacing letter_spacing = model_->GetLetterSpacingModel()->GetLetterSpacingAt(new_index); - browser_->profile()->GetPrefs()->SetInteger( + GetProfile()->GetPrefs()->SetInteger( prefs::kAccessibilityReadAnythingLetterSpacing, static_cast<size_t>(letter_spacing)); } @@ -135,3 +145,12 @@ void ReadAnythingController::OnSystemThemeChanged() { model_->OnSystemThemeChanged(); } + +Profile* ReadAnythingController::GetProfile() { + if (features::IsReadAnythingLocalSidePanelEnabled() && web_contents_) { + return Profile::FromBrowserContext(web_contents_->GetBrowserContext()); + } else { + CHECK(browser_); + return browser_->profile(); + } +}
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_controller.h b/chrome/browser/ui/views/side_panel/read_anything/read_anything_controller.h index ecc9413..c944811 100644 --- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_controller.h +++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_controller.h
@@ -14,6 +14,10 @@ class Browser; +namespace content { +class WebContents; +} // namespace content + /////////////////////////////////////////////////////////////////////////////// // ReadAnythingController // @@ -21,14 +25,19 @@ // business logic of this feature and updates the model. // The controller is meant to be internal to the Read Anything feature and // classes outside this feature should not be making calls to it. The -// coordinator is the external-facing API. -// This class is owned by the ReadAnythingCoordinator and has the same lifetime -// as the browser. +// coordinator or side panel controller is the external-facing API. +// When the side panel entry is global, this class is owned by the +// ReadAnythingCoordinator and has the same lifetime as the browser. +// When the side panel entry is local. this class is owned by the +// ReadAnythingSidePanelController and has the same lifetime as the associated +// web contents. // class ReadAnythingController : public ReadAnythingToolbarView::Delegate, public ReadAnythingFontCombobox::Delegate { public: ReadAnythingController(ReadAnythingModel* model, Browser* browser); + ReadAnythingController(ReadAnythingModel* model, + content::WebContents* web_contents); ReadAnythingController(const ReadAnythingController&) = delete; ReadAnythingController& operator=(const ReadAnythingController&) = delete; virtual ~ReadAnythingController() = default; @@ -50,10 +59,14 @@ ReadAnythingMenuModel* GetLetterSpacingModel() override; void OnSystemThemeChanged() override; - const raw_ptr<ReadAnythingModel> model_; + Profile* GetProfile(); - // ReadAnythingController is owned by ReadAnythingCoordinator which is a - // browser user data, so this pointer is always valid. + const raw_ptr<ReadAnythingModel> model_; + const raw_ptr<content::WebContents> web_contents_; + + // Set when the ReadAnythingController is owned by a ReadAnythingCoordinator. + // ReadAnythingCoordinator is a browser user data, so this pointer is always + // valid. raw_ptr<Browser, DanglingUntriaged> browser_; }; #endif // CHROME_BROWSER_UI_VIEWS_SIDE_PANEL_READ_ANYTHING_READ_ANYTHING_CONTROLLER_H_
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_controller_unittest.cc b/chrome/browser/ui/views/side_panel/read_anything/read_anything_controller_unittest.cc index 5a7a2ad..00f670e 100644 --- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_controller_unittest.cc +++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_controller_unittest.cc
@@ -12,8 +12,10 @@ #include "chrome/browser/ui/webui/side_panel/read_anything/read_anything_prefs.h" #include "chrome/common/accessibility/read_anything_constants.h" #include "chrome/test/base/browser_with_test_window_test.h" +#include "chrome/test/base/testing_profile.h" #include "chrome/test/base/ui_test_utils.h" #include "testing/gmock/include/gmock/gmock.h" +#include "ui/accessibility/accessibility_features.h" using testing::_; class MockReadAnythingModelObserver : public ReadAnythingModel::Observer { @@ -36,11 +38,18 @@ class ReadAnythingControllerTest : public TestWithBrowserView { public: void SetUp() override { + scoped_feature_list_.InitAndEnableFeature( + features::kReadAnythingLocalSidePanel); TestWithBrowserView::SetUp(); model_ = std::make_unique<ReadAnythingModel>(); controller_ = std::make_unique<ReadAnythingController>(model_.get(), browser()); + auto* web_contents_ = browser()->OpenURL(content::OpenURLParams( + GURL("https://google.com"), content::Referrer(), + WindowOpenDisposition::CURRENT_TAB, ui::PAGE_TRANSITION_TYPED, false)); + controller_for_web_contents_ = + std::make_unique<ReadAnythingController>(model_.get(), web_contents_); // Reset prefs to default values for test. browser()->profile()->GetPrefs()->SetString( @@ -60,24 +69,50 @@ static_cast<int>(read_anything::mojom::LetterSpacing::kDefaultValue)); } + void TearDown() override { + controller_for_web_contents_ = nullptr; + controller_ = nullptr; + TestWithBrowserView::TearDown(); + } + void MockOnFontChoiceChanged(int index) { controller_->OnFontChoiceChanged(index); } + void MockControllerForWebContentsOnFontChoiceChanged(int index) { + controller_for_web_contents_->OnFontChoiceChanged(index); + } + void MockOnFontSizeChanged(bool increase) { controller_->OnFontSizeChanged(increase); } + void MockControllerForWebContentsOnFontSizeChanged(bool increase) { + controller_for_web_contents_->OnFontSizeChanged(increase); + } + void MockOnColorsChanged(int index) { controller_->OnColorsChanged(index); } + void MockControllerForWebContentsOnColorsChanged(int index) { + controller_for_web_contents_->OnColorsChanged(index); + } + void MockOnLineSpacingChanged(int index) { controller_->OnLineSpacingChanged(index); } + void MockControllerForWebContentsOnLineSpacingChanged(int index) { + controller_for_web_contents_->OnLineSpacingChanged(index); + } + void MockOnLetterSpacingChanged(int index) { controller_->OnLetterSpacingChanged(index); } + void MockControllerForWebContentsOnLetterSpacingChanged(int index) { + controller_for_web_contents_->OnLetterSpacingChanged(index); + } + void MockModelInit(std::string language, std::string font_name, double font_scale, @@ -119,6 +154,10 @@ std::unique_ptr<ReadAnythingModel> model_; std::unique_ptr<ReadAnythingController> controller_; MockReadAnythingModelObserver model_observer_; + + // Variables for the controller created using web contents; + std::unique_ptr<ReadAnythingController> controller_for_web_contents_; + base::test::ScopedFeatureList scoped_feature_list_; }; TEST_F(ReadAnythingControllerTest, ValidIndexUpdatesFontNamePref) { @@ -136,6 +175,22 @@ EXPECT_EQ(expected_font_name, GetPrefFontName()); } +TEST_F(ReadAnythingControllerTest, + ControllerForWebContentsValidIndexUpdatesFontNamePref) { + std::string expected_font_name = "Comic Neue"; + + // Initialize model with English so all fonts are available choices. + std::string font_name; + std::string language = "en"; + MockModelInit(language, font_name, 4.5, + read_anything::mojom::Colors::kDefaultValue, + read_anything::mojom::LineSpacing::kDefaultValue, + read_anything::mojom::LetterSpacing::kDefaultValue); + MockControllerForWebContentsOnFontChoiceChanged(3); + + EXPECT_EQ(expected_font_name, GetPrefFontName()); +} + TEST_F(ReadAnythingControllerTest, OnFontSizeChangedIncreaseUpdatesPref) { EXPECT_NEAR(GetPrefFontScale(), 1.0, 0.01); @@ -144,6 +199,15 @@ EXPECT_NEAR(GetPrefFontScale(), 1.25, 0.01); } +TEST_F(ReadAnythingControllerTest, + ControllerForWebContentsOnFontSizeChangedIncreaseUpdatesPref) { + EXPECT_NEAR(GetPrefFontScale(), 1.0, 0.01); + + MockControllerForWebContentsOnFontSizeChanged(true); + + EXPECT_NEAR(GetPrefFontScale(), 1.25, 0.01); +} + TEST_F(ReadAnythingControllerTest, OnFontSizeChangedDecreasePref) { EXPECT_NEAR(GetPrefFontScale(), 1.0, 0.01); @@ -152,6 +216,15 @@ EXPECT_NEAR(GetPrefFontScale(), 0.75, 0.01); } +TEST_F(ReadAnythingControllerTest, + ControllerForWebContentsOnFontSizeChangedDecreasePref) { + EXPECT_NEAR(GetPrefFontScale(), 1.0, 0.01); + + MockControllerForWebContentsOnFontSizeChanged(false); + + EXPECT_NEAR(GetPrefFontScale(), 0.75, 0.01); +} + TEST_F(ReadAnythingControllerTest, OnFontSizeChangedHonorsMax) { EXPECT_NEAR(GetPrefFontScale(), 1.0, 0.01); @@ -167,6 +240,22 @@ EXPECT_NEAR(GetPrefFontScale(), 4.5, 0.01); } +TEST_F(ReadAnythingControllerTest, + ControllerForWebContentsOnFontSizeChangedHonorsMax) { + EXPECT_NEAR(GetPrefFontScale(), 1.0, 0.01); + + std::string font_name; + std::string language = "en"; + MockModelInit(language, font_name, 4.5, + read_anything::mojom::Colors::kDefaultValue, + read_anything::mojom::LineSpacing::kDefaultValue, + read_anything::mojom::LetterSpacing::kDefaultValue); + + MockControllerForWebContentsOnFontSizeChanged(true); + + EXPECT_NEAR(GetPrefFontScale(), 4.5, 0.01); +} + TEST_F(ReadAnythingControllerTest, OnFontSizeChangedHonorsMin) { EXPECT_NEAR(GetPrefFontScale(), 1.0, 0.01); @@ -182,6 +271,22 @@ EXPECT_NEAR(GetPrefFontScale(), 0.5, 0.01); } +TEST_F(ReadAnythingControllerTest, + ControllerForWebContentsOnFontSizeChangedHonorsMin) { + EXPECT_NEAR(GetPrefFontScale(), 1.0, 0.01); + + std::string font_name; + std::string language = "en"; + MockModelInit(language, font_name, 0.5, + read_anything::mojom::Colors::kDefaultValue, + read_anything::mojom::LineSpacing::kDefaultValue, + read_anything::mojom::LetterSpacing::kDefaultValue); + + MockControllerForWebContentsOnFontSizeChanged(false); + + EXPECT_NEAR(GetPrefFontScale(), 0.5, 0.01); +} + TEST_F(ReadAnythingControllerTest, OnColorsChangedUpdatesPref) { EXPECT_EQ(GetPrefsColors(), 0); @@ -190,6 +295,16 @@ EXPECT_EQ(GetPrefsColors(), 3); } +TEST_F(ReadAnythingControllerTest, + ControllerForWebContentsOnColorsChangedUpdatesPref) { + EXPECT_EQ(GetPrefsColors(), 0); + + MockControllerForWebContentsOnColorsChanged( + static_cast<int>(read_anything::mojom::Colors::kYellow)); + + EXPECT_EQ(GetPrefsColors(), 3); +} + TEST_F(ReadAnythingControllerTest, OnLineSpacingChangedUpdatesPref) { EXPECT_EQ(GetPrefsLineSpacing(), 2); @@ -202,6 +317,18 @@ } TEST_F(ReadAnythingControllerTest, + ControllerForWebContentsOnLineSpacingChangedUpdatesPref) { + EXPECT_EQ(GetPrefsLineSpacing(), 2); + + // Subtract one to account for the deprecated value (kLooseDeprecated), since + // this is the index in the drop-down and not the enum value. + MockControllerForWebContentsOnLineSpacingChanged( + static_cast<int>(read_anything::mojom::LineSpacing::kStandard) - 1); + + EXPECT_EQ(GetPrefsLineSpacing(), 1); +} + +TEST_F(ReadAnythingControllerTest, OnLineSpacingChangedValidInputAtTopBoundary) { EXPECT_EQ(GetPrefsLineSpacing(), 2); @@ -214,6 +341,18 @@ } TEST_F(ReadAnythingControllerTest, + ControllerForWebContentsOnLineSpacingChangedValidInputAtTopBoundary) { + EXPECT_EQ(GetPrefsLineSpacing(), 2); + + // Subtract one to account for the deprecated value (kLooseDeprecated), since + // this is the index in the drop-down and not the enum value. + MockControllerForWebContentsOnLineSpacingChanged( + static_cast<int>(read_anything::mojom::LineSpacing::kVeryLoose) - 1); + + EXPECT_EQ(GetPrefsLineSpacing(), 3); +} + +TEST_F(ReadAnythingControllerTest, OnLineSpacingChangedInvalidInputAtTopBoundary) { EXPECT_EQ(GetPrefsLineSpacing(), 2); @@ -225,6 +364,18 @@ EXPECT_EQ(GetPrefsLineSpacing(), 2); } +TEST_F(ReadAnythingControllerTest, + ControllerForWebContentsOnLineSpacingChangedInvalidInputAtTopBoundary) { + EXPECT_EQ(GetPrefsLineSpacing(), 2); + + // Subtract one to account for the deprecated value (kLooseDeprecated), since + // this is the index in the drop-down and not the enum value. + MockControllerForWebContentsOnLineSpacingChanged( + static_cast<int>(read_anything::mojom::LineSpacing::kVeryLoose)); + + EXPECT_EQ(GetPrefsLineSpacing(), 2); +} + TEST_F(ReadAnythingControllerTest, OnLineSpacingChangedInvalidInput) { EXPECT_EQ(GetPrefsLineSpacing(), 2); @@ -233,6 +384,15 @@ EXPECT_EQ(GetPrefsLineSpacing(), 2); } +TEST_F(ReadAnythingControllerTest, + ControllerForWebContentsOnLineSpacingChangedInvalidInput) { + EXPECT_EQ(GetPrefsLineSpacing(), 2); + + MockControllerForWebContentsOnLineSpacingChanged(10); + + EXPECT_EQ(GetPrefsLineSpacing(), 2); +} + TEST_F(ReadAnythingControllerTest, OnLetterSpacingChangedUpdatesPref) { EXPECT_EQ(GetPrefsLetterSpacing(), 1); @@ -245,6 +405,18 @@ } TEST_F(ReadAnythingControllerTest, + ControllerForWebContentsOnLetterSpacingChangedUpdatesPref) { + EXPECT_EQ(GetPrefsLetterSpacing(), 1); + + // Subtract one to account for the deprecated value (kLooseDeprecated), since + // this is the index in the drop-down and not the enum value. + MockControllerForWebContentsOnLetterSpacingChanged( + static_cast<int>(read_anything::mojom::LetterSpacing::kWide) - 1); + + EXPECT_EQ(GetPrefsLetterSpacing(), 2); +} + +TEST_F(ReadAnythingControllerTest, OnLetterSpacingChangedValidInputAtTopBoundary) { EXPECT_EQ(GetPrefsLetterSpacing(), 1); @@ -257,6 +429,18 @@ } TEST_F(ReadAnythingControllerTest, + ControllerForWebContentsOnLetterSpacingChangedValidInputAtTopBoundary) { + EXPECT_EQ(GetPrefsLetterSpacing(), 1); + + // Subtract one to account for the deprecated value (kLooseDeprecated), since + // this is the index in the drop-down and not the enum value. + MockControllerForWebContentsOnLetterSpacingChanged( + static_cast<int>(read_anything::mojom::LetterSpacing::kVeryWide) - 1); + + EXPECT_EQ(GetPrefsLetterSpacing(), 3); +} + +TEST_F(ReadAnythingControllerTest, OnLetterSpacingChangedInvalidInputAtTopBoundary) { EXPECT_EQ(GetPrefsLetterSpacing(), 1); @@ -268,6 +452,19 @@ EXPECT_EQ(GetPrefsLetterSpacing(), 1); } +TEST_F( + ReadAnythingControllerTest, + ControllerForWebContentsOnLetterSpacingChangedInvalidInputAtTopBoundary) { + EXPECT_EQ(GetPrefsLetterSpacing(), 1); + + // Since this is the index in the drop-down and not the enum value, the max + // enum value is one larger than the max index value in the drop down. + MockControllerForWebContentsOnLetterSpacingChanged( + static_cast<int>(read_anything::mojom::LetterSpacing::kVeryWide)); + + EXPECT_EQ(GetPrefsLetterSpacing(), 1); +} + TEST_F(ReadAnythingControllerTest, OnLetterSpacingChangedInvalidInput) { EXPECT_EQ(GetPrefsLetterSpacing(), 1); @@ -275,3 +472,12 @@ EXPECT_EQ(GetPrefsLetterSpacing(), 1); } + +TEST_F(ReadAnythingControllerTest, + ControllerForWebContentsOnLetterSpacingChangedInvalidInput) { + EXPECT_EQ(GetPrefsLetterSpacing(), 1); + + MockControllerForWebContentsOnLetterSpacingChanged(10); + + EXPECT_EQ(GetPrefsLetterSpacing(), 1); +}
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_font_combobox.h b/chrome/browser/ui/views/side_panel/read_anything/read_anything_font_combobox.h index b3f60a1..7c1d31ee4 100644 --- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_font_combobox.h +++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_font_combobox.h
@@ -43,7 +43,7 @@ // views::View: void GetAccessibleNodeData(ui::AXNodeData* node_data) override; - raw_ptr<ReadAnythingFontCombobox::Delegate> delegate_; + raw_ptr<ReadAnythingFontCombobox::Delegate, DanglingUntriaged> delegate_; base::WeakPtrFactory<ReadAnythingFontCombobox> weak_pointer_factory_{this}; };
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_model.cc b/chrome/browser/ui/views/side_panel/read_anything/read_anything_model.cc index 7252e22..a2b3ca4 100644 --- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_model.cc +++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_model.cc
@@ -148,26 +148,30 @@ } double ReadAnythingModel::GetValidFontScale(double font_scale) { - if (font_scale < kReadAnythingMinimumFontScale) + if (font_scale < kReadAnythingMinimumFontScale) { return kReadAnythingMinimumFontScale; - if (font_scale > kReadAnythingMaximumFontScale) + } + if (font_scale > kReadAnythingMaximumFontScale) { return kReadAnythingMaximumFontScale; + } return font_scale; } // TODO(1266555): Update with text scaling approach based on UI/UX feedback. void ReadAnythingModel::DecreaseTextSize() { font_scale_ -= kReadAnythingFontScaleIncrement; - if (font_scale_ < kReadAnythingMinimumFontScale) + if (font_scale_ < kReadAnythingMinimumFontScale) { font_scale_ = kReadAnythingMinimumFontScale; + } NotifyThemeChanged(); } void ReadAnythingModel::IncreaseTextSize() { font_scale_ += kReadAnythingFontScaleIncrement; - if (font_scale_ > kReadAnythingMaximumFontScale) + if (font_scale_ > kReadAnythingMaximumFontScale) { font_scale_ = kReadAnythingMaximumFontScale; + } NotifyThemeChanged(); }
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_side_panel_controller.cc b/chrome/browser/ui/views/side_panel/read_anything/read_anything_side_panel_controller.cc index 8e0f6ed..620af34 100644 --- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_side_panel_controller.cc +++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_side_panel_controller.cc
@@ -3,10 +3,14 @@ // found in the LICENSE file. #include "chrome/browser/ui/views/side_panel/read_anything/read_anything_side_panel_controller.h" +#include <algorithm> +#include <memory> #include "chrome/app/vector_icons/vector_icons.h" +#include "chrome/browser/language/language_model_manager_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser_finder.h" +#include "chrome/browser/ui/side_panel/read_anything/read_anything_tab_helper.h" #include "chrome/browser/ui/views/bubble/bubble_contents_wrapper.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/side_panel/read_anything/read_anything_container_view.h" @@ -16,8 +20,13 @@ #include "chrome/browser/ui/views/side_panel/read_anything/read_anything_toolbar_view.h" #include "chrome/browser/ui/views/side_panel/side_panel_registry.h" #include "chrome/browser/ui/views/side_panel/side_panel_web_ui_view.h" +#include "chrome/browser/ui/webui/side_panel/read_anything/read_anything_prefs.h" +#include "chrome/browser/ui/webui/side_panel/read_anything/read_anything_untrusted_page_handler.h" #include "chrome/browser/ui/webui/side_panel/read_anything/read_anything_untrusted_ui.h" #include "chrome/grit/generated_resources.h" +#include "components/language/core/browser/language_model.h" +#include "components/language/core/browser/language_model_manager.h" +#include "components/language/core/common/locale_util.h" #include "read_anything_controller.h" #include "read_anything_coordinator.h" #include "read_anything_side_panel_controller.h" @@ -32,9 +41,80 @@ ReadAnythingSidePanelController::ReadAnythingSidePanelController( content::WebContents* web_contents) - : web_contents_(web_contents) {} + : web_contents_(web_contents) { + // Create the model and initialize it with user prefs (if present). + model_ = std::make_unique<ReadAnythingModel>(); + InitModelWithUserPrefs(); -ReadAnythingSidePanelController::~ReadAnythingSidePanelController() = default; + // Create the controller. + controller_ = + std::make_unique<ReadAnythingController>(model_.get(), web_contents_); +} + +void ReadAnythingSidePanelController::InitModelWithUserPrefs() { + if (!Profile::FromBrowserContext(web_contents_->GetBrowserContext()) || + !Profile::FromBrowserContext(web_contents_->GetBrowserContext()) + ->GetPrefs()) { + return; + } + + // Get user's default language to check for compatible fonts. + language::LanguageModel* language_model = + LanguageModelManagerFactory::GetForBrowserContext( + Profile::FromBrowserContext(web_contents_->GetBrowserContext())) + ->GetPrimaryModel(); + std::string prefs_lang = language_model->GetLanguages().front().lang_code; + prefs_lang = language::ExtractBaseLanguage(prefs_lang); + + std::string prefs_font_name; + prefs_font_name = + Profile::FromBrowserContext(web_contents_->GetBrowserContext()) + ->GetPrefs() + ->GetString(prefs::kAccessibilityReadAnythingFontName); + + double prefs_font_scale; + prefs_font_scale = + Profile::FromBrowserContext(web_contents_->GetBrowserContext()) + ->GetPrefs() + ->GetDouble(prefs::kAccessibilityReadAnythingFontScale); + + read_anything::mojom::Colors prefs_colors; + prefs_colors = static_cast<read_anything::mojom::Colors>( + Profile::FromBrowserContext(web_contents_->GetBrowserContext()) + ->GetPrefs() + ->GetInteger(prefs::kAccessibilityReadAnythingColorInfo)); + + read_anything::mojom::LineSpacing prefs_line_spacing; + prefs_line_spacing = static_cast<read_anything::mojom::LineSpacing>( + Profile::FromBrowserContext(web_contents_->GetBrowserContext()) + ->GetPrefs() + ->GetInteger(prefs::kAccessibilityReadAnythingLineSpacing)); + + read_anything::mojom::LetterSpacing prefs_letter_spacing; + prefs_letter_spacing = static_cast<read_anything::mojom::LetterSpacing>( + Profile::FromBrowserContext(web_contents_->GetBrowserContext()) + ->GetPrefs() + ->GetInteger(prefs::kAccessibilityReadAnythingLetterSpacing)); + + model_->Init( + /* lang code = */ prefs_lang, + /* font_name = */ prefs_font_name, + /* font scale = */ prefs_font_scale, + /* colors = */ prefs_colors, + /* line spacing = */ prefs_line_spacing, + /* letter spacing = */ prefs_letter_spacing); + default_language_code_ = prefs_lang; + for (ReadAnythingSidePanelController::Observer& obs : observers_) { + obs.SetDefaultLanguageCode(prefs_lang); + } +} + +ReadAnythingSidePanelController::~ReadAnythingSidePanelController() { + // Inform observers when |this| is destroyed so they can do their own cleanup. + for (ReadAnythingSidePanelController::Observer& obs : observers_) { + obs.OnSidePanelControllerDestroyed(); + } +} void ReadAnythingSidePanelController::CreateAndRegisterEntry() { auto* registry = SidePanelRegistry::Get(web_contents_); @@ -67,12 +147,54 @@ registry->Deregister(SidePanelEntry::Key(SidePanelEntry::Id::kReadAnything)); } +void ReadAnythingSidePanelController::AddPageHandlerAsObserver( + base::WeakPtr<ReadAnythingUntrustedPageHandler> page_handler) { + AddObserver(page_handler.get()); + AddModelObserver(page_handler.get()); +} + +void ReadAnythingSidePanelController::RemovePageHandlerAsObserver( + base::WeakPtr<ReadAnythingUntrustedPageHandler> page_handler) { + RemoveObserver(page_handler.get()); + RemoveModelObserver(page_handler.get()); +} + +void ReadAnythingSidePanelController::AddObserver( + ReadAnythingSidePanelController::Observer* observer) { + observers_.AddObserver(observer); + + // InitModelWithUserPrefs where default_language_code_ is set may be called + // before all observerers have been added, so ensure that observers are + // updated with the correct language code as they're added. + observer->SetDefaultLanguageCode(default_language_code_); +} + +void ReadAnythingSidePanelController::RemoveObserver( + ReadAnythingSidePanelController::Observer* observer) { + observers_.RemoveObserver(observer); +} + +void ReadAnythingSidePanelController::AddModelObserver( + ReadAnythingModel::Observer* observer) { + DCHECK(model_); + model_->AddObserver(observer); +} + +void ReadAnythingSidePanelController::RemoveModelObserver( + ReadAnythingModel::Observer* observer) { + DCHECK(model_); + model_->RemoveObserver(observer); +} + void ReadAnythingSidePanelController::OnEntryShown(SidePanelEntry* entry) { CHECK_EQ(entry->key().id(), SidePanelEntry::Id::kReadAnything); if (Browser* browser = chrome::FindBrowserWithTab(web_contents_)) { auto* coordinator = ReadAnythingCoordinator::GetOrCreateForBrowser(browser); coordinator->OnReadAnythingSidePanelEntryShown(); } + for (ReadAnythingSidePanelController::Observer& obs : observers_) { + obs.Activate(true); + } } void ReadAnythingSidePanelController::OnEntryHidden(SidePanelEntry* entry) { @@ -81,6 +203,9 @@ auto* coordinator = ReadAnythingCoordinator::GetOrCreateForBrowser(browser); coordinator->OnReadAnythingSidePanelEntryHidden(); } + for (ReadAnythingSidePanelController::Observer& obs : observers_) { + obs.Activate(false); + } } std::unique_ptr<views::View> @@ -92,31 +217,19 @@ return std::move(web_view); } - Browser* browser = chrome::FindBrowserWithTab(web_contents_); - if (!browser) { - // If no browser was found via WebContents, it is probably because the - // web_contents has not been attached to a window yet. Since we are only - // using the browser to find the ReadAnythingCoordinator, it is safe to grab - // the LastActive browser as a fallback. - browser = chrome::FindLastActive(); - } - - CHECK(browser); - auto* coordinator = ReadAnythingCoordinator::GetOrCreateForBrowser(browser); - // Create the views. auto toolbar = std::make_unique<ReadAnythingToolbarView>( - coordinator, - /*toolbar_delegate=*/coordinator->GetController(), - /*font_combobox_delegate=*/coordinator->GetController()); + this, + /*toolbar_delegate=*/controller_.get(), + /*font_combobox_delegate=*/controller_.get()); // Create the component. - // Note that a coordinator would normally maintain ownership of these objects, - // but objects extending {ui/views/view.h} prefer ownership over raw pointers - // (View ownership is typically managed by the View hierarchy, rather than by - // outside coordinators). + // Note that a side panel controller would normally maintain ownership of + // these objects, but objects extending {ui/views/view.h} prefer ownership + // over raw pointers (View ownership is typically managed by the View + // hierarchy, rather than by outside controllers). auto container_view = std::make_unique<ReadAnythingContainerView>( - coordinator, std::move(toolbar), std::move(web_view)); + this, std::move(toolbar), std::move(web_view)); return std::move(container_view); }
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_side_panel_controller.h b/chrome/browser/ui/views/side_panel/read_anything/read_anything_side_panel_controller.h index 8386d3b..5a3d162 100644 --- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_side_panel_controller.h +++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_side_panel_controller.h
@@ -6,6 +6,7 @@ #define CHROME_BROWSER_UI_VIEWS_SIDE_PANEL_READ_ANYTHING_READ_ANYTHING_SIDE_PANEL_CONTROLLER_H_ #include "chrome/browser/ui/side_panel/read_anything/read_anything_tab_helper.h" +#include "chrome/browser/ui/views/side_panel/read_anything/read_anything_model.h" #include "chrome/browser/ui/views/side_panel/side_panel_entry_observer.h" namespace content { @@ -16,10 +17,19 @@ class View; } // namespace views +class ReadAnythingController; +class ReadAnythingUntrustedPageHandler; + // A per-tab class that facilitates the showing of the Read Anything side panel. class ReadAnythingSidePanelController : public ReadAnythingTabHelper::Delegate, public SidePanelEntryObserver { public: + class Observer : public base::CheckedObserver { + public: + virtual void Activate(bool active) {} + virtual void OnSidePanelControllerDestroyed() = 0; + virtual void SetDefaultLanguageCode(const std::string& code) {} + }; explicit ReadAnythingSidePanelController(content::WebContents* web_contents); ReadAnythingSidePanelController(const ReadAnythingSidePanelController&) = delete; @@ -30,15 +40,32 @@ // ReadAnythingTabHelper::Delegate: void CreateAndRegisterEntry() override; void DeregisterEntry() override; + void AddPageHandlerAsObserver( + base::WeakPtr<ReadAnythingUntrustedPageHandler> page_handler) override; + void RemovePageHandlerAsObserver( + base::WeakPtr<ReadAnythingUntrustedPageHandler> page_handler) override; // SidePanelEntryObserver: void OnEntryShown(SidePanelEntry* entry) override; void OnEntryHidden(SidePanelEntry* entry) override; + void AddObserver(ReadAnythingSidePanelController::Observer* observer); + void RemoveObserver(ReadAnythingSidePanelController::Observer* observer); + void AddModelObserver(ReadAnythingModel::Observer* observer); + void RemoveModelObserver(ReadAnythingModel::Observer* observer); + private: + // Used during construction to initialize the model with saved user prefs. + void InitModelWithUserPrefs(); // Creates the container view and all its child views for side panel entry. std::unique_ptr<views::View> CreateContainerView(); + std::string default_language_code_; + std::unique_ptr<ReadAnythingModel> model_; + std::unique_ptr<ReadAnythingController> controller_; + + base::ObserverList<ReadAnythingSidePanelController::Observer> observers_; + const raw_ptr<content::WebContents> web_contents_; };
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_side_panel_controller_unittest.cc b/chrome/browser/ui/views/side_panel/read_anything/read_anything_side_panel_controller_unittest.cc index 9ce995d2..9feec30 100644 --- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_side_panel_controller_unittest.cc +++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_side_panel_controller_unittest.cc
@@ -12,8 +12,17 @@ #include "content/public/test/browser_task_environment.h" #include "content/public/test/test_renderer_host.h" #include "content/public/test/web_contents_tester.h" +#include "read_anything_side_panel_controller.h" +#include "testing/gmock/include/gmock/gmock.h" #include "ui/accessibility/accessibility_features.h" +class MockReadAnythingSidePanelControllerObserver + : public ReadAnythingSidePanelController::Observer { + public: + MOCK_METHOD(void, Activate, (bool active), (override)); + MOCK_METHOD(void, OnSidePanelControllerDestroyed, (), (override)); +}; + class ReadAnythingSidePanelControllerTest : public ChromeViewsTestBase { public: void SetUp() override { @@ -22,9 +31,30 @@ web_contents_ = content::WebContentsTester::CreateTestWebContents(&profile_, nullptr); + side_panel_controller_ = + std::make_unique<ReadAnythingSidePanelController>(web_contents()); + } + + void TearDown() override { + side_panel_controller_ = nullptr; + ChromeViewsTestBase::TearDown(); + } + + // Wrapper methods around the ReadAnythingSidePanelController. These do + // nothing more than keep the below tests less verbose (simple pass-throughs). + + void AddObserver(ReadAnythingSidePanelController::Observer* observer) { + side_panel_controller_->AddObserver(observer); + } + void RemoveObserver(ReadAnythingSidePanelController::Observer* observer) { + side_panel_controller_->RemoveObserver(observer); } protected: + std::unique_ptr<ReadAnythingSidePanelController> side_panel_controller_; + MockReadAnythingSidePanelControllerObserver side_panel_controller_observer_; + raw_ptr<SidePanelRegistry> side_panel_registry_; + content::WebContents* web_contents() { return web_contents_.get(); } private: @@ -37,8 +67,7 @@ TEST_F(ReadAnythingSidePanelControllerTest, RegisterReadAnythingEntry) { // When CreateAndRegisterEntry() is called, the current tab's side // panel registry should contain a kReadAnythingEntry. - ReadAnythingSidePanelController side_panel_controller(web_contents()); - side_panel_controller.CreateAndRegisterEntry(); + side_panel_controller_->CreateAndRegisterEntry(); auto* registry = SidePanelRegistry::Get(web_contents()); EXPECT_EQ(registry ->GetEntryForKey( @@ -51,8 +80,7 @@ TEST_F(ReadAnythingSidePanelControllerTest, DeregisterReadAnythingEntry) { // When Deregister() is called, there should be no side panel entry // in the registry. - ReadAnythingSidePanelController side_panel_controller(web_contents()); - side_panel_controller.CreateAndRegisterEntry(); + side_panel_controller_->CreateAndRegisterEntry(); auto* registry = SidePanelRegistry::Get(web_contents()); EXPECT_EQ(registry @@ -61,7 +89,7 @@ ->key() .id(), SidePanelEntry::Id::kReadAnything); - side_panel_controller.DeregisterEntry(); + side_panel_controller_->DeregisterEntry(); EXPECT_EQ(registry->GetEntryForKey( SidePanelEntry::Key(SidePanelEntry::Id::kReadAnything)), nullptr); @@ -70,8 +98,7 @@ TEST_F(ReadAnythingSidePanelControllerTest, CreateAndRegisterMultipleTimes) { // When CreateAndRegisterEntry() is called multiple times, only // one entry should be added to the registry. - ReadAnythingSidePanelController side_panel_controller(web_contents()); - side_panel_controller.CreateAndRegisterEntry(); + side_panel_controller_->CreateAndRegisterEntry(); auto* registry = SidePanelRegistry::Get(web_contents()); EXPECT_EQ(registry ->GetEntryForKey( @@ -79,14 +106,14 @@ ->key() .id(), SidePanelEntry::Id::kReadAnything); - side_panel_controller.CreateAndRegisterEntry(); + side_panel_controller_->CreateAndRegisterEntry(); EXPECT_EQ(registry ->GetEntryForKey( SidePanelEntry::Key(SidePanelEntry::Id::kReadAnything)) ->key() .id(), SidePanelEntry::Id::kReadAnything); - side_panel_controller.DeregisterEntry(); + side_panel_controller_->DeregisterEntry(); EXPECT_EQ(registry->GetEntryForKey( SidePanelEntry::Key(SidePanelEntry::Id::kReadAnything)), nullptr); @@ -95,6 +122,34 @@ TEST_F(ReadAnythingSidePanelControllerTest, DeregisterEmptyReadAnythingEntry) { // When there is no customize chrome entry, calling deregister should // not crash. - ReadAnythingSidePanelController side_panel_controller(web_contents()); - side_panel_controller.DeregisterEntry(); + side_panel_controller_->DeregisterEntry(); +} + +TEST_F(ReadAnythingSidePanelControllerTest, + OnSidePanelControllerDestroyedCalled) { + AddObserver(&side_panel_controller_observer_); + EXPECT_CALL(side_panel_controller_observer_, OnSidePanelControllerDestroyed()) + .Times(1); +} + +TEST_F(ReadAnythingSidePanelControllerTest, OnEntryShown_ActivateObservers) { + AddObserver(&side_panel_controller_observer_); + side_panel_controller_->CreateAndRegisterEntry(); + auto* registry = SidePanelRegistry::Get(web_contents()); + SidePanelEntry* entry = registry->GetEntryForKey( + SidePanelEntry::Key(SidePanelEntry::Id::kReadAnything)); + + EXPECT_CALL(side_panel_controller_observer_, Activate(true)).Times(1); + side_panel_controller_->OnEntryShown(entry); +} + +TEST_F(ReadAnythingSidePanelControllerTest, OnEntryHidden_ActivateObservers) { + AddObserver(&side_panel_controller_observer_); + side_panel_controller_->CreateAndRegisterEntry(); + auto* registry = SidePanelRegistry::Get(web_contents()); + SidePanelEntry* entry = registry->GetEntryForKey( + SidePanelEntry::Key(SidePanelEntry::Id::kReadAnything)); + + EXPECT_CALL(side_panel_controller_observer_, Activate(false)).Times(1); + side_panel_controller_->OnEntryHidden(entry); }
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_toolbar_view.cc b/chrome/browser/ui/views/side_panel/read_anything/read_anything_toolbar_view.cc index cfa469f..c1ecf41 100644 --- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_toolbar_view.cc +++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_toolbar_view.cc
@@ -12,6 +12,7 @@ #include "chrome/browser/ui/views/side_panel/read_anything/read_anything_menu_button.h" #include "chrome/common/accessibility/read_anything_constants.h" #include "chrome/grit/generated_resources.h" +#include "ui/accessibility/accessibility_features.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/metadata/metadata_impl_macros.h" #include "ui/color/color_id.h" @@ -28,13 +29,33 @@ #include "ui/views/layout/box_layout.h" #include "ui/views/layout/flex_layout.h" +// TODO(crbug.com/1439905): Remove unused constructor when the +// ReadAnythingLocalSidePanel flag is removed. ReadAnythingToolbarView::ReadAnythingToolbarView( ReadAnythingCoordinator* coordinator, ReadAnythingToolbarView::Delegate* toolbar_delegate, ReadAnythingFontCombobox::Delegate* font_combobox_delegate) : delegate_(toolbar_delegate), coordinator_(std::move(coordinator)) { coordinator_->AddObserver(this); + Init(toolbar_delegate, font_combobox_delegate); + // Start observing model after views creation so initial theme is applied. + coordinator_->AddModelObserver(this); +} +ReadAnythingToolbarView::ReadAnythingToolbarView( + ReadAnythingSidePanelController* controller, + ReadAnythingToolbarView::Delegate* toolbar_delegate, + ReadAnythingFontCombobox::Delegate* font_combobox_delegate) + : delegate_(toolbar_delegate), controller_(std::move(controller)) { + controller_->AddObserver(this); + Init(toolbar_delegate, font_combobox_delegate); + // Start observing model after views creation so initial theme is applied. + controller_->AddModelObserver(this); +} + +void ReadAnythingToolbarView::Init( + ReadAnythingToolbarView::Delegate* toolbar_delegate, + ReadAnythingFontCombobox::Delegate* font_combobox_delegate) { // Set a FlexLayout LayoutManager for this view. SetLayoutManager(std::make_unique<views::FlexLayout>()) ->SetOrientation(views::LayoutOrientation::kHorizontal) @@ -110,9 +131,6 @@ colors_button_ = AddChildView(std::move(colors_button)); line_spacing_button_ = AddChildView(std::move(line_spacing_button)); letter_spacing_button_ = AddChildView(std::move(letter_spacing_button)); - - // Start observing model after views creation so initial theme is applied. - coordinator_->AddModelObserver(this); } void ReadAnythingToolbarView::OnThemeChanged() { @@ -129,35 +147,51 @@ } void ReadAnythingToolbarView::DecreaseFontSizeCallback() { - if (delegate_) + if (delegate_) { delegate_->OnFontSizeChanged(/* increase = */ false); + } } void ReadAnythingToolbarView::IncreaseFontSizeCallback() { - if (delegate_) + if (delegate_) { delegate_->OnFontSizeChanged(/* increase = */ true); + } } void ReadAnythingToolbarView::ChangeColorsCallback() { - if (delegate_) + if (delegate_) { delegate_->OnColorsChanged(colors_button_->GetSelectedIndex().value_or(0)); + } } void ReadAnythingToolbarView::ChangeLineSpacingCallback() { - if (delegate_) + if (delegate_) { delegate_->OnLineSpacingChanged( line_spacing_button_->GetSelectedIndex().value_or(1)); + } } void ReadAnythingToolbarView::ChangeLetterSpacingCallback() { - if (delegate_) + if (delegate_) { delegate_->OnLetterSpacingChanged( letter_spacing_button_->GetSelectedIndex().value_or(0)); + } } void ReadAnythingToolbarView::OnCoordinatorDestroyed() { // When the coordinator that created |this| is destroyed, clean up pointers. coordinator_ = nullptr; + CleanUp(); +} + +void ReadAnythingToolbarView::OnSidePanelControllerDestroyed() { + // When the side panel controller that created |this| is destroyed, clean up + // pointers. + controller_ = nullptr; + CleanUp(); +} + +void ReadAnythingToolbarView::CleanUp() { delegate_ = nullptr; font_combobox_->SetModel(nullptr); colors_button_->SetMenuModel(nullptr); @@ -187,8 +221,9 @@ increase_text_size_button_->Disable(); } - if (!GetColorProvider()) + if (!GetColorProvider()) { return; + } SetBackground(views::CreateThemedSolidBackground(background_color_id)); font_combobox_->SetBackgroundColorId(background_color_id); @@ -259,14 +294,17 @@ l10n_util::GetStringUTF16(IDS_READING_MODE_TOOLBAR_LABEL)); } -BEGIN_METADATA(ReadAnythingToolbarView, views::View) -END_METADATA - ReadAnythingToolbarView::~ReadAnythingToolbarView() { - // If |this| is being destroyed before the associated coordinator, then - // remove |this| as an observer. - if (coordinator_) { + // If |this| is being destroyed before the associated coordinator or side + // panel controller, then remove |this| as an observer. + if (features::IsReadAnythingLocalSidePanelEnabled() && controller_) { + controller_->RemoveObserver(this); + controller_->RemoveModelObserver(this); + } else if (coordinator_) { coordinator_->RemoveObserver(this); coordinator_->RemoveModelObserver(this); } } + +BEGIN_METADATA(ReadAnythingToolbarView, views::View) +END_METADATA
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_toolbar_view.h b/chrome/browser/ui/views/side_panel/read_anything/read_anything_toolbar_view.h index 10c905f..8dfedfc1 100644 --- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_toolbar_view.h +++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_toolbar_view.h
@@ -16,6 +16,7 @@ #include "chrome/browser/ui/views/side_panel/read_anything/read_anything_font_combobox.h" #include "chrome/browser/ui/views/side_panel/read_anything/read_anything_menu_button.h" #include "chrome/browser/ui/views/side_panel/read_anything/read_anything_model.h" +#include "chrome/browser/ui/views/side_panel/read_anything/read_anything_side_panel_controller.h" #include "ui/base/metadata/metadata_header_macros.h" #include "ui/base/metadata/metadata_impl_macros.h" #include "ui/base/models/combobox_model.h" @@ -27,12 +28,16 @@ // ReadAnythingToolbarView // // The toolbar for Read Anything. -// This class is created by the ReadAnythingCoordinator and owned by the -// ReadAnythingContainerView. It has the same lifetime as the Side Panel view. +// This class is either created by the ReadAnythingCoordinator (when the side +// panel entry is global) or the ReadAnythingSidePanelController (when the side +// panel entry is local) and owned by the ReadAnythingContainerView. It has the +// same lifetime as the Side Panel view. // -class ReadAnythingToolbarView : public views::View, - public ReadAnythingModel::Observer, - public ReadAnythingCoordinator::Observer { +class ReadAnythingToolbarView + : public views::View, + public ReadAnythingModel::Observer, + public ReadAnythingCoordinator::Observer, + public ReadAnythingSidePanelController::Observer { public: METADATA_HEADER(ReadAnythingToolbarView); class Delegate { @@ -51,6 +56,10 @@ ReadAnythingCoordinator* coordinator, ReadAnythingToolbarView::Delegate* toolbar_delegate, ReadAnythingFontCombobox::Delegate* font_combobox_delegate); + ReadAnythingToolbarView( + ReadAnythingSidePanelController* controller, + ReadAnythingToolbarView::Delegate* toolbar_delegate, + ReadAnythingFontCombobox::Delegate* font_combobox_delegate); ReadAnythingToolbarView(const ReadAnythingToolbarView&) = delete; ReadAnythingToolbarView& operator=(const ReadAnythingToolbarView&) = delete; ~ReadAnythingToolbarView() override; @@ -70,15 +79,20 @@ // ReadAnythingCoordinator::Observer: void OnCoordinatorDestroyed() override; + // ReadAnythingSidePanelController::Observer: + void OnSidePanelControllerDestroyed() override; private: friend class ReadAnythingToolbarViewTest; + void Init(ReadAnythingToolbarView::Delegate* toolbar_delegate, + ReadAnythingFontCombobox::Delegate* font_combobox_delegate); void DecreaseFontSizeCallback(); void IncreaseFontSizeCallback(); void ChangeColorsCallback(); void ChangeLineSpacingCallback(); void ChangeLetterSpacingCallback(); + void CleanUp(); // views::View: void AddedToWidget() override; @@ -98,6 +112,7 @@ raw_ptr<ReadAnythingToolbarView::Delegate> delegate_; raw_ptr<ReadAnythingCoordinator> coordinator_; + raw_ptr<ReadAnythingSidePanelController> controller_; base::WeakPtrFactory<ReadAnythingToolbarView> weak_pointer_factory_{this}; };
diff --git a/chrome/browser/ui/views/tabs/tab_search_container_browsertest.cc b/chrome/browser/ui/views/tabs/tab_search_container_browsertest.cc index 9b11d5fa..d04444b 100644 --- a/chrome/browser/ui/views/tabs/tab_search_container_browsertest.cc +++ b/chrome/browser/ui/views/tabs/tab_search_container_browsertest.cc
@@ -8,6 +8,7 @@ #include "chrome/browser/signin/identity_manager_factory.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/tabs/organization/tab_organization_service.h" +#include "chrome/browser/ui/tabs/organization/tab_organization_utils.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/ui_features.h" #include "chrome/browser/ui/views/frame/browser_view.h" @@ -29,25 +30,9 @@ TabSearchContainerBrowserTest() { feature_list_.InitWithFeatures( {features::kTabOrganization, features::kChromeRefresh2023, - features::kChromeWebuiRefresh2023, - optimization_guide::features::internal:: - kTabOrganizationSettingsVisibility, - optimization_guide::features::kOptimizationGuideModelExecution}, + features::kChromeWebuiRefresh2023}, {}); - } - - void EnableOptGuide() { - signin::MakePrimaryAccountAvailable( - IdentityManagerFactory::GetForProfile(browser()->profile()), - "test@example.com", signin::ConsentLevel::kSync); - - PrefService* prefs = browser()->profile()->GetPrefs(); - prefs->SetInteger( - optimization_guide::prefs::GetSettingEnabledPrefName( - optimization_guide::proto::ModelExecutionFeature:: - MODEL_EXECUTION_FEATURE_TAB_ORGANIZATION), - static_cast<int>( - optimization_guide::prefs::FeatureOptInState::kEnabled)); + TabOrganizationUtils::GetInstance()->SetIgnoreOptGuideForTesting(true); } TabStripModel* tab_strip_model() { return browser()->tab_strip_model(); } @@ -66,11 +51,6 @@ base::test::ScopedFeatureList feature_list_; }; -IN_PROC_BROWSER_TEST_F(TabSearchContainerBrowserTest, - PRE_TogglesActionUIState) { - EnableOptGuide(); -} - IN_PROC_BROWSER_TEST_F(TabSearchContainerBrowserTest, TogglesActionUIState) { ASSERT_FALSE( tab_search_container()->expansion_animation_for_testing()->IsShowing()); @@ -122,11 +102,6 @@ } IN_PROC_BROWSER_TEST_F(TabSearchContainerBrowserTest, - PRE_ImmediatelyHidesWhenOrganizeButtonClicked) { - EnableOptGuide(); -} - -IN_PROC_BROWSER_TEST_F(TabSearchContainerBrowserTest, ImmediatelyHidesWhenOrganizeButtonClicked) { tab_search_container()->expansion_animation_for_testing()->Reset(1); tab_search_container()->SetLockedExpansionModeForTesting( @@ -139,11 +114,6 @@ } IN_PROC_BROWSER_TEST_F(TabSearchContainerBrowserTest, - PRE_ImmediatelyHidesWhenOrganizeButtonDismissed) { - EnableOptGuide(); -} - -IN_PROC_BROWSER_TEST_F(TabSearchContainerBrowserTest, ImmediatelyHidesWhenOrganizeButtonDismissed) { tab_search_container()->expansion_animation_for_testing()->Reset(1); tab_search_container()->SetLockedExpansionModeForTesting(
diff --git a/chrome/browser/ui/views/toolbar/pinned_toolbar_actions_container.cc b/chrome/browser/ui/views/toolbar/pinned_toolbar_actions_container.cc index c2d3f8d..47766c1 100644 --- a/chrome/browser/ui/views/toolbar/pinned_toolbar_actions_container.cc +++ b/chrome/browser/ui/views/toolbar/pinned_toolbar_actions_container.cc
@@ -744,6 +744,16 @@ return button != nullptr; } +bool PinnedToolbarActionsContainer::IsOverflowed(const actions::ActionId& id) { + const auto* const pinned_button = GetPinnedButtonFor(id); + // TODO(crbug.com/1508656): If this container is not visible treat the + // elements inside as overflowed. + // TODO(pengchaocai): Support popped out buttons overflow. + return static_cast<views::LayoutManagerBase*>(GetLayoutManager()) + ->CanBeVisible(pinned_button) && + (!GetVisible() || !pinned_button->GetVisible()); +} + void PinnedToolbarActionsContainer::ReorderViews() { size_t index = 0; // Pinned buttons appear first. Use the model's ordering of pinned ActionIds
diff --git a/chrome/browser/ui/views/toolbar/pinned_toolbar_actions_container.h b/chrome/browser/ui/views/toolbar/pinned_toolbar_actions_container.h index fcdb9e5a..4e80c60 100644 --- a/chrome/browser/ui/views/toolbar/pinned_toolbar_actions_container.h +++ b/chrome/browser/ui/views/toolbar/pinned_toolbar_actions_container.h
@@ -13,6 +13,7 @@ #include "base/memory/raw_ptr.h" #include "chrome/browser/ui/toolbar/pinned_toolbar_actions_model.h" #include "chrome/browser/ui/views/toolbar/toolbar_button.h" +#include "chrome/browser/ui/views/toolbar/toolbar_controller.h" #include "chrome/browser/ui/views/toolbar/toolbar_icon_container_view.h" #include "ui/actions/action_id.h" #include "ui/actions/actions.h" @@ -27,7 +28,8 @@ class PinnedToolbarActionsContainer : public ToolbarIconContainerView, public PinnedToolbarActionsModel::Observer, - public views::DragController { + public views::DragController, + public ToolbarController::PinnedActionsDelegate { METADATA_HEADER(PinnedToolbarActionsContainer, ToolbarIconContainerView) public: @@ -121,6 +123,10 @@ const gfx::Point& press_pt, const gfx::Point& p) override; + // ToolbarController::PinnedActionsDelegate: + actions::ActionItem* GetActionItemFor(const actions::ActionId& id) override; + bool IsOverflowed(const actions::ActionId& id) override; + bool IsActionPinned(const actions::ActionId& id); private: @@ -130,7 +136,6 @@ // A struct representing the position and action being dragged. struct DropInfo; - actions::ActionItem* GetActionItemFor(const actions::ActionId& id); PinnedActionToolbarButton* AddPopOutButtonFor(const actions::ActionId& id); void RemovePoppedOutButtonFor(const actions::ActionId& id); void AddPinnedActionButtonFor(const actions::ActionId& id);
diff --git a/chrome/browser/ui/views/toolbar/toolbar_controller.cc b/chrome/browser/ui/views/toolbar/toolbar_controller.cc index f9e3374..1ab235b 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_controller.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_controller.cc
@@ -4,12 +4,16 @@ #include "chrome/browser/ui/views/toolbar/toolbar_controller.h" +#include "base/functional/overloaded.h" #include "base/metrics/user_metrics.h" #include "base/metrics/user_metrics_action.h" #include "base/no_destructor.h" #include "base/strings/strcat.h" #include "base/strings/string_util.h" +#include "chrome/browser/ui/side_panel/side_panel_enums.h" #include "chrome/browser/ui/toolbar_controller_util.h" +#include "chrome/browser/ui/views/frame/browser_actions.h" +#include "chrome/browser/ui/views/side_panel/side_panel_util.h" #include "chrome/browser/ui/views/toolbar/overflow_button.h" #include "chrome/browser/ui/views/toolbar/toolbar_button.h" #include "chrome/grit/generated_resources.h" @@ -79,11 +83,13 @@ const std::vector<ui::ElementIdentifier>& elements_in_overflow_order, int element_flex_order_start, views::View* toolbar_container_view, - views::View* overflow_button) + views::View* overflow_button, + ToolbarController::PinnedActionsDelegate* pinned_actions_delegate) : responsive_elements_(responsive_elements), element_flex_order_start_(element_flex_order_start), toolbar_container_view_(toolbar_container_view), - overflow_button_(overflow_button) { + overflow_button_(overflow_button), + pinned_actions_delegate_(pinned_actions_delegate) { if (ToolbarControllerUtil::PreventOverflow()) { return; } @@ -91,73 +97,114 @@ const auto id_to_order_map = CalculateFlexOrder(elements_in_overflow_order, element_flex_order_start); for (const auto& element : responsive_elements) { - auto* const toolbar_element = FindToolbarElementWithId( - toolbar_container_view_, element.overflow_identifier); - if (!toolbar_element) { - continue; - } + const auto& overflow_id = element.overflow_id; + const auto& observed_identifier = element.observed_identifier; - views::FlexSpecification* original_spec = - toolbar_element->GetProperty(views::kFlexBehaviorKey); - views::FlexSpecification flex_spec; - if (!original_spec) { - flex_spec = views::FlexSpecification( - views::MinimumFlexSizeRule::kPreferredSnapToZero, - views::MaximumFlexSizeRule::kPreferred); - toolbar_element->SetProperty(views::kFlexBehaviorKey, flex_spec); - } - flex_spec = - toolbar_element->GetProperty(views::kFlexBehaviorKey) - ->WithOrder(id_to_order_map.at(element.overflow_identifier)); - toolbar_element->SetProperty(views::kFlexBehaviorKey, flex_spec); + absl::visit( + base::Overloaded{ + [](actions::ActionId id) { return; }, + [&](ToolbarController::ElementIdInfo id) { + auto* const toolbar_element = FindToolbarElementWithId( + toolbar_container_view_, id.overflow_identifier); + if (!toolbar_element) { + return; + } - // Check `responsive_elements_` is constructed correctly i.e. - // ResponsiveElementInfo::activate_identifier is non-null. - CHECK(element.activate_identifier); + views::FlexSpecification* original_spec = + toolbar_element->GetProperty(views::kFlexBehaviorKey); + views::FlexSpecification flex_spec; + if (!original_spec) { + flex_spec = views::FlexSpecification( + views::MinimumFlexSizeRule::kPreferredSnapToZero, + views::MaximumFlexSizeRule::kPreferred); + toolbar_element->SetProperty(views::kFlexBehaviorKey, + flex_spec); + } + flex_spec = + toolbar_element->GetProperty(views::kFlexBehaviorKey) + ->WithOrder(id_to_order_map.at(id.overflow_identifier)); + toolbar_element->SetProperty(views::kFlexBehaviorKey, flex_spec); - // Create pop out state and pop out handlers to support pop out. - if (element.observed_identifier.has_value()) { - auto state = std::make_unique<PopOutState>(); - if (original_spec) { - state->original_spec = - std::optional<views::FlexSpecification>(*original_spec); - } - state->responsive_spec = flex_spec; - state->handler = std::make_unique<PopOutHandler>( - this, - views::ElementTrackerViews::GetContextForView(toolbar_container_view), - element.overflow_identifier, element.observed_identifier.value()); - pop_out_state_[element.overflow_identifier] = std::move(state); - } + // Create pop out state and pop out handlers to support pop out. + if (observed_identifier.has_value()) { + auto state = std::make_unique<PopOutState>(); + if (original_spec) { + state->original_spec = + std::optional<views::FlexSpecification>(*original_spec); + } + state->responsive_spec = flex_spec; + state->handler = std::make_unique<PopOutHandler>( + this, + views::ElementTrackerViews::GetContextForView( + toolbar_container_view), + id.overflow_identifier, observed_identifier.value()); + pop_out_state_[id.overflow_identifier] = std::move(state); + } + }}, + overflow_id); } } ToolbarController::~ToolbarController() = default; std::vector<ToolbarController::ResponsiveElementInfo> -ToolbarController::GetDefaultResponsiveElements() { +ToolbarController::GetDefaultResponsiveElements(Browser* browser) { // TODO(crbug.com/1445573): Fill in observed identifier. // Order matters because it should match overflow menu order top to bottom. - return std::vector<ToolbarController::ResponsiveElementInfo>( - {{kToolbarForwardButtonElementId, IDS_OVERFLOW_MENU_ITEM_TEXT_FORWARD, - kToolbarForwardButtonElementId}, - {kToolbarHomeButtonElementId, IDS_OVERFLOW_MENU_ITEM_TEXT_HOME, - kToolbarHomeButtonElementId, /*is_section_end=*/true}, - {kToolbarChromeLabsButtonElementId, IDS_OVERFLOW_MENU_ITEM_TEXT_LABS, - kToolbarChromeLabsButtonElementId, /*is_section_end=*/false, - kToolbarChromeLabsBubbleElementId}, - {kToolbarMediaButtonElementId, - IDS_OVERFLOW_MENU_ITEM_TEXT_MEDIA_CONTROLS, - kToolbarMediaButtonElementId, /*is_section_end=*/false, - kToolbarMediaBubbleElementId}, - {kToolbarDownloadButtonElementId, IDS_OVERFLOW_MENU_ITEM_TEXT_DOWNLOADS, - kToolbarDownloadButtonElementId, /*is_section_end=*/false, - kToolbarDownloadBubbleElementId}, - {kToolbarNewTabButtonElementId, IDS_OVERFLOW_MENU_ITEM_TEXT_NEW_TAB, - kToolbarNewTabButtonElementId, /*is_section_end=*/true}, - {kToolbarAvatarButtonElementId, IDS_OVERFLOW_MENU_ITEM_TEXT_PROFILE, - kToolbarAvatarButtonElementId, /*is_section_end=*/false, - kToolbarAvatarBubbleElementId}}); + std::vector<ToolbarController::ResponsiveElementInfo> elements = { + {ToolbarController::ElementIdInfo{kToolbarForwardButtonElementId, + IDS_OVERFLOW_MENU_ITEM_TEXT_FORWARD, + kToolbarForwardButtonElementId}, + /*is_section_end=*/false}, + {ToolbarController::ElementIdInfo{kToolbarHomeButtonElementId, + IDS_OVERFLOW_MENU_ITEM_TEXT_HOME, + kToolbarHomeButtonElementId}, + /*is_section_end=*/true}}; + + // Support actions items. + const auto* const browser_actions = BrowserActions::FromBrowser(browser); + if (browser_actions) { + auto* root_item = browser_actions->root_action_item(); + if (root_item) { + for (const auto& item : root_item->GetChildren().children()) { + auto id = item->GetActionId(); + if (item->GetProperty(actions::kActionItemPinnableKey) && + id.has_value()) { + elements.emplace_back(id.value()); + } + } + auto& last_element = elements.back(); + if (absl::holds_alternative<actions::ActionId>( + last_element.overflow_id)) { + last_element.is_section_end = true; + } + } + } + + elements.insert( + elements.end(), + {{ToolbarController::ElementIdInfo{kToolbarChromeLabsButtonElementId, + IDS_OVERFLOW_MENU_ITEM_TEXT_LABS, + kToolbarChromeLabsButtonElementId}, + /*is_section_end=*/false, kToolbarChromeLabsBubbleElementId}, + {ToolbarController::ElementIdInfo{ + kToolbarMediaButtonElementId, + IDS_OVERFLOW_MENU_ITEM_TEXT_MEDIA_CONTROLS, + kToolbarMediaButtonElementId}, + /*is_section_end=*/false, kToolbarMediaBubbleElementId}, + {ToolbarController::ElementIdInfo{kToolbarDownloadButtonElementId, + IDS_OVERFLOW_MENU_ITEM_TEXT_DOWNLOADS, + kToolbarDownloadButtonElementId}, + /*is_section_end=*/true, kToolbarDownloadBubbleElementId}, + {ToolbarController::ElementIdInfo{kToolbarNewTabButtonElementId, + IDS_OVERFLOW_MENU_ITEM_TEXT_NEW_TAB, + kToolbarNewTabButtonElementId}, + /*is_section_end=*/true}, + {ToolbarController::ElementIdInfo{kToolbarAvatarButtonElementId, + IDS_OVERFLOW_MENU_ITEM_TEXT_PROFILE, + kToolbarAvatarButtonElementId}, + /*is_section_end=*/false, kToolbarAvatarBubbleElementId}}); + return elements; } std::vector<ui::ElementIdentifier> @@ -172,9 +219,10 @@ // Every activate identifier should have an action name in order to emit // metrics. Please update action names in actions.xml to match this map. std::string ToolbarController::GetActionNameFromElementIdentifier( - ui::ElementIdentifier identifier) { + absl::variant<ui::ElementIdentifier, actions::ActionId> identifier) { static const base::NoDestructor< - base::flat_map<ui::ElementIdentifier, base::StringPiece>> + base::flat_map<absl::variant<ui::ElementIdentifier, actions::ActionId>, + base::StringPiece>> identifier_to_action_name_map({ {kToolbarAvatarButtonElementId, "AvatarButton"}, {kToolbarChromeLabsButtonElementId, "ChromeLabsButton"}, @@ -185,6 +233,16 @@ {kToolbarMediaButtonElementId, "MediaButton"}, {kToolbarNewTabButtonElementId, "NewTabButton"}, {kToolbarSidePanelButtonElementId, "SidePanelButton"}, + {kActionSidePanelShowBookmarks, "PinnedShowBookmarkSidePanelButton"}, + {kActionSidePanelShowReadAnything, + "PinnedShowReadAnythingSidePanelButton"}, + {kActionSidePanelShowHistoryCluster, + "PinnedShowHistorySidePanelButton"}, + {kActionSidePanelShowReadingList, + "PinnedShowReadingListSidePanelButton"}, + {kActionSidePanelShowSearchCompanion, + "PinnedShowSearchCompanionSidePanelButton"}, + {kActionSidePanelShowPerformance, "ShowPerformanceSidePanelButton"}, }); const auto it = identifier_to_action_name_map->find(identifier); @@ -253,7 +311,7 @@ // Once at least one button has been dropped by layout manager show overflow // button. for (const auto& element : responsive_elements_) { - if (IsOverflowed(element.overflow_identifier)) { + if (IsOverflowed(element)) { return true; } } @@ -262,7 +320,15 @@ std::u16string ToolbarController::GetMenuText( const ResponsiveElementInfo& element_info) const { - return l10n_util::GetStringUTF16(element_info.menu_text_id); + return absl::visit( + base::Overloaded{ + [this](actions::ActionId id) { + return pinned_actions_delegate_->GetActionItemFor(id)->GetText(); + }, + [](ToolbarController::ElementIdInfo id) { + return l10n_util::GetStringUTF16(id.menu_text_id); + }}, + element_info.overflow_id); } views::View* ToolbarController::FindToolbarElementWithId( @@ -290,20 +356,31 @@ return overflowed_buttons; } for (const auto& element : responsive_elements_) { - if (IsOverflowed(element.overflow_identifier)) { + if (IsOverflowed(element)) { overflowed_buttons.push_back(&element); } } return overflowed_buttons; } -bool ToolbarController::IsOverflowed(ui::ElementIdentifier id) const { - const auto* const toolbar_element = - FindToolbarElementWithId(toolbar_container_view_, id); - const views::FlexLayout* const flex_layout = static_cast<views::FlexLayout*>( - toolbar_container_view_->GetLayoutManager()); - return flex_layout->CanBeVisible(toolbar_element) && - !toolbar_element->GetVisible(); +bool ToolbarController::IsOverflowed( + const ResponsiveElementInfo& element) const { + return absl::visit( + base::Overloaded{[this](actions::ActionId id) { + return pinned_actions_delegate_ && + pinned_actions_delegate_->IsOverflowed(id); + }, + [this](ToolbarController::ElementIdInfo id) { + const auto* const toolbar_element = + FindToolbarElementWithId(toolbar_container_view_, + id.overflow_identifier); + const views::FlexLayout* const flex_layout = + static_cast<views::FlexLayout*>( + toolbar_container_view_->GetLayoutManager()); + return flex_layout->CanBeVisible(toolbar_element) && + !toolbar_element->GetVisible(); + }}, + element.overflow_id); } std::unique_ptr<ui::SimpleMenuModel> @@ -313,10 +390,9 @@ // True if the separator belonging to previous section has not been added yet. bool pre_separator_pending = false; - for (size_t i = 0; i < responsive_elements_.size(); ++i) { const auto& element = responsive_elements_[i]; - if (IsOverflowed(element.overflow_identifier)) { + if (IsOverflowed(element)) { if (pre_separator_pending && menu_model->GetItemCount() > 0) { menu_model->AddSeparator(ui::NORMAL_SEPARATOR); } @@ -331,24 +407,49 @@ } bool ToolbarController::IsCommandIdEnabled(int command_id) const { - const auto* const element = FindToolbarElementWithId( - toolbar_container_view_, - responsive_elements_.at(command_id).overflow_identifier); - return element->GetEnabled(); + return absl::visit( + base::Overloaded{ + [this](actions::ActionId id) { + return pinned_actions_delegate_->GetActionItemFor(id)->GetEnabled(); + }, + [this](ToolbarController::ElementIdInfo id) { + return FindToolbarElementWithId(toolbar_container_view_, + id.overflow_identifier) + ->GetEnabled(); + }}, + responsive_elements_.at(command_id).overflow_id); } void ToolbarController::ExecuteCommand(int command_id, int event_flags) { - ui::ElementIdentifier activate_identifier = - responsive_elements_.at(command_id).activate_identifier; - const auto* const element = - FindToolbarElementWithId(toolbar_container_view_, activate_identifier); - CHECK(element); - const auto* button = AsViewClass<views::Button>(element); - button->button_controller()->NotifyClick(); - - std::string action_name = - GetActionNameFromElementIdentifier(activate_identifier); + const auto& element_info = responsive_elements_.at(command_id); + absl::variant<ui::ElementIdentifier, actions::ActionId> action_key; + absl::visit( + base::Overloaded{ + [&, this](actions::ActionId id) { + pinned_actions_delegate_->GetActionItemFor(id)->InvokeAction( + actions::ActionInvocationContext::Builder() + .SetProperty( + kSidePanelOpenTriggerKey, + static_cast< + std::underlying_type_t<SidePanelOpenTrigger>>( + SidePanelOpenTrigger::kOverflowMenu)) + .Build()); + action_key.emplace<actions::ActionId>(id); + }, + [&, this](ToolbarController::ElementIdInfo id) { + const auto& activate_identifier = id.activate_identifier; + const auto* const element = FindToolbarElementWithId( + toolbar_container_view_, activate_identifier); + CHECK(element); + const auto* button = AsViewClass<views::Button>(element); + button->button_controller()->NotifyClick(); + action_key.emplace<ui::ElementIdentifier>(activate_identifier); + }}, + element_info.overflow_id); + std::string action_name = GetActionNameFromElementIdentifier(action_key); if (!action_name.empty()) { + base::RecordAction( + base::UserMetricsAction("ResponsiveToolbar.OverflowMenuItemActivated")); base::RecordAction(base::UserMetricsAction(action_name.c_str())); } }
diff --git a/chrome/browser/ui/views/toolbar/toolbar_controller.h b/chrome/browser/ui/views/toolbar/toolbar_controller.h index b04a0ac..0b963571 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_controller.h +++ b/chrome/browser/ui/views/toolbar/toolbar_controller.h
@@ -13,13 +13,48 @@ #include "chrome/browser/ui/views/toolbar/overflow_button.h" #include "chrome/browser/ui/views/toolbar/toolbar_button.h" #include "chrome/browser/ui/views/toolbar/toolbar_view.h" +#include "ui/actions/action_id.h" #include "ui/views/layout/flex_layout_types.h" #include "ui/views/view.h" +class Browser; + // Manages toolbar elements' visibility using flex rules. class ToolbarController : public ui::SimpleMenuModel::Delegate { public: - // Data structure to store information of responsive elements. + // Manages action-based pinned toolbar elements. + class PinnedActionsDelegate { + public: + virtual actions::ActionItem* GetActionItemFor( + const actions::ActionId& id) = 0; + + // Returns true if the corresponding element is hidden. + virtual bool IsOverflowed(const actions::ActionId& id) = 0; + + protected: + virtual ~PinnedActionsDelegate() = default; + }; + + // Data structure to store information specifically used to support + // ui::ElementIdentifier as element reference. + struct ElementIdInfo { + // The identifier of toolbar element that potentially overflows. + ui::ElementIdentifier overflow_identifier; + + // Menu text when the element is overflow to the overflow menu. For + // ActionId-based elements this value is supplied when constructing action + // items. + int menu_text_id; + + // The toolbar button to be activated with menu text pressed. This is not + // necessarily the same as the element that overflows. E.g. when the + // overflowed element is kToolbarExtensionsContainerElementId the + // `activate_identifier` should be kExtensionsMenuButtonElementId. + ui::ElementIdentifier activate_identifier; + }; + + // Data structure to store information of responsive elements. Supports both + // ui::ElementIdentifier and ActionId as element reference. struct ResponsiveElementInfo { // Overflow menu structure: // ------------------- @@ -43,22 +78,14 @@ // |-----------------| // The toolbar element that potentially overflows. - ui::ElementIdentifier overflow_identifier; - - // Menu text when the element is overflow to the overflow menu. - int menu_text_id = 0; - - // The toolbar button to be activated with menu text pressed. This is not - // necessarily the same as the element that overflows. E.g. when the - // overflowed element is kToolbarExtensionsContainerElementId the - // `activate_identifier` should be kExtensionsMenuButtonElementId. - ui::ElementIdentifier activate_identifier; + absl::variant<ElementIdInfo, actions::ActionId> overflow_id; // True if current element is a section end in overflow menu structure. bool is_section_end = false; // Pop out button when `observed_identifier` is shown. End pop out when it's - // hidden. + // hidden. Could be empty e.g. when `overflow_key` is an ActionId that opens + // a side panel rather than a View bubble. std::optional<ui::ElementIdentifier> observed_identifier; }; @@ -67,7 +94,8 @@ const std::vector<ui::ElementIdentifier>& elements_in_overflow_order, int element_flex_order_start, views::View* toolbar_container_view, - views::View* overflow_button); + views::View* overflow_button, + PinnedActionsDelegate* PinnedActionsDelegate); ToolbarController(const ToolbarController&) = delete; ToolbarController& operator=(const ToolbarController&) = delete; ~ToolbarController() override; @@ -120,7 +148,8 @@ }; // Return the default responsive elements list in the toolbar. - static std::vector<ResponsiveElementInfo> GetDefaultResponsiveElements(); + static std::vector<ResponsiveElementInfo> GetDefaultResponsiveElements( + Browser* browser); // Return the element list in desired overflow order. The list should contain // only the immediate children of toolbar i.e. those managed by @@ -131,7 +160,7 @@ // Return the action name from element identifier. Return empty if not found. static std::string GetActionNameFromElementIdentifier( - ui::ElementIdentifier identifier); + absl::variant<ui::ElementIdentifier, actions::ActionId> identifier); // Force the UI element with the identifier to show. Return whether the action // is successful. @@ -171,7 +200,7 @@ std::vector<const ResponsiveElementInfo*> GetOverflowedElements(); // Check if element has overflowed. - bool IsOverflowed(ui::ElementIdentifier id) const; + bool IsOverflowed(const ResponsiveElementInfo& element) const; // ui::SimpleMenuModel::Delegate: void ExecuteCommand(int command_id, int event_flags) override; @@ -194,6 +223,8 @@ // `responsive_elements_` overflows. Owned by `toolbar_container_view_`. raw_ptr<views::View> overflow_button_; + const raw_ptr<PinnedActionsDelegate> pinned_actions_delegate_; + // A map to save the original and modified FlexSpecification of responsive // elements that need to pop out. Set when ToolbarController is initialized. base::flat_map<ui::ElementIdentifier, std::unique_ptr<PopOutState>>
diff --git a/chrome/browser/ui/views/toolbar/toolbar_controller_interactive_uitest.cc b/chrome/browser/ui/views/toolbar/toolbar_controller_interactive_uitest.cc index 67b59871..3c2d2927 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_controller_interactive_uitest.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_controller_interactive_uitest.cc
@@ -4,12 +4,19 @@ #include <sstream> #include "base/feature_list.h" +#include "base/functional/overloaded.h" #include "base/test/metrics/user_action_tester.h" #include "base/test/scoped_feature_list.h" +#include "chrome/app/chrome_command_ids.h" +#include "chrome/browser/ui/browser_commands.h" +#include "chrome/browser/ui/toolbar/pinned_toolbar_actions_model.h" #include "chrome/browser/ui/toolbar_controller_util.h" #include "chrome/browser/ui/ui_features.h" #include "chrome/browser/ui/views/frame/browser_view.h" +#include "chrome/browser/ui/views/side_panel/side_panel_coordinator.h" +#include "chrome/browser/ui/views/side_panel/side_panel_util.h" #include "chrome/browser/ui/views/toolbar/chrome_labs_button.h" +#include "chrome/browser/ui/views/toolbar/pinned_toolbar_actions_container.h" #include "chrome/browser/ui/views/toolbar/toolbar_controller.h" #include "chrome/browser/ui/views/toolbar/toolbar_view.h" #include "chrome/grit/generated_resources.h" @@ -35,7 +42,8 @@ public: ToolbarControllerUiTest() { ToolbarControllerUtil::SetPreventOverflowForTesting(false); - scoped_feature_list_.InitWithFeatures({features::kResponsiveToolbar}, {}); + scoped_feature_list_.InitWithFeatures( + {features::kResponsiveToolbar, features::kSidePanelPinning}, {}); } void SetUpOnMainThread() override { @@ -71,15 +79,6 @@ for (auto* element : toolbar_container_view_->children()) { diff_sum += element->GetPreferredSize().width() - element->GetMinimumSize().width(); - - // TODO(crbug.com/1479588): Ignore containers till issue addressed. - // This case only applies to containers. Now that containers are ignored - // their main items (i.e. extensions button, side panel button) width is - // excluded from the calculation too. So is the margin. - if (element->GetMinimumSize().width() == 0 && - element->GetPreferredSize().width() > 0) { - diff_sum += GetLayoutConstant(TOOLBAR_ICON_DEFAULT_MARGIN); - } } return toolbar_container_view_->GetPreferredSize().width() - diff_sum; } @@ -107,24 +106,48 @@ } // Forces `id` to overflow by filling toolbar with dummy buttons. - void AddDummyButtonsToToolbarTillElementOverflows(ui::ElementIdentifier id) { - // The element must be in toolbar. - const auto* element = toolbar_controller_->FindToolbarElementWithId( - toolbar_container_view_, id); - ASSERT_NE(element, nullptr); - + void AddDummyButtonsToToolbarTillElementOverflows( + absl::variant<ui::ElementIdentifier, actions::ActionId> id) { // This element must have been managed by controller. EXPECT_TRUE( - std::find_if(responsive_elements_.begin(), responsive_elements_.end(), - [id](ToolbarController::ResponsiveElementInfo element) { - return element.overflow_identifier == id; - }) != responsive_elements_.end()); + std::find_if( + responsive_elements_.begin(), responsive_elements_.end(), + [id](const ToolbarController::ResponsiveElementInfo& element) { + return absl::visit( + base::Overloaded( + [&](ToolbarController::ElementIdInfo overflow_id) { + return absl::holds_alternative<ui::ElementIdentifier>( + id) && + overflow_id.overflow_identifier == + absl::get<ui::ElementIdentifier>(id); + }, + [&](actions::ActionId overflow_id) { + return absl::holds_alternative<actions::ActionId>(id) && + overflow_id == absl::get<actions::ActionId>(id); + }), + element.overflow_id); + }) != responsive_elements_.end()); SetBrowserWidth(kBrowserContentAllowedMinimumWidth); - while (element->GetVisible()) { - toolbar_container_view_->AddChildView(CreateADummyButton()); - toolbar_container_view_->parent()->Layout(); - } + absl::visit( + base::Overloaded{ + [this](ui::ElementIdentifier id) { + const auto* element = + toolbar_controller_->FindToolbarElementWithId( + toolbar_container_view_, id); + ASSERT_NE(element, nullptr); + while (element->GetVisible()) { + toolbar_container_view_->AddChildView(CreateADummyButton()); + views::test::RunScheduledLayout(browser_view_); + } + }, + [this](actions::ActionId id) { + while (!delegate()->IsOverflowed(id)) { + toolbar_container_view_->AddChildView(CreateADummyButton()); + views::test::RunScheduledLayout(browser_view_); + } + }}, + id); } // This checks menu model, not the actual menu that pops up. @@ -137,8 +160,7 @@ const auto& responsive_elements = toolbar_controller_->responsive_elements_; for (size_t i = 0; i < responsive_elements.size(); ++i) { - if (toolbar_controller_->IsOverflowed( - responsive_elements[i].overflow_identifier)) { + if (toolbar_controller_->IsOverflowed(responsive_elements[i])) { if (toolbar_controller_->GetMenuText(responsive_elements[i]) != menu->GetLabelAt(menu->GetIndexOfCommandId(i).value())) { return false; @@ -149,12 +171,31 @@ })); } - auto ActivateMenuItemWithElementId(ui::ElementIdentifier id) { + auto ActivateMenuItemWithElementId( + absl::variant<ui::ElementIdentifier, actions::ActionId> id) { return Do([=]() { int command_id = -1; for (size_t i = 0; i < responsive_elements_.size(); ++i) { - if (responsive_elements_[i].overflow_identifier == id) { - command_id = i; + const auto& overflow_id = responsive_elements_[i].overflow_id; + absl::visit( + base::Overloaded( + [&](ToolbarController::ElementIdInfo overflow_id) { + if (absl::holds_alternative<ui::ElementIdentifier>(id) && + overflow_id.overflow_identifier == + absl::get<ui::ElementIdentifier>(id)) { + command_id = i; + return; + } + }, + [&](actions::ActionId overflow_id) { + if (absl::holds_alternative<actions::ActionId>(id) && + overflow_id == absl::get<actions::ActionId>(id)) { + command_id = i; + return; + } + }), + overflow_id); + if (command_id != -1) { break; } } @@ -165,6 +206,36 @@ }); } + auto ForceForwardButtonOverflow() { + return Steps(Do([this]() { + AddDummyButtonsToToolbarTillElementOverflows( + kToolbarForwardButtonElementId); + }), + WaitForHide(kToolbarForwardButtonElementId), + WaitForShow(kToolbarOverflowButtonElementId)); + } + + auto CheckActionItemOverflowed(actions::ActionId id, bool overflowed) { + return CheckResult([=]() { return delegate()->IsOverflowed(id); }, + overflowed); + } + + auto PinBookmarkToToolbar() { + return Steps(Do([=]() { + chrome::ExecuteCommand(browser(), + IDC_SHOW_BOOKMARK_SIDE_PANEL); + }), + WaitForShow(kSidePanelElementId), FlushEvents(), + PressButton(kSidePanelPinButtonElementId), + PressButton(kSidePanelCloseButtonElementId), + WaitForHide(kSidePanelElementId), FlushEvents()); + } + + auto SetBrowserSuperWide() { + return Steps(Do([this]() { SetBrowserWidth(3000); }), + WaitForHide(kToolbarOverflowButtonElementId)); + } + void SetBrowserWidth(int width) { int widget_width = browser_view_->GetWidget()->GetSize().width(); int browser_width = browser_view_->size().width(); @@ -179,6 +250,10 @@ toolbar_container_view_, id); } + gfx::Size dummy_button_size() { return dummy_button_size_; } + ToolbarController::PinnedActionsDelegate* delegate() { + return toolbar_controller_->pinned_actions_delegate_; + } const views::View* overflow_button() const { return overflow_button_; } int element_flex_order_start() const { return element_flex_order_start_; } const std::vector<ToolbarController::ResponsiveElementInfo>& @@ -315,11 +390,7 @@ NavigateWebContents(kPrimaryTabPageElementId, forward_url), PressButton(kToolbarBackButtonElementId), WaitForWebContentsNavigation(kPrimaryTabPageElementId, back_url), - EnsurePresent(kToolbarForwardButtonElementId), Do([this]() { - AddDummyButtonsToToolbarTillElementOverflows( - kToolbarForwardButtonElementId); - }), - WaitForHide(kToolbarForwardButtonElementId), + ForceForwardButtonOverflow(), PressButton(kToolbarOverflowButtonElementId), ActivateMenuItemWithElementId(kToolbarForwardButtonElementId), @@ -332,6 +403,122 @@ "ResponsiveToolbar.OverflowMenuItemActivated.ForwardButton")); } +IN_PROC_BROWSER_TEST_F(ToolbarControllerUiTest, + ActionItemsOverflowAndReappear) { + RunTestSequence(PinBookmarkToToolbar(), SetBrowserSuperWide(), + // Pinned bookmark button is visible. + CheckActionItemOverflowed( + ChromeActionIds::kActionSidePanelShowBookmarks, false), + + Do([this]() { + AddDummyButtonsToToolbarTillElementOverflows( + ChromeActionIds::kActionSidePanelShowBookmarks); + }), + CheckActionItemOverflowed( + ChromeActionIds::kActionSidePanelShowBookmarks, true), + WaitForShow(kToolbarOverflowButtonElementId), + + // Set browser super wide action item reappears. + SetBrowserSuperWide(), + CheckActionItemOverflowed( + ChromeActionIds::kActionSidePanelShowBookmarks, false), + WaitForHide(kToolbarOverflowButtonElementId)); +} + +IN_PROC_BROWSER_TEST_F(ToolbarControllerUiTest, + ActionItemsShowInMenuAndActivateFromMenu) { + RunTestSequence( + PinBookmarkToToolbar(), SetBrowserSuperWide(), Do([this]() { + AddDummyButtonsToToolbarTillElementOverflows( + ChromeActionIds::kActionSidePanelShowBookmarks); + }), + CheckActionItemOverflowed(ChromeActionIds::kActionSidePanelShowBookmarks, + true), + WaitForShow(kToolbarOverflowButtonElementId), + PressButton(kToolbarOverflowButtonElementId), + CheckMenuMatchesOverflowedElements(), + + // Check bookmark menu item is activated correctly. + ActivateMenuItemWithElementId( + ChromeActionIds::kActionSidePanelShowBookmarks), + WaitForShow(kSidePanelElementId), FlushEvents(), Check([this]() { + auto* coordinator = + SidePanelUtil::GetSidePanelCoordinatorForBrowser(browser()); + return coordinator->IsSidePanelEntryShowing( + SidePanelEntry::Key(SidePanelEntry::Id::kBookmarks)); + })); +} + +IN_PROC_BROWSER_TEST_F(ToolbarControllerUiTest, + ActivatedActionItemsDoNotOverflow) { + RunTestSequence( + PinBookmarkToToolbar(), SetBrowserSuperWide(), + CheckActionItemOverflowed(ChromeActionIds::kActionSidePanelShowBookmarks, + false), + EnsureNotPresent(kSidePanelElementId), + + // Open bookmark side panel. + Do([=]() { + chrome::ExecuteCommand(browser(), IDC_SHOW_BOOKMARK_SIDE_PANEL); + }), + WaitForShow(kSidePanelElementId), FlushEvents(), + ForceForwardButtonOverflow(), + + // Activated bookmark button is still visible because side panel is open + // even though it should overflow earlier than forward button. + CheckActionItemOverflowed(ChromeActionIds::kActionSidePanelShowBookmarks, + false), + + // Set browser wide still no overflow. + SetBrowserSuperWide(), + CheckActionItemOverflowed(ChromeActionIds::kActionSidePanelShowBookmarks, + false)); +} + +IN_PROC_BROWSER_TEST_F(ToolbarControllerUiTest, + DeactivatedActionItemsOverflow) { + RunTestSequence(PinBookmarkToToolbar(), SetBrowserSuperWide(), Do([this]() { + AddDummyButtonsToToolbarTillElementOverflows( + ChromeActionIds::kActionSidePanelShowBookmarks); + }), + CheckActionItemOverflowed( + ChromeActionIds::kActionSidePanelShowBookmarks, true), + WaitForShow(kToolbarOverflowButtonElementId), + PressButton(kToolbarOverflowButtonElementId), + ActivateMenuItemWithElementId( + ChromeActionIds::kActionSidePanelShowBookmarks), + WaitForShow(kSidePanelElementId), FlushEvents(), + + // Close bookmark side panel. + PressButton(kSidePanelCloseButtonElementId), + WaitForHide(kSidePanelElementId), FlushEvents(), + + // Pinned button overflows after side panel is closed. + CheckActionItemOverflowed( + ChromeActionIds::kActionSidePanelShowBookmarks, true)); +} + +IN_PROC_BROWSER_TEST_F(ToolbarControllerUiTest, + EveryElementHasActionMetricName) { + for (auto& it : ToolbarController::GetDefaultResponsiveElements(browser())) { + absl::visit( + base::Overloaded( + [](actions::ActionId id) { + EXPECT_NE( + ToolbarController::GetActionNameFromElementIdentifier(id), "") + << "Missing metric name for ActionId: " << id; + }, + [&](ToolbarController::ElementIdInfo id) { + EXPECT_NE(ToolbarController::GetActionNameFromElementIdentifier( + id.activate_identifier), + "") + << "Missing metric name for ElementIdentifier: " + << id.activate_identifier; + }), + it.overflow_id); + } +} + class ToolbarControllerIphUiTest : public ToolbarControllerUiTest { public: ToolbarControllerIphUiTest() {
diff --git a/chrome/browser/ui/views/toolbar/toolbar_controller_unittest.cc b/chrome/browser/ui/views/toolbar/toolbar_controller_unittest.cc index f610b031..9351699 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_controller_unittest.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_controller_unittest.cc
@@ -9,6 +9,7 @@ #include "chrome/browser/ui/views/chrome_layout_provider.h" #include "chrome/test/views/chrome_views_test_base.h" #include "testing/gmock/include/gmock/gmock.h" +#include "ui/actions/actions.h" #include "ui/base/models/simple_menu_model.h" #include "ui/events/test/event_generator.h" #include "ui/gfx/geometry/size.h" @@ -33,6 +34,49 @@ DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kDummyObservedView); DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kDummyActivateView); +class TestDelegate : public ToolbarController::PinnedActionsDelegate { + public: + MOCK_METHOD(void, + DummyAction, + (actions::ActionItem*, actions::ActionInvocationContext)); + TestDelegate() { + for (const auto& id : action_ids_) { + action_items_.push_back( + actions::ActionItem::ActionItemBuilder( + base::BindRepeating(&TestDelegate::DummyAction, + base::Unretained(this))) + .SetActionId(id) + .SetText( + base::StrCat({u"DummyAction", base::NumberToString16(id)})) + .Build()); + if (id == 0) { + kIdToOverflowedMap_[id] = false; + } else { + kIdToOverflowedMap_[id] = true; + ++overflowed_count_; + } + kIdToItemMap_[id] = action_items_[id].get(); + } + } + ~TestDelegate() override = default; + + actions::ActionItem* GetActionItemFor(const actions::ActionId& id) override { + return kIdToItemMap_.at(id); + } + bool IsOverflowed(const actions::ActionId& id) override { + return kIdToOverflowedMap_.at(id); + } + int get_overflowed_count() { return overflowed_count_; } + std::vector<actions::ActionId> get_action_ids() { return action_ids_; } + + private: + int overflowed_count_ = 0; + std::vector<actions::ActionId> action_ids_ = {0, 1, 2}; + std::vector<std::unique_ptr<actions::ActionItem>> action_items_; + base::flat_map<actions::ActionId, actions::ActionItem*> kIdToItemMap_; + base::flat_map<actions::ActionId, bool> kIdToOverflowedMap_; +}; + class MockToolbarController : public ToolbarController { public: MockToolbarController( @@ -41,12 +85,14 @@ const std::vector<ui::ElementIdentifier>& elements_in_overflow_order, int element_flex_order_start, views::View* toolbar_container_view, - views::View* overflow_button) + views::View* overflow_button, + TestDelegate* delegate) : ToolbarController(responsive_elements, elements_in_overflow_order, element_flex_order_start, toolbar_container_view, - overflow_button) {} + overflow_button, + delegate) {} MOCK_METHOD(bool, PopOut, (ui::ElementIdentifier identifier), (override)); MOCK_METHOD(bool, EndPopOut, (ui::ElementIdentifier identifier), (override)); }; @@ -95,12 +141,15 @@ TEST_F(PopOutHandlerTest, PopOutAndEndPopOut) { DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kDummyButton); + auto test_delegate = std::make_unique<TestDelegate>(); MockToolbarController toolbar_controller( std::vector<ToolbarController::ResponsiveElementInfo>( - {{kDummyButton, 0, kDummyActivateView, false, kDummyObservedView}}), + {{ToolbarController::ElementIdInfo{kDummyButton, 0, + kDummyActivateView}, + false, kDummyObservedView}}), std::vector<ui::ElementIdentifier>({kDummyButton}), 1, container_view(), - overflow_button()); + overflow_button(), test_delegate.get()); ui::ElementContext context = views::ElementTrackerViews::GetContextForWidget(widget()); @@ -128,12 +177,14 @@ const std::vector<ui::ElementIdentifier>& elements_in_overflow_order, int element_flex_order_start, views::View* toolbar_container_view, - views::View* overflow_button) + views::View* overflow_button, + TestDelegate* delegate) : ToolbarController(responsive_elements, elements_in_overflow_order, element_flex_order_start, toolbar_container_view, - overflow_button) {} + overflow_button, + delegate) {} std::u16string GetMenuText(const ToolbarController::ResponsiveElementInfo& element_info) const override { @@ -145,7 +196,9 @@ {kDummyButton4, u"DummyButton4"}, }); - return kToolbarToMenuTextMap.at(element_info.overflow_identifier); + return kToolbarToMenuTextMap.at( + absl::get<ToolbarController::ElementIdInfo>(element_info.overflow_id) + .overflow_identifier); } }; @@ -184,14 +237,22 @@ overflow_button_ = toolbar_container_view_->AddChildView(std::move(overflow_button)); overflow_button_->SetVisible(false); + test_delegate_ = std::make_unique<TestDelegate>(); toolbar_controller_ = std::make_unique<TestToolbarController>( std::vector<ToolbarController::ResponsiveElementInfo>( - {{kDummyButton1, 0, kDummyActivateView, false, kDummyObservedView}, - {kDummyButton2, 0, kDummyActivateView, true, kDummyObservedView}, - {kDummyButton3, 0, kDummyActivateView, true, kDummyObservedView}}), + {{ToolbarController::ElementIdInfo{kDummyButton1, 0, + kDummyActivateView}, + false, kDummyObservedView}, + {ToolbarController::ElementIdInfo{kDummyButton2, 0, + kDummyActivateView}, + true, kDummyObservedView}, + {ToolbarController::ElementIdInfo{kDummyButton3, 0, + kDummyActivateView}, + true, kDummyObservedView}}), std::vector<ui::ElementIdentifier>( {kDummyButton3, kDummyButton2, kDummyButton1}), - kElementFlexOrderStart, toolbar_container_view_, overflow_button_); + kElementFlexOrderStart, toolbar_container_view_, overflow_button_, + test_delegate_.get()); overflow_button_->set_create_menu_model_callback( base::BindRepeating(&ToolbarController::CreateOverflowMenuModel, base::Unretained(toolbar_controller_.get()))); @@ -221,6 +282,7 @@ event_generator_.reset(); toolbar_controller_.reset(); widget_.reset(); + test_delegate_.reset(); ChromeViewsTestBase::TearDown(); } @@ -242,11 +304,11 @@ return toolbar_controller()->GetOverflowedElements(); } const std::vector<ToolbarController::ResponsiveElementInfo>& - GetResponsiveElements() { - return toolbar_controller_->responsive_elements_; + GetResponsiveElements(const ToolbarController* toolbar_controller) { + return toolbar_controller->responsive_elements_; } bool IsOverflowed(const ToolbarController::ResponsiveElementInfo& element) { - return toolbar_controller_->IsOverflowed(element.overflow_identifier); + return toolbar_controller_->IsOverflowed(element); } private: @@ -255,6 +317,7 @@ std::unique_ptr<ui::test::EventGenerator> event_generator_; raw_ptr<views::View> toolbar_container_view_; raw_ptr<OverflowButton> overflow_button_; + std::unique_ptr<TestDelegate> test_delegate_; // Buttons being tested. std::vector<views::View*> test_buttons_; @@ -293,7 +356,7 @@ // Overflowed buttons should match overflow menu. EXPECT_TRUE(menu); - const auto& responsive_elements = GetResponsiveElements(); + const auto& responsive_elements = GetResponsiveElements(toolbar_controller()); for (size_t i = 0; i < responsive_elements.size(); ++i) { if (IsOverflowed(responsive_elements[i])) { EXPECT_EQ(toolbar_controller()->GetMenuText(responsive_elements[i]), @@ -330,16 +393,23 @@ } TEST_F(ToolbarControllerUnitTest, InValidFirstSectionAddsNoLeadingSeparator) { + auto test_delegate = std::make_unique<TestDelegate>(); std::unique_ptr<ToolbarController> test_controller = std::make_unique<TestToolbarController>( std::vector<ToolbarController::ResponsiveElementInfo>( - {{kDummyButton1, 0, kDummyActivateView, true}, - {kDummyButton2, 0, kDummyActivateView, true}, - {kDummyButton3, 0, kDummyActivateView, true}}), + {{ToolbarController::ElementIdInfo{kDummyButton1, 0, + kDummyActivateView}, + true}, + {ToolbarController::ElementIdInfo{kDummyButton2, 0, + kDummyActivateView}, + true}, + {ToolbarController::ElementIdInfo{kDummyButton3, 0, + kDummyActivateView}, + true}}), std::vector<ui::ElementIdentifier>( {kDummyButton3, kDummyButton2, kDummyButton1}), kElementFlexOrderStart, toolbar_container_view(), - const_cast<views::View*>(overflow_button())); + const_cast<views::View*>(overflow_button()), test_delegate.get()); widget()->SetSize(kButtonSize); SetOverflowButtonVisible(toolbar_controller()->ShouldShowOverflowButton()); @@ -368,16 +438,23 @@ } TEST_F(ToolbarControllerUnitTest, InValidSectionInMiddleAddsNoExtraSeparator) { + auto test_delegate = std::make_unique<TestDelegate>(); std::unique_ptr<ToolbarController> test_controller = std::make_unique<TestToolbarController>( std::vector<ToolbarController::ResponsiveElementInfo>( - {{kDummyButton1, 0, kDummyActivateView, true}, - {kDummyButton2, 0, kDummyActivateView, true}, - {kDummyButton3, 0, kDummyActivateView, true}}), + {{ToolbarController::ElementIdInfo{kDummyButton1, 0, + kDummyActivateView}, + true}, + {ToolbarController::ElementIdInfo{kDummyButton2, 0, + kDummyActivateView}, + true}, + {ToolbarController::ElementIdInfo{kDummyButton3, 0, + kDummyActivateView}, + true}}), std::vector<ui::ElementIdentifier>( {kDummyButton1, kDummyButton3, kDummyButton2}), kElementFlexOrderStart, toolbar_container_view(), - const_cast<views::View*>(overflow_button())); + const_cast<views::View*>(overflow_button()), test_delegate.get()); widget()->SetSize(kButtonSize); SetOverflowButtonVisible(toolbar_controller()->ShouldShowOverflowButton()); @@ -406,16 +483,23 @@ } TEST_F(ToolbarControllerUnitTest, InValidLastSectionAddsNoTrailingSeparator) { + auto test_delegate = std::make_unique<TestDelegate>(); std::unique_ptr<ToolbarController> test_controller = std::make_unique<TestToolbarController>( std::vector<ToolbarController::ResponsiveElementInfo>( - {{kDummyButton1, 0, kDummyActivateView, true}, - {kDummyButton2, 0, kDummyActivateView, true}, - {kDummyButton3, 0, kDummyActivateView, true}}), + {{ToolbarController::ElementIdInfo{kDummyButton1, 0, + kDummyActivateView}, + true}, + {ToolbarController::ElementIdInfo{kDummyButton2, 0, + kDummyActivateView}, + true}, + {ToolbarController::ElementIdInfo{kDummyButton3, 0, + kDummyActivateView}, + true}}), std::vector<ui::ElementIdentifier>( {kDummyButton1, kDummyButton2, kDummyButton3}), kElementFlexOrderStart, toolbar_container_view(), - const_cast<views::View*>(overflow_button())); + const_cast<views::View*>(overflow_button()), test_delegate.get()); widget()->SetSize(kButtonSize); SetOverflowButtonVisible(toolbar_controller()->ShouldShowOverflowButton()); @@ -535,16 +619,23 @@ // Buttons overflow in order: 1, 2, 3. TEST_F(ToolbarControllerUnitTest, ButtonsOverflowLeftToRightInContainer) { + auto test_delegate = std::make_unique<TestDelegate>(); std::unique_ptr<ToolbarController> dummy_controller = std::make_unique<TestToolbarController>( std::vector<ToolbarController::ResponsiveElementInfo>( - {{kDummyButton1, 0, kDummyActivateView}, - {kDummyButton2, 0, kDummyActivateView}, - {kDummyButton3, 0, kDummyActivateView}}), + {{ToolbarController::ElementIdInfo{kDummyButton1, 0, + kDummyActivateView}, + false}, + {ToolbarController::ElementIdInfo{kDummyButton2, 0, + kDummyActivateView}, + false}, + {ToolbarController::ElementIdInfo{kDummyButton3, 0, + kDummyActivateView}, + false}}), std::vector<ui::ElementIdentifier>( {kDummyButton1, kDummyButton2, kDummyButton3}), kElementFlexOrderStart, toolbar_container_view(), - const_cast<views::View*>(overflow_button())); + const_cast<views::View*>(overflow_button()), test_delegate.get()); views::View* button1 = test_buttons()[0]; views::View* button2 = test_buttons()[1]; @@ -598,23 +689,49 @@ const auto overflowed_buttons = GetOverflowedElements(); EXPECT_TRUE(menu); - const auto& responsive_elements = GetResponsiveElements(); + const auto& responsive_elements = GetResponsiveElements(toolbar_controller()); for (size_t i = 0; i < responsive_elements.size(); ++i) { if (IsOverflowed(responsive_elements[i])) { EXPECT_EQ(ToolbarController::FindToolbarElementWithId( toolbar_container_view(), - responsive_elements[i].overflow_identifier) + absl::get<ToolbarController::ElementIdInfo>( + responsive_elements[i].overflow_id) + .overflow_identifier) ->GetEnabled(), menu->IsEnabledAt(menu->GetIndexOfCommandId(i).value())); } } } -TEST_F(ToolbarControllerUnitTest, EveryActivateElementIdentifierHasActionName) { - for (auto& it : ToolbarController::GetDefaultResponsiveElements()) { - EXPECT_NE(ToolbarController::GetActionNameFromElementIdentifier( - it.activate_identifier), - "") - << it.activate_identifier; +TEST_F(ToolbarControllerUnitTest, SupportActionIds) { + auto test_delegate = std::make_unique<TestDelegate>(); + auto test_controller = std::make_unique<ToolbarController>( + std::vector<ToolbarController::ResponsiveElementInfo>( + {{test_delegate->get_action_ids()[0]}, + {test_delegate->get_action_ids()[1]}, + {test_delegate->get_action_ids()[2]}}), + std::vector<ui::ElementIdentifier>(), kElementFlexOrderStart, + toolbar_container_view(), const_cast<views::View*>(overflow_button()), + test_delegate.get()); + + SetOverflowButtonVisible(test_controller->ShouldShowOverflowButton()); + EXPECT_TRUE(overflow_button()->GetVisible()); + + const auto menu = test_controller->CreateOverflowMenuModel(); + EXPECT_TRUE(menu); + EXPECT_EQ(menu->GetItemCount(), + static_cast<size_t>(test_delegate->get_overflowed_count())); + + // Overflowed actions should match overflow menu. + const auto& responsive_elements = + GetResponsiveElements(test_controller.get()); + for (size_t i = 0; i < responsive_elements.size(); ++i) { + if (IsOverflowed(responsive_elements[i])) { + size_t index = menu->GetIndexOfCommandId(i).value(); + EXPECT_EQ(test_controller->GetMenuText(responsive_elements[i]), + menu->GetLabelAt(index)); + EXPECT_CALL(*test_delegate, DummyAction); + menu->ActivatedAt(index); + } } }
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.cc b/chrome/browser/ui/views/toolbar/toolbar_view.cc index 65a1642..ea5b459 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_view.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_view.cc
@@ -983,9 +983,9 @@ // TODO(crbug.com/1479588): Ignore containers till issue addressed. toolbar_controller_ = std::make_unique<ToolbarController>( - ToolbarController::GetDefaultResponsiveElements(), + ToolbarController::GetDefaultResponsiveElements(browser_), ToolbarController::GetDefaultOverflowOrder(), kToolbarFlexOrderStart, - container_view_, overflow_button_); + container_view_, overflow_button_, pinned_toolbar_actions_container_); overflow_button_->set_create_menu_model_callback( base::BindRepeating(&ToolbarController::CreateOverflowMenuModel,
diff --git a/chrome/browser/ui/views/webid/account_selection_bubble_view.cc b/chrome/browser/ui/views/webid/account_selection_bubble_view.cc index 303e284..aebaaae 100644 --- a/chrome/browser/ui/views/webid/account_selection_bubble_view.cc +++ b/chrome/browser/ui/views/webid/account_selection_bubble_view.cc
@@ -10,6 +10,7 @@ #include "base/feature_list.h" #include "base/i18n/case_conversion.h" #include "base/memory/weak_ptr.h" +#include "chrome/app/vector_icons/vector_icons.h" #include "chrome/browser/accessibility/accessibility_state_utils.h" #include "chrome/browser/image_fetcher/image_decoder_impl.h" #include "chrome/browser/ui/monogram_utils.h" @@ -57,6 +58,8 @@ constexpr int kDesiredAvatarSize = 30; // The desired size of the icon of the identity provider. constexpr int kDesiredIdpIconSize = 20; +// The desired size of the icon for the "Use another account" button. +constexpr int kDesiredUseOtherAccountIconSize = 20; // The size of the padding used at the top and bottom of the bubble. constexpr int kTopBottomPadding = 4; // The size of the horizontal padding between the bubble content and the edge of @@ -1023,13 +1026,8 @@ const content::IdentityProviderMetadata& idp_metadata = idp_display_data_list[0].idp_metadata; if (idp_metadata.supports_add_account) { - auto button = std::make_unique<ContinueButton>( - base::BindRepeating(&Observer::OnLoginToIdP, - base::Unretained(observer_), - idp_metadata.idp_login_url), - l10n_util::GetStringUTF16(IDS_ACCOUNT_SELECTION_ADD_ACCOUNT), this, - idp_metadata); - row->AddChildView(std::move(button)); + row->AddChildView(std::make_unique<views::Separator>()); + row->AddChildView(CreateUseOtherAccountButton(idp_metadata)); } // The maximum height that the multi-account-picker can have. This value was @@ -1118,6 +1116,21 @@ return row; } +std::unique_ptr<views::View> +AccountSelectionBubbleView::CreateUseOtherAccountButton( + const content::IdentityProviderMetadata& idp_metadata) { + auto button = std::make_unique<HoverButton>( + base::BindRepeating(&Observer::OnLoginToIdP, base::Unretained(observer_), + idp_metadata.idp_login_url), + ui::ImageModel::FromVectorIcon(kOpenInNewIcon, ui::kColorMenuIcon, + kDesiredUseOtherAccountIconSize), + l10n_util::GetStringUTF16(IDS_ACCOUNT_SELECTION_USE_OTHER_ACCOUNT)); + button->SetBorder(views::CreateEmptyBorder(gfx::Insets::TLBR( + /*top=*/2 * kVerticalSpacing, /*left=*/kLeftRightPadding, /*bottom=*/0, + /*right=*/kLeftRightPadding))); + return button; +} + void AccountSelectionBubbleView::UpdateHeader( const content::IdentityProviderMetadata& idp_metadata, const std::u16string subpage_title,
diff --git a/chrome/browser/ui/views/webid/account_selection_bubble_view.h b/chrome/browser/ui/views/webid/account_selection_bubble_view.h index 78f368e..6c07fa8 100644 --- a/chrome/browser/ui/views/webid/account_selection_bubble_view.h +++ b/chrome/browser/ui/views/webid/account_selection_bubble_view.h
@@ -157,6 +157,10 @@ const IdentityProviderDisplayData& idp_display_data, bool should_hover); + // Creates the "Use other account" button. + std::unique_ptr<views::View> CreateUseOtherAccountButton( + const content::IdentityProviderMetadata& idp_metadata); + // Updates the header title, the header icon visibility and the header back // button visibiltiy. `idp_metadata` is not null when we need to set a header // image based on the IDP.
diff --git a/chrome/browser/ui/views/webid/account_selection_bubble_view_unittest.cc b/chrome/browser/ui/views/webid/account_selection_bubble_view_unittest.cc index a05f3c5..69348e6 100644 --- a/chrome/browser/ui/views/webid/account_selection_bubble_view_unittest.cc +++ b/chrome/browser/ui/views/webid/account_selection_bubble_view_unittest.cc
@@ -597,7 +597,7 @@ /*expect_idp_row=*/false); } -TEST_F(AccountSelectionBubbleViewTest, AddAccount) { +TEST_F(AccountSelectionBubbleViewTest, UseDifferentAccount) { const std::vector<std::string> kAccountSuffixes = {"0"}; CreateMultiAccountPicker(kAccountSuffixes, true); @@ -605,13 +605,13 @@ ASSERT_EQ(children.size(), 3u); views::ScrollView* scroll_view = static_cast<views::ScrollView*>(children[2]); - ASSERT_EQ(scroll_view->contents()->children().size(), 2u); + ASSERT_EQ(scroll_view->contents()->children().size(), 3u); - // Check the "Add Account" button. - views::MdTextButton* button = - static_cast<views::MdTextButton*>(scroll_view->contents()->children()[1]); + // Check the "Use a different account" button. + HoverButton* button = + static_cast<HoverButton*>(scroll_view->contents()->children()[2]); ASSERT_TRUE(button); - EXPECT_EQ(button->GetText(), u"Add Account"); + EXPECT_EQ(button->GetText(), u"Use a different account"); } TEST_F(AccountSelectionBubbleViewTest, ReturningAccount) {
diff --git a/chrome/browser/ui/webui/ash/emoji/emoji_ui.cc b/chrome/browser/ui/webui/ash/emoji/emoji_ui.cc index 5cf47da..19de084 100644 --- a/chrome/browser/ui/webui/ash/emoji/emoji_ui.cc +++ b/chrome/browser/ui/webui/ash/emoji/emoji_ui.cc
@@ -19,6 +19,7 @@ #include "chrome/grit/emoji_picker_resources.h" #include "chrome/grit/emoji_picker_resources_map.h" #include "chrome/grit/generated_resources.h" +#include "chromeos/ash/components/emoji/grit/emoji_map.h" #include "content/public/browser/url_data_source.h" #include "content/public/browser/web_ui.h" #include "content/public/browser/web_ui_data_source.h" @@ -74,6 +75,7 @@ webui::SetupWebUIDataSource( source, base::make_span(kEmojiPickerResources, kEmojiPickerResourcesSize), IDR_EMOJI_PICKER_INDEX_HTML); + source->AddResourcePaths(base::make_span(kEmoji, kEmojiSize)); Profile* profile = Profile::FromWebUI(web_ui); content::URLDataSource::Add(profile,
diff --git a/chrome/browser/ui/webui/ash/settings/pages/files/google_drive_handler_browsertest.cc b/chrome/browser/ui/webui/ash/settings/pages/files/google_drive_handler_browsertest.cc index 9aa8422..4af0005 100644 --- a/chrome/browser/ui/webui/ash/settings/pages/files/google_drive_handler_browsertest.cc +++ b/chrome/browser/ui/webui/ash/settings/pages/files/google_drive_handler_browsertest.cc
@@ -293,7 +293,35 @@ .disabled_features = {ash::features::kDriveFsBulkPinning, ash::features::kFeatureManagementDriveFsBulkPinning}, - }}; + }, + + // OsSettingsRevampWayfinding feature test variations + { + .test_suffix = "BulkPinningAndGoogleDrivePage_Revamp", + .enabled_features = + {ash::features::kOsSettingsRevampWayfinding, + ash::features::kDriveFsBulkPinning, + ash::features::kFeatureManagementDriveFsBulkPinning, + ash::features::kFilesGoogleDriveSettingsPage}, + .disabled_features = {}, + }, + { + .test_suffix = "OnlyBulkPinning_Revamp", + .enabled_features = + {ash::features::kOsSettingsRevampWayfinding, + ash::features::kDriveFsBulkPinning, + ash::features::kFeatureManagementDriveFsBulkPinning}, + .disabled_features = {ash::features::kFilesGoogleDriveSettingsPage}, + }, + { + .test_suffix = "OnlyGoogleDrivePage_Revamp", + .enabled_features = {ash::features::kOsSettingsRevampWayfinding, + ash::features::kFilesGoogleDriveSettingsPage}, + .disabled_features = + {ash::features::kDriveFsBulkPinning, + ash::features::kFeatureManagementDriveFsBulkPinning}, + }, +}; INSTANTIATE_TEST_SUITE_P(, GoogleDriveHandlerTest,
diff --git a/chrome/browser/ui/webui/downloads/downloads.mojom b/chrome/browser/ui/webui/downloads/downloads.mojom index 68e76b9a..b28f6d7 100644 --- a/chrome/browser/ui/webui/downloads/downloads.mojom +++ b/chrome/browser/ui/webui/downloads/downloads.mojom
@@ -110,7 +110,17 @@ GetDownloads(array<string> search_terms); OpenFileRequiringGesture(string id); Drag(string id); + + // This shows the DownloadDangerPrompt (native UI dialog) and is obsoleted by + // the following four methods. + // TODO(chlily): Remove this when cleaning up ImprovedDownloadPageWarnings. SaveDangerousRequiringGesture(string id); + + // Called when "Download suspicious file" is clicked from the + // chrome://downloads overflow menu, for suspicious/unverified files. Does not + // show a prompt. + SaveSuspiciousRequiringGesture(string id); + DiscardDangerous(string id); RetryDownload(string id); Show(string id);
diff --git a/chrome/browser/ui/webui/downloads/downloads_dom_handler.cc b/chrome/browser/ui/webui/downloads/downloads_dom_handler.cc index 17acebd..a6e0471 100644 --- a/chrome/browser/ui/webui/downloads/downloads_dom_handler.cc +++ b/chrome/browser/ui/webui/downloads/downloads_dom_handler.cc
@@ -30,6 +30,7 @@ #include "chrome/browser/download/download_item_warning_data.h" #include "chrome/browser/download/download_prefs.h" #include "chrome/browser/download/download_query.h" +#include "chrome/browser/download/download_ui_safe_browsing_util.h" #include "chrome/browser/download/drag_download_item.h" #include "chrome/browser/download/offline_item_utils.h" #include "chrome/browser/platform_util.h" @@ -70,10 +71,15 @@ namespace { +using WarningAction = DownloadItemWarningData::WarningAction; +using WarningSurface = DownloadItemWarningData::WarningSurface; + enum DownloadsDOMEvent { DOWNLOADS_DOM_EVENT_GET_DOWNLOADS = 0, DOWNLOADS_DOM_EVENT_OPEN_FILE = 1, DOWNLOADS_DOM_EVENT_DRAG = 2, + // This is obsoleted by ImprovedDownloadPageWarnings. + // TODO(chlily): Clean up the value. DOWNLOADS_DOM_EVENT_SAVE_DANGEROUS = 3, DOWNLOADS_DOM_EVENT_DISCARD_DANGEROUS = 4, DOWNLOADS_DOM_EVENT_SHOW = 5, @@ -88,6 +94,7 @@ DOWNLOADS_DOM_EVENT_REVIEW_DANGEROUS = 14, DOWNLOADS_DOM_EVENT_DEEP_SCAN = 15, DOWNLOADS_DOM_EVENT_BYPASS_DEEP_SCAN = 16, + DOWNLOADS_DOM_EVENT_SAVE_SUSPICIOUS = 17, DOWNLOADS_DOM_EVENT_MAX }; @@ -110,6 +117,70 @@ OfflineItemUtils::GetContentIdForDownload(download)); } +// Records DownloadItemWarningData and maybe sends the Safe Browsing report. +// This should be called when the user takes a bypass action (either proceed or +// cancel). +void MaybeReportBypassAction(download::DownloadItem* file, + WarningSurface surface, + WarningAction action) { + CHECK(file); + CHECK(file->IsDangerous()); + CHECK(!file->IsDone()); + CHECK(surface == WarningSurface::DOWNLOADS_PAGE || + surface == WarningSurface::DOWNLOAD_PROMPT); + CHECK(action == WarningAction::PROCEED || action == WarningAction::CANCEL || + action == WarningAction::DISCARD); + // If this is called from the DOWNLOADS_PAGE, the action must be proceed or + // discard. There is no cancellation action on the page, because there's no + // prompt to cancel. + CHECK(surface != WarningSurface::DOWNLOADS_PAGE || + action != WarningAction::CANCEL); + + // The warning action event needs to be added before Safe Browsing report is + // sent, because this event should be included in the report. + DownloadItemWarningData::AddWarningActionEvent(file, surface, action); + + if (!file->GetURL().is_valid()) { + return; + } + if (content::BrowserContext* browser_context = + content::DownloadItemUtils::GetBrowserContext(file); + browser_context && browser_context->IsOffTheRecord()) { + return; + } + // Do not send cancel report since it's not a terminal action. + if (action != WarningAction::PROCEED && action != WarningAction::DISCARD) { + return; + } + SendSafeBrowsingDownloadReport( + safe_browsing::ClientSafeBrowsingReportRequest:: + DANGEROUS_DOWNLOAD_RECOVERY, + /*did_proceed=*/action == WarningAction::PROCEED, file); +} + +// Triggers a Trust and Safety sentiment survey (if enabled). Should be called +// when the user takes an explicit action to save or discard a +// suspicious/dangerous file. Not called when the prompt is merely shown. +void MaybeTriggerTrustSafetySurvey(download::DownloadItem* file, + WarningSurface surface, + WarningAction action) { + CHECK(file); + CHECK(surface == WarningSurface::DOWNLOADS_PAGE || + surface == WarningSurface::DOWNLOAD_PROMPT); + CHECK(action == WarningAction::PROCEED || action == WarningAction::DISCARD); + if (Profile* profile = Profile::FromBrowserContext( + content::DownloadItemUtils::GetBrowserContext(file)); + profile && + safe_browsing::IsSafeBrowsingSurveysEnabled(*profile->GetPrefs())) { + TrustSafetySentimentService* trust_safety_sentiment_service = + TrustSafetySentimentServiceFactory::GetForProfile(profile); + if (trust_safety_sentiment_service) { + trust_safety_sentiment_service->InteractedWithDownloadWarningUI(surface, + action); + } + } +} + } // namespace DownloadsDOMHandler::DownloadsDOMHandler( @@ -208,53 +279,51 @@ } } +// "Suspicious" in this context applies to insecure as well as dangerous +// downloads of certain danger types. +void DownloadsDOMHandler::SaveSuspiciousRequiringGesture( + const std::string& id) { + CHECK(base::FeatureList::IsEnabled( + safe_browsing::kImprovedDownloadPageWarnings)); + if (!GetWebUIWebContents()->HasRecentInteraction()) { + LOG(ERROR) << "SaveSuspiciousRequiringGesture received without recent " + "user interaction"; + return; + } + + CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_SAVE_SUSPICIOUS); + download::DownloadItem* file = GetDownloadByStringId(id); + if (!file || file->IsDone()) { + return; + } + + // If a download is insecure, validate that first. Is most cases, insecure + // download warnings will occur first, but in the worst case scenario, we show + // a dangerous warning twice. That's better than showing an insecure download + // warning, then dismissing the dangerous download warning. Since insecure + // downloads triggering the UI are temporary and rare to begin with, this + // should very rarely occur. + if (file->IsInsecure()) { + // `file` is potentially deleted. + file->ValidateInsecureDownload(); + } else if (file->IsDangerous()) { + MaybeReportBypassAction(file, WarningSurface::DOWNLOADS_PAGE, + WarningAction::PROCEED); + MaybeTriggerTrustSafetySurvey(file, WarningSurface::DOWNLOADS_PAGE, + WarningAction::PROCEED); + // `file` is potentially deleted. + file->ValidateDangerousDownload(); + } +} + void DownloadsDOMHandler::DiscardDangerous(const std::string& id) { CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_DISCARD_DANGEROUS); download::DownloadItem* download = GetDownloadByStringId(id); - if (download) { - content::DownloadManager* manager = GetMainNotifierManager(); - if (manager) { - Profile* profile = - Profile::FromBrowserContext(manager->GetBrowserContext()); - if (profile && - safe_browsing::IsSafeBrowsingSurveysEnabled(*(profile->GetPrefs()))) { - TrustSafetySentimentService* trust_safety_sentiment_service = - TrustSafetySentimentServiceFactory::GetForProfile(profile); - if (trust_safety_sentiment_service) { - // Survey triggered on DISCARD action only. If the user clicks to - // PROCEED in the downloads page, their choice is not confirmed until - // they PROCEED within the dangerous download prompt. - trust_safety_sentiment_service->InteractedWithDownloadWarningUI( - DownloadItemWarningData::WarningSurface::DOWNLOADS_PAGE, - DownloadItemWarningData::WarningAction::DISCARD); - } - } - } - // The warning action event needs to be added before Safe Browsing report is - // sent, because this event should be included in the report. - DownloadItemWarningData::AddWarningActionEvent( - download, DownloadItemWarningData::WarningSurface::DOWNLOADS_PAGE, - DownloadItemWarningData::WarningAction::DISCARD); - // If this download is no longer dangerous, is already canceled or - // completed, don't send any report. - // Only sends dangerous download discard report if : - // 1. Download is dangerous, and - // 2. Download is not canceled or completed, and - // 3. Download URL is not empty, and - // 4. User is not in incognito mode, and - if (download->IsDangerous() && !download->IsDone() && - !download->GetURL().is_empty() && - !GetMainNotifierManager()->GetBrowserContext()->IsOffTheRecord()) { - safe_browsing::SafeBrowsingService* sb_service = - g_browser_process->safe_browsing_service(); - if (sb_service) { - sb_service->SendDownloadReport( - download, - safe_browsing::ClientSafeBrowsingReportRequest:: - DANGEROUS_DOWNLOAD_RECOVERY, - /*did_proceed=*/false, /*show_download_in_folder=*/std::nullopt); - } - } + if (download && !download->IsDone() && download->IsDangerous()) { + MaybeReportBypassAction(download, WarningSurface::DOWNLOADS_PAGE, + WarningAction::DISCARD); + MaybeTriggerTrustSafetySurvey(download, WarningSurface::DOWNLOADS_PAGE, + WarningAction::DISCARD); } RemoveDownloadInArgs(id); } @@ -543,6 +612,8 @@ } } +// TODO(chlily): This is obsoleted by ImprovedDownloadPageWarnings. Clean this +// up. void DownloadsDOMHandler::ShowDangerPrompt( download::DownloadItem* dangerous_item) { DownloadDangerPrompt* danger_prompt = DownloadDangerPrompt::Create( @@ -553,6 +624,8 @@ DCHECK(danger_prompt); } +// TODO(chlily): This is obsoleted by ImprovedDownloadPageWarnings. Clean this +// up. void DownloadsDOMHandler::DangerPromptDone( int download_id, DownloadDangerPrompt::Action action) {
diff --git a/chrome/browser/ui/webui/downloads/downloads_dom_handler.h b/chrome/browser/ui/webui/downloads/downloads_dom_handler.h index b309b677..df5222f 100644 --- a/chrome/browser/ui/webui/downloads/downloads_dom_handler.h +++ b/chrome/browser/ui/webui/downloads/downloads_dom_handler.h
@@ -56,6 +56,7 @@ void OpenFileRequiringGesture(const std::string& id) override; void Drag(const std::string& id) override; void SaveDangerousRequiringGesture(const std::string& id) override; + void SaveSuspiciousRequiringGesture(const std::string& id) override; void DiscardDangerous(const std::string& id) override; void RetryDownload(const std::string& id) override; void Show(const std::string& id) override;
diff --git a/chrome/browser/ui/webui/downloads/downloads_dom_handler_unittest.cc b/chrome/browser/ui/webui/downloads/downloads_dom_handler_unittest.cc index 988b9e4..274b0b52 100644 --- a/chrome/browser/ui/webui/downloads/downloads_dom_handler_unittest.cc +++ b/chrome/browser/ui/webui/downloads/downloads_dom_handler_unittest.cc
@@ -7,7 +7,9 @@ #include <utility> #include <vector> +#include "base/files/file_path.h" #include "chrome/browser/download/download_item_model.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/safe_browsing/download_protection/download_protection_service.h" #include "chrome/browser/safe_browsing/test_safe_browsing_service.h" #include "chrome/browser/ui/hats/mock_trust_safety_sentiment_service.h" @@ -18,10 +20,14 @@ #include "chrome/test/base/testing_profile.h" #include "components/download/public/common/mock_download_item.h" #include "components/prefs/pref_service.h" +#include "components/safe_browsing/core/common/features.h" #include "components/safe_browsing/core/common/proto/csd.pb.h" +#include "content/public/browser/download_item_utils.h" #include "content/public/test/browser_task_environment.h" #include "content/public/test/mock_download_manager.h" +#include "content/public/test/test_renderer_host.h" #include "content/public/test/test_web_ui.h" +#include "content/public/test/web_contents_tester.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "testing/gmock/include/gmock/gmock.h" @@ -29,6 +35,10 @@ namespace { +using ::testing::Return; +using ::testing::ReturnRef; +using ::testing::ReturnRefOfCopy; + const char kTestDangerousDownloadUrl[] = "http://evildownload.com"; class TestDownloadsDOMHandler : public DownloadsDOMHandler { @@ -57,6 +67,14 @@ void SetUp() override { ON_CALL(manager_, GetBrowserContext()) .WillByDefault(testing::Return(&profile_)); + web_contents_ = + content::WebContentsTester::CreateTestWebContents(&profile_, nullptr); + web_ui()->set_web_contents(web_contents_.get()); + } + + void SimulateMouseGestureOnWebUI() { + content::WebContentsTester::For(web_ui()->GetWebContents()) + ->TestDidReceiveMouseDownEvent(); } TestingProfile* profile() { return &profile_; } @@ -70,6 +88,8 @@ // NOTE: The initialization order of these members matters. content::BrowserTaskEnvironment task_environment_; TestingProfile profile_; + content::RenderViewHostTestEnabler rvh_test_enabler_; + std::unique_ptr<content::WebContents> web_contents_; testing::NiceMock<content::MockDownloadManager> manager_; content::TestWebUI web_ui_; @@ -169,17 +189,34 @@ protected: void SetUpDangerousDownload() { EXPECT_CALL(dangerous_download_, IsDangerous()) - .WillRepeatedly(testing::Return(true)); - EXPECT_CALL(dangerous_download_, IsDone()) - .WillRepeatedly(testing::Return(false)); + .WillRepeatedly(Return(true)); + ON_CALL(dangerous_download_, IsInsecure()).WillByDefault(Return(false)); + EXPECT_CALL(dangerous_download_, IsDone()).WillRepeatedly(Return(false)); EXPECT_CALL(dangerous_download_, GetURL()) - .WillRepeatedly(testing::ReturnRef(download_url_)); + .WillRepeatedly(ReturnRef(download_url_)); + ON_CALL(dangerous_download_, GetTargetFilePath()) + .WillByDefault( + ReturnRefOfCopy(base::FilePath(FILE_PATH_LITERAL("foo.pdf")))); EXPECT_CALL(*manager(), GetDownload(1)) - .WillRepeatedly(testing::Return(&dangerous_download_)); + .WillRepeatedly(Return(&dangerous_download_)); safe_browsing::DownloadProtectionService::SetDownloadProtectionData( &dangerous_download_, "token", safe_browsing::ClientDownloadResponse::DANGEROUS, safe_browsing::ClientDownloadResponse::TailoredVerdict()); + content::DownloadItemUtils::AttachInfoForTesting(&dangerous_download_, + profile(), nullptr); + } + + void SetUpInsecureDownload() { + ON_CALL(dangerous_download_, IsDangerous()).WillByDefault(Return(false)); + EXPECT_CALL(dangerous_download_, IsInsecure()).WillRepeatedly(Return(true)); + EXPECT_CALL(dangerous_download_, IsDone()).WillRepeatedly(Return(false)); + EXPECT_CALL(dangerous_download_, GetURL()) + .WillRepeatedly(ReturnRef(download_url_)); + EXPECT_CALL(*manager(), GetDownload(1)) + .WillRepeatedly(Return(&dangerous_download_)); + content::DownloadItemUtils::AttachInfoForTesting(&dangerous_download_, + profile(), nullptr); } std::unique_ptr<safe_browsing::TestSafeBrowsingServiceFactory> @@ -187,7 +224,7 @@ raw_ptr<TestingBrowserProcess> browser_process_; scoped_refptr<safe_browsing::SafeBrowsingService> sb_service_; GURL download_url_ = GURL(kTestDangerousDownloadUrl); - testing::StrictMock<download::MockDownloadItem> dangerous_download_; + testing::NiceMock<download::MockDownloadItem> dangerous_download_; }; TEST_F(DownloadsDOMHandlerWithFakeSafeBrowsingTest, DiscardDangerous) { @@ -258,6 +295,8 @@ TestingProfile::Builder otr_profile_builder; otr_profile_builder.DisallowBrowserWindows(); Profile* incognito_profile = otr_profile_builder.BuildIncognito(profile()); + content::DownloadItemUtils::AttachInfoForTesting(&dangerous_download_, + incognito_profile, nullptr); ON_CALL(*manager(), GetBrowserContext()) .WillByDefault(testing::Return(incognito_profile)); @@ -274,25 +313,97 @@ .empty()); } +class DownloadsDOMHandlerTestImprovedDownloadPageWarnings + : public DownloadsDOMHandlerWithFakeSafeBrowsingTest { + public: + DownloadsDOMHandlerTestImprovedDownloadPageWarnings() { + feature_list_.InitAndEnableFeature( + safe_browsing::kImprovedDownloadPageWarnings); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +TEST_F(DownloadsDOMHandlerTestImprovedDownloadPageWarnings, + SaveSuspiciousRequiringGesture) { + SetUpDangerousDownload(); + + TestDownloadsDOMHandler handler(page_.BindAndGetRemote(), manager(), + web_ui()); + + SimulateMouseGestureOnWebUI(); + + EXPECT_CALL(dangerous_download_, ValidateDangerousDownload()); + handler.SaveSuspiciousRequiringGesture("1"); + + // Verify that dangerous download report is sent. + safe_browsing::ClientSafeBrowsingReportRequest expected_report; + std::string expected_serialized_report; + expected_report.set_url(GURL(kTestDangerousDownloadUrl).spec()); + expected_report.set_type(safe_browsing::ClientSafeBrowsingReportRequest:: + DANGEROUS_DOWNLOAD_RECOVERY); + expected_report.set_did_proceed(true); + expected_report.set_download_verdict( + safe_browsing::ClientDownloadResponse::DANGEROUS); + expected_report.set_token("token"); + expected_report.SerializeToString(&expected_serialized_report); + EXPECT_EQ(expected_serialized_report, + test_safe_browsing_factory_->test_safe_browsing_service() + ->serialized_download_report()); +} + +TEST_F(DownloadsDOMHandlerTestImprovedDownloadPageWarnings, + SaveSuspiciousRequiringGesture_InsecureDownload) { + SetUpInsecureDownload(); + + TestDownloadsDOMHandler handler(page_.BindAndGetRemote(), manager(), + web_ui()); + + SimulateMouseGestureOnWebUI(); + + EXPECT_CALL(dangerous_download_, ValidateInsecureDownload()); + handler.SaveSuspiciousRequiringGesture("1"); + + // No dangerous download report is sent for insecure downloads. + EXPECT_TRUE(test_safe_browsing_factory_->test_safe_browsing_service() + ->serialized_download_report() + .empty()); +} + +TEST_F(DownloadsDOMHandlerTestImprovedDownloadPageWarnings, + SaveSuspiciousRequiringGesture_NoRecentInteraction) { + SetUpDangerousDownload(); + + TestDownloadsDOMHandler handler(page_.BindAndGetRemote(), manager(), + web_ui()); + + EXPECT_CALL(dangerous_download_, ValidateDangerousDownload()).Times(0); + handler.SaveSuspiciousRequiringGesture("1"); +} + class DownloadsDOMHandlerWithFakeSafeBrowsingTestTrustSafetySentimentService : public DownloadsDOMHandlerWithFakeSafeBrowsingTest { public: - DownloadsDOMHandlerWithFakeSafeBrowsingTestTrustSafetySentimentService() = - default; + DownloadsDOMHandlerWithFakeSafeBrowsingTestTrustSafetySentimentService() { + feature_list_.InitAndEnableFeature( + safe_browsing::kImprovedDownloadPageWarnings); + } - void ExpectTrustSafetySentimentServiceCall() { + void ExpectTrustSafetySentimentServiceCall( + DownloadItemWarningData::WarningSurface surface, + DownloadItemWarningData::WarningAction action) { mock_sentiment_service_ = static_cast<MockTrustSafetySentimentService*>( TrustSafetySentimentServiceFactory::GetInstance() ->SetTestingFactoryAndUse( profile(), base::BindRepeating(&BuildMockTrustSafetySentimentService))); EXPECT_CALL(*mock_sentiment_service_, - InteractedWithDownloadWarningUI( - DownloadItemWarningData::WarningSurface::DOWNLOADS_PAGE, - DownloadItemWarningData::WarningAction::DISCARD)); + InteractedWithDownloadWarningUI(surface, action)); } private: + base::test::ScopedFeatureList feature_list_; raw_ptr<MockTrustSafetySentimentService> mock_sentiment_service_; }; @@ -300,9 +411,9 @@ DiscardDangerous_CallsTrustSafetySentimentService) { profile()->GetPrefs()->SetBoolean(prefs::kSafeBrowsingSurveysEnabled, true); SetUpDangerousDownload(); - EXPECT_CALL(dangerous_download_, IsDone()) - .WillRepeatedly(testing::Return(true)); - ExpectTrustSafetySentimentServiceCall(); + ExpectTrustSafetySentimentServiceCall( + DownloadItemWarningData::WarningSurface::DOWNLOADS_PAGE, + DownloadItemWarningData::WarningAction::DISCARD); TestDownloadsDOMHandler handler(page_.BindAndGetRemote(), manager(), web_ui()); @@ -310,3 +421,20 @@ EXPECT_CALL(dangerous_download_, Remove()); handler.DiscardDangerous("1"); } + +TEST_F(DownloadsDOMHandlerWithFakeSafeBrowsingTestTrustSafetySentimentService, + SaveSuspicious_CallsTrustSafetySentimentService) { + profile()->GetPrefs()->SetBoolean(prefs::kSafeBrowsingSurveysEnabled, true); + SetUpDangerousDownload(); + ExpectTrustSafetySentimentServiceCall( + DownloadItemWarningData::WarningSurface::DOWNLOADS_PAGE, + DownloadItemWarningData::WarningAction::PROCEED); + + TestDownloadsDOMHandler handler(page_.BindAndGetRemote(), manager(), + web_ui()); + + SimulateMouseGestureOnWebUI(); + + EXPECT_CALL(dangerous_download_, ValidateDangerousDownload()); + handler.SaveSuspiciousRequiringGesture("1"); +}
diff --git a/chrome/browser/ui/webui/downloads/downloads_page_interactive_uitest.cc b/chrome/browser/ui/webui/downloads/downloads_page_interactive_uitest.cc new file mode 100644 index 0000000..ee569ce --- /dev/null +++ b/chrome/browser/ui/webui/downloads/downloads_page_interactive_uitest.cc
@@ -0,0 +1,323 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/strings/stringprintf.h" +#include "base/test/bind.h" +#include "base/test/scoped_feature_list.h" +#include "chrome/browser/download/chrome_download_manager_delegate.h" +#include "chrome/browser/download/download_browsertest_utils.h" +#include "chrome/browser/download/download_core_service.h" +#include "chrome/browser/download/download_core_service_factory.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_element_identifiers.h" +#include "chrome/browser/ui/toolbar/app_menu_model.h" +#include "chrome/common/webui_url_constants.h" +#include "chrome/test/base/ui_test_utils.h" +#include "chrome/test/interaction/interactive_browser_test.h" +#include "chrome/test/interaction/tracked_element_webcontents.h" +#include "chrome/test/interaction/webcontents_interaction_test_util.h" +#include "components/download/public/common/download_danger_type.h" +#include "components/safe_browsing/core/common/features.h" +#include "content/public/test/browser_test.h" +#include "content/public/test/browser_test_utils.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/interaction/element_identifier.h" +#include "ui/base/interaction/interaction_sequence.h" + +namespace { + +DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kDownloadsPageTabId); + +class DownloadsPageInteractiveUitest + : public InteractiveBrowserTestT<DownloadTestBase> { + public: + DownloadsPageInteractiveUitest() { + feature_list_.InitAndEnableFeature( + safe_browsing::kImprovedDownloadPageWarnings); + } + ~DownloadsPageInteractiveUitest() override = default; + + void SetUp() override { + // This is necessary so that opening the downloads page via app menu will + // reliably open in the same tab. (It only opens in the same tab if the + // current tab is about:blank.) + set_open_about_blank_on_browser_launch(true); + InteractiveBrowserTestT<DownloadTestBase>::SetUp(); + } + + void SetUpOnMainThread() override { + InteractiveBrowserTestT<DownloadTestBase>::SetUpOnMainThread(); + embedded_test_server()->ServeFilesFromDirectory(GetTestDataDirectory()); + ASSERT_TRUE(embedded_test_server()->Start()); + } + + // Opens chrome://downloads via the app menu. All tests must begin with this + // step so that the identifier kDownloadsPageTabId is bound properly. + auto OpenDownloadsPage() { + DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kReadyEvent); + const DeepQuery kPathToDocumentHtml{ + "html", + }; + const char kNotLoadingFn[] = "el => el.getAttribute('loading') === null"; + // Waits for the page to finish loading. (This attribute is applied manually + // by the WebUI and has a TODO to be converted to a class instead, so this + // may be fragile.) + StateChange html_not_loading; + html_not_loading.type = StateChange::Type::kExistsAndConditionTrue; + html_not_loading.where = kPathToDocumentHtml; + html_not_loading.test_function = kNotLoadingFn; + html_not_loading.event = kReadyEvent; + return Steps(InstrumentTab(kDownloadsPageTabId), + PressButton(kToolbarAppMenuButtonElementId), + SelectMenuItem(AppMenuModel::kDownloadsMenuItem), + WaitForWebContentsNavigation( + kDownloadsPageTabId, GURL(chrome::kChromeUIDownloadsURL)), + WaitForStateChange(kDownloadsPageTabId, html_not_loading)); + } + + // Finds the first download item on the page and presses a button in its + // dropdown actions menu. + auto TakeTopmostItemAction(const std::string& menu_item_selector) { + DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kReadyEvent); + const DeepQuery kPathToMenuButton{ + "downloads-manager", + "downloads-item", + "#more-actions", + }; + const DeepQuery path_to_menu_option{ + "downloads-manager", + "downloads-item", + menu_item_selector, + }; + const char kClickFn[] = "el => el.click()"; + StateChange menu_item_visible; + menu_item_visible.type = StateChange::Type::kExists; + menu_item_visible.where = path_to_menu_option; + menu_item_visible.event = kReadyEvent; + return Steps(ExecuteJsAt(kDownloadsPageTabId, kPathToMenuButton, kClickFn), + WaitForStateChange(kDownloadsPageTabId, menu_item_visible), + // Use mouse input instead of JavaScript click() to satisfy the + // user gesture requirement for some menu options. + MoveMouseTo(kDownloadsPageTabId, path_to_menu_option), + ClickMouse()); + } + + // Presses the clear all button in the toolbar. + auto PressClearAll() { + const DeepQuery kPathToClearAllButton{ + "downloads-manager", + "downloads-toolbar", + ".clear-all", + }; + const char kClickFn[] = "el => el.click()"; + return ExecuteJsAt(kDownloadsPageTabId, kPathToClearAllButton, kClickFn); + } + + // Waits for `num` download items to be present in the downloads list. Note + // that iron-list keeps removed elements in the DOM (for possible reuse) so + // the number of download items present is not necessarily the number of list + // elements that are actually displayed, if items have been removed. + auto WaitForDownloadItems(int num) { + DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kReadyEvent); + const DeepQuery kPathToDownloadsList{ + "downloads-manager", + "#downloadsList", + }; + StateChange item_count_matches; + item_count_matches.type = StateChange::Type::kExistsAndConditionTrue; + item_count_matches.where = kPathToDownloadsList; + item_count_matches.test_function = base::StringPrintf( + "el => el.querySelectorAll('downloads-item').length === %d", num); + item_count_matches.event = kReadyEvent; + return WaitForStateChange(kDownloadsPageTabId, item_count_matches); + } + + // Waits for the "no downloads" splash screen to be displayed. + auto WaitForNoDownloads() { + DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kReadyEvent); + const DeepQuery kPathToNoDownloads{ + "downloads-manager", + "#no-downloads:not([hidden])", + }; + StateChange no_downloads_visible; + no_downloads_visible.type = StateChange::Type::kExists; + no_downloads_visible.where = kPathToNoDownloads; + no_downloads_visible.event = kReadyEvent; + return WaitForStateChange(kDownloadsPageTabId, no_downloads_visible); + } + + // Downloads a normal file. + auto DownloadTestFile() { + return Do(base::BindLambdaForTesting([&]() { + DownloadAndWait(browser(), + embedded_test_server()->GetURL(base::StrCat( + {"/", DownloadTestBase::kDownloadTest1Path}))); + })); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +IN_PROC_BROWSER_TEST_F(DownloadsPageInteractiveUitest, DownloadItemsAppear) { + RunTestSequence(OpenDownloadsPage(), // + DownloadTestFile(), // + WaitForDownloadItems(1), // + DownloadTestFile(), // + WaitForDownloadItems(2)); +} + +IN_PROC_BROWSER_TEST_F(DownloadsPageInteractiveUitest, RemoveDownloadItem) { + RunTestSequence(OpenDownloadsPage(), // + DownloadTestFile(), // + WaitForDownloadItems(1), // + TakeTopmostItemAction("#remove"), // + WaitForNoDownloads()); +} + +IN_PROC_BROWSER_TEST_F(DownloadsPageInteractiveUitest, ClearAll) { + RunTestSequence(OpenDownloadsPage(), // + DownloadTestFile(), // + DownloadTestFile(), // + WaitForDownloadItems(2), // + PressClearAll(), // + WaitForNoDownloads()); +} + +// A test fixture in which a dangerous download returns the template parameter +// danger type. +template <download::DownloadDangerType DangerType> +class DownloadsPageInteractiveUitestWithDangerType + : public DownloadsPageInteractiveUitest { + public: + // This is required to make a download appear to be a malicious danger type. + // TODO(chlily): Deduplicate from other places similar classes are used. + class TestDownloadManagerDelegate : public ChromeDownloadManagerDelegate { + public: + explicit TestDownloadManagerDelegate(Profile* profile) + : ChromeDownloadManagerDelegate(profile) { + if (!profile->IsOffTheRecord()) { + GetDownloadIdReceiverCallback().Run(download::DownloadItem::kInvalidId + + 1); + } + } + ~TestDownloadManagerDelegate() override = default; + + // ChromeDownloadManagerDelegate: + bool DetermineDownloadTarget( + download::DownloadItem* item, + content::DownloadTargetCallback* callback) override { + content::DownloadTargetCallback dangerous_callback = base::BindOnce( + &TestDownloadManagerDelegate::SetDangerous, std::move(*callback)); + bool run = ChromeDownloadManagerDelegate::DetermineDownloadTarget( + item, &dangerous_callback); + // ChromeDownloadManagerDelegate::DetermineDownloadTarget() needs to run + // the `callback`. + CHECK(run); + CHECK(!dangerous_callback); + return true; + } + + static void SetDangerous(content::DownloadTargetCallback callback, + const base::FilePath& target_path, + download::DownloadItem::TargetDisposition disp, + download::DownloadDangerType danger_type, + download::DownloadItem::InsecureDownloadStatus ids, + const base::FilePath& intermediate_path, + const base::FilePath& display_name, + const std::string& mime_type, + download::DownloadInterruptReason reason) { + std::move(callback).Run(target_path, disp, DangerType, ids, + intermediate_path, display_name, mime_type, + reason); + } + }; + + DownloadsPageInteractiveUitestWithDangerType() = default; + + void SetUpOnMainThread() override { + DownloadsPageInteractiveUitest::SetUpOnMainThread(); + auto test_delegate = + std::make_unique<TestDownloadManagerDelegate>(browser()->profile()); + DownloadCoreServiceFactory::GetForBrowserContext(browser()->profile()) + ->SetDownloadManagerDelegateForTesting(std::move(test_delegate)); + } + + // Downloads a dangerous file. It's a .swf file so that it's dangerous on all + // platforms (including CrOS). This .swf normally would be categorized as + // DANGEROUS_FILE, but TestDownloadManagerDelegate turns it into the template + // param DangerType. + auto DownloadDangerousTestFile() { + return Do(base::BindLambdaForTesting([&]() { + std::unique_ptr<content::DownloadTestObserver> waiter{ + DangerousDownloadWaiter( + browser(), /*num_downloads=*/1, + content::DownloadTestObserver::DangerousDownloadAction:: + ON_DANGEROUS_DOWNLOAD_QUIT)}; + GURL url = + embedded_test_server()->GetURL("/downloads/dangerous/dangerous.swf"); + EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), url)); + waiter->WaitForFinished(); + })); + } + + // Finds the topmost download item and waits for it to be dangerous or not + // dangerous. If `is_dangerous` is true and `expected_caption_color` is + // provided, also waits for the caption color to match. + auto WaitForTopmostItemDanger( + bool is_dangerous, + std::optional<std::string> expected_caption_color = std::nullopt) { + DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kReadyEvent); + const DeepQuery kPathToItemDangerCaption{"downloads-manager", + "downloads-item", ".description"}; + const char kHiddenFn[] = "el => el.getAttribute('hidden') %s null"; + const char kColorMatchCondition[] = + " && el.getAttribute('description-color') === '%s'"; + // If the download is dangerous, the caption is shown, so the hidden + // attribute is not present (i.e. equal to null). + std::string test_function = + base::StringPrintf(kHiddenFn, is_dangerous ? "===" : "!=="); + if (is_dangerous && expected_caption_color) { + base::StrAppend(&test_function, + {base::StringPrintf(kColorMatchCondition, + expected_caption_color->c_str())}); + } + StateChange danger_caption_visibility; + danger_caption_visibility.type = StateChange::Type::kExistsAndConditionTrue; + danger_caption_visibility.where = kPathToItemDangerCaption; + danger_caption_visibility.test_function = test_function; + danger_caption_visibility.event = kReadyEvent; + return WaitForStateChange(kDownloadsPageTabId, danger_caption_visibility); + } +}; + +// Uncommon downloads follow the "suspicious" pattern and show up with grey +// icons and text. They can be validated from the page directly without a +// confirmation dialog. +using DownloadsPageInteractiveUitestSuspicious = + DownloadsPageInteractiveUitestWithDangerType< + download::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT>; + +IN_PROC_BROWSER_TEST_F(DownloadsPageInteractiveUitestSuspicious, + DiscardSuspiciousFile) { + RunTestSequence(OpenDownloadsPage(), // + DownloadDangerousTestFile(), // + WaitForDownloadItems(1), // + WaitForTopmostItemDanger(true, "grey"), // + TakeTopmostItemAction("#discard-dangerous"), // + WaitForNoDownloads()); +} + +IN_PROC_BROWSER_TEST_F(DownloadsPageInteractiveUitestSuspicious, + ValidateSuspiciousFile) { + RunTestSequence(OpenDownloadsPage(), // + DownloadDangerousTestFile(), // + WaitForDownloadItems(1), // + WaitForTopmostItemDanger(true, "grey"), // + TakeTopmostItemAction("#save-dangerous"), // + WaitForTopmostItemDanger(false)); +} + +} // namespace
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc index 5c65ff9..f2d5c4ae 100644 --- a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc +++ b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
@@ -117,6 +117,14 @@ PrintPreviewUI::TestDelegate* g_test_delegate = nullptr; +// Returns true only for the first time it is called. +bool IsFirstInstanceSinceStartup() { + static bool first_instance = true; + bool first = first_instance; + first_instance = false; + return first; +} + void StopWorker(int document_cookie) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); if (document_cookie <= 0) @@ -421,6 +429,7 @@ std::unique_ptr<PrintPreviewHandler> handler) : ConstrainedWebDialogUI(web_ui), initial_preview_start_time_(base::TimeTicks::Now()), + first_print_usage_since_startup_(IsFirstInstanceSinceStartup()), handler_(handler.get()) { web_ui->AddMessageHandler(std::move(handler)); @@ -432,6 +441,7 @@ PrintPreviewUI::PrintPreviewUI(content::WebUI* web_ui) : ConstrainedWebDialogUI(web_ui), initial_preview_start_time_(base::TimeTicks::Now()), + first_print_usage_since_startup_(IsFirstInstanceSinceStartup()), handler_(CreatePrintPreviewHandlers(web_ui)) { // Allow requests to URLs like chrome-untrusted://print/. web_ui->AddRequestableScheme(content::kChromeUIUntrustedScheme); @@ -542,9 +552,13 @@ return; if (!initial_preview_start_time_.is_null()) { - base::UmaHistogramTimes( - "PrintPreview.InitialDisplayTime", - base::TimeTicks::Now() - initial_preview_start_time_); + base::TimeDelta display_time = + base::TimeTicks::Now() - initial_preview_start_time_; + base::UmaHistogramTimes("PrintPreview.InitialDisplayTime", display_time); + if (first_print_usage_since_startup_) { + base::UmaHistogramTimes("PrintPreview.InitialDisplayTimeFirstPrint", + display_time); + } initial_preview_start_time_ = base::TimeTicks(); }
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui.h b/chrome/browser/ui/webui/print_preview/print_preview_ui.h index 605463d..89784ab 100644 --- a/chrome/browser/ui/webui/print_preview/print_preview_ui.h +++ b/chrome/browser/ui/webui/print_preview/print_preview_ui.h
@@ -282,6 +282,9 @@ base::TimeTicks initial_preview_start_time_; + // Tracks if this is the first instance created since the browser started. + const bool first_print_usage_since_startup_; + // The unique ID for this class instance. Stored here to avoid calling // GetIDForPrintPreviewUI() everywhere. std::optional<int32_t> id_;
diff --git a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_ui.cc b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_ui.cc index 72ca621..3abc8ea6 100644 --- a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_ui.cc +++ b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_chrome_ui.cc
@@ -179,11 +179,12 @@ {"learnMore", IDS_LEARN_MORE}, {"learnMoreAboutFeatureA11yLabel", IDS_LEARN_MORE_ABOUT_FEATURE_A11Y_LABEL}, - {"thumbsDown", IDS_THUMBS_DOWN}, - {"thumbsUp", IDS_THUMBS_UP}, + {"thumbsDown", IDS_THUMBS_DOWN_OPENS_FEEDBACK_FORM_A11Y_LABEL}, + {"thumbsUp", IDS_THUMBS_UP_RESULTS_A11Y_LABEL}, {"wallpaperSearchPageHeader", IDS_NTP_WALLPAPER_SEARCH_PAGE_HEADER}, {"wallpaperSearchTileLabel", IDS_NTP_WALLPAPER_SEARCH_TILE_LABEL}, - }; + {"wallpaperSearchInspirationHeader", + IDS_NTP_WALLPAPER_SEARCH_INSPIRATION_HEADER}}; source->AddLocalizedStrings(kLocalizedStrings); source->AddBoolean( @@ -220,6 +221,11 @@ optimization_guide::proto::ModelExecutionFeature:: MODEL_EXECUTION_FEATURE_WALLPAPER_SEARCH))); + source->AddBoolean( + "wallpaperSearchInspirationCardEnabled", + wallpaper_search_flags_enabled && + base::FeatureList::IsEnabled( + ntp_features::kCustomizeChromeWallpaperSearchInspirationCard)); webui::SetupChromeRefresh2023(source); webui::SetupWebUIDataSource(
diff --git a/chrome/browser/ui/webui/side_panel/read_anything/read_anything_untrusted_page_handler.cc b/chrome/browser/ui/webui/side_panel/read_anything/read_anything_untrusted_page_handler.cc index d33e239..6618550 100644 --- a/chrome/browser/ui/webui/side_panel/read_anything/read_anything_untrusted_page_handler.cc +++ b/chrome/browser/ui/webui/side_panel/read_anything/read_anything_untrusted_page_handler.cc
@@ -79,10 +79,16 @@ ax_action_handler_observer_.Observe( ui::AXActionHandlerRegistry::GetInstance()); - coordinator_ = ReadAnythingCoordinator::FromBrowser(browser_.get()); - if (coordinator_) { - coordinator_->AddObserver(this); - coordinator_->AddModelObserver(this); + if (features::IsReadAnythingLocalSidePanelEnabled()) { + auto* active_web_contents = + browser_->tab_strip_model()->GetActiveWebContents(); + ObserveWebContentsSidePanelController(active_web_contents); + } else { + coordinator_ = ReadAnythingCoordinator::FromBrowser(browser_.get()); + if (coordinator_) { + coordinator_->AddObserver(this); + coordinator_->AddModelObserver(this); + } } if (features::IsReadAnythingWebUIToolbarEnabled()) { @@ -135,15 +141,18 @@ pdf_observer_.reset(); LogTextStyle(); - if (!coordinator_) { - return; + if (features::IsReadAnythingLocalSidePanelEnabled() && tab_helper_) { + // If |this| is destroyed before the |ReadAnythingSidePanelController|, then + // remove |this| from the observer lists. In the cases where the coordinator + // is destroyed first, these will have been destroyed before this call. + tab_helper_->RemovePageHandlerAsObserver(weak_factory_.GetWeakPtr()); + } else if (coordinator_) { + // If |this| is destroyed before the |ReadAnythingCoordinator|, then remove + // |this| from the observer lists. In the cases where the coordinator is + // destroyed first, these will have been destroyed before this call. + coordinator_->RemoveObserver(this); + coordinator_->RemoveModelObserver(this); } - - // If |this| is destroyed before the |ReadAnythingCoordinator|, then remove - // |this| from the observer lists. In the cases where the coordinator is - // destroyed first, these will have been destroyed before this call. - coordinator_->RemoveObserver(this); - coordinator_->RemoveModelObserver(this); } void ReadAnythingUntrustedPageHandler::PrimaryPageChanged() { @@ -327,6 +336,10 @@ coordinator_ = nullptr; } +void ReadAnythingUntrustedPageHandler::OnSidePanelControllerDestroyed() { + tab_helper_ = nullptr; +} + /////////////////////////////////////////////////////////////////////////////// // screen_ai::ScreenAIInstallState::Observer: /////////////////////////////////////////////////////////////////////////////// @@ -367,7 +380,6 @@ TabStripModel* tab_strip_model) { // If the TabStripModel is destroyed before |this|, remove |this| as an // observer. - DCHECK(browser_); tab_strip_model->RemoveObserver(this); } @@ -387,6 +399,12 @@ web_contents = browser_->tab_strip_model()->GetActiveWebContents(); } + if (features::IsReadAnythingLocalSidePanelEnabled()) { + if (!tab_helper_ && web_contents) { + ObserveWebContentsSidePanelController(web_contents); + } + } + main_observer_ = std::make_unique<ReadAnythingWebContentsObserver>( weak_factory_.GetSafeRef(), web_contents); pdf_observer_.reset(); @@ -489,3 +507,11 @@ // Trigger distillation. OnActiveAXTreeIDChanged(true); } + +void ReadAnythingUntrustedPageHandler::ObserveWebContentsSidePanelController( + content::WebContents* web_contents) { + tab_helper_ = ReadAnythingTabHelper::FromWebContents(web_contents); + if (tab_helper_) { + tab_helper_->AddPageHandlerAsObserver(weak_factory_.GetWeakPtr()); + } +}
diff --git a/chrome/browser/ui/webui/side_panel/read_anything/read_anything_untrusted_page_handler.h b/chrome/browser/ui/webui/side_panel/read_anything/read_anything_untrusted_page_handler.h index 307f023..ee85645 100644 --- a/chrome/browser/ui/webui/side_panel/read_anything/read_anything_untrusted_page_handler.h +++ b/chrome/browser/ui/webui/side_panel/read_anything/read_anything_untrusted_page_handler.h
@@ -10,10 +10,12 @@ #include "base/memory/raw_ptr.h" #include "base/memory/safe_ref.h" #include "base/memory/weak_ptr.h" +#include "chrome/browser/ui/side_panel/read_anything/read_anything_tab_helper.h" #include "chrome/browser/ui/tabs/tab_strip_model_observer.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/side_panel/read_anything/read_anything_coordinator.h" #include "chrome/browser/ui/views/side_panel/read_anything/read_anything_model.h" +#include "chrome/browser/ui/views/side_panel/read_anything/read_anything_side_panel_controller.h" #include "chrome/common/accessibility/read_anything.mojom.h" #include "components/services/screen_ai/buildflags/buildflags.h" #include "content/public/browser/ax_event_notification_details.h" @@ -69,6 +71,7 @@ public read_anything::mojom::UntrustedPageHandler, public ReadAnythingModel::Observer, public ReadAnythingCoordinator::Observer, + public ReadAnythingSidePanelController::Observer, #if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE) public screen_ai::ScreenAIInstallState::Observer, #endif @@ -134,6 +137,8 @@ void Activate(bool active) override; void OnCoordinatorDestroyed() override; void SetDefaultLanguageCode(const std::string& code) override; + // ReadAnythingSidePanelController::Observer: + void OnSidePanelControllerDestroyed() override; // TabStripModelObserver: void OnTabStripModelChanged( @@ -158,7 +163,13 @@ // Logs the current visual settings values. void LogTextStyle(); + // Adds this as an observer of the ReadAnythingSidePanelController tied to a + // WebContents. + void ObserveWebContentsSidePanelController( + content::WebContents* web_contents); + raw_ptr<ReadAnythingCoordinator> coordinator_; + raw_ptr<ReadAnythingTabHelper> tab_helper_; const base::WeakPtr<Browser> browser_; const raw_ptr<content::WebUI> web_ui_; const std::map<std::string, ReadAnythingFont> font_map_ = {
diff --git a/chrome/browser/vr/chrome_xr_integration_client.cc b/chrome/browser/vr/chrome_xr_integration_client.cc index e94d1b82..225a54fd 100644 --- a/chrome/browser/vr/chrome_xr_integration_client.cc +++ b/chrome/browser/vr/chrome_xr_integration_client.cc
@@ -27,10 +27,6 @@ #if BUILDFLAG(IS_WIN) #include "chrome/browser/vr/ui_host/vr_ui_host_impl.h" #elif BUILDFLAG(IS_ANDROID) -#if BUILDFLAG(ENABLE_GVR_SERVICES) -#include "chrome/browser/android/vr/gvr_install_helper.h" -#include "device/vr/android/gvr/gvr_device_provider.h" -#endif #if BUILDFLAG(ENABLE_ARCORE) #include "chrome/browser/android/vr/ar_jni_headers/ArCompositorDelegateProviderImpl_jni.h" #include "components/webxr/android/ar_compositor_delegate_provider.h" @@ -125,10 +121,6 @@ ChromeXrIntegrationClient::GetInstallHelper( device::mojom::XRDeviceId device_id) { switch (device_id) { -#if BUILDFLAG(ENABLE_GVR_SERVICES) - case device::mojom::XRDeviceId::GVR_DEVICE_ID: - return std::make_unique<GvrInstallHelper>(); -#endif // BUILDFLAG(ENABLE_GVR_SERVICES) #if BUILDFLAG(ENABLE_ARCORE) case device::mojom::XRDeviceId::ARCORE_DEVICE_ID: return std::make_unique<webxr::ArCoreInstallHelper>(); @@ -167,13 +159,6 @@ preferred_vr_runtime_added = true; } #endif // BUILDFLAG(ENABLE_CARDBOARD) -#if BUILDFLAG(ENABLE_GVR_SERVICES) - if (!preferred_vr_runtime_added && - IsEnabled(command_line, switches::kWebXrRuntimeGVR)) { - providers.push_back(std::make_unique<device::GvrDeviceProvider>()); - preferred_vr_runtime_added = true; - } -#endif // BUILDFLAG(ENABLE_GVR_SERVICES) #if BUILDFLAG(ENABLE_ARCORE) base::android::ScopedJavaLocalRef<jobject> j_ar_compositor_delegate_provider = vr::Java_ArCompositorDelegateProviderImpl_Constructor(
diff --git a/chrome/browser/webauthn/authenticator_request_dialog_model.cc b/chrome/browser/webauthn/authenticator_request_dialog_model.cc index 2e6cae21..c91f740 100644 --- a/chrome/browser/webauthn/authenticator_request_dialog_model.cc +++ b/chrome/browser/webauthn/authenticator_request_dialog_model.cc
@@ -508,6 +508,10 @@ } else { SetCurrentStep(Step::kErrorNoAvailableTransports); } + } else if (transport_availability_.request_type == + device::FidoRequestType::kMakeCredential && + hints_.transport && + StartGuidedFlowForMakeCredentialFromHint(*hints_.transport)) { } else if (ephemeral_state_.priority_mechanism_index_) { Mechanism& mechanism = mechanisms_[*ephemeral_state_.priority_mechanism_index_]; @@ -533,7 +537,10 @@ #endif )) { SetCurrentStep(Step::kSelectPriorityMechanism); - } else { + } else if (cred != nullptr || !hints_.transport.has_value() || + transport_availability_.request_type != + device::FidoRequestType::kGetAssertion || + !StartGuidedFlowForGetAssertionFromHint(*hints_.transport)) { mechanism.callback.Run(); } } else { @@ -595,10 +602,131 @@ StartWinNativeApi(); return; } - SetCurrentStep(Step::kMechanismSelection); + if (!hints_.transport.has_value() || + transport_availability_.request_type != + device::FidoRequestType::kGetAssertion || + // If there were any matches, ignore a hint and show the user the list. + base::ranges::any_of(mechanisms_, + [](const auto& mech) { + return absl::get_if<Mechanism::Credential>( + &mech.type); + }) || + !StartGuidedFlowForGetAssertionFromHint(*hints_.transport)) { + SetCurrentStep(Step::kMechanismSelection); + } } } +bool AuthenticatorRequestDialogModel::StartGuidedFlowForMakeCredentialFromHint( + AuthenticatorTransport transport) { + CHECK_EQ(transport_availability_.request_type, + device::FidoRequestType::kMakeCredential); + + // The RP has given a hint about the expected transport for a create() call. + // See https://w3c.github.io/webauthn/#enum-hints + switch (*hints_.transport) { + case AuthenticatorTransport::kUsbHumanInterfaceDevice: + if (transport_availability_.has_win_native_api_authenticator) { + StartWinNativeApi(); + } else if (base::Contains( + transport_availability_.available_transports, + AuthenticatorTransport::kUsbHumanInterfaceDevice)) { + StartGuidedFlowForTransport(*hints_.transport); + } else { + return false; + } + break; + case AuthenticatorTransport::kHybrid: + if (WebAuthnApiSupportsHybrid()) { + StartWinNativeApi(); + } else if (base::Contains(transport_availability_.available_transports, + AuthenticatorTransport::kHybrid)) { + if (!paired_phones_.empty()) { + SetCurrentStep(Step::kMechanismSelection); + } else { + StartGuidedFlowForAddPhone(); + } + } else { + return false; + } + break; + case AuthenticatorTransport::kInternal: + if (transport_availability_.has_win_native_api_authenticator) { + StartWinNativeApi(); + } else if (transport_availability_.has_icloud_keychain && + should_create_in_icloud_keychain_) { + StartICloudKeychain(); + } else if (base::Contains(transport_availability_.available_transports, + AuthenticatorTransport::kInternal)) { + StartGuidedFlowForTransport(*hints_.transport); + } else { + return false; + } + break; + default: + NOTREACHED(); + return false; + } + return true; +} + +bool AuthenticatorRequestDialogModel::StartGuidedFlowForGetAssertionFromHint( + AuthenticatorTransport transport) { + CHECK_EQ(transport_availability_.request_type, + device::FidoRequestType::kGetAssertion); + + // The RP has given a hint about the expected transport for a get() call. + // See https://w3c.github.io/webauthn/#enum-hints + switch (*hints_.transport) { + case AuthenticatorTransport::kUsbHumanInterfaceDevice: + if (transport_availability_.has_win_native_api_authenticator) { + StartWinNativeApi(); + } else if (base::Contains( + transport_availability_.available_transports, + AuthenticatorTransport::kUsbHumanInterfaceDevice)) { + StartGuidedFlowForTransport(*hints_.transport); + } else { + return false; + } + break; + case AuthenticatorTransport::kHybrid: + if (WebAuthnApiSupportsHybrid()) { + StartWinNativeApi(); + } else if (base::Contains(transport_availability_.available_transports, + AuthenticatorTransport::kHybrid)) { + if (base::ranges::any_of(mechanisms_, [](const auto& mechanism) { + return absl::get_if<Mechanism::Phone>(&mechanism.type) != nullptr; + })) { + SetCurrentStep(Step::kMechanismSelection); + } else { + StartGuidedFlowForAddPhone(); + } + } else { + return false; + } + return true; + case AuthenticatorTransport::kInternal: + // If we can enumerate platform credentials, and there's a match, we'll + // either jump to it immediately, or show an account selector. + if (transport_availability_.has_win_native_api_authenticator) { + StartWinNativeApi(); + } else { + // We might not be able to enumerate iCloud Keychain because of + // permissions issues, but that UI is bit limiting once we have jumped + // to it, and people who have denied Chrome that permission are a bit of + // a corner case, so we'll not currently jump to iCloud Keychain based + // on this hint. (It's only a click away.) + return false; + } + break; + default: + NOTREACHED(); + return false; + } + + return true; +} + void AuthenticatorRequestDialogModel::OnPhoneContactFailed( const std::string& name) { ContactNextPhoneByName(name); @@ -1960,13 +2088,22 @@ } } + // If the new UI is enabled, only show USB as an option if the QR code is + // not available, if tapping it would trigger a prompt to enable BLE, or if + // hints will cause us to jump to USB UI. + const bool include_usb_option = + base::FeatureList::IsEnabled(device::kWebAuthnNewPasskeyUI) && + base::Contains(transport_availability_.available_transports, + AuthenticatorTransport::kUsbHumanInterfaceDevice) && + (!include_add_phone_option || !transport_availability_.is_ble_powered || + transport_availability_.ble_access_denied || + hints_.transport == AuthenticatorTransport::kUsbHumanInterfaceDevice); + if (include_add_phone_option) { std::u16string label; if (base::FeatureList::IsEnabled(device::kWebAuthnNewPasskeyUI)) { - label = l10n_util::GetStringUTF16(GetHybridButtonLabel( - base::Contains(transport_availability_.available_transports, - AuthenticatorTransport::kUsbHumanInterfaceDevice), - specific_phones_listed)); + label = l10n_util::GetStringUTF16( + GetHybridButtonLabel(!include_usb_option, specific_phones_listed)); } else { label = l10n_util::GetStringUTF16( specific_phones_listed @@ -1979,11 +2116,7 @@ &AuthenticatorRequestDialogModel::StartGuidedFlowForAddPhone, base::Unretained(this))); } - if (base::FeatureList::IsEnabled(device::kWebAuthnNewPasskeyUI) && - (!include_add_phone_option || !transport_availability_.is_ble_powered || - transport_availability_.ble_access_denied)) { - // If the new UI is enabled, only show USB as an option if the QR code is - // not available or if tapping it would trigger a prompt to enable BLE. + if (include_usb_option) { transports_to_list_if_active.push_back( AuthenticatorTransport::kUsbHumanInterfaceDevice); } @@ -2078,6 +2211,7 @@ // For all other cases, go to the multi source passkey picker. return absl::nullopt; } + if (mechanisms_.size() == 1) { return 0; } else if (mechanisms_.empty()) {
diff --git a/chrome/browser/webauthn/authenticator_request_dialog_model.h b/chrome/browser/webauthn/authenticator_request_dialog_model.h index a7bac01..e1f0642b0 100644 --- a/chrome/browser/webauthn/authenticator_request_dialog_model.h +++ b/chrome/browser/webauthn/authenticator_request_dialog_model.h
@@ -331,6 +331,11 @@ // Valid action when at step: kNotStarted. void StartGuidedFlowForMostLikelyTransportOrShowMechanismSelection(); + bool HaveCredentialMechanisms() const; + bool StartGuidedFlowForMakeCredentialFromHint( + AuthenticatorTransport transport); + bool StartGuidedFlowForGetAssertionFromHint(AuthenticatorTransport transport); + // Proceeds straight to the platform authenticator prompt. If `type` is // `nullopt` then it actives the default platform authenticator. Otherwise it // actives the platform authenticator of the given type. @@ -629,6 +634,11 @@ is_enclave_authenticator_available_ = available; } + void SetHints( + const content::AuthenticatorRequestClientDelegate::Hints& hints) { + hints_ = hints; + } + void set_cable_transport_info( absl::optional<bool> extension_is_v2, std::vector<std::unique_ptr<device::cablev2::Pairing>> paired_phones, @@ -913,6 +923,10 @@ // profile authenticator. bool should_create_in_icloud_keychain_ = false; + // The RP's hints. See + // https://w3c.github.io/webauthn/#enumdef-publickeycredentialhints + content::AuthenticatorRequestClientDelegate::Hints hints_; + #if BUILDFLAG(IS_MAC) // did_record_macos_start_histogram_ is set to true if a histogram record of // starting the current request was made. Any later successful completion will
diff --git a/chrome/browser/webauthn/authenticator_request_dialog_model_unittest.cc b/chrome/browser/webauthn/authenticator_request_dialog_model_unittest.cc index d7aa2d0..2681a72f 100644 --- a/chrome/browser/webauthn/authenticator_request_dialog_model_unittest.cc +++ b/chrome/browser/webauthn/authenticator_request_dialog_model_unittest.cc
@@ -180,6 +180,9 @@ kCreateInICloudKeychain, kNoTouchId, kUVRequired, + kHintSecurityKeys, + kHintHybrid, + kHintClientDevice, }; base::StringPiece TransportAvailabilityParamToString( @@ -235,6 +238,12 @@ return "kNoTouchId"; case TransportAvailabilityParam::kUVRequired: return "kUVRequired"; + case TransportAvailabilityParam::kHintSecurityKeys: + return "kHintSecurityKeys"; + case TransportAvailabilityParam::kHintHybrid: + return "kHintHybrid"; + case TransportAvailabilityParam::kHintClientDevice: + return "kHintClientDevice"; } } @@ -364,6 +373,9 @@ const auto att_xplat = TransportAvailabilityParam::kAttachmentCrossPlatform; const auto ble_off = TransportAvailabilityParam::kBleDisabled; const auto ble_denied = TransportAvailabilityParam::kBleAccessDenied; + const auto hint_sk = TransportAvailabilityParam::kHintSecurityKeys; + const auto hint_hybrid = TransportAvailabilityParam::kHintHybrid; + const auto hint_plat = TransportAvailabilityParam::kHintClientDevice; [[maybe_unused]] const auto has_ickc = TransportAvailabilityParam::kHasICloudKeychain; [[maybe_unused]] const auto create_ickc = @@ -1092,6 +1104,105 @@ {ickc, t(internal)}, mss}, #endif + + // Tests for RP hints. + // + // create(): Security key hint should show security key UI. + {L, mc, {usb, internal, cable}, {rk, hint_sk}, {}, + {add, t(internal), t(usb)}, usb_ui}, + // But not if USB isn't a valid transport. + {L, mc, {internal, cable}, {rk, hint_sk}, {}, {add, t(internal)}, +#if BUILDFLAG(IS_MAC) + create_pk, +#else + qr, +#endif + }, + // If webauthn.dll is present, jump to it. + {L, mc, {cable}, {has_winapi, rk, hint_sk}, {}, {winapi, add}, plat_ui}, + + // create(): Hybrid hint should show QR. + {L, mc, {usb, internal, cable}, {rk, hint_hybrid}, {}, + {add, t(internal)}, qr}, + // Unless there are paired phones, in which case show the MSS. + {L, mc, {usb, internal, cable}, {rk, hint_hybrid}, {psync("a")}, {p("a"), + add, t(internal)}, mss}, + // But not if Hybrid isn't a valid transport. + {L, mc, {usb, internal}, {rk, hint_hybrid}, {}, {t(internal), t(usb)}, +#if BUILDFLAG(IS_MAC) + create_pk, +#else + mss, +#endif + }, + // If older webauthn.dll is present, don't jump to it since it doesn't do + // hybrid. + {L, mc, {cable}, {has_winapi, rk, hint_hybrid}, {}, {winapi, add}, qr}, +#if BUILDFLAG(IS_WIN) + // ... but do if it supports hybrid. + {L, mc, {cable}, {has_winapi, win_hybrid, rk, hint_hybrid}, {}, {winapi}, + plat_ui}, +#endif + + // create(): Client device hint should jump to the platform + // authenticator. + {L, mc, {usb, internal, cable}, {rk, hint_plat}, {}, {add, t(internal)}, +#if BUILDFLAG(IS_MAC) + create_pk, +#else + plat_ui, +#endif + }, + // But not if there isn't a platform authenticator. + {L, mc, {usb, cable}, {rk, hint_plat}, {}, {add}, qr}, + // If webauthn.dll is present, jump to it. + {L, mc, {cable}, {has_winapi, rk, hint_plat}, {}, {winapi, add}, + plat_ui}, + // Or if there's iCloud Keychain. + {L, mc, {cable}, {has_ickc, create_ickc, rk, hint_plat}, {}, {ickc, add}, + plat_ui}, + + // get(): Security key hint should show security key UI. + {L, ga, {usb, internal, cable}, {rk, hint_sk}, {}, {add, t(usb)}, + usb_ui}, + // But not if USB isn't a valid transport. + {L, ga, {internal, cable}, {rk, hint_sk}, {}, {add}, qr}, + // If credentials are found on a platform authenticator, they are still + // shown. + {L, ga, {usb, internal, cable}, {one_cred, rk, hint_sk}, {}, + {c(cred1), add, t(usb)}, mss}, + // If webauthn.dll is present, jump to it. + {L, ga, {cable}, {has_winapi, rk, hint_sk}, {}, {add, winapi}, plat_ui}, + + // get(): Hybrid hint should show QR. + {L, ga, {usb, internal, cable}, {rk, hint_hybrid}, {}, {add}, qr}, + // Unless there are paired phones listed, in which case show the MSS + {L, ga, {usb, internal, cable}, {rk, hint_hybrid}, {psync("a")}, + {p("a"), add}, mss}, + // But not if hybrid isn't available. + {L, ga, {usb, internal}, {rk, hint_hybrid}, {}, {t(usb)}, usb_ui}, + // If older webauthn.dll is present, don't jump to it since it doesn't do + // hybrid. + {L, ga, {cable}, {has_winapi, rk, hint_hybrid}, {}, {add, winapi}, qr}, +#if BUILDFLAG(IS_WIN) + // ... but do if it supports hybrid. + {L, ga, {cable}, {has_winapi, win_hybrid, rk, hint_hybrid}, {}, {winapi}, + plat_ui}, +#endif + // If credentials are found on a platform authenticator, they are still + // shown. + {L, ga, {usb, internal, cable}, {one_cred, rk, hint_hybrid}, {}, + {c(cred1), add}, mss}, + + // get(): Client device hint should trigger webauthn.dll, if it exists. + {L, ga, {cable}, {rk, has_winapi, hint_plat}, {}, {add, winapi}, + plat_ui}, + // But not if there's a credential match. + {L, ga, {usb, cable, internal}, {one_cred, has_winapi, rk, hint_plat}, + {}, {c(wincred1), add, winapi}, mss}, + // And otherwise it doesn't do anything because we generally assume that + // we can enumerate platform authenticators and do a good job. + {L, ga, {usb, cable, internal}, {rk, hint_plat}, {}, {add}, qr}, }; Test kListSyncedPasskeysTests_Windows[] { @@ -1327,6 +1438,28 @@ } #endif + absl::optional<device::FidoTransportProtocol> hint_transport; + if (base::Contains(test.params, + TransportAvailabilityParam::kHintSecurityKeys)) { + CHECK(!hint_transport.has_value()); + hint_transport = device::FidoTransportProtocol::kUsbHumanInterfaceDevice; + } + if (base::Contains(test.params, TransportAvailabilityParam::kHintHybrid)) { + CHECK(!hint_transport.has_value()); + hint_transport = device::FidoTransportProtocol::kHybrid; + } + if (base::Contains(test.params, + TransportAvailabilityParam::kHintClientDevice)) { + CHECK(!hint_transport.has_value()); + hint_transport = device::FidoTransportProtocol::kInternal; + } + + if (hint_transport.has_value()) { + content::AuthenticatorRequestClientDelegate::Hints hints; + hints.transport = hint_transport; + model.SetHints(hints); + } + model.SetAccountPreselectedCallback( base::BindRepeating([](device::PublicKeyCredentialDescriptor cred) {}));
diff --git a/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc b/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc index a408107..746976ad 100644 --- a/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc +++ b/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
@@ -903,6 +903,11 @@ #endif } +void ChromeAuthenticatorRequestDelegate::SetHints( + const AuthenticatorRequestClientDelegate::Hints& hints) { + dialog_model_->SetHints(hints); +} + void ChromeAuthenticatorRequestDelegate::SelectAccount( std::vector<device::AuthenticatorGetAssertionResponse> responses, base::OnceCallback<void(device::AuthenticatorGetAssertionResponse)>
diff --git a/chrome/browser/webauthn/chrome_authenticator_request_delegate.h b/chrome/browser/webauthn/chrome_authenticator_request_delegate.h index c596a5d..2572fef0 100644 --- a/chrome/browser/webauthn/chrome_authenticator_request_delegate.h +++ b/chrome/browser/webauthn/chrome_authenticator_request_delegate.h
@@ -175,6 +175,8 @@ base::span<const device::CableDiscoveryData> pairings_from_extension, bool is_enclave_authenticator_available, device::FidoDiscoveryFactory* discovery_factory) override; + void SetHints( + const AuthenticatorRequestClientDelegate::Hints& hints) override; void SelectAccount( std::vector<device::AuthenticatorGetAssertionResponse> responses, base::OnceCallback<void(device::AuthenticatorGetAssertionResponse)>
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index be7f91f..2b0f11f 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1702555132-5d422bf165078d94b0a1e0b078478941fdc94889.profdata +chrome-win32-main-1702565862-60e8c893b01792cd9cc936f4cb58a9a79244e23b.profdata
diff --git a/chrome/chrome_paks.gni b/chrome/chrome_paks.gni index 29949b7..c3e7430c 100644 --- a/chrome/chrome_paks.gni +++ b/chrome/chrome_paks.gni
@@ -296,6 +296,7 @@ "$root_gen_dir/chrome/supervision_resources.pak", "$root_gen_dir/chrome/vc_tray_tester_resources.pak", "$root_gen_dir/chromeos/ash/ash_resources.pak", + "$root_gen_dir/chromeos/ash/components/emoji/emoji.pak", "$root_gen_dir/chromeos/chromeos_help_app_bundle_resources.pak", "$root_gen_dir/chromeos/chromeos_help_app_kids_magazine_bundle_resources.pak", "$root_gen_dir/chromeos/chromeos_media_app_bundle_resources.pak", @@ -345,6 +346,7 @@ "//ash/webui/shimless_rma/resources:resources", "//ash/webui/status_area_internals/resources:resources", "//ash/webui/vc_background_ui/resources:resources", + "//chromeos/ash/components/emoji:resources", "//chromeos/ash/resources", "//chromeos/resources", "//ui/chromeos/styles:cros_styles_resources",
diff --git a/chrome/common/extensions/api/_api_features.json b/chrome/common/extensions/api/_api_features.json index 7e005a49..5c34186 100644 --- a/chrome/common/extensions/api/_api_features.json +++ b/chrome/common/extensions/api/_api_features.json
@@ -368,6 +368,9 @@ "documentScan.closeScanner": { "channel": "dev" }, + "documentScan.setOptions": { + "channel": "dev" + }, "documentScan.startScan": { "channel": "dev" },
diff --git a/chrome/common/extensions/api/autofill_private.idl b/chrome/common/extensions/api/autofill_private.idl index 633257c..1adfa8b 100644 --- a/chrome/common/extensions/api/autofill_private.idl +++ b/chrome/common/extensions/api/autofill_private.idl
@@ -12,9 +12,9 @@ boolean isEligibleForAddressAccountStorage; }; - // A copy of ServerFieldType from + // A copy of FieldType from // chrome/common/extensions/api/autofill_private.idl - enum ServerFieldType { + enum FieldType { NO_SERVER_DATA, UNKNOWN_TYPE, EMPTY_TYPE, @@ -162,7 +162,7 @@ // Represents single entry of the autofill profile, containing field type and // the corresponding field value. dictionary AddressField { - ServerFieldType type; + FieldType type; DOMString value; }; @@ -194,7 +194,7 @@ // different components to their addresses. dictionary AddressComponent { // The field type. - ServerFieldType field; + FieldType field; // The name of the field. DOMString fieldName;
diff --git a/chrome/common/extensions/api/document_scan.idl b/chrome/common/extensions/api/document_scan.idl index e9ca0499..ac49bc77 100644 --- a/chrome/common/extensions/api/document_scan.idl +++ b/chrome/common/extensions/api/document_scan.idl
@@ -212,7 +212,7 @@ (long or double)? min; (long or double)? max; (long or double)? quant; - (long[] or double[] or DOMString[])? list; + (double[] or long[] or DOMString[])? list; }; // How an option can be changed. @@ -248,7 +248,7 @@ // Current value of the option if relevant. Note the type passed here must // match the type specified in <code>type</code>. - (boolean or long or long[] or double or double[] or DOMString)? value; + (boolean or double or double[] or long or long[] or DOMString)? value; // Constraint on possible values. OptionConstraint? constraint; @@ -326,6 +326,52 @@ OperationResult result; }; + // A subset of <code>ScannerOption</code> that contains enough information to + // set an option to a new value. + [nodoc] dictionary OptionSetting { + // Name of the option to set. + DOMString name; + + // Type of the option. The requested type must match the real type of the + // underlying option. + OptionType type; + + // Value to set. Leave unset to request automatic setting for options that + // have <code>autoSettable</code> enabled. The type supplied for + // <code>value</code> must match <code>type</code>. + (boolean or double or double[] or long or long[] or DOMString)? value; + }; + + // The result of setting an individual option. Each individual option + // supplied to <code>setOptions()</code> produces a separate result on the + // backend due to things like rounding and constraints. + [nodoc] dictionary SetOptionResult { + // Name of the option that was set. + DOMString name; + + // Backend result of setting the option. + OperationResult result; + }; + + // The response from a call to <code>setOptions()</code>. + [nodoc] dictionary SetOptionsResponse { + // The same scanner handle passed to <code>setOptions()</code>. + DOMString scannerHandle; + + // One result per passed-in <code>OptionSetting</code>. + SetOptionResult[] results; + + // Updated key-value mapping from option names to + // <code>ScannerOption</code> containing the new configuration after + // attempting to set all supplied options. This has the same structure as + // the <code>options</code> field in <code>OpenScannerResponse</code>. + // + // This field will be set even if some options were not set successfully, + // but will be unset if retrieving the updated configuration fails (e.g., + // if the scanner is disconnected in the middle). + object? options; + }; + // Used to specify options for <code>startScan()</code>. [nodoc] dictionary StartScanOptions { // MIME type to return scanned data in. @@ -396,6 +442,11 @@ // Otherwise will return null and set runtime.lastError. [nodoc] callback CloseScannerCallback = void (CloseScannerResponse response); + // Callback from the <code>setOptions</code> method. + // |response| The response from setting the options, if the call was valid. + // Otherwise will return null and set runtime.lastError. + [nodoc] callback SetOptionsCallback = void (SetOptionsResponse response); + // Callback from the <code>startScan</code> method. // |response| The response from starting the scan, if the call was valid. // Otherwise will return null and set runtime.lastError. @@ -446,6 +497,20 @@ [nodoc, supportsPromises] static void closeScanner( DOMString scannerHandle, CloseScannerCallback callback); + // Sends the list of new option values in <code>options</code> as a bundle + // to be set on <code>scannerHandle</code>. Each option will be set by the + // backend the order specified. Returns a backend response indicating the + // result of each option setting and a new set of final option values after + // all options have been updated. + // |scannerHandle| : Open scanner handle previously returned from + // <code>openScanner</code>. + // |options| : A list of <code>OptionSetting</code>s that will be applied to + // <code>scannerHandle</code>. + // |callback| : Called with the result. + [nodoc, supportsPromises] static void setOptions( + DOMString scannerHandle, OptionSetting[] options, + SetOptionsCallback callback); + // Starts a scan using a previously opened scanner handle. A response // indicating the outcome will be sent to the callback. If successful, the // response will include a job handle that can be used in subsequent calls
diff --git a/chrome/common/extensions/api/scripting.idl b/chrome/common/extensions/api/scripting.idl index 44ec8a3..76f62e5 100644 --- a/chrome/common/extensions/api/scripting.idl +++ b/chrome/common/extensions/api/scripting.idl
@@ -142,15 +142,13 @@ // requirements are not met. Defaults to false, meaning that only the top // frame is matched. boolean? allFrames; - // Whether the script should inject into any frames where the URL belongs to - // a scheme that would never match a specified Match Pattern, including - // about:, data:, blob:, and filesystem: schemes. In these cases, in order - // to determine if the script should inject, the origin of the URL is - // checked. If the origin is `null` (as is the case for data: URLs), then - // the "initiator" or "creator" origin is used (i.e., the origin of the - // frame that created or navigated this frame). Note that this may not - // be the parent frame, if the frame was navigated by another frame in the - // document hierarchy. + // Indicates whether the script can be injected into frames where the URL + // contains an unsupported scheme; specifically: about:, data:, blob:, or + // filesystem:. In these cases, the URL's origin is checked to determine if + // the script should be injected. If the origin is `null` (as is the case + // for data: URLs) then the used origin is either the frame that created + // the current frame or the frame that initiated the navigation to this + // frame. Note that this may not be the parent frame. boolean? matchOriginAsFallback; // Specifies when JavaScript files are injected into the web page. The // preferred and default value is <code>document_idle</code>.
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index c30d857..6851cebf 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h
@@ -1528,9 +1528,11 @@ inline constexpr char kImportDialogSearchEngine[] = "import_dialog_search_engine"; +#if BUILDFLAG(IS_CHROMEOS) // Boolean controlling whether native client is force allowed by policy. inline constexpr char kNativeClientForceAllowed[] = "native_client_force_allowed"; +#endif // Profile avatar and name inline constexpr char kProfileAvatarIndex[] = "profile.avatar_index";
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 3850d13..d30ed46f 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -10788,6 +10788,7 @@ "../browser/ui/web_applications/web_app_interactive_uitest.cc", "../browser/ui/webui/access_code_cast/access_code_cast_dialog_browsertest.cc", "../browser/ui/webui/access_code_cast/access_code_cast_handler_browsertest.cc", + "../browser/ui/webui/downloads/downloads_page_interactive_uitest.cc", "../browser/ui/webui/settings/performance_settings_interactive_uitest.cc", "../browser/ui/webui/settings/settings_interactive_uitest.cc", "../browser/ui/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search_interactive_uitest.cc",
diff --git a/chrome/test/data/extensions/api_test/autofill_private/test.js b/chrome/test/data/extensions/api_test/autofill_private/test.js index a6885687..59adcd6 100644 --- a/chrome/test/data/extensions/api_test/autofill_private/test.js +++ b/chrome/test/data/extensions/api_test/autofill_private/test.js
@@ -260,43 +260,43 @@ chrome.autofillPrivate.saveAddress({ fields: [ { - type: chrome.autofillPrivate.ServerFieldType.NAME_FULL, + type: chrome.autofillPrivate.FieldType.NAME_FULL, value: NAME }, { - type: chrome.autofillPrivate.ServerFieldType.ADDRESS_HOME_STATE, + type: chrome.autofillPrivate.FieldType.ADDRESS_HOME_STATE, value: ADDRESS_LEVEL1 }, { - type: chrome.autofillPrivate.ServerFieldType.ADDRESS_HOME_CITY, + type: chrome.autofillPrivate.FieldType.ADDRESS_HOME_CITY, value: ADDRESS_LEVEL2 }, { - type: chrome.autofillPrivate.ServerFieldType + type: chrome.autofillPrivate.FieldType .ADDRESS_HOME_DEPENDENT_LOCALITY, value: ADDRESS_LEVEL3 }, { - type: chrome.autofillPrivate.ServerFieldType.ADDRESS_HOME_ZIP, + type: chrome.autofillPrivate.FieldType.ADDRESS_HOME_ZIP, value: POSTAL_CODE }, { - type: chrome.autofillPrivate.ServerFieldType + type: chrome.autofillPrivate.FieldType .ADDRESS_HOME_SORTING_CODE, value: SORTING_CODE }, { type: - chrome.autofillPrivate.ServerFieldType.ADDRESS_HOME_COUNTRY, + chrome.autofillPrivate.FieldType.ADDRESS_HOME_COUNTRY, value: COUNTRY_CODE }, { - type: chrome.autofillPrivate.ServerFieldType + type: chrome.autofillPrivate.FieldType .PHONE_HOME_WHOLE_NUMBER, value: PHONE }, { - type: chrome.autofillPrivate.ServerFieldType.EMAIL_ADDRESS, + type: chrome.autofillPrivate.FieldType.EMAIL_ADDRESS, value: EMAIL }, ], @@ -357,11 +357,11 @@ guid: addressGuid, fields: [ { - type: chrome.autofillPrivate.ServerFieldType.NAME_FULL, + type: chrome.autofillPrivate.FieldType.NAME_FULL, value: UPDATED_NAME }, { - type: chrome.autofillPrivate.ServerFieldType + type: chrome.autofillPrivate.FieldType .PHONE_HOME_WHOLE_NUMBER, value: UPDATED_PHONE },
diff --git a/chrome/test/data/extensions/api_test/document_scan/load_permissions.js b/chrome/test/data/extensions/api_test/document_scan/load_permissions.js index 0dfc034..8475a9a 100644 --- a/chrome/test/data/extensions/api_test/document_scan/load_permissions.js +++ b/chrome/test/data/extensions/api_test/document_scan/load_permissions.js
@@ -9,6 +9,7 @@ chrome.test.assertTrue(!!chrome.documentScan.getScannerList); chrome.test.assertTrue(!!chrome.documentScan.openScanner); chrome.test.assertTrue(!!chrome.documentScan.closeScanner); + chrome.test.assertTrue(!!chrome.documentScan.setOptions); chrome.test.assertTrue(!!chrome.documentScan.startScan); chrome.test.assertTrue(!!chrome.documentScan.cancelScan); chrome.test.assertTrue(!!chrome.documentScan.readScanData);
diff --git a/chrome/test/data/extensions/api_test/document_scan/perform_scan.js b/chrome/test/data/extensions/api_test/document_scan/perform_scan.js index d0b2b3f..2e70651 100644 --- a/chrome/test/data/extensions/api_test/document_scan/perform_scan.js +++ b/chrome/test/data/extensions/api_test/document_scan/perform_scan.js
@@ -219,5 +219,182 @@ chrome.test.assertEq(null, readResponse2.estimatedCompletion); chrome.test.succeed(); + }, + + async function setOptionsBeforeOpenFails() { + const response = await setOptions('invalid-handle', [ + {name: 'option', type: OptionType.INT}]); + chrome.test.assertEq('invalid-handle', response.scannerHandle); + chrome.test.assertEq(1, response.results.length); + chrome.test.assertEq(OperationResult.INVALID, response.results[0].result); + chrome.test.assertEq('option', response.results[0].name); + chrome.test.assertEq(null, response.options); + chrome.test.succeed(); + }, + + async function setOptionsRequiresMatchingTypes_Fixed() { + // Fixed options can be set from int or double because JS doesn't have a + // clear distinction between these. + const options = [ + {name: 'fixed1', type: OptionType.FIXED, value: 42}, // OK, mapped. + {name: 'fixed2', type: OptionType.FIXED, value: 42.0}, // OK, mapped. + {name: 'fixed3', type: OptionType.FIXED, value: 42.5}, // OK. + {name: 'fixed4', type: OptionType.FIXED, value: '1.0'}, // Wrong type. + {name: 'fixed5', type: OptionType.FIXED, value: [42, 43]}, // OK, mapped. + {name: 'fixed6', type: OptionType.FIXED, + value: [42.0, 43.0]}, // OK, mapped. + {name: 'fixed7', type: OptionType.FIXED, value: [42.5, 43.5]} // OK. + ]; + + const scannerHandle = await getScannerHandle(); + chrome.test.assertNe(null, scannerHandle); + + const response = await setOptions(scannerHandle, options); + chrome.test.assertEq(scannerHandle, response.scannerHandle); + chrome.test.assertEq(options.length, response.results.length); + // Match each result individually instead of one big array to make it easier + // to tell where any failures occur. + chrome.test.assertEq( + {name: 'fixed1', result: OperationResult.SUCCESS}, response.results[0]); + chrome.test.assertEq( + {name: 'fixed2', result: OperationResult.SUCCESS}, response.results[1]); + chrome.test.assertEq( + {name: 'fixed3', result: OperationResult.SUCCESS}, response.results[2]); + chrome.test.assertEq( + {name: 'fixed4', result: OperationResult.WRONG_TYPE}, + response.results[3]); + chrome.test.assertEq( + {name: 'fixed5', result: OperationResult.SUCCESS}, response.results[4]); + chrome.test.assertEq( + {name: 'fixed6', result: OperationResult.SUCCESS}, response.results[5]); + chrome.test.assertEq( + {name: 'fixed7', result: OperationResult.SUCCESS}, response.results[6]); + + chrome.test.assertNe(null, response.options); + chrome.test.succeed(); + }, + + async function setOptionsRequiresMatchingTypes_Int() { + // Int options can be set from int values or from double values with a zero + // fractional part because JS doesn't have a clear distinction between + // these. + const options = [ + {name: 'int1', type: OptionType.INT, value: 42}, // OK. + {name: 'int2', type: OptionType.INT, value: 42.0}, // OK, mapped. + {name: 'int3', type: OptionType.INT, value: 42.5}, // Wrong type. + {name: 'int4', type: OptionType.INT, value: '1.0'}, // Wrong type. + {name: 'int5', type: OptionType.INT, value: [42, 42]}, // OK. + {name: 'int6', type: OptionType.INT, value: [42.0, 42.0]}, // OK, mapped. + {name: 'int7', type: OptionType.INT, value: [42.5]}, // Wrong type. + {name: 'int8', type: OptionType.INT, value: 1e300}, // Wrong type. + {name: 'int9', type: OptionType.INT, value: -1e300}, // Wrong type. + {name: 'int10', type: OptionType.INT, value: [1e300]}, // Wrong type. + {name: 'int11', type: OptionType.INT, value: [-1e300]} // Wrong type. + ]; + + const scannerHandle = await getScannerHandle(); + chrome.test.assertNe(null, scannerHandle); + + const response = await setOptions(scannerHandle, options); + chrome.test.assertEq(scannerHandle, response.scannerHandle); + chrome.test.assertEq(options.length, response.results.length); + // Match each result individually instead of one big array to make it easier + // to tell where any failures occur. + chrome.test.assertEq( + {name: 'int1', result: OperationResult.SUCCESS}, response.results[0]); + chrome.test.assertEq( + {name: 'int2', result: OperationResult.SUCCESS}, response.results[1]); + chrome.test.assertEq( + {name: 'int3', result: OperationResult.WRONG_TYPE}, response.results[2]); + chrome.test.assertEq( + {name: 'int4', result: OperationResult.WRONG_TYPE}, response.results[3]); + chrome.test.assertEq( + {name: 'int5', result: OperationResult.SUCCESS}, response.results[4]); + chrome.test.assertEq( + {name: 'int6', result: OperationResult.SUCCESS}, response.results[5]); + chrome.test.assertEq( + {name: 'int7', result: OperationResult.WRONG_TYPE}, response.results[6]); + chrome.test.assertEq( + {name: 'int8', result: OperationResult.WRONG_TYPE}, response.results[7]); + chrome.test.assertEq( + {name: 'int9', result: OperationResult.WRONG_TYPE}, response.results[8]); + chrome.test.assertEq( + {name: 'int10', result: OperationResult.WRONG_TYPE}, + response.results[9]); + chrome.test.assertEq( + {name: 'int11', result: OperationResult.WRONG_TYPE}, + response.results[10]); + + chrome.test.assertNe(null, response.options); + chrome.test.succeed(); + }, + + async function setOptionsRequiresMatchingTypes_Bool() { + // Bool options can only be set from a bool. + const options = [ + {name: 'bool1', type: OptionType.BOOL, value: true}, // OK. + {name: 'bool2', type: OptionType.BOOL, value: 1}, // Wrong type. + {name: 'bool3', type: OptionType.BOOL, value: 'true'}, // Wrong type. + {name: 'bool4', type: OptionType.BOOL, value: [1]} // Wrong type. + ]; + + const scannerHandle = await getScannerHandle(); + chrome.test.assertNe(null, scannerHandle); + + const response = await setOptions(scannerHandle, options); + chrome.test.assertEq(scannerHandle, response.scannerHandle); + chrome.test.assertEq(options.length, response.results.length); + // Match each result individually instead of one big array to make it easier + // to tell where any failures occur. + chrome.test.assertEq( + {name: 'bool1', result: OperationResult.SUCCESS}, response.results[0]); + chrome.test.assertEq( + {name: 'bool2', result: OperationResult.WRONG_TYPE}, + response.results[1]); + chrome.test.assertEq( + {name: 'bool3', result: OperationResult.WRONG_TYPE}, + response.results[2]); + chrome.test.assertEq( + {name: 'bool4', result: OperationResult.WRONG_TYPE}, + response.results[3]); + + chrome.test.assertNe(null, response.options); + chrome.test.succeed(); + }, + + async function setOptionsRequiresMatchingTypes_String() { + // String options can only be set from a string. + const options = [ + {name: 'string1', type: OptionType.STRING, value: 's'}, // OK. + {name: 'string2', type: OptionType.STRING, value: ''}, // OK. + {name: 'string3', type: OptionType.STRING, value: 1}, // Wrong type. + {name: 'string4', type: OptionType.STRING, value: [1]}, // Wrong type. + {name: 'string5', type: OptionType.STRING, value: true}, // Wrong type. + ]; + + const scannerHandle = await getScannerHandle(); + chrome.test.assertNe(null, scannerHandle); + + const response = await setOptions(scannerHandle, options); + chrome.test.assertEq(scannerHandle, response.scannerHandle); + chrome.test.assertEq(options.length, response.results.length); + // Match each result individually instead of one big array to make it easier + // to tell where any failures occur. + chrome.test.assertEq( + {name: 'string1', result: OperationResult.SUCCESS}, response.results[0]); + chrome.test.assertEq( + {name: 'string2', result: OperationResult.SUCCESS}, response.results[1]); + chrome.test.assertEq( + {name: 'string3', result: OperationResult.WRONG_TYPE}, + response.results[2]); + chrome.test.assertEq( + {name: 'string4', result: OperationResult.WRONG_TYPE}, + response.results[3]); + chrome.test.assertEq( + {name: 'string5', result: OperationResult.WRONG_TYPE}, + response.results[4]); + + chrome.test.assertNe(null, response.options); + chrome.test.succeed(); } ]);
diff --git a/chrome/test/data/extensions/api_test/document_scan/scan_utils.js b/chrome/test/data/extensions/api_test/document_scan/scan_utils.js index a5a1c9f9..652c503e 100644 --- a/chrome/test/data/extensions/api_test/document_scan/scan_utils.js +++ b/chrome/test/data/extensions/api_test/document_scan/scan_utils.js
@@ -3,6 +3,7 @@ // found in the LICENSE file. OperationResult = chrome.documentScan.OperationResult; +OptionType = chrome.documentScan.OptionType; async function getScannerList(filter) { return new Promise(resolve => { @@ -67,3 +68,9 @@ chrome.documentScan.readScanData(jobHandle, resolve); }); } + +async function setOptions(scannerHandle, options) { + return new Promise(resolve => { + chrome.documentScan.setOptions(scannerHandle, options, resolve); + }); +}
diff --git a/chrome/test/data/webui/chromeos/BUILD.gn b/chrome/test/data/webui/chromeos/BUILD.gn index 9dc1839..81a28217 100644 --- a/chrome/test/data/webui/chromeos/BUILD.gn +++ b/chrome/test/data/webui/chromeos/BUILD.gn
@@ -270,7 +270,7 @@ webui_module_path = "/" # Used by legacy MojoWebUIBrowserTest. - generate_legacy_js_bindings = true + use_typescript_sources = false } generate_grd("build_web_ui_test_mojo_grdp") {
diff --git a/chrome/test/data/webui/chromeos/ash_common/shortcut_input_test.ts b/chrome/test/data/webui/chromeos/ash_common/shortcut_input_test.ts index 94b0777..8cc838d 100644 --- a/chrome/test/data/webui/chromeos/ash_common/shortcut_input_test.ts +++ b/chrome/test/data/webui/chromeos/ash_common/shortcut_input_test.ts
@@ -458,4 +458,132 @@ prerewrittenReleasedKeyEvent, shortcutInputProvider.getPrerewrittenKeyEvent()); }); + + test('PressAndReleaseSingleKeyWhenUpdateOnKeyPress', async () => { + shortcutInputElement!.updateOnKeyPress = true; + shortcutInputElement!.startObserving(); + + const keyEvent = { + vkey: VKey.kKeyA, + domCode: 0, + domKey: 0, + modifiers: 0, + keyDisplay: 'a', + }; + + // Press 'a', expect pendingKey keyDisplay is 'a'. + shortcutInputProvider.sendKeyPressEvent(keyEvent, keyEvent); + await flushTasks(); + let pendingKey: ShortcutInputKeyElement|null = + getPendingKeyElement(shortcutInputElement); + assertTrue(isVisible(pendingKey)); + assertEquals('a', pendingKey!.key); + + // Release 'a', expect pendingKey keyDisplay has reset to 'key'. + shortcutInputProvider.sendKeyReleaseEvent(keyEvent, keyEvent); + await flushTasks(); + pendingKey = getPendingKeyElement(shortcutInputElement); + assertTrue(isVisible(pendingKey)); + assertEquals('key', pendingKey!.key); + }); + + test('PressAndReleaseMultipleKeysWhenUpdateOnKeyPress', async () => { + shortcutInputElement!.updateOnKeyPress = true; + shortcutInputElement!.startObserving(); + + const keyAEvent = { + vkey: VKey.kKeyA, + domCode: 0, + domKey: 0, + modifiers: 0, + keyDisplay: 'a', + }; + const keyBEvent = { + vkey: VKey.kKeyB, + domCode: 0, + domKey: 0, + modifiers: 0, + keyDisplay: 'b', + }; + + // Press 'a', expect pendingKey keyDisplay is 'a'. + shortcutInputProvider.sendKeyPressEvent(keyAEvent, keyAEvent); + await flushTasks(); + let pendingKey: ShortcutInputKeyElement|null = + getPendingKeyElement(shortcutInputElement); + assertEquals('a', pendingKey!.key); + + // Press 'b', expect pendingKey keyDisplay updates to 'b'. + shortcutInputProvider.sendKeyPressEvent(keyBEvent, keyBEvent); + await flushTasks(); + pendingKey = getPendingKeyElement(shortcutInputElement); + assertEquals('b', pendingKey!.key); + + // Release 'a', expect pendingKey keyDisplay is reset to 'key'. + shortcutInputProvider.sendKeyReleaseEvent(keyAEvent, keyAEvent); + await flushTasks(); + pendingKey = getPendingKeyElement(shortcutInputElement); + assertEquals('key', pendingKey!.key); + + // Release 'b', expect pendingKey keyDisplay still 'key'. + shortcutInputProvider.sendKeyReleaseEvent(keyBEvent, keyBEvent); + await flushTasks(); + pendingKey = getPendingKeyElement(shortcutInputElement); + assertEquals('key', pendingKey!.key); + }); + + test('PressAndReleaseModifiersWhenUpdateOnKeyPress', async () => { + shortcutInputElement!.updateOnKeyPress = true; + shortcutInputElement!.startObserving(); + + // Press and hold 'ctrl' and 'shift'. + const keyPressEvent = { + vkey: VKey.kControl, + domCode: 0, + domKey: 0, + modifiers: 6, + keyDisplay: 'Control', + }; + // Expect 'ctrl' and 'shift' are highlighted. + shortcutInputProvider.sendKeyPressEvent(keyPressEvent, keyPressEvent); + await flushTasks(); + let ctrlKey = getCtrlElement(shortcutInputElement); + let shiftKey = getShiftElement(shortcutInputElement); + assertEquals(KeyInputState.MODIFIER_SELECTED, ctrlKey!.keyState); + assertEquals(KeyInputState.MODIFIER_SELECTED, shiftKey!.keyState); + + // Release 'ctrl' + const keyEventReleaseCtrl = { + vkey: VKey.kControl, + domCode: 0, + domKey: 0, + modifiers: 2, + keyDisplay: 'Control', + }; + // Expect 'ctrl' is unhighlighted, but 'shift' is still highlighted. + shortcutInputProvider.sendKeyReleaseEvent( + keyEventReleaseCtrl, keyEventReleaseCtrl); + await flushTasks(); + ctrlKey = getCtrlElement(shortcutInputElement); + shiftKey = getShiftElement(shortcutInputElement); + assertEquals(KeyInputState.NOT_SELECTED, ctrlKey!.keyState); + assertEquals(KeyInputState.MODIFIER_SELECTED, shiftKey!.keyState); + + // Release 'shift' + const keyEventReleaseShift = { + vkey: VKey.kShift, + domCode: 0, + domKey: 0, + modifiers: 0, + keyDisplay: 'Shift', + }; + // Expect both 'ctrl' and 'shift' are unhighlighted. + shortcutInputProvider.sendKeyReleaseEvent( + keyEventReleaseShift, keyEventReleaseShift); + await flushTasks(); + ctrlKey = getCtrlElement(shortcutInputElement); + shiftKey = getShiftElement(shortcutInputElement); + assertEquals(KeyInputState.NOT_SELECTED, ctrlKey!.keyState); + assertEquals(KeyInputState.NOT_SELECTED, shiftKey!.keyState); + }); });
diff --git a/chrome/test/data/webui/chromeos/internet_detail_dialog_test.js b/chrome/test/data/webui/chromeos/internet_detail_dialog_test.js index 6eedc30..1f59db0 100644 --- a/chrome/test/data/webui/chromeos/internet_detail_dialog_test.js +++ b/chrome/test/data/webui/chromeos/internet_detail_dialog_test.js
@@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'chrome://internet-detail-dialog/internet_detail_dialog_container.js'; +import 'chrome://internet-detail-dialog/internet_detail_dialog.js'; -import {InternetDetailDialogBrowserProxyImpl} from 'chrome://internet-detail-dialog/internet_detail_dialog_container.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';
diff --git a/chrome/test/data/webui/downloads/item_test.ts b/chrome/test/data/webui/downloads/item_test.ts index 699c0fe6..4db0ad5 100644 --- a/chrome/test/data/webui/downloads/item_test.ts +++ b/chrome/test/data/webui/downloads/item_test.ts
@@ -448,7 +448,7 @@ flush(); // The mojo handler is called directly, no event for the dialog is fired. const id = await testDownloadsProxy.handler.whenCalled( - 'saveDangerousRequiringGesture'); + 'saveSuspiciousRequiringGesture'); assertEquals('itemId', id); });
diff --git a/chrome/test/data/webui/downloads/test_support.ts b/chrome/test/data/webui/downloads/test_support.ts index f4d8ddf..d63dd16 100644 --- a/chrome/test/data/webui/downloads/test_support.ts +++ b/chrome/test/data/webui/downloads/test_support.ts
@@ -23,13 +23,19 @@ class FakePageHandler implements PageHandlerInterface { private callbackRouterRemote_: PageRemote; - private callTracker_: TestBrowserProxy = - new TestBrowserProxy(['remove', 'saveDangerousRequiringGesture']); + private callTracker_: TestBrowserProxy = new TestBrowserProxy([ + 'remove', + 'saveDangerousRequiringGesture', + 'saveSuspiciousRequiringGesture', + ]); constructor(callbackRouterRemote: PageRemote) { this.callbackRouterRemote_ = callbackRouterRemote; - this.callTracker_ = - new TestBrowserProxy(['remove', 'saveDangerousRequiringGesture']); + this.callTracker_ = new TestBrowserProxy([ + 'remove', + 'saveDangerousRequiringGesture', + 'saveSuspiciousRequiringGesture', + ]); } whenCalled(methodName: string): Promise<void> { @@ -46,6 +52,10 @@ this.callTracker_.methodCalled('saveDangerousRequiringGesture', id); } + saveSuspiciousRequiringGesture(id: string) { + this.callTracker_.methodCalled('saveSuspiciousRequiringGesture', id); + } + getDownloads(_searchTerms: string[]) {} openFileRequiringGesture(_id: string) {} drag(_id: string) {}
diff --git a/chrome/test/data/webui/settings/autofill_fake_data.ts b/chrome/test/data/webui/settings/autofill_fake_data.ts index 6fca97f..d6e8a4b 100644 --- a/chrome/test/data/webui/settings/autofill_fake_data.ts +++ b/chrome/test/data/webui/settings/autofill_fake_data.ts
@@ -9,7 +9,7 @@ // clang-format on -const ServerFieldType = chrome.autofillPrivate.ServerFieldType; +const FieldType = chrome.autofillPrivate.FieldType; export const STUB_USER_ACCOUNT_INFO: chrome.autofillPrivate.AccountInfo = { email: 'stub-user@example.com', @@ -35,25 +35,25 @@ return { guid: makeGuid(), fields: [ - {type: ServerFieldType.NAME_FULL, value: fullName}, - {type: ServerFieldType.COMPANY_NAME, value: 'Google'}, + {type: FieldType.NAME_FULL, value: fullName}, + {type: FieldType.COMPANY_NAME, value: 'Google'}, { - type: ServerFieldType.ADDRESS_HOME_STREET_ADDRESS, + type: FieldType.ADDRESS_HOME_STREET_ADDRESS, value: addressLines, }, - {type: ServerFieldType.ADDRESS_HOME_STATE, value: 'CA'}, - {type: ServerFieldType.ADDRESS_HOME_CITY, value: 'Venice'}, + {type: FieldType.ADDRESS_HOME_STATE, value: 'CA'}, + {type: FieldType.ADDRESS_HOME_CITY, value: 'Venice'}, { - type: ServerFieldType.ADDRESS_HOME_ZIP, + type: FieldType.ADDRESS_HOME_ZIP, value: patternMaker('xxxxx', 10), }, - {type: ServerFieldType.ADDRESS_HOME_COUNTRY, value: 'US'}, + {type: FieldType.ADDRESS_HOME_COUNTRY, value: 'US'}, { - type: ServerFieldType.PHONE_HOME_WHOLE_NUMBER, + type: FieldType.PHONE_HOME_WHOLE_NUMBER, value: patternMaker('(xxx) xxx-xxxx', 10), }, { - type: ServerFieldType.EMAIL_ADDRESS, + type: FieldType.EMAIL_ADDRESS, value: patternMaker('userxxxx@gmail.com', 16), }, ],
diff --git a/chrome/test/data/webui/settings/autofill_section_address_validation_test.ts b/chrome/test/data/webui/settings/autofill_section_address_validation_test.ts index 17f4ef3..4a55272 100644 --- a/chrome/test/data/webui/settings/autofill_section_address_validation_test.ts +++ b/chrome/test/data/webui/settings/autofill_section_address_validation_test.ts
@@ -12,7 +12,7 @@ import {CountryDetailManagerTestImpl, createAddressDialog, expectEvent} from './autofill_section_test_utils.js'; // clang-format on -const ServerFieldType = chrome.autofillPrivate.ServerFieldType; +const FieldType = chrome.autofillPrivate.FieldType; suite('AutofillSectionAddressValidationTests', () => { setup(() => { @@ -21,8 +21,7 @@ test('verifyRequiredFields', async () => { const address = createEmptyAddressEntry(); - address.fields.push( - {type: ServerFieldType.ADDRESS_HOME_COUNTRY, value: 'US'}); + address.fields.push({type: FieldType.ADDRESS_HOME_COUNTRY, value: 'US'}); const components = await CountryDetailManagerImpl.getInstance().getAddressFormat('US'); @@ -153,7 +152,7 @@ // This field is required. const entry = address.fields.find( - entry => entry.type === ServerFieldType.ADDRESS_HOME_STREET_ADDRESS); + entry => entry.type === FieldType.ADDRESS_HOME_STREET_ADDRESS); assertTrue(!!entry); address.fields.splice(address.fields.indexOf(entry), 1); @@ -166,8 +165,7 @@ test('verifyInvalidatingInitiallyInvalid', async () => { const address = createEmptyAddressEntry(); address.guid = makeGuid(); - address.fields.push( - {type: ServerFieldType.ADDRESS_HOME_COUNTRY, value: 'US'}); + address.fields.push({type: FieldType.ADDRESS_HOME_COUNTRY, value: 'US'}); address.metadata = { summaryLabel: '', source: chrome.autofillPrivate.AddressSource.ACCOUNT,
diff --git a/chrome/test/data/webui/settings/autofill_section_test.ts b/chrome/test/data/webui/settings/autofill_section_test.ts index a9f0817..b8799c23 100644 --- a/chrome/test/data/webui/settings/autofill_section_test.ts +++ b/chrome/test/data/webui/settings/autofill_section_test.ts
@@ -17,7 +17,7 @@ import {createAutofillSection, initiateRemoving, initiateEditing, CountryDetailManagerTestImpl, createAddressDialog, createRemoveAddressDialog, expectEvent, openAddressDialog, deleteAddress, getAddressFieldValue} from './autofill_section_test_utils.js'; // clang-format on -const ServerFieldType = chrome.autofillPrivate.ServerFieldType; +const FieldType = chrome.autofillPrivate.FieldType; suite('AutofillSectionUiTest', function() { test('testAutofillExtensionIndicator', function() { @@ -512,12 +512,11 @@ assertTrue(!!emailInput, 'email element should be the second cr-input'); assertEquals(undefined, phoneInput.value); - assertFalse(!!getAddressFieldValue( - address, ServerFieldType.PHONE_HOME_WHOLE_NUMBER)); + assertFalse( + !!getAddressFieldValue(address, FieldType.PHONE_HOME_WHOLE_NUMBER)); assertEquals(undefined, emailInput.value); - assertFalse( - !!getAddressFieldValue(address, ServerFieldType.EMAIL_ADDRESS)); + assertFalse(!!getAddressFieldValue(address, FieldType.EMAIL_ADDRESS)); const phoneNumber = '(555) 555-5555'; const emailAddress = 'no-reply@chromium.org'; @@ -531,13 +530,12 @@ assertEquals(phoneNumber, phoneInput.value); assertEquals( phoneNumber, - getAddressFieldValue( - address, ServerFieldType.PHONE_HOME_WHOLE_NUMBER)); + getAddressFieldValue(address, FieldType.PHONE_HOME_WHOLE_NUMBER)); assertEquals(emailAddress, emailInput.value); assertEquals( emailAddress, - getAddressFieldValue(address, ServerFieldType.EMAIL_ADDRESS)); + getAddressFieldValue(address, FieldType.EMAIL_ADDRESS)); }); }); }); @@ -551,7 +549,7 @@ 'cr-textarea, cr-input')[0]!; assertEquals(undefined, honorificElement.value); assertFalse( - !!getAddressFieldValue(address, ServerFieldType.NAME_HONORIFIC_PREFIX)); + !!getAddressFieldValue(address, FieldType.NAME_HONORIFIC_PREFIX)); const honorific = 'Lord'; honorificElement.value = honorific; @@ -561,7 +559,7 @@ assertEquals(honorific, honorificElement.value); assertEquals( honorific, - getAddressFieldValue(address, ServerFieldType.NAME_HONORIFIC_PREFIX)); + getAddressFieldValue(address, FieldType.NAME_HONORIFIC_PREFIX)); }); // TODO(crbug.com/1473847): Fix the flakiness. @@ -572,15 +570,14 @@ const emailAddress = 'no-reply@chromium.org'; address.fields.push({ - type: ServerFieldType.ADDRESS_HOME_COUNTRY, + type: FieldType.ADDRESS_HOME_COUNTRY, value: 'US', }); // Set to allow save to be active. address.fields.push({ - type: ServerFieldType.PHONE_HOME_WHOLE_NUMBER, + type: FieldType.PHONE_HOME_WHOLE_NUMBER, value: phoneNumber, }); - address.fields.push( - {type: ServerFieldType.EMAIL_ADDRESS, value: emailAddress}); + address.fields.push({type: FieldType.EMAIL_ADDRESS, value: emailAddress}); return createAddressDialog(address).then(function(dialog) { const rows = dialog.$.dialog.querySelectorAll('.address-row'); @@ -604,10 +601,9 @@ return expectEvent(dialog, 'save-address', function() { dialog.$.saveButton.click(); }).then(function() { - assertFalse(!!getAddressFieldValue( - address, ServerFieldType.PHONE_HOME_WHOLE_NUMBER)); assertFalse( - !!getAddressFieldValue(address, ServerFieldType.EMAIL_ADDRESS)); + !!getAddressFieldValue(address, FieldType.PHONE_HOME_WHOLE_NUMBER)); + assertFalse(!!getAddressFieldValue(address, FieldType.EMAIL_ADDRESS)); }); }); }); @@ -677,14 +673,14 @@ // Test will timeout if save-address event is not fired. test('verifyDefaultCountryIsAppliedWhenSaving', function() { const address = createEmptyAddressEntry(); - address.fields.push({type: ServerFieldType.NAME_FULL, value: 'Name'}); + address.fields.push({type: FieldType.NAME_FULL, value: 'Name'}); return createAddressDialog(address).then(function(dialog) { return expectEvent(dialog, 'save-address', function() { // Verify |countryCode| is not set. assertEquals( undefined, getAddressFieldValue( - address, ServerFieldType.ADDRESS_HOME_COUNTRY)); + address, FieldType.ADDRESS_HOME_COUNTRY)); dialog.$.saveButton.click(); }).then(function(_event) { // 'US' is the default country for these tests. @@ -768,21 +764,21 @@ address.fields = [ { - type: ServerFieldType.NAME_HONORIFIC_PREFIX, + type: FieldType.NAME_HONORIFIC_PREFIX, value: 'Honorific', }, - {type: ServerFieldType.NAME_FULL, value: 'Name'}, - {type: ServerFieldType.COMPANY_NAME, value: 'Organization'}, + {type: FieldType.NAME_FULL, value: 'Name'}, + {type: FieldType.COMPANY_NAME, value: 'Organization'}, { - type: ServerFieldType.ADDRESS_HOME_STREET_ADDRESS, + type: FieldType.ADDRESS_HOME_STREET_ADDRESS, value: 'Street address', }, - {type: ServerFieldType.ADDRESS_HOME_STATE, value: 'State'}, - {type: ServerFieldType.ADDRESS_HOME_CITY, value: 'City'}, - {type: ServerFieldType.ADDRESS_HOME_ZIP, value: 'ZIP code'}, - {type: ServerFieldType.ADDRESS_HOME_COUNTRY, value: 'US'}, - {type: ServerFieldType.PHONE_HOME_WHOLE_NUMBER, value: 'Phone'}, - {type: ServerFieldType.EMAIL_ADDRESS, value: 'Email'}, + {type: FieldType.ADDRESS_HOME_STATE, value: 'State'}, + {type: FieldType.ADDRESS_HOME_CITY, value: 'City'}, + {type: FieldType.ADDRESS_HOME_ZIP, value: 'ZIP code'}, + {type: FieldType.ADDRESS_HOME_COUNTRY, value: 'US'}, + {type: FieldType.PHONE_HOME_WHOLE_NUMBER, value: 'Phone'}, + {type: FieldType.EMAIL_ADDRESS, value: 'Email'}, ]; @@ -805,7 +801,7 @@ '.address-column'); assertEquals(1, cols.length); assertEquals( - getAddressFieldValue(address, ServerFieldType.NAME_HONORIFIC_PREFIX), + getAddressFieldValue(address, FieldType.NAME_HONORIFIC_PREFIX), cols[0]!.value); index++; // Name @@ -814,8 +810,7 @@ '.address-column'); assertEquals(1, cols.length); assertEquals( - getAddressFieldValue(address, ServerFieldType.NAME_FULL), - cols[0]!.value); + getAddressFieldValue(address, FieldType.NAME_FULL), cols[0]!.value); index++; // Organization row = rows[index]!; @@ -823,7 +818,7 @@ '.address-column'); assertEquals(1, cols.length); assertEquals( - getAddressFieldValue(address, ServerFieldType.COMPANY_NAME), + getAddressFieldValue(address, FieldType.COMPANY_NAME), cols[0]!.value); index++; // Street address @@ -832,8 +827,7 @@ '.address-column'); assertEquals(1, cols.length); assertEquals( - getAddressFieldValue( - address, ServerFieldType.ADDRESS_HOME_STREET_ADDRESS), + getAddressFieldValue(address, FieldType.ADDRESS_HOME_STREET_ADDRESS), cols[0]!.value); index++; // City, State, ZIP code @@ -842,13 +836,13 @@ '.address-column'); assertEquals(3, cols.length); assertEquals( - getAddressFieldValue(address, ServerFieldType.ADDRESS_HOME_CITY), + getAddressFieldValue(address, FieldType.ADDRESS_HOME_CITY), cols[0]!.value); assertEquals( - getAddressFieldValue(address, ServerFieldType.ADDRESS_HOME_STATE), + getAddressFieldValue(address, FieldType.ADDRESS_HOME_STATE), cols[1]!.value); assertEquals( - getAddressFieldValue(address, ServerFieldType.ADDRESS_HOME_ZIP), + getAddressFieldValue(address, FieldType.ADDRESS_HOME_ZIP), cols[2]!.value); index++; // Phone, Email @@ -857,11 +851,10 @@ '.address-column'); assertEquals(2, cols.length); assertEquals( - getAddressFieldValue( - address, ServerFieldType.PHONE_HOME_WHOLE_NUMBER), + getAddressFieldValue(address, FieldType.PHONE_HOME_WHOLE_NUMBER), cols[0]!.value); assertEquals( - getAddressFieldValue(address, ServerFieldType.EMAIL_ADDRESS), + getAddressFieldValue(address, FieldType.EMAIL_ADDRESS), cols[1]!.value); }); }); @@ -872,19 +865,19 @@ const address = createEmptyAddressEntry(); address.fields = [ - {type: ServerFieldType.NAME_HONORIFIC_PREFIX, value: 'Lord'}, - {type: ServerFieldType.NAME_FULL, value: 'Name'}, - {type: ServerFieldType.COMPANY_NAME, value: 'Organization'}, + {type: FieldType.NAME_HONORIFIC_PREFIX, value: 'Lord'}, + {type: FieldType.NAME_FULL, value: 'Name'}, + {type: FieldType.COMPANY_NAME, value: 'Organization'}, { - type: ServerFieldType.ADDRESS_HOME_STREET_ADDRESS, + type: FieldType.ADDRESS_HOME_STREET_ADDRESS, value: 'Street address', }, - {type: ServerFieldType.ADDRESS_HOME_STATE, value: 'County'}, - {type: ServerFieldType.ADDRESS_HOME_CITY, value: 'Post town'}, - {type: ServerFieldType.ADDRESS_HOME_ZIP, value: 'Postal code'}, - {type: ServerFieldType.ADDRESS_HOME_COUNTRY, value: 'GB'}, - {type: ServerFieldType.PHONE_HOME_WHOLE_NUMBER, value: 'Phone'}, - {type: ServerFieldType.EMAIL_ADDRESS, value: 'Email'}, + {type: FieldType.ADDRESS_HOME_STATE, value: 'County'}, + {type: FieldType.ADDRESS_HOME_CITY, value: 'Post town'}, + {type: FieldType.ADDRESS_HOME_ZIP, value: 'Postal code'}, + {type: FieldType.ADDRESS_HOME_COUNTRY, value: 'GB'}, + {type: FieldType.PHONE_HOME_WHOLE_NUMBER, value: 'Phone'}, + {type: FieldType.EMAIL_ADDRESS, value: 'Email'}, ]; return createAddressDialog(address).then(function(dialog) { @@ -906,7 +899,7 @@ '.address-column'); assertEquals(1, cols.length); assertEquals( - getAddressFieldValue(address, ServerFieldType.NAME_HONORIFIC_PREFIX), + getAddressFieldValue(address, FieldType.NAME_HONORIFIC_PREFIX), cols[0]!.value); index++; // Name @@ -915,8 +908,7 @@ '.address-column'); assertEquals(1, cols.length); assertEquals( - getAddressFieldValue(address, ServerFieldType.NAME_FULL), - cols[0]!.value); + getAddressFieldValue(address, FieldType.NAME_FULL), cols[0]!.value); index++; // Organization row = rows[index]!; @@ -924,7 +916,7 @@ '.address-column'); assertEquals(1, cols.length); assertEquals( - getAddressFieldValue(address, ServerFieldType.COMPANY_NAME), + getAddressFieldValue(address, FieldType.COMPANY_NAME), cols[0]!.value); index++; // Street address @@ -933,8 +925,7 @@ '.address-column'); assertEquals(1, cols.length); assertEquals( - getAddressFieldValue( - address, ServerFieldType.ADDRESS_HOME_STREET_ADDRESS), + getAddressFieldValue(address, FieldType.ADDRESS_HOME_STREET_ADDRESS), cols[0]!.value); index++; // Post Town @@ -943,7 +934,7 @@ '.address-column'); assertEquals(1, cols.length); assertEquals( - getAddressFieldValue(address, ServerFieldType.ADDRESS_HOME_CITY), + getAddressFieldValue(address, FieldType.ADDRESS_HOME_CITY), cols[0]!.value); index++; // Postal code @@ -952,7 +943,7 @@ '.address-column'); assertEquals(1, cols.length); assertEquals( - getAddressFieldValue(address, ServerFieldType.ADDRESS_HOME_ZIP), + getAddressFieldValue(address, FieldType.ADDRESS_HOME_ZIP), cols[0]!.value); index++; // County @@ -961,7 +952,7 @@ '.address-column'); assertEquals(1, cols.length); assertEquals( - getAddressFieldValue(address, ServerFieldType.ADDRESS_HOME_STATE), + getAddressFieldValue(address, FieldType.ADDRESS_HOME_STATE), cols[0]!.value); index++; // Phone, Email @@ -970,11 +961,10 @@ '.address-column'); assertEquals(2, cols.length); assertEquals( - getAddressFieldValue( - address, ServerFieldType.PHONE_HOME_WHOLE_NUMBER), + getAddressFieldValue(address, FieldType.PHONE_HOME_WHOLE_NUMBER), cols[0]!.value); assertEquals( - getAddressFieldValue(address, ServerFieldType.EMAIL_ADDRESS), + getAddressFieldValue(address, FieldType.EMAIL_ADDRESS), cols[1]!.value); }); }); @@ -987,21 +977,21 @@ address.fields = [ { - type: ServerFieldType.NAME_HONORIFIC_PREFIX, + type: FieldType.NAME_HONORIFIC_PREFIX, value: 'Honorific', }, - {type: ServerFieldType.NAME_FULL, value: 'Name'}, - {type: ServerFieldType.COMPANY_NAME, value: 'Organization'}, + {type: FieldType.NAME_FULL, value: 'Name'}, + {type: FieldType.COMPANY_NAME, value: 'Organization'}, { - type: ServerFieldType.ADDRESS_HOME_STREET_ADDRESS, + type: FieldType.ADDRESS_HOME_STREET_ADDRESS, value: 'Street address', }, - {type: ServerFieldType.ADDRESS_HOME_STATE, value: 'State'}, - {type: ServerFieldType.ADDRESS_HOME_CITY, value: 'City'}, - {type: ServerFieldType.ADDRESS_HOME_ZIP, value: 'Postal code'}, - {type: ServerFieldType.ADDRESS_HOME_COUNTRY, value: 'IL'}, - {type: ServerFieldType.PHONE_HOME_WHOLE_NUMBER, value: 'Phone'}, - {type: ServerFieldType.EMAIL_ADDRESS, value: 'Email'}, + {type: FieldType.ADDRESS_HOME_STATE, value: 'State'}, + {type: FieldType.ADDRESS_HOME_CITY, value: 'City'}, + {type: FieldType.ADDRESS_HOME_ZIP, value: 'Postal code'}, + {type: FieldType.ADDRESS_HOME_COUNTRY, value: 'IL'}, + {type: FieldType.PHONE_HOME_WHOLE_NUMBER, value: 'Phone'}, + {type: FieldType.EMAIL_ADDRESS, value: 'Email'}, ]; return createAddressDialog(address).then(function(dialog) { @@ -1022,7 +1012,7 @@ '.address-column'); assertEquals(1, cols.length); assertEquals( - getAddressFieldValue(address, ServerFieldType.NAME_HONORIFIC_PREFIX), + getAddressFieldValue(address, FieldType.NAME_HONORIFIC_PREFIX), cols[0]!.value); index++; // Name @@ -1031,8 +1021,7 @@ '.address-column'); assertEquals(1, cols.length); assertEquals( - getAddressFieldValue(address, ServerFieldType.NAME_FULL)!, - cols[0]!.value); + getAddressFieldValue(address, FieldType.NAME_FULL)!, cols[0]!.value); index++; // Organization row = rows[index]!; @@ -1040,7 +1029,7 @@ '.address-column'); assertEquals(1, cols.length); assertEquals( - getAddressFieldValue(address, ServerFieldType.COMPANY_NAME), + getAddressFieldValue(address, FieldType.COMPANY_NAME), cols[0]!.value); index++; // Street address @@ -1049,8 +1038,7 @@ '.address-column'); assertEquals(1, cols.length); assertEquals( - getAddressFieldValue( - address, ServerFieldType.ADDRESS_HOME_STREET_ADDRESS), + getAddressFieldValue(address, FieldType.ADDRESS_HOME_STREET_ADDRESS), cols[0]!.value); index++; // City, Postal code @@ -1059,10 +1047,10 @@ '.address-column'); assertEquals(2, cols.length); assertEquals( - getAddressFieldValue(address, ServerFieldType.ADDRESS_HOME_CITY), + getAddressFieldValue(address, FieldType.ADDRESS_HOME_CITY), cols[0]!.value); assertEquals( - getAddressFieldValue(address, ServerFieldType.ADDRESS_HOME_ZIP), + getAddressFieldValue(address, FieldType.ADDRESS_HOME_ZIP), cols[1]!.value); index++; // Phone, Email @@ -1071,11 +1059,10 @@ '.address-column'); assertEquals(2, cols.length); assertEquals( - getAddressFieldValue( - address, ServerFieldType.PHONE_HOME_WHOLE_NUMBER), + getAddressFieldValue(address, FieldType.PHONE_HOME_WHOLE_NUMBER), cols[0]!.value); assertEquals( - getAddressFieldValue(address, ServerFieldType.EMAIL_ADDRESS), + getAddressFieldValue(address, FieldType.EMAIL_ADDRESS), cols[1]!.value); }); }); @@ -1086,8 +1073,7 @@ loadTimeData.overrideValues({showHonorific: true}); const address = createEmptyAddressEntry(); const experimental_fields_count = 2; - address.fields.push( - {type: ServerFieldType.ADDRESS_HOME_COUNTRY, value: 'US'}); + address.fields.push({type: FieldType.ADDRESS_HOME_COUNTRY, value: 'US'}); return createAddressDialog(address).then(function(dialog) { const city = 'Los Angeles';
diff --git a/chrome/test/data/webui/settings/autofill_section_test_utils.ts b/chrome/test/data/webui/settings/autofill_section_test_utils.ts index 121cdcf9..df6c0cc 100644 --- a/chrome/test/data/webui/settings/autofill_section_test_utils.ts +++ b/chrome/test/data/webui/settings/autofill_section_test_utils.ts
@@ -226,6 +226,6 @@ export function getAddressFieldValue( address: chrome.autofillPrivate.AddressEntry, - type: chrome.autofillPrivate.ServerFieldType): string|undefined { + type: chrome.autofillPrivate.FieldType): string|undefined { return address.fields.find(entry => entry.type === type)?.value; }
diff --git a/chrome/test/data/webui/settings/chromeos/test_api.ts b/chrome/test/data/webui/settings/chromeos/test_api.ts index 3e437aab..6b81d3a 100644 --- a/chrome/test/data/webui/settings/chromeos/test_api.ts +++ b/chrome/test/data/webui/settings/chromeos/test_api.ts
@@ -7,6 +7,7 @@ import {SettingsRadioGroupElement} from 'chrome://os-settings/lazy_load.js'; import {CrButtonElement, SettingsGoogleDriveSubpageElement, SettingsToggleButtonElement} from 'chrome://os-settings/os_settings.js'; +import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; import {assertTrue} from 'chrome://webui-test/chai_assert.js'; import {PasswordSettingsApi} from './os_people_page/password_settings_api.js'; @@ -454,13 +455,26 @@ } private googleDriveSubpage(): SettingsGoogleDriveSubpageElement { - const googleDriveSubpage = querySelectorShadow(document.body, [ - 'os-settings-ui', - 'os-settings-main', - 'main-page-container', - 'os-settings-files-page', - 'settings-google-drive-subpage', - ]); + const isRevampWayfindingEnabled = + loadTimeData.getBoolean('isRevampWayfindingEnabled'); + + const elementPath = isRevampWayfindingEnabled ? + [ + 'os-settings-ui', + 'os-settings-main', + 'main-page-container', + 'settings-system-preferences-page', + 'settings-google-drive-subpage', + ] : + [ + 'os-settings-ui', + 'os-settings-main', + 'main-page-container', + 'os-settings-files-page', + 'settings-google-drive-subpage', + ]; + + const googleDriveSubpage = querySelectorShadow(document.body, elementPath); assertTrue(googleDriveSubpage instanceof HTMLElement); return googleDriveSubpage as SettingsGoogleDriveSubpageElement; }
diff --git a/chrome/test/data/webui/settings/privacy_page_test.ts b/chrome/test/data/webui/settings/privacy_page_test.ts index 95ddb03..0757ded 100644 --- a/chrome/test/data/webui/settings/privacy_page_test.ts +++ b/chrome/test/data/webui/settings/privacy_page_test.ts
@@ -353,6 +353,7 @@ suite(`TrackingProtectionSubpage`, function() { let page: SettingsPrivacyPageElement; let settingsPrefs: SettingsPrefsElement; + let metricsBrowserProxy: TestMetricsBrowserProxy; suiteSetup(function() { loadTimeData.overrideValues({ @@ -365,6 +366,8 @@ }); setup(function() { + metricsBrowserProxy = new TestMetricsBrowserProxy(); + MetricsBrowserProxyImpl.setInstance(metricsBrowserProxy); document.body.innerHTML = window.trustedTypes!.emptyHTML; page = document.createElement('settings-privacy-page'); page.prefs = settingsPrefs.prefs!; @@ -372,6 +375,10 @@ return flushTasks(); }); + teardown(function() { + Router.getInstance().resetRouteForTesting(); + }); + test('trackingProtectionSubpageAttributes', async function() { // The subpage is only in the DOM if the corresponding route is open. page.shadowRoot! @@ -389,6 +396,22 @@ assertTrue(!!associatedControl); assertEquals('trackingProtectionLinkRow', associatedControl.id); }); + + test('clickTrackingProtectionRow', async function() { + const trackingProtectionLinkRow = + page.shadowRoot!.querySelector<HTMLElement>( + '#trackingProtectionLinkRow'); + assertTrue(!!trackingProtectionLinkRow); + trackingProtectionLinkRow.click(); + // Ensure UMA is logged. + assertEquals( + 'Settings.TrackingProtection.OpenedFromPrivacyPage', + await metricsBrowserProxy.whenCalled('recordAction')); + // Ensure we navigate to the correct page. + await flushTasks(); + assertEquals( + routes.TRACKING_PROTECTION, Router.getInstance().getCurrentRoute()); + }); }); suite(`PrivacySandbox4EnabledButRestricted`, function() {
diff --git a/chrome/test/data/webui/side_panel/BUILD.gn b/chrome/test/data/webui/side_panel/BUILD.gn index c664810f..1997193 100644 --- a/chrome/test/data/webui/side_panel/BUILD.gn +++ b/chrome/test/data/webui/side_panel/BUILD.gn
@@ -15,7 +15,7 @@ "bookmarks/test_bookmarks_api_proxy.ts", "bookmarks/test_power_bookmarks_delegate.ts", "bookmarks/commerce/shopping_list_test.ts", - "bookmarks/commerce/test_shopping_list_api_proxy.ts", + "bookmarks/commerce/test_shopping_service_api_proxy.ts", "commerce/shopping_insights_app_test.ts", "commerce/price_tracking_section_test.ts", "performance_controls/app_test.ts",
diff --git a/chrome/test/data/webui/side_panel/bookmarks/commerce/shopping_list_test.ts b/chrome/test/data/webui/side_panel/bookmarks/commerce/shopping_list_test.ts index 07c5280..8810a38 100644 --- a/chrome/test/data/webui/side_panel/bookmarks/commerce/shopping_list_test.ts +++ b/chrome/test/data/webui/side_panel/bookmarks/commerce/shopping_list_test.ts
@@ -8,7 +8,7 @@ import {ActionSource} from 'chrome://bookmarks-side-panel.top-chrome/bookmarks.mojom-webui.js'; import {BookmarksApiProxyImpl} from 'chrome://bookmarks-side-panel.top-chrome/bookmarks_api_proxy.js'; import {ACTION_BUTTON_TRACK_IMAGE, ACTION_BUTTON_UNTRACK_IMAGE, LOCAL_STORAGE_EXPAND_STATUS_KEY, ShoppingListElement} from 'chrome://bookmarks-side-panel.top-chrome/commerce/shopping_list.js'; -import {ShoppingListApiProxyImpl} from 'chrome://bookmarks-side-panel.top-chrome/shared/commerce/shopping_list_api_proxy.js'; +import {ShoppingServiceApiProxyImpl} from 'chrome://bookmarks-side-panel.top-chrome/shared/commerce/shopping_service_api_proxy.js'; import {BookmarkProductInfo} from 'chrome://bookmarks-side-panel.top-chrome/shared/shopping_list.mojom-webui.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; @@ -18,12 +18,12 @@ import {TestBookmarksApiProxy} from '../test_bookmarks_api_proxy.js'; -import {TestShoppingListApiProxy} from './test_shopping_list_api_proxy.js'; +import {TestShoppingServiceApiProxy} from './test_shopping_service_api_proxy.js'; suite('SidePanelShoppingListTest', () => { let shoppingList: ShoppingListElement; let bookmarksApi: TestBookmarksApiProxy; - let shoppingListApi: TestShoppingListApiProxy; + let shoppingServiceApi: TestShoppingServiceApiProxy; let metrics: MetricsTracker; const products: BookmarkProductInfo[] = [ @@ -125,8 +125,8 @@ bookmarksApi = new TestBookmarksApiProxy(); BookmarksApiProxyImpl.setInstance(bookmarksApi); - shoppingListApi = new TestShoppingListApiProxy(); - ShoppingListApiProxyImpl.setInstance(shoppingListApi); + shoppingServiceApi = new TestShoppingServiceApiProxy(); + ShoppingServiceApiProxyImpl.setInstance(shoppingServiceApi); shoppingList = document.createElement('shopping-list'); shoppingList.productInfos = products.slice(); @@ -262,7 +262,7 @@ const actionButton = getProductElements(shoppingList)[0]!.querySelector( '.action-button')! as HTMLElement; actionButton.click(); - let id = await shoppingListApi.whenCalled('untrackPriceForBookmark'); + let id = await shoppingServiceApi.whenCalled('untrackPriceForBookmark'); assertEquals(id, products[0]!.bookmarkId); checkActionButtonStatus(actionButton, false); assertEquals( @@ -272,7 +272,7 @@ metrics.count('Commerce.PriceTracking.SidePanel.Untrack.BellButton')); actionButton.click(); - id = await shoppingListApi.whenCalled('trackPriceForBookmark'); + id = await shoppingServiceApi.whenCalled('trackPriceForBookmark'); assertEquals(id, products[0]!.bookmarkId); checkActionButtonStatus(actionButton, true); assertEquals( @@ -297,7 +297,7 @@ }, }; - shoppingListApi.getCallbackRouterRemote().priceTrackedForBookmark( + shoppingServiceApi.getCallbackRouterRemote().priceTrackedForBookmark( newProduct); await flushTasks(); const productElements = getProductElements(shoppingList); @@ -311,7 +311,7 @@ checkActionButtonStatus(actionButtons[i]!, true); } - shoppingListApi.getCallbackRouterRemote().priceUntrackedForBookmark( + shoppingServiceApi.getCallbackRouterRemote().priceUntrackedForBookmark( newProduct); await flushTasks(); checkActionButtonStatus(actionButtons[0]!, true); @@ -326,20 +326,20 @@ const actionButtonA = getProductElements(shoppingList)[0]!.querySelector( '.action-button')! as HTMLElement; actionButtonA.click(); - const id = await shoppingListApi.whenCalled('untrackPriceForBookmark'); + const id = await shoppingServiceApi.whenCalled('untrackPriceForBookmark'); assertEquals(id, products[0]!.bookmarkId); checkActionButtonStatus(actionButtonA, false); - shoppingListApi.getCallbackRouterRemote().priceTrackedForBookmark(product); + shoppingServiceApi.getCallbackRouterRemote().priceTrackedForBookmark(product); await flushTasks(); checkActionButtonStatus(actionButtonA, true); - shoppingListApi.getCallbackRouterRemote().priceUntrackedForBookmark( + shoppingServiceApi.getCallbackRouterRemote().priceUntrackedForBookmark( product); await flushTasks(); checkActionButtonStatus(actionButtonA, false); - shoppingListApi.getCallbackRouterRemote().priceTrackedForBookmark(product); + shoppingServiceApi.getCallbackRouterRemote().priceTrackedForBookmark(product); await flushTasks(); checkActionButtonStatus(actionButtonA, true); }); @@ -365,7 +365,7 @@ clusterId: BigInt(12345), }, }; - shoppingListApi.getCallbackRouterRemote().priceTrackedForBookmark( + shoppingServiceApi.getCallbackRouterRemote().priceTrackedForBookmark( updatedProduct); await flushTasks(); @@ -380,7 +380,7 @@ let actionButton = getProductElements(shoppingList)[0]!.querySelector( '.action-button')! as HTMLElement; actionButton.click(); - const id = await shoppingListApi.whenCalled('untrackPriceForBookmark'); + const id = await shoppingServiceApi.whenCalled('untrackPriceForBookmark'); assertEquals(id, products[0]!.bookmarkId); checkActionButtonStatus(actionButton, false); @@ -395,23 +395,23 @@ }); test('ShowErrorToastWhenTrackAndUntrackFailed', async () => { - shoppingListApi.getCallbackRouterRemote().operationFailedForBookmark( + shoppingServiceApi.getCallbackRouterRemote().operationFailedForBookmark( products[0]!, true); await flushTasks(); assertTrue(shoppingList.$.errorToast.open); shoppingList.$.errorToast.querySelector('cr-button')!.click(); - let id = await shoppingListApi.whenCalled('trackPriceForBookmark'); + let id = await shoppingServiceApi.whenCalled('trackPriceForBookmark'); assertEquals(id, products[0]!.bookmarkId); assertFalse(shoppingList.$.errorToast.open); - shoppingListApi.getCallbackRouterRemote().operationFailedForBookmark( + shoppingServiceApi.getCallbackRouterRemote().operationFailedForBookmark( products[1]!, false); await flushTasks(); assertTrue(shoppingList.$.errorToast.open); shoppingList.$.errorToast.querySelector('cr-button')!.click(); - id = await shoppingListApi.whenCalled('untrackPriceForBookmark'); + id = await shoppingServiceApi.whenCalled('untrackPriceForBookmark'); assertEquals(id, products[1]!.bookmarkId); assertFalse(shoppingList.$.errorToast.open); });
diff --git a/chrome/test/data/webui/side_panel/bookmarks/commerce/test_shopping_list_api_proxy.ts b/chrome/test/data/webui/side_panel/bookmarks/commerce/test_shopping_service_api_proxy.ts similarity index 94% rename from chrome/test/data/webui/side_panel/bookmarks/commerce/test_shopping_list_api_proxy.ts rename to chrome/test/data/webui/side_panel/bookmarks/commerce/test_shopping_service_api_proxy.ts index 3d32eb8..ff0af2f 100644 --- a/chrome/test/data/webui/side_panel/bookmarks/commerce/test_shopping_list_api_proxy.ts +++ b/chrome/test/data/webui/side_panel/bookmarks/commerce/test_shopping_service_api_proxy.ts
@@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import {ShoppingListApiProxy} from 'chrome://bookmarks-side-panel.top-chrome/shared/commerce/shopping_list_api_proxy.js'; +import {ShoppingServiceApiProxy} from 'chrome://bookmarks-side-panel.top-chrome/shared/commerce/shopping_service_api_proxy.js'; import {BookmarkProductInfo, PageCallbackRouter, PageRemote, PriceInsightsInfo, PriceInsightsInfo_PriceBucket, ProductInfo} from 'chrome://bookmarks-side-panel.top-chrome/shared/shopping_list.mojom-webui.js'; import {TestBrowserProxy} from 'chrome://webui-test/test_browser_proxy.js'; -export class TestShoppingListApiProxy extends TestBrowserProxy implements - ShoppingListApiProxy { +export class TestShoppingServiceApiProxy extends TestBrowserProxy implements + ShoppingServiceApiProxy { callbackRouter: PageCallbackRouter; callbackRouterRemote: PageRemote; private products_: BookmarkProductInfo[] = [];
diff --git a/chrome/test/data/webui/side_panel/bookmarks/power_bookmarks_list_test.ts b/chrome/test/data/webui/side_panel/bookmarks/power_bookmarks_list_test.ts index f46d0c6..1a42592 100644 --- a/chrome/test/data/webui/side_panel/bookmarks/power_bookmarks_list_test.ts +++ b/chrome/test/data/webui/side_panel/bookmarks/power_bookmarks_list_test.ts
@@ -8,7 +8,7 @@ import {BookmarksApiProxyImpl} from 'chrome://bookmarks-side-panel.top-chrome/bookmarks_api_proxy.js'; import {PowerBookmarkRowElement} from 'chrome://bookmarks-side-panel.top-chrome/power_bookmark_row.js'; import {PowerBookmarksListElement} from 'chrome://bookmarks-side-panel.top-chrome/power_bookmarks_list.js'; -import {ShoppingListApiProxyImpl} from 'chrome://bookmarks-side-panel.top-chrome/shared/commerce/shopping_list_api_proxy.js'; +import {ShoppingServiceApiProxyImpl} from 'chrome://bookmarks-side-panel.top-chrome/shared/commerce/shopping_service_api_proxy.js'; import {PageImageServiceBrowserProxy} from 'chrome://resources/cr_components/page_image_service/browser_proxy.js'; import {PageImageServiceHandlerRemote} from 'chrome://resources/cr_components/page_image_service/page_image_service.mojom-webui.js'; import {CrInputElement} from 'chrome://resources/cr_elements/cr_input/cr_input.js'; @@ -20,13 +20,13 @@ import {flushTasks, waitAfterNextRender} from 'chrome://webui-test/polymer_test_util.js'; import {TestMock} from 'chrome://webui-test/test_mock.js'; -import {TestShoppingListApiProxy} from './commerce/test_shopping_list_api_proxy.js'; +import {TestShoppingServiceApiProxy} from './commerce/test_shopping_service_api_proxy.js'; import {TestBookmarksApiProxy} from './test_bookmarks_api_proxy.js'; suite('SidePanelPowerBookmarksListTest', () => { let powerBookmarksList: PowerBookmarksListElement; let bookmarksApi: TestBookmarksApiProxy; - let shoppingListApi: TestShoppingListApiProxy; + let shoppingServiceApi: TestShoppingServiceApiProxy; let imageServiceHandler: TestMock<PageImageServiceHandlerRemote>& PageImageServiceHandlerRemote; @@ -135,8 +135,8 @@ bookmarksApi.setFolders(structuredClone(folders)); BookmarksApiProxyImpl.setInstance(bookmarksApi); - shoppingListApi = new TestShoppingListApiProxy(); - ShoppingListApiProxyImpl.setInstance(shoppingListApi); + shoppingServiceApi = new TestShoppingServiceApiProxy(); + ShoppingServiceApiProxyImpl.setInstance(shoppingServiceApi); imageServiceHandler = TestMock.fromClass(PageImageServiceHandlerRemote); PageImageServiceBrowserProxy.setInstance( @@ -631,7 +631,7 @@ clusterId: BigInt(12345), }, }; - shoppingListApi.getCallbackRouterRemote().priceTrackedForBookmark( + shoppingServiceApi.getCallbackRouterRemote().priceTrackedForBookmark( newProduct); await flushTasks(); assertFalse(isHidden(labels));
diff --git a/chrome/test/data/webui/side_panel/bookmarks/power_bookmarks_service_test.ts b/chrome/test/data/webui/side_panel/bookmarks/power_bookmarks_service_test.ts index 6fdeb52c..cbae5e0 100644 --- a/chrome/test/data/webui/side_panel/bookmarks/power_bookmarks_service_test.ts +++ b/chrome/test/data/webui/side_panel/bookmarks/power_bookmarks_service_test.ts
@@ -6,7 +6,7 @@ import {BookmarksApiProxyImpl} from 'chrome://bookmarks-side-panel.top-chrome/bookmarks_api_proxy.js'; import {PowerBookmarksService} from 'chrome://bookmarks-side-panel.top-chrome/power_bookmarks_service.js'; -import {ShoppingListApiProxyImpl} from 'chrome://bookmarks-side-panel.top-chrome/shared/commerce/shopping_list_api_proxy.js'; +import {ShoppingServiceApiProxyImpl} from 'chrome://bookmarks-side-panel.top-chrome/shared/commerce/shopping_service_api_proxy.js'; import {PageImageServiceBrowserProxy} from 'chrome://resources/cr_components/page_image_service/browser_proxy.js'; import {PageImageServiceHandlerRemote} from 'chrome://resources/cr_components/page_image_service/page_image_service.mojom-webui.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; @@ -16,7 +16,7 @@ import {TestMock} from 'chrome://webui-test/test_mock.js'; import {TestPluralStringProxy} from 'chrome://webui-test/test_plural_string_proxy.js'; -import {TestShoppingListApiProxy} from './commerce/test_shopping_list_api_proxy.js'; +import {TestShoppingServiceApiProxy} from './commerce/test_shopping_service_api_proxy.js'; import {TestBookmarksApiProxy} from './test_bookmarks_api_proxy.js'; import {TestPowerBookmarksDelegate} from './test_power_bookmarks_delegate.js'; @@ -31,7 +31,7 @@ let delegate: ServiceTestPowerBookmarksDelegate; let service: PowerBookmarksService; let bookmarksApi: TestBookmarksApiProxy; - let shoppingListApi: TestShoppingListApiProxy; + let shoppingServiceApi: TestShoppingServiceApiProxy; let imageServiceHandler: TestMock<PageImageServiceHandlerRemote>& PageImageServiceHandlerRemote; @@ -174,8 +174,8 @@ bookmarksApi.setFolders(structuredClone(folders)); BookmarksApiProxyImpl.setInstance(bookmarksApi); - shoppingListApi = new TestShoppingListApiProxy(); - ShoppingListApiProxyImpl.setInstance(shoppingListApi); + shoppingServiceApi = new TestShoppingServiceApiProxy(); + ShoppingServiceApiProxyImpl.setInstance(shoppingServiceApi); const pluralString = new TestPluralStringProxy(); PluralStringProxyImpl.setInstance(pluralString);
diff --git a/chrome/test/data/webui/side_panel/commerce/price_tracking_section_test.ts b/chrome/test/data/webui/side_panel/commerce/price_tracking_section_test.ts index d39d2b6..4d2c0422 100644 --- a/chrome/test/data/webui/side_panel/commerce/price_tracking_section_test.ts +++ b/chrome/test/data/webui/side_panel/commerce/price_tracking_section_test.ts
@@ -7,7 +7,7 @@ import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; import {stringToMojoString16} from 'chrome://resources/js/mojo_type_util.js'; import {PriceTrackingSection} from 'chrome://shopping-insights-side-panel.top-chrome/price_tracking_section.js'; -import {ShoppingListApiProxyImpl} from 'chrome://shopping-insights-side-panel.top-chrome/shared/commerce/shopping_list_api_proxy.js'; +import {ShoppingServiceApiProxyImpl} from 'chrome://shopping-insights-side-panel.top-chrome/shared/commerce/shopping_service_api_proxy.js'; import {BookmarkProductInfo, PageCallbackRouter, PageRemote, PriceInsightsInfo, PriceInsightsInfo_PriceBucket, ProductInfo} from 'chrome://shopping-insights-side-panel.top-chrome/shared/shopping_list.mojom-webui.js'; import {assertEquals, assertTrue} from 'chrome://webui-test/chai_assert.js'; import {fakeMetricsPrivate, MetricsTracker} from 'chrome://webui-test/metrics_test_support.js'; @@ -18,7 +18,7 @@ let priceTrackingSection: PriceTrackingSection; let callbackRouter: PageCallbackRouter; let callbackRouterRemote: PageRemote; - const shoppingListApi = TestMock.fromClass(ShoppingListApiProxyImpl); + const shoppingServiceApi = TestMock.fromClass(ShoppingServiceApiProxyImpl); let metrics: MetricsTracker; const productInfo: ProductInfo = { @@ -90,16 +90,16 @@ setup(async () => { document.body.innerHTML = window.trustedTypes!.emptyHTML; - shoppingListApi.reset(); + shoppingServiceApi.reset(); callbackRouter = new PageCallbackRouter(); - shoppingListApi.setResultFor('getCallbackRouter', callbackRouter); - shoppingListApi.setResultFor( + shoppingServiceApi.setResultFor('getCallbackRouter', callbackRouter); + shoppingServiceApi.setResultFor( 'getParentBookmarkFolderNameForCurrentUrl', Promise.resolve({name: stringToMojoString16('Parent folder')})); callbackRouterRemote = callbackRouter.$.bindNewPipeAndPassRemote(); - ShoppingListApiProxyImpl.setInstance(shoppingListApi); + ShoppingServiceApiProxyImpl.setInstance(shoppingServiceApi); priceTrackingSection = document.createElement('price-tracking-section'); priceTrackingSection.productInfo = productInfo; @@ -112,12 +112,12 @@ test( `PriceTracking section rendering when tracked is ${tracked}`, async () => { - shoppingListApi.setResultFor( + shoppingServiceApi.setResultFor( 'getPriceTrackingStatusForCurrentUrl', Promise.resolve({tracked: tracked})); document.body.appendChild(priceTrackingSection); - await shoppingListApi.whenCalled( + await shoppingServiceApi.whenCalled( 'getPriceTrackingStatusForCurrentUrl'); await flushTasks(); @@ -125,17 +125,17 @@ }); test(`Toggle price tracking when tracked is ${tracked}`, async () => { - shoppingListApi.setResultFor( + shoppingServiceApi.setResultFor( 'getPriceTrackingStatusForCurrentUrl', Promise.resolve({tracked: tracked})); document.body.appendChild(priceTrackingSection); - await shoppingListApi.whenCalled('getPriceTrackingStatusForCurrentUrl'); + await shoppingServiceApi.whenCalled('getPriceTrackingStatusForCurrentUrl'); await flushTasks(); priceTrackingSection.$.toggle!.click(); - const tracking = await shoppingListApi.whenCalled( + const tracking = await shoppingServiceApi.whenCalled( 'setPriceTrackingStatusForCurrentUrl'); assertEquals(!tracking, tracked); if (tracking) { @@ -154,12 +154,12 @@ }); test(`Ignore unrealted product tracking status change`, async () => { - shoppingListApi.setResultFor( + shoppingServiceApi.setResultFor( 'getPriceTrackingStatusForCurrentUrl', Promise.resolve({tracked: tracked})); document.body.appendChild(priceTrackingSection); - await shoppingListApi.whenCalled('getPriceTrackingStatusForCurrentUrl'); + await shoppingServiceApi.whenCalled('getPriceTrackingStatusForCurrentUrl'); await flushTasks(); // Create a unrelated product. @@ -191,12 +191,12 @@ }); test(`Observe current product tracking status change`, async () => { - shoppingListApi.setResultFor( + shoppingServiceApi.setResultFor( 'getPriceTrackingStatusForCurrentUrl', Promise.resolve({tracked: false})); document.body.appendChild(priceTrackingSection); - await shoppingListApi.whenCalled('getPriceTrackingStatusForCurrentUrl'); + await shoppingServiceApi.whenCalled('getPriceTrackingStatusForCurrentUrl'); await flushTasks(); callbackRouterRemote.priceTrackedForBookmark(bookmarkProductInfo); @@ -209,12 +209,12 @@ }); test(`Trigger bookmark editor`, async () => { - shoppingListApi.setResultFor( + shoppingServiceApi.setResultFor( 'getPriceTrackingStatusForCurrentUrl', Promise.resolve({tracked: true})); document.body.appendChild(priceTrackingSection); - await shoppingListApi.whenCalled('getPriceTrackingStatusForCurrentUrl'); + await shoppingServiceApi.whenCalled('getPriceTrackingStatusForCurrentUrl'); await flushTasks(); checkPriceTrackingSectionRendering(true); @@ -222,7 +222,7 @@ '#toggleAnnotationButton')! as HTMLElement; folder.click(); - await shoppingListApi.whenCalled('showBookmarkEditorForCurrentUrl'); + await shoppingServiceApi.whenCalled('showBookmarkEditorForCurrentUrl'); assertEquals( 1, metrics.count( @@ -231,12 +231,12 @@ }); test(`Render error message`, async () => { - shoppingListApi.setResultFor( + shoppingServiceApi.setResultFor( 'getPriceTrackingStatusForCurrentUrl', Promise.resolve({tracked: false})); document.body.appendChild(priceTrackingSection); - await shoppingListApi.whenCalled('getPriceTrackingStatusForCurrentUrl'); + await shoppingServiceApi.whenCalled('getPriceTrackingStatusForCurrentUrl'); await flushTasks(); callbackRouterRemote.operationFailedForBookmark(bookmarkProductInfo, true); @@ -265,12 +265,12 @@ }); test(`Observe product bookmark move event`, async () => { - shoppingListApi.setResultFor( + shoppingServiceApi.setResultFor( 'getPriceTrackingStatusForCurrentUrl', Promise.resolve({tracked: true})); document.body.appendChild(priceTrackingSection); - await shoppingListApi.whenCalled('getPriceTrackingStatusForCurrentUrl'); + await shoppingServiceApi.whenCalled('getPriceTrackingStatusForCurrentUrl'); await flushTasks(); checkPriceTrackingSectionRendering(true); let expectedAnnotation = @@ -280,7 +280,7 @@ checkAnnotationHasText(expectedAnnotation); checkAnnotationHasText(expectedSaveLocationText); - shoppingListApi.setResultFor( + shoppingServiceApi.setResultFor( 'getParentBookmarkFolderNameForCurrentUrl', Promise.resolve({name: stringToMojoString16('New folder')})); callbackRouterRemote.onProductBookmarkMoved(bookmarkProductInfo);
diff --git a/chrome/test/data/webui/side_panel/commerce/shopping_insights_app_test.ts b/chrome/test/data/webui/side_panel/commerce/shopping_insights_app_test.ts index fcbb96c1..8469d07 100644 --- a/chrome/test/data/webui/side_panel/commerce/shopping_insights_app_test.ts +++ b/chrome/test/data/webui/side_panel/commerce/shopping_insights_app_test.ts
@@ -8,7 +8,7 @@ import {stringToMojoString16} from 'chrome://resources/js/mojo_type_util.js'; import {ShoppingInsightsAppElement} from 'chrome://shopping-insights-side-panel.top-chrome/app.js'; import {PriceTrackingSection} from 'chrome://shopping-insights-side-panel.top-chrome/price_tracking_section.js'; -import {ShoppingListApiProxyImpl} from 'chrome://shopping-insights-side-panel.top-chrome/shared/commerce/shopping_list_api_proxy.js'; +import {ShoppingServiceApiProxyImpl} from 'chrome://shopping-insights-side-panel.top-chrome/shared/commerce/shopping_service_api_proxy.js'; import {PageCallbackRouter, PriceInsightsInfo, PriceInsightsInfo_PriceBucket, ProductInfo} from 'chrome://shopping-insights-side-panel.top-chrome/shared/shopping_list.mojom-webui.js'; import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; import {fakeMetricsPrivate, MetricsTracker} from 'chrome://webui-test/metrics_test_support.js'; @@ -18,7 +18,7 @@ suite('ShoppingInsightsAppTest', () => { let shoppingInsightsApp: ShoppingInsightsAppElement; - const shoppingListApi = TestMock.fromClass(ShoppingListApiProxyImpl); + const shoppingServiceApi = TestMock.fromClass(ShoppingServiceApiProxyImpl); let metrics: MetricsTracker; const productInfo: ProductInfo = { @@ -95,13 +95,13 @@ setup(async () => { document.body.innerHTML = window.trustedTypes!.emptyHTML; - shoppingListApi.reset(); - shoppingListApi.setResultFor( + shoppingServiceApi.reset(); + shoppingServiceApi.setResultFor( 'getProductInfoForCurrentUrl', Promise.resolve({productInfo: productInfo})); - shoppingListApi.setResultFor( + shoppingServiceApi.setResultFor( 'isShoppingListEligible', Promise.resolve({eligible: false})); - ShoppingListApiProxyImpl.setInstance(shoppingListApi); + ShoppingServiceApiProxyImpl.setInstance(shoppingServiceApi); shoppingInsightsApp = document.createElement('shopping-insights-app'); @@ -109,13 +109,13 @@ }); test('HasBothRangeAndHistoryMultipleOptions', async () => { - shoppingListApi.setResultFor( + shoppingServiceApi.setResultFor( 'getPriceInsightsInfoForCurrentUrl', Promise.resolve({priceInsightsInfo: priceInsights1})); document.body.appendChild(shoppingInsightsApp); - await shoppingListApi.whenCalled('getProductInfoForCurrentUrl'); - await shoppingListApi.whenCalled('getPriceInsightsInfoForCurrentUrl'); + await shoppingServiceApi.whenCalled('getProductInfoForCurrentUrl'); + await shoppingServiceApi.whenCalled('getPriceInsightsInfoForCurrentUrl'); await flushTasks(); const panelTitle = @@ -165,7 +165,7 @@ const button = attributesRow.shadowRoot!.querySelector('iron-icon'); assertTrue(!!button); button.click(); - const url = await shoppingListApi.whenCalled('openUrlInNewTab'); + const url = await shoppingServiceApi.whenCalled('openUrlInNewTab'); assertEquals('https://foo.com/jackpot', url.url); assertEquals( 1, @@ -189,7 +189,7 @@ assertEquals( loadTimeData.getString('feedback'), feedbackButton.textContent!.trim()); feedbackButton.click(); - assertEquals(1, shoppingListApi.getCallCount('showFeedback')); + assertEquals(1, shoppingServiceApi.getCallCount('showFeedback')); assertEquals( 1, metrics.count('Commerce.PriceInsights.InlineFeedbackLinkClicked')); @@ -198,13 +198,13 @@ }); test('HasRangeOnlySingleOption', async () => { - shoppingListApi.setResultFor( + shoppingServiceApi.setResultFor( 'getPriceInsightsInfoForCurrentUrl', Promise.resolve({priceInsightsInfo: priceInsights2})); document.body.appendChild(shoppingInsightsApp); - await shoppingListApi.whenCalled('getProductInfoForCurrentUrl'); - await shoppingListApi.whenCalled('getPriceInsightsInfoForCurrentUrl'); + await shoppingServiceApi.whenCalled('getProductInfoForCurrentUrl'); + await shoppingServiceApi.whenCalled('getPriceInsightsInfoForCurrentUrl'); await flushTasks(); const panelTitle = @@ -230,13 +230,13 @@ }); test('HasHistoryOnlySingleOption', async () => { - shoppingListApi.setResultFor( + shoppingServiceApi.setResultFor( 'getPriceInsightsInfoForCurrentUrl', Promise.resolve({priceInsightsInfo: priceInsights3})); document.body.appendChild(shoppingInsightsApp); - await shoppingListApi.whenCalled('getProductInfoForCurrentUrl'); - await shoppingListApi.whenCalled('getPriceInsightsInfoForCurrentUrl'); + await shoppingServiceApi.whenCalled('getProductInfoForCurrentUrl'); + await shoppingServiceApi.whenCalled('getPriceInsightsInfoForCurrentUrl'); await flushTasks(); const panelTitle = @@ -262,7 +262,7 @@ assertEquals( loadTimeData.getString('buyOptions'), buyOption.textContent!.trim()); buyOption.click(); - const url = await shoppingListApi.whenCalled('openUrlInNewTab'); + const url = await shoppingServiceApi.whenCalled('openUrlInNewTab'); assertEquals('https://foo.com/jackpot', url.url); assertEquals( 1, @@ -293,13 +293,13 @@ }); test('EmptyJackpotLink', async () => { - shoppingListApi.setResultFor( + shoppingServiceApi.setResultFor( 'getPriceInsightsInfoForCurrentUrl', Promise.resolve({priceInsightsInfo: priceInsights4})); document.body.appendChild(shoppingInsightsApp); - await shoppingListApi.whenCalled('getProductInfoForCurrentUrl'); - await shoppingListApi.whenCalled('getPriceInsightsInfoForCurrentUrl'); + await shoppingServiceApi.whenCalled('getProductInfoForCurrentUrl'); + await shoppingServiceApi.whenCalled('getPriceInsightsInfoForCurrentUrl'); await flushTasks(); const titleSection = @@ -312,28 +312,28 @@ [true, false].forEach((eligible) => { test('PriceTrackingSectionVisibility', async () => { - shoppingListApi.setResultFor( + shoppingServiceApi.setResultFor( 'isShoppingListEligible', Promise.resolve({eligible: eligible})); - shoppingListApi.setResultFor( + shoppingServiceApi.setResultFor( 'getProductInfoForCurrentUrl', Promise.resolve({productInfo: productInfo})); - shoppingListApi.setResultFor( + shoppingServiceApi.setResultFor( 'getPriceInsightsInfoForCurrentUrl', Promise.resolve({priceInsightsInfo: priceInsights1})); - shoppingListApi.setResultFor( + shoppingServiceApi.setResultFor( 'getPriceTrackingStatusForCurrentUrl', Promise.resolve({tracked: true})); - shoppingListApi.setResultFor( + shoppingServiceApi.setResultFor( 'getParentBookmarkFolderNameForCurrentUrl', Promise.resolve({name: stringToMojoString16('Parent folder')})); const callbackRouter = new PageCallbackRouter(); - shoppingListApi.setResultFor('getCallbackRouter', callbackRouter); + shoppingServiceApi.setResultFor('getCallbackRouter', callbackRouter); document.body.appendChild(shoppingInsightsApp); - await shoppingListApi.whenCalled('getProductInfoForCurrentUrl'); - await shoppingListApi.whenCalled('getPriceInsightsInfoForCurrentUrl'); - await shoppingListApi.whenCalled('isShoppingListEligible'); + await shoppingServiceApi.whenCalled('getProductInfoForCurrentUrl'); + await shoppingServiceApi.whenCalled('getPriceInsightsInfoForCurrentUrl'); + await shoppingServiceApi.whenCalled('isShoppingListEligible'); await flushTasks(); const section = shoppingInsightsApp.shadowRoot!.querySelector(
diff --git a/chrome/test/data/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search_test.ts b/chrome/test/data/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search_test.ts index f4e62ee..8db45b7 100644 --- a/chrome/test/data/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search_test.ts +++ b/chrome/test/data/webui/side_panel/customize_chrome/wallpaper_search/wallpaper_search_test.ts
@@ -1294,4 +1294,30 @@ }); }); }); + + suite('Inspiration', () => { + test( + 'inspiration card is not shown if inspiration is disabled', + async () => { + loadTimeData.overrideValues( + {wallpaperSearchInspirationCardEnabled: false}); + + createWallpaperSearchElementWithDescriptors(); + await flushTasks(); + + assertFalse(!!wallpaperSearchElement.shadowRoot!.querySelector( + '#inspirationCard')); + }); + + test('inspiration card shows if inspiration is enabled', async () => { + loadTimeData.overrideValues( + {wallpaperSearchInspirationCardEnabled: true}); + + createWallpaperSearchElementWithDescriptors(); + await flushTasks(); + + assertTrue(!!wallpaperSearchElement.shadowRoot!.querySelector( + '#inspirationCard')); + }); + }); });
diff --git a/chrome/updater/BUILD.gn b/chrome/updater/BUILD.gn index 9ab923b..ea9c76f8 100644 --- a/chrome/updater/BUILD.gn +++ b/chrome/updater/BUILD.gn
@@ -537,6 +537,7 @@ sources = [ "certificate_tag.cc", "certificate_tag.h", + "certificate_tag_internal.h", "tag.cc", "tag.h", ]
diff --git a/chrome/updater/certificate_tag.cc b/chrome/updater/certificate_tag.cc index bdd4f56..d00129c 100644 --- a/chrome/updater/certificate_tag.cc +++ b/chrome/updater/certificate_tag.cc
@@ -16,251 +16,27 @@ #include "base/check_op.h" #include "base/containers/span.h" #include "base/notreached.h" +#include "chrome/updater/certificate_tag_internal.h" #include "third_party/boringssl/src/include/openssl/bytestring.h" #include "third_party/boringssl/src/include/openssl/crypto.h" namespace updater::tagging { -namespace { -// PEBinary represents a Windows PE binary and provides functions to extract and -// set data outside of the signed area (called a "tag"). This allows a binary to -// contain arbitrary data without invalidating any Authenticode signature. -class PEBinary : public BinaryInterface { - public: - PEBinary(const PEBinary&); - PEBinary(); - ~PEBinary() override; +namespace internal { - // Parse a signed, Windows PE binary. Note that the returned structure - // contains pointers into the given data. - static std::unique_ptr<BinaryInterface> Parse( - base::span<const uint8_t> binary); - - // Returns the embedded tag, if any. - std::optional<std::vector<const uint8_t>> tag() const override; - - // SetTag returns an updated version of the PE binary image that contains the - // given tag, or |nullopt| on error. If the binary already contains a tag then - // it will be replaced. - std::optional<std::vector<uint8_t>> SetTag( - base::span<const uint8_t> tag) override; - - private: - // ParseTag attempts to parse out the tag. It returns false on parse error or - // true on success. If successful, it sets |tag_|. - bool ParseTag(); - - // binary_ contains the whole input binary. - base::span<const uint8_t> binary_; - - // content_info_ contains the |WIN_CERTIFICATE| structure. - base::span<const uint8_t> content_info_; - - // tag_ contains the embedded tag, or |nullopt| if there isn't one. - std::optional<std::vector<const uint8_t>> tag_; - - // attr_cert_offset_ is the offset in the file where the |WIN_CERTIFICATE| - // structure appears. (This is the last structure in the file.) - size_t attr_cert_offset_ = 0; - - // certs_size_offset_ is the offset in the file where the u32le size of the - // |WIN_CERTIFICATE| structure is embedded in an |IMAGE_DATA_DIRECTORY|. - size_t certs_size_offset_ = 0; -}; - -#pragma pack(push) -#pragma pack(1) - -// SectorFormat represents parameters of an MSI file sector. -struct SectorFormat { - // the size of a sector in bytes; 512 for dll v3 and 4096 for v4. - uint64_t size = 0; - - // the number of int32s in a sector. - int ints = 0; -}; - -// MSIDirEntry represents a parsed MSI directory entry for a stream. -struct MSIDirEntry { - MSIDirEntry(const MSIDirEntry&); - MSIDirEntry(); - ~MSIDirEntry(); - char name[64] = {}; - uint16_t num_name_bytes = 0; - uint8_t object_type = 0; - uint8_t color_flag = 0; - uint32_t left = 0; - uint32_t right = 0; - uint32_t child = 0; - uint8_t clsid[16] = {}; - uint32_t state_flags = 0; - uint64_t create_time = 0; - uint64_t modify_time = 0; - uint32_t stream_first_sector = 0; - uint64_t stream_size = 0; -}; - -// MSIHeader represents a parsed MSI header. -struct MSIHeader { - MSIHeader(const MSIHeader&); - MSIHeader(); - ~MSIHeader(); - uint8_t magic[8] = {}; - uint8_t clsid[16] = {}; - uint16_t minor_version = 0; - uint16_t dll_version = 0; - uint16_t byte_order = 0; - uint16_t sector_shift = 0; - uint16_t mini_sector_shift = 0; - uint8_t reserved[6] = {}; - uint32_t num_dir_sectors = 0; - uint32_t num_fat_sectors = 0; - uint32_t first_dir_sector = 0; - uint32_t transaction_signature_number = 0; - uint32_t mini_stream_cutoff_size = 0; - uint32_t first_mini_fat_sector = 0; - uint32_t num_mini_fat_sectors = 0; - uint32_t first_difat_sector = 0; - uint32_t num_difat_sectors = 0; -}; - -struct SignedDataDir { - MSIDirEntry sig_dir_entry; - uint64_t offset = 0; - bool found = false; -}; -#pragma pack(pop) - -// MSIBinary represents a Windows MSI binary and provides functions to extract -// and set a "tag" outside of the signed area. This allows the MSI to contain -// arbitrary data without invalidating any Authenticode signature. -class MSIBinary : public BinaryInterface { - public: - MSIBinary(const MSIBinary&); - MSIBinary(); - ~MSIBinary() override; - - // Parses the MSI header, the directory entry for the SignedData, and the - // SignedData itself. If successful, returns a `BinaryInterface` to the - // `MSIBinary` object. - static std::unique_ptr<BinaryInterface> Parse( - base::span<const uint8_t> file_contents); - - // Returns the embedded tag, if any. - std::optional<std::vector<const uint8_t>> tag() const override; - - // Returns a complete MSI binary image based on bin, but where the superfluous - // certificate contains the given tag data. - std::optional<std::vector<uint8_t>> SetTag( - base::span<const uint8_t> tag) override; - - private: - // Builds an MSI binary based on the current `MSIBinary`, but with the given - // SignedData. - std::vector<uint8_t> BuildBinary(const std::vector<uint8_t>& signed_data); - - // Populates the superfluous-cert `tag_` if found. Returns `true` if the - // parsing did not produce any errors, even if a tag was not found. - bool ParseTag(); - - // Reads the stream starting at the given start sector. - std::vector<uint8_t> ReadStream(const std::string& name, - uint32_t start, - uint64_t stream_size, - bool force_fat, - bool free_data); - - // Parse-time functionality is broken out into Populate*() methods for - // clarity. - - void PopulateFatEntries(); - - // Copy the difat entries and make a list of difat sectors, if any. - // The first 109 difat entries must exist and are read from the MSI header, - // the rest come from optional additional sectors. - void PopulateDifatEntries(); - - // Returns the directory entry for the signedData stream, if it exists in the - // given sector. - SignedDataDir SignedDataDirFromSector(uint64_t dir_sector); - - bool PopulateSignatureDirEntry(); - void PopulateSignedData(); - - // Returns the index of the first free entry at the end of a vector of fat - // entries. It returns one past the end of list if there are no free entries - // at the end. - static uint64_t FirstFreeFatEntry(const std::vector<uint32_t>& entries); - uint64_t FirstFreeFatEntry(); - - // Ensures there are at least n free entries at the end of the FAT list, - // and returns the first free entry. - uint64_t EnsureFreeFatEntries(uint64_t n); - - // The header (512 bytes). - std::vector<uint8_t> header_bytes_; - - // The parsed msi header. - MSIHeader header_; - - // sector parameters. - SectorFormat sector_format_; - - // The file contents with no header. - std::vector<uint8_t> contents_; - - // The offset of the signedData stream directory in `contents_`. - uint64_t sig_dir_offset_ = 0; - - // The parsed contents of the signedData stream directory. - MSIDirEntry sig_dir_entry_; - - // The PKCS#7, SignedData in asn1 DER form. - std::vector<uint8_t> signed_data_bytes_; - - // A copy of the FAT entries in one list. - std::vector<uint32_t> fat_entries_; - - // A copy of the DIFAT entries in one list. - std::vector<uint32_t> difat_entries_; - - // A list of the dedicated DIFAT sectors, if any, for convenience. - std::vector<uint32_t> difat_sectors_; - - // The parsed tag, if any. - std::optional<std::vector<const uint8_t>> tag_; -}; - -// CBS is a structure from BoringSSL used for parsing binary and ASN.1-based -// formats. This implementation detail is not exposed in the interface of this -// code so these utility functions convert to/from base::span. - -static CBS CBSFromSpan(const base::span<const uint8_t>& span) { +CBS CBSFromSpan(base::span<const uint8_t> span) { CBS cbs; CBS_init(&cbs, span.data(), span.size()); return cbs; } -static base::span<const uint8_t> SpanFromCBS(const CBS* cbs) { +base::span<const uint8_t> SpanFromCBS(const CBS* cbs) { return base::span<const uint8_t>(CBS_data(cbs), CBS_len(cbs)); } PEBinary::PEBinary(const PEBinary&) = default; PEBinary::~PEBinary() = default; -// kTagOID contains the DER-serialised form of the extension OID that we stuff -// the tag into: 1.3.6.1.4.1.11129.2.1.9999. -static constexpr uint8_t kTagOID[] = {0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, - 0x79, 0x02, 0x01, 0xce, 0x0f}; - -// Certificate constants. See -// http://msdn.microsoft.com/en-us/library/ms920091.aspx. -// -// Despite MSDN claiming that 0x100 is the only, current revision - in -// practice it's 0x200. -static constexpr uint16_t kAttributeCertificateRevision = 0x200; -static constexpr uint16_t kAttributeCertificateTypePKCS7SignedData = 2; - // static std::unique_ptr<BinaryInterface> PEBinary::Parse( base::span<const uint8_t> binary) { @@ -397,9 +173,7 @@ return tag_; } -// AddName appends an X.500 Name structure to |cbb| containing a single -// commonName with the given value. -static bool AddName(CBB* cbb, const char* common_name) { +bool AddName(CBB* cbb, const char* common_name) { // kCommonName is the DER-enabled OID for common names. static constexpr uint8_t kCommonName[] = {0x55, 0x04, 0x03}; @@ -419,22 +193,12 @@ return true; } -// CopyASN1 copies a single ASN.1 element from |in| to |out|. -static bool CopyASN1(CBB* out, CBS* in) { +bool CopyASN1(CBB* out, CBS* in) { CBS element; return CBS_get_any_asn1_element(in, &element, nullptr, nullptr) == 1 && CBB_add_bytes(out, CBS_data(&element), CBS_len(&element)) == 1; } -struct ParseResult { - bool success = false; - std::optional<base::span<const uint8_t>> tag; -}; - -// Parses the `signed_data` PKCS7 object to find the final certificate in the -// list and see whether it has an extension with `kTagOID`, and if so, returns a -// `base::span` of the tag within this `signed_data`. `success` is set to `true` -// if there were no parse errors, even if a tag could not be found. ParseResult ParseTagImpl(base::span<const uint8_t> signed_data) { CBS content_info = CBSFromSpan(signed_data); CBS pkcs7, certs; @@ -533,12 +297,9 @@ return {true, std::nullopt}; } -// Returns an updated version of the ContentInfo signedData PKCS7 object with -// the given `new_tag` added, or `nullopt` on error. If the input `signed_data` -// already contains a tag, then it will be replaced with `new_tag`. std::optional<std::vector<uint8_t>> SetTagImpl( base::span<const uint8_t> signed_data, - base::span<const uint8_t> new_tag) { + base::span<const uint8_t> tag) { bssl::ScopedCBB cbb; if (!CBB_init(cbb.get(), signed_data.size() + 1024)) { return std::nullopt; @@ -677,7 +438,7 @@ // Not critical. !CBB_add_bytes(&critical_flag, reinterpret_cast<const uint8_t*>(""), 1) || !CBB_add_asn1(&extension, &tag_cbb, CBS_ASN1_OCTETSTRING) || - !CBB_add_bytes(&tag_cbb, new_tag.data(), new_tag.size()) || + !CBB_add_bytes(&tag_cbb, tag.data(), tag.size()) || !CBB_add_asn1(&cert, &sigalg, CBS_ASN1_SEQUENCE) || !CBB_add_asn1(&sigalg, &sigalg_oid, CBS_ASN1_OBJECT) || !CBB_add_bytes(&sigalg_oid, kSHA256RSAEncryption, @@ -741,29 +502,6 @@ return success; } -// Compound file binary format constants. -constexpr int kNumHeaderContentBytes = 76; -constexpr int kNumHeaderTotalBytes = 512; -constexpr int kNumDifatHeaderEntries = 109; -constexpr int kNumDirEntryBytes = 128; -constexpr int kMiniStreamCutoffSize = 4096; - -// An unallocated sector (used in the FAT or DIFAT). -constexpr uint32_t kFatFreeSector = 0xFFFFFFFF; - -// End of a linked chain (in the FAT); or end of DIFAT sector chain. -constexpr uint32_t kFatEndOfChain = 0xFFFFFFFE; - -constexpr uint8_t kMsiHeaderSignature[] = {0xd0, 0xcf, 0x11, 0xe0, - 0xa1, 0xb1, 0x1a, 0xe1}; -constexpr uint8_t kMsiHeaderClsid[16] = {}; - -// UTF-16 for "\05DigitalSignature". -constexpr uint8_t kSignatureName[] = { - 0x05, 0x00, 0x44, 0x00, 0x69, 0x00, 0x67, 0x00, 0x69, 0x00, 0x74, 0x00, - 0x61, 0x00, 0x6c, 0x00, 0x53, 0x00, 0x69, 0x00, 0x67, 0x00, 0x6e, 0x00, - 0x61, 0x00, 0x74, 0x00, 0x75, 0x00, 0x72, 0x00, 0x65, 0x00, 0x00, 0x00}; - std::optional<SectorFormat> NewSectorFormat(uint16_t sector_shift) { const uint64_t sector_size = 1 << sector_shift; if (sector_size != 4096 && sector_size != 512) { @@ -773,11 +511,6 @@ return SectorFormat{sector_size, static_cast<int>(sector_size / 4)}; } -// Returns whether the index corresponds to the last entry in a sector. -// -// The last entry in each difat sector is a pointer to the next difat sector, or -// is an end-of-chain marker. -// This does not apply to the last entry stored in the MSI header. bool IsLastInSector(const SectorFormat& format, int index) { return index > kNumDifatHeaderEntries && (index - kNumDifatHeaderEntries + 1) % format.ints == 0; @@ -796,7 +529,7 @@ uint64_t stream_size, bool force_fat, bool free_data) { - // TODO(crbug.com/1422360): handle the mini FAT format. + // TODO(crbug.com/1422360): handle the mini fat format. CHECK(force_fat || stream_size >= kMiniStreamCutoffSize); uint32_t sector = start; @@ -827,7 +560,7 @@ } } - // Find the next sector, then free the FAT entry of the current sector. + // Find the next sector, then free the fat entry of the current sector. uint32_t old = sector; sector = fat_entries_[sector]; if (free_data) { @@ -913,11 +646,64 @@ false, true); } +void MSIBinary::AssignDifatEntry(uint64_t fat_sector) { + EnsureFreeDifatEntry(); + + // Find first free entry at end of list. + int i = difat_entries_.size() - 1; + + // If there are sectors, `i` could be pointing to a fat end-of-chain marker, + // but in that case it is guaranteed by `EnsureFreeDifatEntry()` that the + // prior element is a free sector, and the following loop works. + + // As long as the prior element is a free sector, decrement `i`. + // If the prior element is at the end of a difat sector, skip over it. + while (difat_entries_[i - 1] == kFatFreeSector || + (IsLastInSector(sector_format_, i - 1) && + difat_entries_[i - 2] == kFatFreeSector)) { + --i; + } + difat_entries_[i] = fat_sector; +} + +void MSIBinary::EnsureFreeDifatEntry() { + // By construction, `difat_entries_` is at least `kNumDifatHeaderEntries` + // long. + int i = difat_entries_.size() - 1; + if (difat_entries_[i] == kFatEndOfChain) { + --i; + } + if (difat_entries_[i] == kFatFreeSector) { + return; + } + const int old_difat_tail = difat_entries_.size() - 1; + + // Allocate another sector of difat entries. + for (i = 0; i < sector_format_.ints; ++i) { + difat_entries_.push_back(kFatFreeSector); + } + difat_entries_[difat_entries_.size() - 1] = kFatEndOfChain; + + // Assign the new difat sector in the fat. + uint64_t sector = EnsureFreeFatEntries(1); + fat_entries_[sector] = kFatDifSector; + + // Assign the "next sector" pointer in the previous sector or header. + if (!header_.num_difat_sectors) { + header_.first_difat_sector = sector; + } else { + difat_entries_[old_difat_tail] = sector; + } + ++header_.num_difat_sectors; + + difat_sectors_.push_back(sector); +} + // static uint64_t MSIBinary::FirstFreeFatEntry(const std::vector<uint32_t>& entries) { uint64_t first_free_index = entries.size(); while (entries[first_free_index - 1] == kFatFreeSector) { - first_free_index--; + --first_free_index; } return first_free_index; } @@ -929,11 +715,31 @@ uint64_t MSIBinary::EnsureFreeFatEntries(uint64_t n) { uint64_t size_fat = fat_entries_.size(); uint64_t first_free_index = FirstFreeFatEntry(); + if (size_fat - first_free_index >= n) { + // Nothing to do, there were already enough free sectors. + return first_free_index; + } - // TODO(crbug.com/1422360): handle adding additional FAT sectors. - CHECK_GE(size_fat - first_free_index, n); + // Append another fat sector. + for (int i = 0; i < sector_format_.ints; ++i) { + fat_entries_.push_back(kFatFreeSector); + } - return first_free_index; + // `first_free_index` is free; assign it to the created fat sector. + // Do not change the order of these calls, since `AssignDifatEntry()` could + // invalidate `first_free_index`. + fat_entries_[first_free_index] = kFatFatSector; + AssignDifatEntry(first_free_index); + + // Update the MSI header. + ++header_.num_fat_sectors; + + // If n is large enough, it is possible adding an additional sector was + // insufficient. This will not happen for our use case, but the call to verify + // or fix it is cheap. + EnsureFreeFatEntries(n); + + return FirstFreeFatEntry(); } MSIBinary::MSIBinary(const MSIBinary&) = default; @@ -998,13 +804,13 @@ return {}; } - // Ensure enough free FAT entries for the signedData. + // Ensure enough free fat entries for the signedData. const uint64_t num_signed_data_sectors = (signed_data.size() - 1) / sector_format_.size + 1; const uint64_t first_signed_data_sector = EnsureFreeFatEntries(num_signed_data_sectors); - // Allocate sectors for the signedData, in a copy of the FAT entries. + // Allocate sectors for the signedData, in a copy of the fat entries. std::vector<uint32_t> new_fat_entries = fat_entries_; for (uint64_t i = 0; i < num_signed_data_sectors - 1; ++i) { new_fat_entries[first_signed_data_sector + i] = @@ -1093,15 +899,15 @@ return tag_; } -} // namespace +} // namespace internal std::unique_ptr<BinaryInterface> CreatePEBinary( base::span<const uint8_t> contents) { - return PEBinary::Parse(contents); + return internal::PEBinary::Parse(contents); } std::unique_ptr<BinaryInterface> CreateMSIBinary( base::span<const uint8_t> contents) { - return MSIBinary::Parse(contents); + return internal::MSIBinary::Parse(contents); } } // namespace updater::tagging
diff --git a/chrome/updater/certificate_tag_internal.h b/chrome/updater/certificate_tag_internal.h new file mode 100644 index 0000000..db27a71d --- /dev/null +++ b/chrome/updater/certificate_tag_internal.h
@@ -0,0 +1,336 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_UPDATER_CERTIFICATE_TAG_INTERNAL_H_ +#define CHROME_UPDATER_CERTIFICATE_TAG_INTERNAL_H_ + +#include <cstdint> +#include <cstring> +#include <memory> +#include <optional> +#include <string> +#include <utility> +#include <vector> + +#include "base/containers/span.h" +#include "base/gtest_prod_util.h" +#include "third_party/boringssl/src/include/openssl/bytestring.h" +#include "third_party/boringssl/src/include/openssl/crypto.h" + +namespace updater::tagging::internal { + +// PEBinary represents a Windows PE binary and provides functions to extract and +// set data outside of the signed area (called a "tag"). This allows a binary to +// contain arbitrary data without invalidating any Authenticode signature. +class PEBinary : public BinaryInterface { + public: + PEBinary(const PEBinary&); + PEBinary(); + ~PEBinary() override; + + // Parse a signed, Windows PE binary. Note that the returned structure + // contains pointers into the given data. + static std::unique_ptr<BinaryInterface> Parse( + base::span<const uint8_t> binary); + + // Returns the embedded tag, if any. + std::optional<std::vector<const uint8_t>> tag() const override; + + // SetTag returns an updated version of the PE binary image that contains the + // given tag, or `nullopt` on error. If the binary already contains a tag then + // it will be replaced. + std::optional<std::vector<uint8_t>> SetTag( + base::span<const uint8_t> tag) override; + + private: + // ParseTag attempts to parse out the tag. It returns false on parse error or + // true on success. If successful, it sets `tag_`. + bool ParseTag(); + + // binary_ contains the whole input binary. + base::span<const uint8_t> binary_; + + // content_info_ contains the `WIN_CERTIFICATE` structure. + base::span<const uint8_t> content_info_; + + // tag_ contains the embedded tag, or `nullopt` if there isn't one. + std::optional<std::vector<const uint8_t>> tag_; + + // attr_cert_offset_ is the offset in the file where the `WIN_CERTIFICATE` + // structure appears. (This is the last structure in the file.) + size_t attr_cert_offset_ = 0; + + // certs_size_offset_ is the offset in the file where the u32le size of the + // `WIN_CERTIFICATE` structure is embedded in an `IMAGE_DATA_DIRECTORY`. + size_t certs_size_offset_ = 0; +}; + +#pragma pack(push) +#pragma pack(1) + +// SectorFormat represents parameters of an MSI file sector. +struct SectorFormat { + // the size of a sector in bytes; 512 for dll v3 and 4096 for v4. + uint64_t size = 0; + + // the number of int32s in a sector. + int ints = 0; +}; + +// MSIDirEntry represents a parsed MSI directory entry for a stream. +struct MSIDirEntry { + MSIDirEntry(const MSIDirEntry&); + MSIDirEntry(); + ~MSIDirEntry(); + char name[64] = {}; + uint16_t num_name_bytes = 0; + uint8_t object_type = 0; + uint8_t color_flag = 0; + uint32_t left = 0; + uint32_t right = 0; + uint32_t child = 0; + uint8_t clsid[16] = {}; + uint32_t state_flags = 0; + uint64_t create_time = 0; + uint64_t modify_time = 0; + uint32_t stream_first_sector = 0; + uint64_t stream_size = 0; +}; + +// MSIHeader represents a parsed MSI header. +struct MSIHeader { + MSIHeader(const MSIHeader&); + MSIHeader(); + ~MSIHeader(); + uint8_t magic[8] = {}; + uint8_t clsid[16] = {}; + uint16_t minor_version = 0; + uint16_t dll_version = 0; + uint16_t byte_order = 0; + uint16_t sector_shift = 0; + uint16_t mini_sector_shift = 0; + uint8_t reserved[6] = {}; + uint32_t num_dir_sectors = 0; + uint32_t num_fat_sectors = 0; + uint32_t first_dir_sector = 0; + uint32_t transaction_signature_number = 0; + uint32_t mini_stream_cutoff_size = 0; + uint32_t first_mini_fat_sector = 0; + uint32_t num_mini_fat_sectors = 0; + uint32_t first_difat_sector = 0; + uint32_t num_difat_sectors = 0; +}; + +struct SignedDataDir { + MSIDirEntry sig_dir_entry; + uint64_t offset = 0; + bool found = false; +}; +#pragma pack(pop) + +// MSIBinary represents a Windows MSI binary and provides functions to extract +// and set a "tag" outside of the signed area. This allows the MSI to contain +// arbitrary data without invalidating any Authenticode signature. +class MSIBinary : public BinaryInterface { + public: + MSIBinary(const MSIBinary&); + MSIBinary(); + ~MSIBinary() override; + + // Parses the MSI header, the directory entry for the SignedData, and the + // SignedData itself. If successful, returns a `BinaryInterface` to the + // `MSIBinary` object. + static std::unique_ptr<BinaryInterface> Parse( + base::span<const uint8_t> file_contents); + + // Returns the embedded tag, if any. + std::optional<std::vector<const uint8_t>> tag() const override; + + // Returns a complete MSI binary image based on bin, but where the superfluous + // certificate contains the given tag data. + std::optional<std::vector<uint8_t>> SetTag( + base::span<const uint8_t> tag) override; + + private: + // Builds an MSI binary based on the current `MSIBinary`, but with the given + // SignedData. + std::vector<uint8_t> BuildBinary(const std::vector<uint8_t>& signed_data); + + // Populates the superfluous-cert `tag_` if found. Returns `true` if the + // parsing did not produce any errors, even if a tag was not found. + bool ParseTag(); + + // Reads the stream starting at the given start sector. + std::vector<uint8_t> ReadStream(const std::string& name, + uint32_t start, + uint64_t stream_size, + bool force_fat, + bool free_data); + + // Parse-time functionality is broken out into Populate*() methods for + // clarity. + + void PopulateFatEntries(); + + // Copy the difat entries and make a list of difat sectors, if any. + // The first 109 difat entries must exist and are read from the MSI header, + // the rest come from optional additional sectors. + void PopulateDifatEntries(); + + // Returns the directory entry for the signedData stream, if it exists in the + // given sector. + SignedDataDir SignedDataDirFromSector(uint64_t dir_sector); + + bool PopulateSignatureDirEntry(); + void PopulateSignedData(); + + // Assigns an entry, the sector# of a fat sector, to the end of the difat + // list. + void AssignDifatEntry(uint64_t fat_sector); + + // Ensures there is at least one free entry at the end of the difat list. + void EnsureFreeDifatEntry(); + + // Returns the index of the first free entry at the end of a vector of fat + // entries. It returns one past the end of list if there are no free entries + // at the end. + static uint64_t FirstFreeFatEntry(const std::vector<uint32_t>& entries); + uint64_t FirstFreeFatEntry(); + + // Ensures there are at least n free entries at the end of the fat list, + // and returns the first free entry. + uint64_t EnsureFreeFatEntries(uint64_t n); + + // The header (512 bytes). + std::vector<uint8_t> header_bytes_; + + // The parsed msi header. + MSIHeader header_; + + // sector parameters. + SectorFormat sector_format_; + + // The file contents with no header. + std::vector<uint8_t> contents_; + + // The offset of the signedData stream directory in `contents_`. + uint64_t sig_dir_offset_ = 0; + + // The parsed contents of the signedData stream directory. + MSIDirEntry sig_dir_entry_; + + // The PKCS#7, SignedData in asn1 DER form. + std::vector<uint8_t> signed_data_bytes_; + + // A copy of the fat entries in one list. + std::vector<uint32_t> fat_entries_; + + // A copy of the difat entries in one list. + std::vector<uint32_t> difat_entries_; + + // A list of the dedicated difat sectors, if any, for convenience. + std::vector<uint32_t> difat_sectors_; + + // The parsed tag, if any. + std::optional<std::vector<const uint8_t>> tag_; + + FRIEND_TEST_ALL_PREFIXES(CertificateTagMsiFirstFreeFatEntryTest, TestCases); + FRIEND_TEST_ALL_PREFIXES(CertificateTagMsiEnsureFreeDifatEntryTest, + TestCases); + FRIEND_TEST_ALL_PREFIXES(CertificateTagMsiEnsureFreeFatEntriesTest, + TestCases); + FRIEND_TEST_ALL_PREFIXES(CertificateTagMsiAssignDifatEntryTest, TestCases); + friend MSIBinary GetMsiBinary(const std::vector<uint32_t>& fat_entries, + const std::vector<uint32_t>& difat_entries); +}; + +// CBS is a structure from BoringSSL used for parsing binary and ASN.1-based +// formats. This implementation detail is not exposed in the interface of this +// code so these utility functions convert to/from base::span. +CBS CBSFromSpan(base::span<const uint8_t> span); +base::span<const uint8_t> SpanFromCBS(const CBS* cbs); + +// kTagOID contains the DER-serialised form of the extension OID that we stuff +// the tag into: 1.3.6.1.4.1.11129.2.1.9999. +inline constexpr uint8_t kTagOID[] = {0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, + 0x79, 0x02, 0x01, 0xce, 0x0f}; + +// Certificate constants. See +// http://msdn.microsoft.com/en-us/library/ms920091.aspx. +// +// Despite MSDN claiming that 0x100 is the only, current revision - in +// practice it's 0x200. +inline constexpr uint16_t kAttributeCertificateRevision = 0x200; +inline constexpr uint16_t kAttributeCertificateTypePKCS7SignedData = 2; + +// AddName appends an X.500 Name structure to |cbb| containing a single +// commonName with the given value. +bool AddName(CBB* cbb, const char* common_name); + +// CopyASN1 copies a single ASN.1 element from |in| to |out|. +bool CopyASN1(CBB* out, CBS* in); + +struct ParseResult { + bool success = false; + std::optional<base::span<const uint8_t>> tag; +}; + +// Parses the `signed_data` PKCS7 object to find the final certificate in the +// list and see whether it has an extension with `kTagOID`, and if so, returns a +// `base::span` of the tag within this `signed_data`. `success` is set to `true` +// if there were no parse errors, even if a tag could not be found. +ParseResult ParseTagImpl(base::span<const uint8_t> signed_data); + +// Returns an updated version of the ContentInfo signedData PKCS7 object with +// the given `tag` added, or `nullopt` on error. If the input `signed_data` +// already contains a tag, then it will be replaced with `tag`. +std::optional<std::vector<uint8_t>> SetTagImpl( + base::span<const uint8_t> signed_data, + base::span<const uint8_t> tag); + +// Compound file binary format constants. +inline constexpr int kNumHeaderContentBytes = 76; +inline constexpr int kNumHeaderTotalBytes = 512; +inline constexpr int kNumDifatHeaderEntries = 109; +inline constexpr int kNumDirEntryBytes = 128; +inline constexpr int kMiniStreamSectorSize = 64; +inline constexpr int kMiniStreamCutoffSize = 4096; + +// An unallocated sector (used in the fat or difat). +inline constexpr uint32_t kFatFreeSector = 0xFFFFFFFF; + +// End of a linked chain (in the fat); or end of difat sector chain. +inline constexpr uint32_t kFatEndOfChain = 0xFFFFFFFE; + +// Used in the fat table to indicate a fat sector entry. +inline constexpr uint32_t kFatFatSector = 0xFFFFFFFD; + +// Used in the fat table to indicate a difat sector entry. +inline constexpr uint32_t kFatDifSector = 0xFFFFFFFC; + +// Reserved value. +inline constexpr uint32_t kFatReserved = 0xFFFFFFFB; + +inline constexpr uint8_t kMsiHeaderSignature[] = {0xd0, 0xcf, 0x11, 0xe0, + 0xa1, 0xb1, 0x1a, 0xe1}; +inline constexpr uint8_t kMsiHeaderClsid[16] = {}; + +// UTF-16 for "\05DigitalSignature". +inline constexpr uint8_t kSignatureName[] = { + 0x05, 0x00, 0x44, 0x00, 0x69, 0x00, 0x67, 0x00, 0x69, 0x00, 0x74, 0x00, + 0x61, 0x00, 0x6c, 0x00, 0x53, 0x00, 0x69, 0x00, 0x67, 0x00, 0x6e, 0x00, + 0x61, 0x00, 0x74, 0x00, 0x75, 0x00, 0x72, 0x00, 0x65, 0x00, 0x00, 0x00}; + +std::optional<SectorFormat> NewSectorFormat(uint16_t sector_shift); + +// Returns whether the index corresponds to the last entry in a sector. +// +// The last entry in each difat sector is a pointer to the next difat sector, or +// is an end-of-chain marker. +// This does not apply to the last entry stored in the MSI header. +bool IsLastInSector(const SectorFormat& format, int index); + +} // namespace updater::tagging::internal + +#endif // CHROME_UPDATER_CERTIFICATE_TAG_INTERNAL_H_
diff --git a/chrome/updater/certificate_tag_unittest.cc b/chrome/updater/certificate_tag_unittest.cc index 0d99814..ce915e3 100644 --- a/chrome/updater/certificate_tag_unittest.cc +++ b/chrome/updater/certificate_tag_unittest.cc
@@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "chrome/updater/certificate_tag.h" + #include <cstdint> #include <cstring> #include <memory> @@ -11,7 +13,7 @@ #include "base/containers/span.h" #include "base/files/file_path.h" #include "base/files/file_util.h" -#include "chrome/updater/certificate_tag.h" +#include "chrome/updater/certificate_tag_internal.h" #include "chrome/updater/util/unit_test_util.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/zlib/google/compression_utils.h" @@ -62,4 +64,384 @@ EXPECT_EQ(updated_exe->size(), updated_again_exe->size()); } +namespace internal { + +struct CertificateTagMsiIsLastInSectorTestCase { + const int index; + + // 12 for 4096-byte sectors, 9 for 512-byte sectors. + const uint16_t sector_shift; + const bool expected_is_last_in_sector; +}; + +class CertificateTagMsiIsLastInSectorTest + : public ::testing::TestWithParam<CertificateTagMsiIsLastInSectorTestCase> { +}; + +INSTANTIATE_TEST_SUITE_P( + CertificateTagMsiIsLastInSectorTestCases, + CertificateTagMsiIsLastInSectorTest, + ::testing::ValuesIn(std::vector<CertificateTagMsiIsLastInSectorTestCase>{ + {0, 12, false}, + {1, 12, false}, + {107, 12, false}, + {108, 12, false}, + {109, 12, false}, + {1131, 12, false}, + {1132, 12, true}, + {1133, 12, false}, + {2156, 12, true}, + {0, 9, false}, + {1, 9, false}, + {107, 9, false}, + {108, 9, false}, + {109, 9, false}, + {236, 9, true}, + {364, 9, true}, + })); + +TEST_P(CertificateTagMsiIsLastInSectorTest, TestCases) { + EXPECT_EQ(IsLastInSector(*NewSectorFormat(GetParam().sector_shift), + GetParam().index), + GetParam().expected_is_last_in_sector); +} + +struct CertificateTagMsiFirstFreeFatEntryTestCase { + const int index; + const uint32_t expected_first_free_fat_entry; +}; + +class CertificateTagMsiFirstFreeFatEntryTest + : public ::testing::TestWithParam< + CertificateTagMsiFirstFreeFatEntryTestCase> {}; + +INSTANTIATE_TEST_SUITE_P( + CertificateTagMsiFirstFreeFatEntryTestCases, + CertificateTagMsiFirstFreeFatEntryTest, + ::testing::ValuesIn(std::vector<CertificateTagMsiFirstFreeFatEntryTestCase>{ + {1023, 1024}, + {1000, 1001}, + {10, 11}, + {0, 1}, + })); + +TEST_P(CertificateTagMsiFirstFreeFatEntryTest, TestCases) { + std::vector<uint32_t> entries(1024, kFatFreeSector); + entries[GetParam().index] = 1; + EXPECT_EQ(MSIBinary::FirstFreeFatEntry(entries), + GetParam().expected_first_free_fat_entry); +} + +std::vector<uint32_t> GetFatEntries(int sectors, int free_entries) { + // 1024 int32 entries per sector. + const int used_entries = 1024 * sectors - free_entries; + + // Initialize `entries` to zeroes. Zero is a valid sector. In a valid file + // though, the sector number would not repeat zeroes like this, but this works + // for the unit tests. + std::vector<uint32_t> entries(used_entries); + entries.reserve(used_entries + free_entries); + + // Set a non-contiguous free sector before the end, which should not affect + // anything. + if (used_entries > 2) { + entries[used_entries - 2] = kFatFreeSector; + } + for (int i = 0; i < free_entries; ++i) { + entries.push_back(kFatFreeSector); + } + return entries; +} + +std::vector<uint32_t> GetDifatEntries(int sectors, int free_entries) { + // Similar to GetFatEntries, but there are always 109 non-sector elements from + // the header. The last element of any sectors should be `kFatEndOfChain` or a + // sector number. + // https://learn.microsoft.com/en-us/openspecs/windows_protocols/ + // ms-cfb/0afa4e43-b18f-432a-9917-4f276eca7a73 + std::vector<uint32_t> entries(kNumDifatHeaderEntries); + entries.reserve(kNumDifatHeaderEntries + sectors * 1024); + + // Some sector number. + const uint32_t sentinel = 123; + for (; sectors > 0; --sectors) { + std::vector<uint32_t> new_entries(1024); + new_entries[1023] = sectors == 1 ? kFatEndOfChain : sentinel; + entries.insert(entries.end(), new_entries.begin(), new_entries.end()); + } + size_t i = entries.size() - 1; + while (free_entries > 0) { + if (entries[i] != kFatEndOfChain && entries[i] != sentinel) { + entries[i] = kFatFreeSector; + --free_entries; + } + --i; + } + return entries; +} + +MSIBinary GetMsiBinary(const std::vector<uint32_t>& fat_entries, + const std::vector<uint32_t>& difat_entries) { + // Uses dll version 4, 4096-byte sectors. + // There are difat sectors only if difat_entries.size() > 109. + const size_t n = + difat_entries.size() > kNumDifatHeaderEntries + ? (difat_entries.size() - kNumDifatHeaderEntries - 1) / 1024 + 1 + : 0; + + MSIHeader header; + header.dll_version = 4; + header.sector_shift = 12; + header.num_difat_sectors = n; + + MSIBinary bin; + bin.header_ = header; + bin.sector_format_ = *NewSectorFormat(12); + bin.fat_entries_ = fat_entries; + bin.difat_entries_ = difat_entries; + bin.difat_sectors_.resize(n); + return bin; +} + +std::vector<uint32_t> VerifyAndRemoveDifatChaining( + std::vector<uint32_t> entries) { + const SectorFormat format = *NewSectorFormat(12); + for (int i = entries.size() - 1; i >= 0; --i) { + if (IsLastInSector(format, i)) { + if (static_cast<size_t>(i) == entries.size() - 1) { + EXPECT_EQ(entries[i], kFatEndOfChain); + } else { + EXPECT_LT(entries[i], kFatReserved); + } + entries.erase(entries.begin() + i); + } + } + return entries; +} + +void VerifyEntries(size_t added, + const std::vector<uint32_t>& changed_entries, + std::vector<uint32_t> old_entries, + std::vector<uint32_t> new_entries, + bool is_difat) { + ASSERT_EQ(new_entries.size() - old_entries.size(), added); + + // If this is difat, check and remove the chaining entries. This simplifies + // the checks below. + if (is_difat) { + // If there is an error in `old_entries`, the test case was not set up + // correctly. + old_entries = VerifyAndRemoveDifatChaining(old_entries); + new_entries = VerifyAndRemoveDifatChaining(new_entries); + } + + // Can be past end of slice. + size_t first_free = old_entries.size(); + while (first_free > 0 && old_entries[first_free - 1] == kFatFreeSector) { + --first_free; + } + const std::vector<uint32_t> same_entries = std::vector<uint32_t>( + new_entries.begin(), new_entries.begin() + first_free); + const std::vector<uint32_t> diff_entries = std::vector<uint32_t>( + new_entries.begin() + first_free, + new_entries.begin() + first_free + changed_entries.size()); + const std::vector<uint32_t> free_entries = std::vector<uint32_t>( + new_entries.begin() + first_free + changed_entries.size(), + new_entries.end()); + for (size_t i = 0; i < same_entries.size(); ++i) { + EXPECT_EQ(old_entries[i], same_entries[i]); + } + for (size_t i = 0; i < diff_entries.size(); ++i) { + EXPECT_EQ(changed_entries[i], diff_entries[i]); + } + for (size_t i = 0; i < free_entries.size(); ++i) { + EXPECT_EQ(free_entries[i], kFatFreeSector); + } +} + +struct CertificateTagMsiEnsureFreeDifatEntryTestCase { + const int difat_sectors; + const int num_free_difat_entries; + const std::vector<uint32_t> expected_changed_difat_entries; + const size_t expected_num_difat_entries_added; + const int num_fat_sectors; + const int num_free_fat_entries; + const std::vector<uint32_t> expected_changed_fat_entries; + const size_t expected_num_fat_entries_added; +}; + +class CertificateTagMsiEnsureFreeDifatEntryTest + : public ::testing::TestWithParam< + CertificateTagMsiEnsureFreeDifatEntryTestCase> {}; + +INSTANTIATE_TEST_SUITE_P( + CertificateTagMsiEnsureFreeDifatEntryTestCases, + CertificateTagMsiEnsureFreeDifatEntryTest, + ::testing::ValuesIn( + std::vector<CertificateTagMsiEnsureFreeDifatEntryTestCase>{ + // Note: The number of difat used entries should imply the # of fat + // sectors. + // But that inconsistency doesn't affect these tests. + + // Free difat entry in header, no change. + {0, 108, {}, 0, 1, 40, {}, 0}, + + // No free difat entry, add a difat sector (1024 entries). + {0, 0, {}, 1024, 1, 40, {kFatDifSector}, 0}, + + // Free difat entry in sector, no change. + {1, 1, {}, 0, 1, 40, {}, 0}, + + // No free difat entry, add a difat sector. + {1, 0, {}, 1024, 1, 40, {kFatDifSector}, 0}, + + // Additional sector is completely empty, no change. + {1, 1023, {}, 0, 1, 40, {}, 0}, + + // Free difat entry; No free fat entry. No change to either. + {0, 10, {}, 0, 1, 0, {}, 0}, + + // No free difat entry; add a difat sector. No free fat entry; add a + // fat sector. + {0, 0, {1024}, 1024, 1, 0, {kFatFatSector, kFatDifSector}, 1024}, + {1, 0, {1024}, 1024, 1, 0, {kFatFatSector, kFatDifSector}, 1024}, + })); + +TEST_P(CertificateTagMsiEnsureFreeDifatEntryTest, TestCases) { + const std::vector<uint32_t> fat_entries = GetFatEntries( + GetParam().num_fat_sectors, GetParam().num_free_fat_entries); + const std::vector<uint32_t> difat_entries = GetDifatEntries( + GetParam().difat_sectors, GetParam().num_free_difat_entries); + MSIBinary bin = GetMsiBinary(fat_entries, difat_entries); + bin.EnsureFreeDifatEntry(); + + // Check added entries. + VerifyEntries(GetParam().expected_num_difat_entries_added, + GetParam().expected_changed_difat_entries, difat_entries, + bin.difat_entries_, true); + VerifyEntries(GetParam().expected_num_fat_entries_added, + GetParam().expected_changed_fat_entries, fat_entries, + bin.fat_entries_, false); +} + +struct CertificateTagMsiEnsureFreeFatEntriesTestCase { + const int difat_sectors; + const int num_free_difat_entries; + const std::vector<uint32_t> expected_changed_difat_entries; + const size_t expected_num_difat_entries_added; + const int num_fat_sectors; + const int num_free_fat_entries; + const uint32_t num_fat_entries_requested; + const std::vector<uint32_t> expected_changed_fat_entries; + const size_t expected_num_fat_entries_added; +}; + +class CertificateTagMsiEnsureFreeFatEntriesTest + : public ::testing::TestWithParam< + CertificateTagMsiEnsureFreeFatEntriesTestCase> {}; + +INSTANTIATE_TEST_SUITE_P( + CertificateTagMsiEnsureFreeFatEntriesTestCases, + CertificateTagMsiEnsureFreeFatEntriesTest, + ::testing::ValuesIn(std::vector< + CertificateTagMsiEnsureFreeFatEntriesTestCase>{ + // Note: The number of difat used entries should imply the # of fat + // sectors. + // But that inconsistency doesn't affect these tests. + + {0, 1, {}, 0, 1, 2, 2, {}, 0}, + {0, 0, {}, 0, 1, 2, 2, {}, 0}, + {0, 1, {1022}, 0, 1, 2, 4, {kFatFatSector}, 1024}, + {0, 0, {1022}, 1024, 1, 2, 4, {kFatFatSector, kFatDifSector}, 1024}, + {0, 1, {1024}, 0, 1, 0, 4, {kFatFatSector}, 1024}, + {0, 0, {1024}, 1024, 1, 0, 4, {kFatFatSector, kFatDifSector}, 1024}, + {1, 1, {1022}, 0, 1, 2, 4, {kFatFatSector}, 1024}, + {1, 0, {1022}, 1024, 1, 2, 4, {kFatFatSector, kFatDifSector}, 1024}, + {2, 1, {2046}, 0, 2, 2, 4, {kFatFatSector}, 1024}, + {2, 0, {2046}, 1024, 2, 2, 4, {kFatFatSector, kFatDifSector}, 1024}, + + // These are unlikely cases, but they should work. + // Request exactly one more sector free. The difat sector will consume + // a fat entry as well. + {0, 1, {1022}, 0, 1, 2, 1025, {kFatFatSector}, 1024}, + + // Request more than one more sector. + {0, + 2, + {1022, 1023}, + 0, + 1, + 2, + 1026, + {kFatFatSector, kFatFatSector}, + 2048}, + + // Request more than one sector because of additional difat sector. + {0, + 0, + {1022, 1024}, + 1024, + 1, + 2, + 1025, + {kFatFatSector, kFatDifSector, kFatFatSector}, + 2048}, + })); + +TEST_P(CertificateTagMsiEnsureFreeFatEntriesTest, TestCases) { + const std::vector<uint32_t> fat_entries = GetFatEntries( + GetParam().num_fat_sectors, GetParam().num_free_fat_entries); + const std::vector<uint32_t> difat_entries = GetDifatEntries( + GetParam().difat_sectors, GetParam().num_free_difat_entries); + MSIBinary bin = GetMsiBinary(fat_entries, difat_entries); + bin.EnsureFreeFatEntries(GetParam().num_fat_entries_requested); + + // Check added entries. + VerifyEntries(GetParam().expected_num_difat_entries_added, + GetParam().expected_changed_difat_entries, difat_entries, + bin.difat_entries_, true); + VerifyEntries(GetParam().expected_num_fat_entries_added, + GetParam().expected_changed_fat_entries, fat_entries, + bin.fat_entries_, false); +} + +struct CertificateTagMsiAssignDifatEntryTestCase { + int difat_sectors; + int num_free_difat_entries; + size_t difat_entries_assigned_index; + uint32_t difat_entry_assigned_value; + int num_fat_sectors; + int num_free_fat_entries; +}; + +class CertificateTagMsiAssignDifatEntryTest + : public ::testing::TestWithParam< + CertificateTagMsiAssignDifatEntryTestCase> {}; + +INSTANTIATE_TEST_SUITE_P( + CertificateTagMsiAssignDifatEntryTestCases, + CertificateTagMsiAssignDifatEntryTest, + ::testing::ValuesIn(std::vector<CertificateTagMsiAssignDifatEntryTestCase>{ + {0, 1, 108, 1000, 1, 23}, + {0, 0, 109, 1000, 1, 23}, + {1, 1, 1131, 1000, 1, 23}, + {1, 0, 1133, 1000, 1, 23}, + })); + +TEST_P(CertificateTagMsiAssignDifatEntryTest, TestCases) { + const std::vector<uint32_t> fat_entries = GetFatEntries( + GetParam().num_fat_sectors, GetParam().num_free_fat_entries); + const std::vector<uint32_t> difat_entries = GetDifatEntries( + GetParam().difat_sectors, GetParam().num_free_difat_entries); + MSIBinary bin = GetMsiBinary(fat_entries, difat_entries); + bin.AssignDifatEntry(GetParam().difat_entry_assigned_value); + + ASSERT_GE(bin.difat_entries_.size(), + GetParam().difat_entries_assigned_index + 1); + ASSERT_EQ(bin.difat_entries_[GetParam().difat_entries_assigned_index], + GetParam().difat_entry_assigned_value); +} + +} // namespace internal + } // namespace updater::tagging
diff --git a/chromeos/ash/components/assistant/OWNERS b/chromeos/ash/components/assistant/OWNERS index c0d9bd2..fbebcec 100644 --- a/chromeos/ash/components/assistant/OWNERS +++ b/chromeos/ash/components/assistant/OWNERS
@@ -1,4 +1,8 @@ -esum@google.com -wutao@chromium.org -xiaohuic@chromium.org -yawano@google.com +# Please use this reviewer queue instead of specifying an individual reviewer +# unless there is a specific reason for it. +assistive-code-review@google.com + +esum@google.com #{LAST_RESORT_SUGGESTION} +wutao@chromium.org #{LAST_RESORT_SUGGESTION} +xiaohuic@chromium.org #{LAST_RESORT_SUGGESTION} +yawano@google.com #{LAST_RESORT_SUGGESTION}
diff --git a/chromeos/ash/components/emoji/BUILD.gn b/chromeos/ash/components/emoji/BUILD.gn new file mode 100644 index 0000000..8e10538 --- /dev/null +++ b/chromeos/ash/components/emoji/BUILD.gn
@@ -0,0 +1,132 @@ +# Copyright 2023 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/config/chromeos/ui_mode.gni") +import("//mojo/public/tools/bindings/mojom.gni") +import("//tools/grit/grit_rule.gni") + +assert(is_chromeos_ash, "Non-Chrome-OS builds must not depend on //ash") + +action_foreach("emoji_data") { + script = "tools/emoji_data.py" + + metadata_json = [ + "//third_party/emoji-metadata/src/emoji_15_0_ordering.json", + "./emoji_test_ordering.json", + ] + keyword_xmls = [ + # later keywords will override earlier keywords for a particular emoji. + "//third_party/cldr/src/common/annotations/en.xml", + "//third_party/cldr/src/common/annotations/en_001.xml", + "//third_party/cldr/src/common/annotationsDerived/en.xml", + "//third_party/cldr/src/common/annotationsDerived/en_001.xml", + ] + merged_json = "$target_gen_dir/{{source_name_part}}_start.json" + + sources = metadata_json + inputs = keyword_xmls + outputs = [ merged_json ] + args = [ + "--firstgroup", + "True", + "--metadata", + "{{source}}", + "--output", + rebase_path(merged_json, root_build_dir), + "--keywords", + ] + rebase_path(keyword_xmls, root_build_dir) +} + +action_foreach("emoji_data_remaining") { + script = "tools/emoji_data.py" + + metadata_json = [ + "//third_party/emoji-metadata/src/emoji_15_0_ordering.json", + "./emoji_test_ordering.json", + ] + keyword_xmls = [ + # later keywords will override earlier keywords for a particular emoji. + "//third_party/cldr/src/common/annotations/en.xml", + "//third_party/cldr/src/common/annotations/en_001.xml", + "//third_party/cldr/src/common/annotationsDerived/en.xml", + "//third_party/cldr/src/common/annotationsDerived/en_001.xml", + ] + merged_json = "$target_gen_dir/{{source_name_part}}_remaining.json" + + sources = metadata_json + inputs = keyword_xmls + outputs = [ merged_json ] + args = [ + "--firstgroup", + "False", + "--metadata", + "{{source}}", + "--output", + rebase_path(merged_json, root_build_dir), + "--keywords", + ] + rebase_path(keyword_xmls, root_build_dir) +} + +action_foreach("emoticon_data") { + script = "tools/emoticon_data.py" + merged_json = "$target_gen_dir/{{source_name_part}}.json" + + sources = [ + "./emoticon_test_ordering.json", + "//third_party/emoji-metadata/src/emoticon_ordering.json", + ] + + outputs = [ merged_json ] + args = [ + "--metadata", + "{{source}}", + "--output", + rebase_path(merged_json, root_build_dir), + ] +} + +action("symbol_data") { + script = "tools/symbol_data.py" + + outputs = [ "$target_gen_dir/symbol_ordering.json" ] + + deps = [ + ":emoji_data", + ":emoji_data_remaining", + ] + + args = [ + "--output", + rebase_path(outputs[0], root_build_dir), + ] + args += + [ "--filter-data-paths" ] + + rebase_path(get_target_outputs(":emoji_data"), root_build_dir) + + rebase_path(get_target_outputs(":emoji_data_remaining"), root_build_dir) +} + +copy("symbol_test_data") { + sources = [ "./symbol_test_ordering.json" ] + outputs = [ "$target_gen_dir/symbol_test_ordering.json" ] +} + +# Resources used by chrome://picker. +grit("resources") { + source = "emoji.grd" + + deps = [ + ":emoji_data", + ":emoji_data_remaining", + ":emoticon_data", + ":symbol_data", + ":symbol_test_data", + ] + + outputs = [ + "grit/emoji.h", + "grit/emoji_map.cc", + "grit/emoji_map.h", + "emoji.pak", + ] +}
diff --git a/chromeos/ash/components/emoji/OWNERS b/chromeos/ash/components/emoji/OWNERS new file mode 100644 index 0000000..8d2efed --- /dev/null +++ b/chromeos/ash/components/emoji/OWNERS
@@ -0,0 +1,6 @@ +jopalmer@chromium.org +greywang@google.com +shend@chromium.org + +per-file *.mojom=set noparent +per-file *.mojom=file://ipc/SECURITY_OWNERS \ No newline at end of file
diff --git a/chromeos/ash/components/emoji/emoji.grd b/chromeos/ash/components/emoji/emoji.grd new file mode 100644 index 0000000..7ad91cc --- /dev/null +++ b/chromeos/ash/components/emoji/emoji.grd
@@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<grit latest_public_release="0" current_release="1" output_all_resource_defines="false"> + <outputs> + <output filename="grit/emoji.h" type="rc_header"> + <emit emit_type='prepend'></emit> + </output> + <output filename="emoji.pak" type="data_package" /> + <output filename="grit/emoji_map.cc" + type="resource_file_map_source" /> + <output filename="grit/emoji_map.h" + type="resource_map_header" /> + </outputs> + <release seq="1"> + <includes> + <include name="IDR_EMOJI_PICKER_EMOJI_15_0_ORDERING_JSON_START" file="${root_gen_dir}/chromeos/ash/components/emoji/emoji_15_0_ordering_start.json" resource_path="emoji_15_0_ordering_start.json" use_base_dir="false" type="chrome_html" /> + <include name="IDR_EMOJI_PICKER_EMOJI_15_0_ORDERING_JSON_REMAINING" compress="gzip" file="${root_gen_dir}/chromeos/ash/components/emoji/emoji_15_0_ordering_remaining.json" resource_path="emoji_15_0_ordering_remaining.json" use_base_dir="false" type="chrome_html" /> + <include name="IDR_EMOJI_PICKER_EMOJI_TEST_ORDERING_JSON_START" compress="gzip" file="${root_gen_dir}/chromeos/ash/components/emoji/emoji_test_ordering_start.json" resource_path="emoji_test_ordering_start.json" use_base_dir="false" type="chrome_html" /> + <include name="IDR_EMOJI_PICKER_EMOJI_TEST_ORDERING_JSON_REMAINING" compress="gzip" file="${root_gen_dir}/chromeos/ash/components/emoji/emoji_test_ordering_remaining.json" resource_path="emoji_test_ordering_remaining.json" use_base_dir="false" type="chrome_html" /> + <include name="IDR_EMOJI_PICKER_EMOTICON_ORDERING_JSON" compress="gzip" file="${root_gen_dir}/chromeos/ash/components/emoji/emoticon_ordering.json" resource_path="emoticon_ordering.json" use_base_dir="false" type="chrome_html" /> + <include name="IDR_EMOJI_PICKER_EMOTICON_TEST_ORDERING_JSON" compress="gzip" file="${root_gen_dir}/chromeos/ash/components/emoji/emoticon_test_ordering.json" resource_path="emoticon_test_ordering.json" use_base_dir="false" type="chrome_html" /> + <include name="IDR_EMOJI_PICKER_SYMBOL_ORDERING_JSON" compress="gzip" file="${root_gen_dir}/chromeos/ash/components/emoji/symbol_ordering.json" resource_path="symbol_ordering.json" use_base_dir="false" type="chrome_html" /> + <include name="IDR_EMOJI_PICKER_SYMBOL_TEST_ORDERING_JSON" compress="gzip" file="${root_gen_dir}/chromeos/ash/components/emoji/symbol_test_ordering.json" resource_path="symbol_test_ordering.json" use_base_dir="false" type="chrome_html" /> + </includes> + </release> +</grit> \ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_test_ordering.json b/chromeos/ash/components/emoji/emoji_test_ordering.json similarity index 100% rename from chrome/browser/resources/chromeos/emoji_picker/emoji_test_ordering.json rename to chromeos/ash/components/emoji/emoji_test_ordering.json
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoticon_test_ordering.json b/chromeos/ash/components/emoji/emoticon_test_ordering.json similarity index 100% rename from chrome/browser/resources/chromeos/emoji_picker/emoticon_test_ordering.json rename to chromeos/ash/components/emoji/emoticon_test_ordering.json
diff --git a/chrome/browser/resources/chromeos/emoji_picker/symbol_test_ordering.json b/chromeos/ash/components/emoji/symbol_test_ordering.json similarity index 100% rename from chrome/browser/resources/chromeos/emoji_picker/symbol_test_ordering.json rename to chromeos/ash/components/emoji/symbol_test_ordering.json
diff --git a/chrome/browser/resources/chromeos/emoji_picker/tools/emoji_data.py b/chromeos/ash/components/emoji/tools/emoji_data.py similarity index 98% rename from chrome/browser/resources/chromeos/emoji_picker/tools/emoji_data.py rename to chromeos/ash/components/emoji/tools/emoji_data.py index af3e4504..bf9d3407 100755 --- a/chrome/browser/resources/chromeos/emoji_picker/tools/emoji_data.py +++ b/chromeos/ash/components/emoji/tools/emoji_data.py
@@ -12,7 +12,7 @@ _SCRIPT_DIR = os.path.realpath(os.path.dirname(__file__)) _CHROME_SOURCE = os.path.realpath( - os.path.join(_SCRIPT_DIR, *[os.path.pardir] * 6)) + os.path.join(_SCRIPT_DIR, *[os.path.pardir] * 5)) sys.path.append(os.path.join(_CHROME_SOURCE, 'build'))
diff --git a/chrome/browser/resources/chromeos/emoji_picker/tools/emoticon_data.py b/chromeos/ash/components/emoji/tools/emoticon_data.py similarity index 97% rename from chrome/browser/resources/chromeos/emoji_picker/tools/emoticon_data.py rename to chromeos/ash/components/emoji/tools/emoticon_data.py index 4b0dc0ba..7125702 100644 --- a/chrome/browser/resources/chromeos/emoji_picker/tools/emoticon_data.py +++ b/chromeos/ash/components/emoji/tools/emoticon_data.py
@@ -9,7 +9,7 @@ _SCRIPT_DIR = os.path.realpath(os.path.dirname(__file__)) _CHROME_SOURCE = os.path.realpath( - os.path.join(_SCRIPT_DIR, *[os.path.pardir] * 6)) + os.path.join(_SCRIPT_DIR, *[os.path.pardir] * 5)) sys.path.append(os.path.join(_CHROME_SOURCE, 'build')) import action_helpers
diff --git a/chrome/browser/resources/chromeos/emoji_picker/tools/symbol_data.py b/chromeos/ash/components/emoji/tools/symbol_data.py similarity index 99% rename from chrome/browser/resources/chromeos/emoji_picker/tools/symbol_data.py rename to chromeos/ash/components/emoji/tools/symbol_data.py index 6280e5a..a0b678b 100755 --- a/chrome/browser/resources/chromeos/emoji_picker/tools/symbol_data.py +++ b/chromeos/ash/components/emoji/tools/symbol_data.py
@@ -15,7 +15,7 @@ # Add extra dependencies to the python path. _SCRIPT_DIR = os.path.realpath(os.path.dirname(__file__)) _CHROME_SOURCE = os.path.realpath( - os.path.join(_SCRIPT_DIR, *[os.path.pardir] * 6)) + os.path.join(_SCRIPT_DIR, *[os.path.pardir] * 5)) sys.path.append(os.path.join(_CHROME_SOURCE, 'build')) import action_helpers
diff --git a/chromeos/ash/components/scalable_iph/OWNERS b/chromeos/ash/components/scalable_iph/OWNERS index f2a4238..797cbff 100644 --- a/chromeos/ash/components/scalable_iph/OWNERS +++ b/chromeos/ash/components/scalable_iph/OWNERS
@@ -1,8 +1,8 @@ -# Unless you have a specific reason to ask review to individual owners listed -# below, please assign your CL to: assistive-code-review@google.com. It will -# automatically assign your CL to reviewers. +# Please use this reviewer queue instead of specifying an individual reviewer +# unless there is a specific reason for it. +assistive-code-review@google.com -angelaxiao@chromium.org -wutao@chromium.org -xiaohuic@chromium.org -yawano@google.com \ No newline at end of file +angelaxiao@chromium.org #{LAST_RESORT_SUGGESTION} +wutao@chromium.org #{LAST_RESORT_SUGGESTION} +xiaohuic@chromium.org #{LAST_RESORT_SUGGESTION} +yawano@google.com #{LAST_RESORT_SUGGESTION}
diff --git a/chromeos/ash/services/bluetooth_config/BUILD.gn b/chromeos/ash/services/bluetooth_config/BUILD.gn index b54002e..8b96f62 100644 --- a/chromeos/ash/services/bluetooth_config/BUILD.gn +++ b/chromeos/ash/services/bluetooth_config/BUILD.gn
@@ -75,6 +75,7 @@ "//device/bluetooth", "//device/bluetooth/public/cpp", "//mojo/public/cpp/bindings", + "//third_party/re2", ] }
diff --git a/chromeos/ash/services/bluetooth_config/DEPS b/chromeos/ash/services/bluetooth_config/DEPS index 4f23f44f..4271399 100644 --- a/chromeos/ash/services/bluetooth_config/DEPS +++ b/chromeos/ash/services/bluetooth_config/DEPS
@@ -4,4 +4,5 @@ "+components/sync_preferences/testing_pref_service_syncable.h", "+components/user_manager", "+device/bluetooth", + "+third_party/re2", ]
diff --git a/chromeos/ash/services/bluetooth_config/device_name_manager.cc b/chromeos/ash/services/bluetooth_config/device_name_manager.cc index 476702f..fcb41b5 100644 --- a/chromeos/ash/services/bluetooth_config/device_name_manager.cc +++ b/chromeos/ash/services/bluetooth_config/device_name_manager.cc
@@ -6,6 +6,12 @@ namespace ash::bluetooth_config { +const char DeviceNameManager::kDeviceIdToNicknameMapPrefName[] = + "bluetooth.floss_device_id_to_nickname_map"; + +const char DeviceNameManager::kDeviceIdToNicknameMapPrefNameLegacy[] = + "bluetooth.device_id_to_nickname_map"; + DeviceNameManager::DeviceNameManager() = default; DeviceNameManager::~DeviceNameManager() = default;
diff --git a/chromeos/ash/services/bluetooth_config/device_name_manager.h b/chromeos/ash/services/bluetooth_config/device_name_manager.h index b7b3332..4b7891d 100644 --- a/chromeos/ash/services/bluetooth_config/device_name_manager.h +++ b/chromeos/ash/services/bluetooth_config/device_name_manager.h
@@ -31,6 +31,12 @@ const std::optional<std::string>& nickname) = 0; }; + // The pref name used for the map of Bluetooth device IDs to nicknames. + static const char kDeviceIdToNicknameMapPrefName[]; + + // The pref name used for the legacy map of Bluetooth device IDs to nicknames. + static const char kDeviceIdToNicknameMapPrefNameLegacy[]; + virtual ~DeviceNameManager(); // Retrieves the nickname of the Bluetooth device with ID |device_id| or
diff --git a/chromeos/ash/services/bluetooth_config/device_name_manager_impl.cc b/chromeos/ash/services/bluetooth_config/device_name_manager_impl.cc index 6008255d..9dac678f 100644 --- a/chromeos/ash/services/bluetooth_config/device_name_manager_impl.cc +++ b/chromeos/ash/services/bluetooth_config/device_name_manager_impl.cc
@@ -4,20 +4,22 @@ #include "chromeos/ash/services/bluetooth_config/device_name_manager_impl.h" +#include "base/containers/span.h" +#include "base/strings/string_split.h" +#include "base/strings/string_util.h" #include "chromeos/ash/services/bluetooth_config/public/mojom/cros_bluetooth_config.mojom.h" #include "components/device_event_log/device_event_log.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" #include "components/prefs/scoped_user_pref_update.h" #include "device/bluetooth/chromeos/bluetooth_utils.h" +#include "device/bluetooth/floss/floss_features.h" +#include "third_party/re2/src/re2/re2.h" namespace ash::bluetooth_config { namespace { -const char kDeviceIdToNicknameMapPrefName[] = - "bluetooth.device_id_to_nickname_map"; - bool IsNicknameValid(const std::string& nickname) { if (nickname.empty()) return false; @@ -30,6 +32,7 @@ // static void DeviceNameManagerImpl::RegisterLocalStatePrefs( PrefRegistrySimple* registry) { + registry->RegisterDictionaryPref(kDeviceIdToNicknameMapPrefNameLegacy); registry->RegisterDictionaryPref(kDeviceIdToNicknameMapPrefName); } @@ -48,7 +51,10 @@ } const std::string* nickname = - local_state_->GetDict(kDeviceIdToNicknameMapPrefName) + local_state_ + ->GetDict(floss::features::IsFlossEnabled() + ? kDeviceIdToNicknameMapPrefName + : kDeviceIdToNicknameMapPrefNameLegacy) .FindString(device_id); if (!nickname) return std::nullopt; @@ -84,7 +90,10 @@ return; } - ScopedDictPrefUpdate update(local_state_, kDeviceIdToNicknameMapPrefName); + ScopedDictPrefUpdate update(local_state_, + floss::features::IsFlossEnabled() + ? kDeviceIdToNicknameMapPrefName + : kDeviceIdToNicknameMapPrefNameLegacy); BLUETOOTH_LOG(USER) << "Setting device nickname for " << device_id << " to " << nickname; @@ -101,7 +110,10 @@ return; } - ScopedDictPrefUpdate update(local_state_, kDeviceIdToNicknameMapPrefName); + ScopedDictPrefUpdate update(local_state_, + floss::features::IsFlossEnabled() + ? kDeviceIdToNicknameMapPrefName + : kDeviceIdToNicknameMapPrefNameLegacy); // Do nothing if no nickname exists for |device_id|. if (!update->Find(device_id)) { @@ -117,6 +129,85 @@ void DeviceNameManagerImpl::SetPrefs(PrefService* local_state) { local_state_ = local_state; + + if (!local_state_) { + return; + } + const bool hasPref = + local_state_->HasPrefPath(kDeviceIdToNicknameMapPrefName); + if (!floss::features::IsFlossEnabled()) { + if (hasPref) { + local_state_->ClearPref(kDeviceIdToNicknameMapPrefName); + } + return; + } + if (!hasPref) { + MigrateExistingNicknames(); + } +} + +void DeviceNameManagerImpl::MigrateExistingNicknames() { + DCHECK(floss::features::IsFlossEnabled()); + DCHECK(local_state_); + + BLUETOOTH_LOG(EVENT) << "Starting migration of Bluetooth nickname prefs"; + + const re2::RE2 kFlossIdRegex("^([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}$"); + + const base::Value::Dict& existing_prefs = + local_state_->GetDict(kDeviceIdToNicknameMapPrefNameLegacy); + + for (const auto [id, nickname] : existing_prefs) { + // Check whether the ID already matches the Floss format. If so, simply copy + // the entry into the migrated prefs. + if (re2::RE2::FullMatch(id, kFlossIdRegex)) { + BLUETOOTH_LOG(EVENT) + << "Device ID format already matches Floss format; overwriting entry"; + ScopedDictPrefUpdate update(local_state_, kDeviceIdToNicknameMapPrefName); + update->Set(id, nickname.Clone()); + continue; + } + + // Avoid overwriting an existing entry with a BlueZ nickname. This allows us + // to guarantee that Floss nicknames are migrated and outdate BlueZ + // nicknames are effectively forgotten. + if (local_state_->GetDict(kDeviceIdToNicknameMapPrefName).contains(id)) { + BLUETOOTH_LOG(EVENT) + << "Device ID format already matches Floss format; skipping entry"; + continue; + } + + // Since BlueZ uses the DBus object path of the device as the ID, which + // includes the parts of the address of the device, we are able to extract + // these parts and use them to generate an ID for the device that follows + // the format expected of a Floss device ID. Using the following ID as an + // example: + // + // /org/bluez/hci0/dev_7C_96_D2_8B_FB_17 ==> 7C:96:D2:8B:FB:17 + // + // We start by splitting the ID using underscores as the delimiter and then + // concatenating the last six parts, which correspond to the parts of the + // Bluetooth address of the device, using colons to delineate. + const std::vector<std::string> parts = + base::SplitString(id, "_", base::WhitespaceHandling::TRIM_WHITESPACE, + base::SplitResult::SPLIT_WANT_NONEMPTY); + + // We expect at least seven different parts; six for the device address, and + // at least one additional part for the non-address prefix. + if (parts.size() < 7) { + BLUETOOTH_LOG(ERROR) << "Failed to migrate Bluetooth nickname, device ID " + << "has an unexpected format: " << id; + continue; + } + + ScopedDictPrefUpdate update(local_state_, kDeviceIdToNicknameMapPrefName); + update->Set( + base::JoinString(base::make_span(parts.end() - 6, parts.end()), ":"), + nickname.Clone()); + + BLUETOOTH_LOG(EVENT) << "Successfully migrated Bluetooth nickname pref"; + } + BLUETOOTH_LOG(EVENT) << "Finished migration of Bluetooth nickname prefs"; } bool DeviceNameManagerImpl::DoesDeviceExist(
diff --git a/chromeos/ash/services/bluetooth_config/device_name_manager_impl.h b/chromeos/ash/services/bluetooth_config/device_name_manager_impl.h index c92af9b..d6c2b97 100644 --- a/chromeos/ash/services/bluetooth_config/device_name_manager_impl.h +++ b/chromeos/ash/services/bluetooth_config/device_name_manager_impl.h
@@ -33,6 +33,10 @@ void SetPrefs(PrefService* local_state) override; private: + // Migrates the IDs used to persist nicknames in |local_state_| from the BlueZ + // format to the Floss format. + void MigrateExistingNicknames(); + // Returns true if a BluetoothDevice* with identifier |device_id| exists in // |bluetooth_adapter_|, else false. bool DoesDeviceExist(const std::string& device_id) const;
diff --git a/chromeos/ash/services/bluetooth_config/device_name_manager_impl_unittest.cc b/chromeos/ash/services/bluetooth_config/device_name_manager_impl_unittest.cc index 86e0a25..d02edad 100644 --- a/chromeos/ash/services/bluetooth_config/device_name_manager_impl_unittest.cc +++ b/chromeos/ash/services/bluetooth_config/device_name_manager_impl_unittest.cc
@@ -7,9 +7,11 @@ #include "base/strings/strcat.h" #include "base/strings/string_number_conversions.h" #include "base/test/metrics/histogram_tester.h" +#include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" #include "components/sync_preferences/testing_pref_service_syncable.h" #include "device/bluetooth/chromeos/bluetooth_utils.h" +#include "device/bluetooth/floss/floss_features.h" #include "device/bluetooth/test/mock_bluetooth_adapter.h" #include "testing/gtest/include/gtest/gtest.h" @@ -22,6 +24,9 @@ const uint32_t kTestBluetoothClass = 1337u; const char kTestBluetoothName[] = "testName"; +const char kTestIdBluez[] = "/org/bluez/hci0/dev_7C_96_D2_8B_FB_17"; +const char kTestIdFloss0[] = "7C:96:D2:8B:FB:17"; +const char kTestIdFloss1[] = "C7:69:2D:B8:BF:71"; const char kTestNickname[] = "nickname"; class FakeObserver : public DeviceNameManager::Observer { @@ -113,6 +118,10 @@ return fake_observer_.last_device_nickname_changed(); } + sync_preferences::TestingPrefServiceSyncable* local_state() { + return &test_pref_service_; + } + base::HistogramTester histogram_tester; private: @@ -133,7 +142,11 @@ FakeObserver fake_observer_; }; -TEST_F(DeviceNameManagerImplTest, GetThenSetValidThenSetInvalid) { +TEST_F(DeviceNameManagerImplTest, GetThenSetValidThenSetInvalidFlossDisabled) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature(floss::features::kFlossEnabled); + EXPECT_FALSE(floss::features::IsFlossEnabled()); + std::string device_id; AddDevice(&device_id); std::unique_ptr<DeviceNameManagerImpl> manager = CreateDeviceNameManager(); @@ -175,7 +188,12 @@ device::SetNicknameResult::kSuccess, 1); } -TEST_F(DeviceNameManagerImplTest, NicknameIsPersistedBetweenManagerInstances) { +TEST_F(DeviceNameManagerImplTest, + NicknameIsPersistedBetweenManagerInstancesFlossDisabled) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature(floss::features::kFlossEnabled); + EXPECT_FALSE(floss::features::IsFlossEnabled()); + std::string device_id; AddDevice(&device_id); std::unique_ptr<DeviceNameManagerImpl> manager = CreateDeviceNameManager(); @@ -197,7 +215,11 @@ EXPECT_EQ(manager->GetDeviceNickname(device_id), kTestNickname); } -TEST_F(DeviceNameManagerImplTest, SetNicknameDeviceNotFound) { +TEST_F(DeviceNameManagerImplTest, SetNicknameDeviceNotFoundFlossDisabled) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature(floss::features::kFlossEnabled); + EXPECT_FALSE(floss::features::IsFlossEnabled()); + const std::string device_id = "device_id"; std::unique_ptr<DeviceNameManagerImpl> manager = CreateDeviceNameManager(); EXPECT_FALSE(manager->GetDeviceNickname(device_id)); @@ -213,7 +235,11 @@ device::SetNicknameResult::kSuccess, 0); } -TEST_F(DeviceNameManagerImplTest, RemoveThenSetThenRemove) { +TEST_F(DeviceNameManagerImplTest, RemoveThenSetThenRemoveFlossDisabled) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature(floss::features::kFlossEnabled); + EXPECT_FALSE(floss::features::IsFlossEnabled()); + std::string device_id; AddDevice(&device_id); std::unique_ptr<DeviceNameManagerImpl> manager = CreateDeviceNameManager(); @@ -241,4 +267,198 @@ EXPECT_FALSE(manager->GetDeviceNickname(device_id)); } +TEST_F(DeviceNameManagerImplTest, GetThenSetValidThenSetInvalidFlossEnabled) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(floss::features::kFlossEnabled); + EXPECT_TRUE(floss::features::IsFlossEnabled()); + + std::string device_id; + AddDevice(&device_id); + std::unique_ptr<DeviceNameManagerImpl> manager = CreateDeviceNameManager(); + EXPECT_FALSE(manager->GetDeviceNickname(device_id)); + + manager->SetDeviceNickname(device_id, kTestNickname); + EXPECT_EQ(manager->GetDeviceNickname(device_id), kTestNickname); + EXPECT_EQ(GetNumDeviceNicknameObserverEvents(), 1u); + EXPECT_EQ(GetLastDeviceIdNicknameChanged(), device_id); + EXPECT_EQ(GetLastDeviceNicknameChanged(), kTestNickname); + + histogram_tester.ExpectBucketCount( + "Bluetooth.ChromeOS.SetNickname.Result", + device::SetNicknameResult::kInvalidNicknameFormat, 0); + histogram_tester.ExpectBucketCount("Bluetooth.ChromeOS.SetNickname.Result", + device::SetNicknameResult::kSuccess, 1); + + // Set an empty nickname, this should fail and the nickname should be + // unchanged. + manager->SetDeviceNickname(device_id, ""); + EXPECT_EQ(manager->GetDeviceNickname(device_id), kTestNickname); + EXPECT_EQ(GetNumDeviceNicknameObserverEvents(), 1u); + histogram_tester.ExpectBucketCount( + "Bluetooth.ChromeOS.SetNickname.Result", + device::SetNicknameResult::kInvalidNicknameFormat, 1); + histogram_tester.ExpectBucketCount("Bluetooth.ChromeOS.SetNickname.Result", + device::SetNicknameResult::kSuccess, 1); + + // Set nickname above character limit, this should also fail and the nickname + // should be unchanged. + manager->SetDeviceNickname(device_id, "123456789012345678901234567890123"); + EXPECT_EQ(manager->GetDeviceNickname(device_id), kTestNickname); + EXPECT_EQ(GetNumDeviceNicknameObserverEvents(), 1u); + + histogram_tester.ExpectBucketCount( + "Bluetooth.ChromeOS.SetNickname.Result", + device::SetNicknameResult::kInvalidNicknameFormat, 2); + histogram_tester.ExpectBucketCount("Bluetooth.ChromeOS.SetNickname.Result", + device::SetNicknameResult::kSuccess, 1); +} + +TEST_F(DeviceNameManagerImplTest, + NicknameIsPersistedBetweenManagerInstancesFlossEnabled) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(floss::features::kFlossEnabled); + EXPECT_TRUE(floss::features::IsFlossEnabled()); + + std::string device_id; + AddDevice(&device_id); + std::unique_ptr<DeviceNameManagerImpl> manager = CreateDeviceNameManager(); + EXPECT_FALSE(manager->GetDeviceNickname(device_id)); + + manager->SetDeviceNickname(device_id, kTestNickname); + EXPECT_EQ(manager->GetDeviceNickname(device_id), kTestNickname); + EXPECT_EQ(GetNumDeviceNicknameObserverEvents(), 1u); + EXPECT_EQ(GetLastDeviceIdNicknameChanged(), device_id); + EXPECT_EQ(GetLastDeviceNicknameChanged(), kTestNickname); + histogram_tester.ExpectBucketCount( + "Bluetooth.ChromeOS.SetNickname.Result", + device::SetNicknameResult::kInvalidNicknameFormat, 0); + histogram_tester.ExpectBucketCount("Bluetooth.ChromeOS.SetNickname.Result", + device::SetNicknameResult::kSuccess, 1); + + // Create a new manager and destroy the old one. + manager = CreateDeviceNameManager(); + EXPECT_EQ(manager->GetDeviceNickname(device_id), kTestNickname); +} + +TEST_F(DeviceNameManagerImplTest, SetNicknameDeviceNotFoundFlossEnabled) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(floss::features::kFlossEnabled); + EXPECT_TRUE(floss::features::IsFlossEnabled()); + + const std::string device_id = "device_id"; + std::unique_ptr<DeviceNameManagerImpl> manager = CreateDeviceNameManager(); + EXPECT_FALSE(manager->GetDeviceNickname(device_id)); + + // Setting the nickname of an unknown device should fail. + manager->SetDeviceNickname(device_id, kTestNickname); + EXPECT_FALSE(manager->GetDeviceNickname(device_id)); + EXPECT_EQ(GetNumDeviceNicknameObserverEvents(), 0u); + histogram_tester.ExpectBucketCount("Bluetooth.ChromeOS.SetNickname.Result", + device::SetNicknameResult::kDeviceNotFound, + 1); + histogram_tester.ExpectBucketCount("Bluetooth.ChromeOS.SetNickname.Result", + device::SetNicknameResult::kSuccess, 0); +} + +TEST_F(DeviceNameManagerImplTest, RemoveThenSetThenRemoveFlossEnabled) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(floss::features::kFlossEnabled); + EXPECT_TRUE(floss::features::IsFlossEnabled()); + + std::string device_id; + AddDevice(&device_id); + std::unique_ptr<DeviceNameManagerImpl> manager = CreateDeviceNameManager(); + EXPECT_FALSE(manager->GetDeviceNickname(device_id)); + + // Nothing should happen when removing a nickname that doesn't exist. + manager->RemoveDeviceNickname(device_id); + EXPECT_EQ(GetNumDeviceNicknameObserverEvents(), 0u); + EXPECT_FALSE(manager->GetDeviceNickname(device_id)); + + manager->SetDeviceNickname(device_id, kTestNickname); + EXPECT_EQ(manager->GetDeviceNickname(device_id), kTestNickname); + EXPECT_EQ(GetNumDeviceNicknameObserverEvents(), 1u); + EXPECT_EQ(GetLastDeviceIdNicknameChanged(), device_id); + EXPECT_EQ(GetLastDeviceNicknameChanged(), kTestNickname); + + manager->RemoveDeviceNickname(device_id); + EXPECT_EQ(GetNumDeviceNicknameObserverEvents(), 2u); + EXPECT_FALSE(manager->GetDeviceNickname(device_id)); + EXPECT_EQ(GetLastDeviceIdNicknameChanged(), device_id); + EXPECT_EQ(GetLastDeviceNicknameChanged(), std::nullopt); + + // Create a new manager and destroy the old one. + manager = CreateDeviceNameManager(); + EXPECT_FALSE(manager->GetDeviceNickname(device_id)); +} + +TEST_F(DeviceNameManagerImplTest, Migration_DisablingClearsPrefs) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature(floss::features::kFlossEnabled); + EXPECT_FALSE(floss::features::IsFlossEnabled()); + + // Set the pref to some arbitrary value since we just want to confirm it will + // be cleared when the feature flag is disabled. + local_state()->Set(DeviceNameManager::kDeviceIdToNicknameMapPrefName, + base::Value(base::Value::Dict())); + EXPECT_TRUE(local_state()->HasPrefPath( + DeviceNameManager::kDeviceIdToNicknameMapPrefName)); + CreateDeviceNameManager(); + EXPECT_FALSE(local_state()->HasPrefPath( + DeviceNameManager::kDeviceIdToNicknameMapPrefName)); +} + +TEST_F(DeviceNameManagerImplTest, Migration_MigrationHappensOnce) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(floss::features::kFlossEnabled); + EXPECT_TRUE(floss::features::IsFlossEnabled()); + + // The value that we will set the existing/pre-migration prefs to. + auto existing_prefs = base::Value::Dict().Set(kTestIdBluez, kTestNickname); + local_state()->Set(DeviceNameManager::kDeviceIdToNicknameMapPrefNameLegacy, + base::Value(existing_prefs.Clone())); + + // Set the pref to some arbitrary value since we just want to confirm that if + // the pref has a value we will assume that we have already performed the + // migration and will not attempt another migration. + base::Value::Dict new_prefs; + local_state()->Set(DeviceNameManager::kDeviceIdToNicknameMapPrefName, + base::Value(new_prefs.Clone())); + + EXPECT_TRUE(local_state()->HasPrefPath( + DeviceNameManager::kDeviceIdToNicknameMapPrefName)); + + CreateDeviceNameManager(); + + const base::Value::Dict& migrated_prefs = + local_state()->GetDict(DeviceNameManager::kDeviceIdToNicknameMapPrefName); + EXPECT_EQ(new_prefs, migrated_prefs); +} + +TEST_F(DeviceNameManagerImplTest, Migration) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(floss::features::kFlossEnabled); + EXPECT_TRUE(floss::features::IsFlossEnabled()); + + // The value that we expect to be migrated. + auto existing_prefs = base::Value::Dict() + .Set(kTestIdBluez, kTestNickname) + .Set(kTestIdFloss1, kTestNickname); + + local_state()->Set(DeviceNameManager::kDeviceIdToNicknameMapPrefNameLegacy, + base::Value(existing_prefs.Clone())); + + EXPECT_FALSE(local_state()->HasPrefPath( + DeviceNameManager::kDeviceIdToNicknameMapPrefName)); + + CreateDeviceNameManager(); + + auto migrated_prefs = base::Value::Dict() + .Set(kTestIdFloss0, kTestNickname) + .Set(kTestIdFloss1, kTestNickname); + EXPECT_EQ(migrated_prefs, + local_state()->GetDict( + DeviceNameManager::kDeviceIdToNicknameMapPrefName)); +} + } // namespace ash::bluetooth_config
diff --git a/chromeos/ash/services/libassistant/constants.cc b/chromeos/ash/services/libassistant/constants.cc index ced725e..739ae3b 100644 --- a/chromeos/ash/services/libassistant/constants.cc +++ b/chromeos/ash/services/libassistant/constants.cc
@@ -11,7 +11,6 @@ #define ASSISTANT_SOCKETS_STRING "sockets" #define ASSISTANT_TEMP_DIR "/tmp/libassistant/" #define LIBASSISTANT_DLC_DIR "opt/google/chrome/" -#define LIBASSISTANT_V1_NAME "libassistant.so" #define LIBASSISTANT_V2_NAME "libassistant_v2.so" namespace ash::libassistant { @@ -26,9 +25,6 @@ const char kLibAssistantDlcRootPath[] = "/run/imageloader/assistant-dlc/package/root"; -const base::FilePath::CharType kLibAssistantV1DlcPath[] = - FILE_PATH_LITERAL(LIBASSISTANT_DLC_DIR LIBASSISTANT_V1_NAME); - const base::FilePath::CharType kLibAssistantV2DlcPath[] = FILE_PATH_LITERAL(LIBASSISTANT_DLC_DIR LIBASSISTANT_V2_NAME); #else @@ -41,9 +37,6 @@ const char kLibAssistantDlcRootPath[] = ""; -const base::FilePath::CharType kLibAssistantV1DlcPath[] = - FILE_PATH_LITERAL(LIBASSISTANT_V1_NAME); - const base::FilePath::CharType kLibAssistantV2DlcPath[] = FILE_PATH_LITERAL(LIBASSISTANT_V2_NAME); #endif
diff --git a/chromeos/ash/services/libassistant/constants.h b/chromeos/ash/services/libassistant/constants.h index 957a326..8e6c6bf 100644 --- a/chromeos/ash/services/libassistant/constants.h +++ b/chromeos/ash/services/libassistant/constants.h
@@ -19,10 +19,6 @@ COMPONENT_EXPORT(LIBASSISTANT_CONSTANTS) extern const char kLibAssistantDlcRootPath[]; -// Libassistant v1 library DLC path. -COMPONENT_EXPORT(LIBASSISTANT_CONSTANTS) -extern const base::FilePath::CharType kLibAssistantV1DlcPath[]; - // Libassistant v2 library DLC path. COMPONENT_EXPORT(LIBASSISTANT_CONSTANTS) extern const base::FilePath::CharType kLibAssistantV2DlcPath[];
diff --git a/chromeos/ash/services/libassistant/service_controller.cc b/chromeos/ash/services/libassistant/service_controller.cc index 720ae75..5bb5df62 100644 --- a/chromeos/ash/services/libassistant/service_controller.cc +++ b/chromeos/ash/services/libassistant/service_controller.cc
@@ -292,10 +292,6 @@ // triggered by `ESSENTIAL_SERVICES_AVAILABLE`. After the AssistantManager is // started, it will trigger `ALL_SERVICES_AVAILABLE`. Therefore these two // signals are generated in order. - // For V1, a fake `ESSENTIAL_SERVICES_AVAILABLE` signal is sent in - // AssistantClientV1::StartServices(). An equivalent signal of - // `ALL_SERVICES_AVAILABLE`, DeviceState::StartupState::finished, is sent - // in AssistantManagerImpl::OnBootupCheckinDone(). assistant_client_->assistant_manager()->Start(); // Notify observer on Libassistant services started.
diff --git a/chromeos/components/onc/onc_signature.cc b/chromeos/components/onc/onc_signature.cc index f7cb620c..3d00341 100644 --- a/chromeos/components/onc/onc_signature.cc +++ b/chromeos/components/onc/onc_signature.cc
@@ -322,6 +322,7 @@ {::onc::cellular::kAllowRoaming, &kBoolSignature}, {::onc::cellular::kAPN, &kCellularApnSignature}, {::onc::cellular::kAPNList, &kCellularApnListSignature}, + {::onc::cellular::kAdminAssignedAPNIds, &kStringListSignature}, {::onc::cellular::kAutoConnect, &kBoolSignature}, {::onc::cellular::kCustomAPNList, &kCellularApnListSignature}, {::onc::cellular::kICCID, &kStringSignature}, @@ -419,6 +420,12 @@ {::onc::global_network_config:: kUserCreatedNetworkConfigurationsAreEphemeral, &kBoolSignature}, + {::onc::global_network_config::kAllowAPNModification, &kBoolSignature, + []() { return base::Value(true); }}, + {::onc::global_network_config::kPSIMAdminAssignedAPNIds, + &kStringListSignature}, + {::onc::global_network_config::kPSIMAdminAssignedAPNs, + &kCellularApnListSignature}, {nullptr}}; const OncFieldSignature certificate_fields[] = { @@ -442,6 +449,7 @@ &kNetworkConfigurationListSignature}, {::onc::toplevel_config::kGlobalNetworkConfiguration, &kGlobalNetworkConfigurationSignature}, + {::onc::toplevel_config::kAdminAPNList, &kCellularApnListSignature}, {::onc::toplevel_config::kType, &kStringSignature}, {::onc::encrypted::kCipher, &kStringSignature}, {::onc::encrypted::kCiphertext, &kStringSignature},
diff --git a/chromeos/components/onc/onc_validator.cc b/chromeos/components/onc/onc_validator.cc index 0349bc8..bfc097a8 100644 --- a/chromeos/components/onc/onc_validator.cc +++ b/chromeos/components/onc/onc_validator.cc
@@ -1087,6 +1087,7 @@ ::onc::global_network_config::kAllowTextMessages, ::onc::global_network_config::kAllowCellularSimLock, ::onc::global_network_config::kAllowCellularHotspot, + ::onc::global_network_config::kAllowAPNModification, ::onc::global_network_config::kDisableNetworkTypes, ::onc::global_network_config::kAllowOnlyPolicyCellularNetworks, ::onc::global_network_config::kAllowOnlyPolicyWiFiToConnect,
diff --git a/chromeos/components/onc/onc_validator_unittest.cc b/chromeos/components/onc/onc_validator_unittest.cc index 50a30d7..ed9c9b7 100644 --- a/chromeos/components/onc/onc_validator_unittest.cc +++ b/chromeos/components/onc/onc_validator_unittest.cc
@@ -205,6 +205,11 @@ &kToplevelConfigurationSignature, true, ::onc::ONC_SOURCE_DEVICE_POLICY), + // AllowModifyApns is only allowed for device policies. + OncParams("managed_toplevel_with_apns.onc", + &kToplevelConfigurationSignature, + true, + ::onc::ONC_SOURCE_DEVICE_POLICY), OncParams("managed_toplevel_l2tpipsec.onc", &kToplevelConfigurationSignature, true),
diff --git a/chromeos/components/quick_answers/OWNERS b/chromeos/components/quick_answers/OWNERS index 2c1de0c3..ec1f64c1 100644 --- a/chromeos/components/quick_answers/OWNERS +++ b/chromeos/components/quick_answers/OWNERS
@@ -1,3 +1,7 @@ -angelaxiao@chromium.org -xiaohuic@chromium.org -yawano@google.com +# Please use this reviewer queue instead of specifying an individual reviewer +# unless there is a specific reason for it. +assistive-code-review@google.com + +angelaxiao@chromium.org #{LAST_RESORT_SUGGESTION} +xiaohuic@chromium.org #{LAST_RESORT_SUGGESTION} +yawano@google.com #{LAST_RESORT_SUGGESTION}
diff --git a/chromeos/components/test/data/onc/managed_toplevel_with_apns.onc b/chromeos/components/test/data/onc/managed_toplevel_with_apns.onc new file mode 100644 index 0000000..b3bf067 --- /dev/null +++ b/chromeos/components/test/data/onc/managed_toplevel_with_apns.onc
@@ -0,0 +1,77 @@ +{ + "AdminAPNList": [ + { + "Id": "apn11f760-272b-6939-4c2beffe428697ac", + "AccessPointName": "test-apn", + "Username": "test-username", + "Password": "test-password", + "Authentication": "CHAP", + "IpType": "IPv4orIPv6" + }, + { + "Id": "apn22f760-272b-6939-4c2beffe428697ac", + "AccessPointName": "test-apn2", + "Username": "test-username2", + "Password": "test-password2", + "Authentication": "PAP", + "IpType": "IPv4" + } + ], + "GlobalNetworkConfiguration":{ + "AllowAPNModification": true, + "PSIMAdminAssignedAPNIds": [ + "apn11f760-272b-6939-4c2beffe428697ac", + ], + "PSIMAdminAssignedAPNs": [ + { + "Id": "apn11f760-272b-6939-4c2beffe428697ac", + "AccessPointName": "test-apn", + "Username": "test-username", + "Password": "test-password", + "Authentication": "CHAP", + "IpType": "IPv4orIPv6" + } + ], + }, + "NetworkConfigurations":[ + { + "Type": "Cellular", + "Name": "Test Network", + "GUID":"guid", + "Cellular": { + "AllowRoaming": true, + "APN": { + "Id": "apn22f760-272b-6939-4c2beffe428697ac", + "AccessPointName": "test-apn2", + "Username": "test-username2", + "Password": "test-password2", + "Authentication": "PAP", + "IpType": "IPv4" + }, + "AdminAssignedAPNIds": [ + "apn11f760-272b-6939-4c2beffe428697ac", + "apn22f760-272b-6939-4c2beffe428697ac" + ], + "CustomAPNList": [ + { + "Id": "apn11f760-272b-6939-4c2beffe428697ac", + "AccessPointName": "test-apn", + "Username": "test-username", + "Password": "test-password", + "Authentication": "CHAP", + "IpType": "IPv4orIPv6" + }, + { + "Id": "apn22f760-272b-6939-4c2beffe428697ac", + "AccessPointName": "test-apn2", + "Username": "test-username2", + "Password": "test-password2", + "Authentication": "PAP", + "IpType": "IPv4" + }, + ], + "AutoConnect": true + } + }, + ] +} \ No newline at end of file
diff --git a/chromeos/profiles/atom.afdo.newest.txt b/chromeos/profiles/atom.afdo.newest.txt index 45f29b8..e02d5ede 100644 --- a/chromeos/profiles/atom.afdo.newest.txt +++ b/chromeos/profiles/atom.afdo.newest.txt
@@ -1 +1 @@ -chromeos-chrome-amd64-atom-121-6167.9-1702295304-benchmark-122.0.6179.0-r1-redacted.afdo.xz +chromeos-chrome-amd64-atom-121-6167.9-1702295304-benchmark-122.0.6183.0-r1-redacted.afdo.xz
diff --git a/clank b/clank index 07b6932..08918f0 160000 --- a/clank +++ b/clank
@@ -1 +1 @@ -Subproject commit 07b69327abd1eddebf899b035e18a6b00af12dd6 +Subproject commit 08918f0ace2c32ab3dcc42c3ada371c7de65943e
diff --git a/components/autofill/core/browser/autofill_external_delegate.cc b/components/autofill/core/browser/autofill_external_delegate.cc index ba371bd..64db3af 100644 --- a/components/autofill/core/browser/autofill_external_delegate.cc +++ b/components/autofill/core/browser/autofill_external_delegate.cc
@@ -425,8 +425,7 @@ suggestion.GetPayload<Suggestion::BackendId>(), /*is_preview=*/true, {.trigger_source = TriggerSourceFromSuggestionTriggerSource(trigger_source_), - .field_types_to_fill = - GetServerFieldTypesOfGroup(FieldTypeGroup::kName)}); + .field_types_to_fill = GetFieldTypesOfGroup(FieldTypeGroup::kName)}); break; case PopupItemId::kFillFullPhoneNumber: FillAutofillFormData( @@ -435,7 +434,7 @@ {.trigger_source = TriggerSourceFromSuggestionTriggerSource(trigger_source_), .field_types_to_fill = - GetServerFieldTypesOfGroup(FieldTypeGroup::kPhone)}); + GetFieldTypesOfGroup(FieldTypeGroup::kPhone)}); break; case PopupItemId::kFillFullEmail: FillAutofillFormData( @@ -444,7 +443,7 @@ {.trigger_source = TriggerSourceFromSuggestionTriggerSource(trigger_source_), .field_types_to_fill = - GetServerFieldTypesOfGroup(FieldTypeGroup::kEmail)}); + GetFieldTypesOfGroup(FieldTypeGroup::kEmail)}); break; case PopupItemId::kAutocompleteEntry: case PopupItemId::kIbanEntry: @@ -567,8 +566,7 @@ suggestion.GetPayload<Suggestion::BackendId>(), /*is_preview=*/false, {.trigger_source = TriggerSourceFromSuggestionTriggerSource(trigger_source_), - .field_types_to_fill = - GetServerFieldTypesOfGroup(FieldTypeGroup::kName)}); + .field_types_to_fill = GetFieldTypesOfGroup(FieldTypeGroup::kName)}); break; case PopupItemId::kFillFullPhoneNumber: autofill_metrics::LogFillingMethodUsed( @@ -580,7 +578,7 @@ {.trigger_source = TriggerSourceFromSuggestionTriggerSource(trigger_source_), .field_types_to_fill = - GetServerFieldTypesOfGroup(FieldTypeGroup::kPhone)}); + GetFieldTypesOfGroup(FieldTypeGroup::kPhone)}); break; case PopupItemId::kFillFullEmail: autofill_metrics::LogFillingMethodUsed( @@ -591,7 +589,7 @@ {.trigger_source = TriggerSourceFromSuggestionTriggerSource(trigger_source_), .field_types_to_fill = - GetServerFieldTypesOfGroup(FieldTypeGroup::kEmail)}); + GetFieldTypesOfGroup(FieldTypeGroup::kEmail)}); break; case PopupItemId::kAutocompleteEntry: AutofillMetrics::LogAutocompleteSuggestionAcceptedIndex(position.row);
diff --git a/components/autofill/core/browser/autofill_external_delegate_unittest.cc b/components/autofill/core/browser/autofill_external_delegate_unittest.cc index b64787f4..c80d88ea 100644 --- a/components/autofill/core/browser/autofill_external_delegate_unittest.cc +++ b/components/autofill/core/browser/autofill_external_delegate_unittest.cc
@@ -1278,13 +1278,13 @@ public ::testing::WithParamInterface<GroupFillingTestParams> {}; const GroupFillingTestParams kGroupFillingTestCases[] = { - {.field_types_to_fill = GetServerFieldTypesOfGroup(FieldTypeGroup::kName), + {.field_types_to_fill = GetFieldTypesOfGroup(FieldTypeGroup::kName), .popup_item_id = PopupItemId::kFillFullName, .test_name = "_NameFields"}, - {.field_types_to_fill = GetServerFieldTypesOfGroup(FieldTypeGroup::kPhone), + {.field_types_to_fill = GetFieldTypesOfGroup(FieldTypeGroup::kPhone), .popup_item_id = PopupItemId::kFillFullPhoneNumber, .test_name = "_PhoneFields"}, - {.field_types_to_fill = GetServerFieldTypesOfGroup(FieldTypeGroup::kEmail), + {.field_types_to_fill = GetFieldTypesOfGroup(FieldTypeGroup::kEmail), .popup_item_id = PopupItemId::kFillFullEmail, .test_name = "_EmailAddressFields"}, {.field_types_to_fill = GetAddressFieldsForGroupFilling(),
diff --git a/components/autofill/core/browser/autofill_granular_filling_utils.cc b/components/autofill/core/browser/autofill_granular_filling_utils.cc index f047241..da62643 100644 --- a/components/autofill/core/browser/autofill_granular_filling_utils.cc +++ b/components/autofill/core/browser/autofill_granular_filling_utils.cc
@@ -14,14 +14,14 @@ ServerFieldTypeSet GetServerFieldsForFieldGroup(FieldTypeGroup group) { switch (group) { case FieldTypeGroup::kName: - return GetServerFieldTypesOfGroup(FieldTypeGroup::kName); + return GetFieldTypesOfGroup(FieldTypeGroup::kName); case FieldTypeGroup::kAddress: case FieldTypeGroup::kCompany: return GetAddressFieldsForGroupFilling(); case FieldTypeGroup::kPhone: - return GetServerFieldTypesOfGroup(FieldTypeGroup::kPhone); + return GetFieldTypesOfGroup(FieldTypeGroup::kPhone); case FieldTypeGroup::kEmail: - return GetServerFieldTypesOfGroup(FieldTypeGroup::kEmail); + return GetFieldTypesOfGroup(FieldTypeGroup::kEmail); case FieldTypeGroup::kNoGroup: case FieldTypeGroup::kCreditCard: case FieldTypeGroup::kPasswordField: @@ -54,17 +54,16 @@ } ServerFieldTypeSet GetAddressFieldsForGroupFilling() { - ServerFieldTypeSet fields = - GetServerFieldTypesOfGroup(FieldTypeGroup::kAddress); - fields.insert_all(GetServerFieldTypesOfGroup(FieldTypeGroup::kCompany)); + ServerFieldTypeSet fields = GetFieldTypesOfGroup(FieldTypeGroup::kAddress); + fields.insert_all(GetFieldTypesOfGroup(FieldTypeGroup::kCompany)); return fields; } bool AreFieldsGranularFillingGroup(const ServerFieldTypeSet& field_types) { return field_types == GetAddressFieldsForGroupFilling() || - field_types == GetServerFieldTypesOfGroup(FieldTypeGroup::kName) || - field_types == GetServerFieldTypesOfGroup(FieldTypeGroup::kEmail) || - field_types == GetServerFieldTypesOfGroup(FieldTypeGroup::kPhone); + field_types == GetFieldTypesOfGroup(FieldTypeGroup::kName) || + field_types == GetFieldTypesOfGroup(FieldTypeGroup::kEmail) || + field_types == GetFieldTypesOfGroup(FieldTypeGroup::kPhone); } ServerFieldTypeSet GetTargetServerFieldsForTypeAndLastTargetedFields(
diff --git a/components/autofill/core/browser/autofill_granular_filling_utils_unittest.cc b/components/autofill/core/browser/autofill_granular_filling_utils_unittest.cc index d99cc86e..d8dcc011 100644 --- a/components/autofill/core/browser/autofill_granular_filling_utils_unittest.cc +++ b/components/autofill/core/browser/autofill_granular_filling_utils_unittest.cc
@@ -14,13 +14,13 @@ AreFieldsGranularFillingGroup_ReturnsTrueWhenFieldsMatchAGroupFillingGroup) { // Test `FieldTypeGroup::kName` fields. EXPECT_TRUE(AreFieldsGranularFillingGroup( - GetServerFieldTypesOfGroup(FieldTypeGroup::kName))); + GetFieldTypesOfGroup(FieldTypeGroup::kName))); // Test `FieldTypeGroup::kPhone` fields. EXPECT_TRUE(AreFieldsGranularFillingGroup( - GetServerFieldTypesOfGroup(FieldTypeGroup::kPhone))); + GetFieldTypesOfGroup(FieldTypeGroup::kPhone))); // Test `FieldTypeGroup::kEmail` fields. EXPECT_TRUE(AreFieldsGranularFillingGroup( - GetServerFieldTypesOfGroup(FieldTypeGroup::kEmail))); + GetFieldTypesOfGroup(FieldTypeGroup::kEmail))); // Tests address fields, which in the context of granular filling // are both `FieldTypeGroup::kAddress` and `FieldTypeGroup::kCompany` fields. EXPECT_TRUE(AreFieldsGranularFillingGroup(GetAddressFieldsForGroupFilling())); @@ -32,7 +32,7 @@ TEST(AutofillGranularFillingUtilsTest, AreFieldsGranularFillingGroup_ReturnsFalseForAutofillAddressFieldsOnly) { EXPECT_FALSE(AreFieldsGranularFillingGroup( - GetServerFieldTypesOfGroup(FieldTypeGroup::kAddress))); + GetFieldTypesOfGroup(FieldTypeGroup::kAddress))); } TEST( @@ -54,19 +54,19 @@ EXPECT_EQ(GetTargetServerFieldsForTypeAndLastTargetedFields( GetAddressFieldsForGroupFilling(), /*triggering_field_type=*/NAME_FIRST), - GetServerFieldTypesOfGroup(FieldTypeGroup::kName)); + GetFieldTypesOfGroup(FieldTypeGroup::kName)); //`FieldTypeGroup::kCompany` triggering field. // Note that `FieldTypeGroup::kCompany` behaves the same as // `FieldTypeGroup::kAddress`. EXPECT_EQ(GetTargetServerFieldsForTypeAndLastTargetedFields( - GetServerFieldTypesOfGroup(FieldTypeGroup::kName), + GetFieldTypesOfGroup(FieldTypeGroup::kName), /*triggering_field_type=*/COMPANY_NAME), GetAddressFieldsForGroupFilling()); //`FieldTypeGroup::kAddress` triggering field. EXPECT_EQ(GetTargetServerFieldsForTypeAndLastTargetedFields( - GetServerFieldTypesOfGroup(FieldTypeGroup::kName), + GetFieldTypesOfGroup(FieldTypeGroup::kName), /*triggering_field_type=*/ADDRESS_HOME_LINE1), GetAddressFieldsForGroupFilling()); @@ -74,7 +74,7 @@ EXPECT_EQ(GetTargetServerFieldsForTypeAndLastTargetedFields( GetAddressFieldsForGroupFilling(), /*triggering_field_type=*/EMAIL_ADDRESS), - GetServerFieldTypesOfGroup(FieldTypeGroup::kEmail)); + GetFieldTypesOfGroup(FieldTypeGroup::kEmail)); } TEST(
diff --git a/components/autofill/core/browser/autofill_suggestion_generator_unittest.cc b/components/autofill/core/browser/autofill_suggestion_generator_unittest.cc index 734dade..a6006c7 100644 --- a/components/autofill/core/browser/autofill_suggestion_generator_unittest.cc +++ b/components/autofill/core/browser/autofill_suggestion_generator_unittest.cc
@@ -1222,7 +1222,7 @@ std::vector<Suggestion> suggestions = CreateSuggestionWithChildrenFromProfile( profile(), /*last_targeted_fields=*/ - GetServerFieldTypesOfGroup(FieldTypeGroup::kName), NAME_FIRST); + GetFieldTypesOfGroup(FieldTypeGroup::kName), NAME_FIRST); ASSERT_EQ(suggestions.size(), 1u); EXPECT_EQ(suggestions[0].labels, @@ -1246,7 +1246,7 @@ std::vector<Suggestion> suggestions = suggestion_generator()->CreateSuggestionsFromProfiles( {&profile_1, &profile_2}, {NAME_FIRST, NAME_MIDDLE}, - GetServerFieldTypesOfGroup(FieldTypeGroup::kName), NAME_FIRST, + GetFieldTypesOfGroup(FieldTypeGroup::kName), NAME_FIRST, /*trigger_field_max_length=*/0); ASSERT_EQ(suggestions.size(), 2u);
diff --git a/components/autofill/core/browser/browser_autofill_manager_unittest.cc b/components/autofill/core/browser/browser_autofill_manager_unittest.cc index 5129ca71..33b5605 100644 --- a/components/autofill/core/browser/browser_autofill_manager_unittest.cc +++ b/components/autofill/core/browser/browser_autofill_manager_unittest.cc
@@ -6064,8 +6064,7 @@ FillAutofillFormDataAndGetResults( form, form.fields[0], MakeGuid(1), {.trigger_source = AutofillTriggerSource::kPopup, - .field_types_to_fill = - GetServerFieldTypesOfGroup(FieldTypeGroup::kName)}); + .field_types_to_fill = GetFieldTypesOfGroup(FieldTypeGroup::kName)}); const std::vector<AutofillField::FieldLogEventType>& fill_field_log_events = browser_autofill_manager_->GetAutofillField(form, form.fields[0]) ->field_log_events();
diff --git a/components/autofill/core/browser/field_types.cc b/components/autofill/core/browser/field_types.cc index 46edef55..cf0987d2 100644 --- a/components/autofill/core/browser/field_types.cc +++ b/components/autofill/core/browser/field_types.cc
@@ -456,7 +456,7 @@ NOTREACHED_NORETURN(); } -FieldTypeSet GetServerFieldTypesOfGroup(FieldTypeGroup group) { +FieldTypeSet GetFieldTypesOfGroup(FieldTypeGroup group) { FieldTypeSet fields_matching_group; for (FieldType server_field_type : kAllFieldTypes) { if (GroupTypeOfServerFieldType(server_field_type) == group) {
diff --git a/components/autofill/core/browser/field_types.h b/components/autofill/core/browser/field_types.h index 36af367..5df0bba6 100644 --- a/components/autofill/core/browser/field_types.h +++ b/components/autofill/core/browser/field_types.h
@@ -503,7 +503,7 @@ // There's a one-to-many relationship between FieldTypeGroup and // FieldType as well as HtmlFieldType. -FieldTypeSet GetServerFieldTypesOfGroup(FieldTypeGroup group); +FieldTypeSet GetFieldTypesOfGroup(FieldTypeGroup group); FieldTypeGroup GroupTypeOfServerFieldType(FieldType field_type); FieldTypeGroup GroupTypeOfHtmlFieldType(HtmlFieldType field_type);
diff --git a/components/browser_ui/contacts_picker/android/java/src/org/chromium/components/browser_ui/contacts_picker/ContactsPickerDialogTest.java b/components/browser_ui/contacts_picker/android/java/src/org/chromium/components/browser_ui/contacts_picker/ContactsPickerDialogTest.java index 9a27344..a9308ad1 100644 --- a/components/browser_ui/contacts_picker/android/java/src/org/chromium/components/browser_ui/contacts_picker/ContactsPickerDialogTest.java +++ b/components/browser_ui/contacts_picker/android/java/src/org/chromium/components/browser_ui/contacts_picker/ContactsPickerDialogTest.java
@@ -84,6 +84,7 @@ public RenderTestRule mRenderTestRule = RenderTestRule.Builder.withPublicCorpus() .setBugComponent(RenderTestRule.Component.BLINK_CONTACTS) + .setRevision(1) .build(); // The dialog we are testing.
diff --git a/components/browser_ui/styles/android/java/res/values/themes.xml b/components/browser_ui/styles/android/java/res/values/themes.xml index af05442c..dfa7fee 100644 --- a/components/browser_ui/styles/android/java/res/values/themes.xml +++ b/components/browser_ui/styles/android/java/res/values/themes.xml
@@ -23,14 +23,6 @@ <item name="elevationOverlayEnabled">false</item> </style> - <!-- Updated Clank Baseline Surface-N Colors. See https://crbug.com/1410537. --> - <style name="SurfaceColorsThemeOverlay" parent=""> - <item name="elevationOverlayColor">@color/gm3_baseline_surface_tint</item> - <item name="elevationOverlayAccentColor">@android:color/transparent</item> - <item name="tileViewIconBackgroundModern">@drawable/oval_surface_2</item> - <item name="cardElevation">@dimen/default_elevation_2</item> - </style> - <style name="ThemeOverlay.BrowserUI.DynamicColors" parent="ThemeOverlay.Material3.DynamicColors.DayNight"> <item name="elevationOverlayColor">?attr/colorPrimary</item> <item name="elevationOverlayAccentColor">@android:color/transparent</item>
diff --git a/components/browser_ui/theme/android/java/res/values-night/themes.xml b/components/browser_ui/theme/android/java/res/values-night/themes.xml index 2f28f3e..72957df 100644 --- a/components/browser_ui/theme/android/java/res/values-night/themes.xml +++ b/components/browser_ui/theme/android/java/res/values-night/themes.xml
@@ -26,9 +26,6 @@ <item name="colorOnSurfaceInverse">@color/baseline_neutral_20</item> <item name="colorOutline">@color/baseline_neutral_variant_60</item> <item name="colorError">@color/baseline_error_80</item> - - <!-- Elevation overlays --> - <item name="elevationOverlayColor">@color/baseline_neutral_80</item> </style> <!-- Colors should be mirrored by Theme.BrowserUI.DayNight. --> @@ -50,9 +47,6 @@ <item name="colorOnSurfaceInverse">@color/baseline_neutral_20</item> <item name="colorOutline">@color/baseline_neutral_variant_60</item> <item name="colorError">@color/baseline_error_80</item> - - <!-- Elevation overlays --> - <item name="elevationOverlayColor">@color/baseline_neutral_80</item> </style> <!-- Colors should be mirrored by Theme.BrowserUI.DayNight. --> @@ -74,8 +68,5 @@ <item name="colorOnSurfaceInverse">@color/baseline_neutral_20</item> <item name="colorOutline">@color/baseline_neutral_variant_60</item> <item name="colorError">@color/baseline_error_80</item> - - <!-- Elevation overlays --> - <item name="elevationOverlayColor">@color/baseline_neutral_80</item> </style> </resources>
diff --git a/components/browser_ui/theme/android/java/res/values/themes.xml b/components/browser_ui/theme/android/java/res/values/themes.xml index 5988e099f..5ab6468 100644 --- a/components/browser_ui/theme/android/java/res/values/themes.xml +++ b/components/browser_ui/theme/android/java/res/values/themes.xml
@@ -46,12 +46,8 @@ <!-- Elevation overlays --> <item name="elevationOverlayEnabled">true</item> - <item name="elevationOverlayColor">@color/baseline_neutral_40</item> - <item name="elevationOverlayAccentColor">?attr/colorPrimary</item> - - <!-- Current Clank Baseline Surface-N Colors. See https://crbug.com/1410537. --> - <item name="tileViewIconBackgroundModern">@drawable/oval_surface_1</item> - <item name="cardElevation">@dimen/card_elevation</item> + <item name="elevationOverlayColor">@color/gm3_baseline_surface_tint</item> + <item name="elevationOverlayAccentColor">@android:color/transparent</item> <!-- Dynamic colors that are applied to the buttons and links. --> <item name="globalFilledButtonBgColor">@color/filled_button_bg_dynamic_list</item> @@ -146,12 +142,8 @@ <!-- Elevation overlays --> <item name="elevationOverlayEnabled">true</item> - <item name="elevationOverlayColor">@color/baseline_neutral_40</item> - <item name="elevationOverlayAccentColor">?attr/colorPrimary</item> - - <!-- Current Clank Baseline Surface-N Colors. See https://crbug.com/1410537. --> - <item name="tileViewIconBackgroundModern">@drawable/oval_surface_1</item> - <item name="cardElevation">@dimen/card_elevation</item> + <item name="elevationOverlayColor">@color/gm3_baseline_surface_tint</item> + <item name="elevationOverlayAccentColor">@android:color/transparent</item> <!-- Dynamic colors that are applied to the buttons and links. --> <item name="globalFilledButtonBgColor">@color/filled_button_bg_dynamic_list</item> @@ -213,12 +205,8 @@ <!-- Elevation overlays --> <item name="elevationOverlayEnabled">true</item> - <item name="elevationOverlayColor">@color/baseline_neutral_40</item> - <item name="elevationOverlayAccentColor">?attr/colorPrimary</item> - - <!-- Current Clank Baseline Surface-N Colors. See https://crbug.com/1410537. --> - <item name="tileViewIconBackgroundModern">@drawable/oval_surface_1</item> - <item name="cardElevation">@dimen/card_elevation</item> + <item name="elevationOverlayColor">@color/gm3_baseline_surface_tint</item> + <item name="elevationOverlayAccentColor">@android:color/transparent</item> <!-- Dynamic colors that are applied to the buttons and links. --> <item name="globalFilledButtonBgColor">@color/filled_button_bg_dynamic_list</item>
diff --git a/components/browser_ui/widget/android/java/res/layout/tile_no_text_view.xml b/components/browser_ui/widget/android/java/res/layout/tile_no_text_view.xml index d1ad35e..5b8deae 100644 --- a/components/browser_ui/widget/android/java/res/layout/tile_no_text_view.xml +++ b/components/browser_ui/widget/android/java/res/layout/tile_no_text_view.xml
@@ -18,7 +18,7 @@ android:layout_height="@dimen/tile_view_icon_size" android:layout_gravity="center_horizontal" android:layout_marginTop="@dimen/tile_view_icon_background_margin_top_modern" - android:background="?attr/tileViewIconBackgroundModern"/> + android:background="@drawable/tile_view_icon_background_modern"/> <!-- The main icon. --> <ImageView
diff --git a/components/browser_ui/widget/android/java/res/layout/tile_no_text_view_condensed.xml b/components/browser_ui/widget/android/java/res/layout/tile_no_text_view_condensed.xml index a628bca..35d15416 100644 --- a/components/browser_ui/widget/android/java/res/layout/tile_no_text_view_condensed.xml +++ b/components/browser_ui/widget/android/java/res/layout/tile_no_text_view_condensed.xml
@@ -18,7 +18,7 @@ android:layout_height="@dimen/tile_view_icon_size" android:layout_gravity="center_horizontal" android:layout_marginTop="@dimen/tile_view_icon_background_margin_top_modern" - android:background="?attr/tileViewIconBackgroundModern"/> + android:background="@drawable/tile_view_icon_background_modern"/> <!-- The main icon. --> <ImageView
diff --git a/components/browser_ui/widget/android/java/res/values/attrs.xml b/components/browser_ui/widget/android/java/res/values/attrs.xml index 3d9a83e..7545119 100644 --- a/components/browser_ui/widget/android/java/res/values/attrs.xml +++ b/components/browser_ui/widget/android/java/res/values/attrs.xml
@@ -125,8 +125,4 @@ <enum name="hard" value="2" /> </attr> </declare-styleable> - - <!-- Surface color resources. See https://crbug.com/1410537. --> - <attr name="tileViewIconBackgroundModern" format="reference"/> - <attr name="cardElevation" format="reference|dimension"/> </resources>
diff --git a/components/browser_ui/widget/android/java/res/values/drawables.xml b/components/browser_ui/widget/android/java/res/values/drawables.xml index 34056b2..2d93a3c5 100644 --- a/components/browser_ui/widget/android/java/res/values/drawables.xml +++ b/components/browser_ui/widget/android/java/res/values/drawables.xml
@@ -9,4 +9,5 @@ <drawable name="ic_more_vert_24dp">@drawable/ic_more_vert_24dp_on_light_bg</drawable> <drawable name="dialog_bg_tinted">@drawable/dialog_bg_baseline</drawable> <drawable name="menu_bg_tinted">@drawable/menu_bg_baseline</drawable> + <drawable name="tile_view_icon_background_modern">@drawable/oval_surface_2</drawable> </resources>
diff --git a/components/browser_ui/widget/android/java/res/values/styles.xml b/components/browser_ui/widget/android/java/res/values/styles.xml index 0218452..e67e9e6 100644 --- a/components/browser_ui/widget/android/java/res/values/styles.xml +++ b/components/browser_ui/widget/android/java/res/values/styles.xml
@@ -39,7 +39,7 @@ <style name="MaterialCardStyle"> <item name="cornerRadius">@dimen/card_rounded_corner_radius</item> - <item name="cardElevation">?attr/cardElevation</item> + <item name="cardElevation">@dimen/default_elevation_2</item> </style> <style name="ListActionButton" parent="@style/TextButton">
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/MaterialCardViewNoShadow.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/MaterialCardViewNoShadow.java index 7655194..a39d7fc 100644 --- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/MaterialCardViewNoShadow.java +++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/MaterialCardViewNoShadow.java
@@ -26,7 +26,6 @@ public MaterialCardViewNoShadow(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); - // TODO(https://crbug.com/1410537): Cleanup baseline color experiment references. final TypedArray typedArray = context.obtainStyledAttributes( attrs,
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/promo/PromoCardViewRenderTest.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/promo/PromoCardViewRenderTest.java index f26bb21a..1d0f97b 100644 --- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/promo/PromoCardViewRenderTest.java +++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/promo/PromoCardViewRenderTest.java
@@ -51,6 +51,7 @@ public RenderTestRule mRenderTestRule = RenderTestRule.Builder.withPublicCorpus() .setBugComponent(RenderTestRule.Component.UI_BROWSER_MOBILE) + .setRevision(1) .build(); public PromoCardViewRenderTest(boolean nightModeEnabled) {
diff --git a/components/feature_engagement/public/event_constants.cc b/components/feature_engagement/public/event_constants.cc index 6437131e..c8754de8 100644 --- a/components/feature_engagement/public/event_constants.cc +++ b/components/feature_engagement/public/event_constants.cc
@@ -66,7 +66,7 @@ const char kIncognitoTabOpened[] = "incognito_tab_opened"; const char kClearedBrowsingData[] = "cleared_browsing_data"; const char kViewedReadingList[] = "viewed_reading_list"; -const char kViewedWhatsNew[] = "viewed_whats_new"; +const char kViewedWhatsNew[] = "viewed_whats_new_m116"; const char kTriggeredTranslateInfobar[] = "triggered_translate_infobar"; const char kBottomToolbarOpened[] = "bottom_toolbar_opened"; const char kDiscoverFeedLoaded[] = "discover_feed_loaded";
diff --git a/components/feature_engagement/public/feature_constants.cc b/components/feature_engagement/public/feature_constants.cc index 242d568..1f2de5f 100644 --- a/components/feature_engagement/public/feature_constants.cc +++ b/components/feature_engagement/public/feature_constants.cc
@@ -488,6 +488,9 @@ BASE_FEATURE(kIPHWhatsNewFeature, "IPH_WhatsNew", base::FEATURE_ENABLED_BY_DEFAULT); +BASE_FEATURE(kIPHWhatsNewUpdatedFeature, + "IPH_WhatsNewUpdated", + base::FEATURE_ENABLED_BY_DEFAULT); BASE_FEATURE(kIPHReadingListMessagesFeature, "IPH_ReadingListMessages", base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/components/feature_engagement/public/feature_constants.h b/components/feature_engagement/public/feature_constants.h index 525e35d1..8e70f3e 100644 --- a/components/feature_engagement/public/feature_constants.h +++ b/components/feature_engagement/public/feature_constants.h
@@ -202,6 +202,7 @@ BASE_DECLARE_FEATURE(kIPHNewIncognitoTabTipFeature); BASE_DECLARE_FEATURE(kIPHBadgedReadingListFeature); BASE_DECLARE_FEATURE(kIPHWhatsNewFeature); +BASE_DECLARE_FEATURE(kIPHWhatsNewUpdatedFeature); BASE_DECLARE_FEATURE(kIPHReadingListMessagesFeature); BASE_DECLARE_FEATURE(kIPHBadgedTranslateManualTriggerFeature); BASE_DECLARE_FEATURE(kIPHDiscoverFeedHeaderFeature);
diff --git a/components/feature_engagement/public/feature_list.cc b/components/feature_engagement/public/feature_list.cc index 3c70b3c7..b7872db1 100644 --- a/components/feature_engagement/public/feature_list.cc +++ b/components/feature_engagement/public/feature_list.cc
@@ -119,6 +119,7 @@ &kIPHNewIncognitoTabTipFeature, &kIPHBadgedReadingListFeature, &kIPHWhatsNewFeature, + &kIPHWhatsNewUpdatedFeature, &kIPHReadingListMessagesFeature, &kIPHBadgedTranslateManualTriggerFeature, &kIPHDiscoverFeedHeaderFeature,
diff --git a/components/feature_engagement/public/feature_list.h b/components/feature_engagement/public/feature_list.h index 8be79a5d..82bc5d0 100644 --- a/components/feature_engagement/public/feature_list.h +++ b/components/feature_engagement/public/feature_list.h
@@ -222,6 +222,7 @@ "IPH_LongPressToolbarTip"); DEFINE_VARIATION_PARAM(kIPHNewIncognitoTabTipFeature, "IPH_NewIncognitoTabTip"); DEFINE_VARIATION_PARAM(kIPHBadgedReadingListFeature, "IPH_BadgedReadingList"); +DEFINE_VARIATION_PARAM(kIPHWhatsNewUpdatedFeature, "IPH_WhatsNewUpdated"); DEFINE_VARIATION_PARAM(kIPHWhatsNewFeature, "IPH_WhatsNew"); DEFINE_VARIATION_PARAM(kIPHReadingListMessagesFeature, "IPH_ReadingListMessages"); @@ -571,6 +572,7 @@ VARIATION_ENTRY(kIPHBadgedReadingListFeature), VARIATION_ENTRY(kIPHReadingListMessagesFeature), VARIATION_ENTRY(kIPHWhatsNewFeature), + VARIATION_ENTRY(kIPHWhatsNewUpdatedFeature), VARIATION_ENTRY(kIPHBadgedTranslateManualTriggerFeature), VARIATION_ENTRY(kIPHDiscoverFeedHeaderFeature), VARIATION_ENTRY(kIPHDefaultSiteViewFeature),
diff --git a/components/feature_engagement/public/ios_promo_feature_configuration.cc b/components/feature_engagement/public/ios_promo_feature_configuration.cc index 2d58683..ff8db964 100644 --- a/components/feature_engagement/public/ios_promo_feature_configuration.cc +++ b/components/feature_engagement/public/ios_promo_feature_configuration.cc
@@ -44,9 +44,14 @@ config->groups.push_back(kiOSFullscreenPromosGroup.name); config->used = EventConfig("whats_new_promo_used", Comparator(ANY, 0), 365, 365); - // What's New promo should be trigger no more than once a month. + // What's New promo should be trigger no more than once every 14 days. config->trigger = EventConfig("whats_new_promo_trigger", - Comparator(LESS_THAN, 1), 30, 365); + Comparator(LESS_THAN, 1), 14, 365); + config->event_configs.insert( + EventConfig(feature_engagement::events::kViewedWhatsNew, + Comparator(LESS_THAN, 1), 365, 365)); + config->event_configs.insert(EventConfig( + "chrome_opened", Comparator(GREATER_THAN_OR_EQUAL, 7), 365, 365)); } if (kIPHiOSPromoDefaultBrowserFeature.name == feature->name) { @@ -153,6 +158,23 @@ return config; } + if (kIPHWhatsNewUpdatedFeature.name == feature->name) { + // Should trigger and display What's New badged only when What's New was not + // viewed. + absl::optional<FeatureConfig> config = FeatureConfig(); + config->valid = true; + config->availability = Comparator(ANY, 0); + config->session_rate = Comparator(ANY, 0); + config->used = + EventConfig("whats_new_updated_used", Comparator(ANY, 0), 365, 365); + config->trigger = + EventConfig("whats_new_updated_trigger", Comparator(ANY, 0), 365, 365); + config->event_configs.insert( + EventConfig(feature_engagement::events::kViewedWhatsNew, + Comparator(LESS_THAN, 1), 365, 365)); + return config; + } + if (kIPHiOSDefaultBrowserVideoPromoTriggerFeature.name == feature->name) { // A config for a pseudo feature strictly to keep track of some of the // criteria to register the default browser video promo with the promo
diff --git a/components/image_fetcher/android/java/src/org/chromium/components/image_fetcher/ImageFetcher.java b/components/image_fetcher/android/java/src/org/chromium/components/image_fetcher/ImageFetcher.java index 61c9a14b..b7410f5 100644 --- a/components/image_fetcher/android/java/src/org/chromium/components/image_fetcher/ImageFetcher.java +++ b/components/image_fetcher/android/java/src/org/chromium/components/image_fetcher/ImageFetcher.java
@@ -35,6 +35,7 @@ public static final String QUERY_TILE_UMA_CLIENT_NAME = "QueryTiles"; public static final String WEB_ID_ACCOUNT_SELECTION_UMA_CLIENT_NAME = "WebIDAccountSelection"; public static final String WEB_NOTES_UMA_CLIENT_NAME = "WebNotes"; + public static final String PRICE_CHANGE_MODULE_NAME = "PriceChangeModule"; /** * Encapsulates image fetching customization options. Supports a subset of the native
diff --git a/components/onc/docs/onc_spec.md b/components/onc/docs/onc_spec.md index 8b806df7..30f0a10 100644 --- a/components/onc/docs/onc_spec.md +++ b/components/onc/docs/onc_spec.md
@@ -202,6 +202,16 @@ enabled and a network scan shows a new policy managed network, the device will automatically switch to the managed network. +* **AllowAPNModification** + * (optional, defaults to true) - **boolean** + * Only relevant when the admin does not specify APNs for a SIM. Note that + users cannot modify any admin assigned APNs. When this field is present + and set to false, users won't have the capabilities to add, modify, and + use their own custom APNs for cellular networks that do not have an APN + specified by the admin. When this field is unset or set to true, users + will have the aforementioned capabilities for an eSIM with no + AdminAssignedAPNIds, and for any pSIM if there are no PSIMAssignedAPNIds. + * **AllowTextMessages** * (optional, defaults to Unset) - **string** * When this field is present and set to Allow text message notifications @@ -240,6 +250,20 @@ connections may still be established successfully but will be closed shortly after that by the Chrome OS connection manager. +* **PSIMAdminAssignedAPNs** + * (optional) - [array of APN](#APN-type) + * Setting this field directly will have no effect, as it will be + automatically constructed from the provided *PSIMAdminAssignedAPNIds*, + each mapping to a unique APN in the the top-level *AdminAPNList*. + For all pSIMs, *CustomAPNList* will set to *PSIMAdminAssignedAPNs*. + +* **PSIMAdminAssignedAPNIds** + * (optional) - **array of string** + * List of custom APN configuration IDs added by the admin that map to APNs + that will be applied to all available pSIMs. *PSIMAdminAssignedAPNs* will + be automatically constructed from the provided *PSIMAdminAssignedAPNIds*, + each mapping to a unique APN in the the top-level *AdminAPNList*. + * **RecommendedValuesAreEphemeral** * (optional, defaults to false) - **boolean** * When this field is set to true, settings of device-wide policy-provided @@ -1568,6 +1592,14 @@ * (optional) - **string** * Activation type. +* **AdminAssignedAPNIds** + * (optional) - **array of string** + * List of custom APN configuration IDs added by the admin that map to APNs + that will be applied to the eSIM this cellular network configuration maps + to. *CustomAPNList* will be automatically constructed from the provided + *AdminAssignedAPNIds*, each mapping to a unique APN in the the top-level + *AdminAPNList*. + * **AllowRoaming** * (optional) - **boolean** * Whether cellular data connections are allowed when the device is roaming. @@ -1589,8 +1621,10 @@ * **CustomAPNList** * (optional) - [array of APN](#APN-type) - * List of custom APN configurations, added by either the user or enterprise - admin. + * List of custom APN configurations, added by either the user, or set + automatically with a list of APNs in the top-level *AdminAPNList* + that either map to a non-empty *AdminAssignedAPNIds* for an eSIM, or + to a non-empty *PSIMAdminAssignedAPNIds* for all pSIMs. * **EID** * (optional, read-only, provided only for eSIM networks) - **string** @@ -1760,36 +1794,6 @@ * (optional, read-only) - **boolean** * True if the cellular network supports scanning. -### APN type - -* **AccessPointName** - * (required) - **string** - * The access point name used when making connections. - -* **Name** - * (optional) - **string** - * Description of the APN. - -* **LocalizedName** - * (optional) - **string** - * Localized description of the APN. - -* **Username** - * (optional) - **string** - * Username for making connections if required. - -* **Password** - * (optional) - **string** - * Password for making connections if required. - -* **Authentication** - * (optional) - **string** - * Type of authentication protocol for sending username and password. - -* **Language** - * (optional, rquired if **LocalizedName** is provided) - **string** - Two letter language code for Localizedname if provided. - ### FoundNetwork type * **Status** @@ -1903,6 +1907,67 @@ This format will eventually also cover configuration of Bluetooth and WiFi Direct network technologies, however they are currently not supported. +## APNs + +Each of the following is an array of [APN](#APN-type) type objects: + * Top-level field **AdminAPNList** + * **PSIMAdminAssignedAPNs** field of **GlobalNetworkConfiguration** + * **APNList** field of [Cellular Networks](#Cellular-networks) + * **CustomAPNList** field of [Cellular Networks](#Cellular-networks) + +The **APN**,**LastConnectedAttachApnProperty**, **LastConnectedDefaultApnProperty**, +and **LastGoodAPN** fields of [Cellular](#Cellular-networks) are [APN](#Apn-type) +types. + +Note that each APN contained in the top-level field **AdminAPNList** may be +referenced by its **Id**. For example, **PSIMAdminAssignedAPNIds** +and **AdminAssignedAPNIds** are each an array of [APN](#Apn-type) **Id**s +that reference APNs contained in **AdminAPNList**. + +### APN type + +* **AccessPointName** + * (required) - **string** + * The access point name used when making connections. + +* **Name** + * (optional) - **string** + * Description of the APN. + +* **LocalizedName** + * (optional) - **string** + * Localized description of the APN. + +* **Username** + * (optional) - **string** + * Username for making connections if required. + +* **Password** + * (optional) - **string** + * Password for making connections if required. + +* **Authentication** + * (optional) - **string** + * Type of authentication protocol for sending username and password. + +* **Language** + * (optional, required if **LocalizedName** is provided) - **string** + * Two letter language code for Localizedname if provided. + +* **Id** + * (optional) - **string** + * A unique identifier for this APN. Must be a non-empty string. + +* **IpType** + * (optional) - **string** + * The IP type of the APN. Possible values are "", "IPv4", "IPv6", or + "IPv4orIPv6". If none is provided or the provided string is empty, + the IP type is automatic. + +* **ApnTypes** + * (optional) - **array of string** + * The type(s) of the APN. Possible values are "Default" + and or "Attach". ## Certificates
diff --git a/components/onc/onc_constants.cc b/components/onc/onc_constants.cc index 520dbe16..41c34af 100644 --- a/components/onc/onc_constants.cc +++ b/components/onc/onc_constants.cc
@@ -24,6 +24,7 @@ // Top Level Configuration namespace toplevel_config { +const char kAdminAPNList[] = "AdminAPNList"; const char kCertificates[] = "Certificates"; const char kEncryptedConfiguration[] = "EncryptedConfiguration"; const char kNetworkConfigurations[] = "NetworkConfigurations"; @@ -104,6 +105,7 @@ const char kNotActivated[] = "NotActivated"; const char kPartiallyActivated[] = "PartiallyActivated"; const char kActivationType[] = "ActivationType"; +const char kAdminAssignedAPNIds[] = "AdminAssignedAPNIds"; const char kAllowRoaming[] = "AllowRoaming"; const char kAPN[] = "APN"; const char kAPNList[] = "APNList"; @@ -532,6 +534,7 @@ } // namespace substitutes namespace global_network_config { +const char kAllowAPNModification[] = "AllowAPNModification"; const char kAllowCellularSimLock[] = "AllowCellularSimLock"; const char kAllowCellularHotspot[] = "AllowCellularHotspot"; const char kAllowOnlyPolicyCellularNetworks[] = @@ -555,6 +558,8 @@ const char kBlacklistedHexSSIDs[] = "BlacklistedHexSSIDs"; // Deprecated const char kBlockedHexSSIDs[] = "BlockedHexSSIDs"; const char kDisableNetworkTypes[] = "DisableNetworkTypes"; +const char kPSIMAdminAssignedAPNIds[] = "PSIMAdminAssignedAPNIds"; +const char kPSIMAdminAssignedAPNs[] = "PSIMAdminAssignedAPNs"; const char kRecommendedValuesAreEphemeral[] = "RecommendedValuesAreEphemeral"; const char kUserCreatedNetworkConfigurationsAreEphemeral[] = "UserCreatedNetworkConfigurationsAreEphemeral";
diff --git a/components/onc/onc_constants.h b/components/onc/onc_constants.h index cb20d4b..ca33701 100644 --- a/components/onc/onc_constants.h +++ b/components/onc/onc_constants.h
@@ -47,6 +47,7 @@ // Top Level Configuration namespace toplevel_config { +COMPONENT_EXPORT(ONC) extern const char kAdminAPNList[]; COMPONENT_EXPORT(ONC) extern const char kCertificates[]; COMPONENT_EXPORT(ONC) extern const char kEncryptedConfiguration[]; COMPONENT_EXPORT(ONC) extern const char kNetworkConfigurations[]; @@ -121,6 +122,7 @@ COMPONENT_EXPORT(ONC) extern const char kNotActivated[]; COMPONENT_EXPORT(ONC) extern const char kPartiallyActivated[]; COMPONENT_EXPORT(ONC) extern const char kActivationType[]; +COMPONENT_EXPORT(ONC) extern const char kAdminAssignedAPNIds[]; COMPONENT_EXPORT(ONC) extern const char kAllowRoaming[]; COMPONENT_EXPORT(ONC) extern const char kAPN[]; COMPONENT_EXPORT(ONC) extern const char kAPNList[]; @@ -541,6 +543,7 @@ } // namespace proxy namespace global_network_config { +COMPONENT_EXPORT(ONC) extern const char kAllowAPNModification[]; COMPONENT_EXPORT(ONC) extern const char kAllowCellularSimLock[]; COMPONENT_EXPORT(ONC) extern const char kAllowCellularHotspot[]; COMPONENT_EXPORT(ONC) extern const char kAllowOnlyPolicyCellularNetworks[]; @@ -554,6 +557,8 @@ COMPONENT_EXPORT(ONC) extern const char kBlockedHexSSIDs[]; COMPONENT_EXPORT(ONC) extern const char kDisableNetworkTypes[]; COMPONENT_EXPORT(ONC) extern const char kRecommendedValuesAreEphemeral[]; +COMPONENT_EXPORT(ONC) extern const char kPSIMAdminAssignedAPNIds[]; +COMPONENT_EXPORT(ONC) extern const char kPSIMAdminAssignedAPNs[]; COMPONENT_EXPORT(ONC) extern const char kUserCreatedNetworkConfigurationsAreEphemeral[]; } // namespace global_network_config
diff --git a/components/optimization_guide/internal b/components/optimization_guide/internal index 59cb0f7..173f058 160000 --- a/components/optimization_guide/internal +++ b/components/optimization_guide/internal
@@ -1 +1 @@ -Subproject commit 59cb0f75d907dfe078b70c4eb1504bca1d77a112 +Subproject commit 173f05847ba29e71a934e10d0b8dcc97584e1b1b
diff --git a/components/policy/resources/templates/policies.yaml b/components/policy/resources/templates/policies.yaml index 318c8b08..06c7137 100644 --- a/components/policy/resources/templates/policies.yaml +++ b/components/policy/resources/templates/policies.yaml
@@ -1096,7 +1096,7 @@ 1095: InsecureHashesInTLSHandshakesEnabled 1096: DeviceLoginScreenGeolocationAccessLevel 1097: DeviceReportNetworkEvents - 1098: SafeBrowsingExtensionProtectionAllowed + 1098: '' 1099: ShowDisplaySizeScreenEnabled 1100: EssentialSearchEnabled 1101: LegacyTechReportAllowlist
diff --git a/components/policy/resources/templates/policy_definitions/Miscellaneous/DeviceSwitchFunctionKeysBehaviorEnabled.yaml b/components/policy/resources/templates/policy_definitions/Miscellaneous/DeviceSwitchFunctionKeysBehaviorEnabled.yaml index 486e11c8..a8ff213a 100644 --- a/components/policy/resources/templates/policy_definitions/Miscellaneous/DeviceSwitchFunctionKeysBehaviorEnabled.yaml +++ b/components/policy/resources/templates/policy_definitions/Miscellaneous/DeviceSwitchFunctionKeysBehaviorEnabled.yaml
@@ -34,6 +34,6 @@ schema: type: boolean supported_on: -- chrome_os:121- +- chrome_os:122- tags: [] type: main
diff --git a/components/policy/resources/templates/policy_definitions/SafeBrowsing/SafeBrowsingExtensionProtectionAllowed.yaml b/components/policy/resources/templates/policy_definitions/SafeBrowsing/SafeBrowsingExtensionProtectionAllowed.yaml deleted file mode 100644 index d1b1c4f..0000000 --- a/components/policy/resources/templates/policy_definitions/SafeBrowsing/SafeBrowsingExtensionProtectionAllowed.yaml +++ /dev/null
@@ -1,26 +0,0 @@ -caption: Allow Safe Browsing Extension Protection -desc: |- - When this policy is enabled or left unset, <ph name="SAFE_BROWSING_NAME">Safe Browsing</ph> extension protection will be controlled by <ph name="SAFE_BROWSING_PROTECTION_LEVEL_POLICY_NAME">SafeBrowsingProtectionLevel</ph> for <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph>. If <ph name="SAFE_BROWSING_PROTECTION_LEVEL_POLICY_NAME">SafeBrowsingProtectionLevel</ph> is set to <ph name="SAFE_BROWSING_PROTECTION_LEVEL_VALUE_STANDARD">Standard</ph> or <ph name="SAFE_BROWSING_PROTECTION_LEVEL_VALUE_ENHANCED">Enhanced Protection</ph>, malicious extensions will be disabled faster in <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph>. <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> sends a request to Google Safe Browsing server to check whether an extension has been taken down from Chrome Web Store for being deemed problematic, i.e., malicious, vulnerable, unwanted software, or violating Chrome Web Store (CWS) policies. If an extension has been taken down, <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> will block users from installing the extension and will disable the extension if it has already been installed. - When this policy is disabled, <ph name="SAFE_BROWSING_NAME">Safe Browsing</ph> extension protection will be disabled and malicious extensions will be checked and removed less regularly through <ph name="GOOGLE_UPDATE_NAME">Google Update</ph>. No data is sent to Google <ph name="SAFE_BROWSING_NAME">Safe Browsing</ph> for verdicts. -default: true -example_value: true -features: - cloud_only: true - dynamic_refresh: true - per_profile: true - unlisted: true -items: -- caption: Safe Browsing Extension Protection is controlled by <ph name="SAFE_BROWSING_PROTECTION_LEVEL_POLICY_NAME">SafeBrowsingProtectionLevel</ph> policy - value: true -- caption: Disable Safe Browsing Extension Protection - value: false -owners: -- alexwchen@chromium.org -- file://components/safe_browsing/OWNERS -schema: - type: boolean -supported_on: -- chrome_os:114- -tags: -- google-sharing -type: main
diff --git a/components/policy/resources/templates/policy_definitions/SafeBrowsing/policy_atomic_groups.yaml b/components/policy/resources/templates/policy_definitions/SafeBrowsing/policy_atomic_groups.yaml index ce3c0a6..2d7e44c8 100644 --- a/components/policy/resources/templates/policy_definitions/SafeBrowsing/policy_atomic_groups.yaml +++ b/components/policy/resources/templates/policy_definitions/SafeBrowsing/policy_atomic_groups.yaml
@@ -11,7 +11,6 @@ - SafeBrowsingExtendedReportingEnabled - SafeBrowsingProtectionLevel - SafeBrowsingAllowlistDomains - - SafeBrowsingExtensionProtectionAllowed - SafeBrowsingProxiedRealTimeChecksAllowed - SafeBrowsingSurveysEnabled - SafeBrowsingDeepScanningEnabled
diff --git a/components/policy/test/data/pref_mapping/SafeBrowsingExtensionProtectionAllowed.json b/components/policy/test/data/pref_mapping/SafeBrowsingExtensionProtectionAllowed.json deleted file mode 100644 index 37854d2..0000000 --- a/components/policy/test/data/pref_mapping/SafeBrowsingExtensionProtectionAllowed.json +++ /dev/null
@@ -1,38 +0,0 @@ -[ - { - "os": [ - "chromeos_ash", - "chromeos_lacros" - ], - "policy_pref_mapping_tests": [ - { - "policies": {}, - "prefs": { - "safebrowsing.extension_protection_allowed_by_policy": { - "default_value": true - } - } - }, - { - "policies": { - "SafeBrowsingExtensionProtectionAllowed": true - }, - "prefs": { - "safebrowsing.extension_protection_allowed_by_policy": { - "value": true - } - } - }, - { - "policies": { - "SafeBrowsingExtensionProtectionAllowed": false - }, - "prefs": { - "safebrowsing.extension_protection_allowed_by_policy": { - "value": false - } - } - } - ] - } -]
diff --git a/components/renderer_context_menu/render_view_context_menu_base.cc b/components/renderer_context_menu/render_view_context_menu_base.cc index ffe4002..ad4f009 100644 --- a/components/renderer_context_menu/render_view_context_menu_base.cc +++ b/components/renderer_context_menu/render_view_context_menu_base.cc
@@ -321,14 +321,6 @@ toolkit_delegate_->RebuildMenu(); } -// TODO(crbug.com/1393234): This method returns the RenderViewHost associated -// with the primary main frame. Using this in the presence of out of process -// iframes is generally incorrect, and the use of RenderViewHost itself is -// deprecated. Callers should use GetRenderFrameHost() instead. -RenderViewHost* RenderViewContextMenuBase::GetRenderViewHost() const { - return source_web_contents_->GetPrimaryMainFrame()->GetRenderViewHost(); -} - WebContents* RenderViewContextMenuBase::GetWebContents() const { return source_web_contents_; }
diff --git a/components/renderer_context_menu/render_view_context_menu_base.h b/components/renderer_context_menu/render_view_context_menu_base.h index ce17ade..bed22b2 100644 --- a/components/renderer_context_menu/render_view_context_menu_base.h +++ b/components/renderer_context_menu/render_view_context_menu_base.h
@@ -121,12 +121,11 @@ void RemoveMenuItem(int command_id) override; void RemoveAdjacentSeparators() override; void RemoveSeparatorBeforeMenuItem(int command_id) override; - content::RenderViewHost* GetRenderViewHost() const override; content::WebContents* GetWebContents() const override; content::BrowserContext* GetBrowserContext() const override; // May return nullptr if the frame was deleted while the menu was open. - content::RenderFrameHost* GetRenderFrameHost() const; + content::RenderFrameHost* GetRenderFrameHost() const override; protected: friend class RenderViewContextMenuTest;
diff --git a/components/renderer_context_menu/render_view_context_menu_proxy.h b/components/renderer_context_menu/render_view_context_menu_proxy.h index 7f06164..48b03c6 100644 --- a/components/renderer_context_menu/render_view_context_menu_proxy.h +++ b/components/renderer_context_menu/render_view_context_menu_proxy.h
@@ -10,7 +10,7 @@ namespace content { class BrowserContext; -class RenderViewHost; +class RenderFrameHost; class WebContents; } @@ -52,9 +52,9 @@ // fetcher_->SetRequestContext(context); // content::AssociateURLFetcherWithRenderView( // fetcher_.get(), -// proxy_->GetRenderViewHost()->GetSiteInstance()->GetSite(), -// proxy_->GetRenderViewHost()->GetProcess()->GetID(), -// proxy_->GetRenderViewHost()->GetRoutingID()); +// proxy_->GetRenderFrameHost()->GetSiteInstance()->GetSite(), +// proxy_->GetRenderFrameHost()->GetProcess()->GetID(), +// proxy_->GetRenderFrameHost()->GetRoutingID()); // fetcher_->Start(); // } // @@ -121,7 +121,7 @@ virtual void AddPdfOcrMenuItem() = 0; // Retrieve the given associated objects with a context menu. - virtual content::RenderViewHost* GetRenderViewHost() const = 0; + virtual content::RenderFrameHost* GetRenderFrameHost() const = 0; virtual content::WebContents* GetWebContents() const = 0; virtual content::BrowserContext* GetBrowserContext() const = 0; };
diff --git a/components/safe_browsing/core/common/proto/csd.proto b/components/safe_browsing/core/common/proto/csd.proto index 9060b77..fecc1582 100644 --- a/components/safe_browsing/core/common/proto/csd.proto +++ b/components/safe_browsing/core/common/proto/csd.proto
@@ -1706,7 +1706,7 @@ // Applicable actions: PROCEED, DISCARD, DISMISS, CLOSE, BACK, // PROCEED_DEEP_SCAN, OPEN_LEARN_MORE_LINK BUBBLE_SUBPAGE = 2; - // Applicable actions: DISCARD, KEEP + // Applicable actions: DISCARD, KEEP, PROCEED DOWNLOADS_PAGE = 3; // Applicable actions: PROCEED, CANCEL, CLOSE DOWNLOAD_PROMPT = 4;
diff --git a/components/safe_browsing/core/common/safe_browsing_prefs.cc b/components/safe_browsing/core/common/safe_browsing_prefs.cc index 156cbdf..8464192 100644 --- a/components/safe_browsing/core/common/safe_browsing_prefs.cc +++ b/components/safe_browsing/core/common/safe_browsing_prefs.cc
@@ -139,8 +139,6 @@ "safebrowsing.extension_telemetry_configuration"; const char kExtensionTelemetryFileData[] = "safebrowsing.extension_telemetry_file_data"; -const char kSafeBrowsingExtensionProtectionAllowedByPolicy[] = - "safebrowsing.extension_protection_allowed_by_policy"; const char kHashPrefixRealTimeChecksAllowedByPolicy[] = "safebrowsing.hash_prefix_real_time_checks_allowed_by_policy"; } // namespace prefs @@ -219,11 +217,6 @@ ->IsExtensionControlled(); } -bool IsSafeBrowsingExtensionProtectionAllowed(const PrefService& prefs) { - return prefs.GetBoolean( - prefs::kSafeBrowsingExtensionProtectionAllowedByPolicy); -} - bool AreHashPrefixRealTimeLookupsAllowedByPolicy(const PrefService& prefs) { return prefs.GetBoolean(prefs::kHashPrefixRealTimeChecksAllowedByPolicy); } @@ -314,8 +307,6 @@ base::Time::Now()); registry->RegisterDictionaryPref(prefs::kExtensionTelemetryConfig); registry->RegisterDictionaryPref(prefs::kExtensionTelemetryFileData); - registry->RegisterBooleanPref( - prefs::kSafeBrowsingExtensionProtectionAllowedByPolicy, true); registry->RegisterBooleanPref(prefs::kHashPrefixRealTimeChecksAllowedByPolicy, true); registry->RegisterBooleanPref(prefs::kSafeBrowsingSurveysEnabled, true); @@ -426,11 +417,6 @@ } preferences_list.Append(login_urls); preferences_list.Append(prefs::kPasswordProtectionLoginURLs); - - preferences_list.Append(prefs->GetBoolean( - prefs::kSafeBrowsingExtensionProtectionAllowedByPolicy)); - preferences_list.Append( - prefs::kSafeBrowsingExtensionProtectionAllowedByPolicy); preferences_list.Append( prefs->GetBoolean(prefs::kHashPrefixRealTimeChecksAllowedByPolicy)); preferences_list.Append(prefs::kHashPrefixRealTimeChecksAllowedByPolicy);
diff --git a/components/safe_browsing/core/common/safe_browsing_prefs.h b/components/safe_browsing/core/common/safe_browsing_prefs.h index f91baabc..f5237463 100644 --- a/components/safe_browsing/core/common/safe_browsing_prefs.h +++ b/components/safe_browsing/core/common/safe_browsing_prefs.h
@@ -187,13 +187,6 @@ // Telemetry Service's file processor. extern const char kExtensionTelemetryFileData[]; -// A boolean indicating if Safe Browsing extension blocklist is allowed by -// policy. If false, Safe Browsing extension blocklist will be disabled and no -// ClientCRXListInfoRequest will be sent to Safe Browsing regardless of Safe -// Browsing Protection Level. If true, follow Safe Browsing Protection Level. -// This policy does not impact extension blocklist due to Omaha updater. -extern const char kSafeBrowsingExtensionProtectionAllowedByPolicy[]; - // A boolean indicating if hash-prefix real-time lookups are allowed by policy. // If false, the lookups will instead be hash-prefix database lookups. If true, // there is no such override; the hash-prefix real-time lookups might still not @@ -329,10 +322,6 @@ // Return whether the Safe Browsing preference is controlled by an extension. bool IsSafeBrowsingExtensionControlled(const PrefService& prefs); -// Returns whether Safe Browsing extension protection is allowed for -// the user. -bool IsSafeBrowsingExtensionProtectionAllowed(const PrefService& prefs); - // Returns whether a user can receive HaTS surveys. bool IsSafeBrowsingSurveysEnabled(const PrefService& prefs);
diff --git a/components/safe_browsing/core/common/safe_browsing_prefs_unittest.cc b/components/safe_browsing/core/common/safe_browsing_prefs_unittest.cc index 1e004e2..90fc7cb 100644 --- a/components/safe_browsing/core/common/safe_browsing_prefs_unittest.cc +++ b/components/safe_browsing/core/common/safe_browsing_prefs_unittest.cc
@@ -35,8 +35,6 @@ prefs::kSafeBrowsingExtendedReportingOptInAllowed, true); prefs_.registry()->RegisterListPref(prefs::kSafeBrowsingAllowlistDomains); prefs_.registry()->RegisterBooleanPref( - prefs::kSafeBrowsingExtensionProtectionAllowedByPolicy, true); - prefs_.registry()->RegisterBooleanPref( prefs::kHashPrefixRealTimeChecksAllowedByPolicy, true); } @@ -226,13 +224,6 @@ EXPECT_FALSE(IsURLAllowlistedByPolicy(not_allowlisted_url, prefs_)); } -TEST_F(SafeBrowsingPrefsTest, VerifySafeBrowsingExtensionProtectionAllowed) { - EXPECT_TRUE(IsSafeBrowsingExtensionProtectionAllowed(prefs_)); - prefs_.SetBoolean(prefs::kSafeBrowsingExtensionProtectionAllowedByPolicy, - false); - EXPECT_FALSE(IsSafeBrowsingExtensionProtectionAllowed(prefs_)); -} - TEST_F(SafeBrowsingPrefsTest, VerifyHashPrefixRealTimeChecksAllowedByPolicy) { EXPECT_TRUE(AreHashPrefixRealTimeLookupsAllowedByPolicy(prefs_)); prefs_.SetBoolean(prefs::kHashPrefixRealTimeChecksAllowedByPolicy, false);
diff --git a/components/search/ntp_features.cc b/components/search/ntp_features.cc index 63466ce..2a3281e 100644 --- a/components/search/ntp_features.cc +++ b/components/search/ntp_features.cc
@@ -41,6 +41,12 @@ "CustomizeChromeWallpaperSearch", base::FEATURE_DISABLED_BY_DEFAULT); +// If enabled, shows inspiration card in Customize Chrome Side Panel Wallpaper +// Search. +BASE_FEATURE(kCustomizeChromeWallpaperSearchInspirationCard, + "CustomizeChromeWallpaperSearchInspirationCard", + base::FEATURE_DISABLED_BY_DEFAULT); + // Forces a dark Google logo for a specific subset of Chrome Web Store themes // (see crbug.com/1329552). This is enabled by default to allow finch to disable // this NTP treatment in the case of unexpected regressions.
diff --git a/components/search/ntp_features.h b/components/search/ntp_features.h index 40f49f77..bdfda18 100644 --- a/components/search/ntp_features.h +++ b/components/search/ntp_features.h
@@ -25,6 +25,7 @@ BASE_DECLARE_FEATURE(kCustomizeChromeColorExtraction); BASE_DECLARE_FEATURE(kCustomizeChromeSidePanelExtensionsCard); BASE_DECLARE_FEATURE(kCustomizeChromeWallpaperSearch); +BASE_DECLARE_FEATURE(kCustomizeChromeWallpaperSearchInspirationCard); BASE_DECLARE_FEATURE(kCwsDarkLogo); BASE_DECLARE_FEATURE(kDismissPromos); BASE_DECLARE_FEATURE(kIframeOneGoogleBar);
diff --git a/components/search_engines/site_search_policy_handler.cc b/components/search_engines/site_search_policy_handler.cc index cc860e8..1902c832 100644 --- a/components/search_engines/site_search_policy_handler.cc +++ b/components/search_engines/site_search_policy_handler.cc
@@ -40,8 +40,8 @@ // Converts a site search policy entry `policy_dict` into a dictionary to be // saved to prefs, with fields corresponding to `TemplateURLData`. -base::Value SiteSearchDictFromPolicyValue( - const base::Value::Dict& policy_dict) { +base::Value SiteSearchDictFromPolicyValue(const base::Value::Dict& policy_dict, + bool featured) { base::Value::Dict dict; const std::string* name = @@ -52,16 +52,15 @@ const std::string* shortcut = policy_dict.FindString(SiteSearchPolicyHandler::kShortcut); CHECK(shortcut); - dict.Set(DefaultSearchManager::kKeyword, *shortcut); + dict.Set(DefaultSearchManager::kKeyword, + featured ? "@" + *shortcut : *shortcut); const std::string* url = policy_dict.FindString(SiteSearchPolicyHandler::kUrl); CHECK(url); dict.Set(DefaultSearchManager::kURL, *url); - dict.Set( - DefaultSearchManager::kFeaturedByPolicy, - policy_dict.FindBool(SiteSearchPolicyHandler::kFeatured).value_or(false)); + dict.Set(DefaultSearchManager::kFeaturedByPolicy, featured); dict.Set(DefaultSearchManager::kCreatedByPolicy, static_cast<int>(TemplateURLData::CreatedByPolicy::kSiteSearch)); @@ -353,7 +352,14 @@ for (const base::Value& item : policy_value->GetList()) { const std::string& shortcut = GetShortcut(item); if (ignored_shortcuts_.find(shortcut) == ignored_shortcuts_.end()) { - providers.Append(SiteSearchDictFromPolicyValue(item.GetDict())); + const base::Value::Dict& policy_dict = item.GetDict(); + providers.Append( + SiteSearchDictFromPolicyValue(policy_dict, /*featured=*/false)); + if (policy_dict.FindBool(SiteSearchPolicyHandler::kFeatured) + .value_or(false)) { + providers.Append(SiteSearchDictFromPolicyValue(policy_dict, + /*featured=*/true)); + } } }
diff --git a/components/search_engines/site_search_policy_handler_unittest.cc b/components/search_engines/site_search_policy_handler_unittest.cc index f627a3d..593a2b64 100644 --- a/components/search_engines/site_search_policy_handler_unittest.cc +++ b/components/search_engines/site_search_policy_handler_unittest.cc
@@ -47,7 +47,7 @@ {.name = "work name", .shortcut = "work", .url = "https://work.com/{searchTerms}", - .featured_by_policy = true, + .featured_by_policy = false, .favicon = "https://work.com/favicon.ico"}, {.name = "docs name", .shortcut = "docs", @@ -193,6 +193,25 @@ .favicon = "http://work.com/favicon.ico"}, }; +// Used for tests that require a list of featured providers. +TestProvider kTestProvidersWithFeaturedEntries[] = { + {.name = "work name", + .shortcut = "work", + .url = "https://work.com/{searchTerms}", + .featured_by_policy = true, + .favicon = "https://work.com/favicon.ico"}, + {.name = "non-featured name", + .shortcut = "non-featured", + .url = "https://non-featured.com/{searchTerms}", + .featured_by_policy = false, + .favicon = "https://non-featured.com/favicon.ico"}, + {.name = "docs name", + .shortcut = "docs", + .url = "https://docs.com/{searchTerms}", + .featured_by_policy = true, + .favicon = "https://docs.com/favicon.ico"}, +}; + // Creates a simple list item for the site search policy. base::Value::Dict GenerateSiteSearchPolicyEntry(const std::string& name, const std::string& shortcut, @@ -229,7 +248,7 @@ base::StringPrintf("%s string field `%s` with value `%s`", negation ? "does not contain" : "contains", field_name, - expected_value)) { + expected_value.c_str())) { const std::string* dict_value = (arg).GetDict().FindString(field_name); return dict_value && *dict_value == expected_value; } @@ -273,24 +292,38 @@ // Returns a matcher that accepts entries for the pref corresponding to the // site search policy. Field values are obtained from |test_case|. -testing::Matcher<const base::Value&> IsSiteSearchEntry(TestProvider test_case) { +testing::Matcher<const base::Value&> IsSiteSearchEntry(TestProvider test_case, + bool featured) { + std::string expected_keyword = + base::StringPrintf("%s%s", (featured ? "@" : ""), test_case.shortcut); return AllOf( - HasStringField(DefaultSearchManager::kShortName, test_case.name), - HasStringField(DefaultSearchManager::kKeyword, test_case.shortcut), - HasStringField(DefaultSearchManager::kURL, test_case.url), - HasBooleanField(DefaultSearchManager::kFeaturedByPolicy, - test_case.featured_by_policy), + HasStringField(DefaultSearchManager::kShortName, + std::string(test_case.name)), + HasStringField(DefaultSearchManager::kKeyword, expected_keyword), + HasStringField(DefaultSearchManager::kURL, std::string(test_case.url)), + HasBooleanField(DefaultSearchManager::kFeaturedByPolicy, featured), HasIntegerField( DefaultSearchManager::kCreatedByPolicy, static_cast<int>(TemplateURLData::CreatedByPolicy::kSiteSearch)), HasBooleanField(DefaultSearchManager::kEnforcedByPolicy, false), HasBooleanField(DefaultSearchManager::kIsActive, true), - HasStringField(DefaultSearchManager::kFaviconURL, test_case.favicon), + HasStringField(DefaultSearchManager::kFaviconURL, + std::string(test_case.favicon)), HasBooleanField(DefaultSearchManager::kSafeForAutoReplace, false), HasDoubleField(DefaultSearchManager::kDateCreated), HasDoubleField(DefaultSearchManager::kLastModified)); } +testing::Matcher<const base::Value&> IsNonFeaturedSiteSearchEntry( + TestProvider test_case) { + return IsSiteSearchEntry(test_case, /*featured=*/false); +} + +testing::Matcher<const base::Value&> IsFeaturedSiteSearchEntry( + TestProvider test_case) { + return IsSiteSearchEntry(test_case, /*featured=*/true); +} + MATCHER_P(HasValidationError, expected_str, base::StringPrintf("%s error message `%s` for `SiteSearchSettings`", @@ -381,9 +414,10 @@ EnterpriseSiteSearchManager::kSiteSearchSettingsPrefName, &providers)); ASSERT_NE(providers, nullptr); ASSERT_TRUE(providers->is_list()); - EXPECT_THAT(providers->GetList(), - ElementsAre(IsSiteSearchEntry(kValidTestProviders[0]), - IsSiteSearchEntry(kValidTestProviders[1]))); + EXPECT_THAT( + providers->GetList(), + ElementsAre(IsNonFeaturedSiteSearchEntry(kValidTestProviders[0]), + IsNonFeaturedSiteSearchEntry(kValidTestProviders[1]))); } TEST(SiteSearchPolicyHandlerTest, InvalidFormat) { @@ -527,9 +561,8 @@ EnterpriseSiteSearchManager::kSiteSearchSettingsPrefName, &providers)); ASSERT_NE(providers, nullptr); ASSERT_TRUE(providers->is_list()); - EXPECT_THAT( - providers->GetList(), - ElementsAre(IsSiteSearchEntry(kShortcutNotUniqueTestProviders[2]))); + EXPECT_THAT(providers->GetList(), ElementsAre(IsNonFeaturedSiteSearchEntry( + kShortcutNotUniqueTestProviders[2]))); } TEST(SiteSearchPolicyHandlerTest, NoUniqueShortcut) { @@ -623,8 +656,9 @@ EnterpriseSiteSearchManager::kSiteSearchSettingsPrefName, &providers)); ASSERT_NE(providers, nullptr); ASSERT_TRUE(providers->is_list()); - EXPECT_THAT(providers->GetList(), - ElementsAre(IsSiteSearchEntry(kUnknownFieldTestProviders[0]))); + EXPECT_THAT( + providers->GetList(), + ElementsAre(IsNonFeaturedSiteSearchEntry(kUnknownFieldTestProviders[0]))); } TEST(SiteSearchPolicyHandlerTest, ShortcutWithSpace) { @@ -692,9 +726,9 @@ EnterpriseSiteSearchManager::kSiteSearchSettingsPrefName, &providers)); ASSERT_NE(providers, nullptr); ASSERT_TRUE(providers->is_list()); - EXPECT_THAT( - providers->GetList(), - ElementsAre(IsSiteSearchEntry(kShortcutStartsWithAtTestProviders[1]))); + EXPECT_THAT(providers->GetList(), + ElementsAre(IsNonFeaturedSiteSearchEntry( + kShortcutStartsWithAtTestProviders[1]))); } TEST(SiteSearchPolicyHandlerTest, InvalidUrl) { @@ -762,11 +796,11 @@ EnterpriseSiteSearchManager::kSiteSearchSettingsPrefName, &providers)); ASSERT_NE(providers, nullptr); ASSERT_TRUE(providers->is_list()); - EXPECT_THAT( - providers->GetList(), - ElementsAre( - IsSiteSearchEntry(kShortcutSameAsDSPKeywordTestProviders[0]), - IsSiteSearchEntry(kShortcutSameAsDSPKeywordTestProviders[1]))); + EXPECT_THAT(providers->GetList(), + ElementsAre(IsNonFeaturedSiteSearchEntry( + kShortcutSameAsDSPKeywordTestProviders[0]), + IsNonFeaturedSiteSearchEntry( + kShortcutSameAsDSPKeywordTestProviders[1]))); } TEST(SiteSearchPolicyHandlerTest, ShortcutSameAsDSPKeyword_DSPDisabled) { @@ -805,11 +839,11 @@ EnterpriseSiteSearchManager::kSiteSearchSettingsPrefName, &providers)); ASSERT_NE(providers, nullptr); ASSERT_TRUE(providers->is_list()); - EXPECT_THAT( - providers->GetList(), - ElementsAre( - IsSiteSearchEntry(kShortcutSameAsDSPKeywordTestProviders[0]), - IsSiteSearchEntry(kShortcutSameAsDSPKeywordTestProviders[1]))); + EXPECT_THAT(providers->GetList(), + ElementsAre(IsNonFeaturedSiteSearchEntry( + kShortcutSameAsDSPKeywordTestProviders[0]), + IsNonFeaturedSiteSearchEntry( + kShortcutSameAsDSPKeywordTestProviders[1]))); } TEST(SiteSearchPolicyHandlerTest, ShortcutSameAsDSPKeyword_DSPEnabled) { @@ -853,7 +887,7 @@ ASSERT_NE(providers, nullptr); ASSERT_TRUE(providers->is_list()); EXPECT_THAT(providers->GetList(), - ElementsAre(IsSiteSearchEntry( + ElementsAre(IsNonFeaturedSiteSearchEntry( kShortcutSameAsDSPKeywordTestProviders[1]))); } @@ -888,8 +922,9 @@ EnterpriseSiteSearchManager::kSiteSearchSettingsPrefName, &providers)); ASSERT_NE(providers, nullptr); ASSERT_TRUE(providers->is_list()); - EXPECT_THAT(providers->GetList(), - ElementsAre(IsSiteSearchEntry(kNonHttpsUrlTestProviders[0]))); + EXPECT_THAT( + providers->GetList(), + ElementsAre(IsNonFeaturedSiteSearchEntry(kNonHttpsUrlTestProviders[0]))); } TEST(SiteSearchPolicyHandlerTest, NoValidEntry) { @@ -912,4 +947,44 @@ IDS_POLICY_SITE_SEARCH_SETTINGS_NO_VALID_PROVIDER))); } +TEST(SiteSearchPolicyHandlerTest, FeaturedSiteSearchEntries) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeature(omnibox::kSiteSearchSettingsPolicy); + + SiteSearchPolicyHandler handler( + policy::Schema::Wrap(policy::GetChromeSchemaData())); + + policy::PolicyMap policies; + PolicyErrorMap errors; + PrefValueMap prefs; + + base::Value::List policy_value; + for (auto* it = std::begin(kTestProvidersWithFeaturedEntries); + it != std::end(kTestProvidersWithFeaturedEntries); ++it) { + policy_value.Append(GenerateSiteSearchPolicyEntry(*it)); + } + + policies.Set(key::kSiteSearchSettings, policy::POLICY_LEVEL_MANDATORY, + policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD, + base::Value(std::move(policy_value)), nullptr); + + ASSERT_TRUE(handler.CheckPolicySettings(policies, &errors)); + EXPECT_TRUE(errors.empty()); + + handler.ApplyPolicySettings(policies, &prefs); + base::Value* providers = nullptr; + ASSERT_TRUE(prefs.GetValue( + EnterpriseSiteSearchManager::kSiteSearchSettingsPrefName, &providers)); + ASSERT_NE(providers, nullptr); + ASSERT_TRUE(providers->is_list()); + EXPECT_THAT( + providers->GetList(), + ElementsAre( + IsNonFeaturedSiteSearchEntry(kTestProvidersWithFeaturedEntries[0]), + IsFeaturedSiteSearchEntry(kTestProvidersWithFeaturedEntries[0]), + IsNonFeaturedSiteSearchEntry(kTestProvidersWithFeaturedEntries[1]), + IsNonFeaturedSiteSearchEntry(kTestProvidersWithFeaturedEntries[2]), + IsFeaturedSiteSearchEntry(kTestProvidersWithFeaturedEntries[2]))); +} + } // namespace policy
diff --git a/components/search_engines/template_url.cc b/components/search_engines/template_url.cc index 9ced20b1..d356d65 100644 --- a/components/search_engines/template_url.cc +++ b/components/search_engines/template_url.cc
@@ -39,6 +39,7 @@ #include "components/search_engines/search_engine_utils.h" #include "components/search_engines/search_engines_switches.h" #include "components/search_engines/search_terms_data.h" +#include "components/search_engines/template_url_data.h" #include "components/url_formatter/url_formatter.h" #include "google_apis/google_api_keys.h" #include "net/base/mime_util.h" @@ -209,6 +210,30 @@ return std::string(); } +// Returns true if `enterprise_engine` is strictly better than `other_engine`, +// where `enterprise_engine` is a search engine created by the +// `SiteSearchSettings` policy, and `other_engine` is a search engine not +// created by Enterprise policy. +bool IsEnterpriseSideSearchEngineBetterThanEngine( + const TemplateURL* enterprise_engine, + const TemplateURL* other_engine) { + // Keyword conflicts between search engines set by policy are handled when the + // policies are processed. At this point, `enterprise_engine` is created by + // the `SiteSearchSettings` policy, `other_engine` should have been created by + // something else, but not via policy. + CHECK_EQ(enterprise_engine->created_by_policy(), + TemplateURLData::CreatedByPolicy::kSiteSearch); + CHECK_EQ(other_engine->created_by_policy(), + TemplateURLData::CreatedByPolicy::kNoPolicy); + + const std::u16string& keyword = enterprise_engine->keyword(); + // Prefer `enterprise_engine` if the `keyword` starts with the "@" symbol. + // Otherwise, prefer `other_engine` if it has been manually edited by the + // user. + return (!keyword.empty() && keyword[0] == u'@') || + other_engine->safe_for_autoreplace(); +} + } // namespace // TemplateURLRef::SearchTermsArgs -------------------------------------------- @@ -1481,10 +1506,23 @@ const TemplateURL* other) const { DCHECK(other); + // Site search engines set by enterprise policy have different priority over + // existing search engines because we don't want to break current workflows + // for power users. + if (this->created_by_policy() == + TemplateURLData::CreatedByPolicy::kSiteSearch) { + return IsEnterpriseSideSearchEngineBetterThanEngine(this, other); + } else if (other->created_by_policy() == + TemplateURLData::CreatedByPolicy::kSiteSearch) { + return IsEnterpriseSideSearchEngineBetterThanEngine(other, this); + } + auto get_sort_key = [](const TemplateURL* engine) { return std::make_tuple( // Policy-created engines always win over non-policy created engines. - engine->created_by_policy(), + // At this point, managed search engine should be created by DSP policy. + engine->created_by_policy() == + TemplateURLData::CreatedByPolicy::kDefaultSearchProvider, // Policy-enforced engines always win over policy-recommended engines. engine->enforced_by_policy(), // The integral value of the type enum is used to sort next.
diff --git a/components/search_engines/template_url_service.cc b/components/search_engines/template_url_service.cc index 71ad47db..db5de36c 100644 --- a/components/search_engines/template_url_service.cc +++ b/components/search_engines/template_url_service.cc
@@ -2302,11 +2302,6 @@ // TODO(b/314162426): Check interaction with DSP not set by policy. // TODO(b/309456406): Override existing SE if keywords starts with "@" and // this is a featured site search entry. - // TODO(b/314359989): Only override user-defined search engines with - // `safe_for_autoreplace` == false. - // TODO(b/314368463): Do not delete search engines with - // `safe_for_autoreplace` == true when overridden by - // policy (both DSP and site search). } void TemplateURLService::EnterpriseSiteSearchChanged( @@ -2704,6 +2699,14 @@ bool TemplateURLService::RemoveDuplicateReplaceableEnginesOf( TemplateURL* candidate) { DCHECK(candidate); + + // Do not replace existing search engines if `candidate` was created by the + // `SiteSearchSettings` policy. + if (candidate->created_by_policy() == + TemplateURLData::CreatedByPolicy::kSiteSearch) { + return false; + } + const std::u16string& keyword = candidate->keyword(); // If there's not at least one conflicting TemplateURL, there's nothing to do.
diff --git a/components/services/app_service/public/cpp/app_storage/app_storage.cc b/components/services/app_service/public/cpp/app_storage/app_storage.cc index 7432c35d..13a879e 100644 --- a/components/services/app_service/public/cpp/app_storage/app_storage.cc +++ b/components/services/app_service/public/cpp/app_storage/app_storage.cc
@@ -237,8 +237,8 @@ } IS_APP_VALUE_CHANGED(selected_locale); + IS_APP_VALUE_CHANGED(extra); - // TODO(crbug.com/1385932): Add other files in the App structure. return false; }
diff --git a/components/services/app_service/public/cpp/app_storage/app_storage_file_handler.cc b/components/services/app_service/public/cpp/app_storage/app_storage_file_handler.cc index e238096..9982e3e1 100644 --- a/components/services/app_service/public/cpp/app_storage/app_storage_file_handler.cc +++ b/components/services/app_service/public/cpp/app_storage/app_storage_file_handler.cc
@@ -59,6 +59,7 @@ constexpr char kDataSizeInBytesKey[] = "data_size_in_bytes"; constexpr char kSupportedLocalesKey[] = "supported_locales"; constexpr char kSelectedLocaleKey[] = "selected_locale"; +constexpr char kExtraKey[] = "extra"; absl::optional<std::string> GetStringValueFromDict( const base::Value::Dict& dict, @@ -109,6 +110,12 @@ } template <> +base::Value GetValue(const AppPtr& app, + absl::optional<base::Value::Dict> App::*field) { + return base::Value(std::move((app.get()->*field).value())); +} + +template <> base::Value GetValue(const AppPtr& app, std::vector<std::string> App::*field) { base::Value::List items; for (const auto& item : app.get()->*field) { @@ -297,6 +304,7 @@ SetKey(app, &App::data_size_in_bytes, kDataSizeInBytesKey, dict); SetKey(app, &App::supported_locales, kSupportedLocalesKey, dict); SetKey(app, &App::selected_locale, kSelectedLocaleKey, dict); + SetKey(app, &App::extra, kExtraKey, dict); // TODO(crbug.com/1385932): Add other files in the App structure. app_info_dict.Set(app->app_id, std::move(dict)); @@ -417,6 +425,11 @@ GetListFromKey(value, &App::supported_locales, kSupportedLocalesKey, app); app->selected_locale = GetStringValueFromDict(*value, kSelectedLocaleKey); + base::Value::Dict* extra = value->FindDict(kExtraKey); + if (extra) { + app->extra = std::move(*extra); + } + // TODO(crbug.com/1385932): Add other files in the App structure. app_info->apps.push_back(std::move(app)); app_info->app_types.insert(static_cast<AppType>(app_type.value()));
diff --git a/components/services/app_service/public/cpp/app_storage/app_storage_file_handler_unittest.cc b/components/services/app_service/public/cpp/app_storage/app_storage_file_handler_unittest.cc index add5f9d6..860b69a8 100644 --- a/components/services/app_service/public/cpp/app_storage/app_storage_file_handler_unittest.cc +++ b/components/services/app_service/public/cpp/app_storage/app_storage_file_handler_unittest.cc
@@ -153,9 +153,11 @@ app2->data_size_in_bytes = ULLONG_MAX - 1; app2->supported_locales = {"a", "b", "c"}; app2->selected_locale = "c"; + app2->SetExtraField("vm_name", "vm_name_value"); + app2->SetExtraField("scales", true); + app2->SetExtraField("number", 100); apps.push_back(std::move(app2)); - // TODO(crbug.com/1385932): Add other files in the App structure. return apps; }
diff --git a/components/services/app_service/public/cpp/app_storage/app_storage_unittest.cc b/components/services/app_service/public/cpp/app_storage/app_storage_unittest.cc index fa60025..ab12dbf 100644 --- a/components/services/app_service/public/cpp/app_storage/app_storage_unittest.cc +++ b/components/services/app_service/public/cpp/app_storage/app_storage_unittest.cc
@@ -209,6 +209,9 @@ app2->data_size_in_bytes = 2048; app2->supported_locales = {"a", "b", "c"}; app2->selected_locale = "a"; + app2->SetExtraField("vm_name", "vm_name_value"); + app2->SetExtraField("scales", true); + app2->SetExtraField("number", 100); apps.push_back(std::move(app2)); @@ -276,6 +279,15 @@ /*should_notify_initialized=*/false); } + void ModifyExtra() { + AppPtr app = std::make_unique<App>(kAppType1, kAppId1); + app->SetExtraField("vm_name", "vm_name_value"); + std::vector<AppPtr> apps; + apps.push_back(std::move(app)); + app_registry_cache_.OnApps(std::move(apps), kAppType1, + /*should_notify_initialized=*/false); + } + void RemoveOneApp(AppType app_type, const std::string& app_id) { AppPtr app = std::make_unique<App>(app_type, app_id); app->readiness = Readiness::kUninstalledByUser; @@ -461,6 +473,11 @@ apps[0]->intent_filters.push_back(std::move(intent_filter)); VerifySavedApps(apps); + ModifyExtra(); + app_storage()->WaitForSaveFinished(/*expect_app_count=*/2); + apps[0]->SetExtraField("vm_name", "vm_name_value"); + VerifySavedApps(apps); + // Verify `apps` are not changed. AppPtr app = std::make_unique<App>(kAppType1, kAppId1); // Set `paused` as true to call `OnAppUpdate`.
diff --git a/components/services/app_service/public/cpp/app_types.cc b/components/services/app_service/public/cpp/app_types.cc index d92746b..fd6ca2a 100644 --- a/components/services/app_service/public/cpp/app_types.cc +++ b/components/services/app_service/public/cpp/app_types.cc
@@ -156,6 +156,10 @@ return false; } + if (this->extra != other.extra) { + return false; + } + return true; } @@ -211,6 +215,10 @@ app->supported_locales = supported_locales; app->selected_locale = selected_locale; + if (extra.has_value()) { + app->extra = extra->Clone(); + } + return app; }
diff --git a/components/services/app_service/public/cpp/app_types.h b/components/services/app_service/public/cpp/app_types.h index 12486f7..bdd07c0 100644 --- a/components/services/app_service/public/cpp/app_types.h +++ b/components/services/app_service/public/cpp/app_types.h
@@ -11,6 +11,7 @@ #include "base/component_export.h" #include "base/time/time.h" +#include "base/values.h" #include "components/services/app_service/public/cpp/icon_types.h" #include "components/services/app_service/public/cpp/intent_filter.h" #include "components/services/app_service/public/cpp/macros.h" @@ -137,6 +138,19 @@ std::unique_ptr<App> Clone() const; + // Adds a new field for `extra`. The type `T` can be any type, e.g. int, + // double, string, base::Value::Dict, base::Value::List, base::Value, etc. The + // value is saved in base::Value::Dict `extra`. If the type `T` can't be + // converted to base::Value, an explicit convert function can be added to + // convert `value` to base::Value. + template <typename T> + void SetExtraField(const std::string& field_name, T&& value) { + if (!extra.has_value()) { + extra = base::Value::Dict(); + } + extra->Set(field_name, value); + } + AppType app_type; std::string app_id; @@ -238,6 +252,12 @@ // is not necessarily part of `supported_locales`. absl::optional<std::string> selected_locale; + // The extra information used by the app platform(e.g. ARC, GuestOS) for an + // app. `extra` needs to be modified as a whole, and we can't only modify part + // of `extra`. AppService doesn't use the fields saved in `extra`. App + // publishers modify the content saved in `extra`. + absl::optional<base::Value::Dict> extra; + // When adding new fields to the App type, the `Clone` function, the // `operator==` function, and the `AppUpdate` class should also be updated. If // the new fields should be saved, below functions should be updated:
diff --git a/components/services/app_service/public/cpp/app_types_unittest.cc b/components/services/app_service/public/cpp/app_types_unittest.cc index ef38ae5..a805b01 100644 --- a/components/services/app_service/public/cpp/app_types_unittest.cc +++ b/components/services/app_service/public/cpp/app_types_unittest.cc
@@ -46,6 +46,15 @@ return {100, 200}; } +template <> +std::pair<base::Value::Dict, base::Value::Dict> TestValue() { + base::Value::Dict dict1; + dict1.Set("vm_name", "vm_name_value"); + base::Value::Dict dict2; + dict2.Set("container_name", "container_name_value"); + return {std::move(dict1), std::move(dict2)}; +} + bool IsEqual(AppPtr app1, AppPtr app2) { std::vector<AppPtr> apps1; apps1.push_back(std::move(app1)); @@ -400,4 +409,31 @@ VerifyOptionalValue(&App::data_size_in_bytes); } +TEST_F(AppTypesTest, VerifyAppsIsEqualForSupportedLocales) { + // Verify the app is equal with the same `supported_locales`. + { + AppPtr app1 = std::make_unique<App>(kAppType, kAppId); + app1->supported_locales = {"C"}; + AppPtr app2 = app1->Clone(); + EXPECT_TRUE(IsEqual(std::move(app1), std::move(app2))); + } + + // Verify the app is not equal with different `supported_locales`. + { + AppPtr app1 = std::make_unique<App>(kAppType, kAppId); + AppPtr app2 = app1->Clone(); + app1->supported_locales = {"C"}; + app2->supported_locales = {"B"}; + EXPECT_FALSE(IsEqual(std::move(app1), std::move(app2))); + } +} + +TEST_F(AppTypesTest, VerifyAppsIsEqualForSelectedLocale) { + VerifyOptionalValue(&App::selected_locale); +} + +TEST_F(AppTypesTest, VerifyAppsIsEqualForExtra) { + VerifyOptionalValue(&App::extra); +} + } // namespace apps
diff --git a/components/services/app_service/public/cpp/app_update.cc b/components/services/app_service/public/cpp/app_update.cc index 6dc995fb..e617376 100644 --- a/components/services/app_service/public/cpp/app_update.cc +++ b/components/services/app_service/public/cpp/app_update.cc
@@ -187,6 +187,10 @@ } SET_OPTIONAL_VALUE(selected_locale); + if (delta->extra.has_value()) { + state->extra = delta->extra->Clone(); + } + // When adding new fields to the App type, this function should also be // updated. @@ -247,7 +251,8 @@ update.ResizeLockedChanged() || update.WindowModeChanged() || update.RunOnOsLoginChanged() || update.AllowCloseChanged() || update.AppSizeInBytesChanged() || update.DataSizeInBytesChanged() || - update.SupportedLocalesChanged() || update.SelectedLocaleChanged(); + update.SupportedLocalesChanged() || update.SelectedLocaleChanged() || + update.ExtraChanged(); } AppUpdate::AppUpdate(const App* state, @@ -592,6 +597,20 @@ bool AppUpdate::SelectedLocaleChanged() const { RETURN_OPTIONAL_VALUE_CHANGED(selected_locale)} +absl::optional<base::Value::Dict> AppUpdate::Extra() const { + if (delta_ && delta_->extra.has_value()) { + return delta_->extra->Clone(); + } + if (state_ && state_->extra.has_value()) { + return state_->extra->Clone(); + } + return absl::nullopt; +} + +bool AppUpdate::ExtraChanged() const { + RETURN_OPTIONAL_VALUE_CHANGED(extra); +} + std::ostream& operator<<(std::ostream& out, const AppUpdate& app) { out << "AppType: " << EnumToString(app.AppType()) << std::endl; @@ -662,6 +681,9 @@ << (app.SelectedLocale().has_value() ? app.SelectedLocale().value() : "No selected_locale") << std::endl; + out << "Extra: " + << (app.Extra().has_value() ? app.Extra()->DebugString() : "No Extra") + << std::endl; return out; }
diff --git a/components/services/app_service/public/cpp/app_update.h b/components/services/app_service/public/cpp/app_update.h index e4890af..3829563 100644 --- a/components/services/app_service/public/cpp/app_update.h +++ b/components/services/app_service/public/cpp/app_update.h
@@ -209,6 +209,9 @@ absl::optional<std::string> SelectedLocale() const; bool SelectedLocaleChanged() const; + absl::optional<base::Value::Dict> Extra() const; + bool ExtraChanged() const; + const App* State() const { return state_.get(); } const App* Delta() const { return delta_.get(); }
diff --git a/components/services/app_service/public/cpp/app_update_unittest.cc b/components/services/app_service/public/cpp/app_update_unittest.cc index 109cf7c..8a1cc24 100644 --- a/components/services/app_service/public/cpp/app_update_unittest.cc +++ b/components/services/app_service/public/cpp/app_update_unittest.cc
@@ -142,6 +142,9 @@ absl::optional<std::string> expect_selected_locale_; bool expect_selected_locale_changed_; + absl::optional<base::Value::Dict> expect_extra_; + bool expect_extra_changed_; + void ExpectNoChange() { expect_changed_ = false; expect_readiness_changed_ = false; @@ -1229,6 +1232,34 @@ ExpectNoChange(); CheckExpects(u); } + + // Extra tests. + + if (state) { + base::Value::Dict dict; + dict.Set("vm_name", "vm_name_value"); + state->SetExtraField("vm_name", "vm_name_value"); + expect_extra_ = std::move(dict); + expect_extra_changed_ = false; + CheckExpects(u); + } + + if (delta) { + base::Value::Dict dict; + dict.Set("container_name", "container_name_value"); + delta->SetExtraField("container_name", "container_name_value"); + expect_extra_ = std::move(dict); + expect_extra_changed_ = true; + expect_changed_ = true; + CheckExpects(u); + } + + if (state) { + apps::AppUpdate::Merge(state, delta); + EXPECT_EQ(expect_extra_, state->extra); + ExpectNoChange(); + CheckExpects(u); + } } };
diff --git a/components/shared_highlighting/core/common/shared_highlighting_features.cc b/components/shared_highlighting/core/common/shared_highlighting_features.cc index 71d1ac50..c0a9fed 100644 --- a/components/shared_highlighting/core/common/shared_highlighting_features.cc +++ b/components/shared_highlighting/core/common/shared_highlighting_features.cc
@@ -9,12 +9,6 @@ namespace shared_highlighting { -BASE_FEATURE(kPreemptiveLinkToTextGeneration, - "PreemptiveLinkToTextGeneration", - base::FEATURE_ENABLED_BY_DEFAULT); -constexpr base::FeatureParam<int> kPreemptiveLinkGenTimeoutLengthMs{ - &kPreemptiveLinkToTextGeneration, "TimeoutLengthMs", 500}; - #if BUILDFLAG(IS_IOS) BASE_FEATURE(kSharedHighlightingAmp, "SharedHighlightingAmp", @@ -30,7 +24,11 @@ base::FEATURE_DISABLED_BY_DEFAULT); int GetPreemptiveLinkGenTimeoutLengthMs() { - return kPreemptiveLinkGenTimeoutLengthMs.Get(); +#if BUILDFLAG(IS_ANDROID) + return 100; +#else + return 500; +#endif } } // namespace shared_highlighting
diff --git a/components/user_education/views/help_bubble_view.cc b/components/user_education/views/help_bubble_view.cc index afb1155e..f8661be2 100644 --- a/components/user_education/views/help_bubble_view.cc +++ b/components/user_education/views/help_bubble_view.cc
@@ -142,7 +142,7 @@ ink_drop->SetHighlightOpacity(absl::nullopt); } else { // Prominent style gives a button hover highlight. - SetProminent(true); + SetStyle(ui::ButtonStyle::kProminent); // Focus ring rendering varies significantly between pre- and post-refresh // Chrome. The pre-refresh tactic of setting the focus color to background // is actually a hack; the post-refresh approach is more "correct".
diff --git a/components/viz/service/display/overlay_candidate_factory.cc b/components/viz/service/display/overlay_candidate_factory.cc index 9e5332be..3b6047a 100644 --- a/components/viz/service/display/overlay_candidate_factory.cc +++ b/components/viz/service/display/overlay_candidate_factory.cc
@@ -112,32 +112,11 @@ // Returns true if the overlay candidate bounds rect overlap with at least one // of the rounded corners bounding rects. -// -// TODO(crbug.com/1462171): This method shares some logic with -// DirectRenderer::ShouldApplyRoundedCorner(). Try to move it -// to a shared location. bool ShouldApplyRoundedCorner(OverlayCandidate& candidate, - const SharedQuadState* sqs) { - const gfx::MaskFilterInfo& mask_filter_info = sqs->mask_filter_info; - if (!mask_filter_info.HasRoundedCorners()) { - return false; - } - - const gfx::RRectF& rounded_corner_bounds = - mask_filter_info.rounded_corner_bounds(); - + const DrawQuad* quad) { const gfx::RectF target_rect = OverlayCandidate::DisplayRectInTargetSpace(candidate); - - const gfx::RRectF::Corner corners[] = { - gfx::RRectF::Corner::kUpperLeft, gfx::RRectF::Corner::kUpperRight, - gfx::RRectF::Corner::kLowerRight, gfx::RRectF::Corner::kLowerLeft}; - for (auto c : corners) { - if (rounded_corner_bounds.CornerBoundingRect(c).Intersects(target_rect)) { - return true; - } - } - return false; + return QuadRoundedCornersBoundsIntersects(quad, target_rect); } } // namespace @@ -215,7 +194,7 @@ // TODO(https://crbug.com/1462171): Consider moving this code to // FromDrawQuadResource() that covers all of delegated compositing. if (context_.disable_wire_size_optimization || - ShouldApplyRoundedCorner(candidate, sqs)) { + ShouldApplyRoundedCorner(candidate, quad)) { if (!context_.supports_mask_filter) { return CandidateStatus::kFailMaskFilterNotSupported; }
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc index 1ce8b65..dcdd2308e 100644 --- a/components/viz/service/display/skia_renderer.cc +++ b/components/viz/service/display/skia_renderer.cc
@@ -875,7 +875,11 @@ if (params->draw_region) { canvas->save(); - canvas->concat(bypass_geometry->transform); + if (bypass_geometry) { + // If there's a bypass geometry, the draw_region is relative to that + // coordinate space. + canvas->concat(bypass_geometry->transform); + } canvas->clipPath(params->draw_region_in_path(), SkClipOp::kDifference, aa); canvas->clear(SK_ColorTRANSPARENT); canvas->restore();
diff --git a/components/viz/service/frame_sinks/frame_sink_manager_impl.cc b/components/viz/service/frame_sinks/frame_sink_manager_impl.cc index 2baac0c8..0408df91 100644 --- a/components/viz/service/frame_sinks/frame_sink_manager_impl.cc +++ b/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
@@ -13,6 +13,7 @@ #include "base/check_op.h" #include "base/containers/contains.h" #include "base/containers/queue.h" +#include "base/debug/alias.h" #include "base/feature_list.h" #include "base/functional/bind.h" #include "base/metrics/histogram_functions.h" @@ -212,7 +213,11 @@ mojo::PendingRemote<mojom::FrameSinkBundleClient> client) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); if (base::Contains(bundle_map_, bundle_id)) { + uint32_t client_id = bundle_id.client_id(); + uint32_t bundle_id_value = bundle_id.bundle_id(); receiver_.ReportBadMessage("Duplicate FrameSinkBundle ID"); + base::debug::Alias(&client_id); + base::debug::Alias(&bundle_id_value); return; }
diff --git a/components/webauthn/android/java/src/org/chromium/components/webauthn/Fido2ApiTestHelper.java b/components/webauthn/android/java/src/org/chromium/components/webauthn/Fido2ApiTestHelper.java index 4a4d7df..2af50f6 100644 --- a/components/webauthn/android/java/src/org/chromium/components/webauthn/Fido2ApiTestHelper.java +++ b/components/webauthn/android/java/src/org/chromium/components/webauthn/Fido2ApiTestHelper.java
@@ -479,6 +479,7 @@ throws Exception { PublicKeyCredentialCreationOptions options = new PublicKeyCredentialCreationOptions(); options.challenge = "climb a mountain".getBytes("UTF8"); + options.hints = new int[0]; options.relyingParty = new PublicKeyCredentialRpEntity(); options.relyingParty.id = "subdomain.example.test"; @@ -536,6 +537,7 @@ options.timeout = new TimeDelta(); options.timeout.microseconds = TimeUnit.MILLISECONDS.toMicros(TIMEOUT_MS); options.relyingPartyId = "subdomain.example.test"; + options.hints = new int[0]; PublicKeyCredentialDescriptor descriptor = new PublicKeyCredentialDescriptor(); descriptor.type = 0;
diff --git a/components/webauthn/json/value_conversions_unittest.cc b/components/webauthn/json/value_conversions_unittest.cc index 0ad8918..6d398edfe 100644 --- a/components/webauthn/json/value_conversions_unittest.cc +++ b/components/webauthn/json/value_conversions_unittest.cc
@@ -114,6 +114,7 @@ device::AuthenticatorAttachment::kPlatform, device::ResidentKeyRequirement::kRequired, device::UserVerificationRequirement::kRequired), + /*hints=*/std::vector<blink::mojom::Hint>(), device::AttestationConveyancePreference::kDirect, /*hmac_create_secret=*/true, /*prf_enable=*/true, @@ -155,7 +156,9 @@ // Exercise all supported fields. auto options = PublicKeyCredentialRequestOptions::New( /*is_conditional=*/false, kChallenge, kTimeout, kRpId, - GetCredentialList(), device::UserVerificationRequirement::kRequired, + GetCredentialList(), + /*hints=*/std::vector<blink::mojom::Hint>(), + device::UserVerificationRequirement::kRequired, AuthenticationExtensionsClientInputs::New( kAppId, std::vector<device::CableDiscoveryData>{
diff --git a/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc b/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc index 0c0f1a7..3d3bf02 100644 --- a/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc +++ b/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc
@@ -2735,6 +2735,60 @@ } IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest, + MoveEndpointByUnitLineInertSpan) { + // Spans need to be in the same line: see https://crbug.com/1511390. + LoadInitialAccessibilityTreeFromHtml( + R"HTML(<!DOCTYPE html> + <div> + <div>first line</div> + <span id="span1">go </span><span inert>inert1</span><span inert>inert2</span><span>blue</span> + <div>last line</div> + </div>)HTML"); + BrowserAccessibility* start_node = + FindNode(ax::mojom::Role::kStaticText, "first line"); + ASSERT_NE(nullptr, start_node); + + BrowserAccessibility* end_node = + FindNode(ax::mojom::Role::kStaticText, "last line"); + ASSERT_NE(nullptr, start_node); + + // Navigating forward to the next line. + ComPtr<ITextRangeProvider> text_range_provider; + GetTextRangeProviderFromTextNode(*start_node, &text_range_provider); + ASSERT_NE(nullptr, text_range_provider.Get()); + EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"first line"); + + EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(text_range_provider, + TextPatternRangeEndpoint_End, TextUnit_Line, + /*count*/ 1, + /*expected_text*/ L"first line\ngo blue", + /*expected_count*/ 1); + + EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( + text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Line, + /*count*/ 1, + /*expected_text*/ L"go blue", + /*expected_count*/ 1); + + // Navigating to the previous line. + GetTextRangeProviderFromTextNode(*end_node, &text_range_provider); + ASSERT_NE(nullptr, text_range_provider.Get()); + EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"last line"); + + EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT( + text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Line, + /*count*/ -1, + /*expected_text*/ L"go blue\nlast line", + /*expected_count*/ -1); + + EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(text_range_provider, + TextPatternRangeEndpoint_End, TextUnit_Line, + /*count*/ -1, + /*expected_text*/ L"go blue", + /*expected_count*/ -1); +} + +IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest, IFrameTraversal) { LoadInitialAccessibilityTreeFromUrl(embedded_test_server()->GetURL( "/accessibility/html/iframe-cross-process.html"));
diff --git a/content/browser/android/gesture_listener_manager.cc b/content/browser/android/gesture_listener_manager.cc index a3e64c0..2a03721 100644 --- a/content/browser/android/gesture_listener_manager.cc +++ b/content/browser/android/gesture_listener_manager.cc
@@ -12,7 +12,6 @@ #include "content/public/browser/navigation_handle.h" #include "content/public/browser/web_contents_observer.h" #include "third_party/blink/public/common/input/web_input_event.h" -#include "third_party/blink/public/mojom/input/input_handler.mojom-forward.h" #include "ui/events/android/gesture_event_type.h" #include "ui/events/blink/did_overscroll_params.h" #include "ui/gfx/geometry/size_f.h" @@ -154,8 +153,7 @@ void GestureListenerManager::GestureEventAck( const blink::WebGestureEvent& event, - blink::mojom::InputEventResultState ack_result, - blink::mojom::ScrollResultDataPtr scroll_result_data) { + blink::mojom::InputEventResultState ack_result) { // This is called to fix crash happening while WebContents is being // destroyed. See https://crbug.com/803244#c20 if (web_contents_->IsBeingDestroyed()) @@ -176,14 +174,9 @@ env, j_obj, /*isDirectionUp*/ event.data.scroll_begin.delta_y_hint > 0); return; } - float x = -1.f, y = -1.f; - if (scroll_result_data && scroll_result_data->root_scroll_offset) { - x = scroll_result_data->root_scroll_offset->x(); - y = scroll_result_data->root_scroll_offset->y(); - } Java_GestureListenerManagerImpl_onEventAck( - env, j_obj, static_cast<int>(event.GetType()), consumed, x, y); + env, j_obj, static_cast<int>(event.GetType()), consumed); } void GestureListenerManager::DidStopFlinging() {
diff --git a/content/browser/android/gesture_listener_manager.h b/content/browser/android/gesture_listener_manager.h index 4840410..746813e 100644 --- a/content/browser/android/gesture_listener_manager.h +++ b/content/browser/android/gesture_listener_manager.h
@@ -12,7 +12,6 @@ #include "content/browser/android/render_widget_host_connector.h" #include "content/common/content_export.h" #include "third_party/blink/public/mojom/input/input_event_result.mojom-shared.h" -#include "third_party/blink/public/mojom/input/input_handler.mojom-forward.h" namespace blink { class WebGestureEvent; @@ -60,8 +59,7 @@ } void SetRootScrollOffsetUpdateFrequency(JNIEnv* env, jint frequency); void GestureEventAck(const blink::WebGestureEvent& event, - blink::mojom::InputEventResultState ack_result, - blink::mojom::ScrollResultDataPtr scroll_result_data); + blink::mojom::InputEventResultState ack_result); void DidStopFlinging(); bool FilterInputEvent(const blink::WebInputEvent& event); void DidOverscroll(const ui::DidOverscrollParams& params);
diff --git a/content/browser/devtools/devtools_renderer_channel.cc b/content/browser/devtools/devtools_renderer_channel.cc index e85fc86..4fd3a950 100644 --- a/content/browser/devtools/devtools_renderer_channel.cc +++ b/content/browser/devtools/devtools_renderer_channel.cc
@@ -206,17 +206,19 @@ return; } - DCHECK(context_type == blink::mojom::DevToolsExecutionContextType::kWorklet || - !base::FeatureList::IsEnabled(blink::features::kPlzDedicatedWorker)); + CHECK(context_type == blink::mojom::DevToolsExecutionContextType::kWorklet || + !base::FeatureList::IsEnabled(blink::features::kPlzDedicatedWorker)); if (content::DevToolsAgentHost::GetForId(devtools_worker_token.ToString())) { mojo::ReportBadMessage("Workers should have unique tokens."); return; } auto agent_host = base::MakeRefCounted<WorkerDevToolsAgentHost>( - process_id_, std::move(worker_devtools_agent), std::move(host_receiver), - filtered_url, std::move(name), devtools_worker_token, owner_->GetId(), + process_id_, filtered_url, std::move(name), devtools_worker_token, + owner_->GetId(), base::BindOnce(&DevToolsRendererChannel::ChildTargetDestroyed, weak_factory_.GetWeakPtr())); + agent_host->SetRenderer(process_id_, std::move(worker_devtools_agent), + std::move(host_receiver)); child_targets_.insert(agent_host.get()); if (child_target_created_callback_) child_target_created_callback_.Run(agent_host.get(), waiting_for_debugger);
diff --git a/content/browser/devtools/worker_devtools_agent_host.cc b/content/browser/devtools/worker_devtools_agent_host.cc index be8e38c7..f487c38 100644 --- a/content/browser/devtools/worker_devtools_agent_host.cc +++ b/content/browser/devtools/worker_devtools_agent_host.cc
@@ -31,8 +31,6 @@ WorkerDevToolsAgentHost::WorkerDevToolsAgentHost( int process_id, - mojo::PendingRemote<blink::mojom::DevToolsAgent> agent_remote, - mojo::PendingReceiver<blink::mojom::DevToolsAgentHost> host_receiver, const GURL& url, const std::string& name, const base::UnguessableToken& devtools_worker_token, @@ -54,9 +52,6 @@ // instead. AddRef(); // Self keep-alive while the worker agent is alive. NotifyCreated(); - - if (!base::FeatureList::IsEnabled(blink::features::kPlzDedicatedWorker)) - SetRenderer(process_id, std::move(agent_remote), std::move(host_receiver)); } WorkerDevToolsAgentHost::~WorkerDevToolsAgentHost() = default;
diff --git a/content/browser/devtools/worker_devtools_agent_host.h b/content/browser/devtools/worker_devtools_agent_host.h index e80baf2..431d599 100644 --- a/content/browser/devtools/worker_devtools_agent_host.h +++ b/content/browser/devtools/worker_devtools_agent_host.h
@@ -26,8 +26,6 @@ WorkerDevToolsAgentHost( int process_id, - mojo::PendingRemote<blink::mojom::DevToolsAgent> agent_remote, - mojo::PendingReceiver<blink::mojom::DevToolsAgentHost> host_receiver, const GURL& url, const std::string& name, const base::UnguessableToken& devtools_worker_token,
diff --git a/content/browser/devtools/worker_devtools_manager.cc b/content/browser/devtools/worker_devtools_manager.cc index 7742139..4501133 100644 --- a/content/browser/devtools/worker_devtools_manager.cc +++ b/content/browser/devtools/worker_devtools_manager.cc
@@ -16,7 +16,7 @@ // static WorkerDevToolsManager& WorkerDevToolsManager::GetInstance() { DCHECK_CURRENTLY_ON(BrowserThread::UI); - DCHECK(base::FeatureList::IsEnabled(blink::features::kPlzDedicatedWorker)); + CHECK(base::FeatureList::IsEnabled(blink::features::kPlzDedicatedWorker)); return *base::Singleton<WorkerDevToolsManager>::get(); } @@ -51,9 +51,8 @@ DCHECK(!base::Contains(hosts_, host)); hosts_[host] = base::MakeRefCounted<WorkerDevToolsAgentHost>( - process_id, /*agent_remote=*/mojo::NullRemote(), - /*host_receiver=*/mojo::NullReceiver(), /*url=*/GURL(), /*name=*/"", - host->GetToken().value(), /*parent_id=*/"", + process_id, + /*url=*/GURL(), /*name=*/"", host->GetToken().value(), /*parent_id=*/"", /*destroyed_callback=*/base::DoNothing()); devtools_instrumentation::ThrottleWorkerMainScriptFetch(
diff --git a/content/browser/interest_group/ad_auction_url_loader_interceptor.cc b/content/browser/interest_group/ad_auction_url_loader_interceptor.cc index 1de3b54..943eb007 100644 --- a/content/browser/interest_group/ad_auction_url_loader_interceptor.cc +++ b/content/browser/interest_group/ad_auction_url_loader_interceptor.cc
@@ -40,8 +40,6 @@ // request may arrive before the commit confirmation is received (i.e. // NavigationRequest::DidCommitNavigation()), or after the document is // destroyed. We consider those cases to be ineligible for ad auction headers. - // - // TODO(yaoxia): measure how often this happens. RenderFrameHostImpl* request_initiator_frame = static_cast<RenderFrameHostImpl*>(document_.AsRenderFrameHostIfValid()); if (!request_initiator_frame) {
diff --git a/content/browser/interest_group/interest_group_auction.cc b/content/browser/interest_group/interest_group_auction.cc index 1de8e1c..b987f22 100644 --- a/content/browser/interest_group/interest_group_auction.cc +++ b/content/browser/interest_group/interest_group_auction.cc
@@ -1328,6 +1328,7 @@ bid_state->worklet_handle->GetBidderWorklet()->BeginGenerateBid( auction_worklet::mojom::BidderWorkletNonSharedParams::New( interest_group.name, + interest_group.trusted_bidding_signals_slot_size_mode, interest_group.enable_bidding_signals_prioritization, interest_group.priority_vector, interest_group.execution_mode, interest_group.update_url,
diff --git a/content/browser/renderer_host/accessibility_object_lifetime_win_browsertest.cc b/content/browser/renderer_host/accessibility_object_lifetime_win_browsertest.cc index 0084ed66..1ff4c61 100644 --- a/content/browser/renderer_host/accessibility_object_lifetime_win_browsertest.cc +++ b/content/browser/renderer_host/accessibility_object_lifetime_win_browsertest.cc
@@ -130,6 +130,7 @@ // Verify that the legacy window does not crash when asked for an // accessibility object. legacy_render_widget_host_HWND_->GetOrCreateWindowRootAccessible(false); + legacy_render_widget_host_HWND_ = nullptr; // Remove ourselves as a subclass. ui::HWNDSubclass::RemoveFilterFromAllTargets(this); @@ -139,8 +140,7 @@ } private: - raw_ptr<LegacyRenderWidgetHostHWND, DanglingUntriaged> - legacy_render_widget_host_HWND_; + raw_ptr<LegacyRenderWidgetHostHWND> legacy_render_widget_host_HWND_; }; IN_PROC_BROWSER_TEST_F(AccessibilityObjectLifetimeWinBrowserTest,
diff --git a/content/browser/renderer_host/cross_process_frame_connector.cc b/content/browser/renderer_host/cross_process_frame_connector.cc index ccc4660..a8cd4b7 100644 --- a/content/browser/renderer_host/cross_process_frame_connector.cc +++ b/content/browser/renderer_host/cross_process_frame_connector.cc
@@ -24,7 +24,6 @@ #include "third_party/blink/public/common/frame/frame_visual_properties.h" #include "third_party/blink/public/common/input/web_input_event.h" #include "third_party/blink/public/mojom/frame/intrinsic_sizing_info.mojom.h" -#include "third_party/blink/public/mojom/input/input_handler.mojom-forward.h" #include "ui/base/cursor/cursor.h" #include "ui/gfx/geometry/dip_util.h" @@ -263,8 +262,7 @@ void CrossProcessFrameConnector::ForwardAckedTouchpadZoomEvent( const blink::WebGestureEvent& event, - blink::mojom::InputEventResultState ack_result, - blink::mojom::ScrollResultDataPtr scroll_result_data) { + blink::mojom::InputEventResultState ack_result) { auto* root_view = GetRootRenderWidgetHostView(); if (!root_view) return; @@ -273,8 +271,7 @@ const gfx::PointF root_point = view_->TransformPointToRootCoordSpaceF(event.PositionInWidget()); root_event.SetPositionInWidget(root_point); - root_view->GestureEventAck(root_event, ack_result, - std::move(scroll_result_data)); + root_view->GestureEventAck(root_event, ack_result); } bool CrossProcessFrameConnector::BubbleScrollEvent( @@ -515,14 +512,12 @@ void CrossProcessFrameConnector::DidAckGestureEvent( const blink::WebGestureEvent& event, - blink::mojom::InputEventResultState ack_result, - blink::mojom::ScrollResultDataPtr scroll_result_data) { + blink::mojom::InputEventResultState ack_result) { auto* root_view = GetRootRenderWidgetHostView(); if (!root_view) return; - root_view->ChildDidAckGestureEvent(event, ack_result, - std::move(scroll_result_data)); + root_view->ChildDidAckGestureEvent(event, ack_result); } void CrossProcessFrameConnector::SetVisibilityForChildViews(
diff --git a/content/browser/renderer_host/cross_process_frame_connector.h b/content/browser/renderer_host/cross_process_frame_connector.h index 05ecb60..3c92b89 100644 --- a/content/browser/renderer_host/cross_process_frame_connector.h +++ b/content/browser/renderer_host/cross_process_frame_connector.h
@@ -19,7 +19,6 @@ #include "third_party/blink/public/mojom/frame/lifecycle.mojom.h" #include "third_party/blink/public/mojom/frame/viewport_intersection_state.mojom.h" #include "third_party/blink/public/mojom/input/input_event_result.mojom-shared.h" -#include "third_party/blink/public/mojom/input/input_handler.mojom-forward.h" #include "third_party/blink/public/mojom/input/pointer_lock_result.mojom-shared.h" #include "ui/display/screen_infos.h" #include "ui/gfx/geometry/rect.h" @@ -169,8 +168,7 @@ // for processing. void ForwardAckedTouchpadZoomEvent( const blink::WebGestureEvent& event, - blink::mojom::InputEventResultState ack_result, - blink::mojom::ScrollResultDataPtr scroll_result_data); + blink::mojom::InputEventResultState ack_result); // A gesture scroll sequence that is not consumed by a child must be bubbled // to ancestors who may consume it. @@ -256,8 +254,7 @@ bool has_size() const { return has_size_; } void DidAckGestureEvent(const blink::WebGestureEvent& event, - blink::mojom::InputEventResultState ack_result, - blink::mojom::ScrollResultDataPtr scroll_result_data); + blink::mojom::InputEventResultState ack_result); // Called by RenderWidgetHostViewChildFrame to update the visibility of any // nested child RWHVCFs inside it.
diff --git a/content/browser/renderer_host/input/input_disposition_handler.h b/content/browser/renderer_host/input/input_disposition_handler.h index 7cd807fa..3d6350ce 100644 --- a/content/browser/renderer_host/input/input_disposition_handler.h +++ b/content/browser/renderer_host/input/input_disposition_handler.h
@@ -9,7 +9,6 @@ #include "content/public/common/input/native_web_keyboard_event.h" #include "third_party/blink/public/common/input/web_input_event.h" #include "third_party/blink/public/mojom/input/input_event_result.mojom-shared.h" -#include "third_party/blink/public/mojom/input/input_handler.mojom-forward.h" namespace content { @@ -30,8 +29,7 @@ virtual void OnGestureEventAck( const GestureEventWithLatencyInfo& event, blink::mojom::InputEventResultSource ack_source, - blink::mojom::InputEventResultState ack_result, - blink::mojom::ScrollResultDataPtr scroll_result_data) = 0; + blink::mojom::InputEventResultState ack_result) = 0; }; } // namespace content
diff --git a/content/browser/renderer_host/input/input_router_impl.cc b/content/browser/renderer_host/input/input_router_impl.cc index bca1577..9f0a2ae 100644 --- a/content/browser/renderer_host/input/input_router_impl.cc +++ b/content/browser/renderer_host/input/input_router_impl.cc
@@ -25,7 +25,6 @@ #include "services/tracing/public/cpp/perfetto/flow_event_utils.h" #include "third_party/blink/public/common/input/web_coalesced_input_event.h" #include "third_party/blink/public/mojom/input/input_event_result.mojom-shared.h" -#include "third_party/blink/public/mojom/input/input_handler.mojom-forward.h" #include "third_party/blink/public/mojom/input/input_handler.mojom-shared.h" #include "third_party/blink/public/mojom/input/touch_event.mojom.h" #include "ui/events/blink/blink_event_util.h" @@ -145,8 +144,7 @@ TRACE_EVENT_INSTANT0("input", "FilteredForFling", TRACE_EVENT_SCOPE_THREAD); disposition_handler_->OnGestureEventAck( gesture_event, blink::mojom::InputEventResultSource::kBrowser, - blink::mojom::InputEventResultState::kConsumed, - /*scroll_result_data=*/nullptr); + blink::mojom::InputEventResultState::kConsumed); return; } @@ -173,8 +171,7 @@ TRACE_EVENT_SCOPE_THREAD); disposition_handler_->OnGestureEventAck( gesture_event, blink::mojom::InputEventResultSource::kBrowser, - blink::mojom::InputEventResultState::kConsumed, - /*scroll_result_data=*/nullptr); + blink::mojom::InputEventResultState::kConsumed); return; } @@ -183,8 +180,7 @@ if (HandleGestureScrollForStylusWriting(gesture_event.event)) { disposition_handler_->OnGestureEventAck( gesture_event, blink::mojom::InputEventResultSource::kBrowser, - blink::mojom::InputEventResultState::kConsumed, - /*scroll_result_data=*/nullptr); + blink::mojom::InputEventResultState::kConsumed); return; } @@ -218,8 +214,7 @@ TRACE_EVENT_SCOPE_THREAD); disposition_handler_->OnGestureEventAck( gesture_event, blink::mojom::InputEventResultSource::kBrowser, - blink::mojom::InputEventResultState::kConsumed, - /*scroll_result_data=*/nullptr); + blink::mojom::InputEventResultState::kConsumed); } } @@ -518,11 +513,9 @@ void InputRouterImpl::OnGestureEventAck( const GestureEventWithLatencyInfo& event, blink::mojom::InputEventResultSource ack_source, - blink::mojom::InputEventResultState ack_result, - blink::mojom::ScrollResultDataPtr scroll_result_data) { + blink::mojom::InputEventResultState ack_result) { touch_event_queue_.OnGestureEventAck(event, ack_result); - disposition_handler_->OnGestureEventAck(event, ack_source, ack_result, - std::move(scroll_result_data)); + disposition_handler_->OnGestureEventAck(event, ack_source, ack_result); } void InputRouterImpl::SendGeneratedWheelEvent( @@ -576,8 +569,7 @@ const GestureEventWithLatencyInfo& event, blink::mojom::InputEventResultSource ack_source, blink::mojom::InputEventResultState ack_result) { - OnGestureEventAck(event, ack_source, ack_result, - /*scroll_result_data=*/nullptr); + OnGestureEventAck(event, ack_source, ack_result); } bool InputRouterImpl::IsWheelScrollInProgress() { @@ -615,8 +607,7 @@ TRACE_EVENT_SCOPE_THREAD); if (filtered_state != blink::mojom::InputEventResultState::kUnknown) { std::move(callback).Run(blink::mojom::InputEventResultSource::kBrowser, - latency_info, filtered_state, nullptr, nullptr, - /*scroll_result_data=*/nullptr); + latency_info, filtered_state, nullptr, nullptr); } return; } @@ -635,8 +626,7 @@ const ui::LatencyInfo& latency, blink::mojom::InputEventResultState state, blink::mojom::DidOverscrollParamsPtr overscroll, - blink::mojom::TouchActionOptionalPtr touch_action, - blink::mojom::ScrollResultDataPtr scroll_result_data) { + blink::mojom::TouchActionOptionalPtr touch_action) { // Filter source to ensure only valid values are sent from the // renderer. if (source == blink::mojom::InputEventResultSource::kBrowser) { @@ -645,9 +635,9 @@ return; } - std::move(callback).Run( - source, latency, state, std::move(overscroll), - std::move(touch_action), std::move(scroll_result_data)); + std::move(callback).Run(source, latency, state, + std::move(overscroll), + std::move(touch_action)); }, std::move(callback), weak_this_); client_->GetWidgetInputHandler()->DispatchEvent( @@ -657,10 +647,9 @@ TRACE_EVENT_SCOPE_THREAD); client_->GetWidgetInputHandler()->DispatchNonBlockingEvent( std::move(event)); - std::move(callback).Run(blink::mojom::InputEventResultSource::kBrowser, - latency_info, - blink::mojom::InputEventResultState::kIgnored, - nullptr, nullptr, /*scroll_result_data=*/nullptr); + std::move(callback).Run( + blink::mojom::InputEventResultSource::kBrowser, latency_info, + blink::mojom::InputEventResultState::kIgnored, nullptr, nullptr); } // Ensure that the associated PendingTask for the WidgetInputHandler is // recorded when tasking long-running chrome tasks. This is needed to @@ -675,8 +664,7 @@ const ui::LatencyInfo& latency, blink::mojom::InputEventResultState state, blink::mojom::DidOverscrollParamsPtr overscroll, - blink::mojom::TouchActionOptionalPtr touch_action, - blink::mojom::ScrollResultDataPtr scroll_result_data) { + blink::mojom::TouchActionOptionalPtr touch_action) { TRACE_EVENT2("input", "InputRouterImpl::KeyboardEventHandled", "type", WebInputEvent::GetName(event.event.GetType()), "ack", InputEventResultStateToString(state)); @@ -699,8 +687,7 @@ const ui::LatencyInfo& latency, blink::mojom::InputEventResultState state, blink::mojom::DidOverscrollParamsPtr overscroll, - blink::mojom::TouchActionOptionalPtr touch_action, - blink::mojom::ScrollResultDataPtr scroll_result_data) { + blink::mojom::TouchActionOptionalPtr touch_action) { TRACE_EVENT2("input", "InputRouterImpl::MouseEventHandled", "type", WebInputEvent::GetName(event.event.GetType()), "ack", InputEventResultStateToString(state)); @@ -717,8 +704,7 @@ const ui::LatencyInfo& latency, blink::mojom::InputEventResultState state, blink::mojom::DidOverscrollParamsPtr overscroll, - blink::mojom::TouchActionOptionalPtr touch_action, - blink::mojom::ScrollResultDataPtr scroll_result_data) { + blink::mojom::TouchActionOptionalPtr touch_action) { TRACE_EVENT2("input", "InputRouterImpl::TouchEventHandled", "type", WebInputEvent::GetName(touch_event.event.GetType()), "ack", InputEventResultStateToString(state)); @@ -749,8 +735,7 @@ const ui::LatencyInfo& latency, blink::mojom::InputEventResultState state, blink::mojom::DidOverscrollParamsPtr overscroll, - blink::mojom::TouchActionOptionalPtr touch_action, - blink::mojom::ScrollResultDataPtr scroll_result_data) { + blink::mojom::TouchActionOptionalPtr touch_action) { TRACE_EVENT2("input", "InputRouterImpl::GestureEventHandled", "type", WebInputEvent::GetName(gesture_event.event.GetType()), "ack", InputEventResultStateToString(state)); @@ -764,9 +749,8 @@ } // |gesture_event_queue_| will forward to OnGestureEventAck when appropriate. - gesture_event_queue_.ProcessGestureAck(source, state, - gesture_event.event.GetType(), latency, - std::move(scroll_result_data)); + gesture_event_queue_.ProcessGestureAck( + source, state, gesture_event.event.GetType(), latency); } void InputRouterImpl::MouseWheelEventHandled( @@ -776,8 +760,7 @@ const ui::LatencyInfo& latency, blink::mojom::InputEventResultState state, blink::mojom::DidOverscrollParamsPtr overscroll, - blink::mojom::TouchActionOptionalPtr touch_action, - blink::mojom::ScrollResultDataPtr scroll_result_data) { + blink::mojom::TouchActionOptionalPtr touch_action) { TRACE_EVENT2("input", "InputRouterImpl::MouseWheelEventHandled", "type", WebInputEvent::GetName(event.event.GetType()), "ack", InputEventResultStateToString(state));
diff --git a/content/browser/renderer_host/input/input_router_impl.h b/content/browser/renderer_host/input/input_router_impl.h index a32ba90..a940ab44 100644 --- a/content/browser/renderer_host/input/input_router_impl.h +++ b/content/browser/renderer_host/input/input_router_impl.h
@@ -164,8 +164,7 @@ void OnGestureEventAck( const GestureEventWithLatencyInfo& event, blink::mojom::InputEventResultSource ack_source, - blink::mojom::InputEventResultState ack_result, - blink::mojom::ScrollResultDataPtr scroll_result_data) override; + blink::mojom::InputEventResultState ack_result) override; // FlingControllerEventSenderClient void SendGeneratedWheelEvent( @@ -206,38 +205,32 @@ const ui::LatencyInfo& latency_info, blink::mojom::WidgetInputHandler::DispatchEventCallback callback); - void KeyboardEventHandled( - const NativeWebKeyboardEventWithLatencyInfo& event, - KeyboardEventCallback event_result_callback, - blink::mojom::InputEventResultSource source, - const ui::LatencyInfo& latency, - blink::mojom::InputEventResultState state, - blink::mojom::DidOverscrollParamsPtr overscroll, - blink::mojom::TouchActionOptionalPtr touch_action, - blink::mojom::ScrollResultDataPtr scroll_result_data); + void KeyboardEventHandled(const NativeWebKeyboardEventWithLatencyInfo& event, + KeyboardEventCallback event_result_callback, + blink::mojom::InputEventResultSource source, + const ui::LatencyInfo& latency, + blink::mojom::InputEventResultState state, + blink::mojom::DidOverscrollParamsPtr overscroll, + blink::mojom::TouchActionOptionalPtr touch_action); void MouseEventHandled(const MouseEventWithLatencyInfo& event, MouseEventCallback event_result_callback, blink::mojom::InputEventResultSource source, const ui::LatencyInfo& latency, blink::mojom::InputEventResultState state, blink::mojom::DidOverscrollParamsPtr overscroll, - blink::mojom::TouchActionOptionalPtr touch_action, - blink::mojom::ScrollResultDataPtr scroll_result_data); + blink::mojom::TouchActionOptionalPtr touch_action); void TouchEventHandled(const TouchEventWithLatencyInfo& touch_event, blink::mojom::InputEventResultSource source, const ui::LatencyInfo& latency, blink::mojom::InputEventResultState state, blink::mojom::DidOverscrollParamsPtr overscroll, - blink::mojom::TouchActionOptionalPtr touch_action, - blink::mojom::ScrollResultDataPtr scroll_result_data); - void GestureEventHandled( - const GestureEventWithLatencyInfo& gesture_event, - blink::mojom::InputEventResultSource source, - const ui::LatencyInfo& latency, - blink::mojom::InputEventResultState state, - blink::mojom::DidOverscrollParamsPtr overscroll, - blink::mojom::TouchActionOptionalPtr touch_action, - blink::mojom::ScrollResultDataPtr scroll_result_data); + blink::mojom::TouchActionOptionalPtr touch_action); + void GestureEventHandled(const GestureEventWithLatencyInfo& gesture_event, + blink::mojom::InputEventResultSource source, + const ui::LatencyInfo& latency, + blink::mojom::InputEventResultState state, + blink::mojom::DidOverscrollParamsPtr overscroll, + blink::mojom::TouchActionOptionalPtr touch_action); void MouseWheelEventHandled( const MouseWheelEventWithLatencyInfo& event, MouseWheelEventQueueClient::MouseWheelEventHandledCallback callback, @@ -245,8 +238,7 @@ const ui::LatencyInfo& latency, blink::mojom::InputEventResultState state, blink::mojom::DidOverscrollParamsPtr overscroll, - blink::mojom::TouchActionOptionalPtr touch_action, - blink::mojom::ScrollResultDataPtr scroll_result_data); + blink::mojom::TouchActionOptionalPtr touch_action); // Called when a touch timeout-affecting bit has changed, in turn toggling the // touch ack timeout feature of the |touch_event_queue_| as appropriate. Input
diff --git a/content/browser/renderer_host/input/input_router_impl_unittest.cc b/content/browser/renderer_host/input/input_router_impl_unittest.cc index d182f014..ff4c81f4 100644 --- a/content/browser/renderer_host/input/input_router_impl_unittest.cc +++ b/content/browser/renderer_host/input/input_router_impl_unittest.cc
@@ -539,8 +539,7 @@ TouchEventWithLatencyInfo(touch_event_), blink::mojom::InputEventResultSource::kMainThread, ui::LatencyInfo(), blink::mojom::InputEventResultState::kNoConsumerExists, nullptr, - blink::mojom::TouchActionOptional::New(cc::TouchAction::kPanY), - nullptr); + blink::mojom::TouchActionOptional::New(cc::TouchAction::kPanY)); EXPECT_EQ(input_router_->AllowedTouchAction().value(), cc::TouchAction::kAuto); } @@ -553,7 +552,7 @@ input_router_->TouchEventHandled( TouchEventWithLatencyInfo(touch_event_), blink::mojom::InputEventResultSource::kMainThread, ui::LatencyInfo(), - state, nullptr, std::move(touch_action), nullptr); + state, nullptr, std::move(touch_action)); EXPECT_EQ(input_router_->touch_action_filter_.num_of_active_touches_, 1); ReleaseTouchPoint(0); input_router_->OnTouchEventAck( @@ -571,8 +570,7 @@ TouchEventWithLatencyInfo(touch_event_), blink::mojom::InputEventResultSource::kCompositorThread, ui::LatencyInfo(), blink::mojom::InputEventResultState::kNotConsumed, - nullptr, blink::mojom::TouchActionOptional::New(cc::TouchAction::kPan), - nullptr); + nullptr, blink::mojom::TouchActionOptional::New(cc::TouchAction::kPan)); EXPECT_TRUE(input_router_->touch_event_queue_.IsTimeoutRunningForTesting()); input_router_->SetTouchActionFromMain(cc::TouchAction::kPan); EXPECT_FALSE( @@ -1477,7 +1475,7 @@ dispatched_messages[0]->ToEvent()->CallCallback( blink::mojom::InputEventResultSource::kMainThread, ui::LatencyInfo(), blink::mojom::InputEventResultState::kConsumed, nullptr, - blink::mojom::TouchActionOptional::New(cc::TouchAction::kNone), nullptr); + blink::mojom::TouchActionOptional::New(cc::TouchAction::kNone)); EXPECT_EQ(1U, disposition_handler_->GetAndResetAckCount()); EXPECT_FALSE(TouchEventTimeoutEnabled()); @@ -1564,7 +1562,7 @@ touch_press_event1[0]->ToEvent()->CallCallback( blink::mojom::InputEventResultSource::kMainThread, ui::LatencyInfo(), blink::mojom::InputEventResultState::kConsumed, nullptr, - blink::mojom::TouchActionOptional::New(cc::TouchAction::kNone), nullptr); + blink::mojom::TouchActionOptional::New(cc::TouchAction::kNone)); touch_move_event1[0]->ToEvent()->CallCallback( blink::mojom::InputEventResultState::kConsumed); @@ -1589,8 +1587,7 @@ touch_press_event2[0]->ToEvent()->CallCallback( blink::mojom::InputEventResultSource::kCompositorThread, ui::LatencyInfo(), blink::mojom::InputEventResultState::kConsumed, - nullptr, blink::mojom::TouchActionOptional::New(cc::TouchAction::kAuto), - nullptr); + nullptr, blink::mojom::TouchActionOptional::New(cc::TouchAction::kAuto)); touch_press_event2[0]->ToEvent()->CallCallback( blink::mojom::InputEventResultState::kConsumed); touch_move_event2[0]->ToEvent()->CallCallback( @@ -1631,7 +1628,7 @@ touch_press_event1[0]->ToEvent()->CallCallback( blink::mojom::InputEventResultSource::kMainThread, ui::LatencyInfo(), blink::mojom::InputEventResultState::kConsumed, nullptr, - blink::mojom::TouchActionOptional::New(cc::TouchAction::kNone), nullptr); + blink::mojom::TouchActionOptional::New(cc::TouchAction::kNone)); touch_move_event1[0]->ToEvent()->CallCallback( blink::mojom::InputEventResultState::kConsumed); @@ -1709,7 +1706,7 @@ dispatched_messages[0]->ToEvent()->CallCallback( blink::mojom::InputEventResultSource::kMainThread, ui::LatencyInfo(), blink::mojom::InputEventResultState::kConsumed, nullptr, - blink::mojom::TouchActionOptional::New(cc::TouchAction::kNone), nullptr); + blink::mojom::TouchActionOptional::New(cc::TouchAction::kNone)); EXPECT_EQ(0U, GetAndResetDispatchedMessages().size()); dispatched_messages[1]->ToEvent()->CallCallback( blink::mojom::InputEventResultState::kNotConsumed); @@ -1847,7 +1844,7 @@ dispatched_messages[0]->ToEvent()->CallCallback( blink::mojom::InputEventResultSource::kMainThread, ui::LatencyInfo(), blink::mojom::InputEventResultState::kConsumed, nullptr, - blink::mojom::TouchActionOptional::New(cc::TouchAction::kNone), nullptr); + blink::mojom::TouchActionOptional::New(cc::TouchAction::kNone)); ReleaseTouchPoint(0); SendTouchEvent(); @@ -2223,7 +2220,7 @@ dispatched_messages[0]->ToEvent()->CallCallback( blink::mojom::InputEventResultSource::kCompositorThread, ui::LatencyInfo(), blink::mojom::InputEventResultState::kNotConsumed, - wheel_overscroll.Clone(), nullptr, nullptr); + wheel_overscroll.Clone(), nullptr); client_overscroll = client_->GetAndResetOverscroll(); EXPECT_EQ(wheel_overscroll.accumulated_overscroll, @@ -2292,8 +2289,7 @@ dispatched_messages[0]->ToEvent()->CallCallback( blink::mojom::InputEventResultSource::kCompositorThread, ui::LatencyInfo(), blink::mojom::InputEventResultState::kConsumed, - nullptr, blink::mojom::TouchActionOptional::New(cc::TouchAction::kPan), - nullptr); + nullptr, blink::mojom::TouchActionOptional::New(cc::TouchAction::kPan)); ASSERT_EQ(1U, disposition_handler_->GetAndResetAckCount()); absl::optional<cc::TouchAction> allowed_touch_action = AllowedTouchAction(); cc::TouchAction compositor_allowed_touch_action = @@ -2481,8 +2477,7 @@ dispatched_messages[0]->ToEvent()->CallCallback( blink::mojom::InputEventResultSource::kCompositorThread, ui::LatencyInfo(), blink::mojom::InputEventResultState::kNotConsumed, - nullptr, blink::mojom::TouchActionOptional::New(cc::TouchAction::kPan), - nullptr); + nullptr, blink::mojom::TouchActionOptional::New(cc::TouchAction::kPan)); ASSERT_EQ(1U, disposition_handler_->GetAndResetAckCount()); absl::optional<cc::TouchAction> allowed_touch_action = AllowedTouchAction(); cc::TouchAction compositor_allowed_touch_action =
diff --git a/content/browser/renderer_host/input/mock_input_disposition_handler.cc b/content/browser/renderer_host/input/mock_input_disposition_handler.cc index 2e7489b..3b680ef 100644 --- a/content/browser/renderer_host/input/mock_input_disposition_handler.cc +++ b/content/browser/renderer_host/input/mock_input_disposition_handler.cc
@@ -58,8 +58,7 @@ void MockInputDispositionHandler::OnGestureEventAck( const GestureEventWithLatencyInfo& event, blink::mojom::InputEventResultSource ack_source, - blink::mojom::InputEventResultState ack_result, - blink::mojom::ScrollResultDataPtr scroll_result_data) { + blink::mojom::InputEventResultState ack_result) { VLOG(1) << __FUNCTION__ << " called!"; acked_gesture_event_ = event.event; RecordAckCalled(event.event.GetType(), ack_result);
diff --git a/content/browser/renderer_host/input/mock_input_disposition_handler.h b/content/browser/renderer_host/input/mock_input_disposition_handler.h index 1f01f342..a0e5e853 100644 --- a/content/browser/renderer_host/input/mock_input_disposition_handler.h +++ b/content/browser/renderer_host/input/mock_input_disposition_handler.h
@@ -14,7 +14,6 @@ #include "content/browser/renderer_host/input/input_disposition_handler.h" #include "content/browser/renderer_host/input/input_router.h" #include "content/browser/scheduler/browser_ui_thread_scheduler.h" -#include "third_party/blink/public/mojom/input/input_handler.mojom-forward.h" namespace content { @@ -38,8 +37,7 @@ void OnGestureEventAck( const GestureEventWithLatencyInfo& event, blink::mojom::InputEventResultSource ack_source, - blink::mojom::InputEventResultState ack_result, - blink::mojom::ScrollResultDataPtr scroll_result_data) override; + blink::mojom::InputEventResultState ack_result) override; size_t GetAndResetAckCount();
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index 01807b1..efebe760 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -3540,6 +3540,7 @@ #endif #if BUILDFLAG(IS_WIN) switches::kDisableHighResTimer, + switches::kTrySupportedChannelLayouts, switches::kRaiseTimerFrequency, #endif #if BUILDFLAG(IS_OZONE)
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc index a8457665..aa9159e8 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -120,7 +120,6 @@ #include "third_party/blink/public/common/widget/visual_properties.h" #include "third_party/blink/public/mojom/drag/drag.mojom.h" #include "third_party/blink/public/mojom/frame/intrinsic_sizing_info.mojom.h" -#include "third_party/blink/public/mojom/input/input_handler.mojom-forward.h" #include "third_party/blink/public/mojom/input/touch_event.mojom.h" #include "ui/base/clipboard/clipboard_constants.h" #include "ui/base/cursor/cursor.h" @@ -3424,8 +3423,7 @@ void RenderWidgetHostImpl::OnGestureEventAck( const GestureEventWithLatencyInfo& event, blink::mojom::InputEventResultSource ack_source, - blink::mojom::InputEventResultState ack_result, - blink::mojom::ScrollResultDataPtr scroll_result_data) { + blink::mojom::InputEventResultState ack_result) { latency_tracker_.OnInputEventAck(event.event, &event.latency, ack_result); for (auto& input_event_observer : input_event_observers_) { input_event_observer.OnInputEventAck(ack_source, ack_result, event.event); @@ -3438,8 +3436,7 @@ } if (view_) { - view_->GestureEventAck(event.event, ack_result, - std::move(scroll_result_data)); + view_->GestureEventAck(event.event, ack_result); } }
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h index fd7e2578..25f8b73a 100644 --- a/content/browser/renderer_host/render_widget_host_impl.h +++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -58,7 +58,6 @@ #include "services/viz/public/mojom/hit_test/input_target_client.mojom.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/public/mojom/input/input_event_result.mojom-shared.h" -#include "third_party/blink/public/mojom/input/input_handler.mojom-forward.h" #include "third_party/blink/public/mojom/input/input_handler.mojom.h" #include "third_party/blink/public/mojom/input/pointer_lock_context.mojom.h" #include "third_party/blink/public/mojom/manifest/display_mode.mojom.h" @@ -966,8 +965,7 @@ void OnGestureEventAck( const GestureEventWithLatencyInfo& event, blink::mojom::InputEventResultSource ack_source, - blink::mojom::InputEventResultState ack_result, - blink::mojom::ScrollResultDataPtr scroll_result_data) override; + blink::mojom::InputEventResultState ack_result) override; // virtual for testing. virtual void OnMouseEventAck(const MouseEventWithLatencyInfo& event,
diff --git a/content/browser/renderer_host/render_widget_host_input_event_router.cc b/content/browser/renderer_host/render_widget_host_input_event_router.cc index fb29e9c..87c9a88 100644 --- a/content/browser/renderer_host/render_widget_host_input_event_router.cc +++ b/content/browser/renderer_host/render_widget_host_input_event_router.cc
@@ -1613,8 +1613,7 @@ if (!touchscreen_gesture_target_) { root_view->GestureEventAck( - gesture_event, blink::mojom::InputEventResultState::kNoConsumerExists, - nullptr); + gesture_event, blink::mojom::InputEventResultState::kNoConsumerExists); return; } @@ -1721,7 +1720,7 @@ } else { root_view->GestureEventAck( touchpad_gesture_event, - blink::mojom::InputEventResultState::kNoConsumerExists, nullptr); + blink::mojom::InputEventResultState::kNoConsumerExists); } return; } @@ -1736,7 +1735,7 @@ } else { root_view->GestureEventAck( touchpad_gesture_event, - blink::mojom::InputEventResultState::kNoConsumerExists, nullptr); + blink::mojom::InputEventResultState::kNoConsumerExists); } return; } @@ -1751,7 +1750,7 @@ if (!touchpad_gesture_target_) { root_view->GestureEventAck( touchpad_gesture_event, - blink::mojom::InputEventResultState::kNoConsumerExists, nullptr); + blink::mojom::InputEventResultState::kNoConsumerExists); return; }
diff --git a/content/browser/renderer_host/render_widget_host_unittest.cc b/content/browser/renderer_host/render_widget_host_unittest.cc index 60cb0a2..c3dc360 100644 --- a/content/browser/renderer_host/render_widget_host_unittest.cc +++ b/content/browser/renderer_host/render_widget_host_unittest.cc
@@ -234,8 +234,7 @@ } void GestureEventAck( const WebGestureEvent& event, - blink::mojom::InputEventResultState ack_result, - blink::mojom::ScrollResultDataPtr scroll_result_data) override { + blink::mojom::InputEventResultState ack_result) override { gesture_event_type_ = event.GetType(); ack_result_ = ack_result; }
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc index 54185648..1c63e52 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.cc +++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -2190,8 +2190,7 @@ void RenderWidgetHostViewAndroid::GestureEventAck( const blink::WebGestureEvent& event, - blink::mojom::InputEventResultState ack_result, - blink::mojom::ScrollResultDataPtr scroll_result_data) { + blink::mojom::InputEventResultState ack_result) { if (overscroll_controller_) overscroll_controller_->OnGestureEventAck(event, ack_result); mouse_wheel_phase_handler_.GestureEventAck(event, ack_result); @@ -2203,19 +2202,16 @@ StopFlingingIfNecessary(event, ack_result); if (gesture_listener_manager_) - gesture_listener_manager_->GestureEventAck(event, ack_result, - std::move(scroll_result_data)); + gesture_listener_manager_->GestureEventAck(event, ack_result); HandleSwipeToMoveCursorGestureAck(event); } void RenderWidgetHostViewAndroid::ChildDidAckGestureEvent( const blink::WebGestureEvent& event, - blink::mojom::InputEventResultState ack_result, - blink::mojom::ScrollResultDataPtr scroll_result_data) { + blink::mojom::InputEventResultState ack_result) { if (gesture_listener_manager_) - gesture_listener_manager_->GestureEventAck(event, ack_result, - std::move(scroll_result_data)); + gesture_listener_manager_->GestureEventAck(event, ack_result); } blink::mojom::InputEventResultState
diff --git a/content/browser/renderer_host/render_widget_host_view_android.h b/content/browser/renderer_host/render_widget_host_view_android.h index 0d00264..b41b87f 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.h +++ b/content/browser/renderer_host/render_widget_host_view_android.h
@@ -179,14 +179,11 @@ blink::mojom::InputEventResultState ack_result) override; blink::mojom::InputEventResultState FilterInputEvent( const blink::WebInputEvent& input_event) override; - void GestureEventAck( - const blink::WebGestureEvent& event, - blink::mojom::InputEventResultState ack_result, - blink::mojom::ScrollResultDataPtr scroll_result_data) override; + void GestureEventAck(const blink::WebGestureEvent& event, + blink::mojom::InputEventResultState ack_result) override; void ChildDidAckGestureEvent( const blink::WebGestureEvent& event, - blink::mojom::InputEventResultState ack_result, - blink::mojom::ScrollResultDataPtr scroll_result_data) override; + blink::mojom::InputEventResultState ack_result) override; blink::mojom::PointerLockResult LockMouse( bool request_unadjusted_movement) override; blink::mojom::PointerLockResult ChangeMouseLock(
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc index 268533e..4f2a3b28 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -58,7 +58,6 @@ #include "content/public/common/page_visibility_state.h" #include "services/service_manager/public/cpp/interface_provider.h" #include "third_party/blink/public/common/input/web_input_event.h" -#include "third_party/blink/public/mojom/input/input_handler.mojom-forward.h" #include "third_party/blink/public/mojom/widget/record_content_to_visible_time_request.mojom.h" #include "ui/accessibility/aura/aura_window_properties.h" #include "ui/accessibility/platform/ax_platform_node.h" @@ -1128,8 +1127,7 @@ void RenderWidgetHostViewAura::GestureEventAck( const blink::WebGestureEvent& event, - blink::mojom::InputEventResultState ack_result, - blink::mojom::ScrollResultDataPtr scroll_result_data) { + blink::mojom::InputEventResultState ack_result) { const blink::WebInputEvent::Type event_type = event.GetType(); if (event_type == blink::WebGestureEvent::Type::kGestureScrollBegin || event_type == blink::WebGestureEvent::Type::kGestureScrollEnd) {
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h index ee7a970..42d4bbc 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.h +++ b/content/browser/renderer_host/render_widget_host_view_aura.h
@@ -160,10 +160,8 @@ gfx::Rect GetBoundsInRootWindow() override; void WheelEventAck(const blink::WebMouseWheelEvent& event, blink::mojom::InputEventResultState ack_result) override; - void GestureEventAck( - const blink::WebGestureEvent& event, - blink::mojom::InputEventResultState ack_result, - blink::mojom::ScrollResultDataPtr scroll_result_data) override; + void GestureEventAck(const blink::WebGestureEvent& event, + blink::mojom::InputEventResultState ack_result) override; void DidOverscroll(const ui::DidOverscrollParams& params) override; void ProcessAckedTouchEvent( const TouchEventWithLatencyInfo& touch,
diff --git a/content/browser/renderer_host/render_widget_host_view_base.cc b/content/browser/renderer_host/render_widget_host_view_base.cc index 8410542..cfacbb9 100644 --- a/content/browser/renderer_host/render_widget_host_view_base.cc +++ b/content/browser/renderer_host/render_widget_host_view_base.cc
@@ -400,13 +400,11 @@ void RenderWidgetHostViewBase::GestureEventAck( const blink::WebGestureEvent& event, - blink::mojom::InputEventResultState ack_result, - blink::mojom::ScrollResultDataPtr scroll_result_data) {} + blink::mojom::InputEventResultState ack_result) {} void RenderWidgetHostViewBase::ChildDidAckGestureEvent( const blink::WebGestureEvent& event, - blink::mojom::InputEventResultState ack_result, - blink::mojom::ScrollResultDataPtr scroll_result_data) {} + blink::mojom::InputEventResultState ack_result) {} void RenderWidgetHostViewBase::ForwardTouchpadZoomEventIfNecessary( const blink::WebGestureEvent& event,
diff --git a/content/browser/renderer_host/render_widget_host_view_base.h b/content/browser/renderer_host/render_widget_host_view_base.h index d9ba498c..67cb5cf0 100644 --- a/content/browser/renderer_host/render_widget_host_view_base.h +++ b/content/browser/renderer_host/render_widget_host_view_base.h
@@ -37,7 +37,6 @@ #include "third_party/blink/public/mojom/frame/fullscreen.mojom.h" #include "third_party/blink/public/mojom/frame/intrinsic_sizing_info.mojom-forward.h" #include "third_party/blink/public/mojom/input/input_event_result.mojom-shared.h" -#include "third_party/blink/public/mojom/input/input_handler.mojom-forward.h" #include "third_party/blink/public/mojom/widget/record_content_to_visible_time_request.mojom.h" #include "third_party/skia/include/core/SkImageInfo.h" #include "ui/accessibility/ax_action_handler_registry.h" @@ -238,15 +237,12 @@ virtual void WheelEventAck(const blink::WebMouseWheelEvent& event, blink::mojom::InputEventResultState ack_result); - virtual void GestureEventAck( - const blink::WebGestureEvent& event, - blink::mojom::InputEventResultState ack_result, - blink::mojom::ScrollResultDataPtr scroll_result_data); + virtual void GestureEventAck(const blink::WebGestureEvent& event, + blink::mojom::InputEventResultState ack_result); virtual void ChildDidAckGestureEvent( const blink::WebGestureEvent& event, - blink::mojom::InputEventResultState ack_result, - blink::mojom::ScrollResultDataPtr scroll_result_data); + blink::mojom::InputEventResultState ack_result); // Create a platform specific SyntheticGestureTarget implementation that will // be used to inject synthetic input events.
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame.cc b/content/browser/renderer_host/render_widget_host_view_child_frame.cc index 2b5c0cb..c4312c899 100644 --- a/content/browser/renderer_host/render_widget_host_view_child_frame.cc +++ b/content/browser/renderer_host/render_widget_host_view_child_frame.cc
@@ -35,7 +35,6 @@ #include "third_party/blink/public/common/input/web_touch_event.h" #include "third_party/blink/public/mojom/frame/intrinsic_sizing_info.mojom.h" #include "third_party/blink/public/mojom/frame/viewport_intersection_state.mojom.h" -#include "third_party/blink/public/mojom/input/input_handler.mojom-forward.h" #include "ui/base/cursor/cursor.h" #include "ui/base/ime/mojom/text_input_state.mojom.h" #include "ui/display/display_util.h" @@ -548,8 +547,7 @@ void RenderWidgetHostViewChildFrame::GestureEventAck( const blink::WebGestureEvent& event, - blink::mojom::InputEventResultState ack_result, - blink::mojom::ScrollResultDataPtr scroll_result_data) { + blink::mojom::InputEventResultState ack_result) { // Stop flinging if a GSU event with momentum phase is sent to the renderer // but not consumed. StopFlingingIfNecessary(event, ack_result); @@ -560,9 +558,7 @@ return; if (event.IsTouchpadZoomEvent()) - ProcessTouchpadZoomEventAckInRoot( - event, ack_result, - scroll_result_data ? scroll_result_data.Clone() : nullptr); + ProcessTouchpadZoomEventAckInRoot(event, ack_result); // GestureScrollBegin is a blocking event; It is forwarded for bubbling if // its ack is not consumed. For the rest of the scroll events @@ -586,18 +582,15 @@ } } - frame_connector_->DidAckGestureEvent(event, ack_result, - std::move(scroll_result_data)); + frame_connector_->DidAckGestureEvent(event, ack_result); } void RenderWidgetHostViewChildFrame::ProcessTouchpadZoomEventAckInRoot( const blink::WebGestureEvent& event, - blink::mojom::InputEventResultState ack_result, - blink::mojom::ScrollResultDataPtr scroll_result_data) { + blink::mojom::InputEventResultState ack_result) { DCHECK(event.IsTouchpadZoomEvent()); - frame_connector_->ForwardAckedTouchpadZoomEvent( - event, ack_result, std::move(scroll_result_data)); + frame_connector_->ForwardAckedTouchpadZoomEvent(event, ack_result); } void RenderWidgetHostViewChildFrame::ForwardTouchpadZoomEventIfNecessary(
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame.h b/content/browser/renderer_host/render_widget_host_view_child_frame.h index 1dfd9c0..e340087 100644 --- a/content/browser/renderer_host/render_widget_host_view_child_frame.h +++ b/content/browser/renderer_host/render_widget_host_view_child_frame.h
@@ -32,7 +32,6 @@ #include "third_party/blink/public/mojom/frame/intrinsic_sizing_info.mojom-forward.h" #include "third_party/blink/public/mojom/frame/viewport_intersection_state.mojom-forward.h" #include "third_party/blink/public/mojom/input/input_event_result.mojom-shared.h" -#include "third_party/blink/public/mojom/input/input_handler.mojom-forward.h" #include "third_party/blink/public/mojom/widget/record_content_to_visible_time_request.mojom-forward.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/native_widget_types.h" @@ -119,10 +118,8 @@ void UpdateTooltipFromKeyboard(const std::u16string& tooltip_text, const gfx::Rect& bounds) override; void ClearKeyboardTriggeredTooltip() override; - void GestureEventAck( - const blink::WebGestureEvent& event, - blink::mojom::InputEventResultState ack_result, - blink::mojom::ScrollResultDataPtr scroll_result_data) override; + void GestureEventAck(const blink::WebGestureEvent& event, + blink::mojom::InputEventResultState ack_result) override; // Since the URL of content rendered by this class is not displayed in // the URL bar, this method does not need an implementation. void ResetFallbackToFirstNavigationSurface() override {} @@ -308,8 +305,7 @@ void ProcessTouchpadZoomEventAckInRoot( const blink::WebGestureEvent& event, - blink::mojom::InputEventResultState ack_result, - blink::mojom::ScrollResultDataPtr scroll_result_data); + blink::mojom::InputEventResultState ack_result); void ForwardTouchpadZoomEventIfNecessary( const blink::WebGestureEvent& event, blink::mojom::InputEventResultState ack_result) override;
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame_unittest.cc b/content/browser/renderer_host/render_widget_host_view_child_frame_unittest.cc index a850f27..e6219e9e 100644 --- a/content/browser/renderer_host/render_widget_host_view_child_frame_unittest.cc +++ b/content/browser/renderer_host/render_widget_host_view_child_frame_unittest.cc
@@ -55,11 +55,6 @@ 1, base::UnguessableToken::CreateForTesting(2, 3)); -blink::mojom::ScrollResultDataPtr MakeDefaultScrollResultData() { - return blink::mojom::ScrollResultData::New( - absl::optional<::gfx::PointF>(::gfx::PointF(0, 100))); -} - } // namespace class MockFrameConnector : public CrossProcessFrameConnector { @@ -335,19 +330,16 @@ blink::WebInputEvent::Type::kGestureScrollEnd, blink::WebGestureDevice::kTouchscreen); - view_->GestureEventAck(scroll_begin, - blink::mojom::InputEventResultState::kNoConsumerExists, - MakeDefaultScrollResultData()); + view_->GestureEventAck( + scroll_begin, blink::mojom::InputEventResultState::kNoConsumerExists); EXPECT_EQ(blink::WebInputEvent::Type::kGestureScrollBegin, test_frame_connector_->GetAndResetLastBubbledEventType()); - view_->GestureEventAck(scroll_update, - blink::mojom::InputEventResultState::kNoConsumerExists, - MakeDefaultScrollResultData()); + view_->GestureEventAck( + scroll_update, blink::mojom::InputEventResultState::kNoConsumerExists); EXPECT_EQ(blink::WebInputEvent::Type::kGestureScrollUpdate, test_frame_connector_->GetAndResetLastBubbledEventType()); view_->GestureEventAck(scroll_end, - blink::mojom::InputEventResultState::kIgnored, - MakeDefaultScrollResultData()); + blink::mojom::InputEventResultState::kIgnored); EXPECT_EQ(blink::WebInputEvent::Type::kGestureScrollEnd, test_frame_connector_->GetAndResetLastBubbledEventType()); } @@ -367,27 +359,23 @@ blink::WebGestureDevice::kTouchscreen); view_->GestureEventAck(scroll_begin, - blink::mojom::InputEventResultState::kConsumed, - MakeDefaultScrollResultData()); + blink::mojom::InputEventResultState::kConsumed); EXPECT_EQ(blink::WebInputEvent::Type::kUndefined, test_frame_connector_->GetAndResetLastBubbledEventType()); view_->GestureEventAck(scroll_update, - blink::mojom::InputEventResultState::kConsumed, - MakeDefaultScrollResultData()); + blink::mojom::InputEventResultState::kConsumed); EXPECT_EQ(blink::WebInputEvent::Type::kUndefined, test_frame_connector_->GetAndResetLastBubbledEventType()); // Scrolling in a child my reach its extent and no longer be consumed, however // scrolling is latched to the child so we do not bubble the update. - view_->GestureEventAck(scroll_update, - blink::mojom::InputEventResultState::kNoConsumerExists, - MakeDefaultScrollResultData()); + view_->GestureEventAck( + scroll_update, blink::mojom::InputEventResultState::kNoConsumerExists); EXPECT_EQ(blink::WebInputEvent::Type::kUndefined, test_frame_connector_->GetAndResetLastBubbledEventType()); view_->GestureEventAck(scroll_end, - blink::mojom::InputEventResultState::kIgnored, - MakeDefaultScrollResultData()); + blink::mojom::InputEventResultState::kIgnored); EXPECT_EQ(blink::WebInputEvent::Type::kUndefined, test_frame_connector_->GetAndResetLastBubbledEventType()); } @@ -409,41 +397,35 @@ test_frame_connector_->SetCanBubble(false); - view_->GestureEventAck(scroll_begin, - blink::mojom::InputEventResultState::kNoConsumerExists, - MakeDefaultScrollResultData()); + view_->GestureEventAck( + scroll_begin, blink::mojom::InputEventResultState::kNoConsumerExists); EXPECT_EQ(blink::WebInputEvent::Type::kGestureScrollBegin, test_frame_connector_->GetAndResetLastBubbledEventType()); // The GSB was rejected, so the child view must not attempt to bubble the // remaining events of the scroll sequence. - view_->GestureEventAck(scroll_update, - blink::mojom::InputEventResultState::kNoConsumerExists, - MakeDefaultScrollResultData()); + view_->GestureEventAck( + scroll_update, blink::mojom::InputEventResultState::kNoConsumerExists); EXPECT_EQ(blink::WebInputEvent::Type::kUndefined, test_frame_connector_->GetAndResetLastBubbledEventType()); view_->GestureEventAck(scroll_end, - blink::mojom::InputEventResultState::kIgnored, - MakeDefaultScrollResultData()); + blink::mojom::InputEventResultState::kIgnored); EXPECT_EQ(blink::WebInputEvent::Type::kUndefined, test_frame_connector_->GetAndResetLastBubbledEventType()); test_frame_connector_->SetCanBubble(true); // When we have a new scroll gesture, the view may try bubbling again. - view_->GestureEventAck(scroll_begin, - blink::mojom::InputEventResultState::kNoConsumerExists, - MakeDefaultScrollResultData()); + view_->GestureEventAck( + scroll_begin, blink::mojom::InputEventResultState::kNoConsumerExists); EXPECT_EQ(blink::WebInputEvent::Type::kGestureScrollBegin, test_frame_connector_->GetAndResetLastBubbledEventType()); - view_->GestureEventAck(scroll_update, - blink::mojom::InputEventResultState::kNoConsumerExists, - MakeDefaultScrollResultData()); + view_->GestureEventAck( + scroll_update, blink::mojom::InputEventResultState::kNoConsumerExists); EXPECT_EQ(blink::WebInputEvent::Type::kGestureScrollUpdate, test_frame_connector_->GetAndResetLastBubbledEventType()); view_->GestureEventAck(scroll_end, - blink::mojom::InputEventResultState::kIgnored, - MakeDefaultScrollResultData()); + blink::mojom::InputEventResultState::kIgnored); EXPECT_EQ(blink::WebInputEvent::Type::kGestureScrollEnd, test_frame_connector_->GetAndResetLastBubbledEventType()); }
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.h b/content/browser/renderer_host/render_widget_host_view_mac.h index 066c1a8..04033ad 100644 --- a/content/browser/renderer_host/render_widget_host_view_mac.h +++ b/content/browser/renderer_host/render_widget_host_view_mac.h
@@ -25,7 +25,6 @@ #include "content/common/render_widget_host_ns_view.mojom.h" #include "mojo/public/cpp/bindings/associated_receiver.h" #include "mojo/public/cpp/bindings/associated_remote.h" -#include "third_party/blink/public/mojom/input/input_handler.mojom-forward.h" #include "third_party/blink/public/mojom/webshare/webshare.mojom.h" #include "third_party/blink/public/mojom/widget/record_content_to_visible_time_request.mojom-forward.h" #include "ui/accelerated_widget_mac/accelerated_widget_mac.h" @@ -182,10 +181,8 @@ void UnlockKeyboard() override; bool IsKeyboardLocked() override; base::flat_map<std::string, std::string> GetKeyboardLayoutMap() override; - void GestureEventAck( - const blink::WebGestureEvent& event, - blink::mojom::InputEventResultState ack_result, - blink::mojom::ScrollResultDataPtr scroll_result_data) override; + void GestureEventAck(const blink::WebGestureEvent& event, + blink::mojom::InputEventResultState ack_result) override; void ProcessAckedTouchEvent( const TouchEventWithLatencyInfo& touch, blink::mojom::InputEventResultState ack_result) override;
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm index 404d89f7..0f1bc6f3 100644 --- a/content/browser/renderer_host/render_widget_host_view_mac.mm +++ b/content/browser/renderer_host/render_widget_host_view_mac.mm
@@ -1426,8 +1426,7 @@ void RenderWidgetHostViewMac::GestureEventAck( const WebGestureEvent& event, - blink::mojom::InputEventResultState ack_result, - blink::mojom::ScrollResultDataPtr scroll_result_data) { + blink::mojom::InputEventResultState ack_result) { ForwardTouchpadZoomEventIfNecessary(event, ack_result); // Stop flinging if a GSU event with momentum phase is sent to the renderer
diff --git a/content/browser/service_worker/embedded_worker_instance.cc b/content/browser/service_worker/embedded_worker_instance.cc index 8fb4374e..90797cc4 100644 --- a/content/browser/service_worker/embedded_worker_instance.cc +++ b/content/browser/service_worker/embedded_worker_instance.cc
@@ -659,6 +659,9 @@ } void EmbeddedWorkerInstance::OnWorkerVersionDoomed() { + if (!context_) { + return; + } ServiceWorkerDevToolsManager::GetInstance()->WorkerVersionDoomed( process_id(), worker_devtools_agent_route_id(), base::WrapRefCounted(context_->wrapper()), owner_version_->version_id()); @@ -1115,6 +1118,7 @@ mojo::PendingRemote<network::mojom::URLLoaderFactory> EmbeddedWorkerInstance::MakeScriptLoaderFactoryRemote( std::unique_ptr<blink::PendingURLLoaderFactoryBundle> script_bundle) { + CHECK(context_); mojo::PendingRemote<network::mojom::URLLoaderFactory> script_loader_factory_remote;
diff --git a/content/browser/utility_process_host.cc b/content/browser/utility_process_host.cc index be11389..5b66cb0 100644 --- a/content/browser/utility_process_host.cc +++ b/content/browser/utility_process_host.cc
@@ -366,7 +366,11 @@ #endif #if BUILDFLAG(IS_WIN) switches::kDisableHighResTimer, + switches::kEnableExclusiveAudio, + switches::kForceWaveAudio, switches::kRaiseTimerFrequency, + switches::kTrySupportedChannelLayouts, + switches::kWaveOutBuffers, switches::kWebXrForceRuntime, sandbox::policy::switches::kAddXrAppContainerCaps, #endif
diff --git a/content/browser/webauth/authenticator_common_impl.cc b/content/browser/webauth/authenticator_common_impl.cc index 47f3e00..cd0c3f7 100644 --- a/content/browser/webauth/authenticator_common_impl.cc +++ b/content/browser/webauth/authenticator_common_impl.cc
@@ -478,6 +478,33 @@ return prf_values; } +void SetHints(AuthenticatorRequestClientDelegate* request_delegate, + const base::flat_set<blink::mojom::Hint> hints) { + // The first recognised transport takes priority. + absl::optional<device::FidoTransportProtocol> transport; + for (const auto hint : hints) { + switch (hint) { + case blink::mojom::Hint::SECURITY_KEY: + transport = transport.value_or( + device::FidoTransportProtocol::kUsbHumanInterfaceDevice); + break; + case blink::mojom::Hint::CLIENT_DEVICE: + transport = + transport.value_or(device::FidoTransportProtocol::kInternal); + break; + case blink::mojom::Hint::HYBRID: + transport = transport.value_or(device::FidoTransportProtocol::kHybrid); + break; + } + } + + if (transport) { + AuthenticatorRequestClientDelegate::Hints delegate_hints; + delegate_hints.transport = transport; + request_delegate->SetHints(delegate_hints); + } +} + } // namespace // RequestState contains all state that is specific to a single WebAuthn call. @@ -529,6 +556,8 @@ // is_payment_request indicates that the current request is Secure Payment // Confirmation-related. bool is_payment_request = false; + // The hints set by the request, if any. + base::flat_set<blink::mojom::Hint> hints; base::flat_set<RequestExtension> requested_extensions; @@ -603,6 +632,7 @@ GetWebAuthenticationDelegate()->IsEnclaveAuthenticatorAvailable( GetBrowserContext()), discovery_factory()); + SetHints(req_state_->request_delegate.get(), req_state_->hints); req_state_->make_credential_options->allow_skipping_pin_touch = allow_skipping_pin_touch; @@ -659,6 +689,7 @@ discovery_factory()->set_get_assertion_request_for_legacy_credential_check( *req_state_->ctap_get_assertion_request); #endif + SetHints(req_state_->request_delegate.get(), req_state_->hints); base::flat_set<device::FidoTransportProtocol> transports = GetWebAuthnTransports( @@ -715,6 +746,7 @@ req_state_->make_credential_response_callback = std::move(callback); req_state_->is_payment_request = options->is_payment_credential_creation; + req_state_->hints.insert(options->hints.begin(), options->hints.end()); // TODO(crbug.com/1459443): remove this and everything else from // the CL that added it if this is unused by June 2024. @@ -1028,6 +1060,7 @@ req_state_->get_assertion_response_callback = std::move(callback); req_state_->is_payment_request = !payment_options.is_null(); + req_state_->hints.insert(options->hints.begin(), options->hints.end()); // TODO(crbug.com/1459443): remove this and everything else from // the CL that added it if this is unused by June 2024.
diff --git a/content/browser/webid/federated_auth_request_impl.cc b/content/browser/webid/federated_auth_request_impl.cc index 24bc145..fb224688 100644 --- a/content/browser/webid/federated_auth_request_impl.cc +++ b/content/browser/webid/federated_auth_request_impl.cc
@@ -1746,9 +1746,6 @@ } case IdpNetworkRequestManager::ParseStatus::kSuccess: { FilterAccountsWithLoginHint(idp_info->provider->login_hint, accounts); - if (IsFedCmDomainHintEnabled()) { - FilterAccountsWithDomainHint(idp_info->provider->domain_hint, accounts); - } if (accounts.empty()) { render_frame_host().AddMessageToConsole( blink::mojom::ConsoleMessageLevel::kError, @@ -1762,6 +1759,22 @@ TokenStatus::kAccountsListEmpty); return; } + if (IsFedCmDomainHintEnabled()) { + FilterAccountsWithDomainHint(idp_info->provider->domain_hint, accounts); + if (accounts.empty()) { + render_frame_host().AddMessageToConsole( + blink::mojom::ConsoleMessageLevel::kError, + "Accounts were received, but none matched the domainHint."); + // If there are no accounts after filtering based on the domain hint, + // treat this exactly the same as if we had received an empty accounts + // list, i.e. IdpNetworkRequestManager::ParseStatus::kEmptyListError. + HandleAccountsFetchFailure( + std::move(idp_info), old_idp_signin_status, + FederatedAuthRequestResult::kErrorFetchingAccountsListEmpty, + TokenStatus::kAccountsListEmpty); + return; + } + } ComputeLoginStateAndReorderAccounts( url::Origin::Create(idp_info->provider->config->config_url), accounts);
diff --git a/content/browser/webid/federated_auth_request_impl_unittest.cc b/content/browser/webid/federated_auth_request_impl_unittest.cc index ea2762c..1bf4ae2 100644 --- a/content/browser/webid/federated_auth_request_impl_unittest.cc +++ b/content/browser/webid/federated_auth_request_impl_unittest.cc
@@ -112,6 +112,9 @@ constexpr char kLoginHintNoMatchMessage[] = "Accounts were received, but none matched the loginHint."; +constexpr char kDomainHintNoMatchMessage[] = + "Accounts were received, but none matched the domainHint."; + static const std::vector<IdentityRequestAccount> kSingleAccount{{ kAccountId, // id kEmail, // email @@ -4514,7 +4517,7 @@ const RequestExpectations expectations = { RequestTokenStatus::kError, FederatedAuthRequestResult::kErrorFetchingAccountsListEmpty, - {kLoginHintNoMatchMessage}, + {kDomainHintNoMatchMessage}, /*selected_idp_config_url=*/absl::nullopt}; MockConfiguration configuration = kConfigurationValid; @@ -4537,7 +4540,7 @@ const RequestExpectations expectations = { RequestTokenStatus::kError, FederatedAuthRequestResult::kErrorFetchingAccountsListEmpty, - {kLoginHintNoMatchMessage}, + {kDomainHintNoMatchMessage}, /*selected_idp_config_url=*/absl::nullopt}; MockConfiguration configuration = kConfigurationValid; @@ -4562,7 +4565,7 @@ const RequestExpectations expectations = { RequestTokenStatus::kError, FederatedAuthRequestResult::kErrorFetchingAccountsListEmpty, - {kLoginHintNoMatchMessage}, + {kDomainHintNoMatchMessage}, /*selected_idp_config_url=*/absl::nullopt}; RunAuthTest(parameters, expectations, kConfigurationValid); @@ -4647,7 +4650,7 @@ const RequestExpectations expectations = { RequestTokenStatus::kError, FederatedAuthRequestResult::kErrorFetchingAccountsListEmpty, - {kLoginHintNoMatchMessage}, + {kDomainHintNoMatchMessage}, /*selected_idp_config_url=*/absl::nullopt}; MockConfiguration configuration = kConfigurationValid;
diff --git a/content/common/input/gesture_event_queue.cc b/content/common/input/gesture_event_queue.cc index af2ff95..13c2336 100644 --- a/content/common/input/gesture_event_queue.cc +++ b/content/common/input/gesture_event_queue.cc
@@ -8,7 +8,6 @@ #include "base/trace_event/trace_event.h" #include "content/common/input/touchpad_tap_suppression_controller.h" #include "content/common/input/touchscreen_tap_suppression_controller.h" -#include "third_party/blink/public/mojom/input/input_handler.mojom.h" #include "ui/events/blink/blink_features.h" #include "ui/events/blink/web_input_event_traits.h" @@ -17,8 +16,8 @@ namespace content { -GestureEventQueue::GestureEventWithLatencyInfoAckStateAndScrollResultData:: - GestureEventWithLatencyInfoAckStateAndScrollResultData( +GestureEventQueue::GestureEventWithLatencyInfoAckState:: + GestureEventWithLatencyInfoAckState( const GestureEventWithLatencyInfo& event) : GestureEventWithLatencyInfo(event) {} @@ -160,8 +159,7 @@ blink::mojom::InputEventResultSource ack_source, blink::mojom::InputEventResultState ack_result, WebInputEvent::Type type, - const ui::LatencyInfo& latency, - blink::mojom::ScrollResultDataPtr scroll_result_data) { + const ui::LatencyInfo& latency) { TRACE_EVENT0("input", "GestureEventQueue::ProcessGestureAck"); if (sent_events_awaiting_ack_.empty()) { @@ -179,7 +177,6 @@ if (outstanding_event.event.GetType() == type) { outstanding_event.latency.AddNewLatencyFrom(latency); outstanding_event.set_ack_info(ack_source, ack_result); - outstanding_event.set_scroll_result_data(std::move(scroll_result_data)); break; } } @@ -199,24 +196,18 @@ if (iter->ack_state() == blink::mojom::InputEventResultState::kUnknown) { break; } - GestureEventWithLatencyInfoAckStateAndScrollResultData event = *iter; + GestureEventWithLatencyInfoAckState event = *iter; sent_events_awaiting_ack_.erase(iter); - auto scroll_result_data = blink::mojom::ScrollResultData::New( - event.scroll_result_data().root_scroll_offset); - - AckGestureEventToClient(event, event.ack_source(), event.ack_state(), - std::move(scroll_result_data)); + AckGestureEventToClient(event, event.ack_source(), event.ack_state()); } } void GestureEventQueue::AckGestureEventToClient( const GestureEventWithLatencyInfo& event_with_latency, blink::mojom::InputEventResultSource ack_source, - blink::mojom::InputEventResultState ack_result, - blink::mojom::ScrollResultDataPtr scroll_result_data) { - client_->OnGestureEventAck(event_with_latency, ack_source, ack_result, - std::move(scroll_result_data)); + blink::mojom::InputEventResultState ack_result) { + client_->OnGestureEventAck(event_with_latency, ack_source, ack_result); } TouchpadTapSuppressionController*
diff --git a/content/common/input/gesture_event_queue.h b/content/common/input/gesture_event_queue.h index f9312ce..4d4999f 100644 --- a/content/common/input/gesture_event_queue.h +++ b/content/common/input/gesture_event_queue.h
@@ -14,10 +14,8 @@ #include "content/common/content_export.h" #include "content/common/input/event_with_latency_info.h" #include "content/common/input/fling_controller.h" -#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/public/common/input/web_input_event.h" #include "third_party/blink/public/mojom/input/input_event_result.mojom-shared.h" -#include "third_party/blink/public/mojom/input/input_handler.mojom.h" namespace content { class GestureEventQueueTest; @@ -35,8 +33,7 @@ virtual void OnGestureEventAck( const GestureEventWithLatencyInfo& event, blink::mojom::InputEventResultSource ack_source, - blink::mojom::InputEventResultState ack_result, - blink::mojom::ScrollResultDataPtr scroll_result_data) = 0; + blink::mojom::InputEventResultState ack_result) = 0; }; // Despite its name, this class isn't so much one queue as it is a collection @@ -107,8 +104,7 @@ void ProcessGestureAck(blink::mojom::InputEventResultSource ack_source, blink::mojom::InputEventResultState ack_result, blink::WebInputEvent::Type type, - const ui::LatencyInfo& latency, - blink::mojom::ScrollResultDataPtr scroll_result_data); + const ui::LatencyInfo& latency); // Returns the |TouchpadTapSuppressionController| instance. TouchpadTapSuppressionController* GetTouchpadTapSuppressionController(); @@ -145,12 +141,10 @@ friend class GestureEventQueueTest; friend class MockRenderWidgetHost; - class GestureEventWithLatencyInfoAckStateAndScrollResultData + class GestureEventWithLatencyInfoAckState : public GestureEventWithLatencyInfo { public: - GestureEventWithLatencyInfoAckStateAndScrollResultData( - const GestureEventWithLatencyInfo&); - ~GestureEventWithLatencyInfoAckStateAndScrollResultData() = default; + GestureEventWithLatencyInfoAckState(const GestureEventWithLatencyInfo&); blink::mojom::InputEventResultState ack_state() const { return ack_state_; } void set_ack_info(blink::mojom::InputEventResultSource source, blink::mojom::InputEventResultState state) { @@ -160,28 +154,12 @@ blink::mojom::InputEventResultSource ack_source() const { return ack_source_; } - void set_scroll_result_data( - blink::mojom::ScrollResultDataPtr scroll_result_data) { - // Creating a new instance and setting the field(s) explicitly because - // having blink::mojom::ScrollResultDataPtr as a field makes this class - // move-only and causes issues pushing into and removing from - // sent_events_awaiting_ack_. - // TODO(sinansahin): This class can probably be refactored to work with - // being move-only. - scroll_result_data_ = blink::mojom::ScrollResultData( - scroll_result_data ? scroll_result_data->root_scroll_offset - : absl::nullopt); - } - const blink::mojom::ScrollResultData& scroll_result_data() { - return scroll_result_data_; - } private: blink::mojom::InputEventResultSource ack_source_ = blink::mojom::InputEventResultSource::kUnknown; blink::mojom::InputEventResultState ack_state_ = blink::mojom::InputEventResultState::kUnknown; - blink::mojom::ScrollResultData scroll_result_data_; }; // Inovked on the expiration of the debounce interval to release @@ -195,11 +173,9 @@ // ACK completed events in order until we have reached an incomplete event. // Will preserve the FIFO order as events originally arrived. void AckCompletedEvents(); - void AckGestureEventToClient( - const GestureEventWithLatencyInfo&, - blink::mojom::InputEventResultSource, - blink::mojom::InputEventResultState, - blink::mojom::ScrollResultDataPtr scroll_result_data); + void AckGestureEventToClient(const GestureEventWithLatencyInfo&, + blink::mojom::InputEventResultSource, + blink::mojom::InputEventResultState); bool FlingInProgressForTest() const; @@ -211,8 +187,8 @@ bool processing_acks_ = false; - using GestureQueueWithAckState = base::circular_deque< - GestureEventWithLatencyInfoAckStateAndScrollResultData>; + using GestureQueueWithAckState = + base::circular_deque<GestureEventWithLatencyInfoAckState>; // Stores outstanding events that have been sent to the renderer but not yet // been ACK'd. These are kept in the order they were sent in so that they can
diff --git a/content/common/input/gesture_event_queue_unittest.cc b/content/common/input/gesture_event_queue_unittest.cc index e6fb18d..947013e 100644 --- a/content/common/input/gesture_event_queue_unittest.cc +++ b/content/common/input/gesture_event_queue_unittest.cc
@@ -21,9 +21,7 @@ #include "third_party/blink/public/common/input/synthetic_web_input_event_builders.h" #include "third_party/blink/public/common/input/web_input_event.h" #include "third_party/blink/public/mojom/input/input_event_result.mojom-shared.h" -#include "third_party/blink/public/mojom/input/input_handler.mojom.h" #include "ui/events/blink/blink_features.h" -#include "ui/gfx/geometry/point_f.h" #if BUILDFLAG(IS_CHROMEOS) #include "ui/display/test/test_screen.h" @@ -79,18 +77,16 @@ if (sync_ack_result_) { std::unique_ptr<blink::mojom::InputEventResultState> ack_result = std::move(sync_ack_result_); - SendInputEventACK(event.event.GetType(), *ack_result, nullptr); + SendInputEventACK(event.event.GetType(), *ack_result); } } void OnGestureEventAck( const GestureEventWithLatencyInfo& event, blink::mojom::InputEventResultSource ack_source, - blink::mojom::InputEventResultState ack_result, - blink::mojom::ScrollResultDataPtr scroll_result_data) override { + blink::mojom::InputEventResultState ack_result) override { ++acked_gesture_event_count_; last_acked_event_ = event.event; - last_acked_event_scroll_result_data_ = std::move(scroll_result_data); if (sync_followup_event_) { auto sync_followup_event = std::move(sync_followup_event_); SimulateGestureEvent(*sync_followup_event); @@ -167,11 +163,10 @@ } void SendInputEventACK(WebInputEvent::Type type, - blink::mojom::InputEventResultState ack, - blink::mojom::ScrollResultDataPtr scroll_result_data) { + blink::mojom::InputEventResultState ack) { queue()->ProcessGestureAck( blink::mojom::InputEventResultSource::kCompositorThread, ack, type, - ui::LatencyInfo(), std::move(scroll_result_data)); + ui::LatencyInfo()); } void RunUntilIdle() { task_environment_.RunUntilIdle(); } @@ -232,10 +227,6 @@ GestureEventQueue* queue() const { return queue_.get(); } - blink::mojom::ScrollResultDataPtr last_acked_event_scroll_result_data() { - return std::move(last_acked_event_scroll_result_data_); - } - private: base::test::SingleThreadTaskEnvironment task_environment_; std::unique_ptr<GestureEventQueue> queue_; @@ -245,7 +236,6 @@ std::unique_ptr<blink::mojom::InputEventResultState> sync_ack_result_; std::unique_ptr<WebGestureEvent> sync_followup_event_; base::test::ScopedFeatureList feature_list_; - blink::mojom::ScrollResultDataPtr last_acked_event_scroll_result_data_; #if BUILDFLAG(IS_CHROMEOS) // This is necessary on ChromeOS to access tablet mode info. display::test::TestScreen test_screen_{/*create_dispay=*/true, @@ -280,7 +270,7 @@ EXPECT_EQ(1U, GetAndResetAckedGestureEventCount()); SendInputEventACK(WebInputEvent::Type::kGestureShowPress, - blink::mojom::InputEventResultState::kConsumed, nullptr); + blink::mojom::InputEventResultState::kConsumed); EXPECT_EQ(0U, GetAndResetSentGestureEventCount()); EXPECT_EQ(0U, GestureEventQueueSize()); EXPECT_EQ(1U, GetAndResetAckedGestureEventCount()); @@ -529,14 +519,14 @@ // Simulate GSB ACK. SendInputEventACK(WebInputEvent::Type::kGestureScrollBegin, - blink::mojom::InputEventResultState::kConsumed, nullptr); + blink::mojom::InputEventResultState::kConsumed); EXPECT_EQ(WebInputEvent::Type::kGestureScrollBegin, last_acked_event().GetType()); EXPECT_EQ(2U, GestureEventQueueSize()); // Simulate GSE ACK first since it's usually dispatched non-blocking. SendInputEventACK(WebInputEvent::Type::kGestureScrollEnd, - blink::mojom::InputEventResultState::kConsumed, nullptr); + blink::mojom::InputEventResultState::kConsumed); // GSE ACK will be cached in GestureEventQueue since we haven't ACKed GSU yet. EXPECT_EQ(WebInputEvent::Type::kGestureScrollBegin, last_acked_event().GetType()); @@ -544,7 +534,7 @@ // Simulate GSU ACK. SendInputEventACK(WebInputEvent::Type::kGestureScrollUpdate, - blink::mojom::InputEventResultState::kConsumed, nullptr); + blink::mojom::InputEventResultState::kConsumed); // Both ACKs should be released in order. EXPECT_EQ(WebInputEvent::Type::kGestureScrollEnd, last_acked_event().GetType()); @@ -578,31 +568,25 @@ GestureEventLastQueueEvent().GetType()); SendInputEventACK(WebInputEvent::Type::kGestureScrollBegin, - blink::mojom::InputEventResultState::kConsumed, nullptr); + blink::mojom::InputEventResultState::kConsumed); EXPECT_EQ(4U, GestureEventQueueSize()); - auto scroll_result_data = - blink::mojom::ScrollResultData::New(gfx::PointF(0.f, 4.f)); SendInputEventACK(WebInputEvent::Type::kGesturePinchBegin, - blink::mojom::InputEventResultState::kConsumed, nullptr); + blink::mojom::InputEventResultState::kConsumed); SendInputEventACK(WebInputEvent::Type::kGestureScrollUpdate, - blink::mojom::InputEventResultState::kConsumed, - std::move(scroll_result_data)); + blink::mojom::InputEventResultState::kConsumed); // Both GestureScrollUpdate and GesturePinchUpdate should have been sent. EXPECT_EQ(WebInputEvent::Type::kGestureScrollUpdate, last_acked_event().GetType()); - // scroll_result_data should be preserved. - EXPECT_EQ(4.f, - last_acked_event_scroll_result_data()->root_scroll_offset->y()); EXPECT_EQ(2U, GestureEventQueueSize()); EXPECT_EQ(0U, GetAndResetSentGestureEventCount()); // Ack the last 2 GesturePinchUpdate events. SendInputEventACK(WebInputEvent::Type::kGesturePinchUpdate, - blink::mojom::InputEventResultState::kConsumed, nullptr); + blink::mojom::InputEventResultState::kConsumed); SendInputEventACK(WebInputEvent::Type::kGesturePinchUpdate, - blink::mojom::InputEventResultState::kConsumed, nullptr); + blink::mojom::InputEventResultState::kConsumed); EXPECT_EQ(WebInputEvent::Type::kGesturePinchUpdate, last_acked_event().GetType()); EXPECT_EQ(0U, GestureEventQueueSize());
diff --git a/content/public/android/java/src/org/chromium/content/browser/GestureListenerManagerImpl.java b/content/public/android/java/src/org/chromium/content/browser/GestureListenerManagerImpl.java index 1ddb5218..6c52ff61 100644 --- a/content/public/android/java/src/org/chromium/content/browser/GestureListenerManagerImpl.java +++ b/content/public/android/java/src/org/chromium/content/browser/GestureListenerManagerImpl.java
@@ -6,11 +6,9 @@ import static org.chromium.cc.mojom.RootScrollOffsetUpdateFrequency.NONE; -import android.graphics.Point; import android.view.HapticFeedbackConstants; import android.view.View; -import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import org.jni_zero.CalledByNative; @@ -64,7 +62,6 @@ private SelectionPopupControllerImpl mSelectionPopupController; private ViewAndroidDelegate mViewDelegate; private InternalAccessDelegate mScrollDelegate; - private final Point mRootScrollOffsetStruct = new Point(); private long mNativeGestureListenerManager; @@ -291,7 +288,7 @@ @CalledByNative @VisibleForTesting - void onEventAck(int event, boolean consumed, float scrollOffsetX, float scrollOffsetY) { + void onEventAck(int event, boolean consumed) { switch (event) { case EventType.GESTURE_FLING_START: // If we're here, then |consumed| is false as otherwise #onFlingStart() would have @@ -307,10 +304,7 @@ if (!consumed) break; destroyPastePopup(); for (mIterator.rewind(); mIterator.hasNext(); ) { - // TODO(sinansahin): Can we update the RenderCoordinates using these values - // and make them available through other scroll events? - Point scrollOffset = getRootScrollOffsetStruct(scrollOffsetX, scrollOffsetY); - mIterator.next().onScrollUpdateGestureConsumed(scrollOffset); + mIterator.next().onScrollUpdateGestureConsumed(); } break; case EventType.GESTURE_SCROLL_END: @@ -340,20 +334,6 @@ } } - /** - * Returns a {@link Point} with the given x and y scroll offset values. Returns null if the - * values are invalid, i.e. negative. - * - * @param scrollOffsetX Horizontal scroll offset in pixels. - * @param scrollOffsetY Vertical scroll offset in pixels. - */ - private @Nullable Point getRootScrollOffsetStruct(float scrollOffsetX, float scrollOffsetY) { - if (scrollOffsetX < 0 || scrollOffsetY < 0) return null; - - mRootScrollOffsetStruct.set((int) scrollOffsetX, (int) scrollOffsetY); - return mRootScrollOffsetStruct; - } - /** Called when a gesture event ack happens for |EventType.GESTURE_SCROLL_BEGIN|. */ @CalledByNative @VisibleForTesting
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/GestureStateListener.java b/content/public/android/java/src/org/chromium/content_public/browser/GestureStateListener.java index 1d573ea..4830f7d 100644 --- a/content/public/android/java/src/org/chromium/content_public/browser/GestureStateListener.java +++ b/content/public/android/java/src/org/chromium/content_public/browser/GestureStateListener.java
@@ -4,10 +4,6 @@ package org.chromium.content_public.browser; -import android.graphics.Point; - -import androidx.annotation.Nullable; - /** * An interface that is notified of events and state changes related to gesture processing * from content layer. @@ -26,15 +22,12 @@ public void onFlingEndGesture(int scrollOffsetY, int scrollExtentY) {} /** - * Called to indicate that a scroll update gesture had been consumed by the page. - * This callback is called whenever any layer is scrolled (like a frame or div). It is - * not called when a JS touch handler consumes the event (preventDefault), it is not called - * for JS-initiated scrolling. - * - * @param rootScrollOffset Updated root scroll offset if the scroll was consumed by the - * viewport, null otherwise. + * Called to indicate that a scroll update gesture had been consumed by the page. This callback + * is called whenever any layer is scrolled (like a frame or div). It is not called when a JS + * touch handler consumes the event (preventDefault), it is not called for JS-initiated + * scrolling. */ - public void onScrollUpdateGestureConsumed(@Nullable Point rootScrollOffset) {} + public void onScrollUpdateGestureConsumed() {} /** Called when a scroll gesture has started. */ public void onScrollStarted(int scrollOffsetY, int scrollExtentY, boolean isDirectionUp) {}
diff --git a/content/public/android/junit/src/org/chromium/content/browser/GestureListenerManagerImplUnitTest.java b/content/public/android/junit/src/org/chromium/content/browser/GestureListenerManagerImplUnitTest.java index 75f0d15..0d675bbb 100644 --- a/content/public/android/junit/src/org/chromium/content/browser/GestureListenerManagerImplUnitTest.java +++ b/content/public/android/junit/src/org/chromium/content/browser/GestureListenerManagerImplUnitTest.java
@@ -15,7 +15,6 @@ import static org.chromium.cc.mojom.RootScrollOffsetUpdateFrequency.NONE; import static org.chromium.cc.mojom.RootScrollOffsetUpdateFrequency.ON_SCROLL_END; -import android.graphics.Point; import android.view.ViewGroup; import org.junit.Assert; @@ -84,25 +83,13 @@ Assert.assertTrue("Scroll should started.", mGestureManager.isScrollInProgress()); verify(mGestureStateListener).onScrollStarted(anyInt(), anyInt(), eq(true)); - mGestureManager.onEventAck( - EventType.GESTURE_SCROLL_UPDATE, - /* consumed= */ true, - /* scrollOffsetX= */ 0.f, - /* scrollOffsetY= */ 1.f); - verify(mGestureStateListener).onScrollUpdateGestureConsumed(eq(new Point(0, 1))); + mGestureManager.onEventAck(EventType.GESTURE_SCROLL_UPDATE, /* consumed= */ true); + verify(mGestureStateListener).onScrollUpdateGestureConsumed(); Mockito.reset(mGestureStateListener); - mGestureManager.onEventAck( - EventType.GESTURE_SCROLL_UPDATE, - /* consumed= */ true, - /* scrollOffsetX= */ 1.f, - /* scrollOffsetY= */ 0.f); - verify(mGestureStateListener).onScrollUpdateGestureConsumed(eq(new Point(1, 0))); + mGestureManager.onEventAck(EventType.GESTURE_SCROLL_UPDATE, /* consumed= */ true); + verify(mGestureStateListener).onScrollUpdateGestureConsumed(); - mGestureManager.onEventAck( - EventType.GESTURE_SCROLL_END, - /* consumed= */ true, - /* scrollOffsetX= */ 0.f, - /* scrollOffsetY= */ 0.f); + mGestureManager.onEventAck(EventType.GESTURE_SCROLL_END, /* consumed= */ true); verify(mGestureStateListener).onScrollEnded(anyInt(), anyInt()); }
diff --git a/content/public/browser/authenticator_request_client_delegate.cc b/content/public/browser/authenticator_request_client_delegate.cc index 0991f2f..ef31e10 100644 --- a/content/public/browser/authenticator_request_client_delegate.cc +++ b/content/public/browser/authenticator_request_client_delegate.cc
@@ -161,6 +161,8 @@ bool is_enclave_authenticator_available, device::FidoDiscoveryFactory* fido_discovery_factory) {} +void AuthenticatorRequestClientDelegate::SetHints(const Hints& hints) {} + void AuthenticatorRequestClientDelegate::SelectAccount( std::vector<device::AuthenticatorGetAssertionResponse> responses, base::OnceCallback<void(device::AuthenticatorGetAssertionResponse)>
diff --git a/content/public/browser/authenticator_request_client_delegate.h b/content/public/browser/authenticator_request_client_delegate.h index ad5e851..893a3ad7 100644 --- a/content/public/browser/authenticator_request_client_delegate.h +++ b/content/public/browser/authenticator_request_client_delegate.h
@@ -18,6 +18,7 @@ #include "device/fido/discoverable_credential_metadata.h" #include "device/fido/fido_request_handler_base.h" #include "device/fido/fido_transport_protocol.h" +#include "device/fido/fido_types.h" #include "device/fido/public_key_credential_descriptor.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -294,6 +295,17 @@ bool is_enclave_authenticator_available, device::FidoDiscoveryFactory* fido_discovery_factory); + // Hints reflects the "hints" parameter that can be set on a request. See + // https://w3c.github.io/webauthn/#enumdef-publickeycredentialhints + struct Hints { + // The site's preferred transport for this operation. + absl::optional<device::FidoTransportProtocol> transport; + }; + + // SetHints communicates the "hints" that were set in the request. See + // https://w3c.github.io/webauthn/#enumdef-publickeycredentialhints + virtual void SetHints(const Hints& hints); + // SelectAccount is called to allow the embedder to select between one or more // accounts. This is triggered when the web page requests an unspecified // credential (by passing an empty allow-list). In this case, any accounts
diff --git a/content/services/auction_worklet/bidder_worklet.cc b/content/services/auction_worklet/bidder_worklet.cc index 53757c36..73ea08b7 100644 --- a/content/services/auction_worklet/bidder_worklet.cc +++ b/content/services/auction_worklet/bidder_worklet.cc
@@ -1263,7 +1263,12 @@ bidder_worklet_non_shared_params.update_url->spec())) || (trusted_bidding_signals_url_ && !SetTrustedBiddingSignalsUrl(isolate, interest_group_object, - trusted_bidding_signals_url_->spec()))) { + trusted_bidding_signals_url_->spec())) || + !interest_group_dict.Set( + "trustedBiddingSignalsSlotSizeMode", + blink::InterestGroup::TrustedBiddingSignalsSlotSizeModeToString( + bidder_worklet_non_shared_params + .trusted_bidding_signals_slot_size_mode))) { return absl::nullopt; }
diff --git a/content/services/auction_worklet/bidder_worklet_unittest.cc b/content/services/auction_worklet/bidder_worklet_unittest.cc index d4f914c..b685d59 100644 --- a/content/services/auction_worklet/bidder_worklet_unittest.cc +++ b/content/services/auction_worklet/bidder_worklet_unittest.cc
@@ -619,6 +619,7 @@ } return mojom::BidderWorkletNonSharedParams::New( interest_group_name_, + blink::InterestGroup::TrustedBiddingSignalsSlotSizeMode::kNone, interest_group_enable_bidding_signals_prioritization_, interest_group_priority_vector_, execution_mode_, update_url_, interest_group_trusted_bidding_signals_keys_,
diff --git a/content/services/auction_worklet/public/mojom/bidder_worklet.mojom b/content/services/auction_worklet/public/mojom/bidder_worklet.mojom index f024d3f..01f485a 100644 --- a/content/services/auction_worklet/public/mojom/bidder_worklet.mojom +++ b/content/services/auction_worklet/public/mojom/bidder_worklet.mojom
@@ -62,6 +62,9 @@ struct BidderWorkletNonSharedParams { string name; + blink.mojom.InterestGroup.TrustedBiddingSignalsSlotSizeMode + trusted_bidding_signals_slot_size_mode; + bool enable_bidding_signals_prioritization; map<string, double>? priority_vector;
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index a19857a..29d87af9 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -1077,7 +1077,7 @@ # Generate WebUI bindings in JavaScript instead of TypeScript. This is # necessary since this target is intentionally testing JS WebUI bindings. - generate_webui_js_bindings = true + use_typescript_sources = false } }
diff --git a/content/test/data/interest_group/bidding_argument_validator.js b/content/test/data/interest_group/bidding_argument_validator.js index 6ef266b..e5aa051 100644 --- a/content/test/data/interest_group/bidding_argument_validator.js +++ b/content/test/data/interest_group/bidding_argument_validator.js
@@ -40,7 +40,7 @@ if (!interestGroup) throw 'No interest group'; - if (Object.keys(interestGroup).length !== 15) { + if (Object.keys(interestGroup).length !== 16) { throw 'Wrong number of interestGroupFields ' + JSON.stringify(interestGroup); } @@ -117,6 +117,11 @@ trustedBiddingSignalsKeysJson; } + if (interestGroup.trustedBiddingSignalsSlotSizeMode != 'none') { + throw 'Incorrect trustedBiddingSignalsSlotSizeMode ' + + interestGroup.trustedBiddingSignalsSlotSizeMode; + } + // If userBiddingSignals is passed as a JSON string instead of an object, // stringify() will wrap it in another layer of quotes, causing the test to // fail. The order of properties produced by stringify() isn't guaranteed by
diff --git a/content/test/data/interest_group/component_auction_bidding_argument_validator.js b/content/test/data/interest_group/component_auction_bidding_argument_validator.js index 20d6a88d..da35f23 100644 --- a/content/test/data/interest_group/component_auction_bidding_argument_validator.js +++ b/content/test/data/interest_group/component_auction_bidding_argument_validator.js
@@ -40,7 +40,7 @@ if (!interestGroup) throw 'No interest group'; - if (Object.keys(interestGroup).length !== 15) { + if (Object.keys(interestGroup).length !== 16) { throw 'Wrong number of interestGroupFields ' + JSON.stringify(interestGroup); } @@ -110,6 +110,11 @@ trustedBiddingSignalsKeysJson; } + if (interestGroup.trustedBiddingSignalsSlotSizeMode != 'none') { + throw 'Incorrect trustedBiddingSignalsSlotSizeMode ' + + interestGroup.trustedBiddingSignalsSlotSizeMode; + } + // TODO(crbug.com/1186444): Consider validating URL fields like // interestGroup.biddingLogicURL once we decide what to do about URL // normalization.
diff --git a/content/test/mock_widget_input_handler.cc b/content/test/mock_widget_input_handler.cc index a92012c..3e9ec72f 100644 --- a/content/test/mock_widget_input_handler.cc +++ b/content/test/mock_widget_input_handler.cc
@@ -233,10 +233,9 @@ MockWidgetInputHandler::DispatchedEventMessage::~DispatchedEventMessage() { if (callback_) { - std::move(callback_).Run(blink::mojom::InputEventResultSource::kUnknown, - ui::LatencyInfo(), - blink::mojom::InputEventResultState::kNotConsumed, - nullptr, nullptr, nullptr); + std::move(callback_).Run( + blink::mojom::InputEventResultSource::kUnknown, ui::LatencyInfo(), + blink::mojom::InputEventResultState::kNotConsumed, nullptr, nullptr); base::RunLoop().RunUntilIdle(); } } @@ -250,8 +249,7 @@ blink::mojom::InputEventResultState state) { if (callback_) { std::move(callback_).Run(blink::mojom::InputEventResultSource::kMainThread, - ui::LatencyInfo(), state, nullptr, nullptr, - nullptr); + ui::LatencyInfo(), state, nullptr, nullptr); base::RunLoop().RunUntilIdle(); } } @@ -261,12 +259,10 @@ const ui::LatencyInfo& latency_info, blink::mojom::InputEventResultState state, blink::mojom::DidOverscrollParamsPtr overscroll, - blink::mojom::TouchActionOptionalPtr touch_action, - blink::mojom::ScrollResultDataPtr scroll_result_data) { + blink::mojom::TouchActionOptionalPtr touch_action) { if (callback_) { std::move(callback_).Run(source, latency_info, state, std::move(overscroll), - std::move(touch_action), - std::move(scroll_result_data)); + std::move(touch_action)); base::RunLoop().RunUntilIdle(); } }
diff --git a/content/test/mock_widget_input_handler.h b/content/test/mock_widget_input_handler.h index 6e176f5c..e10cfffc 100644 --- a/content/test/mock_widget_input_handler.h +++ b/content/test/mock_widget_input_handler.h
@@ -178,8 +178,7 @@ const ui::LatencyInfo& latency_info, blink::mojom::InputEventResultState state, blink::mojom::DidOverscrollParamsPtr overscroll, - blink::mojom::TouchActionOptionalPtr touch_action, - blink::mojom::ScrollResultDataPtr scroll_result_data); + blink::mojom::TouchActionOptionalPtr touch_action); // Return if the callback is set. bool HasCallback() const;
diff --git a/device/vr/buildflags/buildflags.gni b/device/vr/buildflags/buildflags.gni index 8b73378..1505826 100644 --- a/device/vr/buildflags/buildflags.gni +++ b/device/vr/buildflags/buildflags.gni
@@ -37,7 +37,4 @@ enable_gvr_services || enable_openxr || enable_cardboard || enable_arcore || (is_linux && !is_castos && (current_cpu == "x64" || current_cpu == "x86")) - - # Whether to include VR extras like test APKs in non-VR-specific targets - include_vr_data = false }
diff --git a/docs/rust.md b/docs/rust.md index 5c687500..c3e5551a 100644 --- a/docs/rust.md +++ b/docs/rust.md
@@ -67,10 +67,6 @@ * `git add -f third_party/rust/chromium_crates_io/vendor` * The `-f` is important, as files may be skipped otherwise from a `.gitignore` inside the crate. -1. If a crate in `//third_party/rust/chromium_crates_io/patches` was updated - as part of vendoring, then reapply patches to it: - * Go to the `//third_party/rust/chromium_crates_io` directory. - * `./apply_patches.sh` (this currently requires linux). 1. (optional) If the crate is only to be used by tests and tooling, then specify the `"test"` group in `//third_party/rust/chromium_crates_io/gnrt_config.toml`: ```
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h index daa9e07..9b8500c 100644 --- a/extensions/browser/extension_function_histogram_value.h +++ b/extensions/browser/extension_function_histogram_value.h
@@ -1919,6 +1919,7 @@ DOCUMENTSCAN_STARTSCAN = 1857, DOCUMENTSCAN_CANCELSCAN = 1858, DOCUMENTSCAN_READSCANDATA = 1859, + DOCUMENTSCAN_SETOPTIONS = 1860, // Last entry: Add new entries above, then run: // tools/metrics/histograms/update_extension_histograms.py ENUM_BOUNDARY
diff --git a/extensions/browser/extension_util.cc b/extensions/browser/extension_util.cc index ba4c761..c43da8a 100644 --- a/extensions/browser/extension_util.cc +++ b/extensions/browser/extension_util.cc
@@ -9,6 +9,7 @@ #include "base/no_destructor.h" #include "build/chromeos_buildflags.h" #include "components/crx_file/id_util.h" +#include "components/guest_view/browser/guest_view_base.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/child_process_security_policy.h" #include "content/public/browser/render_frame_host.h" @@ -25,6 +26,7 @@ #include "extensions/common/manifest.h" #include "extensions/common/manifest_handlers/incognito_info.h" #include "extensions/common/manifest_handlers/shared_module_info.h" +#include "extensions/common/mojom/host_id.mojom.h" #include "extensions/common/permissions/permissions_data.h" #include "extensions/common/switches.h" #include "extensions/grit/extensions_browser_resources.h" @@ -56,6 +58,31 @@ } // namespace +mojom::HostID::HostType HostIDTypeFromGuestView( + const guest_view::GuestViewBase& guest) { + if (guest.IsOwnedByWebUI()) { + return mojom::HostID::HostType::kWebUi; + } + + if (guest.IsOwnedByControlledFrameEmbedder()) { + return mojom::HostID::HostType::kControlledFrameEmbedder; + } + + // Note: We return a type of kExtensions for all cases where + // |guest.IsOwnedByExtension()| are true, as well as some additional cases + // where that call is false but also |guest.IsOwnedByWebUI()| and + // |guest.IsOwnedByControlledFrameEmbedder()| are false. Those appear to be + // when the provided extension identifier is blank. Future work in this area + // could improve the checks here so all the cases are declared relative to + // what the GuestView instance asserts itself to be. + return mojom::HostID::HostType::kExtensions; +} + +mojom::HostID GenerateHostIDFromGuestView( + const guest_view::GuestViewBase& guest) { + return mojom::HostID(HostIDTypeFromGuestView(guest), guest.owner_host()); +} + bool CanBeIncognitoEnabled(const Extension* extension) { return IncognitoInfo::IsIncognitoAllowed(extension) && (!extension->is_platform_app() ||
diff --git a/extensions/browser/extension_util.h b/extensions/browser/extension_util.h index d073f69..13cf4fc 100644 --- a/extensions/browser/extension_util.h +++ b/extensions/browser/extension_util.h
@@ -10,6 +10,7 @@ #include "base/functional/callback.h" #include "extensions/common/manifest.h" +#include "extensions/common/mojom/host_id.mojom.h" #include "extensions/common/mojom/renderer.mojom.h" #include "url/gurl.h" @@ -21,6 +22,10 @@ class ImageSkia; } // namespace gfx +namespace guest_view { +class GuestViewBase; +} // namespace guest_view + namespace content { class BrowserContext; class ServiceWorkerContext; @@ -40,6 +45,14 @@ // chrome/browser/extensions/extension_util.h/cc that are only dependent on // extensions/ here. +// Returns a HostID type based on the given GuestViewBase. +mojom::HostID::HostType HostIDTypeFromGuestView( + const guest_view::GuestViewBase& guest); + +// Returns a HostID instance based on the given GuestViewBase. +mojom::HostID GenerateHostIDFromGuestView( + const guest_view::GuestViewBase& guest); + // Returns true if the extension can be enabled in incognito mode. bool CanBeIncognitoEnabled(const Extension* extension);
diff --git a/extensions/common/manifest_handlers/mime_types_handler.cc b/extensions/common/manifest_handlers/mime_types_handler.cc index 0f6f642..017ff21 100644 --- a/extensions/common/manifest_handlers/mime_types_handler.cc +++ b/extensions/common/manifest_handlers/mime_types_handler.cc
@@ -77,17 +77,6 @@ return *allowlist_vector; } -// static -void MimeTypesHandler::ReportUsedHandler(const std::string& extension_id) { - auto* const* it = - base::ranges::find(kMIMETypeHandlersAllowlist, extension_id); - if (it != std::end(kMIMETypeHandlersAllowlist)) { - MimeHandlerType type = static_cast<MimeHandlerType>( - it - std::begin(kMIMETypeHandlersAllowlist)); - base::UmaHistogramEnumeration("Extensions.UsedMimeTypeHandler", type); - } -} - MimeTypesHandler::MimeTypesHandler() = default; MimeTypesHandler::~MimeTypesHandler() = default;
diff --git a/extensions/common/manifest_handlers/mime_types_handler.h b/extensions/common/manifest_handlers/mime_types_handler.h index e802de6..69e9cf34 100644 --- a/extensions/common/manifest_handlers/mime_types_handler.h +++ b/extensions/common/manifest_handlers/mime_types_handler.h
@@ -21,9 +21,6 @@ static MimeTypesHandler* GetHandler(const extensions::Extension* extension); - // Sends a UMA stat about usage of the specific type handler. - static void ReportUsedHandler(const std::string& extension_id); - MimeTypesHandler(); ~MimeTypesHandler();
diff --git a/infra/config/generated/builders/ci/ToTiOS/properties.json b/infra/config/generated/builders/ci/ToTiOS/properties.json index 8691689..3a5650f 100644 --- a/infra/config/generated/builders/ci/ToTiOS/properties.json +++ b/infra/config/generated/builders/ci/ToTiOS/properties.json
@@ -58,5 +58,5 @@ "sheriff_rotations": [ "chromium.clang" ], - "xcode_build_version": "14c18" + "xcode_build_version": "15a507" } \ No newline at end of file
diff --git a/infra/config/generated/builders/ci/ToTiOSDevice/properties.json b/infra/config/generated/builders/ci/ToTiOSDevice/properties.json index 7c1b8af..37d0d1a 100644 --- a/infra/config/generated/builders/ci/ToTiOSDevice/properties.json +++ b/infra/config/generated/builders/ci/ToTiOSDevice/properties.json
@@ -58,5 +58,5 @@ "sheriff_rotations": [ "chromium.clang" ], - "xcode_build_version": "14c18" + "xcode_build_version": "15a507" } \ No newline at end of file
diff --git a/infra/config/generated/builders/ci/chromeos-jacuzzi-rel-skylab-fyi/properties.json b/infra/config/generated/builders/ci/chromeos-jacuzzi-rel-skylab-fyi/properties.json index d1225c2..246ee47 100644 --- a/infra/config/generated/builders/ci/chromeos-jacuzzi-rel-skylab-fyi/properties.json +++ b/infra/config/generated/builders/ci/chromeos-jacuzzi-rel-skylab-fyi/properties.json
@@ -37,7 +37,7 @@ "config": "chromium" }, "skylab_upload_location": { - "gs_bucket": "chrome-test-builds", + "gs_bucket": "chromium-skylab-ci", "gs_extra": "ash" } }
diff --git a/infra/config/generated/builders/ci/chromeos-octopus-rel-skylab-fyi/properties.json b/infra/config/generated/builders/ci/chromeos-octopus-rel-skylab-fyi/properties.json index 940c5f7d..3c935c86 100644 --- a/infra/config/generated/builders/ci/chromeos-octopus-rel-skylab-fyi/properties.json +++ b/infra/config/generated/builders/ci/chromeos-octopus-rel-skylab-fyi/properties.json
@@ -37,7 +37,7 @@ "config": "chromium" }, "skylab_upload_location": { - "gs_bucket": "chrome-test-builds", + "gs_bucket": "chromium-skylab-ci", "gs_extra": "ash" } }
diff --git a/infra/config/generated/builders/reclient/ios-simulator reclient staging untrusted/properties.json b/infra/config/generated/builders/reclient/ios-simulator reclient staging untrusted/properties.json index e13d7dae..4f25f94e 100644 --- a/infra/config/generated/builders/reclient/ios-simulator reclient staging untrusted/properties.json +++ b/infra/config/generated/builders/reclient/ios-simulator reclient staging untrusted/properties.json
@@ -70,5 +70,5 @@ }, "builder_group": "chromium.reclient.fyi", "recipe": "chromium", - "xcode_build_version": "14c18" + "xcode_build_version": "15a507" } \ No newline at end of file
diff --git a/infra/config/generated/builders/reclient/ios-simulator reclient staging/properties.json b/infra/config/generated/builders/reclient/ios-simulator reclient staging/properties.json index b0d5a67..5a8303a 100644 --- a/infra/config/generated/builders/reclient/ios-simulator reclient staging/properties.json +++ b/infra/config/generated/builders/reclient/ios-simulator reclient staging/properties.json
@@ -70,5 +70,5 @@ }, "builder_group": "chromium.reclient.fyi", "recipe": "chromium", - "xcode_build_version": "14c18" + "xcode_build_version": "15a507" } \ No newline at end of file
diff --git a/infra/config/generated/builders/reclient/ios-simulator reclient test untrusted/properties.json b/infra/config/generated/builders/reclient/ios-simulator reclient test untrusted/properties.json index b4fd3d7..c799a3d 100644 --- a/infra/config/generated/builders/reclient/ios-simulator reclient test untrusted/properties.json +++ b/infra/config/generated/builders/reclient/ios-simulator reclient test untrusted/properties.json
@@ -70,5 +70,5 @@ }, "builder_group": "chromium.reclient.fyi", "recipe": "chromium", - "xcode_build_version": "14c18" + "xcode_build_version": "15a507" } \ No newline at end of file
diff --git a/infra/config/generated/builders/reclient/ios-simulator reclient test/properties.json b/infra/config/generated/builders/reclient/ios-simulator reclient test/properties.json index 1ab293c..9e0476d 100644 --- a/infra/config/generated/builders/reclient/ios-simulator reclient test/properties.json +++ b/infra/config/generated/builders/reclient/ios-simulator reclient test/properties.json
@@ -70,5 +70,5 @@ }, "builder_group": "chromium.reclient.fyi", "recipe": "chromium", - "xcode_build_version": "14c18" + "xcode_build_version": "15a507" } \ No newline at end of file
diff --git a/infra/config/generated/builders/try/chromeos-jacuzzi-rel-skylab/properties.json b/infra/config/generated/builders/try/chromeos-jacuzzi-rel-skylab/properties.json index 5c30172..8591daf 100644 --- a/infra/config/generated/builders/try/chromeos-jacuzzi-rel-skylab/properties.json +++ b/infra/config/generated/builders/try/chromeos-jacuzzi-rel-skylab/properties.json
@@ -37,7 +37,7 @@ "config": "chromium" }, "skylab_upload_location": { - "gs_bucket": "chrome-test-builds", + "gs_bucket": "chromium-skylab-ci", "gs_extra": "ash" } }
diff --git a/infra/config/generated/builders/try/chromeos-octopus-rel-skylab/properties.json b/infra/config/generated/builders/try/chromeos-octopus-rel-skylab/properties.json index eb8c2f8e..e33af6d 100644 --- a/infra/config/generated/builders/try/chromeos-octopus-rel-skylab/properties.json +++ b/infra/config/generated/builders/try/chromeos-octopus-rel-skylab/properties.json
@@ -37,7 +37,7 @@ "config": "chromium" }, "skylab_upload_location": { - "gs_bucket": "chrome-test-builds", + "gs_bucket": "chromium-skylab-ci", "gs_extra": "ash" } }
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg index 8f81075..521a672 100644 --- a/infra/config/generated/luci/cr-buildbucket.cfg +++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -15153,12 +15153,12 @@ ' "sheriff_rotations": [' ' "chromium"' ' ],' - ' "xcode_build_version": "14c18"' + ' "xcode_build_version": "15a507"' '}' execution_timeout_secs: 14400 caches { - name: "xcode_ios_14c18" - path: "xcode_ios_14c18.app" + name: "xcode_ios_15a507" + path: "xcode_ios_15a507.app" } build_numbers: YES service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com" @@ -25242,8 +25242,8 @@ '}' execution_timeout_secs: 50400 caches { - name: "xcode_ios_14c18" - path: "xcode_ios_14c18.app" + name: "xcode_ios_15a507" + path: "xcode_ios_15a507.app" } build_numbers: YES service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com" @@ -25339,8 +25339,8 @@ '}' execution_timeout_secs: 50400 caches { - name: "xcode_ios_14c18" - path: "xcode_ios_14c18.app" + name: "xcode_ios_15a507" + path: "xcode_ios_15a507.app" } build_numbers: YES service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com" @@ -30185,25 +30185,25 @@ '{' ' "$build/avd_packager": {' ' "avd_configs": [' + ' "tools/android/avd/proto/creation/android_28_google_apis_x86.textpb",' + ' "tools/android/avd/proto/creation/android_29_google_apis_x86.textpb",' + ' "tools/android/avd/proto/creation/android_30_google_apis_x86.textpb",' + ' "tools/android/avd/proto/creation/android_31_google_apis_x64.textpb",' + ' "tools/android/avd/proto/creation/android_32_google_apis_x64_foldable.textpb",' + ' "tools/android/avd/proto/creation/android_33_google_apis_x64.textpb",' + ' "tools/android/avd/proto/creation/android_34_google_apis_x64.textpb",' ' "tools/android/avd/proto/creation/android_30_google_atd_x86.textpb",' ' "tools/android/avd/proto/creation/android_30_google_atd_x64.textpb",' ' "tools/android/avd/proto/creation/android_31_google_atd_x64.textpb",' ' "tools/android/avd/proto/creation/android_32_google_atd_x64_foldable.textpb",' ' "tools/android/avd/proto/creation/android_33_google_atd_x64.textpb",' - ' "tools/android/avd/proto/creation/android_34_google_apis_x64.textpb",' ' "tools/android/avd/proto/creation/generic_android19.textpb",' ' "tools/android/avd/proto/creation/generic_android22.textpb",' ' "tools/android/avd/proto/creation/generic_android23.textpb",' ' "tools/android/avd/proto/creation/generic_android24.textpb",' ' "tools/android/avd/proto/creation/generic_android25.textpb",' ' "tools/android/avd/proto/creation/generic_android26.textpb",' - ' "tools/android/avd/proto/creation/generic_android27.textpb",' - ' "tools/android/avd/proto/creation/generic_android28.textpb",' - ' "tools/android/avd/proto/creation/generic_android29.textpb",' - ' "tools/android/avd/proto/creation/generic_android30.textpb",' - ' "tools/android/avd/proto/creation/generic_android31.textpb",' - ' "tools/android/avd/proto/creation/generic_android32_foldable.textpb",' - ' "tools/android/avd/proto/creation/generic_android33.textpb"' + ' "tools/android/avd/proto/creation/generic_android27.textpb"' ' ],' ' "gclient_apply_config": [' ' "android"' @@ -38624,12 +38624,12 @@ ' "sheriff_rotations": [' ' "angle"' ' ],' - ' "xcode_build_version": "14c18"' + ' "xcode_build_version": "15a507"' '}' execution_timeout_secs: 10800 caches { - name: "xcode_ios_14c18" - path: "xcode_ios_14c18.app" + name: "xcode_ios_15a507" + path: "xcode_ios_15a507.app" } build_numbers: YES service_account: "chromium-ci-gpu-builder@chops-service-accounts.iam.gserviceaccount.com" @@ -61000,8 +61000,8 @@ priority: 35 execution_timeout_secs: 10800 caches { - name: "xcode_ios_14c18" - path: "xcode_ios_14c18.app" + name: "xcode_ios_15a507" + path: "xcode_ios_15a507.app" } build_numbers: YES service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com" @@ -61089,8 +61089,8 @@ priority: 35 execution_timeout_secs: 10800 caches { - name: "xcode_ios_14c18" - path: "xcode_ios_14c18.app" + name: "xcode_ios_15a507" + path: "xcode_ios_15a507.app" } build_numbers: YES service_account: "chromium-cq-staging-builder@chops-service-accounts.iam.gserviceaccount.com" @@ -61178,8 +61178,8 @@ priority: 35 execution_timeout_secs: 10800 caches { - name: "xcode_ios_14c18" - path: "xcode_ios_14c18.app" + name: "xcode_ios_15a507" + path: "xcode_ios_15a507.app" } build_numbers: YES service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com" @@ -61267,8 +61267,8 @@ priority: 35 execution_timeout_secs: 10800 caches { - name: "xcode_ios_14c18" - path: "xcode_ios_14c18.app" + name: "xcode_ios_15a507" + path: "xcode_ios_15a507.app" } build_numbers: YES service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com" @@ -62877,10 +62877,6 @@ value: 10 } experiments { - key: "chromium.skip_successful_tests" - value: 50 - } - experiments { key: "chromium_swarming.expose_merge_script_failures" value: 100 } @@ -63632,10 +63628,6 @@ value: 100 } experiments { - key: "chromium.skip_successful_tests" - value: 50 - } - experiments { key: "chromium_swarming.expose_merge_script_failures" value: 100 } @@ -69075,10 +69067,6 @@ value: 5 } experiments { - key: "chromium.skip_successful_tests" - value: 50 - } - experiments { key: "chromium_swarming.expose_merge_script_failures" value: 100 } @@ -69178,10 +69166,6 @@ value: 10 } experiments { - key: "chromium.skip_successful_tests" - value: 50 - } - experiments { key: "chromium_swarming.expose_merge_script_failures" value: 100 } @@ -69564,10 +69548,6 @@ value: 5 } experiments { - key: "chromium.skip_successful_tests" - value: 50 - } - experiments { key: "chromium_swarming.expose_merge_script_failures" value: 100 } @@ -69855,10 +69835,6 @@ value: 5 } experiments { - key: "chromium.skip_successful_tests" - value: 50 - } - experiments { key: "chromium_swarming.expose_merge_script_failures" value: 100 } @@ -71203,10 +71179,6 @@ value: 10 } experiments { - key: "chromium.skip_successful_tests" - value: 50 - } - experiments { key: "chromium_swarming.expose_merge_script_failures" value: 100 } @@ -71592,10 +71564,6 @@ value: 5 } experiments { - key: "chromium.skip_successful_tests" - value: 50 - } - experiments { key: "chromium_swarming.expose_merge_script_failures" value: 100 } @@ -75452,10 +75420,6 @@ value: 100 } experiments { - key: "chromium.skip_successful_tests" - value: 50 - } - experiments { key: "chromium_swarming.expose_merge_script_failures" value: 100 } @@ -80808,10 +80772,6 @@ value: 10 } experiments { - key: "chromium.skip_successful_tests" - value: 50 - } - experiments { key: "chromium_swarming.expose_merge_script_failures" value: 100 } @@ -82078,10 +82038,6 @@ value: 5 } experiments { - key: "chromium.skip_successful_tests" - value: 50 - } - experiments { key: "chromium_swarming.expose_merge_script_failures" value: 100 } @@ -82370,10 +82326,6 @@ value: 5 } experiments { - key: "chromium.skip_successful_tests" - value: 50 - } - experiments { key: "chromium_swarming.expose_merge_script_failures" value: 100 } @@ -85032,10 +84984,6 @@ value: 5 } experiments { - key: "chromium.skip_successful_tests" - value: 50 - } - experiments { key: "chromium_swarming.expose_merge_script_failures" value: 100 } @@ -85327,10 +85275,6 @@ value: 10 } experiments { - key: "chromium.skip_successful_tests" - value: 50 - } - experiments { key: "chromium_swarming.expose_merge_script_failures" value: 100 } @@ -87220,10 +87164,6 @@ value: 10 } experiments { - key: "chromium.skip_successful_tests" - value: 50 - } - experiments { key: "chromium_swarming.expose_merge_script_failures" value: 100 } @@ -87599,10 +87539,6 @@ value: 5 } experiments { - key: "chromium.skip_successful_tests" - value: 50 - } - experiments { key: "chromium_swarming.expose_merge_script_failures" value: 100 } @@ -88177,10 +88113,6 @@ value: 10 } experiments { - key: "chromium.skip_successful_tests" - value: 50 - } - experiments { key: "chromium_swarming.expose_merge_script_failures" value: 100 } @@ -90775,10 +90707,6 @@ value: 5 } experiments { - key: "chromium.skip_successful_tests" - value: 50 - } - experiments { key: "chromium_swarming.expose_merge_script_failures" value: 100 } @@ -91168,10 +91096,6 @@ value: 100 } experiments { - key: "chromium.skip_successful_tests" - value: 50 - } - experiments { key: "chromium_swarming.expose_merge_script_failures" value: 100 } @@ -91606,7 +91530,7 @@ name: "linux_chromium_chromeos_asan_rel_ng" swarming_host: "chromium-swarm.appspot.com" dimensions: "builderless:1" - dimensions: "cores:8" + dimensions: "cores:16" dimensions: "cpu:x86-64" dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.try" @@ -91933,10 +91857,6 @@ value: 5 } experiments { - key: "chromium.skip_successful_tests" - value: 50 - } - experiments { key: "chromium_swarming.expose_merge_script_failures" value: 100 } @@ -92427,10 +92347,6 @@ value: 10 } experiments { - key: "chromium.skip_successful_tests" - value: 50 - } - experiments { key: "chromium_swarming.expose_merge_script_failures" value: 100 } @@ -94701,10 +94617,6 @@ value: 10 } experiments { - key: "chromium.skip_successful_tests" - value: 50 - } - experiments { key: "chromium_swarming.expose_merge_script_failures" value: 100 } @@ -97708,10 +97620,6 @@ value: 5 } experiments { - key: "chromium.skip_successful_tests" - value: 50 - } - experiments { key: "chromium_swarming.expose_merge_script_failures" value: 100 } @@ -100316,10 +100224,6 @@ value: 5 } experiments { - key: "chromium.skip_successful_tests" - value: 50 - } - experiments { key: "chromium_swarming.expose_merge_script_failures" value: 100 } @@ -100699,10 +100603,6 @@ value: 100 } experiments { - key: "chromium.skip_successful_tests" - value: 50 - } - experiments { key: "chromium_swarming.expose_merge_script_failures" value: 100 } @@ -104680,7 +104580,7 @@ name: "WebRTC Chromium FYI ios-device" swarming_host: "chromium-swarm.appspot.com" dimensions: "cpu:x86-64" - dimensions: "os:Mac" + dimensions: "os:Mac-13" dimensions: "pool:luci.chromium.webrtc.fyi" exe { cipd_package: "infra/chromium/bootstrapper/${platform}" @@ -104731,7 +104631,7 @@ name: "WebRTC Chromium FYI ios-simulator" swarming_host: "chromium-swarm.appspot.com" dimensions: "cpu:x86-64" - dimensions: "os:Mac" + dimensions: "os:Mac-13" dimensions: "pool:luci.chromium.webrtc.fyi" exe { cipd_package: "infra/chromium/bootstrapper/${platform}"
diff --git a/infra/config/generated/testing/mixins.pyl b/infra/config/generated/testing/mixins.pyl index a81110f..a46890b8 100644 --- a/infra/config/generated/testing/mixins.pyl +++ b/infra/config/generated/testing/mixins.pyl
@@ -1133,12 +1133,6 @@ }, }, }, - 'vr_instrumentation_test': { - 'args': [ - '--remove-system-package=com.google.vr.vrcore', - '--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk', - ], - }, 'walleye': { 'swarming': { 'dimensions': {
diff --git a/infra/config/generated/testing/test_suites.pyl b/infra/config/generated/testing/test_suites.pyl index 7b9865cc..51130324 100644 --- a/infra/config/generated/testing/test_suites.pyl +++ b/infra/config/generated/testing/test_suites.pyl
@@ -35,47 +35,6 @@ 'vr_android_unittests': {}, }, - 'android_ddready_vr_gtests': { - 'chrome_public_test_vr_apk-ddready-cardboard': { - 'test': 'chrome_public_test_vr_apk', - 'mixins': [ - 'vr_instrumentation_test', - ], - 'args': [ - '--shared-prefs-file=//chrome/android/shared_preference_files/test/vr_cardboard_skipdon_setupcomplete.json', - ], - 'swarming': { - 'shards': 2, - }, - }, - 'chrome_public_test_vr_apk-ddready-ddview': { - 'test': 'chrome_public_test_vr_apk', - 'mixins': [ - 'skia_gold_test', - 'vr_instrumentation_test', - ], - 'args': [ - '--shared-prefs-file=//chrome/android/shared_preference_files/test/vr_ddview_skipdon_setupcomplete.json', - '--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_keyboard/vr_keyboard_current.apk', - ], - 'swarming': { - 'shards': 4, - }, - }, - 'chrome_public_test_vr_apk-ddready-don-enabled': { - 'test': 'chrome_public_test_vr_apk', - 'mixins': [ - 'vr_instrumentation_test', - ], - 'args': [ - '--shared-prefs-file=//chrome/android/shared_preference_files/test/vr_ddview_don_setupcomplete.json', - '--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_keyboard/vr_keyboard_current.apk', - '--annotation=Restriction=VR_DON_Enabled', - '--vr-don-enabled', - ], - }, - }, - 'android_emulator_specific_chrome_public_tests': { 'chrome_public_test_apk': { 'mixins': [ @@ -5320,10 +5279,6 @@ 'vr_android_specific_chromium_tests': { 'chrome_public_test_vr_apk': { - 'args': [ - '--shared-prefs-file=//chrome/android/shared_preference_files/test/vr_cardboard_skipdon_setupcomplete.json', - '--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk', - ], 'swarming': { 'shards': 2, }, @@ -5814,8 +5769,8 @@ 'android_10_rel_gtests': [ 'android_ar_gtests', - 'android_ddready_vr_gtests', 'android_trichrome_smoke_tests', + 'vr_android_specific_chromium_tests', ], 'android_12_dbg_emulator_gtests': [ @@ -5849,10 +5804,10 @@ 'android_oreo_gtests': [ 'android_ar_gtests', - 'android_ddready_vr_gtests', 'android_monochrome_smoke_tests', 'android_oreo_standard_gtests', 'android_smoke_tests', + 'vr_android_specific_chromium_tests', ], 'android_pie_coverage_instrumentation_tests': [ @@ -5865,10 +5820,10 @@ 'android_pie_gtests': [ 'android_ar_gtests', - 'android_ddready_vr_gtests', 'android_monochrome_smoke_tests', 'android_smoke_tests', 'chromium_tracing_gtests', + 'vr_android_specific_chromium_tests', ], 'android_pie_rel_emulator_gtests': [
diff --git a/infra/config/lib/builders.star b/infra/config/lib/builders.star index 784e9c3b..b4522141 100644 --- a/infra/config/lib/builders.star +++ b/infra/config/lib/builders.star
@@ -161,7 +161,10 @@ # Keep this in-sync with the versions of bots in //ios/build/bots/. xcode = struct( - # (current default for other projects) xc12.0 gm seed + # Default Xcode Version, stays in sync with x15main + xcode_default = xcode_enum("15a507"), + + # xc12.0 gm seed x12a7209 = xcode_enum("12a7209"), # xc12.4 gm seed x12d4e = xcode_enum("12d4e"),
diff --git a/infra/config/subprojects/chromium/ci/chromium.angle.star b/infra/config/subprojects/chromium/ci/chromium.angle.star index 038aef1..085106f 100644 --- a/infra/config/subprojects/chromium/ci/chromium.angle.star +++ b/infra/config/subprojects/chromium/ci/chromium.angle.star
@@ -385,7 +385,7 @@ short_name = "x64", ), contact_team_email = "angle-team@google.com", - xcode = xcode.x14main, + xcode = xcode.xcode_default, ) ci.thin_tester(
diff --git a/infra/config/subprojects/chromium/ci/chromium.clang.star b/infra/config/subprojects/chromium/ci/chromium.clang.star index 13430ea..6d8fc79 100644 --- a/infra/config/subprojects/chromium/ci/chromium.clang.star +++ b/infra/config/subprojects/chromium/ci/chromium.clang.star
@@ -1330,7 +1330,7 @@ short_name = "sim", ), contact_team_email = "lexan@google.com", - xcode = xcode.x14main, + xcode = xcode.xcode_default, ) ci.builder( @@ -1371,7 +1371,7 @@ short_name = "dev", ), contact_team_email = "lexan@google.com", - xcode = xcode.x14main, + xcode = xcode.xcode_default, ) clang_mac_builder(
diff --git a/infra/config/subprojects/chromium/ci/chromium.coverage.star b/infra/config/subprojects/chromium/ci/chromium.coverage.star index 2cfef8e..5d1cb73 100644 --- a/infra/config/subprojects/chromium/ci/chromium.coverage.star +++ b/infra/config/subprojects/chromium/ci/chromium.coverage.star
@@ -293,7 +293,7 @@ coverage_test_types = ["overall", "unit"], export_coverage_to_zoss = True, use_clang_coverage = True, - xcode = xcode.x15main, + xcode = xcode.xcode_default, ) coverage_builder(
diff --git a/infra/config/subprojects/chromium/ci/chromium.fuzz.star b/infra/config/subprojects/chromium/ci/chromium.fuzz.star index ffac8cf..624821a 100644 --- a/infra/config/subprojects/chromium/ci/chromium.fuzz.star +++ b/infra/config/subprojects/chromium/ci/chromium.fuzz.star
@@ -824,7 +824,7 @@ ), contact_team_email = "chrome-deet-core@google.com", execution_timeout = 4 * time.hour, - xcode = xcode.x14main, + xcode = xcode.xcode_default, ) ci.builder(
diff --git a/infra/config/subprojects/chromium/ci/chromium.fyi.star b/infra/config/subprojects/chromium/ci/chromium.fyi.star index e285399..341304b 100644 --- a/infra/config/subprojects/chromium/ci/chromium.fyi.star +++ b/infra/config/subprojects/chromium/ci/chromium.fyi.star
@@ -80,7 +80,7 @@ if kwargs.get("builderless", False): kwargs.setdefault("os", os.MAC_DEFAULT) kwargs.setdefault("reclient_scandeps_server", True) - kwargs.setdefault("xcode", xcode.x15main) + kwargs.setdefault("xcode", xcode.xcode_default) return ci.builder(name = name, **kwargs) def mac_builder_defaults(**kwargs): @@ -182,7 +182,7 @@ ], ), skylab_upload_location = builder_config.skylab_upload_location( - gs_bucket = "chrome-test-builds", + gs_bucket = "chromium-skylab-ci", gs_extra = "ash", ), ), @@ -235,7 +235,7 @@ ], ), skylab_upload_location = builder_config.skylab_upload_location( - gs_bucket = "chrome-test-builds", + gs_bucket = "chromium-skylab-ci", gs_extra = "ash", ), ), @@ -1482,7 +1482,7 @@ reclient_cache_silo = "Comparison ios - cache siloed", reclient_instance = reclient.instance.TEST_TRUSTED, shadow_reclient_instance = reclient.instance.TEST_UNTRUSTED, - xcode = xcode.x15main, + xcode = xcode.xcode_default, ) fyi_reclient_comparison_builder( @@ -1594,7 +1594,7 @@ reclient_instance = reclient.instance.TEST_UNTRUSTED, reclient_jobs = 150, shadow_reclient_instance = reclient.instance.TEST_UNTRUSTED, - xcode = xcode.x15main, + xcode = xcode.xcode_default, ) ci.builder(
diff --git a/infra/config/subprojects/chromium/ci/chromium.infra.star b/infra/config/subprojects/chromium/ci/chromium.infra.star index b10e6d0d..99d993fe 100644 --- a/infra/config/subprojects/chromium/ci/chromium.infra.star +++ b/infra/config/subprojects/chromium/ci/chromium.infra.star
@@ -146,12 +146,22 @@ properties = { "$build/avd_packager": { "avd_configs": [ + # google_apis system images + "tools/android/avd/proto/creation/android_28_google_apis_x86.textpb", + "tools/android/avd/proto/creation/android_29_google_apis_x86.textpb", + "tools/android/avd/proto/creation/android_30_google_apis_x86.textpb", + "tools/android/avd/proto/creation/android_31_google_apis_x64.textpb", + "tools/android/avd/proto/creation/android_32_google_apis_x64_foldable.textpb", + "tools/android/avd/proto/creation/android_33_google_apis_x64.textpb", + "tools/android/avd/proto/creation/android_34_google_apis_x64.textpb", + + # google_atd system images "tools/android/avd/proto/creation/android_30_google_atd_x86.textpb", "tools/android/avd/proto/creation/android_30_google_atd_x64.textpb", "tools/android/avd/proto/creation/android_31_google_atd_x64.textpb", "tools/android/avd/proto/creation/android_32_google_atd_x64_foldable.textpb", "tools/android/avd/proto/creation/android_33_google_atd_x64.textpb", - "tools/android/avd/proto/creation/android_34_google_apis_x64.textpb", + # TODO(hypan): Using more specific names for the configs below. "tools/android/avd/proto/creation/generic_android19.textpb", "tools/android/avd/proto/creation/generic_android22.textpb", @@ -160,12 +170,6 @@ "tools/android/avd/proto/creation/generic_android25.textpb", "tools/android/avd/proto/creation/generic_android26.textpb", "tools/android/avd/proto/creation/generic_android27.textpb", - "tools/android/avd/proto/creation/generic_android28.textpb", - "tools/android/avd/proto/creation/generic_android29.textpb", - "tools/android/avd/proto/creation/generic_android30.textpb", - "tools/android/avd/proto/creation/generic_android31.textpb", - "tools/android/avd/proto/creation/generic_android32_foldable.textpb", - "tools/android/avd/proto/creation/generic_android33.textpb", ], "gclient_config": "chromium", "gclient_apply_config": ["android"],
diff --git a/infra/config/subprojects/chromium/ci/chromium.mac.star b/infra/config/subprojects/chromium/ci/chromium.mac.star index 90ff145..84c31be 100644 --- a/infra/config/subprojects/chromium/ci/chromium.mac.star +++ b/infra/config/subprojects/chromium/ci/chromium.mac.star
@@ -56,7 +56,7 @@ def ios_builder(*, name, **kwargs): kwargs.setdefault("sheriff_rotations", sheriff_rotations.IOS) - kwargs.setdefault("xcode", xcode.x15main) + kwargs.setdefault("xcode", xcode.xcode_default) return ci.builder(name = name, **kwargs) ci.builder(
diff --git a/infra/config/subprojects/chromium/ci/chromium.memory.star b/infra/config/subprojects/chromium/ci/chromium.memory.star index 8f5385f..d8897203 100644 --- a/infra/config/subprojects/chromium/ci/chromium.memory.star +++ b/infra/config/subprojects/chromium/ci/chromium.memory.star
@@ -775,5 +775,5 @@ category = "iOS", short_name = "asn", ), - xcode = xcode.x15main, + xcode = xcode.xcode_default, )
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.android.star b/infra/config/subprojects/chromium/try/tryserver.chromium.android.star index 0f893e5..63d47c6 100644 --- a/infra/config/subprojects/chromium/try/tryserver.chromium.android.star +++ b/infra/config/subprojects/chromium/try/tryserver.chromium.android.star
@@ -96,7 +96,6 @@ experiments = { # go/nplus1shardsproposal "chromium.add_one_test_shard": 10, - "chromium.skip_successful_tests": 50, }, main_list_view = "try", tryjob = try_.job(), @@ -175,7 +174,6 @@ # go/nplus1shardsproposal "chromium.add_one_test_shard": 10, "chromium.compilator_can_outlive_parent": 100, - "chromium.skip_successful_tests": 50, }, main_list_view = "try", tryjob = try_.job(), @@ -833,7 +831,6 @@ coverage_test_types = ["unit", "overall"], experiments = { "chromium.add_one_test_shard": 10, - "chromium.skip_successful_tests": 50, }, main_list_view = "try", tryjob = try_.job(), @@ -928,9 +925,6 @@ ], ), builderless = not settings.is_main, - experiments = { - "chromium.skip_successful_tests": 50, - }, main_list_view = "try", siso_enabled = True, tryjob = try_.job(), @@ -958,9 +952,6 @@ builderless = not settings.is_main, cores = 32 if settings.is_main else 16, ssd = True, - experiments = { - "chromium.skip_successful_tests": 50, - }, main_list_view = "try", reclient_jobs = reclient.jobs.HIGH_JOBS_FOR_CQ, siso_enabled = True, @@ -1075,9 +1066,6 @@ ), builderless = not settings.is_main, contact_team_email = "cronet-team@google.com", - experiments = { - "chromium.skip_successful_tests": 50, - }, main_list_view = "try", siso_enabled = True, tryjob = try_.job(),
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.chromiumos.star b/infra/config/subprojects/chromium/try/tryserver.chromium.chromiumos.star index 4adebef..6671c53 100644 --- a/infra/config/subprojects/chromium/try/tryserver.chromium.chromiumos.star +++ b/infra/config/subprojects/chromium/try/tryserver.chromium.chromiumos.star
@@ -169,7 +169,6 @@ experiments = { # go/nplus1shardsproposal "chromium.add_one_test_shard": 10, - "chromium.skip_successful_tests": 50, }, main_list_view = "try", tryjob = try_.job(), @@ -271,9 +270,6 @@ ], ), builderless = not settings.is_main, - experiments = { - "chromium.skip_successful_tests": 50, - }, main_list_view = "try", tryjob = try_.job(), ) @@ -301,9 +297,6 @@ ), compilator = "lacros-amd64-generic-rel-compilator", contact_team_email = "chrome-desktop-engprod@google.com", - experiments = { - "chromium.skip_successful_tests": 50, - }, main_list_view = "try", tryjob = try_.job(), ) @@ -355,9 +348,6 @@ ], ), builderless = not settings.is_main, - experiments = { - "chromium.skip_successful_tests": 50, - }, main_list_view = "try", tryjob = try_.job(), ) @@ -416,9 +406,6 @@ ], ), builderless = not settings.is_main, - experiments = { - "chromium.skip_successful_tests": 50, - }, main_list_view = "try", reclient_jobs = reclient.jobs.HIGH_JOBS_FOR_CQ, tryjob = try_.job(), @@ -519,7 +506,6 @@ experiments = { # go/nplus1shardsproposal "chromium.add_one_test_shard": 10, - "chromium.skip_successful_tests": 50, }, main_list_view = "try", tryjob = try_.job(), @@ -568,7 +554,6 @@ experiments = { # go/nplus1shardsproposal "chromium.add_one_test_shard": 10, - "chromium.skip_successful_tests": 50, }, main_list_view = "try", tryjob = try_.job(),
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.fuchsia.star b/infra/config/subprojects/chromium/try/tryserver.chromium.fuchsia.star index 99358ee7c..690dfb4 100644 --- a/infra/config/subprojects/chromium/try/tryserver.chromium.fuchsia.star +++ b/infra/config/subprojects/chromium/try/tryserver.chromium.fuchsia.star
@@ -234,7 +234,6 @@ # go/nplus1shardsproposal "chromium.add_one_test_shard": 10, "chromium.compilator_can_outlive_parent": 100, - "chromium.skip_successful_tests": 50, }, main_list_view = "try", tryjob = try_.job(),
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star b/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star index 19e6c6d..3d49ab5 100644 --- a/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star +++ b/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star
@@ -264,9 +264,6 @@ branch_selector = branches.selector.LINUX_BRANCHES, executable = "recipe:chromium/fuzz", builderless = not settings.is_main, - experiments = { - "chromium.skip_successful_tests": 50, - }, main_list_view = "try", tryjob = try_.job(), ) @@ -317,7 +314,6 @@ experiments = { # go/nplus1shardsproposal "chromium.add_one_test_shard": 10, - "chromium.skip_successful_tests": 50, }, main_list_view = "try", tryjob = try_.job(), @@ -446,9 +442,6 @@ ], ), builderless = not settings.is_main, - experiments = { - "chromium.skip_successful_tests": 50, - }, main_list_view = "try", reclient_jobs = reclient.jobs.HIGH_JOBS_FOR_CQ, siso_enabled = True, @@ -516,7 +509,6 @@ # go/nplus1shardsproposal "chromium.add_one_test_shard": 10, "chromium.compilator_can_outlive_parent": 100, - "chromium.skip_successful_tests": 50, }, main_list_view = "try", tryjob = try_.job(), @@ -601,6 +593,9 @@ "ci/Linux Chromium OS ASan LSan Tests (1)", ], gn_args = "ci/Linux Chromium OS ASan LSan Builder", + # TODO(crbug.com/1510339): Remove this when memory consumption during links + # is reduced. + cores = 16, ssd = True, # TODO(crbug/1144484): Remove this timeout once we figure out the # regression in compiler or toolchain. @@ -651,9 +646,6 @@ path = "linux_debug", ), ], - experiments = { - "chromium.skip_successful_tests": 50, - }, main_list_view = "try", reclient_jobs = reclient.jobs.HIGH_JOBS_FOR_CQ, tryjob = try_.job(), @@ -763,7 +755,6 @@ experiments = { # go/nplus1shardsproposal "chromium.add_one_test_shard": 10, - "chromium.skip_successful_tests": 50, }, main_list_view = "try", tryjob = try_.job(),
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.mac.star b/infra/config/subprojects/chromium/try/tryserver.chromium.mac.star index bcb94fb..ea4afe07 100644 --- a/infra/config/subprojects/chromium/try/tryserver.chromium.mac.star +++ b/infra/config/subprojects/chromium/try/tryserver.chromium.mac.star
@@ -32,7 +32,7 @@ kwargs.setdefault("builderless", False) kwargs.setdefault("os", os.MAC_DEFAULT) kwargs.setdefault("ssd", None) - kwargs.setdefault("xcode", xcode.x15main) + kwargs.setdefault("xcode", xcode.xcode_default) return try_.builder(name = name, **kwargs) consoles.list_view( @@ -167,7 +167,6 @@ experiments = { # go/nplus1shardsproposal "chromium.add_one_test_shard": 10, - "chromium.skip_successful_tests": 50, }, main_list_view = "try", tryjob = try_.job(), @@ -444,9 +443,6 @@ "ci/Mac Builder (dbg)", ], ), - experiments = { - "chromium.skip_successful_tests": 50, - }, main_list_view = "try", reclient_jobs = reclient.jobs.LOW_JOBS_FOR_CQ, tryjob = try_.job(), @@ -592,7 +588,6 @@ experiments = { # go/nplus1shardsproposal "chromium.add_one_test_shard": 10, - "chromium.skip_successful_tests": 50, }, main_list_view = "try", tryjob = try_.job(), @@ -607,7 +602,7 @@ cpu = cpu.ARM64, ssd = None, main_list_view = "try", - xcode = xcode.x15main, + xcode = xcode.xcode_default, ) # TODO: crbug.com/1502025 - Reduce duplicated configs from the shadow builder. @@ -644,7 +639,7 @@ contact_team_email = "chrome-build-team@google.com", main_list_view = "try", siso_enabled = True, - xcode = xcode.x15main, + xcode = xcode.xcode_default, ) ios_builder(
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.win.star b/infra/config/subprojects/chromium/try/tryserver.chromium.win.star index e373f7f9..3968aca 100644 --- a/infra/config/subprojects/chromium/try/tryserver.chromium.win.star +++ b/infra/config/subprojects/chromium/try/tryserver.chromium.win.star
@@ -92,9 +92,6 @@ executable = "recipe:chromium/fuzz", builderless = False, os = os.WINDOWS_ANY, - experiments = { - "chromium.skip_successful_tests": 50, - }, main_list_view = "try", reclient_jobs = reclient.jobs.HIGH_JOBS_FOR_CQ, tryjob = try_.job(), @@ -125,7 +122,6 @@ # go/nplus1shardsproposal "chromium.add_one_test_shard": 5, "chromium.compilator_can_outlive_parent": 100, - "chromium.skip_successful_tests": 50, }, main_list_view = "try", tryjob = try_.job(),
diff --git a/infra/config/subprojects/goma/goma.star b/infra/config/subprojects/goma/goma.star index b4f7df5..4baf61e0 100644 --- a/infra/config/subprojects/goma/goma.star +++ b/infra/config/subprojects/goma/goma.star
@@ -158,7 +158,7 @@ ), cores = None, os = os.MAC_DEFAULT, - xcode = xcode.x15main, + xcode = xcode.xcode_default, ) fyi_goma_rbe_canary_builder(
diff --git a/infra/config/subprojects/reclient/reclient.star b/infra/config/subprojects/reclient/reclient.star index 9f07faa..9fd269b 100644 --- a/infra/config/subprojects/reclient/reclient.star +++ b/infra/config/subprojects/reclient/reclient.star
@@ -430,7 +430,7 @@ reclient_bootstrap_env = { "GLOG_vmodule": "bridge*=2", }, - xcode = xcode.x14main, + xcode = xcode.xcode_default, ) fyi_reclient_staging_builder( @@ -467,7 +467,7 @@ reclient_bootstrap_env = { "GLOG_vmodule": "bridge*=2", }, - xcode = xcode.x14main, + xcode = xcode.xcode_default, ) fyi_reclient_staging_builder(
diff --git a/infra/config/subprojects/webrtc/webrtc.fyi.star b/infra/config/subprojects/webrtc/webrtc.fyi.star index 3a7ab14..8c12ca0 100644 --- a/infra/config/subprojects/webrtc/webrtc.fyi.star +++ b/infra/config/subprojects/webrtc/webrtc.fyi.star
@@ -348,7 +348,7 @@ os = os.WINDOWS_DEFAULT, ) -# Builders run on the default Win OS version offered +# Builders run on the default Mac OS version offered # in the Chrome infra however the tasks will be sharded # to swarming bots with appropriate OS using swarming # dimensions. @@ -368,8 +368,8 @@ ), build_gs_bucket = "chromium-webrtc", ), - os = os.MAC_ANY, - xcode = xcode.x15main, + os = os.MAC_DEFAULT, + xcode = xcode.xcode_default, ) builder( @@ -388,6 +388,6 @@ ), build_gs_bucket = "chromium-webrtc", ), - os = os.MAC_ANY, - xcode = xcode.x15main, + os = os.MAC_DEFAULT, + xcode = xcode.xcode_default, )
diff --git a/infra/config/targets/basic_suites.star b/infra/config/targets/basic_suites.star index 07e1b306..746fcd20 100644 --- a/infra/config/targets/basic_suites.star +++ b/infra/config/targets/basic_suites.star
@@ -39,23 +39,6 @@ ) targets.legacy_basic_suite( - name = "android_ddready_vr_gtests", - tests = { - "chrome_public_test_vr_apk-ddready-cardboard": targets.legacy_test_config( - swarming = targets.swarming( - shards = 2, - ), - ), - "chrome_public_test_vr_apk-ddready-ddview": targets.legacy_test_config( - swarming = targets.swarming( - shards = 4, - ), - ), - "chrome_public_test_vr_apk-ddready-don-enabled": targets.legacy_test_config(), - }, -) - -targets.legacy_basic_suite( name = "android_emulator_specific_chrome_public_tests", tests = { "chrome_public_test_apk": targets.legacy_test_config( @@ -4914,10 +4897,6 @@ name = "vr_android_specific_chromium_tests", tests = { "chrome_public_test_vr_apk": targets.legacy_test_config( - args = [ - "--shared-prefs-file=//chrome/android/shared_preference_files/test/vr_cardboard_skipdon_setupcomplete.json", - "--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk", - ], swarming = targets.swarming( shards = 2, ),
diff --git a/infra/config/targets/compound_suites.star b/infra/config/targets/compound_suites.star index 4d8907a5..2e73326 100644 --- a/infra/config/targets/compound_suites.star +++ b/infra/config/targets/compound_suites.star
@@ -16,7 +16,7 @@ basic_suites = [ "android_trichrome_smoke_tests", "android_ar_gtests", - "android_ddready_vr_gtests", + "vr_android_specific_chromium_tests", ], ) @@ -62,7 +62,7 @@ name = "android_oreo_gtests", basic_suites = [ "android_ar_gtests", - "android_ddready_vr_gtests", + "vr_android_specific_chromium_tests", "android_monochrome_smoke_tests", "android_oreo_standard_gtests", "android_smoke_tests", @@ -84,7 +84,7 @@ name = "android_pie_gtests", basic_suites = [ "android_ar_gtests", - "android_ddready_vr_gtests", + "vr_android_specific_chromium_tests", "android_monochrome_smoke_tests", "android_smoke_tests", "chromium_tracing_gtests",
diff --git a/infra/config/targets/mixins.star b/infra/config/targets/mixins.star index 4f3bc51653..6c75a8a 100644 --- a/infra/config/targets/mixins.star +++ b/infra/config/targets/mixins.star
@@ -1440,14 +1440,6 @@ ), ) -targets.mixin( - name = "vr_instrumentation_test", - args = [ - "--remove-system-package=com.google.vr.vrcore", - "--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk", - ], -) - # Pixel 2 targets.mixin( name = "walleye",
diff --git a/internal b/internal index eff5a45..2f4e35e 160000 --- a/internal +++ b/internal
@@ -1 +1 @@ -Subproject commit eff5a4585a80e2b59b057dd145e5931c768ebc6d +Subproject commit 2f4e35e9c81b8c737b0a03b3d28d374831d66aff
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd index b24a935..29b46c6 100644 --- a/ios/chrome/app/strings/ios_strings.grd +++ b/ios/chrome/app/strings/ios_strings.grd
@@ -2089,6 +2089,24 @@ <message name="IDS_IOS_OMNIBOX_PEDAL_SUBTITLE_VIEW_CHROME_HISTORY" desc="Subtitle for the View Your Chrome History acceleration pedal in the omnibox that should correspond to the path to History"> Menu → History </message> + <message name="IDS_IOS_OMNIBOX_POSITION_PROMO_TITLE" desc="Title for the omnibox position choice promo screen. (Title case)"> + Address Bar Position + </message> + <message name="IDS_IOS_OMNIBOX_POSITION_PROMO_IPH_SUBTITLE" desc="Subtitle for the omnibox position choice screen in a fullscreen promo."> + Switch your address bar from the top to the bottom for a customized browsing experience. + </message> + <message name="IDS_IOS_OMNIBOX_POSITION_PROMO_FRE_SUBTITLE" desc="Subtitle for the omnibox position choice screen in the first run experience."> + Switch your address bar to the top or bottom for a customized browsing experience. + </message> + <message name="IDS_IOS_OMNIBOX_POSITION_PROMO_VALIDATE" desc="Text in the validation button of the omnibox position choice screen promo. (Title case)"> + Set Position + </message> + <message name="IDS_IOS_OMNIBOX_POSITION_PROMO_DISCARD" desc="Text in the discard button of the omnibox position choice screen promo. (Title case)"> + No Thanks + </message> + <message name="IDS_IOS_OMNIBOX_POSITION_PROMO_SKIP" desc="Text in the skip button of the omnibox position choice screen promo. (Title case)"> + Skip + </message> <message name="IDS_IOS_OPEN_TABS_LAST_USED" desc="Last used timestamp label [Length: 20em] [iOS only]"> Last synced: <ph name="LAST_USED_TIME">$1<ex>3 mins ago</ex></ph> </message>
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_OMNIBOX_POSITION_PROMO_DISCARD.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_OMNIBOX_POSITION_PROMO_DISCARD.png.sha1 new file mode 100644 index 0000000..ef29670 --- /dev/null +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_OMNIBOX_POSITION_PROMO_DISCARD.png.sha1
@@ -0,0 +1 @@ +522b0a396ba4ab867112da8541602455c0b2706d \ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_OMNIBOX_POSITION_PROMO_FRE_SUBTITLE.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_OMNIBOX_POSITION_PROMO_FRE_SUBTITLE.png.sha1 new file mode 100644 index 0000000..ef29670 --- /dev/null +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_OMNIBOX_POSITION_PROMO_FRE_SUBTITLE.png.sha1
@@ -0,0 +1 @@ +522b0a396ba4ab867112da8541602455c0b2706d \ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_OMNIBOX_POSITION_PROMO_IPH_SUBTITLE.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_OMNIBOX_POSITION_PROMO_IPH_SUBTITLE.png.sha1 new file mode 100644 index 0000000..9a54c9bc --- /dev/null +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_OMNIBOX_POSITION_PROMO_IPH_SUBTITLE.png.sha1
@@ -0,0 +1 @@ +71280755d86ed4cef9c9ba80df6611c60b5b20fc \ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_OMNIBOX_POSITION_PROMO_SKIP.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_OMNIBOX_POSITION_PROMO_SKIP.png.sha1 new file mode 100644 index 0000000..19a19b90 --- /dev/null +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_OMNIBOX_POSITION_PROMO_SKIP.png.sha1
@@ -0,0 +1 @@ +035fa61f68d30166d1122c2485a94d6dd69f1abd \ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_OMNIBOX_POSITION_PROMO_TITLE.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_OMNIBOX_POSITION_PROMO_TITLE.png.sha1 new file mode 100644 index 0000000..ef29670 --- /dev/null +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_OMNIBOX_POSITION_PROMO_TITLE.png.sha1
@@ -0,0 +1 @@ +522b0a396ba4ab867112da8541602455c0b2706d \ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_OMNIBOX_POSITION_PROMO_VALIDATE.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_OMNIBOX_POSITION_PROMO_VALIDATE.png.sha1 new file mode 100644 index 0000000..ef29670 --- /dev/null +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_OMNIBOX_POSITION_PROMO_VALIDATE.png.sha1
@@ -0,0 +1 @@ +522b0a396ba4ab867112da8541602455c0b2706d \ No newline at end of file
diff --git a/ios/chrome/browser/ui/content_suggestions/BUILD.gn b/ios/chrome/browser/ui/content_suggestions/BUILD.gn index c7b214b2..a13453a 100644 --- a/ios/chrome/browser/ui/content_suggestions/BUILD.gn +++ b/ios/chrome/browser/ui/content_suggestions/BUILD.gn
@@ -49,6 +49,7 @@ "//components/commerce/core:shopping_service", "//components/favicon/core", "//components/favicon/ios", + "//components/feature_engagement/public", "//components/feed/core/shared_prefs:feed_shared_prefs", "//components/feed/core/v2/public/ios:feed_ios_public", "//components/history/core/browser", @@ -76,6 +77,7 @@ "//ios/chrome/browser/discover_feed/model:discover_feed_factory", "//ios/chrome/browser/drag_and_drop/model", "//ios/chrome/browser/favicon", + "//ios/chrome/browser/feature_engagement/model", "//ios/chrome/browser/intents:intents_donation_helper", "//ios/chrome/browser/metrics/model:metrics_internal", "//ios/chrome/browser/net/model:crurl", @@ -412,6 +414,7 @@ "//base", "//base/test:test_support", "//build:branding_buildflags", + "//components/feature_engagement/public", "//components/feed/core/shared_prefs:feed_shared_prefs", "//components/feed/core/v2/public/ios:feed_ios_public", "//components/segmentation_platform/public",
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm index cb448c4..a7234da 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm
@@ -20,6 +20,8 @@ #import "base/time/time.h" #import "components/commerce/core/shopping_service.h" #import "components/favicon/ios/web_favicon_driver.h" +#import "components/feature_engagement/public/event_constants.h" +#import "components/feature_engagement/public/tracker.h" #import "components/feed/core/v2/public/ios/pref_names.h" #import "components/history/core/browser/features.h" #import "components/ntp_tiles/features.h" @@ -45,6 +47,7 @@ #import "ios/chrome/app/application_delegate/app_state.h" #import "ios/chrome/app/application_delegate/app_state_observer.h" #import "ios/chrome/browser/default_browser/model/utils.h" +#import "ios/chrome/browser/feature_engagement/model/tracker_factory.h" #import "ios/chrome/browser/intents/intents_donation_helper.h" #import "ios/chrome/browser/ntp/model/new_tab_page_tab_helper.h" #import "ios/chrome/browser/ntp/model/set_up_list.h" @@ -674,7 +677,6 @@ [self.dispatcher showHistory]; break; case NTPCollectionShortcutTypeWhatsNew: - SetWhatsNewUsed(self.promosManager); [self.dispatcher showWhatsNew]; break; case NTPCollectionShortcutTypeCount: @@ -1203,6 +1205,18 @@ return NO; } + // TODO(crbug.com/1510484): The FET is not ready upon app launch in the NTP. + // Consequently, we must load a URL first and then load the NTP where the FET + // becomes ready. + feature_engagement::Tracker* tracker = + feature_engagement::TrackerFactory::GetForBrowserState( + self.browser->GetBrowserState()); + DCHECK(tracker); + if (!tracker->WouldTriggerHelpUI( + feature_engagement::kIPHWhatsNewUpdatedFeature)) { + return NO; + } + AuthenticationService* authService = AuthenticationServiceFactory::GetForBrowserState( self.browser->GetBrowserState());
diff --git a/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm b/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm index cbd2a59..bf4c9ee 100644 --- a/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm +++ b/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm
@@ -5,8 +5,10 @@ #import "base/apple/foundation_util.h" #import "base/functional/bind.h" #import "base/ios/ios_util.h" +#import "base/strings/stringprintf.h" #import "base/strings/sys_string_conversions.h" #import "build/branding_buildflags.h" +#import "components/feature_engagement/public/feature_constants.h" #import "components/feed/core/v2/public/ios/pref_names.h" #import "components/strings/grit/components_strings.h" #import "ios/chrome/browser/flags/chrome_switches.h" @@ -126,9 +128,7 @@ + (void)setUpForTestCase { [super setUpForTestCase]; - // Mark What's New as already-seen so it does not override Bookmarks. - [ChromeEarlGrey setUserDefaultsObject:@YES forKey:kWhatsNewUsageEntryKey]; - [ChromeEarlGrey setUserDefaultsObject:@YES forKey:kWhatsNewM116UsageEntryKey]; + [NTPHomeTestCase setUpHelper]; } @@ -143,9 +143,6 @@ + (void)tearDown { [self closeAllTabs]; - // Clean up What's New already-seen. - [ChromeEarlGrey removeUserDefaultsObjectForKey:kWhatsNewUsageEntryKey]; - [ChromeEarlGrey setUserDefaultsObject:@YES forKey:kWhatsNewM116UsageEntryKey]; [super tearDown]; } @@ -170,6 +167,14 @@ if ([self isRunningTest:@selector(DISABLED_testMinimumHeight)]) { config.features_enabled.push_back(kMagicStack); } + + if ([self isRunningTest:@selector(testCollectionShortcuts)]) { + // This ensures that the test will not fail when What's New is updated. + config.additional_args.push_back(base::StringPrintf( + "--disable-features=%s", + feature_engagement::kIPHWhatsNewUpdatedFeature.name)); + } + return config; } @@ -203,6 +208,10 @@ // Tests that the collections shortcut are displayed and working. - (void)testCollectionShortcuts { + AppLaunchConfiguration config = self.appConfigurationForTestCase; + config.relaunch_policy = ForceRelaunchByCleanShutdown; + [[AppLaunchManager sharedManager] ensureAppLaunchedWithConfiguration:config]; + // Close NTP and reopen. [ChromeEarlGrey closeAllTabs]; [ChromeEarlGrey openNewTab]; @@ -272,10 +281,20 @@ - (void)MAYBE_testCollectionShortcutsWithWhatsNew { AppLaunchConfiguration config = self.appConfigurationForTestCase; config.relaunch_policy = ForceRelaunchByCleanShutdown; - [ChromeEarlGrey setUserDefaultsObject:@NO forKey:kWhatsNewM116UsageEntryKey]; - + // This ensures that the test will not fail when What's New has already been + // opened during testing. + config.additional_args.push_back( + base::StringPrintf("--enable-features=%s:chosen_feature/%s", + feature_engagement::kIPHDemoMode.name, + feature_engagement::kIPHWhatsNewUpdatedFeature.name)); [[AppLaunchManager sharedManager] ensureAppLaunchedWithConfiguration:config]; + // Navigate + // TODO(crbug.com/1510484): The FET is not ready upon app launch in the NTP. + // Consequently, close NTP and reopen the NTP where the FET becomes ready. + [ChromeEarlGrey closeAllTabs]; + [ChromeEarlGrey openNewTab]; + // Check the What's New. [[EarlGrey selectElementWithMatcher:chrome_test_util::ButtonWithAccessibilityLabelId(
diff --git a/ios/chrome/browser/ui/first_run/omnibox_position/omnibox_position_choice_view_controller.mm b/ios/chrome/browser/ui/first_run/omnibox_position/omnibox_position_choice_view_controller.mm index c179e21a..22a0315 100644 --- a/ios/chrome/browser/ui/first_run/omnibox_position/omnibox_position_choice_view_controller.mm +++ b/ios/chrome/browser/ui/first_run/omnibox_position/omnibox_position_choice_view_controller.mm
@@ -14,6 +14,13 @@ #import "ios/chrome/grit/ios_strings.h" #import "ui/base/l10n/l10n_util_mac.h" +namespace { + +/// Leading and trailing padding for the `addressBarView`. +constexpr CGFloat kAddressViewHorizontalPadding = 11; + +} // namespace + @implementation OmniboxPositionChoiceViewController { /// The view for the top address bar preference option. AddressBarOptionView* _topAddressBar; @@ -46,16 +53,23 @@ // TODO(crbug.com/1503638): Implement this and remove placeholder text. self.view.accessibilityIdentifier = first_run::kFirstRunOmniboxPositionChoiceScreenAccessibilityIdentifier; + self.bannerName = @"default_browser_screen_banner"; - self.titleText = @"**Tailor to Your Needs**"; - self.subtitleText = @"**Decide the position of the search bar to tailor your " - @"needs and browsing habits**"; + + self.titleHorizontalMargin = 0; + self.titleText = l10n_util::GetNSString(IDS_IOS_OMNIBOX_POSITION_PROMO_TITLE); + self.primaryActionString = + l10n_util::GetNSString(IDS_IOS_OMNIBOX_POSITION_PROMO_VALIDATE); if (_isFirstRun) { - self.primaryActionString = @"**Finish**"; - self.secondaryActionString = @"**Skip**"; + self.subtitleText = + l10n_util::GetNSString(IDS_IOS_OMNIBOX_POSITION_PROMO_FRE_SUBTITLE); + self.secondaryActionString = + l10n_util::GetNSString(IDS_IOS_OMNIBOX_POSITION_PROMO_SKIP); } else { - self.primaryActionString = @"**Confirm**"; - self.secondaryActionString = @"**No, thanks**"; + self.subtitleText = + l10n_util::GetNSString(IDS_IOS_OMNIBOX_POSITION_PROMO_IPH_SUBTITLE); + self.secondaryActionString = + l10n_util::GetNSString(IDS_IOS_OMNIBOX_POSITION_PROMO_DISCARD); } [_topAddressBar addTarget:self @@ -77,9 +91,11 @@ addressBarView.distribution = UIStackViewDistributionFillEqually; [self.specificContentView addSubview:addressBarView]; - AddSameConstraintsToSides( - self.specificContentView, addressBarView, - LayoutSides::kTop | LayoutSides::kLeading | LayoutSides::kTrailing); + AddSameConstraintsToSidesWithInsets( + addressBarView, self.specificContentView, + LayoutSides::kTop | LayoutSides::kLeading | LayoutSides::kTrailing, + NSDirectionalEdgeInsetsMake(0, kAddressViewHorizontalPadding, 0, + kAddressViewHorizontalPadding)); [NSLayoutConstraint activateConstraints:@[ [self.specificContentView.bottomAnchor
diff --git a/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_mediator.mm b/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_mediator.mm index a099b92..1d56588 100644 --- a/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_mediator.mm +++ b/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_mediator.mm
@@ -246,6 +246,11 @@ feature_engagement::kIPHBadgedReadingListFeature); } + if (self.whatsNewDestination.badge != BadgeTypeNone) { + _engagementTracker->Dismissed( + feature_engagement::kIPHWhatsNewUpdatedFeature); + } + _engagementTracker = nullptr; } @@ -1711,7 +1716,10 @@ } return self.settingsDestination; case overflow_menu::Destination::WhatsNew: - if (!WasWhatsNewUsed()) { + // Set the new label badge. + if (!WasWhatsNewUsed() && self.engagementTracker && + self.engagementTracker->ShouldTriggerHelpUI( + feature_engagement::kIPHWhatsNewUpdatedFeature)) { // Highlight What's New with a badge if it was never used before. self.whatsNewDestination.badge = BadgeTypeNew; } @@ -1761,10 +1769,6 @@ _engagementTracker->NotifyEvent( feature_engagement::events::kBlueDotPromoOverflowMenuDismissed); } - - if (!WasWhatsNewUsed()) { - SetWhatsNewUsed(self.promosManager); - } } #pragma mark - OverflowMenuActionProvider @@ -2149,14 +2153,6 @@ // Dismisses the menu and opens What's New. - (void)openWhatsNew { - if (!WasWhatsNewUsed()) { - SetWhatsNewUsed(self.promosManager); - } - - if (self.engagementTracker) { - self.engagementTracker->NotifyEvent( - feature_engagement::events::kViewedWhatsNew); - } [self dismissMenu]; [self.browserCoordinatorHandler showWhatsNew]; }
diff --git a/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_mediator_unittest.mm b/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_mediator_unittest.mm index 3b08ee2..0fa212ec 100644 --- a/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_mediator_unittest.mm +++ b/ios/chrome/browser/ui/popup_menu/overflow_menu/overflow_menu_mediator_unittest.mm
@@ -444,23 +444,22 @@ UIViewController* baseViewController_; translate::LanguageDetectionModel language_detection_model_; TestingPrefServiceSimple pref_service_; + feature_engagement::test::MockTracker tracker_; }; // Tests that the feature engagement tracker get notified when the mediator is // disconnected and the tracker wants the notification badge displayed. TEST_F(OverflowMenuMediatorTest, TestFeatureEngagementDisconnect) { CreateMediator(/*is_incognito=*/NO); - feature_engagement::test::MockTracker tracker; - EXPECT_CALL(tracker, ShouldTriggerHelpUI(testing::_)) + EXPECT_CALL(tracker_, ShouldTriggerHelpUI(testing::_)) .WillRepeatedly(Return(true)); - mediator_.engagementTracker = &tracker; + mediator_.engagementTracker = &tracker_; // Force model update. mediator_.model = model_; // There may be one or more Tools Menu items that use engagement trackers. - EXPECT_CALL(tracker, Dismissed(testing::_)).Times(testing::AtLeast(1)); - [mediator_ disconnect]; + EXPECT_CALL(tracker_, Dismissed(testing::_)).Times(testing::AtLeast(1)); } // Tests that the mediator is returning the right number of items and sections @@ -805,11 +804,6 @@ // Create Mediator and DO NOT set the Tracker on it. CreateMediator(/*is_incognito=*/NO); - std::unique_ptr<MockPromosManager> promos_manager = - std::make_unique<MockPromosManager>(); - EXPECT_CALL(*promos_manager, DeregisterPromo(testing::_)); - mediator_.promosManager = promos_manager.get(); - // Force model update. mediator_.model = model_; @@ -928,6 +922,11 @@ web_state_->SetCurrentURL(kUrl); CreateBrowserStatePrefs(); CreateMediator(/*is_incognito=*/NO); + // Show the new label badge for What's New. + ON_CALL(tracker_, ShouldTriggerHelpUI(testing::Ref( + feature_engagement::kIPHWhatsNewUpdatedFeature))) + .WillByDefault(testing::Return(true)); + mediator_.engagementTracker = &tracker_; SetUpActiveWebState(); mediator_.webStateList = browser_->GetWebStateList(); mediator_.webContentAreaOverlayPresenter = OverlayPresenter::FromBrowser( @@ -959,6 +958,11 @@ TEST_F(OverflowMenuMediatorTest, TestPromotedDestinationsWhenNoHistoryUsageRanking) { CreateMediator(/*is_incognito=*/NO); + // Show the new label badge for What's New. + ON_CALL(tracker_, ShouldTriggerHelpUI(testing::Ref( + feature_engagement::kIPHWhatsNewUpdatedFeature))) + .WillByDefault(testing::Return(true)); + mediator_.engagementTracker = &tracker_; syncer::MockSyncService syncService; ON_CALL(syncService, GetUserActionableError()) .WillByDefault(
diff --git a/ios/chrome/browser/ui/whats_new/BUILD.gn b/ios/chrome/browser/ui/whats_new/BUILD.gn index 2035652..06a12b9c 100644 --- a/ios/chrome/browser/ui/whats_new/BUILD.gn +++ b/ios/chrome/browser/ui/whats_new/BUILD.gn
@@ -27,8 +27,10 @@ deps = [ ":util", "//base", + "//components/feature_engagement/public", "//ios/chrome/app/strings", "//ios/chrome/browser/default_browser/model:utils", + "//ios/chrome/browser/feature_engagement/model", "//ios/chrome/browser/shared/coordinator/chrome_coordinator", "//ios/chrome/browser/shared/model/browser", "//ios/chrome/browser/shared/public/commands",
diff --git a/ios/chrome/browser/ui/whats_new/promo/BUILD.gn b/ios/chrome/browser/ui/whats_new/promo/BUILD.gn index 3d78b46d..793a329 100644 --- a/ios/chrome/browser/ui/whats_new/promo/BUILD.gn +++ b/ios/chrome/browser/ui/whats_new/promo/BUILD.gn
@@ -12,6 +12,7 @@ deps = [ "//components/feature_engagement/public", "//ios/chrome/browser/default_browser/model:utils", + "//ios/chrome/browser/feature_engagement/model", "//ios/chrome/browser/promos_manager", "//ios/chrome/browser/promos_manager:constants", "//ios/chrome/browser/promos_manager:features",
diff --git a/ios/chrome/browser/ui/whats_new/promo/whats_new_promo_display_handler.mm b/ios/chrome/browser/ui/whats_new/promo/whats_new_promo_display_handler.mm index 508beb6..aeacebd 100644 --- a/ios/chrome/browser/ui/whats_new/promo/whats_new_promo_display_handler.mm +++ b/ios/chrome/browser/ui/whats_new/promo/whats_new_promo_display_handler.mm
@@ -26,13 +26,7 @@ } - (void)handleDisplay { - // Don't show the promo if What's New has been previously open. - if (WasWhatsNewUsed()) { - return; - } - DCHECK(self.handler); - SetWhatsNewUsed(_promosManager); base::RecordAction(base::UserMetricsAction("WhatsNew.Promo.Displayed")); [self.handler showWhatsNewPromo]; }
diff --git a/ios/chrome/browser/ui/whats_new/promo/whats_new_scene_agent.mm b/ios/chrome/browser/ui/whats_new/promo/whats_new_scene_agent.mm index 8d8c4ea..7943d59 100644 --- a/ios/chrome/browser/ui/whats_new/promo/whats_new_scene_agent.mm +++ b/ios/chrome/browser/ui/whats_new/promo/whats_new_scene_agent.mm
@@ -36,9 +36,12 @@ transitionedToActivationLevel:(SceneActivationLevel)level { switch (level) { case SceneActivationLevelForegroundActive: { - if (ShouldRegisterWhatsNewPromo()) { - [self registerPromoForSingleDisplay]; + if (WasWhatsNewUsed()) { + return; } + DCHECK(self.promosManager); + self.promosManager->RegisterPromoForContinuousDisplay( + promos_manager::Promo::WhatsNew); break; } case SceneActivationLevelUnattached: @@ -59,16 +62,4 @@ } } -#pragma mark - Private - -// Register the What's New promo for a single display in the promo manager. -- (void)registerPromoForSingleDisplay { - DCHECK(self.promosManager); - - self.promosManager->RegisterPromoForSingleDisplay( - promos_manager::Promo::WhatsNew); - - setWhatsNewPromoRegistration(); -} - @end
diff --git a/ios/chrome/browser/ui/whats_new/promo/whats_new_scene_agent_unittest.mm b/ios/chrome/browser/ui/whats_new/promo/whats_new_scene_agent_unittest.mm index 672f973..98af144 100644 --- a/ios/chrome/browser/ui/whats_new/promo/whats_new_scene_agent_unittest.mm +++ b/ios/chrome/browser/ui/whats_new/promo/whats_new_scene_agent_unittest.mm
@@ -4,7 +4,6 @@ #import "ios/chrome/browser/ui/whats_new/promo/whats_new_scene_agent.h" -#import "base/test/scoped_feature_list.h" #import "base/test/task_environment.h" #import "ios/chrome/app/application_delegate/app_state.h" #import "ios/chrome/app/application_delegate/fake_startup_information.h" @@ -21,37 +20,6 @@ #import "third_party/ocmock/OCMock/OCMock.h" #import "third_party/ocmock/gtest_support.h" -namespace { - -void UpdateWhatsNewDaysAfterFre(int num_day) { - NSTimeInterval days = num_day * 24 * 60 * 60; - NSDate* date = [NSDate dateWithTimeIntervalSinceNow:-days]; - [[NSUserDefaults standardUserDefaults] setObject:date - forKey:kWhatsNewDaysAfterFre]; -} - -void UpdateWhatsNewLaunchesAfterFre(int num_lanches) { - [[NSUserDefaults standardUserDefaults] setInteger:num_lanches - forKey:kWhatsNewLaunchesAfterFre]; -} - -void ClearWhatsNewUserData() { - [[NSUserDefaults standardUserDefaults] - removeObjectForKey:kWhatsNewDaysAfterFre]; - [[NSUserDefaults standardUserDefaults] - removeObjectForKey:kWhatsNewLaunchesAfterFre]; - [[NSUserDefaults standardUserDefaults] - removeObjectForKey:kWhatsNewPromoRegistrationKey]; - [[NSUserDefaults standardUserDefaults] - removeObjectForKey:kWhatsNewM116PromoRegistrationKey]; - [[NSUserDefaults standardUserDefaults] - removeObjectForKey:kWhatsNewUsageEntryKey]; - [[NSUserDefaults standardUserDefaults] - removeObjectForKey:kWhatsNewM116UsageEntryKey]; -} - -} // namespace - class WhatsNewSceneAgentTest : public PlatformTest { public: WhatsNewSceneAgentTest() : PlatformTest() { @@ -73,7 +41,10 @@ agent_.sceneState = scene_state_; } - void TearDown() override { ClearWhatsNewUserData(); } + void TearDown() override { + [[NSUserDefaults standardUserDefaults] + removeObjectForKey:kWhatsNewM116UsageEntryKey]; + } protected: WhatsNewSceneAgent* agent_; @@ -82,76 +53,23 @@ SceneState* scene_state_; base::test::TaskEnvironment task_environment_; std::unique_ptr<MockPromosManager> promos_manager_; - base::test::ScopedFeatureList scoped_feature_list_; }; -// Tests that the What's New promo did not register in the promo manager when -// the conditions aren't met. -TEST_F(WhatsNewSceneAgentTest, TestWhatsNewNoPromoRegistration) { - EXPECT_CALL(*promos_manager_.get(), - RegisterPromoForSingleDisplay(promos_manager::Promo::WhatsNew)) - .Times(0); - - // Set the number of day after FRE to 0. - UpdateWhatsNewDaysAfterFre(0); - // Set the number of launches to 0. - UpdateWhatsNewLaunchesAfterFre(0); - - scene_state_.activationLevel = SceneActivationLevelForegroundActive; -} - -// Tests that the What's New promo registers in the promo manager after 6 days -// have been recorded. -// TODO(crbug.com/1508296): test consistently fail, re-enable when fixed. -TEST_F(WhatsNewSceneAgentTest, - DISABLED_TestWhatsNewPromoRegistrationWith6Days) { - EXPECT_CALL(*promos_manager_.get(), - RegisterPromoForSingleDisplay(promos_manager::Promo::WhatsNew)) +// Tests that the What's New promo continuous registers in the promo manager. +TEST_F(WhatsNewSceneAgentTest, TestWhatsNewPromoRegistration) { + EXPECT_CALL(*promos_manager_.get(), RegisterPromoForContinuousDisplay( + promos_manager::Promo::WhatsNew)) .Times(1); - - // Set the number of day after FRE to 6. - UpdateWhatsNewDaysAfterFre(6); scene_state_.activationLevel = SceneActivationLevelForegroundActive; } -// Tests that the What's New promo did not register in the promo manager after 4 -// days have been recorded. -// TODO(crbug.com/1508296): test consistently fail, re-enable when fixed. -TEST_F(WhatsNewSceneAgentTest, - DISABLED_TestWhatsNewPromoNoRegistrationWith4Days) { - EXPECT_CALL(*promos_manager_.get(), - RegisterPromoForSingleDisplay(promos_manager::Promo::WhatsNew)) +// Tests that the What's New promo did not register in the promo manager if the +// user viewed What's New M116 prior to the migration to FET. +TEST_F(WhatsNewSceneAgentTest, TestWhatsNewDoesNotRegisterWhenDefaultM116Used) { + [[NSUserDefaults standardUserDefaults] setBool:YES + forKey:kWhatsNewM116UsageEntryKey]; + EXPECT_CALL(*promos_manager_.get(), RegisterPromoForContinuousDisplay( + promos_manager::Promo::WhatsNew)) .Times(0); - - // Set the number of day after FRE to 4. - UpdateWhatsNewDaysAfterFre(4); - scene_state_.activationLevel = SceneActivationLevelForegroundActive; -} - -// Tests that the What's New promo registers in the promo manager after 6 -// launches have been recorded. -// TODO(crbug.com/1508296): test consistently fail, re-enable when fixed. -TEST_F(WhatsNewSceneAgentTest, - DISABLED_TestWhatsNewPromoRegistrationWith6Launches) { - EXPECT_CALL(*promos_manager_.get(), - RegisterPromoForSingleDisplay(promos_manager::Promo::WhatsNew)) - .Times(1); - - // Set the number of launches to 6. - UpdateWhatsNewLaunchesAfterFre(6); - scene_state_.activationLevel = SceneActivationLevelForegroundActive; -} - -// Tests that the What's New promo did not register in the promo manager after 3 -// launches have been recorded. -// TODO(crbug.com/1508296): test consistently fail, re-enable when fixed. -TEST_F(WhatsNewSceneAgentTest, - DISABLED_TestWhatsNewPromoNoRegistrationWith3Launches) { - EXPECT_CALL(*promos_manager_.get(), - RegisterPromoForSingleDisplay(promos_manager::Promo::WhatsNew)) - .Times(0); - - // Set the number of launches to 3. - UpdateWhatsNewLaunchesAfterFre(3); scene_state_.activationLevel = SceneActivationLevelForegroundActive; }
diff --git a/ios/chrome/browser/ui/whats_new/whats_new_coordinator.mm b/ios/chrome/browser/ui/whats_new/whats_new_coordinator.mm index 1c4594d..bdecca5 100644 --- a/ios/chrome/browser/ui/whats_new/whats_new_coordinator.mm +++ b/ios/chrome/browser/ui/whats_new/whats_new_coordinator.mm
@@ -9,6 +9,9 @@ #import "base/metrics/histogram_functions.h" #import "base/metrics/user_metrics.h" #import "base/time/time.h" +#import "components/feature_engagement/public/event_constants.h" +#import "components/feature_engagement/public/tracker.h" +#import "ios/chrome/browser/feature_engagement/model/tracker_factory.h" #import "ios/chrome/browser/shared/public/commands/application_commands.h" #import "ios/chrome/browser/shared/public/commands/browser_coordinator_commands.h" #import "ios/chrome/browser/shared/public/commands/command_dispatcher.h" @@ -55,6 +58,12 @@ #pragma mark - ChromeCoordinator - (void)start { + feature_engagement::Tracker* tracker = + feature_engagement::TrackerFactory::GetForBrowserState( + self.browser->GetBrowserState()); + DCHECK(tracker); + tracker->NotifyEvent(feature_engagement::events::kViewedWhatsNew); + self.clicksOnWhatsNewItemsCount = 0; base::RecordAction(base::UserMetricsAction("WhatsNew.Started")); self.mediator = [[WhatsNewMediator alloc] init];
diff --git a/ios/chrome/browser/ui/whats_new/whats_new_util.h b/ios/chrome/browser/ui/whats_new/whats_new_util.h index 184f96b..a290f6a 100644 --- a/ios/chrome/browser/ui/whats_new/whats_new_util.h +++ b/ios/chrome/browser/ui/whats_new/whats_new_util.h
@@ -9,23 +9,10 @@ #import "base/feature_list.h" #import "ios/chrome/browser/ui/whats_new/data_source/whats_new_item.h" -class PromosManager; - // Returns whether What's New was used in the overflow menu. This is used to // decide on the location of the What's New entry point in the overflow menu. bool WasWhatsNewUsed(); -// Set that What's New was used in the overflow menu. -void SetWhatsNewUsed(PromosManager* promosManager); - -// Set that What's New has been registered in the promo manager. -void setWhatsNewPromoRegistration(); - -// Returns whether What's New promo should be registered in the promo manager. -// This is used to avoid registering the What's New promo in the promo manager -// more than once. -bool ShouldRegisterWhatsNewPromo(); - // Returns a string version of WhatsNewType. const char* WhatsNewTypeToString(WhatsNewType type);
diff --git a/ios/chrome/browser/ui/whats_new/whats_new_util.mm b/ios/chrome/browser/ui/whats_new/whats_new_util.mm index aecd3e2..8146efe 100644 --- a/ios/chrome/browser/ui/whats_new/whats_new_util.mm +++ b/ios/chrome/browser/ui/whats_new/whats_new_util.mm
@@ -14,98 +14,31 @@ namespace { -// Time interval of 6 days. This is used to calculate 6 days after FRE to -// trigger What's New Promo. -const NSTimeInterval kSixDays = 6 * 24 * 60 * 60; - -// Returns whether today is the 6th and more day after the FRE. This is used to -// decide to register What's New promo in the promo manager or not. -bool IsSixDaysAfterFre() { - // TODO(crbug.com/1462404): Clean up unused user defaults and find a better - // solution to update existing user defaults for future versions of What's - // New. - NSString* const daysAfterFre = kWhatsNewM116DaysAfterFre; - NSDate* startDate = - [[NSUserDefaults standardUserDefaults] objectForKey:daysAfterFre]; - if (!startDate) { - [[NSUserDefaults standardUserDefaults] setObject:[NSDate date] - forKey:daysAfterFre]; - return false; - } - - NSDate* sixDaysAgoDate = [NSDate dateWithTimeIntervalSinceNow:-kSixDays]; - if ([sixDaysAgoDate compare:startDate] == NSOrderedDescending) { - return true; - } - return false; -} - -// Returns whether this launch is the 6th and more launches after the FRE. This -// is used to decide to register What's New promo in the promo manager or not. -bool IsSixLaunchAfterFre() { - // TODO(crbug.com/1462404): Clean up unused user defaults and find a better - // solution to update existing user defaults for future versions of What's - // New. - NSString* const launchesAfterFre = kWhatsNewM116LaunchesAfterFre; - - NSInteger num = - [[NSUserDefaults standardUserDefaults] integerForKey:launchesAfterFre]; - - if (num >= 6) { - return true; - } - - num++; - [[NSUserDefaults standardUserDefaults] setInteger:num - forKey:launchesAfterFre]; - return false; -} - -// Returns whether What's New promo has been registered in the promo manager. -bool IsWhatsNewPromoRegistered() { - return [[NSUserDefaults standardUserDefaults] - boolForKey:kWhatsNewM116PromoRegistrationKey]; -} - +// Clean up user defaults. +// TODO(crbug.com/1462404): Safe to remove in M123+. void CleanUpWhatsNewUserDefaults() { NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; + [defaults removeObjectForKey:kWhatsNewM116PromoRegistrationKey]; [defaults removeObjectForKey:kWhatsNewPromoRegistrationKey]; [defaults removeObjectForKey:kWhatsNewDaysAfterFre]; [defaults removeObjectForKey:kWhatsNewLaunchesAfterFre]; + [defaults removeObjectForKey:kWhatsNewM116DaysAfterFre]; + [defaults removeObjectForKey:kWhatsNewM116LaunchesAfterFre]; } } // namespace +// For users who have already viewed What's New M116, the ensures that the promo +// is not triggered again until the next version of What's New. +// Note that we no longer write userDefault. bool WasWhatsNewUsed() { + CleanUpWhatsNewUserDefaults(); + return [[NSUserDefaults standardUserDefaults] boolForKey:kWhatsNewM116UsageEntryKey]; } -void SetWhatsNewUsed(PromosManager* promosManager) { - if (WasWhatsNewUsed()) { - return; - } - - // Deregister What's New promo. - DCHECK(promosManager); - promosManager->DeregisterPromo(promos_manager::Promo::WhatsNew); - [[NSUserDefaults standardUserDefaults] setBool:YES - forKey:kWhatsNewM116UsageEntryKey]; -} - -void setWhatsNewPromoRegistration() { - [[NSUserDefaults standardUserDefaults] - setBool:YES - forKey:kWhatsNewM116PromoRegistrationKey]; -} - -bool ShouldRegisterWhatsNewPromo() { - CleanUpWhatsNewUserDefaults(); - return !IsWhatsNewPromoRegistered() && - (IsSixLaunchAfterFre() || IsSixDaysAfterFre()); -} - // Please do not modify this method. The content is updated by script. For more // info, please see `tools/whats_new`. const char* WhatsNewTypeToString(WhatsNewType type) {
diff --git a/ios_internal b/ios_internal index 8d8296d..3803d9c 160000 --- a/ios_internal +++ b/ios_internal
@@ -1 +1 @@ -Subproject commit 8d8296d300748fa61c52dd36c7e95da202e42329 +Subproject commit 3803d9c28df7c8d5121cbc7d09c60a5a5c0c558c
diff --git a/media/audio/win/audio_low_latency_output_win.cc b/media/audio/win/audio_low_latency_output_win.cc index 97428e1..1435a43 100644 --- a/media/audio/win/audio_low_latency_output_win.cc +++ b/media/audio/win/audio_low_latency_output_win.cc
@@ -73,6 +73,15 @@ } // namespace +// static +AUDCLNT_SHAREMODE +WASAPIAudioOutputStream::GetShareMode() { + const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); + if (cmd_line->HasSwitch(switches::kEnableExclusiveAudio)) + return AUDCLNT_SHAREMODE_EXCLUSIVE; + return AUDCLNT_SHAREMODE_SHARED; +} + WASAPIAudioOutputStream::WASAPIAudioOutputStream( AudioManagerWin* manager, const std::string& device_id, @@ -92,6 +101,7 @@ endpoint_buffer_size_frames_(0), device_id_(device_id), device_role_(device_role), + share_mode_(GetShareMode()), num_written_frames_(0), source_(nullptr), log_callback_(std::move(log_callback)) { @@ -213,62 +223,86 @@ } // Extra sanity to ensure that the provided device format is still valid. - if (!CoreAudioUtil::IsFormatSupported(audio_client.Get(), &format_)) { + if (!CoreAudioUtil::IsFormatSupported(audio_client.Get(), share_mode_, + &format_)) { RecordAudioFailure(kOpenFailureHistogram, GetLastError()); SendLogMessage("%s => (ERROR: CAU::IsFormatSupported failed)", __func__); return false; } - // Initialize the audio stream between the client and the device in shared - // mode and using event-driven buffer handling. - HRESULT hr = CoreAudioUtil::SharedModeInitialize( - audio_client.Get(), &format_, audio_samples_render_event_.Get(), - requested_iaudioclient3_buffer_size_, &endpoint_buffer_size_frames_, - communications_device ? &kCommunicationsSessionId : nullptr); - if (FAILED(hr)) { - RecordAudioFailure(kOpenFailureHistogram, hr); - SendLogMessage("%s => (ERROR: IAudioClient::SharedModeInitialize=[%s])", - __func__, ErrorToString(hr).c_str()); - return false; - } + HRESULT hr = S_FALSE; + if (share_mode_ == AUDCLNT_SHAREMODE_SHARED) { + // Initialize the audio stream between the client and the device in shared + // mode and using event-driven buffer handling. + hr = CoreAudioUtil::SharedModeInitialize( + audio_client.Get(), &format_, audio_samples_render_event_.Get(), + requested_iaudioclient3_buffer_size_, &endpoint_buffer_size_frames_, + communications_device ? &kCommunicationsSessionId : nullptr); + if (FAILED(hr)) { + RecordAudioFailure(kOpenFailureHistogram, hr); + SendLogMessage("%s => (ERROR: IAudioClient::SharedModeInitialize=[%s])", + __func__, ErrorToString(hr).c_str()); + return false; + } - REFERENCE_TIME device_period = 0; - if (FAILED(CoreAudioUtil::GetDevicePeriod( - audio_client.Get(), AUDCLNT_SHAREMODE_SHARED, &device_period))) { - RecordAudioFailure(kOpenFailureHistogram, GetLastError()); - return false; - } + REFERENCE_TIME device_period = 0; + if (FAILED(CoreAudioUtil::GetDevicePeriod( + audio_client.Get(), AUDCLNT_SHAREMODE_SHARED, &device_period))) { + RecordAudioFailure(kOpenFailureHistogram, GetLastError()); + return false; + } - const int preferred_frames_per_buffer = static_cast<int>( - format_.Format.nSamplesPerSec * - CoreAudioUtil::ReferenceTimeToTimeDelta(device_period).InSecondsF() + - 0.5); - SendLogMessage("%s => (preferred_frames_per_buffer=[%d audio frames])", - __func__, preferred_frames_per_buffer); + const int preferred_frames_per_buffer = static_cast<int>( + format_.Format.nSamplesPerSec * + CoreAudioUtil::ReferenceTimeToTimeDelta(device_period) + .InSecondsF() + + 0.5); + SendLogMessage("%s => (preferred_frames_per_buffer=[%d audio frames])", + __func__, preferred_frames_per_buffer); - // Packet size should always be an even divisor of the device period for - // best performance; things will still work otherwise, but may glitch for a - // couple of reasons. - // - // The first reason is if/when repeated RenderAudioFromSource() hit the - // shared memory boundary between the renderer and the browser. The next - // audio buffer is always requested after the current request is consumed. - // With back-to-back calls the round-trip may not be fast enough and thus - // audio will glitch as we fail to deliver audio in a timely manner. - // - // The second reason is event wakeup efficiency. We may have too few or too - // many frames to fill the output buffer requested by WASAPI. If too few, - // we'll refuse the render event and wait until more output space is - // available. If we have too many frames, we'll only partially fill and - // wait for the next render event. In either case certain remainders may - // leave us unable to fulfill the request in a timely manner, thus glitches. - // - // Log a warning in these cases so we can help users in the field. - // Examples: 48kHz => 960 % 480, 44.1kHz => 896 % 448 or 882 % 441. - if (preferred_frames_per_buffer % packet_size_frames_) { + // Packet size should always be an even divisor of the device period for + // best performance; things will still work otherwise, but may glitch for a + // couple of reasons. + // + // The first reason is if/when repeated RenderAudioFromSource() hit the + // shared memory boundary between the renderer and the browser. The next + // audio buffer is always requested after the current request is consumed. + // With back-to-back calls the round-trip may not be fast enough and thus + // audio will glitch as we fail to deliver audio in a timely manner. + // + // The second reason is event wakeup efficiency. We may have too few or too + // many frames to fill the output buffer requested by WASAPI. If too few, + // we'll refuse the render event and wait until more output space is + // available. If we have too many frames, we'll only partially fill and + // wait for the next render event. In either case certain remainders may + // leave us unable to fulfill the request in a timely manner, thus glitches. + // + // Log a warning in these cases so we can help users in the field. + // Examples: 48kHz => 960 % 480, 44.1kHz => 896 % 448 or 882 % 441. + if (preferred_frames_per_buffer % packet_size_frames_) { + SendLogMessage( + "%s => (WARNING: Using output audio with a non-optimal buffer size)", + __func__); + } + } else { SendLogMessage( - "%s => (WARNING: Using output audio with a non-optimal buffer size)", + "%s => (WARNING: Using exclusive mode can lead to bad performance)", __func__); + // TODO(henrika): break out to CoreAudioUtil::ExclusiveModeInitialize() + // when removing the enable-exclusive-audio flag. + hr = ExclusiveModeInitialization(audio_client.Get(), + audio_samples_render_event_.Get(), + &endpoint_buffer_size_frames_); + if (FAILED(hr)) + return false; + + // The buffer scheme for exclusive mode streams is not designed for max + // flexibility. We only allow a "perfect match" between the packet size set + // by the user and the actual endpoint buffer size. + if (endpoint_buffer_size_frames_ != packet_size_frames_) { + LOG(ERROR) << "Bailing out due to non-perfect timing."; + return false; + } } // Create an IAudioRenderClient client for an initialized IAudioClient. @@ -329,22 +363,24 @@ // been invalidated (AUDCLNT_E_DEVICE_INVALIDATED), we retry for all errors // for simplicity and due to large sites like YouTube reporting high success // rates with a simple retry upon detection of an audio output error. - if (!CoreAudioUtil::FillRenderEndpointBufferWithSilence( - audio_client_.Get(), audio_render_client_.Get())) { - // Failed to prepare endpoint buffers with silence. Attempting recovery - // with a new IAudioClient and IAudioRenderClient." - SendLogMessage( - "%s => (WARNING: CAU::FillRenderEndpointBufferWithSilence failed)", - __func__); - opened_ = false; - audio_client_.Reset(); - audio_render_client_.Reset(); - if (!Open() || !CoreAudioUtil::FillRenderEndpointBufferWithSilence( - audio_client_.Get(), audio_render_client_.Get())) { - RecordAudioFailure(kStartFailureHistogram, GetLastError()); - SendLogMessage("%s => (ERROR: Recovery attempt failed)", __func__); - callback->OnError(AudioSourceCallback::ErrorType::kUnknown); - return; + if (share_mode_ == AUDCLNT_SHAREMODE_SHARED) { + if (!CoreAudioUtil::FillRenderEndpointBufferWithSilence( + audio_client_.Get(), audio_render_client_.Get())) { + // Failed to prepare endpoint buffers with silence. Attempting recovery + // with a new IAudioClient and IAudioRenderClient." + SendLogMessage( + "%s => (WARNING: CAU::FillRenderEndpointBufferWithSilence failed)", + __func__); + opened_ = false; + audio_client_.Reset(); + audio_render_client_.Reset(); + if (!Open() || !CoreAudioUtil::FillRenderEndpointBufferWithSilence( + audio_client_.Get(), audio_render_client_.Get())) { + RecordAudioFailure(kStartFailureHistogram, GetLastError()); + SendLogMessage("%s => (ERROR: Recovery attempt failed)", __func__); + callback->OnError(AudioSourceCallback::ErrorType::kUnknown); + return; + } } } @@ -421,12 +457,15 @@ // Extra safety check to ensure that the buffers are cleared. // If the buffers are not cleared correctly, the next call to Start() // would fail with AUDCLNT_E_BUFFER_ERROR at IAudioRenderClient::GetBuffer(). - UINT32 num_queued_frames = 0; - audio_client_->GetCurrentPadding(&num_queued_frames); - DCHECK_EQ(0u, num_queued_frames); - if (num_queued_frames > 0) { - SendLogMessage("%s => (WARNING: Buffers are not cleared correctly)", - __func__); + // This check is is only needed for shared-mode streams. + if (share_mode_ == AUDCLNT_SHAREMODE_SHARED) { + UINT32 num_queued_frames = 0; + audio_client_->GetCurrentPadding(&num_queued_frames); + DCHECK_EQ(0u, num_queued_frames); + if (num_queued_frames > 0) { + SendLogMessage("%s => (WARNING: Buffers are not cleared correctly)", + __func__); + } } } @@ -581,23 +620,36 @@ // engine has not yet read from the buffer. UINT32 num_available_frames = 0; - // Get the padding value which represents the amount of rendering - // data that is queued up to play in the endpoint buffer. - hr = audio_client_->GetCurrentPadding(&num_queued_frames); - if (FAILED(hr)) { - RecordAudioFailure(kRenderFailureHistogram, hr); - LOG(ERROR) << "WAOS::" << __func__ - << " => (ERROR: IAudioClient::GetCurrentPadding=[" - << ErrorToString(hr).c_str() << "])"; - return false; + if (share_mode_ == AUDCLNT_SHAREMODE_SHARED) { + // Get the padding value which represents the amount of rendering + // data that is queued up to play in the endpoint buffer. + hr = audio_client_->GetCurrentPadding(&num_queued_frames); + if (FAILED(hr)) { + RecordAudioFailure(kRenderFailureHistogram, hr); + LOG(ERROR) << "WAOS::" << __func__ + << " => (ERROR: IAudioClient::GetCurrentPadding=[" + << ErrorToString(hr).c_str() << "])"; + return false; + } + TRACE_COUNTER_ID1(TRACE_DISABLED_BY_DEFAULT("audio"), + "IAudioClient_queued_frames", this, num_queued_frames); + if (!num_queued_frames) { + TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("audio"), "buffer empty", + TRACE_EVENT_SCOPE_THREAD); + } + num_available_frames = endpoint_buffer_size_frames_ - num_queued_frames; + } else { + // While the stream is running, the system alternately sends one + // buffer or the other to the client. This form of double buffering + // is referred to as "ping-ponging". Each time the client receives + // a buffer from the system (triggers this event) the client must + // process the entire buffer. Calls to the GetCurrentPadding method + // are unnecessary because the packet size must always equal the + // buffer size. In contrast to the shared mode buffering scheme, + // the latency for an event-driven, exclusive-mode stream depends + // directly on the buffer size. + num_available_frames = endpoint_buffer_size_frames_; } - TRACE_COUNTER_ID1(TRACE_DISABLED_BY_DEFAULT("audio"), - "IAudioClient_queued_frames", this, num_queued_frames); - if (!num_queued_frames) { - TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("audio"), "buffer empty", - TRACE_EVENT_SCOPE_THREAD); - } - num_available_frames = endpoint_buffer_size_frames_ - num_queued_frames; TRACE_EVENT( TRACE_DISABLED_BY_DEFAULT("audio"), "IAudioClient frames", @@ -851,6 +903,8 @@ IAudioClient* client, HANDLE event_handle, uint32_t* endpoint_buffer_size) { + DCHECK_EQ(share_mode_, AUDCLNT_SHAREMODE_EXCLUSIVE); + float f = (1000.0 * packet_size_frames_) / format_.Format.nSamplesPerSec; REFERENCE_TIME requested_buffer_duration = static_cast<REFERENCE_TIME>(f * 10000.0 + 0.5);
diff --git a/media/audio/win/audio_low_latency_output_win.h b/media/audio/win/audio_low_latency_output_win.h index c0acbdf6..c4526746 100644 --- a/media/audio/win/audio_low_latency_output_win.h +++ b/media/audio/win/audio_low_latency_output_win.h
@@ -248,6 +248,11 @@ // Defines the role that the system has assigned to an audio endpoint device. const ERole device_role_; + // The sharing mode for the connection. + // Valid values are AUDCLNT_SHAREMODE_SHARED and AUDCLNT_SHAREMODE_EXCLUSIVE + // where AUDCLNT_SHAREMODE_SHARED is the default. + const AUDCLNT_SHAREMODE share_mode_; + // Counts the number of audio frames written to the endpoint buffer. UINT64 num_written_frames_;
diff --git a/media/audio/win/audio_low_latency_output_win_unittest.cc b/media/audio/win/audio_low_latency_output_win_unittest.cc index 4d5f5dcb..17d50664 100644 --- a/media/audio/win/audio_low_latency_output_win_unittest.cc +++ b/media/audio/win/audio_low_latency_output_win_unittest.cc
@@ -146,6 +146,11 @@ size_t elements_to_write_; }; +static bool ExclusiveModeIsEnabled() { + return (WASAPIAudioOutputStream::GetShareMode() == + AUDCLNT_SHAREMODE_EXCLUSIVE); +} + static bool HasCoreAudioAndOutputDevices(AudioManager* audio_man) { // The low-latency (WASAPI-based) version requires Windows Vista or higher. // TODO(henrika): note that we use Wave today to query the number of @@ -381,4 +386,180 @@ aos->Close(); } +// Verify that we can open the output stream in exclusive mode using a +// certain set of audio parameters and a sample rate of 48kHz. +// The expected outcomes of each setting in this test has been derived +// manually using log outputs (--v=1). +// It's disabled by default because a flag is required to enable exclusive mode. +TEST_F(WASAPIAudioOutputStreamTest, DISABLED_ExclusiveModeBufferSizesAt48kHz) { + ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndOutputDevices(audio_manager_.get()) && + ExclusiveModeIsEnabled()); + + AudioOutputStreamWrapper aosw(audio_manager_.get()); + + // 10ms @ 48kHz shall work. + // Note that, this is the same size as we can use for shared-mode streaming + // but here the endpoint buffer delay is only 10ms instead of 20ms. + AudioOutputStream* aos = aosw.Create(48000, 480); + EXPECT_TRUE(aos->Open()); + aos->Close(); + + // 5ms @ 48kHz does not work due to misalignment. + // This test will propose an aligned buffer size of 5.3333ms. + // Note that we must call Close() even is Open() fails since Close() also + // deletes the object and we want to create a new object in the next test. + aos = aosw.Create(48000, 240); + EXPECT_FALSE(aos->Open()); + aos->Close(); + + // 5.3333ms @ 48kHz should work (see test above). + aos = aosw.Create(48000, 256); + EXPECT_TRUE(aos->Open()); + aos->Close(); + + // 2.6667ms is smaller than the minimum supported size (=3ms). + aos = aosw.Create(48000, 128); + EXPECT_FALSE(aos->Open()); + aos->Close(); + + // 3ms does not correspond to an aligned buffer size. + // This test will propose an aligned buffer size of 3.3333ms. + aos = aosw.Create(48000, 144); + EXPECT_FALSE(aos->Open()); + aos->Close(); + + // 3.3333ms @ 48kHz <=> smallest possible buffer size we can use. + aos = aosw.Create(48000, 160); + EXPECT_TRUE(aos->Open()); + aos->Close(); +} + +// Verify that we can open the output stream in exclusive mode using a +// certain set of audio parameters and a sample rate of 44.1kHz. +// The expected outcomes of each setting in this test has been derived +// manually using log outputs (--v=1). +// It's disabled by default because a flag is required to enable exclusive mode. +TEST_F(WASAPIAudioOutputStreamTest, DISABLED_ExclusiveModeBufferSizesAt44kHz) { + ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndOutputDevices(audio_manager_.get()) && + ExclusiveModeIsEnabled()); + + AudioOutputStreamWrapper aosw(audio_manager_.get()); + + // 10ms @ 44.1kHz does not work due to misalignment. + // This test will propose an aligned buffer size of 10.1587ms. + AudioOutputStream* aos = aosw.Create(44100, 441); + EXPECT_FALSE(aos->Open()); + aos->Close(); + + // 10.1587ms @ 44.1kHz shall work (see test above). + aos = aosw.Create(44100, 448); + EXPECT_TRUE(aos->Open()); + aos->Close(); + + // 5.8050ms @ 44.1 should work. + aos = aosw.Create(44100, 256); + EXPECT_TRUE(aos->Open()); + aos->Close(); + + // 4.9887ms @ 44.1kHz does not work to misalignment. + // This test will propose an aligned buffer size of 5.0794ms. + // Note that we must call Close() even is Open() fails since Close() also + // deletes the object and we want to create a new object in the next test. + aos = aosw.Create(44100, 220); + EXPECT_FALSE(aos->Open()); + aos->Close(); + + // 5.0794ms @ 44.1kHz shall work (see test above). + aos = aosw.Create(44100, 224); + EXPECT_TRUE(aos->Open()); + aos->Close(); + + // 2.9025ms is smaller than the minimum supported size (=3ms). + aos = aosw.Create(44100, 132); + EXPECT_FALSE(aos->Open()); + aos->Close(); + + // 3.01587ms is larger than the minimum size but is not aligned. + // This test will propose an aligned buffer size of 3.6281ms. + aos = aosw.Create(44100, 133); + EXPECT_FALSE(aos->Open()); + aos->Close(); + + // 3.6281ms @ 44.1kHz <=> smallest possible buffer size we can use. + aos = aosw.Create(44100, 160); + EXPECT_TRUE(aos->Open()); + aos->Close(); +} + +// Verify that we can open and start the output stream in exclusive mode at +// the lowest possible delay at 48kHz. +// It's disabled by default because a flag is required to enable exclusive mode. +TEST_F(WASAPIAudioOutputStreamTest, + DISABLED_ExclusiveModeMinBufferSizeAt48kHz) { + ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndOutputDevices(audio_manager_.get()) && + ExclusiveModeIsEnabled()); + + MockAudioSourceCallback source; + // Create exclusive-mode WASAPI output stream which plays out in stereo + // using the minimum buffer size at 48kHz sample rate. + AudioOutputStreamWrapper aosw(audio_manager_.get()); + AudioOutputStream* aos = aosw.Create(48000, 160); + EXPECT_TRUE(aos->Open()); + + // Derive the expected size in bytes of each packet. + base::TimeDelta packet_duration = base::Seconds( + static_cast<double>(aosw.samples_per_packet()) / aosw.sample_rate()); + + // Wait for the first callback and verify its parameters. + EXPECT_CALL(source, OnMoreData(HasValidDelay(packet_duration), _, + AudioGlitchInfo(), NotNull())) + .WillOnce( + DoAll(QuitLoop(base::SingleThreadTaskRunner::GetCurrentDefault()), + Return(aosw.samples_per_packet()))) + .WillRepeatedly(Return(aosw.samples_per_packet())); + + aos->Start(&source); + base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask( + FROM_HERE, base::RunLoop::QuitCurrentWhenIdleClosureDeprecated(), + TestTimeouts::action_timeout()); + base::RunLoop().Run(); + aos->Stop(); + aos->Close(); +} + +// Verify that we can open and start the output stream in exclusive mode at +// the lowest possible delay at 44.1kHz. +// It's disabled by default because a flag is required to enable exclusive mode. +TEST_F(WASAPIAudioOutputStreamTest, + DISABLED_ExclusiveModeMinBufferSizeAt44kHz) { + ABORT_AUDIO_TEST_IF_NOT(ExclusiveModeIsEnabled()); + + MockAudioSourceCallback source; + // Create exclusive-mode WASAPI output stream which plays out in stereo + // using the minimum buffer size at 44.1kHz sample rate. + AudioOutputStreamWrapper aosw(audio_manager_.get()); + AudioOutputStream* aos = aosw.Create(44100, 160); + EXPECT_TRUE(aos->Open()); + + // Derive the expected size in bytes of each packet. + base::TimeDelta packet_duration = base::Seconds( + static_cast<double>(aosw.samples_per_packet()) / aosw.sample_rate()); + + // Wait for the first callback and verify its parameters. + EXPECT_CALL(source, OnMoreData(HasValidDelay(packet_duration), _, + AudioGlitchInfo(), NotNull())) + .WillOnce( + DoAll(QuitLoop(base::SingleThreadTaskRunner::GetCurrentDefault()), + Return(aosw.samples_per_packet()))) + .WillRepeatedly(Return(aosw.samples_per_packet())); + + aos->Start(&source); + base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask( + FROM_HERE, base::RunLoop::QuitCurrentWhenIdleClosureDeprecated(), + TestTimeouts::action_timeout()); + base::RunLoop().Run(); + aos->Stop(); + aos->Close(); +} + } // namespace media
diff --git a/media/audio/win/audio_manager_win.cc b/media/audio/win/audio_manager_win.cc index 0b38c2f..b160875 100644 --- a/media/audio/win/audio_manager_win.cc +++ b/media/audio/win/audio_manager_win.cc
@@ -15,6 +15,7 @@ #include <utility> +#include "base/command_line.h" #include "base/functional/bind.h" #include "base/functional/callback_helpers.h" #include "base/strings/string_number_conversions.h" @@ -64,7 +65,22 @@ // determined from the system constexpr int kFallbackBufferSize = 2048; -constexpr int kNumberOfWaveOutBuffers = 3; +namespace { + +int NumberOfWaveOutBuffers() { + // Use the user provided buffer count if provided. + int buffers = 0; + std::string buffers_str( + base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( + switches::kWaveOutBuffers)); + if (base::StringToInt(buffers_str, &buffers) && buffers > 0) { + return buffers; + } + + return 3; +} + +} // namespace AudioManagerWin::AudioManagerWin(std::unique_ptr<AudioThread> audio_thread, AudioLogFactory* audio_log_factory) @@ -218,7 +234,7 @@ if (params.channels() > kWinMaxChannels) return nullptr; - return new PCMWaveOutAudioOutputStream(this, params, kNumberOfWaveOutBuffers, + return new PCMWaveOutAudioOutputStream(this, params, NumberOfWaveOutBuffers(), WAVE_MAPPER); } @@ -253,6 +269,12 @@ if (params.channels() > kWinMaxChannels) return nullptr; + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kForceWaveAudio)) { + DLOG(WARNING) << "Forcing usage of Windows WaveXxx APIs"; + return nullptr; + } + // Pass an empty string to indicate that we want the default device // since we consistently only check for an empty string in // WASAPIAudioOutputStream. @@ -305,6 +327,7 @@ AudioParameters AudioManagerWin::GetPreferredOutputStreamParameters( const std::string& output_device_id, const AudioParameters& input_params) { + const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); ChannelLayoutConfig channel_layout_config = ChannelLayoutConfig::Stereo(); int sample_rate = 48000; int buffer_size = kFallbackBufferSize; @@ -312,7 +335,17 @@ int min_buffer_size = 0; int max_buffer_size = 0; - { + if (cmd_line->HasSwitch(switches::kEnableExclusiveAudio)) { + // TODO(rtoy): tune these values for best possible WebAudio + // performance. WebRTC works well at 48kHz and a buffer size of 480 + // samples will be used for this case. Note that exclusive mode is + // experimental. This sample rate will be combined with a buffer size of + // 256 samples, which corresponds to an output delay of ~5.33ms. + sample_rate = 48000; + buffer_size = 256; + if (input_params.IsValid()) + channel_layout_config = input_params.channel_layout_config(); + } else { AudioParameters params; HRESULT hr = CoreAudioUtil::GetPreferredAudioParameters( output_device_id.empty() ? GetDefaultOutputDeviceID() @@ -344,7 +377,11 @@ } if (input_params.IsValid()) { - if (channel_layout_config.channel_layout() == CHANNEL_LAYOUT_UNSUPPORTED) { + // If the user has enabled checking supported channel layouts or we don't + // have a valid channel layout yet, try to use the input layout. See bugs + // http://crbug.com/259165 and http://crbug.com/311906 for more details. + if (cmd_line->HasSwitch(switches::kTrySupportedChannelLayouts) || + channel_layout_config.channel_layout() == CHANNEL_LAYOUT_UNSUPPORTED) { // Check if it is possible to open up at the specified input channel // layout but avoid checking if the specified layout is the same as the // hardware (preferred) layout. We do this extra check to avoid the
diff --git a/media/audio/win/core_audio_util_win.cc b/media/audio/win/core_audio_util_win.cc index a05d4bd..d4c94d3c0 100644 --- a/media/audio/win/core_audio_util_win.cc +++ b/media/audio/win/core_audio_util_win.cc
@@ -11,7 +11,7 @@ #include <stddef.h> #include <bitset> -#include "base/feature_list.h" +#include "base/command_line.h" #include "base/functional/bind.h" #include "base/functional/callback.h" #include "base/logging.h" @@ -301,6 +301,14 @@ } bool IsSupportedInternal() { + // It is possible to force usage of WaveXxx APIs by using a command line + // flag. + const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); + if (cmd_line->HasSwitch(switches::kForceWaveAudio)) { + DVLOG(1) << "Forcing usage of Windows WaveXxx APIs"; + return false; + } + // Verify that it is possible to a create the IMMDeviceEnumerator interface. ComPtr<IMMDeviceEnumerator> device_enumerator = CreateDeviceEnumeratorInternal(false); @@ -591,6 +599,13 @@ return base::Microseconds(0.1 * time + 0.5); } +AUDCLNT_SHAREMODE CoreAudioUtil::GetShareMode() { + const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); + if (cmd_line->HasSwitch(switches::kEnableExclusiveAudio)) + return AUDCLNT_SHAREMODE_EXCLUSIVE; + return AUDCLNT_SHAREMODE_SHARED; +} + int CoreAudioUtil::NumberOfActiveDevices(EDataFlow data_flow) { // Create the IMMDeviceEnumerator interface. ComPtr<IMMDeviceEnumerator> device_enumerator = CreateDeviceEnumerator(); @@ -856,10 +871,10 @@ } bool CoreAudioUtil::IsFormatSupported(IAudioClient* client, + AUDCLNT_SHAREMODE share_mode, const WaveFormatWrapper format) { ScopedCoMem<WAVEFORMATEX> closest_match; - HRESULT hr = client->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, format, - &closest_match); + HRESULT hr = client->IsFormatSupported(share_mode, format, &closest_match); // This log can only be triggered for shared mode. DLOG_IF(ERROR, hr == S_FALSE) << "Format is not supported " @@ -920,7 +935,8 @@ // an even wider range of shared-mode formats where the installation package // for the audio device includes a local effects (LFX) audio processing // object (APO) that can handle format conversions. - return CoreAudioUtil::IsFormatSupported(client.Get(), format); + return CoreAudioUtil::IsFormatSupported(client.Get(), + AUDCLNT_SHAREMODE_SHARED, format); } HRESULT CoreAudioUtil::GetDevicePeriod(IAudioClient* client,
diff --git a/media/audio/win/core_audio_util_win.h b/media/audio/win/core_audio_util_win.h index ed53298..223e7e9 100644 --- a/media/audio/win/core_audio_util_win.h +++ b/media/audio/win/core_audio_util_win.h
@@ -79,6 +79,10 @@ // Example: double s = RefererenceTimeToTimeDelta(t).InMillisecondsF(); static base::TimeDelta ReferenceTimeToTimeDelta(REFERENCE_TIME time); + // Returns AUDCLNT_SHAREMODE_EXCLUSIVE if --enable-exclusive-mode is used + // as command-line flag and AUDCLNT_SHAREMODE_SHARED otherwise (default). + static AUDCLNT_SHAREMODE GetShareMode(); + // The Windows Multimedia Device (MMDevice) API enables audio clients to // discover audio endpoint devices and determine their capabilities. @@ -162,6 +166,7 @@ // Returns true if the specified |client| supports the format in |format| // for the given |share_mode| (shared or exclusive). static bool IsFormatSupported(IAudioClient* client, + AUDCLNT_SHAREMODE share_mode, WaveFormatWrapper format); // Returns true if the specified |channel_layout| is supported for the
diff --git a/media/audio/win/core_audio_util_win_unittest.cc b/media/audio/win/core_audio_util_win_unittest.cc index 1fcf162..cd88148 100644 --- a/media/audio/win/core_audio_util_win_unittest.cc +++ b/media/audio/win/core_audio_util_win_unittest.cc
@@ -466,7 +466,8 @@ eRender, eConsole); EXPECT_TRUE(client.Get()); format.Format.nSamplesPerSec = format.Format.nSamplesPerSec + 1; - EXPECT_FALSE(CoreAudioUtil::IsFormatSupported(client.Get(), &format)); + EXPECT_FALSE(CoreAudioUtil::IsFormatSupported( + client.Get(), AUDCLNT_SHAREMODE_SHARED, &format)); hr = CoreAudioUtil::SharedModeInitialize(client.Get(), &format, NULL, 0, &endpoint_buffer_size, NULL); EXPECT_TRUE(FAILED(hr)); @@ -482,7 +483,8 @@ EXPECT_TRUE(client.Get()); EXPECT_TRUE( SUCCEEDED(CoreAudioUtil::GetSharedModeMixFormat(client.Get(), &format))); - EXPECT_TRUE(CoreAudioUtil::IsFormatSupported(client.Get(), &format)); + EXPECT_TRUE(CoreAudioUtil::IsFormatSupported( + client.Get(), AUDCLNT_SHAREMODE_SHARED, &format)); hr = CoreAudioUtil::SharedModeInitialize(client.Get(), &format, event_handle.Get(), 0, &endpoint_buffer_size, NULL);
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc index 514edfef..f36e06c5 100644 --- a/media/base/media_switches.cc +++ b/media/base/media_switches.cc
@@ -69,6 +69,28 @@ #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || // BUILDFLAG(IS_FREEBSD) || BUILDFLAG(IS_SOLARIS) +#if BUILDFLAG(IS_WIN) +// Use exclusive mode audio streaming for Windows Vista and higher. +// Leads to lower latencies for audio streams which uses the +// AudioParameters::AUDIO_PCM_LOW_LATENCY audio path. +// See http://msdn.microsoft.com/en-us/library/windows/desktop/dd370844.aspx +// for details. +const char kEnableExclusiveAudio[] = "enable-exclusive-audio"; + +// Use Windows WaveOut/In audio API even if Core Audio is supported. +const char kForceWaveAudio[] = "force-wave-audio"; + +// Instead of always using the hardware channel layout, check if a driver +// supports the source channel layout. Avoids outputting empty channels and +// permits drivers to enable stereo to multichannel expansion. Kept behind a +// flag since some drivers lie about supported layouts and hang when used. See +// http://crbug.com/259165 for more details. +const char kTrySupportedChannelLayouts[] = "try-supported-channel-layouts"; + +// Number of buffers to use for WaveOut. +const char kWaveOutBuffers[] = "waveout-buffers"; +#endif // BUILDFLAG(IS_WIN) + #if BUILDFLAG(IS_FUCHSIA) // Enables protected buffers for encrypted video streams. const char kEnableProtectedVideoBuffers[] = "enable-protected-video-buffers";
diff --git a/media/base/media_switches.h b/media/base/media_switches.h index cbb5753..056bc55 100644 --- a/media/base/media_switches.h +++ b/media/base/media_switches.h
@@ -48,6 +48,13 @@ MEDIA_EXPORT extern const char kAlsaOutputDevice[]; #endif +#if BUILDFLAG(IS_WIN) +MEDIA_EXPORT extern const char kEnableExclusiveAudio[]; +MEDIA_EXPORT extern const char kForceWaveAudio[]; +MEDIA_EXPORT extern const char kTrySupportedChannelLayouts[]; +MEDIA_EXPORT extern const char kWaveOutBuffers[]; +#endif + #if BUILDFLAG(IS_FUCHSIA) MEDIA_EXPORT extern const char kEnableProtectedVideoBuffers[]; MEDIA_EXPORT extern const char kForceProtectedVideoOutputBuffers[];
diff --git a/media/gpu/android/media_codec_video_decoder.cc b/media/gpu/android/media_codec_video_decoder.cc index 9e8f6a8..a77616f 100644 --- a/media/gpu/android/media_codec_video_decoder.cc +++ b/media/gpu/android/media_codec_video_decoder.cc
@@ -82,6 +82,10 @@ !can_use_builtin_software_decoder || allow_media_codec_software_decoder; if (info.is_software_codec && !is_os_software_decoder_allowed) { + supported_configs.emplace_back(info.profile, info.profile, + info.coded_size_min, info.coded_size_max, + kAllowEncrypted, + /*require_encrypted=*/true); continue; }
diff --git a/media/gpu/android/media_codec_video_decoder_unittest.cc b/media/gpu/android/media_codec_video_decoder_unittest.cc index e3b1bf4..988dafd 100644 --- a/media/gpu/android/media_codec_video_decoder_unittest.cc +++ b/media/gpu/android/media_codec_video_decoder_unittest.cc
@@ -350,9 +350,21 @@ ASSERT_TRUE(Initialize(TestVideoConfig::NormalH264())); } +// Ensures that we always report support for low resolution encrypted content +// since Android guarantees support for these codecs. +TEST_P(MediaCodecVideoDecoderTest, SoftwareDecodersSupportEncrypted) { + auto configs = MediaCodecVideoDecoder::GetSupportedConfigs(); + for (const auto& c : configs) { + if (c.Matches(TestVideoConfig::NormalEncrypted(GetParam()))) { + return; + } + } + FAIL() << "No encrypted config found for " << GetCodecName(GetParam()); +} + TEST_P(MediaCodecVideoDecoderVp8Test, SmallVp8IsRejected) { auto configs = MediaCodecVideoDecoder::GetSupportedConfigs(); - auto small_vp8_config = TestVideoConfig::Normal(); + auto small_vp8_config = TestVideoConfig::Normal(VideoCodec::kVP8); for (const auto& c : configs) ASSERT_FALSE(c.Matches(small_vp8_config)); }
diff --git a/media/renderers/audio_renderer_impl.cc b/media/renderers/audio_renderer_impl.cc index 67792e9..29886c7 100644 --- a/media/renderers/audio_renderer_impl.cc +++ b/media/renderers/audio_renderer_impl.cc
@@ -10,7 +10,7 @@ #include <memory> #include <utility> -#include "base/feature_list.h" +#include "base/command_line.h" #include "base/functional/bind.h" #include "base/functional/callback.h" #include "base/functional/callback_helpers.h" @@ -547,6 +547,13 @@ int stream_channel_count = stream->audio_decoder_config().channels(); + bool try_supported_channel_layouts = false; +#if BUILDFLAG(IS_WIN) + try_supported_channel_layouts = + base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kTrySupportedChannelLayouts); +#endif + // We don't know how to up-mix for DISCRETE layouts (fancy multichannel // hardware with non-standard speaker arrangement). Instead, pretend the // hardware layout is stereo and let the OS take care of further up-mixing @@ -557,7 +564,8 @@ // mixer will attempt to up-mix stereo source streams to just the left/right // speaker of the 5.1 setup, nulling out the other channels // (http://crbug.com/177872). - hw_channel_layout = hw_params.channel_layout() == CHANNEL_LAYOUT_DISCRETE + hw_channel_layout = hw_params.channel_layout() == CHANNEL_LAYOUT_DISCRETE || + try_supported_channel_layouts ? CHANNEL_LAYOUT_STEREO : hw_params.channel_layout(); int hw_channel_count = ChannelLayoutToChannelCount(hw_channel_layout);
diff --git a/mojo/public/tools/bindings/mojom.gni b/mojo/public/tools/bindings/mojom.gni index 3f6e54e..0cf19db 100644 --- a/mojo/public/tools/bindings/mojom.gni +++ b/mojo/public/tools/bindings/mojom.gni
@@ -340,12 +340,24 @@ # # generate_webui_js_bindings (optional) # Generate WebUI bindings in JavaScript rather than TypeScript. Defaults -# to false. ChromeOS only parameter. +# to false. ChromeOS only parameter. Use instead of +# |use_typescript_sources|, which is being removed. +# +# use_typescript_sources (optional) +# Generate WebUI bindings in TypeScript. Defaults to "true". When set to +# "false", WebUI bindings will be generated in JavaScript instead. +# Ignored if |webui_module_path| is not set. +# +# Note: DO NOT USE in new targets. New WebUI code should always be in +# TypeScript, so the corresponding WebUI mojo bindings should be in +# TypeScript as well. This parameter should only be set to false to +# support legacy WebUI code that still uses the Closure Compiler for +# typechecking. # # generate_legacy_js_bindings (optional) # Generate js_data_deps target containing legacy JavaScript bindings files # for Blink tests and other non-WebUI users when generating TypeScript -# bindings for WebUI. Ignored if generate_webui_js_bindings is set to +# bindings for WebUI. Ignored if use_typescript_sources is not set to # true. # # js_generate_struct_deserializers (optional) @@ -374,7 +386,7 @@ # given URL. # # Note: WebUI module bindings are generated in TypeScript by default, -# unless |generate_webui_js_bindings| is specified as true. +# unless |use_typescript_sources| is specified as false. # # The following parameters are used to support the component build. They are # needed so that bindings which are linked with a component can use the same @@ -808,8 +820,10 @@ "--add-module-metadata", "webui_module_path=${invoker.webui_module_path}", ] - if (defined(invoker.generate_webui_js_bindings) && - invoker.generate_webui_js_bindings) { + if ((defined(invoker.use_typescript_sources) && + !invoker.use_typescript_sources) || + (defined(invoker.generate_webui_js_bindings) && + invoker.generate_webui_js_bindings)) { args += [ "--add-module-metadata", "generate_webui_js=True", @@ -1847,7 +1861,19 @@ } use_typescript_for_target = defined(invoker.webui_module_path) && - !defined(invoker.generate_webui_js_bindings) + !defined(invoker.generate_webui_js_bindings) && + (!defined(invoker.use_typescript_sources) || + (defined(invoker.use_typescript_sources) && + invoker.use_typescript_sources)) + + # Don't allow JavaScript WebUI bindings on non-ChromeOS platforms. + # TODO (rbpotter): Remove this check once use_typescript_sources is removed. + if (!use_typescript_for_target && defined(invoker.webui_module_path)) { + assert( + is_chromeos_ash, + "WebUI bindings should be in TypeScript on non-ChromeOS platforms. " + + "Remove use_typescript_sources = false") + } generate_legacy_js = !use_typescript_for_target || (defined(invoker.generate_legacy_js_bindings) &&
diff --git a/sandbox/policy/mojom/BUILD.gn b/sandbox/policy/mojom/BUILD.gn index 2265876..836f5b2 100644 --- a/sandbox/policy/mojom/BUILD.gn +++ b/sandbox/policy/mojom/BUILD.gn
@@ -21,7 +21,7 @@ # bindings in JavaScript rather than TypeScript to support this legacy code. if (is_chromeos_ash) { webui_module_path = "/" - generate_webui_js_bindings = true + use_typescript_sources = false } enabled_features = []
diff --git a/services/device/public/mojom/BUILD.gn b/services/device/public/mojom/BUILD.gn index 1468b8ed..7ed4926e 100644 --- a/services/device/public/mojom/BUILD.gn +++ b/services/device/public/mojom/BUILD.gn
@@ -233,6 +233,7 @@ mojom("geolocation_internals") { sources = [ "geolocation_internals.mojom" ] webui_module_path = "/" + use_typescript_sources = true public_deps = [ ":geoposition", "//mojo/public/mojom/base",
diff --git a/services/network/public/mojom/BUILD.gn b/services/network/public/mojom/BUILD.gn index bc29d50..2bd74aa1 100644 --- a/services/network/public/mojom/BUILD.gn +++ b/services/network/public/mojom/BUILD.gn
@@ -29,7 +29,7 @@ # Used by ash/webui/resources/common/network_health, which is still using # Closure Compiler, so generate WebUI bindings in JavaScript. - generate_webui_js_bindings = true + use_typescript_sources = false } public_deps = [ "//url/mojom:url_mojom_gurl" ]
diff --git a/services/on_device_model/ml/chrome_ml.cc b/services/on_device_model/ml/chrome_ml.cc index 588fbdc..b8f7ccc 100644 --- a/services/on_device_model/ml/chrome_ml.cc +++ b/services/on_device_model/ml/chrome_ml.cc
@@ -55,6 +55,10 @@ base::UmaHistogramEnumeration("OnDeviceModel.GpuBlockedReason", reason); } +void FatalErrorFn(const char* msg) { + CHECK(false) << "ChromeML Error: " << msg; +} + } // namespace ChromeML::ChromeML(base::PassKey<ChromeML>, @@ -115,6 +119,9 @@ } api->InitDawnProcs(dawn::native::GetProcs()); + if (api->SetFatalErrorFn) { + api->SetFatalErrorFn(&FatalErrorFn); + } return std::make_unique<ChromeML>(base::PassKey<ChromeML>(), std::move(scoped_library), api); }
diff --git a/services/on_device_model/ml/chrome_ml_api.h b/services/on_device_model/ml/chrome_ml_api.h index 895d6d3..829b564 100644 --- a/services/on_device_model/ml/chrome_ml_api.h +++ b/services/on_device_model/ml/chrome_ml_api.h
@@ -15,6 +15,9 @@ extern "C" { +// A function used to handle fatal errors. +using ChromeMLFatalErrorFn = void (*)(const char* msg); + // A scheduling function used to run arbitrary async tasks. Given to // CreateModelExecutor() and called into by ChromeML as needed. When called, the // value of `context` is the same value given to CreateModelExecutor(). @@ -153,6 +156,9 @@ // functions. void (*InitDawnProcs)(const DawnProcTable& procs); + // Sets an error handling function for fatal errors. + void (*SetFatalErrorFn)(ChromeMLFatalErrorFn error_fn) = nullptr; + // Creates a new ChromeML model instance as described by `model`. The returned // object can be destroyed by passing it to DestroyModel(). `context` is // forwarded to any invocations of `schedule` or `token_output` made by this
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json index a5d107a..9621b5c 100644 --- a/testing/buildbot/chromium.android.json +++ b/testing/buildbot/chromium.android.json
@@ -1300,22 +1300,19 @@ }, { "args": [ - "--shared-prefs-file=//chrome/android/shared_preference_files/test/vr_cardboard_skipdon_setupcomplete.json", "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--remove-system-package=com.google.vr.vrcore", - "--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk" + "--recover-devices" ], "merge": { "args": [ "--bucket", "chromium-result-details", "--test-name", - "chrome_public_test_vr_apk-ddready-cardboard" + "chrome_public_test_vr_apk" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "chrome_public_test_vr_apk-ddready-cardboard", + "name": "chrome_public_test_vr_apk", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1346,107 +1343,6 @@ }, { "args": [ - "--shared-prefs-file=//chrome/android/shared_preference_files/test/vr_ddview_skipdon_setupcomplete.json", - "--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_keyboard/vr_keyboard_current.apk", - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--git-revision=${got_revision}", - "--remove-system-package=com.google.vr.vrcore", - "--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "chrome_public_test_vr_apk-ddready-ddview" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "chrome_public_test_vr_apk-ddready-ddview", - "precommit_args": [ - "--gerrit-issue=${patch_issue}", - "--gerrit-patchset=${patch_set}", - "--buildbucket-id=${buildbucket_build_id}" - ], - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "OPM4.171019.021.P2", - "device_os_flavor": "google", - "device_os_type": "userdebug", - "device_type": "walleye", - "os": "Android" - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 4 - }, - "test": "chrome_public_test_vr_apk", - "test_id_prefix": "ninja://chrome/android:chrome_public_test_vr_apk/" - }, - { - "args": [ - "--shared-prefs-file=//chrome/android/shared_preference_files/test/vr_ddview_don_setupcomplete.json", - "--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_keyboard/vr_keyboard_current.apk", - "--annotation=Restriction=VR_DON_Enabled", - "--vr-don-enabled", - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--remove-system-package=com.google.vr.vrcore", - "--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "chrome_public_test_vr_apk-ddready-don-enabled" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "chrome_public_test_vr_apk-ddready-don-enabled", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "OPM4.171019.021.P2", - "device_os_flavor": "google", - "device_os_type": "userdebug", - "device_type": "walleye", - "os": "Android" - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "chrome_public_test_vr_apk", - "test_id_prefix": "ninja://chrome/android:chrome_public_test_vr_apk/" - }, - { - "args": [ "--gs-results-bucket=chromium-result-details", "--recover-devices", "--git-revision=${got_revision}" @@ -1715,22 +1611,19 @@ "gtest_tests": [ { "args": [ - "--shared-prefs-file=//chrome/android/shared_preference_files/test/vr_cardboard_skipdon_setupcomplete.json", "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--remove-system-package=com.google.vr.vrcore", - "--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk" + "--recover-devices" ], "merge": { "args": [ "--bucket", "chromium-result-details", "--test-name", - "chrome_public_test_vr_apk-ddready-cardboard" + "chrome_public_test_vr_apk" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "chrome_public_test_vr_apk-ddready-cardboard", + "name": "chrome_public_test_vr_apk", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -1761,107 +1654,6 @@ }, { "args": [ - "--shared-prefs-file=//chrome/android/shared_preference_files/test/vr_ddview_skipdon_setupcomplete.json", - "--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_keyboard/vr_keyboard_current.apk", - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--git-revision=${got_revision}", - "--remove-system-package=com.google.vr.vrcore", - "--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "chrome_public_test_vr_apk-ddready-ddview" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "chrome_public_test_vr_apk-ddready-ddview", - "precommit_args": [ - "--gerrit-issue=${patch_issue}", - "--gerrit-patchset=${patch_set}", - "--buildbucket-id=${buildbucket_build_id}" - ], - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "QQ1A.191205.008", - "device_os_flavor": "google", - "device_os_type": "userdebug", - "device_type": "walleye", - "os": "Android" - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 4 - }, - "test": "chrome_public_test_vr_apk", - "test_id_prefix": "ninja://chrome/android:chrome_public_test_vr_apk/" - }, - { - "args": [ - "--shared-prefs-file=//chrome/android/shared_preference_files/test/vr_ddview_don_setupcomplete.json", - "--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_keyboard/vr_keyboard_current.apk", - "--annotation=Restriction=VR_DON_Enabled", - "--vr-don-enabled", - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--remove-system-package=com.google.vr.vrcore", - "--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "chrome_public_test_vr_apk-ddready-don-enabled" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "chrome_public_test_vr_apk-ddready-don-enabled", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "QQ1A.191205.008", - "device_os_flavor": "google", - "device_os_type": "userdebug", - "device_type": "walleye", - "os": "Android" - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "chrome_public_test_vr_apk", - "test_id_prefix": "ninja://chrome/android:chrome_public_test_vr_apk/" - }, - { - "args": [ "--gs-results-bucket=chromium-result-details", "--recover-devices" ], @@ -18309,8 +18101,6 @@ }, { "args": [ - "--shared-prefs-file=//chrome/android/shared_preference_files/test/vr_cardboard_skipdon_setupcomplete.json", - "--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk", "--gs-results-bucket=chromium-result-details", "--recover-devices" ], @@ -30662,22 +30452,19 @@ }, { "args": [ - "--shared-prefs-file=//chrome/android/shared_preference_files/test/vr_cardboard_skipdon_setupcomplete.json", "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--remove-system-package=com.google.vr.vrcore", - "--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk" + "--recover-devices" ], "merge": { "args": [ "--bucket", "chromium-result-details", "--test-name", - "chrome_public_test_vr_apk-ddready-cardboard" + "chrome_public_test_vr_apk" ], "script": "//build/android/pylib/results/presentation/test_results_presentation.py" }, - "name": "chrome_public_test_vr_apk-ddready-cardboard", + "name": "chrome_public_test_vr_apk", "resultdb": { "enable": true, "has_native_resultdb_integration": true @@ -30708,107 +30495,6 @@ }, { "args": [ - "--shared-prefs-file=//chrome/android/shared_preference_files/test/vr_ddview_skipdon_setupcomplete.json", - "--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_keyboard/vr_keyboard_current.apk", - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--git-revision=${got_revision}", - "--remove-system-package=com.google.vr.vrcore", - "--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "chrome_public_test_vr_apk-ddready-ddview" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "chrome_public_test_vr_apk-ddready-ddview", - "precommit_args": [ - "--gerrit-issue=${patch_issue}", - "--gerrit-patchset=${patch_set}", - "--buildbucket-id=${buildbucket_build_id}" - ], - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "PQ3A.190801.002", - "device_os_flavor": "google", - "device_os_type": "userdebug", - "device_type": "walleye", - "os": "Android" - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 4 - }, - "test": "chrome_public_test_vr_apk", - "test_id_prefix": "ninja://chrome/android:chrome_public_test_vr_apk/" - }, - { - "args": [ - "--shared-prefs-file=//chrome/android/shared_preference_files/test/vr_ddview_don_setupcomplete.json", - "--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_keyboard/vr_keyboard_current.apk", - "--annotation=Restriction=VR_DON_Enabled", - "--vr-don-enabled", - "--gs-results-bucket=chromium-result-details", - "--recover-devices", - "--remove-system-package=com.google.vr.vrcore", - "--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "chrome_public_test_vr_apk-ddready-don-enabled" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "name": "chrome_public_test_vr_apk-ddready-don-enabled", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "dimensions": { - "device_os": "PQ3A.190801.002", - "device_os_flavor": "google", - "device_os_type": "userdebug", - "device_type": "walleye", - "os": "Android" - }, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test": "chrome_public_test_vr_apk", - "test_id_prefix": "ninja://chrome/android:chrome_public_test_vr_apk/" - }, - { - "args": [ "--gs-results-bucket=chromium-result-details", "--recover-devices" ],
diff --git a/testing/buildbot/chromium.coverage.json b/testing/buildbot/chromium.coverage.json index fb1817cd..e96daca 100644 --- a/testing/buildbot/chromium.coverage.json +++ b/testing/buildbot/chromium.coverage.json
@@ -98,8 +98,6 @@ }, { "args": [ - "--shared-prefs-file=//chrome/android/shared_preference_files/test/vr_cardboard_skipdon_setupcomplete.json", - "--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk", "--gs-results-bucket=chromium-result-details", "--recover-devices" ],
diff --git a/testing/buildbot/chromium.fuchsia.json b/testing/buildbot/chromium.fuchsia.json index c179ff05..f3cd0c2 100644 --- a/testing/buildbot/chromium.fuchsia.json +++ b/testing/buildbot/chromium.fuchsia.json
@@ -3,6 +3,7 @@ "AAAAA2 See generate_buildbot_json.py to make changes": {}, "fuchsia-arm64-cast-receiver-rel": { "additional_compile_targets": [ + "all", "cast_test_lists" ], "gtest_tests": [ @@ -1947,6 +1948,7 @@ }, "fuchsia-x64-cast-receiver-rel": { "additional_compile_targets": [ + "all", "cast_test_lists" ], "gtest_tests": [
diff --git a/testing/buildbot/filters/linux-chromeos.browser_tests.require_lacros.filter b/testing/buildbot/filters/linux-chromeos.browser_tests.require_lacros.filter index f50c191..1e9f07b 100644 --- a/testing/buildbot/filters/linux-chromeos.browser_tests.require_lacros.filter +++ b/testing/buildbot/filters/linux-chromeos.browser_tests.require_lacros.filter
@@ -20,6 +20,7 @@ FileTaskBrowserTest* NonKioskAcceleratorLacrosTest* SelectToSpeak* +StickyKeysBrowserTest* SwitchAccess* VpnExtensionObserverBrowserTest* WebAppsCrosapiBrowserTest* @@ -53,11 +54,12 @@ -AutoclickWithAccessibilityServiceTest.ScrollableBoundsPlumbing # TODO(b/277256412): Test is flaky -DictationUIE2ETest.HintsTimeoutWithChromeVox +# TODO(b/316393493): Figure out how to set home button pref in Lacros. +-StickyKeysBrowserTest.CtrlClickHomeButton # TODO(accessibility): these are native C++ tests that need investigation. -TestAsNormalAndGuestUser/SpokenFeedbackTest.NavigateChromeVoxMenu* -TestAsNormalAndGuestUser/SpokenFeedbackTest.ShowFormControlsList* -SelectToSpeakTest.ContinuesReadingDuringResize --StickyKeysBrowserTest* # These tests do not run with the browser and do not need to run with Lacros. -AccessibilityCommonTest* -AccessibilityPrivateApiTest* @@ -69,6 +71,8 @@ -AccessibilityHighlightsBrowserTest.CursorHighlightAddsFocusRing -SelectToSpeakTest.SelectToSpeakDoesNotDismissTrayBubble -SelectToSpeakTest.SpeakStatusTray +-StickyKeysBrowserTest.OpenTrayMenu +-StickyKeysBrowserTest.OverlayShown -TestAsNormalAndGuestUser/SpokenFeedbackTest.TouchExploreStatusTray* -TestAsNormalAndGuestUser/SpokenFeedbackTest.ShelfBlockedAppIconBadgeAnnouncement* -TestAsNormalAndGuestUser/SpokenFeedbackTest.ShelfNotificationBadgeAnnouncement* @@ -77,6 +81,7 @@ -TestAsNormalAndGuestUser/SpokenFeedbackTest.FocusShelf* -TestAsNormalAndGuestUser/SpokenFeedbackTest.ShelfIconFocusForward* -TestAsNormalAndGuestUser/SpokenFeedbackTest.TouchExploreSecondaryDisplay* +-TouchExplorationTest # TODO(crbug/1484723): Flaky -BrowserAppShelfControllerBrowserTest.WindowedApps -BrowserAppShelfControllerBrowserTest.TabbedApps
diff --git a/testing/buildbot/mixins.pyl b/testing/buildbot/mixins.pyl index a81110f..a46890b8 100644 --- a/testing/buildbot/mixins.pyl +++ b/testing/buildbot/mixins.pyl
@@ -1133,12 +1133,6 @@ }, }, }, - 'vr_instrumentation_test': { - 'args': [ - '--remove-system-package=com.google.vr.vrcore', - '--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk', - ], - }, 'walleye': { 'swarming': { 'dimensions': {
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl index 7b9865cc..51130324 100644 --- a/testing/buildbot/test_suites.pyl +++ b/testing/buildbot/test_suites.pyl
@@ -35,47 +35,6 @@ 'vr_android_unittests': {}, }, - 'android_ddready_vr_gtests': { - 'chrome_public_test_vr_apk-ddready-cardboard': { - 'test': 'chrome_public_test_vr_apk', - 'mixins': [ - 'vr_instrumentation_test', - ], - 'args': [ - '--shared-prefs-file=//chrome/android/shared_preference_files/test/vr_cardboard_skipdon_setupcomplete.json', - ], - 'swarming': { - 'shards': 2, - }, - }, - 'chrome_public_test_vr_apk-ddready-ddview': { - 'test': 'chrome_public_test_vr_apk', - 'mixins': [ - 'skia_gold_test', - 'vr_instrumentation_test', - ], - 'args': [ - '--shared-prefs-file=//chrome/android/shared_preference_files/test/vr_ddview_skipdon_setupcomplete.json', - '--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_keyboard/vr_keyboard_current.apk', - ], - 'swarming': { - 'shards': 4, - }, - }, - 'chrome_public_test_vr_apk-ddready-don-enabled': { - 'test': 'chrome_public_test_vr_apk', - 'mixins': [ - 'vr_instrumentation_test', - ], - 'args': [ - '--shared-prefs-file=//chrome/android/shared_preference_files/test/vr_ddview_don_setupcomplete.json', - '--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_keyboard/vr_keyboard_current.apk', - '--annotation=Restriction=VR_DON_Enabled', - '--vr-don-enabled', - ], - }, - }, - 'android_emulator_specific_chrome_public_tests': { 'chrome_public_test_apk': { 'mixins': [ @@ -5320,10 +5279,6 @@ 'vr_android_specific_chromium_tests': { 'chrome_public_test_vr_apk': { - 'args': [ - '--shared-prefs-file=//chrome/android/shared_preference_files/test/vr_cardboard_skipdon_setupcomplete.json', - '--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk', - ], 'swarming': { 'shards': 2, }, @@ -5814,8 +5769,8 @@ 'android_10_rel_gtests': [ 'android_ar_gtests', - 'android_ddready_vr_gtests', 'android_trichrome_smoke_tests', + 'vr_android_specific_chromium_tests', ], 'android_12_dbg_emulator_gtests': [ @@ -5849,10 +5804,10 @@ 'android_oreo_gtests': [ 'android_ar_gtests', - 'android_ddready_vr_gtests', 'android_monochrome_smoke_tests', 'android_oreo_standard_gtests', 'android_smoke_tests', + 'vr_android_specific_chromium_tests', ], 'android_pie_coverage_instrumentation_tests': [ @@ -5865,10 +5820,10 @@ 'android_pie_gtests': [ 'android_ar_gtests', - 'android_ddready_vr_gtests', 'android_monochrome_smoke_tests', 'android_smoke_tests', 'chromium_tracing_gtests', + 'vr_android_specific_chromium_tests', ], 'android_pie_rel_emulator_gtests': [
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl index db1cffb..1a8e97b 100644 --- a/testing/buildbot/waterfalls.pyl +++ b/testing/buildbot/waterfalls.pyl
@@ -2972,13 +2972,14 @@ 'mixins': ['chromium-tester-service-account'], 'machines': { 'fuchsia-arm64-cast-receiver-rel': { + 'additional_compile_targets': [ + 'all', + 'cast_test_lists', + ], 'test_suites': { 'gtest_tests': 'fuchsia_web_engine_non_graphical_gtests', 'isolated_scripts': 'fuchsia_arm64_isolated_scripts', }, - 'additional_compile_targets': [ - 'cast_test_lists', - ], 'mixins': [ 'arm64', 'docker', @@ -3000,6 +3001,10 @@ ], }, 'fuchsia-x64-cast-receiver-rel': { + 'additional_compile_targets': [ + 'all', + 'cast_test_lists', + ], 'browser_config': 'web-engine-shell', 'os_type': 'fuchsia', 'mixins': [ @@ -3016,9 +3021,6 @@ 'gtest_tests': 'fuchsia_gtests', 'isolated_scripts': 'fuchsia_isolated_scripts', }, - 'additional_compile_targets': [ - 'cast_test_lists', - ], }, 'fuchsia-x64-dbg': { 'additional_compile_targets': [
diff --git a/testing/flake_suppressor_common/argument_parsing.py b/testing/flake_suppressor_common/argument_parsing.py index 8b86568..723e458 100644 --- a/testing/flake_suppressor_common/argument_parsing.py +++ b/testing/flake_suppressor_common/argument_parsing.py
@@ -16,7 +16,8 @@ '"chrome-luci-data.chromium.gpu_ci_test_results".')) parser.add_argument('--sample-period', type=int, - default=1, + default=7, + choices=range(1, 30), help=('The number of days to sample data from.')) parser.add_argument('--no-group-by-tags', action='store_false', @@ -77,7 +78,7 @@ parser.add_argument( '--build-fail-total-number-threshold', type=int, - default=0, + default=10, help=('Threshold based on failed build number when ' '--non-hidden-failures-only is used. A test will be ' 'suppressed if its failed build number is equal to or more than ' @@ -87,11 +88,19 @@ '--build-fail-consecutive-days-threshold', type=int, default=2, + choices=range(1, 30), help=('Threshold based on number of consecutive days that non-hidden' 'failures occur. A test will be suppressed if the number of' 'consecutive days that it has non-hidden failures is equal' 'to or more than this threshold. All --build-fail*-thresholds ' 'must be hit in order for a test to actually be suppressed.')) + parser.add_argument('--build-fail-recent-days-threshold', + type=int, + default=2, + choices=range(1, 30), + help=('Suppress tests with non-hidden build failures' + ' within |build_fail_recent_day_threshold| days ' + 'when all other build-fail* thresholds meet.')) parser.add_argument('--builder-name', default=[], action="append", @@ -109,8 +118,5 @@ '--flaky-threshold must be greater than --ignore-threshold') if args.build_fail_total_number_threshold < 0: raise ValueError('--build-fail-total-number-threshold must be positive') - if args.build_fail_consecutive_days_threshold < 0: - raise ValueError('--build-fail-consecutive-days-threshold must be ' - 'positive') return args
diff --git a/testing/flake_suppressor_common/expectations.py b/testing/flake_suppressor_common/expectations.py index 28cd2ab2..44a66de 100644 --- a/testing/flake_suppressor_common/expectations.py +++ b/testing/flake_suppressor_common/expectations.py
@@ -5,7 +5,7 @@ import base64 import collections -from datetime import timedelta +from datetime import timedelta, date import itertools import os import posixpath @@ -52,7 +52,7 @@ return False -def OverFailedBuildByDayThreshold( +def OverFailedBuildByConsecutiveDayThreshold( failed_result_tuple_list: List[ct.ResultTupleType], build_fail_consecutive_day_threshold: int) -> bool: """Check if the max number of build fail in consecutive date @@ -89,6 +89,28 @@ return False +def FailedBuildWithinRecentDayThreshold( + failed_result_tuple_list: List[ct.ResultTupleType], + build_fail_recent_day_threshold: int) -> bool: + """Check if there are any failed builds within the most + recent |build_fail_latest_day_threshold| days. + + Args: + failed_result_tuple_list: A list of ct.ResultTupleType failed test result. + build_fail_recent_day_threshold: Threshold base on the recent day range + that the test caused build fail. + + Returns: + Whether the test caused build fail within the recent day. + """ + recent_check_day = date.today() - timedelta( + days=build_fail_recent_day_threshold) + for test in failed_result_tuple_list: + if test.date >= recent_check_day: + return True + return False + + class ExpectationProcessor(): # pylint: disable=too-many-locals def IterateThroughResultsForUser(self, result_map: ct.AggregatedResultsType, @@ -191,7 +213,8 @@ def CreateExpectationsForAllResults( self, result_map: ct.AggregatedStatusResultsType, group_by_tags: bool, include_all_tags: bool, build_fail_total_number_threshold: int, - build_fail_consecutive_day_threshold: int) -> None: + build_fail_consecutive_day_threshold: int, + build_fail_recent_day_threshold: int) -> None: """Iterates over |result_map|, selects tests that hit all build-fail*-thresholds and adds expectations for their results. Same test in all builders that caused build fail must be over all threshold @@ -215,6 +238,11 @@ expectations, if the consecutive days that it caused build fail are equal to or more than this. All build-fail*-thresholds must be hit in order for a test to actually be suppressed. + build_fail_recent_day_threshold: How many days worth of recent builds + to check for non-hidden failures. A test will be suppressed if + it has non-hidden failures within this time span. All + build-fail*-thresholds must be hit in order for a test to actually + be suppressed. """ for suite, test_map in result_map.items(): if self.IsSuiteUnsupported(suite): @@ -225,10 +253,13 @@ all_results = list(itertools.chain(*tag_map.values())) if (not OverFailedBuildThreshold(all_results, build_fail_total_number_threshold) - or not OverFailedBuildByDayThreshold( + or not OverFailedBuildByConsecutiveDayThreshold( all_results, build_fail_consecutive_day_threshold)): continue for typ_tags, result_tuple_list in tag_map.items(): + if not FailedBuildWithinRecentDayThreshold( + result_tuple_list, build_fail_recent_day_threshold): + continue status = set() for test_result in result_tuple_list: # Should always add a pass to all flaky web tests in
diff --git a/testing/flake_suppressor_common/expectations_unittest.py b/testing/flake_suppressor_common/expectations_unittest.py index 08772b5..ad58c57f 100755 --- a/testing/flake_suppressor_common/expectations_unittest.py +++ b/testing/flake_suppressor_common/expectations_unittest.py
@@ -322,48 +322,45 @@ 'pixel_integration_test': { 'foo_test': { tuple(['win']): [ - ct.ResultTupleType(ct.ResultStatus.FAIL, - 'http://ci.chromium.org/b/1111', - datetime.date(2022, 1, - 2), False, ['Pass']), - ct.ResultTupleType(ct.ResultStatus.FAIL, - 'http://ci.chromium.org/b/2222', - datetime.date(2022, 1, - 1), False, ['Pass']), + ct.ResultTupleType( + ct.ResultStatus.FAIL, 'http://ci.chromium.org/b/1111', + datetime.date.today() - datetime.timedelta(days=2), + False, ['Pass']), + ct.ResultTupleType( + ct.ResultStatus.FAIL, 'http://ci.chromium.org/b/2222', + datetime.date.today() - datetime.timedelta(days=3), + False, ['Pass']), ct.ResultTupleType(ct.ResultStatus.FAIL, 'http://ci.chromium.org/b/3333', - datetime.date(2022, 1, - 4), False, ['Pass']), + datetime.date.today(), False, ['Pass']), ], tuple(['mac']): [ - ct.ResultTupleType(ct.ResultStatus.FAIL, - 'http://ci.chromium.org/b/1111', - datetime.date(2022, 1, - 5), False, ['Pass']), + ct.ResultTupleType( + ct.ResultStatus.FAIL, 'http://ci.chromium.org/b/1111', + datetime.date.today() - datetime.timedelta(days=1), + False, ['Pass']), ct.ResultTupleType(ct.ResultStatus.FAIL, 'http://ci.chromium.org/b/2222', - datetime.date(2022, 1, - 6), False, ['Pass']), - ct.ResultTupleType(ct.ResultStatus.FAIL, - 'http://ci.chromium.org/b/3333', - datetime.date(2022, 1, - 3), False, ['Pass']), + datetime.date.today(), False, ['Pass']), + ct.ResultTupleType( + ct.ResultStatus.FAIL, 'http://ci.chromium.org/b/3333', + datetime.date.today() - datetime.timedelta(days=3), + False, ['Pass']), ], }, 'bar_test': { tuple(['win']): [ ct.ResultTupleType(ct.ResultStatus.FAIL, 'http://ci.chromium.org/b/4444', - datetime.date(2022, 1, - 9), False, ['Pass']), - ct.ResultTupleType(ct.ResultStatus.FAIL, - 'http://ci.chromium.org/b/5555', - datetime.date(2022, 1, - 8), False, ['Pass']), - ct.ResultTupleType(ct.ResultStatus.FAIL, - 'http://ci.chromium.org/b/6666', - datetime.date(2022, 1, - 7), False, ['Pass']), + datetime.date.today(), False, ['Pass']), + ct.ResultTupleType( + ct.ResultStatus.FAIL, 'http://ci.chromium.org/b/5555', + datetime.date.today() - datetime.timedelta(days=1), + False, ['Pass']), + ct.ResultTupleType( + ct.ResultStatus.FAIL, 'http://ci.chromium.org/b/6666', + datetime.date.today() - datetime.timedelta(days=2), + False, ['Pass']), ], }, 'baz_test': { @@ -372,26 +369,21 @@ tuple(['win']): [ ct.ResultTupleType(ct.ResultStatus.FAIL, 'http://ci.chromium.org/b/7777', - datetime.date(2021, 1, - 10), False, ['Pass']), + datetime.date.today(), False, ['Pass']), ct.ResultTupleType(ct.ResultStatus.FAIL, 'http://ci.chromium.org/b/8888', - datetime.date(2022, 1, - 10), False, ['Pass']), + datetime.date.today(), False, ['Pass']), ct.ResultTupleType(ct.ResultStatus.FAIL, 'http://ci.chromium.org/b/9999', - datetime.date(2023, 1, - 10), False, ['Pass']), + datetime.date.today(), False, ['Pass']), ], tuple(['mac']): [ ct.ResultTupleType(ct.ResultStatus.FAIL, 'http://ci.chromium.org/b/7777', - datetime.date(2022, 1, - 10), False, ['Pass']), + datetime.date.today(), False, ['Pass']), ct.ResultTupleType(ct.ResultStatus.FAIL, 'http://ci.chromium.org/b/8888', - datetime.date(2022, 1, - 10), False, ['Pass']), + datetime.date.today(), False, ['Pass']), ], }, 'wpt_test': { @@ -399,24 +391,23 @@ tuple(['win']): [ ct.ResultTupleType(ct.ResultStatus.FAIL, 'http://ci.chromium.org/b/1234', - datetime.date(2021, 1, - 10), False, ['Pass']), + datetime.date.today(), False, ['Pass']), ], tuple(['mac']): [ - ct.ResultTupleType(ct.ResultStatus.FAIL, - 'http://ci.chromium.org/b/2345', - datetime.date(2022, 1, - 11), False, ['Pass']), + ct.ResultTupleType( + ct.ResultStatus.FAIL, 'http://ci.chromium.org/b/2345', + datetime.date.today() - datetime.timedelta(days=1), + False, ['Pass']), ct.ResultTupleType(ct.ResultStatus.FAIL, 'http://ci.chromium.org/b/3456', - datetime.date(2022, 1, - 12), False, ['Pass']), + datetime.date.today(), False, ['Pass']), ], }, }, } self.build_fail_total_number_threshold = 3 self.build_fail_consecutive_day_threshold = 2 + self.build_fail_recent_day_threshold = 1 self.expectation_file = os.path.join(uu.ABSOLUTE_EXPECTATION_FILE_DIRECTORY, 'pixel_expectations.txt') @@ -439,7 +430,8 @@ """Tests that threshold-based expectations work when grouping by tags.""" self._expectations.CreateExpectationsForAllResults( self.result_map, True, True, self.build_fail_total_number_threshold, - self.build_fail_consecutive_day_threshold) + self.build_fail_consecutive_day_threshold, + self.build_fail_recent_day_threshold) expected_contents = uu.TAG_HEADER + """\ [ win ] some_test [ Failure Pass ] [ win ] foo_test [ Failure Pass ] @@ -457,7 +449,8 @@ """Tests that threshold-based expectations work when not grouping by tags""" self._expectations.CreateExpectationsForAllResults( self.result_map, False, True, self.build_fail_total_number_threshold, - self.build_fail_consecutive_day_threshold) + self.build_fail_consecutive_day_threshold, + self.build_fail_recent_day_threshold) expected_contents = uu.TAG_HEADER + """\ [ win ] some_test [ Failure Pass ] [ mac ] some_test [ Failure Pass ] @@ -477,48 +470,45 @@ 'pixel_integration_test': { 'foo_test': { tuple(['win', 'win10']): [ - ct.ResultTupleType(ct.ResultStatus.FAIL, - 'http://ci.chromium.org/b/1111', - datetime.date(2022, 1, - 2), False, ['Pass']), - ct.ResultTupleType(ct.ResultStatus.FAIL, - 'http://ci.chromium.org/b/2222', - datetime.date(2022, 1, - 1), False, ['Pass']), + ct.ResultTupleType( + ct.ResultStatus.FAIL, 'http://ci.chromium.org/b/1111', + datetime.date.today() - datetime.timedelta(days=2), + False, ['Pass']), + ct.ResultTupleType( + ct.ResultStatus.FAIL, 'http://ci.chromium.org/b/2222', + datetime.date.today() - datetime.timedelta(days=3), + False, ['Pass']), ct.ResultTupleType(ct.ResultStatus.FAIL, 'http://ci.chromium.org/b/3333', - datetime.date(2022, 1, - 4), False, ['Pass']), + datetime.date.today(), False, ['Pass']), ], tuple(['mac']): [ - ct.ResultTupleType(ct.ResultStatus.FAIL, - 'http://ci.chromium.org/b/1111', - datetime.date(2022, 1, - 5), False, ['Pass']), + ct.ResultTupleType( + ct.ResultStatus.FAIL, 'http://ci.chromium.org/b/1111', + datetime.date.today() - datetime.timedelta(days=1), + False, ['Pass']), ct.ResultTupleType(ct.ResultStatus.FAIL, 'http://ci.chromium.org/b/2222', - datetime.date(2022, 1, - 6), False, ['Pass']), - ct.ResultTupleType(ct.ResultStatus.FAIL, - 'http://ci.chromium.org/b/3333', - datetime.date(2022, 1, - 3), False, ['Pass']), + datetime.date.today(), False, ['Pass']), + ct.ResultTupleType( + ct.ResultStatus.FAIL, 'http://ci.chromium.org/b/3333', + datetime.date.today() - datetime.timedelta(days=3), + False, ['Pass']), ], }, 'bar_test': { tuple(['win', 'win10']): [ ct.ResultTupleType(ct.ResultStatus.FAIL, 'http://ci.chromium.org/b/4444', - datetime.date(2022, 1, - 9), False, ['Pass']), - ct.ResultTupleType(ct.ResultStatus.FAIL, - 'http://ci.chromium.org/b/5555', - datetime.date(2022, 1, - 8), False, ['Pass']), - ct.ResultTupleType(ct.ResultStatus.FAIL, - 'http://ci.chromium.org/b/6666', - datetime.date(2022, 1, - 7), False, ['Pass']), + datetime.date.today(), False, ['Pass']), + ct.ResultTupleType( + ct.ResultStatus.FAIL, 'http://ci.chromium.org/b/5555', + datetime.date.today() - datetime.timedelta(days=1), + False, ['Pass']), + ct.ResultTupleType( + ct.ResultStatus.FAIL, 'http://ci.chromium.org/b/6666', + datetime.date.today() - datetime.timedelta(days=2), + False, ['Pass']), ], }, 'baz_test': { @@ -527,33 +517,29 @@ tuple(['win']): [ ct.ResultTupleType(ct.ResultStatus.FAIL, 'http://ci.chromium.org/b/7777', - datetime.date(2021, 1, - 10), False, ['Pass']), + datetime.date.today(), False, ['Pass']), ct.ResultTupleType(ct.ResultStatus.FAIL, 'http://ci.chromium.org/b/8888', - datetime.date(2022, 1, - 10), False, ['Pass']), + datetime.date.today(), False, ['Pass']), ct.ResultTupleType(ct.ResultStatus.FAIL, 'http://ci.chromium.org/b/9999', - datetime.date(2023, 1, - 10), False, ['Pass']), + datetime.date.today(), False, ['Pass']), ], tuple(['mac']): [ ct.ResultTupleType(ct.ResultStatus.FAIL, 'http://ci.chromium.org/b/7777', - datetime.date(2022, 1, - 10), False, ['Pass']), + datetime.date.today(), False, ['Pass']), ct.ResultTupleType(ct.ResultStatus.FAIL, 'http://ci.chromium.org/b/8888', - datetime.date(2022, 1, - 10), False, ['Pass']), + datetime.date.today(), False, ['Pass']), ], }, }, } self._expectations.CreateExpectationsForAllResults( self.result_map, False, False, self.build_fail_total_number_threshold, - self.build_fail_consecutive_day_threshold) + self.build_fail_consecutive_day_threshold, + self.build_fail_recent_day_threshold) expected_contents = uu.TAG_HEADER + """\ [ win ] some_test [ Failure Pass ] [ mac ] some_test [ Failure Pass ] @@ -931,7 +917,7 @@ result_tuple_list, self.build_fail_total_number_threshold)) -class OverFailedBuildByDayThresholdUnittest(unittest.TestCase): +class OverFailedBuildByConsecutiveDayThresholdUnittest(unittest.TestCase): def setUp(self) -> None: self.build_fail_consecutive_day_threshold = 3 @@ -953,7 +939,7 @@ datetime.date(2022, 1, 3), False, ['Pass']), ] self.assertTrue( - expectations.OverFailedBuildByDayThreshold( + expectations.OverFailedBuildByConsecutiveDayThreshold( result_tuple_list, self.build_fail_consecutive_day_threshold)) def testUnderThreshold(self) -> None: @@ -974,7 +960,7 @@ datetime.date(2022, 1, 1), False, ['Pass']), ] self.assertFalse( - expectations.OverFailedBuildByDayThreshold( + expectations.OverFailedBuildByConsecutiveDayThreshold( result_tuple_list, self.build_fail_consecutive_day_threshold)) result_tuple_list = [ @@ -986,7 +972,7 @@ datetime.date(2022, 1, 2), False, ['Pass']), ] self.assertFalse( - expectations.OverFailedBuildByDayThreshold( + expectations.OverFailedBuildByConsecutiveDayThreshold( result_tuple_list, self.build_fail_consecutive_day_threshold)) result_tuple_list = [ @@ -1001,9 +987,56 @@ datetime.date(2022, 1, 4), False, ['Pass']), ] self.assertFalse( - expectations.OverFailedBuildByDayThreshold( + expectations.OverFailedBuildByConsecutiveDayThreshold( result_tuple_list, self.build_fail_consecutive_day_threshold)) +class FailedBuildWithinRecentDayThresholdUnittest(unittest.TestCase): + def setUp(self) -> None: + self.build_fail_recent_day_threshold = 3 + + def testWithinThreshold(self) -> None: + """Tests functionality when |result_tuple_list| has build fail within + |build_fail_recent_day_threshold|. + + True is expected output on these inputs. + """ + result_tuple_list = [ + ct.ResultTupleType(ct.ResultStatus.FAIL, + 'http://ci.chromium.org/b/1111', + datetime.date.today(), False, ['Pass']), + ct.ResultTupleType(ct.ResultStatus.FAIL, + 'http://ci.chromium.org/b/2222', + datetime.date.today(), False, ['Pass']), + ct.ResultTupleType(ct.ResultStatus.FAIL, + 'http://ci.chromium.org/b/3333', + datetime.date.today(), False, ['Pass']), + ] + self.assertTrue( + expectations.FailedBuildWithinRecentDayThreshold( + result_tuple_list, self.build_fail_recent_day_threshold)) + + def testBeyondThreshold(self) -> None: + """Tests functionality when |result_tuple_list| has no build fail within + |build_fail_recent_day_threshold|. + + False is expected output on these inputs. + """ + result_tuple_list = [ + ct.ResultTupleType(ct.ResultStatus.FAIL, + 'http://ci.chromium.org/b/1111', + datetime.date(2022, 1, 1), False, ['Pass']), + ct.ResultTupleType(ct.ResultStatus.FAIL, + 'http://ci.chromium.org/b/2222', + datetime.date(2022, 1, 1), False, ['Pass']), + ct.ResultTupleType(ct.ResultStatus.FAIL, + 'http://ci.chromium.org/b/3333', + datetime.date(2022, 1, 1), False, ['Pass']), + ] + self.assertFalse( + expectations.FailedBuildWithinRecentDayThreshold( + result_tuple_list, self.build_fail_recent_day_threshold)) + + if __name__ == '__main__': unittest.main(verbosity=2)
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 22053408..9673a9b6 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -4018,7 +4018,6 @@ "use_root_bookmark_as_default": "true" }, "enable_features": [ - "BookmarksImprovedSaveFlow", "CommercePriceTracking", "OptimizationGuidePushNotifications", "ReadLater", @@ -4052,7 +4051,6 @@ "use_root_bookmark_as_default": "true" }, "enable_features": [ - "BookmarksImprovedSaveFlow", "ReadLater" ] }, @@ -4094,7 +4092,6 @@ "use_root_bookmark_as_default": "true" }, "enable_features": [ - "BookmarksImprovedSaveFlow", "CommercePriceTracking", "ReadLater" ] @@ -4111,7 +4108,6 @@ "use_root_bookmark_as_default": "true" }, "enable_features": [ - "BookmarksImprovedSaveFlow", "CommercePriceTracking", "OptimizationGuidePushNotifications", "ReadLater", @@ -4127,7 +4123,6 @@ "use_root_bookmark_as_default": "true" }, "enable_features": [ - "BookmarksImprovedSaveFlow", "ReadLater" ] }, @@ -4144,7 +4139,6 @@ "use_root_bookmark_as_default": "true" }, "enable_features": [ - "BookmarksImprovedSaveFlow", "CommercePriceTracking", "OptimizationGuidePushNotifications", "ReadLater", @@ -4165,7 +4159,6 @@ "use_root_bookmark_as_default": "true" }, "enable_features": [ - "BookmarksImprovedSaveFlow", "CommercePriceTracking", "OptimizationGuidePushNotifications", "ReadLater", @@ -17196,45 +17189,6 @@ ] } ], - "SharedHighlightingTimeout": [ - { - "platforms": [ - "chromeos", - "chromeos_lacros", - "fuchsia", - "linux", - "mac", - "windows" - ], - "experiments": [ - { - "name": "Enabled_600", - "params": { - "TimeoutLengthMs": "600" - }, - "enable_features": [ - "PreemptiveLinkToTextGeneration" - ] - } - ] - }, - { - "platforms": [ - "android" - ], - "experiments": [ - { - "name": "Enabled_120", - "params": { - "TimeoutLengthMs": "120" - }, - "enable_features": [ - "PreemptiveLinkToTextGeneration" - ] - } - ] - } - ], "SharingHubDesktopScreenshots": [ { "platforms": [
diff --git a/third_party/blink/common/interest_group/interest_group.cc b/third_party/blink/common/interest_group/interest_group.cc index d603a219..f5d1647 100644 --- a/third_party/blink/common/interest_group/interest_group.cc +++ b/third_party/blink/common/interest_group/interest_group.cc
@@ -379,6 +379,18 @@ other.aggregation_coordinator_origin); } +std::string_view InterestGroup::TrustedBiddingSignalsSlotSizeModeToString( + TrustedBiddingSignalsSlotSizeMode slot_size_mode) { + switch (slot_size_mode) { + case TrustedBiddingSignalsSlotSizeMode::kNone: + return "none"; + case TrustedBiddingSignalsSlotSizeMode::kSlotSize: + return "slot-size"; + case TrustedBiddingSignalsSlotSizeMode::kAllSlotsRequestedSizes: + return "all-slots-requested-sizes"; + } +} + std::string KAnonKeyForAdBid(const InterestGroup& group, const GURL& ad_url) { return KAnonKeyForAdBid(group, blink::AdDescriptor(ad_url)); }
diff --git a/third_party/blink/common/interest_group/interest_group_unittest.cc b/third_party/blink/common/interest_group/interest_group_unittest.cc index 6e638629..5588306 100644 --- a/third_party/blink/common/interest_group/interest_group_unittest.cc +++ b/third_party/blink/common/interest_group/interest_group_unittest.cc
@@ -41,4 +41,33 @@ KAnonKeyForAdNameReporting(ig, ig.ads->at(2))); } +// Test ParseTrustedBiddingSignalsSlotSizeMode() and +// TrustedBiddingSignalsSlotSizeModeToString(). +TEST(InterestGroupTest, TrustedBiddingSignalsSlotSizeMode) { + EXPECT_EQ(InterestGroup::TrustedBiddingSignalsSlotSizeMode::kNone, + InterestGroup::ParseTrustedBiddingSignalsSlotSizeMode("none")); + EXPECT_EQ("none", + InterestGroup::TrustedBiddingSignalsSlotSizeModeToString( + InterestGroup::TrustedBiddingSignalsSlotSizeMode::kNone)); + + EXPECT_EQ(InterestGroup::TrustedBiddingSignalsSlotSizeMode::kSlotSize, + InterestGroup::ParseTrustedBiddingSignalsSlotSizeMode("slot-size")); + EXPECT_EQ("slot-size", + InterestGroup::TrustedBiddingSignalsSlotSizeModeToString( + InterestGroup::TrustedBiddingSignalsSlotSizeMode::kSlotSize)); + + EXPECT_EQ( + InterestGroup::TrustedBiddingSignalsSlotSizeMode::kAllSlotsRequestedSizes, + InterestGroup::ParseTrustedBiddingSignalsSlotSizeMode( + "all-slots-requested-sizes")); + EXPECT_EQ("all-slots-requested-sizes", + InterestGroup::TrustedBiddingSignalsSlotSizeModeToString( + InterestGroup::TrustedBiddingSignalsSlotSizeMode:: + kAllSlotsRequestedSizes)); + + EXPECT_EQ(InterestGroup::TrustedBiddingSignalsSlotSizeMode::kNone, + InterestGroup::ParseTrustedBiddingSignalsSlotSizeMode( + "not-a-valid-mode")); +} + } // namespace blink
diff --git a/third_party/blink/public/common/interest_group/interest_group.h b/third_party/blink/public/common/interest_group/interest_group.h index a925df6..0b35295 100644 --- a/third_party/blink/public/common/interest_group/interest_group.h +++ b/third_party/blink/public/common/interest_group/interest_group.h
@@ -119,6 +119,11 @@ return TrustedBiddingSignalsSlotSizeMode::kNone; } + // Takes a TrustedBiddingSignalsSlotSizeMode and returns the corresponding + // string. + static std::string_view TrustedBiddingSignalsSlotSizeModeToString( + TrustedBiddingSignalsSlotSizeMode slot_size_mode); + base::Time expiry; url::Origin owner; std::string name; @@ -151,7 +156,7 @@ absl::optional<AdditionalBidKey> additional_bid_key; absl::optional<url::Origin> aggregation_coordinator_origin; - static_assert(__LINE__ == 154, R"( + static_assert(__LINE__ == 159, R"( If modifying InterestGroup fields, make sure to also modify: * IsValid(), EstimateSize(), and IsEqualForTesting() in this class
diff --git a/third_party/blink/public/mojom/input/input_handler.mojom b/third_party/blink/public/mojom/input/input_handler.mojom index 5c21961..c38e851b 100644 --- a/third_party/blink/public/mojom/input/input_handler.mojom +++ b/third_party/blink/public/mojom/input/input_handler.mojom
@@ -431,12 +431,6 @@ kNotFocusedAndNotActive }; -// TODO(sinansahin): DidOverscrollParams and TouchActionOptional can be moved -// into this struct as well. -struct ScrollResultData { - gfx.mojom.PointF? root_scroll_offset; -}; - // Interface exposed by the renderer to the browser. This class represents // an input interface for an associated Widget object. See FrameWidgetInputHandler // for an interface at the frame level. @@ -501,8 +495,7 @@ ui.mojom.LatencyInfo updated_latency, blink.mojom.InputEventResultState state, DidOverscrollParams? overscroll, - TouchActionOptional? touch_action, - ScrollResultData? scroll_result_data); + TouchActionOptional? touch_action); // Sends a non-blocking input event to the render widget. The behaviour // of this API is the same as DispatchEvent just that there is no callback
diff --git a/third_party/blink/public/mojom/webauthn/authenticator.mojom b/third_party/blink/public/mojom/webauthn/authenticator.mojom index 9cbd5df..057e152 100644 --- a/third_party/blink/public/mojom/webauthn/authenticator.mojom +++ b/third_party/blink/public/mojom/webauthn/authenticator.mojom
@@ -67,6 +67,13 @@ INTERNAL, }; +// See https://w3c.github.io/webauthn/#enum-hints +enum Hint { + SECURITY_KEY, + CLIENT_DEVICE, + HYBRID, +}; + // Credential information returned by both Authenticator::MakeCredential // and Authenticator::GetAssertion. struct CommonCredentialInfo { @@ -365,6 +372,9 @@ // accept as the signing credential. array<PublicKeyCredentialDescriptor> allow_credentials; + // https://w3c.github.io/webauthn/#enumdef-publickeycredentialhints + array<Hint> hints; + // Indicates the relying party's need for a user-verifying authenticator. UserVerificationRequirement user_verification; @@ -497,6 +507,9 @@ // Specify the relying party's authenticator attribute requirements. AuthenticatorSelectionCriteria? authenticator_selection; + // https://w3c.github.io/webauthn/#enumdef-publickeycredentialhints + array<Hint> hints; + // Specifies whether the RP wants attestation information for the created // credential. AttestationConveyancePreference attestation;
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc index 27a78f4..84a63595 100644 --- a/third_party/blink/renderer/core/dom/document.cc +++ b/third_party/blink/renderer/core/dom/document.cc
@@ -7505,8 +7505,7 @@ void Document::OnPrepareToStopParsing() { if (render_blocking_resource_manager_) { - render_blocking_resource_manager_->SetMainDocumentParsingIsRenderBlocking( - false); + render_blocking_resource_manager_->ClearPendingParsingElements(); } MaybeExecuteDelayedAsyncScripts( MilestoneForDelayedAsyncScript::kFinishedParsing);
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc index 3610b6b..408b8df 100644 --- a/third_party/blink/renderer/core/dom/element.cc +++ b/third_party/blink/renderer/core/dom/element.cc
@@ -179,6 +179,7 @@ #include "third_party/blink/renderer/core/layout/layout_text_combine.h" #include "third_party/blink/renderer/core/layout/layout_text_fragment.h" #include "third_party/blink/renderer/core/layout/layout_view.h" +#include "third_party/blink/renderer/core/loader/render_blocking_resource_manager.h" #include "third_party/blink/renderer/core/page/chrome_client.h" #include "third_party/blink/renderer/core/page/focus_controller.h" #include "third_party/blink/renderer/core/page/page.h" @@ -2462,6 +2463,11 @@ AtomicString old_id = GetElementData()->SetIdForStyleResolution(new_id); GetDocument().GetStyleEngine().IdChangedForElement(old_id, new_id, *this); } + + if (auto* manager = GetDocument().GetRenderBlockingResourceManager(); + manager && IsFinishedParsingChildren()) { + manager->RemovePendingParsingElement(new_id); + } } else if (name == html_names::kClassAttr) { if (params.old_value == params.new_value && params.reason != AttributeModificationReason::kByMoveToNewDocument && @@ -5412,6 +5418,11 @@ CheckForEmptyStyleChange(this, this); CheckForSiblingStyleChanges(kFinishedParsingChildren, nullptr, lastChild(), nullptr); + + if (auto* manager = GetDocument().GetRenderBlockingResourceManager()) { + manager->RemovePendingParsingElement(GetIdAttribute()); + } + GetDocument() .GetStyleEngine() .ScheduleInvalidationsForHasPseudoAffectedByInsertion(
diff --git a/third_party/blink/renderer/core/dom/events/event_dispatcher.cc b/third_party/blink/renderer/core/dom/events/event_dispatcher.cc index 40fcf13..36f5e2d2 100644 --- a/third_party/blink/renderer/core/dom/events/event_dispatcher.cc +++ b/third_party/blink/renderer/core/dom/events/event_dispatcher.cc
@@ -222,12 +222,11 @@ std::unique_ptr<SoftNavigationEventScope> soft_navigation_scope; if ((is_click || is_unfocused_keyboard_event) && event_->isTrusted() && frame) { - ScriptState* script_state = ToScriptStateForMainWorld(frame); - if (window && frame->IsMainFrame() && script_state) { + if (window && frame->IsMainFrame()) { bool is_new_interaction = is_click || (event_->type() == event_type_names::kKeydown); soft_navigation_scope = std::make_unique<SoftNavigationEventScope>( - SoftNavigationHeuristics::From(*window), script_state, + SoftNavigationHeuristics::From(*window), is_unfocused_keyboard_event ? SoftNavigationHeuristics::EventScopeType::Keyboard : SoftNavigationHeuristics::EventScopeType::Click,
diff --git a/third_party/blink/renderer/core/frame/frame_test_helpers.cc b/third_party/blink/renderer/core/frame/frame_test_helpers.cc index 81e46b1..c775a923 100644 --- a/third_party/blink/renderer/core/frame/frame_test_helpers.cc +++ b/third_party/blink/renderer/core/frame/frame_test_helpers.cc
@@ -55,7 +55,6 @@ #include "third_party/blink/public/mojom/frame/frame_replication_state.mojom.h" #include "third_party/blink/public/mojom/frame/intrinsic_sizing_info.mojom-blink.h" #include "third_party/blink/public/mojom/frame/tree_scope_type.mojom-blink.h" -#include "third_party/blink/public/mojom/input/input_handler.mojom-blink-forward.h" #include "third_party/blink/public/mojom/input/touch_event.mojom-blink.h" #include "third_party/blink/public/mojom/page/widget.mojom-blink.h" #include "third_party/blink/public/platform/interface_registry.h" @@ -977,8 +976,7 @@ [](TestWebFrameWidget* widget, mojom::blink::InputEventResultSource, const ui::LatencyInfo&, mojom::blink::InputEventResultState, mojom::blink::DidOverscrollParamsPtr overscroll, - mojom::blink::TouchActionOptionalPtr, - mojom::blink::ScrollResultDataPtr) { + mojom::blink::TouchActionOptionalPtr) { if (widget) widget->last_overscroll_ = std::move(overscroll); },
diff --git a/third_party/blink/renderer/core/html/html_html_element.cc b/third_party/blink/renderer/core/html/html_html_element.cc index 224ad2e..a4af7b9 100644 --- a/third_party/blink/renderer/core/html/html_html_element.cc +++ b/third_party/blink/renderer/core/html/html_html_element.cc
@@ -44,24 +44,7 @@ namespace blink { HTMLHtmlElement::HTMLHtmlElement(Document& document) - : HTMLElement(html_names::kHTMLTag, document), - blocking_attribute_(MakeGarbageCollected<BlockingAttribute>(this)) {} - -void HTMLHtmlElement::ParseAttribute( - const AttributeModificationParams& params) { - if (params.name == html_names::kBlockingAttr && - RuntimeEnabledFeatures::DocumentRenderBlockingEnabled()) { - blocking_attribute_->OnAttributeValueChanged(params.old_value, - params.new_value); - if (auto* render_blocking_resource_manager = - GetDocument().GetRenderBlockingResourceManager()) { - render_blocking_resource_manager->SetMainDocumentParsingIsRenderBlocking( - blocking_attribute_->HasRenderToken()); - } - } else { - HTMLElement::ParseAttribute(params); - } -} + : HTMLElement(html_names::kHTMLTag, document) {} bool HTMLHtmlElement::IsURLAttribute(const Attribute& attribute) const { return attribute.GetName() == html_names::kManifestAttr || @@ -82,11 +65,6 @@ } } -void HTMLHtmlElement::Trace(Visitor* visitor) const { - visitor->Trace(blocking_attribute_); - HTMLElement::Trace(visitor); -} - namespace { bool NeedsLayoutStylePropagation(const ComputedStyle& layout_style,
diff --git a/third_party/blink/renderer/core/html/html_html_element.h b/third_party/blink/renderer/core/html/html_html_element.h index 53fa5b1..4a5f601 100644 --- a/third_party/blink/renderer/core/html/html_html_element.h +++ b/third_party/blink/renderer/core/html/html_html_element.h
@@ -38,22 +38,12 @@ void InsertedByParser(); - void ParseAttribute(const AttributeModificationParams&) override; bool HasNonInBodyInsertionMode() const override { return true; } void PropagateWritingModeAndDirectionFromBody(); const ComputedStyle* LayoutStyleForElement(const ComputedStyle* style); - BlockingAttribute& blocking() const { return *blocking_attribute_; } - bool IsPotentiallyRenderBlocking() const override { - return blocking_attribute_->HasRenderToken(); - } - - void Trace(Visitor*) const override; - private: bool IsURLAttribute(const Attribute&) const override; - - Member<BlockingAttribute> blocking_attribute_; }; } // namespace blink
diff --git a/third_party/blink/renderer/core/html/html_html_element.idl b/third_party/blink/renderer/core/html/html_html_element.idl index bd4176c..cd5f7112 100644 --- a/third_party/blink/renderer/core/html/html_html_element.idl +++ b/third_party/blink/renderer/core/html/html_html_element.idl
@@ -25,6 +25,4 @@ // obsolete members // https://html.spec.whatwg.org/C/#HTMLHtmlElement-partial [CEReactions, Reflect] attribute DOMString version; - - [RuntimeEnabled=DocumentRenderBlocking, SameObject, PutForwards=value] readonly attribute DOMTokenList blocking; };
diff --git a/third_party/blink/renderer/core/html/html_link_element.cc b/third_party/blink/renderer/core/html/html_link_element.cc index 4aed8f0..ca4d1bc 100644 --- a/third_party/blink/renderer/core/html/html_link_element.cc +++ b/third_party/blink/renderer/core/html/html_link_element.cc
@@ -43,6 +43,7 @@ #include "third_party/blink/renderer/core/html_names.h" #include "third_party/blink/renderer/core/inspector/console_message.h" #include "third_party/blink/renderer/core/loader/link_loader.h" +#include "third_party/blink/renderer/core/loader/render_blocking_resource_manager.h" #include "third_party/blink/renderer/core/origin_trials/origin_trial_context.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/instrumentation/use_counter.h" @@ -51,6 +52,17 @@ #include "third_party/blink/renderer/platform/wtf/functional.h" namespace blink { +namespace { + +AtomicString ParseHrefAsId(const String& href) { + if (href.empty() || href[0] != '#') { + return AtomicString(); + } + auto result = AtomicString(href.Substring(1)); + return result; +} + +} // namespace HTMLLinkElement::HTMLLinkElement(Document& document, const CreateElementFlags flags) @@ -68,7 +80,14 @@ const QualifiedName& name = params.name; const AtomicString& value = params.new_value; if (name == html_names::kRelAttr) { + // We're about to change the rel attribute. If it was "expect", first remove + // it from a render blocking list. + RemoveExpectRenderBlockingLink(); + rel_attribute_ = LinkRelAttribute(value); + // TODO(vmpstr): Add rel=expect to UseCounter. + AddExpectRenderBlockingLinkIfNeeded(); + if (rel_attribute_.IsMonetization() && GetDocument().IsInOutermostMainFrame()) { // TODO(1031476): The Web Monetization specification is an unofficial @@ -98,9 +117,11 @@ if (GetLinkStyle() && GetLinkStyle()->StyleSheetIsLoading()) GetLinkStyle()->UnblockRenderingForPendingSheet(); } + HandleExpectBlockingChanges(); } else if (name == html_names::kHrefAttr) { // Log href attribute before logging resource fetching in process(). LogUpdateAttributeIfIsolatedWorldAndInDocument("link", params); + HandleExpectHrefChanges(params.old_value, value); Process(); } else if (name == html_names::kTypeAttr) { type_ = value; @@ -125,6 +146,7 @@ Process(); } else if (name == html_names::kMediaAttr) { media_ = value.LowerASCII(); + HandleExpectMediaChanges(); Process(LinkLoadParameters::Reason::kMediaChange); } else if (name == html_names::kIntegrityAttr) { integrity_ = value; @@ -166,6 +188,12 @@ return false; } + // We don't load links for the rel=expect, since that's just an expectation of + // parsing of some other element on the page. + if (rel_attribute_.IsExpect()) { + return false; + } + const KURL& href = GetNonEmptyURLAttribute(html_names::kHrefAttr); return !href.PotentiallyDanglingMarkup(); } @@ -196,7 +224,6 @@ // the sheet from the style engine and do style recalculation. if (GetLinkStyle() && GetLinkStyle()->HasSheet()) return GetLinkStyle(); - // TODO(yoav): Ideally, the element's error event would be fired here. return nullptr; } @@ -223,8 +250,9 @@ } void HTMLLinkElement::Process(LinkLoadParameters::Reason reason) { - if (LinkResource* link = LinkResourceToProcess()) + if (LinkResource* link = LinkResourceToProcess()) { link->Process(reason); + } } Node::InsertionNotificationRequest HTMLLinkElement::InsertedInto( @@ -251,6 +279,7 @@ if (link_) link_->OwnerInserted(); + AddExpectRenderBlockingLinkIfNeeded(); return kInsertionDone; } @@ -272,6 +301,8 @@ insertion_point); if (link_) link_->OwnerRemoved(); + + RemoveExpectRenderBlockingLink(); } void HTMLLinkElement::FinishParsingChildren() { @@ -397,4 +428,85 @@ LinkLoaderClient::Trace(visitor); } +void HTMLLinkElement::HandleExpectBlockingChanges() { + if (!rel_attribute_.IsExpect()) { + return; + } + + if (blocking_attribute_->HasRenderToken()) { + AddExpectRenderBlockingLinkIfNeeded(); + } else { + RemoveExpectRenderBlockingLink(); + } +} + +void HTMLLinkElement::HandleExpectHrefChanges(const String& old_value, + const String& new_value) { + if (!rel_attribute_.IsExpect()) { + return; + } + + RemoveExpectRenderBlockingLink(old_value); + AddExpectRenderBlockingLinkIfNeeded(new_value); +} + +bool HTMLLinkElement::MediaQueryMatches() const { + if (LocalFrame* frame = GetDocument().GetFrame(); frame && !media_.empty()) { + auto* media_queries = + MediaQuerySet::Create(media_, GetDocument().GetExecutionContext()); + MediaQueryEvaluator evaluator(frame); + return evaluator.Eval(*media_queries); + } + return true; +} + +void HTMLLinkElement::HandleExpectMediaChanges() { + if (!rel_attribute_.IsExpect()) { + return; + } + + if (MediaQueryMatches()) { + AddExpectRenderBlockingLinkIfNeeded(String(), + /*media_known_to_match=*/true); + } else { + RemoveExpectRenderBlockingLink(); + } +} + +void HTMLLinkElement::RemoveExpectRenderBlockingLink(const String& href) { + if (!rel_attribute_.IsExpect()) { + return; + } + + if (auto* render_blocking_resource_manager = + GetDocument().GetRenderBlockingResourceManager()) { + render_blocking_resource_manager->RemovePendingParsingElementLink( + ParseHrefAsId(href.IsNull() ? FastGetAttribute(html_names::kHrefAttr) + : href), + this); + } +} + +void HTMLLinkElement::AddExpectRenderBlockingLinkIfNeeded( + const String& href, + bool media_known_to_match) { + if (!rel_attribute_.IsExpect()) { + return; + } + + bool media_matches = media_known_to_match || MediaQueryMatches(); + bool is_blocking_render = blocking_attribute_->HasRenderToken(); + if (!media_matches || !is_blocking_render || !isConnected()) { + return; + } + + if (auto* render_blocking_resource_manager = + GetDocument().GetRenderBlockingResourceManager()) { + render_blocking_resource_manager->AddPendingParsingElementLink( + ParseHrefAsId(href.IsNull() ? FastGetAttribute(html_names::kHrefAttr) + : href), + this); + } +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/html/html_link_element.h b/third_party/blink/renderer/core/html/html_link_element.h index c54e0f26..9e8e391 100644 --- a/third_party/blink/renderer/core/html/html_link_element.h +++ b/third_party/blink/renderer/core/html/html_link_element.h
@@ -152,6 +152,17 @@ void LinkLoaded() override; void LinkLoadingErrored() override; + bool MediaQueryMatches() const; + + void HandleExpectBlockingChanges(); + void HandleExpectHrefChanges(const String& old_value, + const String& new_value); + void HandleExpectMediaChanges(); + + void RemoveExpectRenderBlockingLink(const String& href = String()); + void AddExpectRenderBlockingLinkIfNeeded(const String& href = String(), + bool media_known_to_match = false); + Member<LinkResource> link_; Member<LinkLoader> link_loader_;
diff --git a/third_party/blink/renderer/core/html/link_rel_attribute.cc b/third_party/blink/renderer/core/html/link_rel_attribute.cc index 4b3d65d..473712e 100644 --- a/third_party/blink/renderer/core/html/link_rel_attribute.cc +++ b/third_party/blink/renderer/core/html/link_rel_attribute.cc
@@ -30,29 +30,10 @@ */ #include "third_party/blink/renderer/core/html/link_rel_attribute.h" - +#include "third_party/blink/renderer/platform/runtime_enabled_features.h" namespace blink { -LinkRelAttribute::LinkRelAttribute() - : icon_type_(mojom::blink::FaviconIconType::kInvalid), - is_style_sheet_(false), - is_alternate_(false), - is_dns_prefetch_(false), - is_preconnect_(false), - is_link_prefetch_(false), - is_link_preload_(false), - is_link_prerender_(false), - is_link_next_(false), - is_manifest_(false), - is_module_preload_(false), - is_service_worker_(false), - is_canonical_(false), - is_monetization_(false), - is_dictionary_(false), - is_privacy_policy_(false), - is_terms_of_service_(false) {} - LinkRelAttribute::LinkRelAttribute(const String& rel) : LinkRelAttribute() { if (rel.empty()) return; @@ -102,6 +83,9 @@ is_privacy_policy_ = true; } else if (EqualIgnoringASCIICase(link_type, "terms-of-service")) { is_terms_of_service_ = true; + } else if (RuntimeEnabledFeatures::DocumentRenderBlockingEnabled() && + EqualIgnoringASCIICase(link_type, "expect")) { + is_expect_ = true; } // Adding or removing a value here whose processing model is web-visible
diff --git a/third_party/blink/renderer/core/html/link_rel_attribute.h b/third_party/blink/renderer/core/html/link_rel_attribute.h index f76fa88..bdc99c69 100644 --- a/third_party/blink/renderer/core/html/link_rel_attribute.h +++ b/third_party/blink/renderer/core/html/link_rel_attribute.h
@@ -43,7 +43,7 @@ DISALLOW_NEW(); public: - LinkRelAttribute(); + LinkRelAttribute() = default; explicit LinkRelAttribute(const String&); bool IsStyleSheet() const { return is_style_sheet_; } @@ -63,25 +63,28 @@ bool IsDictionary() const { return is_dictionary_; } bool IsPrivacyPolicy() const { return is_privacy_policy_; } bool IsTermsOfService() const { return is_terms_of_service_; } + bool IsExpect() const { return is_expect_; } private: - mojom::blink::FaviconIconType icon_type_; - bool is_style_sheet_ : 1; - bool is_alternate_ : 1; - bool is_dns_prefetch_ : 1; - bool is_preconnect_ : 1; - bool is_link_prefetch_ : 1; - bool is_link_preload_ : 1; - bool is_link_prerender_ : 1; - bool is_link_next_ : 1; - bool is_manifest_ : 1; - bool is_module_preload_ : 1; - bool is_service_worker_ : 1; - bool is_canonical_ : 1; - bool is_monetization_ : 1; - bool is_dictionary_ : 1; - bool is_privacy_policy_ : 1; - bool is_terms_of_service_ : 1; + mojom::blink::FaviconIconType icon_type_ = + mojom::blink::FaviconIconType::kInvalid; + bool is_style_sheet_ : 1 = false; + bool is_alternate_ : 1 = false; + bool is_dns_prefetch_ : 1 = false; + bool is_preconnect_ : 1 = false; + bool is_link_prefetch_ : 1 = false; + bool is_link_preload_ : 1 = false; + bool is_link_prerender_ : 1 = false; + bool is_link_next_ : 1 = false; + bool is_manifest_ : 1 = false; + bool is_module_preload_ : 1 = false; + bool is_service_worker_ : 1 = false; + bool is_canonical_ : 1 = false; + bool is_monetization_ : 1 = false; + bool is_dictionary_ : 1 = false; + bool is_privacy_policy_ : 1 = false; + bool is_terms_of_service_ : 1 = false; + bool is_expect_ : 1 = false; }; } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/grid/grid_layout_algorithm.cc b/third_party/blink/renderer/core/layout/grid/grid_layout_algorithm.cc index 33deaeb..74aa5426 100644 --- a/third_party/blink/renderer/core/layout/grid/grid_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/grid/grid_layout_algorithm.cc
@@ -42,9 +42,8 @@ // and also have something like "min-width: min-content". This is // cyclic. Just return the border/scrollbar/padding as our // "intrinsic" size. - return MinMaxSizesResult( - {border_scrollbar_padding, border_scrollbar_padding}, - /* depends_on_block_constraints */ false); + return {{border_scrollbar_padding, border_scrollbar_padding}, + /* depends_on_block_constraints */ false}; }); grid_min_available_size_.inline_size = @@ -418,21 +417,19 @@ // TODO(crbug.com/1272533): This should be |depends_on_block_constraints| // (rather than false). However we need more cache slots to handle the // performance degradation we currently experience. See bug for more details. - return MinMaxSizesResult( - sizes, RuntimeEnabledFeatures::LayoutNewMeasureCacheEnabled() && - depends_on_block_constraints); + return {sizes, RuntimeEnabledFeatures::LayoutNewMeasureCacheEnabled() && + depends_on_block_constraints}; } MinMaxSizesResult GridLayoutAlgorithm::ComputeMinMaxSizes( const GridSizingSubtree& sizing_subtree) { DCHECK(sizing_subtree); - return MinMaxSizesResult( - {ComputeSubgridContributionSize(sizing_subtree, kForColumns, - SizingConstraint::kMinContent), - ComputeSubgridContributionSize(sizing_subtree, kForColumns, - SizingConstraint::kMaxContent)}, - /* depends_on_block_constraints */ false); + return {{ComputeSubgridContributionSize(sizing_subtree, kForColumns, + SizingConstraint::kMinContent), + ComputeSubgridContributionSize(sizing_subtree, kForColumns, + SizingConstraint::kMaxContent)}, + /* depends_on_block_constraints */ false}; } namespace { @@ -1150,11 +1147,17 @@ }; auto MinOrMaxContentSize = [&](bool is_min_content) -> LayoutUnit { - if (grid_item->IsSubgrid()) { - return SubgridContributionSize(is_min_content); - } - - const auto result = ComputeMinAndMaxContentContributionForSelf(node, space); + const auto result = + grid_item->IsSubgrid() + ? ComputeMinAndMaxContentContributionForSelf( + node, space, + [&](MinMaxSizesType) -> MinMaxSizesResult { + const auto& subgrid_sizing_subtree = + sizing_subtree.SubgridSizingSubtree(*grid_item); + return ComputeMinMaxSizesForSubgrid(subgrid_sizing_subtree, + *grid_item, space); + }) + : ComputeMinAndMaxContentContributionForSelf(node, space); // The min/max contribution may depend on the block-size of the grid-area: // <div style="display: inline-grid; grid-template-columns: auto auto;">
diff --git a/third_party/blink/renderer/core/layout/length_utils.cc b/third_party/blink/renderer/core/layout/length_utils.cc index a7477516..3824ea5 100644 --- a/third_party/blink/renderer/core/layout/length_utils.cc +++ b/third_party/blink/renderer/core/layout/length_utils.cc
@@ -229,81 +229,6 @@ namespace { -template <typename MinMaxSizesFunc> -MinMaxSizesResult ComputeMinAndMaxContentContributionInternal( - WritingMode parent_writing_mode, - const BlockNode& child, - const ConstraintSpace& space, - const MinMaxSizesFunc& min_max_sizes_func) { - const ComputedStyle& style = child.Style(); - const WritingMode child_writing_mode = style.GetWritingMode(); - const BoxStrut border_padding = - ComputeBorders(space, child) + ComputePadding(space, style); - - MinMaxSizesResult result; - - const Length& inline_size = parent_writing_mode == WritingMode::kHorizontalTb - ? style.UsedWidth() - : style.UsedHeight(); - if (inline_size.IsAuto() || inline_size.IsPercentOrCalc() || - inline_size.IsFillAvailable() || inline_size.IsFitContent()) { - result = min_max_sizes_func(MinMaxSizesType::kContent); - } else { - if (IsParallelWritingMode(parent_writing_mode, child_writing_mode)) { - MinMaxSizes sizes; - sizes = ResolveMainInlineLength(space, style, border_padding, - min_max_sizes_func, inline_size); - result = MinMaxSizesResult(sizes, - /* depends_on_block_constraints */ false); - } else { - auto IntrinsicBlockSizeFunc = [&]() -> LayoutUnit { - return min_max_sizes_func(inline_size.IsMinIntrinsic() - ? MinMaxSizesType::kIntrinsic - : MinMaxSizesType::kContent) - .sizes.max_size; - }; - MinMaxSizes sizes; - sizes = ResolveMainBlockLength(space, style, border_padding, inline_size, - IntrinsicBlockSizeFunc); - result = MinMaxSizesResult(sizes, - /* depends_on_block_constraints */ false); - } - } - - const Length& max_length = parent_writing_mode == WritingMode::kHorizontalTb - ? style.UsedMaxWidth() - : style.UsedMaxHeight(); - LayoutUnit max; - if (IsParallelWritingMode(parent_writing_mode, child_writing_mode)) { - max = ResolveMaxInlineLength(space, style, border_padding, - min_max_sizes_func, max_length); - } else { - max = ResolveMaxBlockLength(space, style, border_padding, max_length); - } - result.sizes.Constrain(max); - - const Length& min_length = parent_writing_mode == WritingMode::kHorizontalTb - ? style.UsedMinWidth() - : style.UsedMinHeight(); - LayoutUnit min; - if (IsParallelWritingMode(parent_writing_mode, child_writing_mode)) { - min = ResolveMinInlineLength(space, style, border_padding, - min_max_sizes_func, min_length); - } else { - min = ResolveMinBlockLength(space, style, border_padding, min_length); - } - result.sizes.Encompass(min); - - // Tables need to apply one final constraint. They are never allowed to go - // below their min-intrinsic size (even if they have an inline-size, etc). - if (child.IsTable()) { - result.sizes.Encompass( - min_max_sizes_func(MinMaxSizesType::kIntrinsic).sizes.min_size); - } - - return result; -} - // Currently this simply sets the correct override sizes for the replaced // element, and lets legacy layout do the result. MinMaxSizesResult ComputeMinAndMaxContentContributionForReplaced(
diff --git a/third_party/blink/renderer/core/layout/length_utils.h b/third_party/blink/renderer/core/layout/length_utils.h index b096788..78ff22b 100644 --- a/third_party/blink/renderer/core/layout/length_utils.h +++ b/third_party/blink/renderer/core/layout/length_utils.h
@@ -255,42 +255,6 @@ /* override_percentage_resolution_size */ nullptr, anchor_evaluator); } -// For the given |child|, computes the min and max content contribution -// (https://drafts.csswg.org/css-sizing/#contributions). -// -// This is similar to ComputeInlineSizeForFragment except that it does not -// require a constraint space (percentage sizes as well as auto margins compute -// to zero) and an auto inline-size resolves to the respective min/max content -// size. -// -// Additoinally, the min/max contribution includes the inline margins. Because -// content contributions are commonly needed by a block's parent, we also take -// a writing-mode here so we can compute this in the parent's coordinate system. -// -// Note that if the writing mode of the child is orthogonal to that of the -// parent, we'll still return the inline min/max contribution in the writing -// mode of the parent (i.e. typically something based on the preferred *block* -// size of the child). -MinMaxSizesResult ComputeMinAndMaxContentContribution( - const ComputedStyle& parent_style, - const BlockNode& child, - const ConstraintSpace& space, - const MinMaxSizesFloatInput float_input = MinMaxSizesFloatInput()); - -// Similar to |ComputeMinAndMaxContentContribution| but ignores the parent -// writing-mode, and instead computes the contribution relative to |child|'s -// own writing-mode. -MinMaxSizesResult ComputeMinAndMaxContentContributionForSelf( - const BlockNode& child, - const ConstraintSpace& space); - -// Used for unit-tests. -CORE_EXPORT MinMaxSizes -ComputeMinAndMaxContentContributionForTest(WritingMode writing_mode, - const BlockNode&, - const ConstraintSpace&, - const MinMaxSizes&); - // Computes the min-block-size and max-block-size values for a node. MinMaxSizes ComputeMinMaxBlockSizes( const ConstraintSpace&, @@ -799,6 +763,125 @@ LayoutUnit current_intrinsic_block_size, absl::optional<LayoutUnit> body_margin_block_sum = absl::nullopt); +template <typename MinMaxSizesFunc> +MinMaxSizesResult ComputeMinAndMaxContentContributionInternal( + WritingMode parent_writing_mode, + const BlockNode& child, + const ConstraintSpace& space, + const MinMaxSizesFunc& min_max_sizes_func) { + const auto& style = child.Style(); + + const bool is_parallel_with_parent = + IsParallelWritingMode(parent_writing_mode, style.GetWritingMode()); + const bool is_parent_writing_mode_horizontal = + IsHorizontalWritingMode(parent_writing_mode); + + const auto border_padding = + ComputeBorders(space, child) + ComputePadding(space, style); + const auto& inline_size = is_parent_writing_mode_horizontal + ? style.UsedWidth() + : style.UsedHeight(); + + MinMaxSizesResult result; + if (inline_size.IsAuto() || inline_size.IsPercentOrCalc() || + inline_size.IsFillAvailable() || inline_size.IsFitContent()) { + result = min_max_sizes_func(MinMaxSizesType::kContent); + } else { + const auto size = + is_parallel_with_parent + ? ResolveMainInlineLength(space, style, border_padding, + min_max_sizes_func, inline_size) + : ResolveMainBlockLength( + space, style, border_padding, inline_size, + [&]() -> LayoutUnit { + return min_max_sizes_func(inline_size.IsMinIntrinsic() + ? MinMaxSizesType::kIntrinsic + : MinMaxSizesType::kContent) + .sizes.max_size; + }); + + // This child's contribution size is not dependent on the available size, so + // it's considered definite. Return this size for both min and max. + result = {{size, size}, /* depends_on_block_constraints */ false}; + } + + const auto& max_inline_size = is_parent_writing_mode_horizontal + ? style.UsedMaxWidth() + : style.UsedMaxHeight(); + result.sizes.Constrain( + is_parallel_with_parent + ? ResolveMaxInlineLength(space, style, border_padding, + min_max_sizes_func, max_inline_size) + : ResolveMaxBlockLength(space, style, border_padding, + max_inline_size)); + + const auto& min_inline_size = is_parent_writing_mode_horizontal + ? style.UsedMinWidth() + : style.UsedMinHeight(); + result.sizes.Encompass( + is_parallel_with_parent + ? ResolveMinInlineLength(space, style, border_padding, + min_max_sizes_func, min_inline_size) + : ResolveMinBlockLength(space, style, border_padding, + min_inline_size)); + + // Tables need to apply one final constraint. They are never allowed to go + // below their min-intrinsic size (even if they have an inline-size, etc). + if (child.IsTable()) { + result.sizes.Encompass( + min_max_sizes_func(MinMaxSizesType::kIntrinsic).sizes.min_size); + } + return result; +} + +// For the given |child|, computes the min and max content contribution +// (https://drafts.csswg.org/css-sizing/#contributions). +// +// This is similar to `ComputeInlineSizeForFragment` except that it does not +// require a constraint space (percentage sizes as well as auto margins compute +// to zero) and an auto inline-size resolves to the respective min/max content +// size. +// +// Additionally, the min/max contribution includes the inline margins. Because +// content contributions are commonly needed by a block's parent, we also take +// a writing-mode here so we can compute this in the parent's coordinate system. +// +// Note that if the writing mode of the child is orthogonal to that of the +// parent, we'll still return the inline min/max contribution in the writing +// mode of the parent (i.e. typically something based on the preferred *block* +// size of the child). +MinMaxSizesResult ComputeMinAndMaxContentContribution( + const ComputedStyle& parent_style, + const BlockNode& child, + const ConstraintSpace& space, + const MinMaxSizesFloatInput float_input = MinMaxSizesFloatInput()); + +// Similar to `ComputeMinAndMaxContentContribution` but ignores the writing mode +// of the parent, and instead computes the contribution relative to the child's +// own writing mode. +MinMaxSizesResult ComputeMinAndMaxContentContributionForSelf( + const BlockNode& child, + const ConstraintSpace& space); + +// Same as above, but allows a custom function to compute min/max sizes. +template <typename MinMaxSizesFunc> +MinMaxSizesResult ComputeMinAndMaxContentContributionForSelf( + const BlockNode& child, + const ConstraintSpace& space, + const MinMaxSizesFunc& min_max_sizes_func) { + DCHECK(child.CreatesNewFormattingContext()); + + return ComputeMinAndMaxContentContributionInternal( + child.Style().GetWritingMode(), child, space, min_max_sizes_func); +} + +// Used for unit-tests. +CORE_EXPORT MinMaxSizes +ComputeMinAndMaxContentContributionForTest(WritingMode writing_mode, + const BlockNode&, + const ConstraintSpace&, + const MinMaxSizes&); + // This function checks if the inline size of this node has to be calculated // without considering children. If so, it returns the calculated size. // Otherwise, it returns absl::nullopt and the caller has to compute the size
diff --git a/third_party/blink/renderer/core/loader/document_loader.cc b/third_party/blink/renderer/core/loader/document_loader.cc index cc1756f..e1497f6 100644 --- a/third_party/blink/renderer/core/loader/document_loader.cc +++ b/third_party/blink/renderer/core/loader/document_loader.cc
@@ -1006,8 +1006,7 @@ // need to do that now. soft_navigation_event_scope = std::make_unique<SoftNavigationEventScope>( - heuristics, script_state, - SoftNavigationHeuristics::EventScopeType::Navigate, + heuristics, SoftNavigationHeuristics::EventScopeType::Navigate, /*is_new_interaction=*/true); heuristics->SameDocumentNavigationStarted(script_state); }
diff --git a/third_party/blink/renderer/core/loader/render_blocking_resource_manager.cc b/third_party/blink/renderer/core/loader/render_blocking_resource_manager.cc index 4f855733..0a513b4 100644 --- a/third_party/blink/renderer/core/loader/render_blocking_resource_manager.cc +++ b/third_party/blink/renderer/core/loader/render_blocking_resource_manager.cc
@@ -10,6 +10,7 @@ #include "third_party/blink/renderer/core/css/font_face.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/html/html_document.h" +#include "third_party/blink/renderer/core/html/html_link_element.h" #include "third_party/blink/renderer/core/loader/document_loader.h" #include "third_party/blink/renderer/core/loader/pending_link_preload.h" #include "third_party/blink/renderer/core/script/script_element_base.h" @@ -134,28 +135,88 @@ document_->RenderBlockingResourceUnblocked(); } -void RenderBlockingResourceManager::SetMainDocumentParsingIsRenderBlocking( - bool blocking) { - if (blocked_on_main_document_parsing_ == blocking) { - return; - } - +void RenderBlockingResourceManager::AddPendingParsingElementLink( + const AtomicString& id, + const HTMLLinkElement* link) { if (!RuntimeEnabledFeatures::DocumentRenderBlockingEnabled()) { return; } - // render-blocking resources can only be added until the body element is - // parsed. - if (blocking && document_->body()) { + CHECK(link); + + // We can only add resources until the body element is parsed. + // Also we need a valid id. + if (document_->body() || id.empty()) { return; } - blocked_on_main_document_parsing_ = blocking; - if (!blocked_on_main_document_parsing_) { + auto it = element_render_blocking_links_.find(id); + if (it == element_render_blocking_links_.end()) { + auto result = element_render_blocking_links_.insert( + id, + MakeGarbageCollected<HeapHashSet<WeakMember<const HTMLLinkElement>>>()); + result.stored_value->value->insert(link); + } else { + it->value->insert(link); + } +} + +void RenderBlockingResourceManager::RemovePendingParsingElement( + const AtomicString& id) { + if (!RuntimeEnabledFeatures::DocumentRenderBlockingEnabled()) { + return; + } + + if (element_render_blocking_links_.empty() || id.empty()) { + return; + } + + element_render_blocking_links_.erase(id); + if (element_render_blocking_links_.empty()) { RenderBlockingResourceUnblocked(); } } +void RenderBlockingResourceManager::RemovePendingParsingElementLink( + const AtomicString& id, + const HTMLLinkElement* link) { + if (!RuntimeEnabledFeatures::DocumentRenderBlockingEnabled()) { + return; + } + + // We don't add empty ids. + if (id.empty()) { + return; + } + + auto it = element_render_blocking_links_.find(id); + if (it == element_render_blocking_links_.end()) { + return; + } + + it->value->erase(link); + if (it->value->empty()) { + element_render_blocking_links_.erase(it); + } + + if (element_render_blocking_links_.empty()) { + RenderBlockingResourceUnblocked(); + } +} + +void RenderBlockingResourceManager::ClearPendingParsingElements() { + if (!RuntimeEnabledFeatures::DocumentRenderBlockingEnabled()) { + return; + } + + if (element_render_blocking_links_.empty()) { + return; + } + + element_render_blocking_links_.clear(); + RenderBlockingResourceUnblocked(); +} + void RenderBlockingResourceManager::SetFontPreloadTimeoutForTest( base::TimeDelta timeout) { if (font_preload_max_blocking_timer_.IsActive()) { @@ -237,6 +298,7 @@ } void RenderBlockingResourceManager::Trace(Visitor* visitor) const { + visitor->Trace(element_render_blocking_links_); visitor->Trace(document_); visitor->Trace(pending_stylesheet_owner_nodes_); visitor->Trace(pending_scripts_);
diff --git a/third_party/blink/renderer/core/loader/render_blocking_resource_manager.h b/third_party/blink/renderer/core/loader/render_blocking_resource_manager.h index 8ef43f7..d971a55 100644 --- a/third_party/blink/renderer/core/loader/render_blocking_resource_manager.h +++ b/third_party/blink/renderer/core/loader/render_blocking_resource_manager.h
@@ -11,6 +11,7 @@ #include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/timer.h" +#include "third_party/blink/renderer/platform/wtf/text/atomic_string_hash.h" namespace blink { @@ -19,6 +20,7 @@ class PendingLinkPreload; class Node; class ScriptElementBase; +class HTMLLinkElement; // https://html.spec.whatwg.org/#render-blocking-mechanism with some extensions. class CORE_EXPORT RenderBlockingResourceManager final @@ -36,7 +38,7 @@ } bool HasNonFontRenderBlockingResources() const { return pending_stylesheet_owner_nodes_.size() || pending_scripts_.size() || - blocked_on_main_document_parsing_; + element_render_blocking_links_.size(); } bool HasRenderBlockingFonts() const { return pending_font_preloads_.size() || imperative_font_loading_count_; @@ -70,9 +72,12 @@ void EnsureStartFontPreloadMaxFCPDelayTimer(); void FontPreloadingTimerFired(TimerBase*); - // Notifies whether rendering should remain blocked until main Document - // parsing is complete. - void SetMainDocumentParsingIsRenderBlocking(bool blocking); + void AddPendingParsingElementLink(const AtomicString& id, + const HTMLLinkElement* element); + void RemovePendingParsingElement(const AtomicString& id); + void RemovePendingParsingElementLink(const AtomicString& id, + const HTMLLinkElement* element); + void ClearPendingParsingElements(); void Trace(Visitor* visitor) const; @@ -99,6 +104,12 @@ // Tracks the currently pending render-blocking font preloads. HeapHashSet<WeakMember<const PendingLinkPreload>> pending_font_preloads_; + // Tracks the currently pending render-blocking element ids and the links that + // caused them to be blocking. + HeapHashMap<AtomicString, + Member<HeapHashSet<WeakMember<const HTMLLinkElement>>>> + element_render_blocking_links_; + Member<Document> document_; unsigned imperative_font_loading_count_ = 0; @@ -109,7 +120,6 @@ font_preload_max_fcp_delay_timer_; base::TimeDelta font_preload_timeout_; bool font_preload_timer_has_fired_ = false; - bool blocked_on_main_document_parsing_ = false; }; } // namespace blink
diff --git a/third_party/blink/renderer/core/navigation_api/navigation_api.cc b/third_party/blink/renderer/core/navigation_api/navigation_api.cc index bad87ee..433be3d 100644 --- a/third_party/blink/renderer/core/navigation_api/navigation_api.cc +++ b/third_party/blink/renderer/core/navigation_api/navigation_api.cc
@@ -838,7 +838,7 @@ // consider this a "user initiated click", and the dispatched event handlers // as potential soft navigation tasks. soft_navigation_scope = std::make_unique<SoftNavigationEventScope>( - soft_navigation_heuristics, script_state, + soft_navigation_heuristics, SoftNavigationHeuristics::EventScopeType::Navigate, /*is_new_interaction=*/true); }
diff --git a/third_party/blink/renderer/core/timing/soft_navigation_heuristics.cc b/third_party/blink/renderer/core/timing/soft_navigation_heuristics.cc index e3ea0ed..b15de56 100644 --- a/third_party/blink/renderer/core/timing/soft_navigation_heuristics.cc +++ b/third_party/blink/renderer/core/timing/soft_navigation_heuristics.cc
@@ -137,6 +137,13 @@ ScriptState* script_state, EventScopeType type, bool is_new_interaction) { + // TODO(crbug.com/1503284): return early to avoid check failure crashes. + if (is_new_interaction || !last_interaction_task_id_) { + if (pending_interaction_timestamp_.is_null()) { + return; + } + } + // Set task ID to the current one. initial_interaction_encountered_ = true; ThreadScheduler* scheduler = ThreadScheduler::Current(); @@ -171,12 +178,11 @@ "SoftNavigationHeuristics::UserInitiatedInteraction"); } -void SoftNavigationHeuristics::UserInitiatedInteraction( - ScriptState* script_state) { +void SoftNavigationHeuristics::UserInitiatedInteraction() { // Ensure that paints would be reset, so that paint recording would continue // despite the user interaction. did_reset_paints_ = false; - ResetPaintsIfNeeded(script_state); + ResetPaintsIfNeeded(); } absl::optional<scheduler::TaskAttributionId> @@ -421,14 +427,13 @@ } } -void SoftNavigationHeuristics::ResetPaintsIfNeeded(ScriptState* script_state) { - ScriptState::Scope scope(script_state); - LocalFrame* frame = ToLocalFrameIfNotDetached(script_state->GetContext()); +void SoftNavigationHeuristics::ResetPaintsIfNeeded() { + LocalDOMWindow* window = GetSupplementable(); + LocalFrame* frame = + window->IsCurrentlyDisplayedInFrame() ? window->GetFrame() : nullptr; if (!frame || !frame->IsOutermostMainFrame()) { return; } - LocalDOMWindow* window = frame->DomWindow(); - DCHECK(window); if (!did_reset_paints_) { LocalFrameView* local_frame_view = frame->View(); @@ -534,10 +539,9 @@ // /////////////////////////////////////////// SoftNavigationEventScope::SoftNavigationEventScope( SoftNavigationHeuristics* heuristics, - ScriptState* script_state, SoftNavigationHeuristics::EventScopeType type, bool is_new_interaction) - : heuristics_(heuristics), script_state_(script_state) { + : heuristics_(heuristics) { ThreadScheduler* scheduler = ThreadScheduler::Current(); DCHECK(scheduler); auto* tracker = scheduler->GetTaskAttributionTracker(); @@ -552,9 +556,8 @@ // that created tasks know they were initiated by the correct event type. heuristics_->SetEventParametersAndQueueNestedOnes(type, is_new_interaction, nested); - if (!nested) { - heuristics_->UserInitiatedInteraction(script_state); + heuristics_->UserInitiatedInteraction(); } }
diff --git a/third_party/blink/renderer/core/timing/soft_navigation_heuristics.h b/third_party/blink/renderer/core/timing/soft_navigation_heuristics.h index 5087c66..555e83d0 100644 --- a/third_party/blink/renderer/core/timing/soft_navigation_heuristics.h +++ b/third_party/blink/renderer/core/timing/soft_navigation_heuristics.h
@@ -64,7 +64,7 @@ void InteractionCallbackCalled(ScriptState*, EventScopeType, bool is_new_interaction); - void UserInitiatedInteraction(ScriptState*); + void UserInitiatedInteraction(); void SameDocumentNavigationStarted(ScriptState*); void SameDocumentNavigationCommitted(ScriptState*, const String& url); bool ModifiedDOM(ScriptState*); @@ -114,7 +114,7 @@ ScriptState*, FlagType); void ResetHeuristic(); - void ResetPaintsIfNeeded(ScriptState*); + void ResetPaintsIfNeeded(); void CommitPreviousPaints(LocalFrame*); void EmitSoftNavigationEntry(LocalFrame*); @@ -163,14 +163,12 @@ class SoftNavigationEventScope { public: SoftNavigationEventScope(SoftNavigationHeuristics* heuristics, - ScriptState* script_state, SoftNavigationHeuristics::EventScopeType type, bool is_new_interaction); ~SoftNavigationEventScope(); private: Persistent<SoftNavigationHeuristics> heuristics_; - Persistent<ScriptState> script_state_; }; } // namespace blink
diff --git a/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc b/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc index 54c55f9..303e11b 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
@@ -757,13 +757,24 @@ // Found cursor: use it to find next inline leaf. if (cursor) { cursor.MoveToNextInlineLeafOnLine(); - if (cursor) { + while (cursor) { LayoutObject* runner_layout_object = cursor.CurrentMutableLayoutObject(); DCHECK(runner_layout_object); AXObject* result = AXObjectCache().GetOrCreate(runner_layout_object); + + bool is_inert = result ? result->IsInert() : false; + result = GetDeepestAXChildInLayoutTree(result, true); - if (result) + if (result) { return result; + } + + // We want to continue searching for the next inline leaf if the + // current one is inert. + if (!is_inert) { + break; + } + cursor.MoveToNextInlineLeafOnLine(); } } @@ -841,13 +852,24 @@ // Found cursor: use it to find previous inline leaf. if (cursor) { cursor.MoveToPreviousInlineLeafOnLine(); - if (cursor) { + while (cursor) { LayoutObject* runner_layout_object = cursor.CurrentMutableLayoutObject(); DCHECK(runner_layout_object); AXObject* result = AXObjectCache().GetOrCreate(runner_layout_object); + + bool is_inert = result ? result->IsInert() : false; + result = GetDeepestAXChildInLayoutTree(result, false); - if (result) + if (result) { return result; + } + + // We want to continue searching for the previous inline leaf if the + // current one is inert. + if (!is_inert) { + break; + } + cursor.MoveToPreviousInlineLeafOnLine(); } }
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_test.cc b/third_party/blink/renderer/modules/accessibility/ax_object_test.cc index 13aba0f..c4f9cd6 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_object_test.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_object_test.cc
@@ -926,6 +926,29 @@ EXPECT_EQ("b", next->GetNode()->textContent()); } +TEST_F(AccessibilityTest, NextAndPreviousOnLineInert) { + // Spans need to be in the same line: see https://crbug.com/1511390. + SetBodyInnerHTML(R"HTML( + <div> + <div>first line</div> + <span id="span1">go </span><span inert>inert1</span><span inert>inert2</span><span>blue</span> + <div>last line</div> + </div> + )HTML"); + const AXObject* span1 = GetAXObjectByElementId("span1"); + ASSERT_NE(nullptr, span1); + EXPECT_EQ("go ", span1->GetNode()->textContent()); + + const AXObject* next = span1->NextOnLine(); + ASSERT_NE(nullptr, next); + EXPECT_EQ("blue", next->GetNode()->textContent()); + + // Now we go backwards. + + const AXObject* previous = next->PreviousOnLine(); + EXPECT_EQ("go ", previous->GetNode()->textContent()); +} + TEST_F(AccessibilityTest, TableRowAndCellIsLineBreakingObject) { SetBodyInnerHTML(R"HTML( <table id="table">
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc index 6a4e888..b975d9f4 100644 --- a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc +++ b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc
@@ -434,23 +434,18 @@ state_stack_.front() = MakeGarbageCollected<CanvasRenderingContext2DState>(); layer_count_ = 0; SetIsTransformInvertible(true); - Clear(); + CanvasPath::Clear(); + RestartRecording(); + + // Clear the frame in case a flush previously drew to the canvas surface. if (cc::PaintCanvas* c = GetPaintCanvas()) { - // The canvas should always have an initial/unbalanced save frame, which - // we use to reset the top level matrix and clip here. - c->restoreToCount(1); - // Save once, to match the first entry in `state_stack_`. - c->save(); - DCHECK(c->getLocalToDevice() == SkM44()); -#if DCHECK_IS_ON() - SkIRect clip_bounds; - DCHECK(c->getDeviceClipBounds(&clip_bounds)); - DCHECK(clip_bounds == c->imageInfo().bounds()); -#endif - // We only want to clear the backing buffer if the surface exists because - // this function is also used when the context is lost. - clearRect(0, 0, Width(), Height(), /*for_reset=*/true); + int width = Width(); // Keeping results to avoid repetitive virtual calls. + int height = Height(); + WillDraw(SkIRect::MakeXYWH(0, 0, width, height), + CanvasPerformanceMonitor::DrawType::kOther); + c->drawRect(SkRect::MakeXYWH(0.0f, 0.0f, width, height), GetClearFlags()); } + ValidateStateStack(); origin_tainted_by_content_ = false; } @@ -1432,11 +1427,21 @@ return path.StrokeContains(transformed_point, stroke_data, ctm); } +cc::PaintFlags BaseRenderingContext2D::GetClearFlags() const { + cc::PaintFlags clear_flags; + clear_flags.setStyle(cc::PaintFlags::kFill_Style); + if (HasAlpha()) { + clear_flags.setBlendMode(SkBlendMode::kClear); + } else { + clear_flags.setColor(SK_ColorBLACK); + } + return clear_flags; +} + void BaseRenderingContext2D::clearRect(double x, double y, double width, - double height, - bool for_reset) { + double height) { if (!ValidateRectForCanvas(x, y, width, height)) return; @@ -1455,13 +1460,7 @@ width, height); } - cc::PaintFlags clear_flags; - clear_flags.setStyle(cc::PaintFlags::kFill_Style); - if (HasAlpha()) { - clear_flags.setBlendMode(SkBlendMode::kClear); - } else { - clear_flags.setColor(SK_ColorBLACK); - } + cc::PaintFlags clear_flags = GetClearFlags(); // clamp to float to avoid float cast overflow when used as SkScalar AdjustRectForCanvas(x, y, width, height); @@ -1472,15 +1471,8 @@ gfx::RectF rect(fx, fy, fwidth, fheight); if (RectContainsTransformedRect(rect, clip_bounds)) { - if (for_reset) { - // In the reset case, we can use kUntransformedUnclippedFill because we - // know the state state was reset. - CheckOverdraw(&clear_flags, CanvasRenderingContext2DState::kNoImage, - OverdrawOp::kContextReset); - } else { - CheckOverdraw(&clear_flags, CanvasRenderingContext2DState::kNoImage, - OverdrawOp::kClearRect); - } + CheckOverdraw(&clear_flags, CanvasRenderingContext2DState::kNoImage, + OverdrawOp::kClearRect); WillDraw(clip_bounds, CanvasPerformanceMonitor::DrawType::kOther); c->drawRect(gfx::RectFToSkRect(rect), clear_flags); } else { @@ -2549,7 +2541,7 @@ } } - WillOverwriteCanvas(); + SkipQueuedDrawCommands(); } void BaseRenderingContext2D::WillUseCurrentFont() const {
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h index 4ae13a49..697b760 100644 --- a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h +++ b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h
@@ -158,11 +158,7 @@ bool isPointInStroke(const double x, const double y); bool isPointInStroke(Path2D*, const double x, const double y); - void clearRect(double x, - double y, - double width, - double height, - bool for_reset = false); + void clearRect(double x, double y, double width, double height); void fillRect(double x, double y, double width, double height); void strokeRect(double x, double y, double width, double height); @@ -550,7 +546,8 @@ virtual bool IsPaint2D() const { return false; } void WillOverwriteCanvas(OverdrawOp); - virtual void WillOverwriteCanvas() = 0; + virtual void SkipQueuedDrawCommands() = 0; + virtual void RestartRecording() = 0; void SetColorScheme(mojom::blink::ColorScheme color_scheme) { if (color_scheme == color_scheme_) { @@ -713,6 +710,8 @@ ColorParseResult ParseColorOrCurrentColor(const String& color_string, Color& color) const; + cc::PaintFlags GetClearFlags() const; + bool origin_tainted_by_content_; UsePaintCache path2d_use_paint_cache_; int num_readbacks_performed_ = 0;
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d_test.cc b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d_test.cc index e400fbf..4c313f1 100644 --- a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d_test.cc +++ b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d_test.cc
@@ -136,7 +136,8 @@ return PredefinedColorSpace::kSRGB; } - void WillOverwriteCanvas() override {} + void SkipQueuedDrawCommands() override { RestartRecording(); } + void RestartRecording() override { recorder_.finishRecordingAsPicture(); } HTMLCanvasElement* HostAsHTMLCanvasElement() const override { return host_canvas_element_;
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc index de6f5e0..1a90825 100644 --- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc +++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc
@@ -260,9 +260,16 @@ row_bytes, x, y); } -void CanvasRenderingContext2D::WillOverwriteCanvas() { - if (IsPaintable()) - canvas()->GetCanvas2DLayerBridge()->WillOverwriteCanvas(); +void CanvasRenderingContext2D::SkipQueuedDrawCommands() { + if (Host() && Host()->ResourceProvider()) { + Host()->ResourceProvider()->SkipQueuedDrawCommands(); + } +} + +void CanvasRenderingContext2D::RestartRecording() { + if (Host() && Host()->ResourceProvider()) { + Host()->ResourceProvider()->RestartRecording(); + } } void CanvasRenderingContext2D::Reset() {
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h index 76cbd53..92c5d6e 100644 --- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h +++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h
@@ -222,7 +222,8 @@ size_t row_bytes, int x, int y) override; - void WillOverwriteCanvas() override; + void SkipQueuedDrawCommands() override; + void RestartRecording() override; void TryRestoreContextEvent(TimerBase*) override; bool WillSetFont() const final;
diff --git a/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc b/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc index bf85c63..313af3c0 100644 --- a/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc +++ b/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc
@@ -364,8 +364,18 @@ orig_info, pixels, row_bytes, x, y); } -void OffscreenCanvasRenderingContext2D::WillOverwriteCanvas() { - GetCanvasResourceProvider()->SkipQueuedDrawCommands(); +void OffscreenCanvasRenderingContext2D::SkipQueuedDrawCommands() { + if (CanvasResourceProvider* provider = GetCanvasResourceProvider(); + provider != nullptr) { + provider->SkipQueuedDrawCommands(); + } +} + +void OffscreenCanvasRenderingContext2D::RestartRecording() { + if (CanvasResourceProvider* provider = GetCanvasResourceProvider(); + provider != nullptr) { + provider->RestartRecording(); + } } bool OffscreenCanvasRenderingContext2D::ResolveFont(const String& new_font) {
diff --git a/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h b/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h index 75d2dee..966a62c 100644 --- a/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h +++ b/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h
@@ -157,7 +157,8 @@ size_t row_bytes, int x, int y) override; - void WillOverwriteCanvas() override; + void SkipQueuedDrawCommands() override; + void RestartRecording() override; void DispatchContextLostEvent(TimerBase*) override; void TryRestoreContextEvent(TimerBase*) override;
diff --git a/third_party/blink/renderer/modules/credentialmanagement/credential_manager_type_converters.cc b/third_party/blink/renderer/modules/credentialmanagement/credential_manager_type_converters.cc index 023eaab..088b5fc 100644 --- a/third_party/blink/renderer/modules/credentialmanagement/credential_manager_type_converters.cc +++ b/third_party/blink/renderer/modules/credentialmanagement/credential_manager_type_converters.cc
@@ -73,6 +73,7 @@ using blink::mojom::blink::DigitalCredentialProviderPtr; using blink::mojom::blink::DigitalCredentialSelector; using blink::mojom::blink::DigitalCredentialSelectorPtr; +using blink::mojom::blink::Hint; using blink::mojom::blink::IdentityCredentialDisconnectOptions; using blink::mojom::blink::IdentityCredentialDisconnectOptionsPtr; using blink::mojom::blink::IdentityProvider; @@ -590,6 +591,8 @@ AuthenticatorSelectionCriteria::From(*options.authenticatorSelection()); } + mojo_options->hints = ConvertTo<Vector<Hint>>(options.hints()); + mojo_options->attestation = AttestationConveyancePreference::NONE; if (options.hasAttestation()) { absl::optional<AttestationConveyancePreference> attestation = @@ -754,6 +757,8 @@ } } + mojo_options->hints = ConvertTo<Vector<Hint>>(options.hints()); + if (options.hasExtensions()) { mojo_options->extensions = ConvertTo<blink::mojom::blink::AuthenticationExtensionsClientInputsPtr>( @@ -1078,4 +1083,22 @@ return mojo_disconnect_options; } +Vector<Hint> TypeConverter<Vector<Hint>, Vector<String>>::Convert( + const Vector<String>& hints) { + Vector<Hint> ret; + + for (const String& hint : hints) { + if (hint == "security-key") { + ret.push_back(Hint::SECURITY_KEY); + } else if (hint == "client-device") { + ret.push_back(Hint::CLIENT_DEVICE); + } else if (hint == "hybrid") { + ret.push_back(Hint::HYBRID); + } + // Unrecognised values are ignored. + } + + return ret; +} + } // namespace mojo
diff --git a/third_party/blink/renderer/modules/credentialmanagement/credential_manager_type_converters.h b/third_party/blink/renderer/modules/credentialmanagement/credential_manager_type_converters.h index 879d2ed8..f37c5c3 100644 --- a/third_party/blink/renderer/modules/credentialmanagement/credential_manager_type_converters.h +++ b/third_party/blink/renderer/modules/credentialmanagement/credential_manager_type_converters.h
@@ -288,6 +288,11 @@ const blink::IdentityCredentialDisconnectOptions&); }; +template <> +struct TypeConverter<Vector<blink::mojom::blink::Hint>, Vector<String>> { + static Vector<blink::mojom::blink::Hint> Convert(const Vector<String>&); +}; + } // namespace mojo #endif // THIRD_PARTY_BLINK_RENDERER_MODULES_CREDENTIALMANAGEMENT_CREDENTIAL_MANAGER_TYPE_CONVERTERS_H_
diff --git a/third_party/blink/renderer/modules/credentialmanagement/public_key_credential_creation_options.idl b/third_party/blink/renderer/modules/credentialmanagement/public_key_credential_creation_options.idl index 014ca27..7e126da 100644 --- a/third_party/blink/renderer/modules/credentialmanagement/public_key_credential_creation_options.idl +++ b/third_party/blink/renderer/modules/credentialmanagement/public_key_credential_creation_options.idl
@@ -11,6 +11,7 @@ unsigned long timeout; sequence<PublicKeyCredentialDescriptor> excludeCredentials = []; AuthenticatorSelectionCriteria authenticatorSelection; + [RuntimeEnabled=WebAuthenticationHints] sequence<DOMString> hints = []; // https://w3c.github.io/webauthn/#enumdef-attestationconveyancepreference DOMString attestation; AuthenticationExtensionsClientInputs extensions;
diff --git a/third_party/blink/renderer/modules/credentialmanagement/public_key_credential_request_options.idl b/third_party/blink/renderer/modules/credentialmanagement/public_key_credential_request_options.idl index c64dc1ef..4304025a 100644 --- a/third_party/blink/renderer/modules/credentialmanagement/public_key_credential_request_options.idl +++ b/third_party/blink/renderer/modules/credentialmanagement/public_key_credential_request_options.idl
@@ -11,5 +11,6 @@ sequence<PublicKeyCredentialDescriptor> allowCredentials = []; // A DOMString expressing a UserVerificationRequirement. DOMString userVerification; + [RuntimeEnabled=WebAuthenticationHints] sequence<DOMString> hints = []; AuthenticationExtensionsClientInputs extensions; };
diff --git a/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.cc b/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.cc index 2f41bd9..7431123 100644 --- a/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.cc +++ b/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.cc
@@ -102,7 +102,7 @@ return PredefinedColorSpace::kSRGB; } -void PaintRenderingContext2D::WillOverwriteCanvas() { +void PaintRenderingContext2D::SkipQueuedDrawCommands() { previous_frame_ = absl::nullopt; if (paint_recorder_.HasRecordedDrawOps()) { // Discard previous draw commands @@ -110,6 +110,12 @@ } } +void PaintRenderingContext2D::RestartRecording() { + previous_frame_ = absl::nullopt; + // Discard previous draw commands + paint_recorder_.finishRecordingAsPicture(); +} + DOMMatrix* PaintRenderingContext2D::getTransform() { const AffineTransform& t = GetState().GetTransform(); DOMMatrix* m = DOMMatrix::Create();
diff --git a/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.h b/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.h index baece2e9..8bce8214 100644 --- a/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.h +++ b/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.h
@@ -104,7 +104,8 @@ protected: PredefinedColorSpace GetDefaultImageDataColorSpace() const final; bool IsPaint2D() const override { return true; } - void WillOverwriteCanvas() override; + void SkipQueuedDrawCommands() override; + void RestartRecording() override; // PaintRenderingContext2D is unable to resolve fonts. bool ResolveFont(const String& new_font) final { return false; }
diff --git a/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.cc b/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.cc index bf8360b..e3ac18e0 100644 --- a/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.cc +++ b/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.cc
@@ -443,8 +443,8 @@ context.GetBrowserInterfaceBroker().GetInterface( perf_recorder.InitWithNewPipeAndPassReceiver()); - webrtc_video_perf_reporter_ = MakeGarbageCollected<WebrtcVideoPerfReporter>( - context.GetTaskRunner(TaskType::kInternalMedia), &context, + webrtc_video_perf_reporter_.Initialize( + context.GetTaskRunner(TaskType::kInternalMedia), std::move(perf_recorder)); } @@ -636,16 +636,14 @@ std::unique_ptr<webrtc::VideoEncoderFactory> webrtc_encoder_factory = blink::CreateWebrtcVideoEncoderFactory( gpu_factories, std::move(video_encoder_metrics_provider_factory), - base::BindRepeating( - &WebrtcVideoPerfReporter::StoreWebrtcVideoStats, - WrapPersistent(webrtc_video_perf_reporter_.Get()))); + base::BindRepeating(&WebrtcVideoPerfReporter::StoreWebrtcVideoStats, + base::Unretained(&webrtc_video_perf_reporter_))); std::unique_ptr<webrtc::VideoDecoderFactory> webrtc_decoder_factory = blink::CreateWebrtcVideoDecoderFactory( gpu_factories, media_decoder_factory, std::move(media_task_runner), render_color_space, - base::BindRepeating( - &WebrtcVideoPerfReporter::StoreWebrtcVideoStats, - WrapPersistent(webrtc_video_perf_reporter_.Get()))); + base::BindRepeating(&WebrtcVideoPerfReporter::StoreWebrtcVideoStats, + base::Unretained(&webrtc_video_perf_reporter_))); // Enable Multiplex codec in SDP optionally. if (base::FeatureList::IsEnabled(blink::features::kWebRtcMultiplexCodec)) { @@ -905,6 +903,7 @@ void PeerConnectionDependencyFactory::CleanupPeerConnectionFactory() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DVLOG(1) << "PeerConnectionDependencyFactory::CleanupPeerConnectionFactory()"; + webrtc_video_perf_reporter_.Shutdown(); socket_factory_ = nullptr; // Not obtaining `signaling_thread` using GetWebRtcSignalingTaskRunner() // because that method triggers EnsureInitialized() and we're trying to @@ -1014,6 +1013,5 @@ Supplement<ExecutionContext>::Trace(visitor); ExecutionContextLifecycleObserver::Trace(visitor); visitor->Trace(p2p_socket_dispatcher_); - visitor->Trace(webrtc_video_perf_reporter_); } } // namespace blink
diff --git a/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.h b/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.h index 88b067b5..a4200ef4 100644 --- a/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.h +++ b/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.h
@@ -20,6 +20,7 @@ #include "third_party/blink/renderer/platform/heap/prefinalizer.h" #include "third_party/blink/renderer/platform/mojo/mojo_binding_context.h" #include "third_party/blink/renderer/platform/supplementable.h" +#include "third_party/blink/renderer/platform/wtf/gc_plugin.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" #include "third_party/blink/renderer/platform/wtf/vector.h" #include "third_party/webrtc/api/async_dns_resolver.h" @@ -207,7 +208,8 @@ raw_ptr<media::GpuVideoAcceleratorFactories, ExperimentalRenderer> gpu_factories_; - Member<WebrtcVideoPerfReporter> webrtc_video_perf_reporter_; + GC_PLUGIN_IGNORE("https://crbug.com/1381979") + WebrtcVideoPerfReporter webrtc_video_perf_reporter_; THREAD_CHECKER(thread_checker_); };
diff --git a/third_party/blink/renderer/modules/peerconnection/webrtc_video_perf_reporter.cc b/third_party/blink/renderer/modules/peerconnection/webrtc_video_perf_reporter.cc index cee2a22..6f5445b 100644 --- a/third_party/blink/renderer/modules/peerconnection/webrtc_video_perf_reporter.cc +++ b/third_party/blink/renderer/modules/peerconnection/webrtc_video_perf_reporter.cc
@@ -10,15 +10,28 @@ namespace blink { -WebrtcVideoPerfReporter::WebrtcVideoPerfReporter( +WebrtcVideoPerfReporter::WebrtcVideoPerfReporter() { + weak_this_ = weak_factory_.GetWeakPtr(); +} + +WebrtcVideoPerfReporter::~WebrtcVideoPerfReporter() { + // `task_runner_` may not be set in some unit tests of other features. + DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence()); +} + +void WebrtcVideoPerfReporter::Shutdown() { + // `task_runner_` may not be set in some unit tests of other features. + DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence()); + weak_factory_.InvalidateWeakPtrs(); +} + +void WebrtcVideoPerfReporter::Initialize( scoped_refptr<base::SingleThreadTaskRunner> task_runner, - ContextLifecycleNotifier* notifier, mojo::PendingRemote<media::mojom::blink::WebrtcVideoPerfRecorder> - perf_recorder) - : perf_recorder_(notifier) { + perf_recorder) { task_runner_ = task_runner; DCHECK(task_runner_->RunsTasksInCurrentSequence()); - perf_recorder_.Bind(std::move(perf_recorder), task_runner_); + perf_recorder_.Bind(std::move(perf_recorder)); } void WebrtcVideoPerfReporter::StoreWebrtcVideoStats( @@ -29,7 +42,7 @@ FROM_HERE, base::BindOnce( &WebrtcVideoPerfReporter::StoreWebrtcVideoStatsOnTaskRunner, - WrapWeakPersistent(this), stats_key, video_stats)); + weak_this_, stats_key, video_stats)); } void WebrtcVideoPerfReporter::StoreWebrtcVideoStatsOnTaskRunner( @@ -38,10 +51,6 @@ DCHECK(task_runner_); DCHECK(task_runner_->RunsTasksInCurrentSequence()); - if (!perf_recorder_.is_bound()) { - return; - } - auto mojo_features = media::mojom::blink::WebrtcPredictionFeatures::New( stats_key.is_decode, static_cast<media::mojom::blink::VideoCodecProfile>(
diff --git a/third_party/blink/renderer/modules/peerconnection/webrtc_video_perf_reporter.h b/third_party/blink/renderer/modules/peerconnection/webrtc_video_perf_reporter.h index 784b934..2bbbb188 100644 --- a/third_party/blink/renderer/modules/peerconnection/webrtc_video_perf_reporter.h +++ b/third_party/blink/renderer/modules/peerconnection/webrtc_video_perf_reporter.h
@@ -8,41 +8,41 @@ #include "base/task/single_thread_task_runner.h" #include "media/base/video_codecs.h" #include "media/mojo/mojom/webrtc_video_perf.mojom-blink.h" +#include "mojo/public/cpp/bindings/remote.h" #include "third_party/blink/renderer/modules/modules_export.h" -#include "third_party/blink/renderer/platform/heap/garbage_collected.h" -#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h" #include "third_party/blink/renderer/platform/peerconnection/stats_collector.h" namespace blink { -class ContextLifecycleNotifier; - // This class is used for WebRTC video performance stats data collection. Its // sole purpose is to pass data collected in the render process to the browser // process where the data is stored to a local database. The data is later used // for smoothness predictions when the MediaCapabilities API receives a query // for a particular video configuration. -class MODULES_EXPORT WebrtcVideoPerfReporter - : public GarbageCollected<WebrtcVideoPerfReporter> { +class MODULES_EXPORT WebrtcVideoPerfReporter { public: - WebrtcVideoPerfReporter( + WebrtcVideoPerfReporter(); + ~WebrtcVideoPerfReporter(); + + void Initialize( scoped_refptr<base::SingleThreadTaskRunner> task_runner, - ContextLifecycleNotifier* notifier, mojo::PendingRemote<media::mojom::blink::WebrtcVideoPerfRecorder> perf_recorder); void StoreWebrtcVideoStats(const StatsCollector::StatsKey& stats_key, const StatsCollector::VideoStats& video_stats); - void Trace(Visitor* visitor) const { visitor->Trace(perf_recorder_); } + void Shutdown(); private: void StoreWebrtcVideoStatsOnTaskRunner( const StatsCollector::StatsKey& stats_key, const StatsCollector::VideoStats& video_stats); + base::WeakPtr<WebrtcVideoPerfReporter> weak_this_; scoped_refptr<base::SingleThreadTaskRunner> task_runner_; - HeapMojoRemote<media::mojom::blink::WebrtcVideoPerfRecorder> perf_recorder_; + mojo::Remote<media::mojom::blink::WebrtcVideoPerfRecorder> perf_recorder_; + base::WeakPtrFactory<WebrtcVideoPerfReporter> weak_factory_{this}; }; } // namespace blink
diff --git a/third_party/blink/renderer/modules/peerconnection/webrtc_video_perf_reporter_test.cc b/third_party/blink/renderer/modules/peerconnection/webrtc_video_perf_reporter_test.cc index 48d4a66..b54127f9 100644 --- a/third_party/blink/renderer/modules/peerconnection/webrtc_video_perf_reporter_test.cc +++ b/third_party/blink/renderer/modules/peerconnection/webrtc_video_perf_reporter_test.cc
@@ -46,15 +46,15 @@ public: WebrtcVideoPerfReporterTest() { mock_recorder_ = std::make_unique<MockWebrtcVideoPerfRecorder>(); - reporter_ = MakeGarbageCollected<WebrtcVideoPerfReporter>( + reporter_.Initialize( blink::scheduler::GetSingleThreadTaskRunnerForTesting(), - /* notifier */ nullptr, mock_recorder_->CreatePendingRemote()); + mock_recorder_->CreatePendingRemote()); } protected: test::TaskEnvironment task_environment_; std::unique_ptr<MockWebrtcVideoPerfRecorder> mock_recorder_; - Persistent<WebrtcVideoPerfReporter> reporter_; + WebrtcVideoPerfReporter reporter_; }; TEST_F(WebrtcVideoPerfReporterTest, StoreWebrtcVideoStats) { @@ -78,7 +78,7 @@ EXPECT_EQ(kExpectedFeaturesA, *features); EXPECT_EQ(kExpectedVideoStats, *video_stats); }); - reporter_->StoreWebrtcVideoStats(kStatsKeyA, kVideoStats); + reporter_.StoreWebrtcVideoStats(kStatsKeyA, kVideoStats); base::RunLoop().RunUntilIdle(); // Toggle the booleans. @@ -97,7 +97,7 @@ EXPECT_EQ(kExpectedFeaturesB, *features); EXPECT_EQ(kExpectedVideoStats, *video_stats); }); - reporter_->StoreWebrtcVideoStats(kStatsKeyB, kVideoStats); + reporter_.StoreWebrtcVideoStats(kStatsKeyB, kVideoStats); base::RunLoop().RunUntilIdle(); }
diff --git a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc index a0b436b..aef77aa 100644 --- a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc +++ b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc
@@ -164,9 +164,6 @@ return; } - SkipQueuedDrawCommands(); - DCHECK(!resource_host_->ResourceProvider()->HasRecordedDrawOps()); - // Frees canvas resource. lose_context_in_background_ = true; ResetResourceProvider(); @@ -315,13 +312,15 @@ int x, int y) { CHECK(resource_host_); - if (!GetOrCreateResourceProvider()) + CanvasResourceProvider* provider = GetOrCreateResourceProvider(); + if (provider == nullptr) { return false; + } if (x <= 0 && y <= 0 && x + orig_info.width() >= resource_host_->Size().width() && y + orig_info.height() >= resource_host_->Size().height()) { - SkipQueuedDrawCommands(); + provider->SkipQueuedDrawCommands(); } else { FlushRecording(FlushReason::kWritePixels); if (!GetOrCreateResourceProvider()) @@ -331,10 +330,6 @@ return ResourceProvider()->WritePixels(orig_info, pixels, row_bytes, x, y); } -void Canvas2DLayerBridge::SkipQueuedDrawCommands() { - ResourceProvider()->SkipQueuedDrawCommands(); -} - void Canvas2DLayerBridge::FlushRecording(FlushReason reason) { CHECK(resource_host_); CanvasResourceProvider* provider = GetOrCreateResourceProvider(); @@ -442,10 +437,6 @@ return ResourceProvider()->Snapshot(reason); } -void Canvas2DLayerBridge::WillOverwriteCanvas() { - SkipQueuedDrawCommands(); -} - void Canvas2DLayerBridge::Logger::ReportHibernationEvent( HibernationEvent event) { UMA_HISTOGRAM_ENUMERATION("Blink.Canvas.HibernationEvents", event);
diff --git a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h index aa5d1b58..3335382 100644 --- a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h +++ b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h
@@ -60,9 +60,6 @@ void PageVisibilityChanged(); bool Restore(); - // virtual for unit testing - virtual void WillOverwriteCanvas(); - void DrawFullImage(const cc::PaintImage&); // This may recreate CanvasResourceProvider @@ -128,8 +125,6 @@ CanvasResourceProvider* ResourceProvider() const; void ResetResourceProvider(); - void SkipQueuedDrawCommands(); - // Check if the Raster Mode is GPU and if the GPU context is not lost bool ShouldAccelerate() const;
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc index 4ae7bed..54e3fcc 100644 --- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc +++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
@@ -1717,15 +1717,35 @@ } void CanvasResourceProvider::SkipQueuedDrawCommands() { - // Note that this function only gets called when canvas needs a full repaint, - // so always update the |mode_| to discard the old copy of canvas content. + // Notify the provider that the recording has been cleared. + RecordingCleared(); + + // If no draw calls have been recorded, we have nothing to skip. The recoding + // could still contain layers or matrix clip stack levels. As an optimization, + // we can early abort as there is no need to discard the layer matrix clip + // stack just to rebuild it again. + if (!HasRecordedDrawOps()) { + return; + } + + // Discards the whole recording and rebuilds the layer and matrix clip stack. + recorder_.finishRecordingAsPicture(); +} + +void CanvasResourceProvider::RestartRecording() { + // Notify the provider that the recording has been cleared. + RecordingCleared(); + // Discard the whole recording and re-initialize it. + recorder_.finishRecordingAsPicture(); +} + +void CanvasResourceProvider::RecordingCleared() { + // The recording was cleared from any draw command it might have had. + // It's now safe to update `mode_` to discard the old copy of canvas content. mode_ = SkSurface::kDiscard_ContentChangeMode; clear_frame_ = true; last_flush_reason_ = FlushReason::kNone; printing_fallback_reason_ = FlushReason::kNone; - if (!HasRecordedDrawOps()) - return; - recorder_.finishRecordingAsPicture(); } void CanvasResourceProvider::RestoreBackBuffer(const cc::PaintImage& image) {
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h index e1064f4f..a349037 100644 --- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h +++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.h
@@ -243,7 +243,17 @@ FlushReason printing_fallback_reason() { return printing_fallback_reason_; } + // Drops all draw ops from the recording while preserving the layer and matrix + // clip stack. This is done by discarding the whole recording and rebuilding + // the layer and matrix clip stack. If the recording contains no draw calls, + // the flush and stack rebuild is optimized out. void SkipQueuedDrawCommands(); + // Restarts the whole recording. This will rebuild the layer and matrix clip + // stack, but since this function is meant to be called after resetting the + // canvas state stack, the matrix clip stack should be rebuilt to it's default + // initial state. + void RestartRecording(); + void RestoreBackBuffer(const cc::PaintImage&); ResourceProviderType GetType() const { return type_; } @@ -353,6 +363,9 @@ void Clear(); + // Called after the recording was cleared from any draw ops it might have had. + void RecordingCleared(); + base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper_; base::WeakPtr<CanvasResourceDispatcher> resource_dispatcher_; // Note that `info_` should be const, but the relevant SkImageInfo
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index ea851e4..4c6fe83 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -4129,6 +4129,11 @@ status: "test", base_feature: "none", }, + // https://w3c.github.io/webauthn/#enum-hints + { + name: "WebAuthenticationHints", + status: "experimental", + }, // https://w3c.github.io/webauthn/#dom-publickeycredential-tojson // https://w3c.github.io/webauthn/#sctn-parseCreationOptionsFromJSON // https://w3c.github.io/webauthn/#sctn-parseRequestOptionsFromJSON
diff --git a/third_party/blink/renderer/platform/widget/input/compositor_thread_event_queue.cc b/third_party/blink/renderer/platform/widget/input/compositor_thread_event_queue.cc index 8714f38..53052da8 100644 --- a/third_party/blink/renderer/platform/widget/input/compositor_thread_event_queue.cc +++ b/third_party/blink/renderer/platform/widget/input/compositor_thread_event_queue.cc
@@ -51,8 +51,7 @@ event_with_callback->RunCallbacks( InputHandlerProxy::DROP_EVENT, event_with_callback->latency_info(), /*did_overscroll_params=*/nullptr, - /*attribution=*/WebInputEventAttribution(), - /*scroll_result_data=*/nullptr); + /*attribution=*/WebInputEventAttribution()); } }
diff --git a/third_party/blink/renderer/platform/widget/input/event_with_callback.cc b/third_party/blink/renderer/platform/widget/input/event_with_callback.cc index cb1eee76..003639a6 100644 --- a/third_party/blink/renderer/platform/widget/input/event_with_callback.cc +++ b/third_party/blink/renderer/platform/widget/input/event_with_callback.cc
@@ -8,7 +8,6 @@ #include "base/trace_event/trace_event.h" #include "cc/metrics/event_metrics.h" #include "third_party/blink/public/common/input/web_input_event_attribution.h" -#include "third_party/blink/public/mojom/input/input_handler.mojom-blink.h" namespace blink { @@ -80,8 +79,7 @@ const ui::LatencyInfo& latency, std::unique_ptr<InputHandlerProxy::DidOverscrollParams> did_overscroll_params, - const WebInputEventAttribution& attribution, - mojom::blink::ScrollResultDataPtr scroll_result_data) { + const WebInputEventAttribution& attribution) { // |original_events_| could be empty if this is the scroll event extracted // from the matrix multiplication. if (original_events_.size() == 0) @@ -96,8 +94,7 @@ ? std::make_unique<InputHandlerProxy::DidOverscrollParams>( *did_overscroll_params) : nullptr, - attribution, std::move(oldest_event.metrics_), - scroll_result_data ? scroll_result_data->Clone() : nullptr); + attribution, std::move(oldest_event.metrics_)); original_events_.pop_front(); // If the event was handled on the compositor thread, ack other events with @@ -127,8 +124,7 @@ ? std::make_unique<InputHandlerProxy::DidOverscrollParams>( *did_overscroll_params) : nullptr, - attribution, std::move(coalesced_event.metrics_), - scroll_result_data ? scroll_result_data->Clone() : nullptr); + attribution, std::move(coalesced_event.metrics_)); } }
diff --git a/third_party/blink/renderer/platform/widget/input/event_with_callback.h b/third_party/blink/renderer/platform/widget/input/event_with_callback.h index fe706ccd..4f11660 100644 --- a/third_party/blink/renderer/platform/widget/input/event_with_callback.h +++ b/third_party/blink/renderer/platform/widget/input/event_with_callback.h
@@ -9,7 +9,6 @@ #include "base/time/time.h" #include "third_party/blink/public/common/input/web_coalesced_input_event.h" -#include "third_party/blink/public/mojom/input/input_handler.mojom-blink-forward.h" #include "third_party/blink/renderer/platform/platform_export.h" #include "third_party/blink/renderer/platform/widget/input/input_handler_proxy.h" #include "ui/latency/latency_info.h" @@ -55,8 +54,7 @@ void RunCallbacks(InputHandlerProxy::EventDisposition, const ui::LatencyInfo& latency, std::unique_ptr<InputHandlerProxy::DidOverscrollParams>, - const WebInputEventAttribution&, - mojom::blink::ScrollResultDataPtr scroll_result_data); + const WebInputEventAttribution&); const WebInputEvent& event() const { return event_->Event(); } WebInputEvent* event_pointer() { return event_->EventPointer(); }
diff --git a/third_party/blink/renderer/platform/widget/input/input_handler_proxy.cc b/third_party/blink/renderer/platform/widget/input/input_handler_proxy.cc index 40aa3056..50c5085a 100644 --- a/third_party/blink/renderer/platform/widget/input/input_handler_proxy.cc +++ b/third_party/blink/renderer/platform/widget/input/input_handler_proxy.cc
@@ -33,7 +33,6 @@ #include "third_party/blink/public/common/input/web_mouse_wheel_event.h" #include "third_party/blink/public/common/input/web_pointer_event.h" #include "third_party/blink/public/common/input/web_touch_event.h" -#include "third_party/blink/public/mojom/input/input_handler.mojom-blink.h" #include "third_party/blink/renderer/platform/widget/input/compositor_thread_event_queue.h" #include "third_party/blink/renderer/platform/widget/input/cursor_control_handler.h" #include "third_party/blink/renderer/platform/widget/input/elastic_overscroll_controller.h" @@ -214,7 +213,6 @@ handling_gesture_on_impl_thread_(false), scroll_sequence_ignored_(false), current_overscroll_params_(nullptr), - current_scroll_result_data_(nullptr), has_seen_first_gesture_scroll_update_after_begin_(false), last_injected_gesture_was_begin_(false), tick_clock_(base::DefaultTickClock::GetInstance()), @@ -426,7 +424,7 @@ PerformEventAttribution(event->Event()); std::move(callback).Run(DROP_EVENT, std::move(event), /*overscroll_params=*/nullptr, attribution, - std::move(metrics), /*scroll_result_data=*/nullptr); + std::move(metrics)); } // We blocked the compositor gesture event queue while the hit test was @@ -498,8 +496,7 @@ // Will run callback for every original events. event_with_callback->RunCallbacks(disposition, monitored_latency_info, std::move(current_overscroll_params_), - attribution, - std::move(current_scroll_result_data_)); + attribution); } bool InputHandlerProxy::HasQueuedEventsReadyForDispatch(bool frame_aligned) { @@ -1102,14 +1099,6 @@ if (metrics && scroll_result.needs_main_thread_repaint) metrics->set_requires_main_thread_update(); - if (scroll_result.did_scroll) { - current_scroll_result_data_ = mojom::blink::ScrollResultData::New(); - if (input_handler_->IsCurrentlyScrollingViewport()) { - current_scroll_result_data_->root_scroll_offset = - scroll_result.current_visual_offset; - } - } - return scroll_result.did_scroll ? DID_HANDLE : DROP_EVENT; }
diff --git a/third_party/blink/renderer/platform/widget/input/input_handler_proxy.h b/third_party/blink/renderer/platform/widget/input/input_handler_proxy.h index 18649acb4..3417690 100644 --- a/third_party/blink/renderer/platform/widget/input/input_handler_proxy.h +++ b/third_party/blink/renderer/platform/widget/input/input_handler_proxy.h
@@ -15,7 +15,6 @@ #include "cc/paint/element_id.h" #include "third_party/blink/public/common/input/web_coalesced_input_event.h" #include "third_party/blink/public/common/input/web_gesture_event.h" -#include "third_party/blink/public/mojom/input/input_handler.mojom-blink.h" #include "third_party/blink/public/platform/web_common.h" #include "third_party/blink/renderer/platform/platform_export.h" @@ -152,8 +151,7 @@ std::unique_ptr<blink::WebCoalescedInputEvent> event, std::unique_ptr<DidOverscrollParams>, const blink::WebInputEventAttribution&, - std::unique_ptr<cc::EventMetrics> metrics, - mojom::blink::ScrollResultDataPtr)>; + std::unique_ptr<cc::EventMetrics> metrics)>; void HandleInputEventWithLatencyInfo( std::unique_ptr<blink::WebCoalescedInputEvent> event, std::unique_ptr<cc::EventMetrics> metrics, @@ -371,11 +369,6 @@ // bundled in the event ack, saving an IPC. std::unique_ptr<DidOverscrollParams> current_overscroll_params_; - // Used to cache the scroll result data - e.g. root scroll offset - when a - // scroll gesture is handled. This data is then passed back using - // |EventDispositionCallback|. - mojom::blink::ScrollResultDataPtr current_scroll_result_data_; - std::unique_ptr<CompositorThreadEventQueue> compositor_event_queue_; // Set only when the compositor input handler is handling a gesture. Tells
diff --git a/third_party/blink/renderer/platform/widget/input/input_handler_proxy_unittest.cc b/third_party/blink/renderer/platform/widget/input/input_handler_proxy_unittest.cc index d8ebce0..a381251 100644 --- a/third_party/blink/renderer/platform/widget/input/input_handler_proxy_unittest.cc +++ b/third_party/blink/renderer/platform/widget/input/input_handler_proxy_unittest.cc
@@ -468,8 +468,7 @@ std::unique_ptr<blink::WebCoalescedInputEvent> event, std::unique_ptr<InputHandlerProxy::DidOverscrollParams> callback, const WebInputEventAttribution& attribution, - std::unique_ptr<cc::EventMetrics> metrics, - mojom::blink::ScrollResultDataPtr scroll_result_data) { + std::unique_ptr<cc::EventMetrics> metrics) { event_disposition = disposition; })); return event_disposition; @@ -496,8 +495,7 @@ std::unique_ptr<blink::WebCoalescedInputEvent> event, std::unique_ptr<InputHandlerProxy::DidOverscrollParams> callback, const WebInputEventAttribution& attribution, - std::unique_ptr<cc::EventMetrics> metrics, - mojom::blink::ScrollResultDataPtr scroll_result_data) { + std::unique_ptr<cc::EventMetrics> metrics) { event_disposition = disposition; })); @@ -556,8 +554,7 @@ std::unique_ptr<WebCoalescedInputEvent> input_event, std::unique_ptr<InputHandlerProxy::DidOverscrollParams> overscroll_params, const WebInputEventAttribution& attribution, - std::unique_ptr<cc::EventMetrics> metrics, - mojom::blink::ScrollResultDataPtr scroll_result_data) { + std::unique_ptr<cc::EventMetrics> metrics) { event_disposition_recorder_.push_back(event_disposition); latency_info_recorder_.push_back(input_event->latency_info()); } @@ -1908,8 +1905,7 @@ std::unique_ptr<WebCoalescedInputEvent> input_event, std::unique_ptr<InputHandlerProxy::DidOverscrollParams> overscroll_params, const WebInputEventAttribution& attribution, - std::unique_ptr<cc::EventMetrics> metrics, - mojom::blink::ScrollResultDataPtr scroll_result_data) { + std::unique_ptr<cc::EventMetrics> metrics) { if (out_disposition) *out_disposition = event_disposition; }
diff --git a/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.cc b/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.cc index a90da03..4bf3319 100644 --- a/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.cc +++ b/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.cc
@@ -24,7 +24,6 @@ #include "third_party/blink/public/common/input/web_coalesced_input_event.h" #include "third_party/blink/public/common/input/web_input_event_attribution.h" #include "third_party/blink/public/common/input/web_keyboard_event.h" -#include "third_party/blink/public/mojom/input/input_handler.mojom-blink-forward.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/public/platform/scheduler/web_thread_scheduler.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" @@ -72,8 +71,7 @@ mojom::blink::InputEventResultState result_state, const ui::LatencyInfo& latency_info, mojom::blink::DidOverscrollParamsPtr overscroll_params, - absl::optional<cc::TouchAction> touch_action, - mojom::blink::ScrollResultDataPtr scroll_result_data) { + absl::optional<cc::TouchAction> touch_action) { ui::LatencyInfo::TraceIntermediateFlowEvents( {latency_info}, ChromeLatencyInfo::STEP_HANDLED_INPUT_EVENT_IMPL); std::move(callback).Run( @@ -81,8 +79,7 @@ result_state, std::move(overscroll_params), touch_action ? mojom::blink::TouchActionOptional::New(touch_action.value()) - : nullptr, - std::move(scroll_result_data)); + : nullptr); } mojom::blink::InputEventResultState InputEventDispositionToAck( @@ -546,10 +543,9 @@ if (suppress_input && !allow_pre_commit_input_ && !event_is_mouse_or_pointer_move) { if (callback) { - std::move(callback).Run(mojom::blink::InputEventResultSource::kMainThread, - ui::LatencyInfo(), - mojom::blink::InputEventResultState::kNotConsumed, - nullptr, nullptr, /*scroll_result_data=*/nullptr); + std::move(callback).Run( + mojom::blink::InputEventResultSource::kMainThread, ui::LatencyInfo(), + mojom::blink::InputEventResultState::kNotConsumed, nullptr, nullptr); } return; } @@ -630,8 +626,8 @@ std::move(callback).Run( mojom::blink::InputEventResultSource::kMainThread, ui::LatencyInfo(), - mojom::blink::InputEventResultState::kNotConsumed, nullptr, nullptr, - /*scroll_result_data=*/nullptr); + mojom::blink::InputEventResultState::kNotConsumed, nullptr, + nullptr); } return; } @@ -823,7 +819,7 @@ std::move(callback).Run(mojom::blink::InputEventResultSource::kMainThread, event->latency_info(), mojom::blink::InputEventResultState::kNotConsumed, - nullptr, nullptr, nullptr); + nullptr, nullptr); } return; } @@ -853,7 +849,7 @@ .Run(mojom::blink::InputEventResultSource::kMainThread, ui::LatencyInfo(), mojom::blink::InputEventResultState::kNotConsumed, nullptr, - nullptr, nullptr); + nullptr); return; } @@ -882,8 +878,7 @@ std::unique_ptr<WebCoalescedInputEvent> event, std::unique_ptr<InputHandlerProxy::DidOverscrollParams> overscroll_params, const WebInputEventAttribution& attribution, - std::unique_ptr<cc::EventMetrics> metrics, - mojom::blink::ScrollResultDataPtr scroll_result_data) { + std::unique_ptr<cc::EventMetrics> metrics) { TRACE_EVENT1("input", "WidgetInputHandlerManager::DidHandleInputEventSentToCompositor", "Disposition", event_disposition); @@ -993,8 +988,7 @@ ToDidOverscrollParams(overscroll_params.get()), touch_action ? mojom::blink::TouchActionOptional::New(touch_action.value()) - : nullptr, - std::move(scroll_result_data)); + : nullptr); } } @@ -1046,8 +1040,7 @@ compositor_thread_default_task_runner_->PostTask( FROM_HERE, base::BindOnce(CallCallback, std::move(callback), ack_state, latency_info, std::move(overscroll_params), - touch_action_for_ack, - /*scroll_result_data=*/nullptr)); + touch_action_for_ack)); } else { // Otherwise call the callback immediately. std::move(callback).Run( @@ -1057,8 +1050,7 @@ latency_info, ack_state, std::move(overscroll_params), touch_action_for_ack ? mojom::blink::TouchActionOptional::New( touch_action_for_ack.value()) - : nullptr, - /*scroll_result_data=*/nullptr); + : nullptr); } }
diff --git a/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.h b/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.h index c0526ff..493f299 100644 --- a/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.h +++ b/third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.h
@@ -15,7 +15,6 @@ #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/shared_remote.h" -#include "third_party/blink/public/mojom/input/input_handler.mojom-blink-forward.h" #include "third_party/blink/public/mojom/input/input_handler.mojom-blink.h" #include "third_party/blink/renderer/platform/platform_export.h" #include "third_party/blink/renderer/platform/widget/input/input_handler_proxy.h" @@ -238,8 +237,7 @@ std::unique_ptr<WebCoalescedInputEvent> event, std::unique_ptr<InputHandlerProxy::DidOverscrollParams> overscroll_params, const WebInputEventAttribution& attribution, - std::unique_ptr<cc::EventMetrics> metrics, - mojom::blink::ScrollResultDataPtr scroll_result_data); + std::unique_ptr<cc::EventMetrics> metrics); // Similar to the above; this is used by the main thread input handler to // communicate back the result of handling the event. Note: this may be
diff --git a/third_party/blink/tools/blinkpy/web_tests/flake_suppressor/suppress_flakes.py b/third_party/blink/tools/blinkpy/web_tests/flake_suppressor/suppress_flakes.py index 53c6d0d..db02b6df 100644 --- a/third_party/blink/tools/blinkpy/web_tests/flake_suppressor/suppress_flakes.py +++ b/third_party/blink/tools/blinkpy/web_tests/flake_suppressor/suppress_flakes.py
@@ -77,7 +77,8 @@ expectations_processor.CreateExpectationsForAllResults( aggregated_results, args.group_by_tags, args.include_all_tags, args.build_fail_total_number_threshold, - args.build_fail_consecutive_days_threshold) + args.build_fail_consecutive_days_threshold, + args.build_fail_recent_days_threshold) else: if len(args.builder_names) > 0: result_counts = querier_instance.\
diff --git a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/analyzer.py b/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/analyzer.py index 593b601..cf64355 100644 --- a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/analyzer.py +++ b/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/analyzer.py
@@ -7,6 +7,9 @@ from blinkpy.web_tests.fuzzy_diff_analyzer import data_types as dt +MAX_BUILDER_NUM = 5 +AVG_DURATION_THRESHOLD = 0.75 + class ImageMatchingAnalyzer: """Abstract base class for all analyzers.""" @@ -138,3 +141,73 @@ des += ('distinct_diff_num_threshold of %d' % self._distinct_diff_num_threshold) return des + + +class SlowTestAnalyzer: + def __init__(self, + slow_result_ratio_threshold: float = 0.9, + timeout_result_threshold: int = 0): + """Class for the slow test analyzer for web tests. + + Args: (Both thresholds must be hit for a test to be considered slow) + slow_result_ratio_threshold: A float denoting what fraction + of results need to be slow for a test to be considered slow. + timeout_result_threshold: An int denoting the number of timeout + results necessary for a test to be considered slow. + """ + assert slow_result_ratio_threshold >= 0 + assert slow_result_ratio_threshold <= 1 + assert timeout_result_threshold >= 0 + self._slow_result_ratio_threshold = slow_result_ratio_threshold + self._timeout_result_threshold = timeout_result_threshold + + def run_analyzer( + self, test_results: List[dt.TestSlownessTupleType] + ) -> dt.TestAnalysisResultType: + """Analyze the input test slowness data to show a statistics and + suggestion. + + Args: + test_results: list of slowness data per builder. + + Returns: + A test analysis result representing the analyzer's statistics and + suggestion for the slow test. + """ + # Filter slowness data per builder + slow_tests = [] + for result in test_results: + if (result.timeout_count >= self._timeout_result_threshold + and result.avg_duration >= + result.timeout * AVG_DURATION_THRESHOLD): + total_non_timeout_count = result.slow_count + result.non_slow_count + slow_ratio = (result.slow_count / total_non_timeout_count + if total_non_timeout_count else 0) + if slow_ratio >= self._slow_result_ratio_threshold: + slow_tests.append( + dt.TestSlownessData(result.builder, result.slow_count, + slow_ratio, result.timeout_count, + result.avg_duration)) + + # No slowness data meet the threshold, return no result. + if not slow_tests: + return dt.TestAnalysisResultType( + False, 'Test does not meet threshold in all builders.') + + sorted(slow_tests, key=lambda x: x.slow_ratio) + count = min(MAX_BUILDER_NUM, len(slow_tests)) + result = 'Test is slow in the below list of builders:\n' + for i in range(count): + test = slow_tests[i] + result += '%s : timeout count: %d, ' % (test.builder, + test.timeout_count) + result += 'slow count: %d, ' % test.slow_count + result += 'slow ratio: %.2f, ' % test.slow_ratio + result += 'avg duration: %.2f\n' % test.avg_duration + return dt.TestAnalysisResultType(True, result) + + def description(self) -> str: + des = (f'Slow test analyzer with slow_result_ration_threshold of ' + f'{self._slow_result_ratio_threshold} and ' + f'timeout_result_threshold of {self._timeout_result_threshold}') + return des
diff --git a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/analyzer_unittest.py b/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/analyzer_unittest.py index 928ad55d..5b6a210 100644 --- a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/analyzer_unittest.py +++ b/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/analyzer_unittest.py
@@ -149,3 +149,75 @@ analyzer.FuzzyMatchingAnalyzer( fuzzy_match_image_diff_num_threshold=0, fuzzy_match_distinct_diff_num_threshold=-1) + + +class SlowTestAnalyzerTest(unittest.TestCase): + def test_run_analyzer_in_bad_slow_ratio_threshold(self) -> None: + slow_test_analyzer = analyzer.SlowTestAnalyzer(0.95, 0) + + test_data = \ + [ + dt.TestSlownessTupleType('builder1', 1, 30, 1.1, 2, 6), + dt.TestSlownessTupleType('builder2', 30, 5, 3.1, 5, 6), + ] + actual_result = slow_test_analyzer.run_analyzer( + test_data).analysis_result + expected_result = 'Test does not meet threshold in all builders.' + self.assertEqual(actual_result, expected_result) + + def test_run_analyzer_in_good_slow_ratio_threshold(self) -> None: + slow_test_analyzer = analyzer.SlowTestAnalyzer(0.9, 0) + + test_data = \ + [ + dt.TestSlownessTupleType('builder1', 1, 30, 1.1, 2, 6), + dt.TestSlownessTupleType('builder2', 30, 3, 4.9, 5, 6), + ] + actual_result = slow_test_analyzer.run_analyzer( + test_data).analysis_result + expected_result = 'Test is slow in the below list of builders:\n' \ + 'builder2 : timeout count: 5, slow count: 30, ' \ + 'slow ratio: 0.91, avg duration: 4.90\n' + self.assertEqual(actual_result, expected_result) + + def test_run_analyzer_in_bad_timeout_count_threshold(self) -> None: + slow_test_analyzer = analyzer.SlowTestAnalyzer(0.9, 10) + + test_data = \ + [ + dt.TestSlownessTupleType('builder1', 20, 1, 5.1, 2, 6), + dt.TestSlownessTupleType('builder2', 30, 1, 3.1, 5, 6), + ] + actual_result = slow_test_analyzer.run_analyzer( + test_data).analysis_result + expected_result = 'Test does not meet threshold in all builders.' + self.assertEqual(actual_result, expected_result) + + def test_run_analyzer_in_good_timeout_count_threshold(self) -> None: + slow_test_analyzer = analyzer.SlowTestAnalyzer(0.9, 4) + + test_data = \ + [ + dt.TestSlownessTupleType('builder1', 20, 1, 3.1, 6, 6), + dt.TestSlownessTupleType('builder2', 30, 1, 5.1, 5, 6), + ] + actual_result = slow_test_analyzer.run_analyzer( + test_data).analysis_result + expected_result = 'Test is slow in the below list of builders:\n' \ + 'builder2 : timeout count: 5, slow count: 30, ' \ + 'slow ratio: 0.97, avg duration: 5.10\n' + self.assertEqual(actual_result, expected_result) + + def test_invalid_args(self) -> None: + # Test negative number. + with self.assertRaises(AssertionError): + analyzer.SlowTestAnalyzer(slow_result_ratio_threshold=-1, + timeout_result_threshold=0) + # Test number greater than 1. + with self.assertRaises(AssertionError): + analyzer.SlowTestAnalyzer(slow_result_ratio_threshold=1.1, + timeout_result_threshold=0) + # Test negative number. + with self.assertRaises(AssertionError): + analyzer.SlowTestAnalyzer(slow_result_ratio_threshold=0, + timeout_result_threshold=-1)
diff --git a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/data_types.py b/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/data_types.py index 2b1360b..4908011 100644 --- a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/data_types.py +++ b/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/data_types.py
@@ -27,6 +27,22 @@ TestAnalysisResultType = namedtuple('TestAnalysisResultType', ['is_analyzed', 'analysis_result']) +# Test slowness data, example: ['builder1', 5, 100, 2.1, 10, 6] +# Sample: +# { +# 'test_name': [ ('builder1', 5, 100, 2.1, 1, 6), +# ('builder2', 10, 5, 5.1, 20, 6), ] +# } +TestSlownessTupleType = namedtuple('TestSlownessTupleType', [ + 'builder', 'slow_count', 'non_slow_count', 'avg_duration', 'timeout_count', + 'timeout' +]) +AggregatedSlownessResultsType = Dict[str, List[TestSlownessTupleType]] + +TestSlownessData = namedtuple( + 'TestSlownessData', + ['builder', 'slow_count', 'slow_ratio', 'timeout_count', 'avg_duration']) + class Result: """Container for an image diff test result.
diff --git a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/fuzzy_diff_analyzer.py b/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/fuzzy_diff_analyzer.py index 19668eb..0fc8a349 100644 --- a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/fuzzy_diff_analyzer.py +++ b/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/fuzzy_diff_analyzer.py
@@ -80,8 +80,7 @@ def main() -> int: args = ParseArgs() - querier_instance = queries.FuzzyDiffAnalyzerQuerier( - args.sample_period, args.project) + querier_instance = queries.Querier(args.sample_period, args.project) results_processor = results.ResultProcessor() matching_analyzer = analyzer.FuzzyMatchingAnalyzer( args.image_diff_num_threshold, args.distinct_diff_num_threshold)
diff --git a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/queries.py b/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/queries.py index 8eefb6768..5c16398 100644 --- a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/queries.py +++ b/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/queries.py
@@ -9,6 +9,7 @@ from typing import Optional from flake_suppressor_common import common_typing as ct +from flake_suppressor_common import queries as queries_module from unexpected_passes_common import queries as upc_queries # Gets all image comparison failures from the past |sample_period| days from CI @@ -66,6 +67,57 @@ image_diff_total_pixels IS NOT NULL """ +# Gets overall test slowness from the past |sample_period| days from CI +# bots. +# List of data selected from the database: +# test_name - the full test name, like external/wpt/rendering/test1 +# builder - name of the builder that runs the test +# slow_count - total number of pass and failed test runs that are slow +# non_slow_count - total number of pass and failed test runs that are not slow +# avg_duration - average runtime of slow and non-slow tests +# timeout_count - total number of timeout test runs +CI_TESTS_OVERALL_SLOWNESS_QUERY = """\ +WITH + {sheriff_rotations_ci_builds} + tests_slowness AS ( + SELECT + test_metadata.name as test_name, + CAST((SELECT value FROM tr.tags + WHERE key = "web_tests_base_timeout") AS float64) as timeout, + (SELECT value FROM tr.variant + WHERE key = "test_suite") as test_suite, + (SELECT value FROM tr.variant + WHERE key = "builder") as builder, + CAST(( + SELECT value + FROM tr.tags + WHERE key = "web_tests_test_was_slow") AS bool) as test_was_slow, + duration, + status, + FROM `chrome-luci-data.chromium.blink_web_tests_ci_test_results` tr + WHERE + (status = "ABORT" OR status = "PASS" OR status = "FAIL") AND + {test_path_selector} + exported.realm = "chromium:ci" AND + partition_time > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), + INTERVAL @sample_period DAY) +) +SELECT + test_name, + builder, + timeout, + SUM(CASE WHEN test_was_slow = true THEN 1 ELSE 0 END) AS slow_count, + SUM(CASE WHEN test_was_slow = false THEN 1 ELSE 0 END) AS non_slow_count, + AVG(CASE WHEN status = "ABORT" THEN NULL ELSE duration END) AS avg_duration, + SUM(CASE WHEN status = "ABORT" THEN 1 ELSE 0 END) AS timeout_count, +FROM tests_slowness +WHERE + (REGEXP_CONTAINS(test_suite, "blink_w(pt|eb)_tests") + AND NOT REGEXP_CONTAINS(test_suite, "^webgpu")) + {builder_selector} +GROUP BY test_name, builder, timeout +""" + # Gets all web test flaky bugs and their flaky tests from the past |sample_period| # days. # List of data selected from the database: @@ -98,9 +150,9 @@ """ -class FuzzyDiffAnalyzerQuerier: +class Querier: def __init__(self, sample_period: int, billing_project: str): - """Class for making calls to BigQuery for Fuzzy Diff Analyzer. + """Class for making calls to BigQuery. Args: sample_period: An int denoting the number of days that data should be @@ -132,6 +184,45 @@ CI_FAILED_IMAGE_COMPARISON_TEST_QUERY.format( test_path_selector=test_path_selector)) + def get_overall_slowness_ci_tests( + self, + test_path: Optional[str] = None, + only_check_sheriff_builds: Optional[bool] = True + ) -> ct.QueryJsonType: + """Gets overall test slowness data from CI under the test path. + + Args: + test_path: A string of test path that contains the tests to do + analysis. If the value is empty, this will check all tests. + only_check_sheriff_builds: A bool var to indicate if only + check sheriff builders or all builders. + + Returns: + A JSON representation of the BigQuery results containing all found + overall test slowness that came from CI bots under the test path. + """ + if test_path: + test_path_selector = ('STARTS_WITH(test_metadata.name, "%s") AND' % + test_path) + else: + test_path_selector = '' + + if only_check_sheriff_builds: + chromium_builds = queries_module.SHERIFF_ROTATIONS_CI_BUILDS_TEMPLATE + sheriff_rotations_ci_builds = \ + f'sheriff_rotations_ci_builds AS ({chromium_builds}),' + builder_selector = ('AND builder IN (SELECT builder ' + 'FROM sheriff_rotations_ci_builds)') + else: + sheriff_rotations_ci_builds = '' + builder_selector = '' + + return self._get_json_results( + CI_TESTS_OVERALL_SLOWNESS_QUERY.format( + sheriff_rotations_ci_builds=sheriff_rotations_ci_builds, + test_path_selector=test_path_selector, + builder_selector=builder_selector)) + def get_web_test_flaky_bugs(self) -> ct.QueryJsonType: """Gets all web test flaky bugs from the database.
diff --git a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/queries_unittest.py b/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/queries_unittest.py index 2d9ab28..23fcb3fa 100644 --- a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/queries_unittest.py +++ b/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/queries_unittest.py
@@ -39,10 +39,26 @@ 'test_ids': ['testC', 'testD', 'testE'], }] +QUERY_DATA_3 = [{ + 'name': 'foo/bar/windows', + 'builder': 'windows_builder', + 'slow_count': 5, + 'non_slow_count': 100, + 'avg_duration': 2.1, + 'timeout_count': 3, +}, { + 'name': 'foo/bar/mac', + 'builder': 'mac_builder', + 'slow_count': 30, + 'non_slow_count': 2, + 'avg_duration': 5.5, + 'timeout_count': 20, +}] + class FuzzyDiffAnalyzerQueriesUnittest(unittest.TestCase): def setUp(self) -> None: - self._querier_instance = queries.FuzzyDiffAnalyzerQuerier(1, 'project') + self._querier_instance = queries.Querier(1, 'project') self._subprocess_patcher = mock.patch( 'flake_suppressor_common.queries.subprocess.run') self._subprocess_mock = self._subprocess_patcher.start() @@ -55,8 +71,7 @@ self.assertEqual( query,queries.CI_FAILED_IMAGE_COMPARISON_TEST_QUERY.format( test_path_selector='')) - query_result = QUERY_DATA - return uu.FakeProcess(stdout=json.dumps(query_result)) + return uu.FakeProcess(stdout=json.dumps(QUERY_DATA)) self._subprocess_mock.side_effect = side_effect result_query = \ @@ -69,11 +84,29 @@ def side_effect(*_, **kwargs) -> uu.FakeProcess: query = kwargs['input'] self.assertEqual(query, queries.WEB_TEST_FLAKY_BUGS_QUERY) - query_result = QUERY_DATA_2 - return uu.FakeProcess(stdout=json.dumps(query_result)) + return uu.FakeProcess(stdout=json.dumps(QUERY_DATA_2)) self._subprocess_mock.side_effect = side_effect result_query = \ self._querier_instance.get_web_test_flaky_bugs() self.assertEqual(result_query, QUERY_DATA_2) self.assertEqual(self._subprocess_mock.call_count, 1) + + def testGetOverallTestSlowness(self) -> None: + """Tests that the query instance is sending the sql.""" + def side_effect(*_, **kwargs) -> uu.FakeProcess: + query = kwargs['input'] + self.assertEqual( + query, + queries.CI_TESTS_OVERALL_SLOWNESS_QUERY.format( + test_path_selector='', + sheriff_rotations_ci_builds='', + builder_selector='')) + return uu.FakeProcess(stdout=json.dumps(QUERY_DATA_3)) + + self._subprocess_mock.side_effect = side_effect + result_query = \ + self._querier_instance.get_overall_slowness_ci_tests( + only_check_sheriff_builds=False) + self.assertEqual(result_query, QUERY_DATA_3) + self.assertEqual(self._subprocess_mock.call_count, 1)
diff --git a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/results.py b/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/results.py index a0e74d1..edfd5294 100644 --- a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/results.py +++ b/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/results.py
@@ -56,3 +56,32 @@ object_results.append( dt.Result(r['name'], typ_tags, image_diff_tag, build_id)) return object_results + + def aggregate_test_slowness_results( + self, + results: ct.QueryJsonType) -> dt.AggregatedSlownessResultsType: + """Aggregates BigQuery results for test slowness data. + + Args: + results: Parsed JSON test results from a BigQuery query. + + Returns: + A map in the following format: + { + 'test_name': { + 'typ_tags_as_tuple': [ ('builder1', 5, 100, 2.1, 1), + ('builder2', 10, 5, 5.1, 20), ] + }, + } + """ + aggregated_results = defaultdict(lambda: []) + for r in results: + avg_duration = float(r['avg_duration']) if r['avg_duration'] else 0 + slowness_data = dt.TestSlownessTupleType(r['builder'], + int(r['slow_count']), + int(r['non_slow_count']), + avg_duration, + int(r['timeout_count']), + float(r['timeout'])) + aggregated_results[r['test_name']].append(slowness_data) + return aggregated_results
diff --git a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/results_unittest.py b/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/results_unittest.py index 2f5f8fe..cf806c3 100644 --- a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/results_unittest.py +++ b/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/results_unittest.py
@@ -93,3 +93,55 @@ self.assertEqual( self._result_processor._convert_json_results_to_result_objects(r), expected_results) + + +class AggregateSlownessResultsUnittest(BaseResultsUnittest): + def testBasic(self) -> None: + """Basic functionality test.""" + query_results = [ + { + 'test_name': 'test1', + 'builder': 'builder1', + 'slow_count': '1', + 'non_slow_count': '40', + 'avg_duration': '1.2', + 'timeout_count': '0', + 'timeout': '6', + }, + { + 'test_name': 'test2', + 'builder': 'builder2', + 'slow_count': '10', + 'non_slow_count': '4', + 'avg_duration': '5.2', + 'timeout_count': '3', + 'timeout': '6', + }, + { + 'test_name': 'test3', + 'builder': 'builder1', + 'slow_count': '0', + 'non_slow_count': '100', + 'avg_duration': '0.2', + 'timeout_count': '0', + 'timeout': '6', + }, + { + 'test_name': 'test1', + 'builder': 'builder2', + 'slow_count': '100', + 'non_slow_count': '0', + 'avg_duration': '5.9', + 'timeout_count': '20', + 'timeout': '6', + }, + ] + expected_output = { + 'test1': [('builder1', 1, 40, 1.2, 0, 6), + ('builder2', 100, 0, 5.9, 20, 6)], + 'test2': [('builder2', 10, 4, 5.2, 3, 6)], + 'test3': [('builder1', 0, 100, 0.2, 0, 6)], + } + self.assertEqual( + self._result_processor.aggregate_test_slowness_results( + query_results), expected_output)
diff --git a/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/slow_test_analyzer.py b/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/slow_test_analyzer.py new file mode 100644 index 0000000..e6a0f255 --- /dev/null +++ b/third_party/blink/tools/blinkpy/web_tests/fuzzy_diff_analyzer/slow_test_analyzer.py
@@ -0,0 +1,82 @@ +# 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. +"""Script to analysis the test slowness data. + +Example usage, which finds slowness data of web tests in the +past 3 days. The script will provide a statistics of the slowness +and recommended an action for each slow test: + +third_party/blink/tools/run_slow_test_analyzer.py \ + --sample-period 3 + +Example output: +Test name: test1 +Test is slow in the below list of builders: +builder1 : timeout count: 7, slow count: 35, slow ratio: 1.00, avg duration: 5.30 +builder2 : timeout count: 5, slow count: 32, slow ratio: 1.00, avg duration: 5.24 +""" + +import argparse + +from blinkpy.web_tests.fuzzy_diff_analyzer import analyzer +from blinkpy.web_tests.fuzzy_diff_analyzer import queries +from blinkpy.web_tests.fuzzy_diff_analyzer import results + + +def ParseArgs() -> argparse.Namespace: + parser = argparse.ArgumentParser( + description=('Script to check and analysis slowness for web tests')) + parser.add_argument( + '--project', + default='chrome-unexpected-pass-data', + help=('The billing project to use for BigQuery queries. ' + 'Must have access to the ResultDB BQ tables, e.g. ' + '"luci-resultdb.chromium.web_tests_ci_test_results".')) + parser.add_argument( + '--slow-result-ratio-threshold', + default=0.9, + type=float, + help="A float denoting what fraction of results need to be slow" + " for a test to be considered slow. Both thresholds must be" + " hit for a test to be considered slow.") + parser.add_argument( + '--timeout-result-threshold', + default=5, + help="An int denoting the number of timeout results necessary" + " for a test to be considered slow. Both thresholds must " + "be hit for a test to be considered slow.") + parser.add_argument('--sample-period', + type=int, + default=1, + choices=range(1, 30), + help='The number of days to sample data from, ' + 'must be within 30 days.') + parser.add_argument( + '--test-path', + help='The test path that contains the tests to do slowness analysis.') + args = parser.parse_args() + return args + + +def main() -> int: + args = ParseArgs() + + querier_instance = queries.Querier(args.sample_period, args.project) + query_results = (querier_instance.get_overall_slowness_ci_tests( + args.test_path)) + results_processor = results.ResultProcessor() + aggregated_results = results_processor.aggregate_test_slowness_results( + query_results) + + slowness_analyzer = analyzer.SlowTestAnalyzer( + args.slow_result_ratio_threshold, args.timeout_result_threshold) + for test_name, test_data in aggregated_results.items(): + test_analysis_result = slowness_analyzer.run_analyzer(test_data) + if test_analysis_result.is_analyzed: + result_string = '' + result_string += '\nTest name: %s\n' % test_name + result_string += test_analysis_result.analysis_result + print(result_string) + + return 0
diff --git a/third_party/blink/tools/run_slow_test_analyzer.py b/third_party/blink/tools/run_slow_test_analyzer.py new file mode 100755 index 0000000..e4d17287 --- /dev/null +++ b/third_party/blink/tools/run_slow_test_analyzer.py
@@ -0,0 +1,12 @@ +#!/usr/bin/env vpython3 +# 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. + +from blinkpy.web_tests.fuzzy_diff_analyzer import slow_test_analyzer + +import sys + +if __name__ == '__main__': + rc = slow_test_analyzer.main() + sys.exit(rc)
diff --git a/third_party/blink/web_tests/ChromeTestExpectations b/third_party/blink/web_tests/ChromeTestExpectations index e69543fd..861265e0 100644 --- a/third_party/blink/web_tests/ChromeTestExpectations +++ b/third_party/blink/web_tests/ChromeTestExpectations
@@ -583,6 +583,9 @@ crbug.com/1507050 external/wpt/html/semantics/scripting-1/the-script-element/moving-between-documents/after-prepare-iframe-success-inline-classic.html [ Failure Pass ] # ====== New tests from wpt-importer added here ====== +crbug.com/626703 external/wpt/css/css-page/page-orientation-on-landscape-001-print.html [ Failure ] +crbug.com/626703 external/wpt/css/css-page/page-orientation-on-portrait-001-print.html [ Failure ] +crbug.com/626703 external/wpt/css/css-page/page-orientation-on-square-001-print.html [ Failure ] crbug.com/626703 external/wpt/css/css-backgrounds/table-cell-background-local-003.html [ Failure ] crbug.com/626703 external/wpt/css/css-scroll-snap-2/snapchanging/snapchanging-after-layout-change.tentative.html [ Crash ] crbug.com/626703 external/wpt/dom/events/scrolling/overscroll-event-fired-to-scrolled-element.html [ Crash ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index 4abbaf5..d0685e8 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -2639,6 +2639,9 @@ crbug.com/626703 external/wpt/editing/other/insertparagraph-in-editing-host-cannot-have-div.tentative.html* [ Failure ] # ====== New tests from wpt-importer added here ====== +crbug.com/626703 external/wpt/css/css-page/page-orientation-on-landscape-001-print.html [ Failure ] +crbug.com/626703 external/wpt/css/css-page/page-orientation-on-portrait-001-print.html [ Failure ] +crbug.com/626703 external/wpt/css/css-page/page-orientation-on-square-001-print.html [ Failure ] crbug.com/626703 [ Mac ] external/wpt/css/css-contain/content-visibility/content-visibility-with-popover-top-layer-005.html [ Failure ] crbug.com/626703 [ Mac ] external/wpt/css/css-contain/content-visibility/content-visibility-with-top-layer-005.html [ Failure ] crbug.com/626703 [ Mac13-arm64 ] external/wpt/long-animation-frame/tentative/loaf-source-location-redirect.html [ Skip Timeout ] @@ -6508,6 +6511,7 @@ external/wpt/https-upgrades/tentative/http-redirecting-to-http.https.sub.html [ Timeout ] external/wpt/https-upgrades/tentative/http-redirecting-to-http-redirecting-to-http.https.sub.html [ Timeout ] external/wpt/https-upgrades/tentative/http-redirecting-to-https.https.sub.html [ Timeout ] +external/wpt/https-upgrades/tentative/referrer.https.sub.html [ Timeout ] # Sherrif 2023-06-09 crbug.com/1358175 [ Mac12 ] media/controls/closed-captions-single-track.html [ Failure Pass ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites index 92c8bfc..a77a5e7 100644 --- a/third_party/blink/web_tests/VirtualTestSuites +++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -497,7 +497,7 @@ "bases": ["external/wpt/longtask-timing/shared-renderer"], "args": ["--renderer-process-limit=1", "--disable-threaded-compositing", "--disable-threaded-animation"], - "expires": "Jul 1, 2023" + "expires": "Jul 1, 2024" }, { "prefix": "percent-based-scrolling", @@ -1288,7 +1288,7 @@ "exclusive_tests": "ALL", "args": ["--enable-threaded-compositing", "--disable-auto-wpt-origin-isolation"], - "expires": "Jul 1, 2023" + "expires": "Jul 1, 2024" }, { @@ -1643,7 +1643,7 @@ "--enable-features=LCPMultipleUpdatesPerElement", "--disable-threaded-compositing", "--disable-threaded-animation" ], - "expires": "Jul 1, 2023" + "expires": "Jul 1, 2024" }, { "prefix": "lcp-mouseover-heuristics", @@ -1656,7 +1656,7 @@ "--enable-features=LCPMouseoverHeuristics", "--disable-threaded-compositing", "--disable-threaded-animation" ], - "expires": "Jul 1, 2023" + "expires": "Jul 1, 2024" }, { "prefix": "low-priority-async-script-execution", @@ -2282,7 +2282,7 @@ "bases": ["external/wpt/longtask-timing"], "args": ["--enable-blink-features=LongTaskFromLongAnimationFrame", "--disable-threaded-compositing", "--disable-threaded-animation"], - "expires": "Aug 1, 2023" + "expires": "Aug 1, 2024" }, { "prefix": "netinfo-constant-type",
diff --git a/third_party/blink/web_tests/dom/domparsing/document-render-blocking-no-block.html b/third_party/blink/web_tests/dom/domparsing/document-render-blocking-no-block.html index 6f96379a..9bdc2e11 100644 --- a/third_party/blink/web_tests/dom/domparsing/document-render-blocking-no-block.html +++ b/third_party/blink/web_tests/dom/domparsing/document-render-blocking-no-block.html
@@ -5,7 +5,6 @@ <script src="../../resources/testharnessreport.js"></script> <title>Absence of blocking doesn't defer frames until complete document parsed</title> <script> - assert_implements(document.documentElement.blocking, "no blocking attribute"); function jank(ms) { let start = performance.now(); while (performance.now() < start + ms);
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json index f95577d8..1d076779 100644 --- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json +++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -19509,6 +19509,69 @@ {} ] ], + "page-orientation-on-landscape-001-print.html": [ + "6832a5537d96aed1b37ec72e18ef6aa102646471", + [ + null, + [ + [ + "/css/css-page/page-orientation-portrait-ref.html", + "==" + ] + ], + { + "page_ranges": { + "/css/css-page/page-orientation-on-landscape-001-print.html": [ + [ + 2 + ] + ] + } + } + ] + ], + "page-orientation-on-portrait-001-print.html": [ + "5ab3e1edfd1a260c8fa9c516d1357ed3a4238147", + [ + null, + [ + [ + "/css/css-page/page-orientation-landscape-ref.html", + "==" + ] + ], + { + "page_ranges": { + "/css/css-page/page-orientation-on-portrait-001-print.html": [ + [ + 2 + ] + ] + } + } + ] + ], + "page-orientation-on-square-001-print.html": [ + "06e4f00d3c43fed651f958d6ccf578e4ca717f99", + [ + null, + [ + [ + "/css/css-page/page-orientation-square-ref.html", + "==" + ] + ], + { + "page_ranges": { + "/css/css-page/page-orientation-on-square-001-print.html": [ + [ + 2 + ] + ] + } + } + ] + ], "page-rule-specificity-001-print.html": [ "dc28ad75db381a3297080bd867397a0f51a30220", [ @@ -105014,6 +105077,19 @@ {} ] ], + "at-supports-048.html": [ + "dc0ed9dc425595f7da0066ff8036954d27d65a4c", + [ + null, + [ + [ + "/css/css-conditional/at-supports-048-ref.html", + "==" + ] + ], + {} + ] + ], "at-supports-content-001.html": [ "19c99f504be7766978dc3816d186e7c2dabe126e", [ @@ -120365,7 +120441,7 @@ ] ], "flexbox-align-self-horiz-001-table.xhtml": [ - "1785ca8dfc0a8bf5b52a0e870e4605902b8f2685", + "c168c822e998771c82c87fe82975f2743ba00aa3", [ null, [ @@ -307208,6 +307284,10 @@ "9d1fbaaf47b97cb82dc3003ffd2d46268100774e", [] ], + "at-supports-048-ref.html": [ + "414d9bf6f4c83876f604d2f47bd4cfc462d314bf", + [] + ], "at-supports-selector-detecting-invalid-in-logical-combinations-ref.html": [ "3e1f9b6a78416bd7c74759c5ad859001f101081e", [] @@ -326028,6 +326108,18 @@ "e78cb65df988abff25061a58d96f2ce2525248f7", [] ], + "page-orientation-landscape-ref.html": [ + "caa7542dac9a8ceeccc0a3eb22377c5a85f56777", + [] + ], + "page-orientation-portrait-ref.html": [ + "c545c3163c7a713020465332888ca972cb47c45f", + [] + ], + "page-orientation-square-ref.html": [ + "9eacc3e092124218d4dc7fe44ee68611816b1876", + [] + ], "page-orientation.tentative-expected.txt": [ "b55045e534ae9e59306a50d02c88ab3e9c5d7567", [] @@ -479048,11 +479140,22 @@ ] ], "observable-constructor.window.js": [ - "34776f8fc56b5b2ed69b407db6b66ce18b7792e8", + "d2b597c819054f2b4c186d24f1e908bf5d46d2a2", [ "dom/observable/tentative/observable-constructor.window.html", {} ] + ], + "observable-event-target.any.js": [ + "0f7ace2acc0794a96dae575f33a23a47cb287d8b", + [ + "dom/observable/tentative/observable-event-target.any.html", + {} + ], + [ + "dom/observable/tentative/observable-event-target.any.worker.html", + {} + ] ] } }, @@ -638553,7 +638656,7 @@ ] ], "trusted-types-event-handlers.html": [ - "57f8d3d90c4162949832ec0b48f62c0511007c93", + "9dd7133cbb0b5b75b4bc04b8e05762e7981ad864", [ null, {} @@ -701178,7 +701281,7 @@ }, "response_started": { "response_started.py": [ - "c4e3710c6c1e7f91ba51f8c73fc870342bb064a7", + "c4e9c653a7867f2f0e1061cd940607665aae6320", [ null, {}
diff --git a/third_party/blink/web_tests/external/wpt/css/css-conditional/at-supports-048-ref.html b/third_party/blink/web_tests/external/wpt/css/css-conditional/at-supports-048-ref.html new file mode 100644 index 0000000..414d9bf6 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-conditional/at-supports-048-ref.html
@@ -0,0 +1,23 @@ +<!doctype html> +<html> + <head> + <title>CSS Test (Conditional Rules): Mixing @supports and CSS nesting</title> + <link rel="author" title="Matthieu Dubet" href="m_dubet@apple.com"> + <link rel="help" href="http://www.w3.org/TR/css3-conditional/#at-supports"> + <style> + div { + background:red; + height:100px; + width:100px; + margin: 10px; + border: solid 1px black; + background-color: green; + } + </style> + </head> + + <p>Test passes if there are only green rectangles. + <div class="test-1"></div> + <div class="test-2"></div> + <div class="test-3"></div> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-conditional/at-supports-048.html b/third_party/blink/web_tests/external/wpt/css/css-conditional/at-supports-048.html new file mode 100644 index 0000000..dc0ed9d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-conditional/at-supports-048.html
@@ -0,0 +1,41 @@ +<!doctype html> +<html> + <head> + <title>CSS Test (Conditional Rules): Mixing @supports and CSS nesting</title> + <link rel="author" title="Matthieu Dubet" href="m_dubet@apple.com"> + <link rel="help" href="http://www.w3.org/TR/css3-conditional/#at-supports"> + <link rel="match" href="at-supports-048-ref.html"> + <style> + div { + background:red; + height:100px; + width:100px; + margin: 10px; + border: solid 1px black; + } + .test-1 { + background-color: red; + @supports (background-color: red) { + background-color: green; + } + } + .test-2 { + background-color: green; + @supports (invalid-declaration: foobar) { + background-color: red; + } + } + .test-3 { + background-color: green; + @supports (color: red) { + color: red; + } + } + </style> + </head> + + <p>Test passes if there are only green rectangles. + <div class="test-1"></div> + <div class="test-2"></div> + <div class="test-3"></div> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/flexbox-align-self-horiz-001-table.xhtml b/third_party/blink/web_tests/external/wpt/css/css-flexbox/flexbox-align-self-horiz-001-table.xhtml index 1785ca8d..c168c82 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-flexbox/flexbox-align-self-horiz-001-table.xhtml +++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/flexbox-align-self-horiz-001-table.xhtml
@@ -59,7 +59,6 @@ .stretch { background: pink; align-self: stretch; - display: block; /* XXXdholbert Hackaround for bug 799725 */ } .auto { background: yellow;
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/standalone-axis-size-003.html b/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/standalone-axis-size-003.html new file mode 100644 index 0000000..5c06ee6 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/standalone-axis-size-003.html
@@ -0,0 +1,25 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Grid Test: Subgrid contribution size on standalone axis</title> +<link rel="author" title="Ethan Jimenez" href="mailto:ethavar@microsoft.com"> +<link rel="help" href="https://drafts.csswg.org/css-grid-2/#subgrid-box-alignment"> +<link rel="match" href="../../reference/ref-filled-green-100px-square.xht"> +<style> +.grid { + background: green; + display: inline-grid; + grid-template-rows: 100px; +} +.subgrid { + width: 100px; + display: grid; + grid-template-rows: subgrid; +} +.w200 { width: 200px } +</style> +<p>Test passes if there is a filled green square and <strong>no red</strong>.</p> +<div class="grid"> + <div class="subgrid"> + <div class="w200"></div> + </div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/standalone-axis-size-004.html b/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/standalone-axis-size-004.html new file mode 100644 index 0000000..d69412d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/standalone-axis-size-004.html
@@ -0,0 +1,25 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Grid Test: Subgrid contribution size on standalone axis</title> +<link rel="author" title="Ethan Jimenez" href="mailto:ethavar@microsoft.com"> +<link rel="help" href="https://drafts.csswg.org/css-grid-2/#subgrid-box-alignment"> +<link rel="match" href="../../reference/ref-filled-green-100px-square.xht"> +<style> +.grid { + display: inline-grid; + grid-template: 100px / minmax(auto, 100px); +} +.subgrid { + width: 100%; + display: grid; + background: green; + grid-template-rows: subgrid; +} +.w200 { width: 200px } +</style> +<p>Test passes if there is a filled green square and <strong>no red</strong>.</p> +<div class="grid"> + <div class="subgrid"> + <div class="w200"></div> + </div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/standalone-axis-size-005.html b/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/standalone-axis-size-005.html new file mode 100644 index 0000000..586d26b --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/standalone-axis-size-005.html
@@ -0,0 +1,34 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Grid Test: Subgrid contribution size on standalone axis</title> +<link rel="author" title="Ethan Jimenez" href="mailto:ethavar@microsoft.com"> +<link rel="help" href="https://drafts.csswg.org/css-grid-2/#subgrid-box-alignment"> +<link rel="match" href="../../reference/ref-filled-green-100px-square.xht"> +<style> +.grid { + display: grid; + background: red; + width: max-content; + grid-template-columns: minmax(min-content, max-content); +} +.subgrid { + display: grid; + background: green; + width: min-content; + grid-template-rows: subgrid; +} +.w100 { + display: inline-block; + height: 50px; + width: 100px; +} +</style> +<p>Test passes if there is a filled green square and <strong>no red</strong>.</p> +<div class="grid"> + <div class="subgrid"> + <div style="font-size: 0"> + <div class="w100"></div> + <div class="w100"></div> + </div> + </div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/standalone-axis-size-006.html b/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/standalone-axis-size-006.html new file mode 100644 index 0000000..056f0a4 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-grid/subgrid/standalone-axis-size-006.html
@@ -0,0 +1,34 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Grid Test: Subgrid contribution size on standalone axis</title> +<link rel="author" title="Ethan Jimenez" href="mailto:ethavar@microsoft.com"> +<link rel="help" href="https://drafts.csswg.org/css-grid-2/#subgrid-box-alignment"> +<link rel="match" href="../../reference/ref-filled-green-100px-square.xht"> +<style> +.grid { + display: grid; + background: red; + width: min-content; +} +.subgrid { + display: grid; + background: green; + max-width: 100px; + width: max-content; + grid-template-rows: subgrid; +} +.w100 { + display: inline-block; + height: 50px; + width: 100px; +} +</style> +<p>Test passes if there is a filled green square and <strong>no red</strong>.</p> +<div class="grid"> + <div class="subgrid"> + <div style="font-size: 0"> + <div class="w100"></div> + <div class="w100"></div> + </div> + </div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-page/page-orientation-landscape-ref.html b/third_party/blink/web_tests/external/wpt/css/css-page/page-orientation-landscape-ref.html new file mode 100644 index 0000000..caa7542d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-page/page-orientation-landscape-ref.html
@@ -0,0 +1,27 @@ +<!DOCTYPE html> +<html> + <meta charset="utf-8"> + <link rel="author" title="Jonathan Watt" href="mailto:jwatt@jwatt.org"> + <style> + +@page { + size: landscape; +} +div { + box-sizing: border-box; + width: 4in; + height: 2in; + border-top: none; + border-right: 15px solid orange; + border-bottom: none; + border-left: 15px solid blue; +} +body { + margin: 0; +} + + </style> + <body> + <div></div> + </body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-page/page-orientation-on-landscape-001-print.html b/third_party/blink/web_tests/external/wpt/css/css-page/page-orientation-on-landscape-001-print.html new file mode 100644 index 0000000..6832a553 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-page/page-orientation-on-landscape-001-print.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html> + <meta charset="utf-8"> + <link rel="author" title="Jonathan Watt" href="mailto:jwatt@jwatt.org"> + <link rel="help" href="https://drafts.csswg.org/css-page/#page-orientation-prop"> + <meta name="assert" content="page-orientation rotates landscape page to match portrait ref"> + <link rel="match" href="page-orientation-portrait-ref.html"> + <meta name="reftest-pages" content="2"> + <style> + +@page second-page { + size: landscape; + page-orientation: rotate-right; +} +div:nth-of-type(2) { + page: second-page; + break-before: page; + + box-sizing: border-box; + width: 4in; + height: 2in; + border-top: 15px solid orange; + border-right: none; + border-bottom: 15px solid blue; + border-left: none; +} +body { + margin: 0; +} + + </style> + <body> + <div>Page 1. Not compared. Just bumps testing to page 2.</div> + <div></div> + </body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-page/page-orientation-on-portrait-001-print.html b/third_party/blink/web_tests/external/wpt/css/css-page/page-orientation-on-portrait-001-print.html new file mode 100644 index 0000000..5ab3e1e --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-page/page-orientation-on-portrait-001-print.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html> + <meta charset="utf-8"> + <link rel="author" title="Jonathan Watt" href="mailto:jwatt@jwatt.org"> + <link rel="help" href="https://drafts.csswg.org/css-page/#page-orientation-prop"> + <meta name="assert" content="page-orientation rotates portrait page to match landscape ref"> + <link rel="match" href="page-orientation-landscape-ref.html"> + <meta name="reftest-pages" content="2"> + <style> + +@page second-page { + size: portrait; + page-orientation: rotate-right; +} +div:nth-of-type(2) { + page: second-page; + break-before: page; + + box-sizing: border-box; + width: 2in; + height: 4in; + border-top: 15px solid orange; + border-right: none; + border-bottom: 15px solid blue; + border-left: none; +} +body { + margin: 0; +} + + </style> + <body> + <div>Page 1. Not compared. Just bumps testing to page 2.</div> + <div></div> + </body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-page/page-orientation-on-square-001-print.html b/third_party/blink/web_tests/external/wpt/css/css-page/page-orientation-on-square-001-print.html new file mode 100644 index 0000000..06e4f00d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-page/page-orientation-on-square-001-print.html
@@ -0,0 +1,39 @@ +<!DOCTYPE html> +<html> + <meta charset="utf-8"> + <link rel="author" title="Jonathan Watt" href="mailto:jwatt@jwatt.org"> + <link rel="help" href="https://drafts.csswg.org/css-page/#page-orientation-prop"> + <meta name="assert" content="page-orientation rotates square page"> + <link rel="match" href="page-orientation-square-ref.html"> + <meta name="reftest-pages" content="2"> + <style> + +@page { + size: 3in 3in; + margin: 0.5in; +} +@page second-page { + page-orientation: rotate-right; +} +div:nth-of-type(2) { + page: second-page; + break-before: page; + + box-sizing: border-box; + width: 2in; + height: 2in; + border-top: 15px solid orange; + border-right: none; + border-bottom: 15px solid blue; + border-left: none; +} +body { + margin: 0; +} + + </style> + <body> + <div>Page 1. Not compared. Just bumps testing to page 2.</div> + <div></div> + </body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-page/page-orientation-portrait-ref.html b/third_party/blink/web_tests/external/wpt/css/css-page/page-orientation-portrait-ref.html new file mode 100644 index 0000000..c545c31 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-page/page-orientation-portrait-ref.html
@@ -0,0 +1,27 @@ +<!DOCTYPE html> +<html> + <meta charset="utf-8"> + <link rel="author" title="Jonathan Watt" href="mailto:jwatt@jwatt.org"> + <style> + +@page { + size: portrait; +} +div { + box-sizing: border-box; + width: 2in; + height: 4in; + border-top: none; + border-right: 15px solid orange; + border-bottom: none; + border-left: 15px solid blue; +} +body { + margin: 0; +} + + </style> + <body> + <div></div> + </body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-page/page-orientation-square-ref.html b/third_party/blink/web_tests/external/wpt/css/css-page/page-orientation-square-ref.html new file mode 100644 index 0000000..9eacc3e0 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-page/page-orientation-square-ref.html
@@ -0,0 +1,28 @@ +<!DOCTYPE html> +<html> + <meta charset="utf-8"> + <link rel="author" title="Jonathan Watt" href="mailto:jwatt@jwatt.org"> + <style> + +@page { + size: 3in 3in; + margin: 0.5in; +} +div { + box-sizing: border-box; + width: 2in; + height: 2in; + border-top: none; + border-right: 15px solid orange; + border-bottom: none; + border-left: 15px solid blue; +} +body { + margin: 0; +} + + </style> + <body> + <div></div> + </body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/private-network-access/anchor.tentative.https.window.js b/third_party/blink/web_tests/external/wpt/fetch/private-network-access/anchor.tentative.https.window.js index 8ad99b1e..4e860ad 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/private-network-access/anchor.tentative.https.window.js +++ b/third_party/blink/web_tests/external/wpt/fetch/private-network-access/anchor.tentative.https.window.js
@@ -2,6 +2,7 @@ // META: script=/common/dispatcher/dispatcher.js // META: script=/common/utils.js // META: script=resources/support.sub.js +// META: timeout=long // META: variant=?include=from-local // META: variant=?include=from-private // META: variant=?include=from-public
diff --git a/third_party/blink/web_tests/external/wpt/fetch/private-network-access/anchor.tentative.window.js b/third_party/blink/web_tests/external/wpt/fetch/private-network-access/anchor.tentative.window.js index 60ccbde..cb53865 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/private-network-access/anchor.tentative.window.js +++ b/third_party/blink/web_tests/external/wpt/fetch/private-network-access/anchor.tentative.window.js
@@ -1,6 +1,7 @@ // META: script=/common/dispatcher/dispatcher.js // META: script=/common/utils.js // META: script=resources/support.sub.js +// META: timeout=long // // Spec: https://wicg.github.io/private-network-access/ //
diff --git a/third_party/blink/web_tests/external/wpt/fetch/private-network-access/resources/support.sub.js b/third_party/blink/web_tests/external/wpt/fetch/private-network-access/resources/support.sub.js index 920ded6..69d8f50f 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/private-network-access/resources/support.sub.js +++ b/third_party/blink/web_tests/external/wpt/fetch/private-network-access/resources/support.sub.js
@@ -499,7 +499,7 @@ const result = await Promise.race([ reply, new Promise((resolve) => { - t.step_timeout(() => resolve("timeout"), 3000 /* ms */); + t.step_timeout(() => resolve("timeout"), 10000 /* ms */); }), ]); @@ -526,7 +526,7 @@ const result = await Promise.race([ reply, new Promise((resolve) => { - t.step_timeout(() => resolve("timeout"), 4000 /* ms */); + t.step_timeout(() => resolve("timeout"), 10000 /* ms */); }), ]);
diff --git a/third_party/blink/web_tests/external/wpt/fetch/private-network-access/window-open.tentative.https.window.js b/third_party/blink/web_tests/external/wpt/fetch/private-network-access/window-open.tentative.https.window.js index c91ec235..6793d1f3 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/private-network-access/window-open.tentative.https.window.js +++ b/third_party/blink/web_tests/external/wpt/fetch/private-network-access/window-open.tentative.https.window.js
@@ -2,6 +2,7 @@ // META: script=/common/dispatcher/dispatcher.js // META: script=/common/utils.js // META: script=resources/support.sub.js +// META: timeout=long // META: variant=?include=from-local // META: variant=?include=from-private // META: variant=?include=from-public
diff --git a/third_party/blink/web_tests/external/wpt/fetch/private-network-access/window-open.tentative.window.js b/third_party/blink/web_tests/external/wpt/fetch/private-network-access/window-open.tentative.window.js index 18a0260..5e2313d 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/private-network-access/window-open.tentative.window.js +++ b/third_party/blink/web_tests/external/wpt/fetch/private-network-access/window-open.tentative.window.js
@@ -1,6 +1,7 @@ // META: script=/common/dispatcher/dispatcher.js // META: script=/common/utils.js // META: script=resources/support.sub.js +// META: timeout=long // // Spec: https://wicg.github.io/private-network-access/ //
diff --git a/third_party/blink/web_tests/external/wpt/fledge/tentative/interest-group-passed-to-generate-bid.https.window.js b/third_party/blink/web_tests/external/wpt/fledge/tentative/interest-group-passed-to-generate-bid.https.window.js new file mode 100644 index 0000000..cf46855 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/fledge/tentative/interest-group-passed-to-generate-bid.https.window.js
@@ -0,0 +1,177 @@ +// META: script=/resources/testdriver.js +// META: script=/common/utils.js +// META: script=resources/fledge-util.sub.js +// META: script=/common/subset-tests.js +// META: timeout=long +// META: variant=?1-5 +// META: variant=?6-10 +// META: variant=?11-15 +// META: variant=?16-last + +"use strict;" + +// These tests focus on making sure InterestGroup fields are passed to generateBid(), +// and are normalized if necessary. This test does not check the behaviors of the +// fields. + +const makeTest = ({ + // Test name. + name, + // InterestGroup field name. + fieldName, + // InterestGroup field value, both expected in worklets and acution in the + // auction. If undefined, value will not be set in interestGroup, and will + // be expected to also not be set in the interestGroup passed to generateBid(). + fieldValue, + // Additional values to use in the InterestGroup passed to joinInterestGroup(). + // If it contains a value for the key specified in `fieldName`, that takes + // precedent over `fieldValue`. + interestGroupOverrides = {} +}) => { + subsetTest(promise_test, async test => { + const uuid = generateUuid(test); + + if (!(fieldName in interestGroupOverrides) && fieldValue !== undefined) + interestGroupOverrides[fieldName] = fieldValue; + + let comparison = `deepEquals(interestGroup["${fieldName}"], ${JSON.stringify(fieldValue)})`; + // In the case it's undefined, require value not to be set. + if (fieldValue === undefined) + comparison = `!("${fieldName}" in interestGroup)`; + + // Prefer to use `interestGroupOverrides.owner` if present. Treat it as a URL + // and then convert it to an origin because one test passes in a URL. + let origin = location.origin; + if (interestGroupOverrides.owner) + origin = new URL(interestGroupOverrides.owner).origin; + + interestGroupOverrides.biddingLogicURL = + createBiddingScriptURL( + { origin: origin, + generateBid: + `if (!${comparison}) + throw "Unexpected value: " + JSON.stringify(interestGroup["${fieldName}"]);` + }); + if (origin !== location.origin) { + await joinCrossOriginInterestGroup(test, uuid, origin, interestGroupOverrides); + } else { + await joinInterestGroup(test, uuid, interestGroupOverrides); + } + + await runBasicFledgeTestExpectingWinner(test, uuid, {interestGroupBuyers: [origin]}); + }, name); +}; + +makeTest({ + name: 'InterestGroup.owner.', + fieldName: 'owner', + fieldValue: OTHER_ORIGIN1 +}); + +makeTest({ + name: 'InterestGroup.owner with non-normalized origin.', + fieldName: 'owner', + fieldValue: OTHER_ORIGIN1, + interestGroupOverrides: {seller: ` ${OTHER_ORIGIN1.toUpperCase()} `} +}); + +makeTest({ + name: 'InterestGroup.owner is URL.', + fieldName: 'owner', + fieldValue: OTHER_ORIGIN1, + interestGroupOverrides: {seller: OTHER_ORIGIN1 + "/Foopy"} +}); + +makeTest({ + name: 'InterestGroup.trustedBiddingSignalsURL not set.', + fieldName: 'trustedBiddingSignalsURL', + fieldValue: undefined +}); + +makeTest({ + name: 'InterestGroup.trustedBiddingSignalsURL.', + fieldName: 'trustedBiddingSignalsURL', + fieldValue: `${OTHER_ORIGIN1}${BASE_PATH}this-file-does-not-exist.json`, + interestGroupOverrides: {owner: OTHER_ORIGIN1} +}); + +makeTest({ + name: 'InterestGroup.trustedBiddingSignalsURL with non-normalized value.', + fieldName: 'trustedBiddingSignalsURL', + fieldValue: `${OTHER_ORIGIN1}${BASE_PATH}this-file-does-not-exist.json`, + interestGroupOverrides: { + owner: OTHER_ORIGIN1, + trustedScoringSignalsURL: + `${OTHER_ORIGIN1.toUpperCase()}${BASE_PATH}this-file-does-not-exist.json` + } +}); + +makeTest({ + name: 'InterestGroup.trustedBiddingSignalsKeys not set.', + fieldName: 'trustedBiddingSignalsKeys', + fieldValue: undefined +}); + +makeTest({ + name: 'InterestGroup.name.', + fieldName: 'name', + fieldValue: 'Jim' +}); + +makeTest({ + name: 'InterestGroup.name with unicode characters.', + fieldName: 'name', + fieldValue: '\u2665' +}); + +makeTest({ + name: 'InterestGroup.trustedBiddingSignalsKeys.', + fieldName: 'trustedBiddingSignalsKeys', + fieldValue: ['a', ' b ', 'c', '1', '%20', '3', '\u2665'] +}); + +makeTest({ + name: 'InterestGroup.trustedBiddingSignalsKeys with non-normalized values.', + fieldName: 'trustedBiddingSignalsKeys', + fieldValue: ['1', '2', '3'], + interestGroupOverrides: { trustedBiddingSignalsKeys: [1, 0x2, '3'] } +}); + +makeTest({ + name: 'InterestGroup.trustedBiddingSignalsSlotSizeMode empty.', + fieldName: 'trustedBiddingSignalsSlotSizeMode', + fieldValue: 'none', + interestGroupOverrides: { trustedBiddingSignalsSlotSizeMode: undefined } +}); + +makeTest({ + name: 'InterestGroup.trustedBiddingSignalsSlotSizeMode none.', + fieldName: 'trustedBiddingSignalsSlotSizeMode', + fieldValue: 'none' +}); + +makeTest({ + name: 'InterestGroup.trustedBiddingSignalsSlotSizeMode slot-size.', + fieldName: 'trustedBiddingSignalsSlotSizeMode', + fieldValue: 'slot-size' +}); + +makeTest({ + name: 'InterestGroup.trustedBiddingSignalsSlotSizeMode all-slots-requested-sizes.', + fieldName: 'trustedBiddingSignalsSlotSizeMode', + fieldValue: 'all-slots-requested-sizes' +}); + +makeTest({ + name: 'InterestGroup.trustedBiddingSignalsSlotSizeMode unrecognized value.', + fieldName: 'trustedBiddingSignalsSlotSizeMode', + fieldValue: 'none', + interestGroupOverrides: { trustedBiddingSignalsSlotSizeMode: 'unrecognized value' } +}); + +makeTest({ + name: 'InterestGroup.nonStandardField.', + fieldName: 'nonStandardField', + fieldValue: undefined, + interestGroupOverrides: {nonStandardField: 'This value should not be passed to worklets'} +});
diff --git a/third_party/blink/web_tests/external/wpt/fledge/tentative/resources/bidding-logic.sub.py b/third_party/blink/web_tests/external/wpt/fledge/tentative/resources/bidding-logic.sub.py index c0d6114..707e37f 100644 --- a/third_party/blink/web_tests/external/wpt/fledge/tentative/resources/bidding-logic.sub.py +++ b/third_party/blink/web_tests/external/wpt/fledge/tentative/resources/bidding-logic.sub.py
@@ -1,3 +1,5 @@ +from pathlib import Path + # General bidding logic script. Depending on query parameters, it can # simulate a variety of network errors, and its generateBid() and # reportWin() functions can have arbitrary Javascript code injected @@ -30,9 +32,10 @@ elif error != b"no-allow-fledge": response.headers.set(b"Ad-Auction-Allowed", b"true") - body = b'' if error == b"no-body": - return body + return b'' + + body = (Path(__file__).parent.resolve() / 'worklet-helpers.js').read_text().encode("ASCII") if error != b"no-generateBid": # Use bid query param if present. Otherwise, use a bid of 9. bid = (request.GET.first(b"bid", None) or b"9").decode("ASCII")
diff --git a/third_party/blink/web_tests/external/wpt/fledge/tentative/resources/decision-logic.sub.py b/third_party/blink/web_tests/external/wpt/fledge/tentative/resources/decision-logic.sub.py index 4e1862a..78d459e 100644 --- a/third_party/blink/web_tests/external/wpt/fledge/tentative/resources/decision-logic.sub.py +++ b/third_party/blink/web_tests/external/wpt/fledge/tentative/resources/decision-logic.sub.py
@@ -1,3 +1,5 @@ +from pathlib import Path + # General decision logic script. Depending on query parameters, it can # simulate a variety of network errors, and its scoreAd() and # reportResult() functions can have arbitrary Javascript code injected @@ -30,32 +32,12 @@ elif error != b"no-allow-fledge": response.headers.set(b"Ad-Auction-Allowed", b"true") - body = b'' if error == b"no-body": - return body + return b'' + + body = (Path(__file__).parent.resolve() / 'worklet-helpers.js').read_text().encode("ASCII") if error != b"no-scoreAd": body += b""" - // Comparison function checks if two arguments are the same. - // Not intended for use on anything other than built-in types - // (Arrays, objects, and primitive types). - function deepEquals(a, b) { - if (typeof a !== typeof b) - return false; - if (typeof a !== 'object' || a === null || b === null) - return a === b; - - let aKeys = Object.keys(a); - if (aKeys.length != Object.keys(b).length) - return false; - for (key in aKeys) { - if (a.hasOwnProperty(key) != b.hasOwnProperty(key) || - !deepEquals(a[key], b[key])) { - return false; - } - } - return true; - } - function scoreAd(adMetadata, bid, auctionConfig, trustedScoringSignals, browserSignals, directFromSellerSignals) { // Don't bid on interest group with the wrong uuid. This is to prevent
diff --git a/third_party/blink/web_tests/external/wpt/fledge/tentative/resources/worklet-helpers.js b/third_party/blink/web_tests/external/wpt/fledge/tentative/resources/worklet-helpers.js new file mode 100644 index 0000000..dd3b9a7d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/fledge/tentative/resources/worklet-helpers.js
@@ -0,0 +1,23 @@ +// This file contains helper methods that are appended to the start of bidder +// and seller worklets. + +// Comparison function that checks if two arguments are the same. +// Not intended for use on anything other than built-in types +// (Arrays, objects, and primitive types). +function deepEquals(a, b) { + if (typeof a !== typeof b) + return false; + if (typeof a !== 'object' || a === null || b === null) + return a === b; + + let aKeys = Object.keys(a); + if (aKeys.length != Object.keys(b).length) + return false; + for (key in aKeys) { + if (a.hasOwnProperty(key) != b.hasOwnProperty(key) || + !deepEquals(a[key], b[key])) { + return false; + } + } + return true; +}
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/document-render-blocking-partial.tentative.html b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/document-render-blocking-partial.tentative.html deleted file mode 100644 index 89ab05e..0000000 --- a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/document-render-blocking-partial.tentative.html +++ /dev/null
@@ -1,34 +0,0 @@ -<!DOCTYPE html> - <html blocking=render> - <script src="/resources/testharness.js"></script> - <script src="/resources/testharnessreport.js"></script> - <script src="support/utils.js"></script> - <title>`blocking=render` defers frames until the attribute is set</title> - <script> - assert_implements(document.documentElement.blocking, "no blocking attribute"); - - promise_test(() => { - return new Promise((resolve, reject) => { - requestAnimationFrame(() => { - if (document.getElementById("last")) - reject(); - else - resolve(); - }); - }); - }, "blocking defers frames until removed"); - </script> - </head> - <body> - <div id="first"></div> - <script> - jankMany(100, 10); - document.documentElement.blocking=""; - </script> - <div id="second"></div> - <script> - jankMany(100, 10); - </script> - <div id="last"></div> - </body> -</html>
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/document-render-blocking.tentative.html b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/document-render-blocking.tentative.html deleted file mode 100644 index 909029b..0000000 --- a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/document-render-blocking.tentative.html +++ /dev/null
@@ -1,33 +0,0 @@ -<!DOCTYPE html> - <html blocking=render> - <script src="/resources/testharness.js"></script> - <script src="/resources/testharnessreport.js"></script> - <script src="support/utils.js"></script> - <title>`blocking=render` defers frames until complete document parsed</title> - <script> - assert_implements(document.documentElement.blocking, "no blocking attribute"); - - promise_test(() => { - return new Promise((resolve, reject) => { - requestAnimationFrame(() => { - if (document.getElementById("last")) - resolve(); - else - reject(); - }); - }); - }, "blocking defers frames until full parsing"); - </script> - </head> - <body> - <div id="first"></div> - <script> - jankMany(100, 10); - </script> - <div id="second"></div> - <script> - jankMany(100, 10); - </script> - <div id="last"></div> - </body> -</html>
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-001.tentative.html b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-001.tentative.html new file mode 100644 index 0000000..9624b41a1 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-001.tentative.html
@@ -0,0 +1,28 @@ +<!DOCTYPE html> +<head> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/utils.js"></script> +<title>`link rel=expect` defers frames until href element is parsed</title> + +<link rel=expect href="#last" blocking="render"> +<script> +async_test((t) => { + requestAnimationFrame(() => { + t.step(() => assert_true(!!document.getElementById("last"))); + t.done(); + }); +}, "blocking defers frames until full parsing"); +</script> +</head> +<body> + <div id="first"></div> + <script> + jankMany(100, 10); + </script> + <div id="second"></div> + <script> + jankMany(100, 10); + </script> + <div id="last"></div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-002.tentative.html b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-002.tentative.html new file mode 100644 index 0000000..ab0fd51 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-002.tentative.html
@@ -0,0 +1,37 @@ +<!DOCTYPE html> +<head> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/utils.js"></script> +<title>Frames starts after href element is parsed before the end</title> + +<link rel=expect href="#third" blocking="render"> +<script> +async_test((t) => { + requestAnimationFrame(() => { + t.step(() => assert_true(!!document.getElementById("third"))); + t.step(() => assert_false(!!document.getElementById("last"))); + t.done(); + }); +}, "blocking defers until needed element is parsed"); +</script> +</head> +<body> + <div id="first"></div> + <script> + jankMany(100, 10); + </script> + <div id="second"></div> + <script> + jankMany(100, 10); + </script> + <div id="third"></div> + <script> + jankMany(100, 10); + </script> + <div id="fourth"></div> + <script> + jankMany(100, 10); + </script> + <div id="last"></div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-003.tentative.html b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-003.tentative.html new file mode 100644 index 0000000..eb3a347 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-003.tentative.html
@@ -0,0 +1,33 @@ +<!DOCTYPE html> +<head> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/utils.js"></script> +<title>Adding link in the head has an effect</title> + +<script> +let link = document.createElement("link"); +link.rel = "expect"; +link.href = "#last"; +link.blocking = "render"; +document.head.appendChild(link) + +async_test((t) => { + requestAnimationFrame(() => { + t.step(() => assert_true(!!document.getElementById("last"))); + t.done(); + }); +}, "adding link in the head defers frames"); +</script> +</head> +<body> + <div id="first"></div> + <script> + jankMany(100, 10); + </script> + <div id="second"></div> + <script> + jankMany(100, 10); + </script> + <div id="last"></div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-004.tentative.html b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-004.tentative.html new file mode 100644 index 0000000..2c50f2d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-004.tentative.html
@@ -0,0 +1,30 @@ +<!DOCTYPE html> +<head> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/utils.js"></script> +<title>Removing link in the head has an effect</title> + +<link id=link rel=expect href="#last" blocking="render"> +<script> +link.remove(); + +async_test((t) => { + requestAnimationFrame(() => { + t.step(() => assert_false(!!document.getElementById("last"))); + t.done(); + }); +}, "removing link in the head makes it no longer blocking"); +</script> +</head> +<body> + <div id="first"></div> + <script> + jankMany(100, 10); + </script> + <div id="second"></div> + <script> + jankMany(100, 10); + </script> + <div id="last"></div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-005.tentative.html b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-005.tentative.html new file mode 100644 index 0000000..04cdab4 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-005.tentative.html
@@ -0,0 +1,30 @@ +<!DOCTYPE html> +<head> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/utils.js"></script> +<title>Removing blocking attr in the head has an effect</title> + +<link id=link rel=expect href="#last" blocking="render"> +<script> +link.blocking = "" + +async_test((t) => { + requestAnimationFrame(() => { + t.step(() => assert_false(!!document.getElementById("last"))); + t.done(); + }); +}, "removing 'blocking' makes it no longer blocking"); +</script> +</head> +<body> + <div id="first"></div> + <script> + jankMany(100, 10); + </script> + <div id="second"></div> + <script> + jankMany(100, 10); + </script> + <div id="last"></div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-006.tentative.html b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-006.tentative.html new file mode 100644 index 0000000..1c9da25 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-006.tentative.html
@@ -0,0 +1,30 @@ +<!DOCTYPE html> +<head> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/utils.js"></script> +<title>Adding blocking attr in the head has an effect</title> + +<link id=link rel=expect href="#last"> +<script> +link.blocking = "render" + +async_test((t) => { + requestAnimationFrame(() => { + t.step(() => assert_true(!!document.getElementById("last"))); + t.done(); + }); +}, "adding 'blocking=render' in the head makes it blocking"); +</script> +</head> +<body> + <div id="first"></div> + <script> + jankMany(100, 10); + </script> + <div id="second"></div> + <script> + jankMany(100, 10); + </script> + <div id="last"></div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-007.tentative.html b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-007.tentative.html new file mode 100644 index 0000000..df8f9ae3 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-007.tentative.html
@@ -0,0 +1,28 @@ +<!DOCTYPE html> +<head> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/utils.js"></script> +<title>Media attribute that doesn't match makes the link not apply</title> + +<link rel=expect href="#last" blocking="render" media="(max-width: 10px)"> +<script> +async_test((t) => { + requestAnimationFrame(() => { + t.step(() => assert_false(!!document.getElementById("last"))); + t.done(); + }); +}, "link with non-matching media has no effect"); +</script> +</head> +<body> + <div id="first"></div> + <script> + jankMany(100, 10); + </script> + <div id="second"></div> + <script> + jankMany(100, 10); + </script> + <div id="last"></div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-008.tentative.html b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-008.tentative.html new file mode 100644 index 0000000..c2458a0b --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-008.tentative.html
@@ -0,0 +1,30 @@ +<!DOCTYPE html> +<head> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/utils.js"></script> +<title>Media attribute changes in the head to apply</title> + +<link id=link rel=expect href="#last" blocking="render" media="(max-width: 10px)"> +<script> +link.media = "(min-width: 10px)"; + +async_test((t) => { + requestAnimationFrame(() => { + t.step(() => assert_true(!!document.getElementById("last"))); + t.done(); + }); +}, "changing media to matching causes link to have an effect"); +</script> +</head> +<body> + <div id="first"></div> + <script> + jankMany(100, 10); + </script> + <div id="second"></div> + <script> + jankMany(100, 10); + </script> + <div id="last"></div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-009.tentative.html b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-009.tentative.html new file mode 100644 index 0000000..d765ac8a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-009.tentative.html
@@ -0,0 +1,30 @@ +<!DOCTYPE html> +<head> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/utils.js"></script> +<title>Media attribute changes in the head to not apply</title> + +<link id=link rel=expect href="#last" blocking="render" media="(min-width: 10px)"> +<script> +link.media = "(max-width: 10px)"; + +async_test((t) => { + requestAnimationFrame(() => { + t.step(() => assert_false(!!document.getElementById("last"))); + t.done(); + }); +}, "changing media to non-matching makes it non blocking"); +</script> +</head> +<body> + <div id="first"></div> + <script> + jankMany(100, 10); + </script> + <div id="second"></div> + <script> + jankMany(100, 10); + </script> + <div id="last"></div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-010.tentative.html b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-010.tentative.html new file mode 100644 index 0000000..7ef6a1b --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-010.tentative.html
@@ -0,0 +1,30 @@ +<!DOCTYPE html> +<head> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/utils.js"></script> +<title>Rel attribute changes in the head to not apply</title> + +<link id=link rel=expect href="#last" blocking="render"> +<script> +link.rel = "stylesheet"; + +async_test((t) => { + requestAnimationFrame(() => { + t.step(() => assert_false(!!document.getElementById("last"))); + t.done(); + }); +}, "changing rel to non-expect makes it non blocking"); +</script> +</head> +<body> + <div id="first"></div> + <script> + jankMany(100, 10); + </script> + <div id="second"></div> + <script> + jankMany(100, 10); + </script> + <div id="last"></div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-011.tentative.html b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-011.tentative.html new file mode 100644 index 0000000..31df9b0 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-011.tentative.html
@@ -0,0 +1,30 @@ +<!DOCTYPE html> +<head> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/utils.js"></script> +<title>Rel attribute changes in the head to apply</title> + +<link id=link rel=stylesheet href="#last" blocking="render"> +<script> +link.rel = "expect"; + +async_test((t) => { + requestAnimationFrame(() => { + t.step(() => assert_true(!!document.getElementById("last"))); + t.done(); + }); +}, "changing rel to expect in the head causes it to be blocking"); +</script> +</head> +<body> + <div id="first"></div> + <script> + jankMany(100, 10); + </script> + <div id="second"></div> + <script> + jankMany(100, 10); + </script> + <div id="last"></div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-012.tentative.html b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-012.tentative.html new file mode 100644 index 0000000..8f2594d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-012.tentative.html
@@ -0,0 +1,30 @@ +<!DOCTYPE html> +<head> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/utils.js"></script> +<title>Href attribute changes in the head to apply</title> + +<link id=link rel=expect href="" blocking="render"> +<script> +link.href = "#last"; + +async_test((t) => { + requestAnimationFrame(() => { + t.step(() => assert_true(!!document.getElementById("last"))); + t.done(); + }); +}, "adding href in the head makes it blocking"); +</script> +</head> +<body> + <div id="first"></div> + <script> + jankMany(100, 10); + </script> + <div id="second"></div> + <script> + jankMany(100, 10); + </script> + <div id="last"></div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-013.tentative.html b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-013.tentative.html new file mode 100644 index 0000000..9d65bd9 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-013.tentative.html
@@ -0,0 +1,30 @@ +<!DOCTYPE html> +<head> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/utils.js"></script> +<title>Href attribute changes in the head to not apply</title> + +<link id=link rel=expect href="#last" blocking="render"> +<script> +link.href = ""; + +async_test((t) => { + requestAnimationFrame(() => { + t.step(() => assert_false(!!document.getElementById("last"))); + t.done(); + }); +}, "removing href makes it no longer blocking"); +</script> +</head> +<body> + <div id="first"></div> + <script> + jankMany(100, 10); + </script> + <div id="second"></div> + <script> + jankMany(100, 10); + </script> + <div id="last"></div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-014.tentative.html b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-014.tentative.html new file mode 100644 index 0000000..d042b96b --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-014.tentative.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<head> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/utils.js"></script> +<title>Blocking link added in the body has no effect</title> + +<script> +async_test((t) => { + requestAnimationFrame(() => { + t.step(() => assert_false(!!document.getElementById("last"))); + t.done(); + }); +}, "link in the body has no effect"); +</script> +</head> +<body> +<link rel=expect href="#last" blocking="render"> +<script> +let link = document.createElement("link"); +link.rel = "rel"; +link.href = "#last"; +link.blocking = "render"; +document.head.appendChild(link); +</script> + + <div id="first"></div> + <script> + jankMany(100, 10); + </script> + <div id="second"></div> + <script> + jankMany(100, 10); + </script> + <div id="last"></div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-015.tentative.html b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-015.tentative.html new file mode 100644 index 0000000..f7ac0b1 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-015.tentative.html
@@ -0,0 +1,32 @@ +<!DOCTYPE html> +<head> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/utils.js"></script> +<title>Blocking link removed in the body has an effect</title> + +<link id=link rel=expect href="#last" blocking="render"> +<script> +async_test((t) => { + requestAnimationFrame(() => { + t.step(() => assert_false(!!document.getElementById("last"))); + t.done(); + }); +}, "removing link the body makes it non blocking"); +</script> +</head> +<body> +<script> +link.remove(); +</script> + + <div id="first"></div> + <script> + jankMany(100, 10); + </script> + <div id="second"></div> + <script> + jankMany(100, 10); + </script> + <div id="last"></div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-016.tentative.html b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-016.tentative.html new file mode 100644 index 0000000..d32a046 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-016.tentative.html
@@ -0,0 +1,32 @@ +<!DOCTYPE html> +<head> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/utils.js"></script> +<title>Removing blocking attr in the body has an effect</title> + +<link id=link rel=expect href="#last" blocking="render"> +<script> +async_test((t) => { + requestAnimationFrame(() => { + t.step(() => assert_false(!!document.getElementById("last"))); + t.done(); + }); +}, "removing 'blocking' in the body makes it non blocking"); +</script> +</head> +<body> +<script> +link.blocking = ""; +</script> + + <div id="first"></div> + <script> + jankMany(100, 10); + </script> + <div id="second"></div> + <script> + jankMany(100, 10); + </script> + <div id="last"></div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-017.tentative.html b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-017.tentative.html new file mode 100644 index 0000000..d3a6046 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-017.tentative.html
@@ -0,0 +1,31 @@ +<!DOCTYPE html> +<head> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/utils.js"></script> +<title>Adding blocking attr in the body has no effect</title> + +<link id=link rel=expect href="#last"> +<script> +async_test((t) => { + requestAnimationFrame(() => { + t.step(() => assert_false(!!document.getElementById("last"))); + t.done(); + }); +}, "adding 'blocking=render' in the body has no effect"); +</script> +</head> +<body> +<script> +link.blocking = "render" +</script> + <div id="first"></div> + <script> + jankMany(100, 10); + </script> + <div id="second"></div> + <script> + jankMany(100, 10); + </script> + <div id="last"></div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-018.tentative.html b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-018.tentative.html new file mode 100644 index 0000000..0d74022 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-018.tentative.html
@@ -0,0 +1,32 @@ +<!DOCTYPE html> +<head> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/utils.js"></script> +<title>Media attribute changes in the body to apply, but has no effect</title> + +<link id=link rel=expect href="#last" blocking="render" media="(max-width: 10px)"> +<script> +async_test((t) => { + requestAnimationFrame(() => { + t.step(() => assert_false(!!document.getElementById("last"))); + t.done(); + }); +}, "changing media to matching in the body has no effect"); +</script> +</head> +<body> +<script> +link.media = "(min-width: 10px)"; +</script> + + <div id="first"></div> + <script> + jankMany(100, 10); + </script> + <div id="second"></div> + <script> + jankMany(100, 10); + </script> + <div id="last"></div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-019.tentative.html b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-019.tentative.html new file mode 100644 index 0000000..fea9e3a2 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-019.tentative.html
@@ -0,0 +1,32 @@ +<!DOCTYPE html> +<head> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/utils.js"></script> +<title>Media attribute changes in the body to not apply</title> + +<link id=link rel=expect href="#last" blocking="render" media="(min-width: 10px)"> +<script> +async_test((t) => { + requestAnimationFrame(() => { + t.step(() => assert_false(!!document.getElementById("last"))); + t.done(); + }); +}, "changing media to non-matching in the body makes it non blocking"); +</script> +</head> +<body> +<script> +link.media = "(max-width: 10px)"; +</script> + + <div id="first"></div> + <script> + jankMany(100, 10); + </script> + <div id="second"></div> + <script> + jankMany(100, 10); + </script> + <div id="last"></div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-020.tentative.html b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-020.tentative.html new file mode 100644 index 0000000..7fc0fe1 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-020.tentative.html
@@ -0,0 +1,31 @@ +<!DOCTYPE html> +<head> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/utils.js"></script> +<title>Rel attribute changes in the body to not apply</title> + +<link id=link rel=expect href="#last" blocking="render"> +<script> +async_test((t) => { + requestAnimationFrame(() => { + t.step(() => assert_false(!!document.getElementById("last"))); + t.done(); + }); +}, "changing rel to non-expect in the body makes it non blocking"); +</script> +</head> +<body> +<script> +link.rel = "stylesheet"; +</script> + <div id="first"></div> + <script> + jankMany(100, 10); + </script> + <div id="second"></div> + <script> + jankMany(100, 10); + </script> + <div id="last"></div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-021.tentative.html b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-021.tentative.html new file mode 100644 index 0000000..29430349 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-021.tentative.html
@@ -0,0 +1,35 @@ +<!DOCTYPE html> +<head> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/utils.js"></script> +<title>Rel attribute changes in the body to apply, but has no effect</title> + +<link id=link rel=stylesheet href="#last" blocking="render"> +<script> +async_test((t) => { + requestAnimationFrame(() => { + t.step(() => assert_false(!!document.getElementById("last"))); + t.done(); + }); +}, "changing rel to expect in the body has no effect"); +</script> +</head> +<body> +<script> +link.rel = "expect"; +</script> + <div id="first"></div> + <script> + jankMany(100, 10); + </script> + <div id="second"></div> + <script> + jankMany(100, 10); + </script> + <div id="third"></div> + <script> + jankMany(100, 10); + </script> + <div id="last"></div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-022.tentative.html b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-022.tentative.html new file mode 100644 index 0000000..6548c9e --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-022.tentative.html
@@ -0,0 +1,32 @@ +<!DOCTYPE html> +<head> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/utils.js"></script> +<title>Href attribute changes in the body to apply, but has no effect</title> + +<link id=link rel=expect href="" blocking="render"> +<script> +async_test((t) => { + requestAnimationFrame(() => { + t.step(() => assert_false(!!document.getElementById("last"))); + t.done(); + }); +}, "adding href in the body has no effect"); +</script> +</head> +<body> +<script> +link.href = "#last"; +</script> + + <div id="first"></div> + <script> + jankMany(100, 10); + </script> + <div id="second"></div> + <script> + jankMany(100, 10); + </script> + <div id="last"></div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-023.tentative.html b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-023.tentative.html new file mode 100644 index 0000000..c3661bc --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-023.tentative.html
@@ -0,0 +1,31 @@ +<!DOCTYPE html> +<head> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/utils.js"></script> +<title>Href attribute changes in the body to not apply</title> + +<link id=link rel=expect href="#last" blocking="render"> +<script> +async_test((t) => { + requestAnimationFrame(() => { + t.step(() => assert_false(!!document.getElementById("last"))); + t.done(); + }); +}, "removing href in the body makes it non blocking"); +</script> +</head> +<body> +<script> +link.href = ""; +</script> + <div id="first"></div> + <script> + jankMany(100, 10); + </script> + <div id="second"></div> + <script> + jankMany(100, 10); + </script> + <div id="last"></div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-024.tentative.html b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-024.tentative.html new file mode 100644 index 0000000..c98022cf --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-024.tentative.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<head> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/utils.js"></script> +<title>Unknown href causes the whole document to be blocked</title> + +<link rel=expect href="#unknown" blocking="render"> +<script> +async_test((t) => { + requestAnimationFrame(() => { + t.step(() => assert_true(!!document.getElementById("last"))); + t.done(); + }); +}, "unknown href causes the whole document to be blocked"); +</script> +</head> +<body> + <div id="first"></div> + <script> + jankMany(100, 10); + </script> + <div id="second"></div> + <script> + jankMany(100, 10); + </script> + <div id="third"></div> + <script> + jankMany(100, 10); + </script> + <div id="fourth"></div> + <script> + jankMany(100, 10); + </script> + <div id="last"></div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-025.tentative.html b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-025.tentative.html new file mode 100644 index 0000000..29868b9 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-025.tentative.html
@@ -0,0 +1,38 @@ +<!DOCTYPE html> +<head> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/utils.js"></script> +<title>Adding an id to parsed element satisfies render block</title> + +<link rel=expect href="#first" blocking="render"> +<script> +async_test((t) => { + requestAnimationFrame(() => { + t.step(() => assert_true(!!document.getElementById("first"))); + t.step(() => assert_false(!!document.getElementById("last"))); + t.done(); + }); +}, "adding an id in the body satisfies render block"); +</script> +</head> +<body> + <div id="willbefirst"></div> + <script> + willbefirst.id = "first"; + jankMany(100, 10); + </script> + <div id="second"></div> + <script> + jankMany(100, 10); + </script> + <div id="third"></div> + <script> + jankMany(100, 10); + </script> + <div id="fourth"></div> + <script> + jankMany(100, 10); + </script> + <div id="last"></div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-026.tentative.html b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-026.tentative.html new file mode 100644 index 0000000..dc23211b --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-026.tentative.html
@@ -0,0 +1,38 @@ +<!DOCTYPE html> +<head> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/utils.js"></script> +<title>Removing id keeps render block satisfied</title> + +<link rel=expect href="#first" blocking="render"> +<script> +async_test((t) => { + requestAnimationFrame(() => { + t.step(() => assert_true(!!document.getElementById("wasfirst"))); + t.step(() => assert_false(!!document.getElementById("last"))); + t.done(); + }); +}, "removing id after it was renderer keeps render block satisfied"); +</script> +</head> +<body> + <div id="first"></div> + <script> + first.id = "wasfirst"; + jankMany(100, 10); + </script> + <div id="second"></div> + <script> + jankMany(100, 10); + </script> + <div id="third"></div> + <script> + jankMany(100, 10); + </script> + <div id="fourth"></div> + <script> + jankMany(100, 10); + </script> + <div id="last"></div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-027.tentative.html b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-027.tentative.html new file mode 100644 index 0000000..5b8a5eb2 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-027.tentative.html
@@ -0,0 +1,38 @@ +<!DOCTYPE html> +<head> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/utils.js"></script> +<title>Unknown href causes the whole document to be blocked</title> + +<link id=link rel=expect href="#unknown" blocking="render"> +<script> +link.href = "#stillunknown"; + +async_test((t) => { + requestAnimationFrame(() => { + t.step(() => assert_true(!!document.getElementById("last"))); + t.done(); + }); +}, "unknown href causes the whole document to be blocked (with href changes!)"); +</script> +</head> +<body> + <div id="notfirst"></div> + <script> + jankMany(100, 10); + </script> + <div id="second"></div> + <script> + jankMany(100, 10); + </script> + <div id="third"></div> + <script> + jankMany(100, 10); + </script> + <div id="fourth"></div> + <script> + jankMany(100, 10); + </script> + <div id="last"></div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-028.tentative.html b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-028.tentative.html new file mode 100644 index 0000000..57ba3d6 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/element-render-blocking-028.tentative.html
@@ -0,0 +1,48 @@ +<!DOCTYPE html> +<head> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/utils.js"></script> +<title>Multiple links and all but one removed</title> + +<link rel=expect href="#third" blocking="render"> +<link id=one rel=expect href="#third" blocking="render"> +<link id=two rel=expect href="#third" blocking="render"> +<link id=three rel=expect href="#third" blocking="render"> +<link id=four rel=expect href="#third" blocking="render"> +<script> +async_test((t) => { + requestAnimationFrame(() => { + t.step(() => assert_true(!!document.getElementById("third"))); + t.step(() => assert_false(!!document.getElementById("last"))); + t.done(); + }); +}, "removing some links but not all keeps at least the matching link blocking"); + +one.remove(); +two.remove(); +</script> +</head> +<body> +<script> +three.remove(); +four.remove(); +</script> + <div id="first"></div> + <script> + jankMany(100, 10); + </script> + <div id="second"></div> + <script> + jankMany(100, 10); + </script> + <div id="third"></div> + <script> + jankMany(100, 10); + </script> + <div id="fourth"></div> + <script> + jankMany(100, 10); + </script> + <div id="last"></div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/https-upgrades/resources/pass-with-referrer.html b/third_party/blink/web_tests/external/wpt/https-upgrades/resources/pass-with-referrer.html new file mode 100644 index 0000000..be978c1 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/https-upgrades/resources/pass-with-referrer.html
@@ -0,0 +1,13 @@ +<!DOCTYPE html> +<html> + <body> + <script> + window.onload = (event) => { + window.opener.postMessage({ + 'pass': true, + 'referrer': document.referrer}, + '*'); + }; + </script> + </body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/https-upgrades/tentative/referrer.https.sub.html b/third_party/blink/web_tests/external/wpt/https-upgrades/tentative/referrer.https.sub.html new file mode 100644 index 0000000..3cd83ba --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/https-upgrades/tentative/referrer.https.sub.html
@@ -0,0 +1,29 @@ +<!DOCTYPE html> +<html> + <head> + <title>HTTPS Upgrades: Upgrade.</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="/common/get-host-info.sub.js"></script> + + <meta name="referrer" content="no-referrer-when-downgrade" /> + + </head> + <body> + <script> + setup({ single_test: true }); + // When the referrer policy is no-referrer-when-downgrade, HTTPS upgrades should not drop + // the referrer upon navigating to an HTTP URL if the upgrade is successful. + + // HTTPS upgrades don't change custom ports, so this will load correctly if an HTTPS upgrade is performed, + // and will fail to load otherwise (since the port will be wrong for http). + var url = new URL("http://{{host}}:{{ports[https][0]}}/https-upgrades/resources/pass-with-referrer.html") + window.onmessage = function(event) { + if (event.data['pass'] && event.data['referrer'] == document.location.href) { + done(); + } + } + win = window.open(url) + </script> + </body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/webauthn/createcredential-hints.https.html b/third_party/blink/web_tests/external/wpt/webauthn/createcredential-hints.https.html new file mode 100644 index 0000000..a662bce --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/webauthn/createcredential-hints.https.html
@@ -0,0 +1,38 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>WebAuthn createWithHints</title> +<meta name="timeout" content="long"> +<link rel="help" href="https://w3c.github.io/webauthn/#sctn-public-key-easy"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="helpers.js"></script> +<script src="resources/utils.js"></script> +<script> +function testCreateWithHints() { + "use strict"; + + // The 'hints' parameter affects UI, which cannot be tested with WPTs. + // However, we can check that unknown values are ignored, as they + // should be, and don't trigger an error. + standardSetup(function() { + promise_test(async t => { + return createCredential({ + options: { + publicKey: { + hints: ["not-a-defined-value"], + }, + }, + }); + }); + }); +} + +testCreateWithHints(); +</script> +</head> +<body></body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/webauthn/getcredential-hints.https.html b/third_party/blink/web_tests/external/wpt/webauthn/getcredential-hints.https.html new file mode 100644 index 0000000..45f6e6b --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/webauthn/getcredential-hints.https.html
@@ -0,0 +1,24 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>navigator.credentials.get() with hints</title> +<meta name="timeout" content="long"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src=helpers.js></script> +<body></body> +<script> +standardSetup(async function() { + "use strict"; + + const credPromise = createCredential(); + + // The 'hints' parameter affects UI, which cannot be tested with WPTs. + // However, we can check that unknown values are ignored, as they + // should be, and don't trigger an error. + new GetCredentialsTest("options.publicKey.hints", ["not-a-defined-value"]) + .addCredential(credPromise) + .runTest("navigator.credentials.get with hints"); +}, {}); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/network/response_started/response_started.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/network/response_started/response_started.py index c4e3710..c4e9c65 100644 --- a/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/network/response_started/response_started.py +++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/network/response_started/response_started.py
@@ -220,11 +220,11 @@ events = network_events[RESPONSE_STARTED_EVENT] on_response_started = wait_for_event(RESPONSE_STARTED_EVENT) - - # Note that here we explicitly do not navigate to the auth_url and instead - # simply do a fetch, because otherwise Firefox fails to cleanly cancel the - # authentication prompt on test teardown. - asyncio.ensure_future(fetch(auth_url, context=new_tab, method="GET")) + await bidi_session.browsing_context.navigate( + context=new_tab["context"], + url=auth_url, + wait="none", + ) await wait_for_future_safe(on_response_started)
diff --git a/third_party/blink/web_tests/fast/canvas/reset-after-flush-expected.html b/third_party/blink/web_tests/fast/canvas/reset-after-flush-expected.html new file mode 100644 index 0000000..4bca99e --- /dev/null +++ b/third_party/blink/web_tests/fast/canvas/reset-after-flush-expected.html
@@ -0,0 +1,11 @@ +<!DOCTYPE html> +<p>Resetting after flush shouldn't preserve previous drawing.</p> +<canvas id="canvas" width="100" height="100"></canvas> +<script> + +const canvas = document.getElementById('canvas'); +const ctx = canvas.getContext('2d'); + +ctx.fillStyle = 'blue'; +ctx.fillRect(32, 0, 16, 16); +</script>
diff --git a/third_party/blink/web_tests/fast/canvas/reset-after-flush.html b/third_party/blink/web_tests/fast/canvas/reset-after-flush.html new file mode 100644 index 0000000..ee0eae4 --- /dev/null +++ b/third_party/blink/web_tests/fast/canvas/reset-after-flush.html
@@ -0,0 +1,18 @@ +<!DOCTYPE html> +<p>Resetting after flush shouldn't preserve previous drawing.</p> +<canvas id="canvas" width="100" height="100"></canvas> +<script> + +const canvas = document.getElementById('canvas'); +const ctx = canvas.getContext('2d'); + +ctx.fillStyle = 'red'; +ctx.fillRect(0, 0, 16, 16); + +canvas.toDataURL(); // Forces a flush. + +ctx.reset(); + +ctx.fillStyle = 'blue'; +ctx.fillRect(32, 0, 16, 16); +</script>
diff --git a/third_party/blink/web_tests/fast/scrolling/user-scroll-device-emulation.html b/third_party/blink/web_tests/fast/scrolling/user-scroll-device-emulation.html index 815fb8a..e3a1598 100644 --- a/third_party/blink/web_tests/fast/scrolling/user-scroll-device-emulation.html +++ b/third_party/blink/web_tests/fast/scrolling/user-scroll-device-emulation.html
@@ -17,6 +17,8 @@ internals.setDeviceEmulationScale(scale); promise_test(async (t) => { + await waitForCompositorCommit(); + const bottombox = document.getElementById("bottombox"); const topbox = document.getElementById("topbox");
diff --git a/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt b/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt index 5c89ce6..870b397d 100644 --- a/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt +++ b/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt
@@ -677,7 +677,6 @@ property size property width html element html - property blocking property version html element i html element iframe
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt index e4fadf5c..9581d62 100644 --- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt +++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -4075,10 +4075,8 @@ setter align interface HTMLHtmlElement : HTMLElement attribute @@toStringTag - getter blocking getter version method constructor - setter blocking setter version interface HTMLIFrameElement : HTMLElement attribute @@toStringTag
diff --git a/third_party/catapult b/third_party/catapult index 396204c..2298e63 160000 --- a/third_party/catapult +++ b/third_party/catapult
@@ -1 +1 @@ -Subproject commit 396204ce89dcd51eaeba6f41116acb736ef22007 +Subproject commit 2298e6389913688b2fee8100c4535053d627ef8c
diff --git a/third_party/chromium-variations b/third_party/chromium-variations index 9689477..709c9fa 160000 --- a/third_party/chromium-variations +++ b/third_party/chromium-variations
@@ -1 +1 @@ -Subproject commit 968947731e36aa16182c769c0d52620517260473 +Subproject commit 709c9fa43a4003a7fd787b22d540b4fb9de25e30
diff --git a/third_party/depot_tools b/third_party/depot_tools index 5ce8e01..3900055 160000 --- a/third_party/depot_tools +++ b/third_party/depot_tools
@@ -1 +1 @@ -Subproject commit 5ce8e010db12629c396c80a24713fc801cceeb22 +Subproject commit 390005586bde14be9b55fde71ca4ae2107021ac9
diff --git a/third_party/devtools-frontend-internal b/third_party/devtools-frontend-internal index de0f5812..9a50858 160000 --- a/third_party/devtools-frontend-internal +++ b/third_party/devtools-frontend-internal
@@ -1 +1 @@ -Subproject commit de0f5812708a5cfa7606ac1792d5c8dcc054d2ac +Subproject commit 9a50858ef92b662c0f264a32b6a94c189da5e945
diff --git a/third_party/libaom/README.chromium b/third_party/libaom/README.chromium index 936d894f..f76e933 100644 --- a/third_party/libaom/README.chromium +++ b/third_party/libaom/README.chromium
@@ -2,7 +2,7 @@ Short Name: libaom URL: https://aomedia.googlesource.com/aom/ Version: N/A -Revision: e1b78c57e41b332d2345b3f85ad84956002468e9 +Revision: 77657197c709017246e15ae4074eb9108d3b62c8 CPEPrefix: cpe:/a:aomedia:aomedia:3.6.1 License: BSD License File: source/libaom/LICENSE
diff --git a/third_party/libaom/libaom_srcs.gni b/third_party/libaom/libaom_srcs.gni index 01009e0..03138e5 100644 --- a/third_party/libaom/libaom_srcs.gni +++ b/third_party/libaom/libaom_srcs.gni
@@ -652,6 +652,12 @@ "//third_party/libaom/source/libaom/aom_dsp/x86/jnt_variance_ssse3.c", ] +aom_dsp_encoder_intrin_sve = [ + "//third_party/libaom/source/libaom/aom_dsp/arm/avg_sve.c", + "//third_party/libaom/source/libaom/aom_dsp/arm/blk_sse_sum_sve.c", + "//third_party/libaom/source/libaom/aom_dsp/arm/sum_squares_sve.c", +] + aom_dsp_encoder_sources = [ "//third_party/libaom/source/libaom/aom_dsp/avg.c", "//third_party/libaom/source/libaom/aom_dsp/binary_codes_writer.c",
diff --git a/third_party/libaom/source/config/config/aom_version.h b/third_party/libaom/source/config/config/aom_version.h index c8cf3f0..1b2f244 100644 --- a/third_party/libaom/source/config/config/aom_version.h +++ b/third_party/libaom/source/config/config/aom_version.h
@@ -12,8 +12,8 @@ #define VERSION_MAJOR 3 #define VERSION_MINOR 8 #define VERSION_PATCH 0 -#define VERSION_EXTRA "102-ge1b78c57e4" +#define VERSION_EXTRA "131-g77657197c7" #define VERSION_PACKED \ ((VERSION_MAJOR << 16) | (VERSION_MINOR << 8) | (VERSION_PATCH)) -#define VERSION_STRING_NOSP "3.8.0-102-ge1b78c57e4" -#define VERSION_STRING " 3.8.0-102-ge1b78c57e4" +#define VERSION_STRING_NOSP "3.8.0-131-g77657197c7" +#define VERSION_STRING " 3.8.0-131-g77657197c7"
diff --git a/third_party/libaom/source/config/linux/arm-neon-cpu-detect/config/aom_config.asm b/third_party/libaom/source/config/linux/arm-neon-cpu-detect/config/aom_config.asm index d4b4e2540e..b5c5faa 100644 --- a/third_party/libaom/source/config/linux/arm-neon-cpu-detect/config/aom_config.asm +++ b/third_party/libaom/source/config/linux/arm-neon-cpu-detect/config/aom_config.asm
@@ -40,6 +40,7 @@ CONFIG_INSPECTION equ 0 CONFIG_INTERNAL_STATS equ 0 CONFIG_INTER_STATS_ONLY equ 0 +CONFIG_LIBVMAF_PSNR_PEAK equ 1 CONFIG_LIBYUV equ 0 CONFIG_MAX_DECODE_PROFILE equ 0 CONFIG_MISMATCH_DEBUG equ 0
diff --git a/third_party/libaom/source/config/linux/arm-neon-cpu-detect/config/aom_config.h b/third_party/libaom/source/config/linux/arm-neon-cpu-detect/config/aom_config.h index 23777a1..dc730dd7 100644 --- a/third_party/libaom/source/config/linux/arm-neon-cpu-detect/config/aom_config.h +++ b/third_party/libaom/source/config/linux/arm-neon-cpu-detect/config/aom_config.h
@@ -42,6 +42,7 @@ #define CONFIG_INSPECTION 0 #define CONFIG_INTERNAL_STATS 0 #define CONFIG_INTER_STATS_ONLY 0 +#define CONFIG_LIBVMAF_PSNR_PEAK 1 #define CONFIG_LIBYUV 0 #define CONFIG_MAX_DECODE_PROFILE 0 #define CONFIG_MISMATCH_DEBUG 0
diff --git a/third_party/libaom/source/config/linux/arm-neon/config/aom_config.asm b/third_party/libaom/source/config/linux/arm-neon/config/aom_config.asm index 90b886e..07db92bf 100644 --- a/third_party/libaom/source/config/linux/arm-neon/config/aom_config.asm +++ b/third_party/libaom/source/config/linux/arm-neon/config/aom_config.asm
@@ -40,6 +40,7 @@ CONFIG_INSPECTION equ 0 CONFIG_INTERNAL_STATS equ 0 CONFIG_INTER_STATS_ONLY equ 0 +CONFIG_LIBVMAF_PSNR_PEAK equ 1 CONFIG_LIBYUV equ 0 CONFIG_MAX_DECODE_PROFILE equ 0 CONFIG_MISMATCH_DEBUG equ 0
diff --git a/third_party/libaom/source/config/linux/arm-neon/config/aom_config.h b/third_party/libaom/source/config/linux/arm-neon/config/aom_config.h index 559111fa..65fdfa9b 100644 --- a/third_party/libaom/source/config/linux/arm-neon/config/aom_config.h +++ b/third_party/libaom/source/config/linux/arm-neon/config/aom_config.h
@@ -42,6 +42,7 @@ #define CONFIG_INSPECTION 0 #define CONFIG_INTERNAL_STATS 0 #define CONFIG_INTER_STATS_ONLY 0 +#define CONFIG_LIBVMAF_PSNR_PEAK 1 #define CONFIG_LIBYUV 0 #define CONFIG_MAX_DECODE_PROFILE 0 #define CONFIG_MISMATCH_DEBUG 0
diff --git a/third_party/libaom/source/config/linux/arm/config/aom_config.asm b/third_party/libaom/source/config/linux/arm/config/aom_config.asm index 2982c69..d5ea3f1 100644 --- a/third_party/libaom/source/config/linux/arm/config/aom_config.asm +++ b/third_party/libaom/source/config/linux/arm/config/aom_config.asm
@@ -40,6 +40,7 @@ CONFIG_INSPECTION equ 0 CONFIG_INTERNAL_STATS equ 0 CONFIG_INTER_STATS_ONLY equ 0 +CONFIG_LIBVMAF_PSNR_PEAK equ 1 CONFIG_LIBYUV equ 0 CONFIG_MAX_DECODE_PROFILE equ 0 CONFIG_MISMATCH_DEBUG equ 0
diff --git a/third_party/libaom/source/config/linux/arm/config/aom_config.h b/third_party/libaom/source/config/linux/arm/config/aom_config.h index 36a43f9..54468ee 100644 --- a/third_party/libaom/source/config/linux/arm/config/aom_config.h +++ b/third_party/libaom/source/config/linux/arm/config/aom_config.h
@@ -42,6 +42,7 @@ #define CONFIG_INSPECTION 0 #define CONFIG_INTERNAL_STATS 0 #define CONFIG_INTER_STATS_ONLY 0 +#define CONFIG_LIBVMAF_PSNR_PEAK 1 #define CONFIG_LIBYUV 0 #define CONFIG_MAX_DECODE_PROFILE 0 #define CONFIG_MISMATCH_DEBUG 0
diff --git a/third_party/libaom/source/config/linux/arm64-cpu-detect/config/aom_config.asm b/third_party/libaom/source/config/linux/arm64-cpu-detect/config/aom_config.asm index 605a59f0..e01af9a8 100644 --- a/third_party/libaom/source/config/linux/arm64-cpu-detect/config/aom_config.asm +++ b/third_party/libaom/source/config/linux/arm64-cpu-detect/config/aom_config.asm
@@ -40,6 +40,7 @@ CONFIG_INSPECTION equ 0 CONFIG_INTERNAL_STATS equ 0 CONFIG_INTER_STATS_ONLY equ 0 +CONFIG_LIBVMAF_PSNR_PEAK equ 1 CONFIG_LIBYUV equ 0 CONFIG_MAX_DECODE_PROFILE equ 0 CONFIG_MISMATCH_DEBUG equ 0
diff --git a/third_party/libaom/source/config/linux/arm64-cpu-detect/config/aom_config.h b/third_party/libaom/source/config/linux/arm64-cpu-detect/config/aom_config.h index 27a407f8c..41d21e95 100644 --- a/third_party/libaom/source/config/linux/arm64-cpu-detect/config/aom_config.h +++ b/third_party/libaom/source/config/linux/arm64-cpu-detect/config/aom_config.h
@@ -42,6 +42,7 @@ #define CONFIG_INSPECTION 0 #define CONFIG_INTERNAL_STATS 0 #define CONFIG_INTER_STATS_ONLY 0 +#define CONFIG_LIBVMAF_PSNR_PEAK 1 #define CONFIG_LIBYUV 0 #define CONFIG_MAX_DECODE_PROFILE 0 #define CONFIG_MISMATCH_DEBUG 0
diff --git a/third_party/libaom/source/config/linux/generic/config/aom_config.asm b/third_party/libaom/source/config/linux/generic/config/aom_config.asm index 2e40d87..9b149375 100644 --- a/third_party/libaom/source/config/linux/generic/config/aom_config.asm +++ b/third_party/libaom/source/config/linux/generic/config/aom_config.asm
@@ -40,6 +40,7 @@ CONFIG_INSPECTION equ 0 CONFIG_INTERNAL_STATS equ 0 CONFIG_INTER_STATS_ONLY equ 0 +CONFIG_LIBVMAF_PSNR_PEAK equ 1 CONFIG_LIBYUV equ 0 CONFIG_MAX_DECODE_PROFILE equ 0 CONFIG_MISMATCH_DEBUG equ 0
diff --git a/third_party/libaom/source/config/linux/generic/config/aom_config.h b/third_party/libaom/source/config/linux/generic/config/aom_config.h index e377526..72b2f12 100644 --- a/third_party/libaom/source/config/linux/generic/config/aom_config.h +++ b/third_party/libaom/source/config/linux/generic/config/aom_config.h
@@ -42,6 +42,7 @@ #define CONFIG_INSPECTION 0 #define CONFIG_INTERNAL_STATS 0 #define CONFIG_INTER_STATS_ONLY 0 +#define CONFIG_LIBVMAF_PSNR_PEAK 1 #define CONFIG_LIBYUV 0 #define CONFIG_MAX_DECODE_PROFILE 0 #define CONFIG_MISMATCH_DEBUG 0
diff --git a/third_party/libaom/source/config/linux/ia32/config/aom_config.asm b/third_party/libaom/source/config/linux/ia32/config/aom_config.asm index ffc8e7a..a950275 100644 --- a/third_party/libaom/source/config/linux/ia32/config/aom_config.asm +++ b/third_party/libaom/source/config/linux/ia32/config/aom_config.asm
@@ -30,6 +30,7 @@ %define CONFIG_INSPECTION 0 %define CONFIG_INTERNAL_STATS 0 %define CONFIG_INTER_STATS_ONLY 0 +%define CONFIG_LIBVMAF_PSNR_PEAK 1 %define CONFIG_LIBYUV 0 %define CONFIG_MAX_DECODE_PROFILE 0 %define CONFIG_MISMATCH_DEBUG 0
diff --git a/third_party/libaom/source/config/linux/ia32/config/aom_config.h b/third_party/libaom/source/config/linux/ia32/config/aom_config.h index 078a967b..145ff726 100644 --- a/third_party/libaom/source/config/linux/ia32/config/aom_config.h +++ b/third_party/libaom/source/config/linux/ia32/config/aom_config.h
@@ -42,6 +42,7 @@ #define CONFIG_INSPECTION 0 #define CONFIG_INTERNAL_STATS 0 #define CONFIG_INTER_STATS_ONLY 0 +#define CONFIG_LIBVMAF_PSNR_PEAK 1 #define CONFIG_LIBYUV 0 #define CONFIG_MAX_DECODE_PROFILE 0 #define CONFIG_MISMATCH_DEBUG 0
diff --git a/third_party/libaom/source/config/linux/x64/config/aom_config.asm b/third_party/libaom/source/config/linux/x64/config/aom_config.asm index 0913e462..38dc716 100644 --- a/third_party/libaom/source/config/linux/x64/config/aom_config.asm +++ b/third_party/libaom/source/config/linux/x64/config/aom_config.asm
@@ -30,6 +30,7 @@ %define CONFIG_INSPECTION 0 %define CONFIG_INTERNAL_STATS 0 %define CONFIG_INTER_STATS_ONLY 0 +%define CONFIG_LIBVMAF_PSNR_PEAK 1 %define CONFIG_LIBYUV 0 %define CONFIG_MAX_DECODE_PROFILE 0 %define CONFIG_MISMATCH_DEBUG 0
diff --git a/third_party/libaom/source/config/linux/x64/config/aom_config.h b/third_party/libaom/source/config/linux/x64/config/aom_config.h index c7e88c8..058faa3 100644 --- a/third_party/libaom/source/config/linux/x64/config/aom_config.h +++ b/third_party/libaom/source/config/linux/x64/config/aom_config.h
@@ -42,6 +42,7 @@ #define CONFIG_INSPECTION 0 #define CONFIG_INTERNAL_STATS 0 #define CONFIG_INTER_STATS_ONLY 0 +#define CONFIG_LIBVMAF_PSNR_PEAK 1 #define CONFIG_LIBYUV 0 #define CONFIG_MAX_DECODE_PROFILE 0 #define CONFIG_MISMATCH_DEBUG 0
diff --git a/third_party/libaom/source/config/win/arm64-cpu-detect/config/aom_config.asm b/third_party/libaom/source/config/win/arm64-cpu-detect/config/aom_config.asm index 605a59f0..e01af9a8 100644 --- a/third_party/libaom/source/config/win/arm64-cpu-detect/config/aom_config.asm +++ b/third_party/libaom/source/config/win/arm64-cpu-detect/config/aom_config.asm
@@ -40,6 +40,7 @@ CONFIG_INSPECTION equ 0 CONFIG_INTERNAL_STATS equ 0 CONFIG_INTER_STATS_ONLY equ 0 +CONFIG_LIBVMAF_PSNR_PEAK equ 1 CONFIG_LIBYUV equ 0 CONFIG_MAX_DECODE_PROFILE equ 0 CONFIG_MISMATCH_DEBUG equ 0
diff --git a/third_party/libaom/source/config/win/arm64-cpu-detect/config/aom_config.h b/third_party/libaom/source/config/win/arm64-cpu-detect/config/aom_config.h index 03b12a3..afe2ec9e 100644 --- a/third_party/libaom/source/config/win/arm64-cpu-detect/config/aom_config.h +++ b/third_party/libaom/source/config/win/arm64-cpu-detect/config/aom_config.h
@@ -42,6 +42,7 @@ #define CONFIG_INSPECTION 0 #define CONFIG_INTERNAL_STATS 0 #define CONFIG_INTER_STATS_ONLY 0 +#define CONFIG_LIBVMAF_PSNR_PEAK 1 #define CONFIG_LIBYUV 0 #define CONFIG_MAX_DECODE_PROFILE 0 #define CONFIG_MISMATCH_DEBUG 0
diff --git a/third_party/libaom/source/config/win/ia32/config/aom_config.asm b/third_party/libaom/source/config/win/ia32/config/aom_config.asm index fccc023..b0d831cb 100644 --- a/third_party/libaom/source/config/win/ia32/config/aom_config.asm +++ b/third_party/libaom/source/config/win/ia32/config/aom_config.asm
@@ -30,6 +30,7 @@ %define CONFIG_INSPECTION 0 %define CONFIG_INTERNAL_STATS 0 %define CONFIG_INTER_STATS_ONLY 0 +%define CONFIG_LIBVMAF_PSNR_PEAK 1 %define CONFIG_LIBYUV 0 %define CONFIG_MAX_DECODE_PROFILE 0 %define CONFIG_MISMATCH_DEBUG 0
diff --git a/third_party/libaom/source/config/win/ia32/config/aom_config.h b/third_party/libaom/source/config/win/ia32/config/aom_config.h index a137fd1..23079efd 100644 --- a/third_party/libaom/source/config/win/ia32/config/aom_config.h +++ b/third_party/libaom/source/config/win/ia32/config/aom_config.h
@@ -42,6 +42,7 @@ #define CONFIG_INSPECTION 0 #define CONFIG_INTERNAL_STATS 0 #define CONFIG_INTER_STATS_ONLY 0 +#define CONFIG_LIBVMAF_PSNR_PEAK 1 #define CONFIG_LIBYUV 0 #define CONFIG_MAX_DECODE_PROFILE 0 #define CONFIG_MISMATCH_DEBUG 0
diff --git a/third_party/libaom/source/config/win/x64/config/aom_config.asm b/third_party/libaom/source/config/win/x64/config/aom_config.asm index f05bbd4..94ab526 100644 --- a/third_party/libaom/source/config/win/x64/config/aom_config.asm +++ b/third_party/libaom/source/config/win/x64/config/aom_config.asm
@@ -30,6 +30,7 @@ %define CONFIG_INSPECTION 0 %define CONFIG_INTERNAL_STATS 0 %define CONFIG_INTER_STATS_ONLY 0 +%define CONFIG_LIBVMAF_PSNR_PEAK 1 %define CONFIG_LIBYUV 0 %define CONFIG_MAX_DECODE_PROFILE 0 %define CONFIG_MISMATCH_DEBUG 0
diff --git a/third_party/libaom/source/config/win/x64/config/aom_config.h b/third_party/libaom/source/config/win/x64/config/aom_config.h index 0bc7136..ba8e845a 100644 --- a/third_party/libaom/source/config/win/x64/config/aom_config.h +++ b/third_party/libaom/source/config/win/x64/config/aom_config.h
@@ -42,6 +42,7 @@ #define CONFIG_INSPECTION 0 #define CONFIG_INTERNAL_STATS 0 #define CONFIG_INTER_STATS_ONLY 0 +#define CONFIG_LIBVMAF_PSNR_PEAK 1 #define CONFIG_LIBYUV 0 #define CONFIG_MAX_DECODE_PROFILE 0 #define CONFIG_MISMATCH_DEBUG 0
diff --git a/third_party/libaom/source/libaom b/third_party/libaom/source/libaom index e1b78c5..7765719 160000 --- a/third_party/libaom/source/libaom +++ b/third_party/libaom/source/libaom
@@ -1 +1 @@ -Subproject commit e1b78c57e41b332d2345b3f85ad84956002468e9 +Subproject commit 77657197c709017246e15ae4074eb9108d3b62c8
diff --git a/third_party/libc++abi/src b/third_party/libc++abi/src index 6bd2588..c7c5649 160000 --- a/third_party/libc++abi/src +++ b/third_party/libc++abi/src
@@ -1 +1 @@ -Subproject commit 6bd25883ff3cef44ae402ed5c62b4dac21235ada +Subproject commit c7c5649e8badcb31e66f188f5cf7933f9a8f8287
diff --git a/third_party/perfetto b/third_party/perfetto index 3cee914..d6dd1af 160000 --- a/third_party/perfetto +++ b/third_party/perfetto
@@ -1 +1 @@ -Subproject commit 3cee91476cdf8bb14facf7b8208fe2ba6a2ad5d8 +Subproject commit d6dd1afcbdccd18eff2a5992ad7eedaef4a6b4c6
diff --git a/third_party/re2/src b/third_party/re2/src index 9d0b5bf..c217103 160000 --- a/third_party/re2/src +++ b/third_party/re2/src
@@ -1 +1 @@ -Subproject commit 9d0b5bf57cf0dc5388568127bcf079812d3f989e +Subproject commit c21710327d0330cd933cf52ca89482e845824269
diff --git a/third_party/skia b/third_party/skia index 4170fba..79f23e8 160000 --- a/third_party/skia +++ b/third_party/skia
@@ -1 +1 @@ -Subproject commit 4170fba2d89fc0319aad5702a15acdee4470f606 +Subproject commit 79f23e8d8b5d3c602bc2a1081ddb39d3f8085c9e
diff --git a/third_party/webrtc b/third_party/webrtc index 6f0f158a..3ba809d 160000 --- a/third_party/webrtc +++ b/third_party/webrtc
@@ -1 +1 @@ -Subproject commit 6f0f158af0290f928a4597cdacdc065ccd39d1fe +Subproject commit 3ba809d6a6bc20931adde485bb04586a6556db11
diff --git a/tools/android/avd/proto/creation/generic_android28.textpb b/tools/android/avd/proto/creation/android_28_google_apis_x86.textpb similarity index 67% rename from tools/android/avd/proto/creation/generic_android28.textpb rename to tools/android/avd/proto/creation/android_28_google_apis_x86.textpb index 5cee08f..ff9cf92 100644 --- a/tools/android/avd/proto/creation/generic_android28.textpb +++ b/tools/android/avd/proto/creation/android_28_google_apis_x86.textpb
@@ -2,24 +2,24 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -# Configuration for a generic x86 android-28 AVD. +# Configuration for an Android Pie (API 28) AVD on google_apis on x86 emulator_package { package_name: "chromium/third_party/android_sdk/public/emulator" version: "N2X90_ADQtGKgoxkXZH3-TM5dbrynU-zGC4mj0B5KMIC" # 32.1.15 - dest_path: "generic_android28" + dest_path: "android_28_google_apis_x86" } system_image_package { package_name: "chromium/third_party/android_sdk/public/system-images/android-28/google_apis/x86" version: "n5ghWmdJtOyffzCTuQwcIHCz34tTB6Cac9gJGU5pCMAC" # r12 - dest_path: "generic_android28" + dest_path: "android_28_google_apis_x86" } system_image_name: "system-images;android-28;google_apis;x86" avd_package { package_name: "chromium/third_party/android_sdk/public/avds/android-28/google_apis/x86" - dest_path: "generic_android28" + dest_path: "android_28_google_apis_x86" } avd_name: "android_28_google_apis_x86" @@ -34,3 +34,10 @@ value: "on" } } + +min_sdk: 28 +additional_apk { + package_name: "chrome_internal/third_party/google3/apks/gmscore/x86" + version: "d3fTL5W2oRaqhhYdbk9SivHLBycVC3tlpplGGbsz6jgC" + dest_path: "android_28_google_apis_x86/gmscore_apks" +}
diff --git a/tools/android/avd/proto/creation/generic_android29.textpb b/tools/android/avd/proto/creation/android_29_google_apis_x86.textpb similarity index 67% rename from tools/android/avd/proto/creation/generic_android29.textpb rename to tools/android/avd/proto/creation/android_29_google_apis_x86.textpb index b140e1e1..ca7c937 100644 --- a/tools/android/avd/proto/creation/generic_android29.textpb +++ b/tools/android/avd/proto/creation/android_29_google_apis_x86.textpb
@@ -2,24 +2,24 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -# Configuration for a generic x86 android-29 AVD. +# Configuration for an Android-10 (Q, API 29) AVD on google_apis on x86 emulator_package { package_name: "chromium/third_party/android_sdk/public/emulator" version: "N2X90_ADQtGKgoxkXZH3-TM5dbrynU-zGC4mj0B5KMIC" # 32.1.15 - dest_path: "generic_android29" + dest_path: "android_29_google_apis_x86" } system_image_package { package_name: "chromium/third_party/android_sdk/public/system-images/android-29/google_apis/x86" version: "9cGIyFNG8n9H3gwo2Vgs88BWlGztVAy8eJsKIXsL6zcC" # r12 - dest_path: "generic_android29" + dest_path: "android_29_google_apis_x86" } system_image_name: "system-images;android-29;google_apis;x86" avd_package { package_name: "chromium/third_party/android_sdk/public/avds/android-29/google_apis/x86" - dest_path: "generic_android29" + dest_path: "android_29_google_apis_x86" } avd_name: "android_29_google_apis_x86" @@ -34,3 +34,10 @@ value: "on" } } + +min_sdk: 29 +additional_apk { + package_name: "chrome_internal/third_party/google3/apks/gmscore/x86" + version: "d3fTL5W2oRaqhhYdbk9SivHLBycVC3tlpplGGbsz6jgC" + dest_path: "android_29_google_apis_x86/gmscore_apks" +}
diff --git a/tools/android/avd/proto/creation/generic_android30.textpb b/tools/android/avd/proto/creation/android_30_google_apis_x86.textpb similarity index 67% rename from tools/android/avd/proto/creation/generic_android30.textpb rename to tools/android/avd/proto/creation/android_30_google_apis_x86.textpb index 72f9a78e..9fe2e39 100644 --- a/tools/android/avd/proto/creation/generic_android30.textpb +++ b/tools/android/avd/proto/creation/android_30_google_apis_x86.textpb
@@ -2,24 +2,24 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -# Configuration for a generic x86 android-30 AVD. +# Configuration for an Android-11 (R, API 30) AVD on google_apis on x86 emulator_package { package_name: "chromium/third_party/android_sdk/public/emulator" version: "N2X90_ADQtGKgoxkXZH3-TM5dbrynU-zGC4mj0B5KMIC" # 32.1.15 - dest_path: "generic_android30" + dest_path: "android_30_google_apis_x86" } system_image_package { package_name: "chromium/third_party/android_sdk/public/system-images/android-30/google_apis/x86" version: "cX-cza6YinY0j4RRlq-Orvef6P-GKKcmWiJllIj4UHgC" # r10 - dest_path: "generic_android30" + dest_path: "android_30_google_apis_x86" } system_image_name: "system-images;android-30;google_apis;x86" avd_package { package_name: "chromium/third_party/android_sdk/public/avds/android-30/google_apis/x86" - dest_path: "generic_android30" + dest_path: "android_30_google_apis_x86" } avd_name: "android_30_google_apis_x86" @@ -34,3 +34,10 @@ value: "on" } } + +min_sdk: 30 +additional_apk { + package_name: "chrome_internal/third_party/google3/apks/gmscore/x86" + version: "d3fTL5W2oRaqhhYdbk9SivHLBycVC3tlpplGGbsz6jgC" + dest_path: "android_30_google_apis_x86/gmscore_apks" +}
diff --git a/tools/android/avd/proto/creation/generic_android31.textpb b/tools/android/avd/proto/creation/android_31_google_apis_x64.textpb similarity index 64% rename from tools/android/avd/proto/creation/generic_android31.textpb rename to tools/android/avd/proto/creation/android_31_google_apis_x64.textpb index 5b7d608..163f92d 100644 --- a/tools/android/avd/proto/creation/generic_android31.textpb +++ b/tools/android/avd/proto/creation/android_31_google_apis_x64.textpb
@@ -2,26 +2,26 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -# Configuration for a generic x86_64 android-12 AVD (userdebug build). +# Configuration for an Android-12 (S, API 31) AVD on google_apis on x86_64 emulator_package { package_name: "chromium/third_party/android_sdk/public/emulator" version: "N2X90_ADQtGKgoxkXZH3-TM5dbrynU-zGC4mj0B5KMIC" # 32.1.15 - dest_path: "generic_android31" + dest_path: "android_31_google_apis_x64" } system_image_package { package_name: "chromium/third_party/android_sdk/public/system-images/android-31/google_apis/x86_64" version: "MYBnQWsww48BqFoQMJt3QC06pDAQNTtcAXZalvRNCY0C" # r14 - dest_path: "generic_android31" + dest_path: "android_31_google_apis_x64" } system_image_name: "system-images;android-31;google_apis;x86_64" avd_package { package_name: "chromium/third_party/android_sdk/public/avds/android-31/google_apis/x86_64" - dest_path: "generic_android31" + dest_path: "android_31_google_apis_x64" } -avd_name: "android_31_google_apis_x86_64" +avd_name: "android_31_google_apis_x64" avd_settings { screen { @@ -34,3 +34,10 @@ value: "on" } } + +min_sdk: 31 +additional_apk { + package_name: "chrome_internal/third_party/google3/apks/gmscore/x86_64" + version: "yPyAJAHojVhJz8dfy28tCLyUidWpD95q2Zzj6JXJRkIC" + dest_path: "android_31_google_apis_x64/gmscore_apks" +}
diff --git a/tools/android/avd/proto/creation/generic_android32_foldable.textpb b/tools/android/avd/proto/creation/android_32_google_apis_x64_foldable.textpb similarity index 83% rename from tools/android/avd/proto/creation/generic_android32_foldable.textpb rename to tools/android/avd/proto/creation/android_32_google_apis_x64_foldable.textpb index 5aa0df3..396dd07 100644 --- a/tools/android/avd/proto/creation/generic_android32_foldable.textpb +++ b/tools/android/avd/proto/creation/android_32_google_apis_x64_foldable.textpb
@@ -2,26 +2,26 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -# Configuration for a generic x86_64 android-12L AVD (userdebug build). +# Configuration for an Android-12L (S_V2, API 32) AVD on google_apis on x86_64 emulator_package { package_name: "chromium/third_party/android_sdk/public/emulator" version: "N2X90_ADQtGKgoxkXZH3-TM5dbrynU-zGC4mj0B5KMIC" # 32.1.15 - dest_path: "generic_android32_foldable" + dest_path: "android_32_google_apis_x64_foldable" } system_image_package { package_name: "chromium/third_party/android_sdk/public/system-images/android-32/google_apis/x86_64" version: "KK_VeEUvdJrxL7eEKvVnt_4bjZPRLsGPymVm6Ios5HEC" # r7 - dest_path: "generic_android32_foldable" + dest_path: "android_32_google_apis_x64_foldable" } system_image_name: "system-images;android-32;google_apis;x86_64" avd_package { package_name: "chromium/third_party/android_sdk/public/avds/android-32/google_apis/x86_64" - dest_path: "generic_android32_foldable" + dest_path: "android_32_google_apis_x64_foldable" } -avd_name: "android_32_foldable_google_apis_x86_64" +avd_name: "android_32_google_apis_x64_foldable" # Mirror the configs of '7.6" Fold-in with outer display' avd_settings { @@ -88,10 +88,8 @@ } min_sdk: 32 -install_privileged_apk_partition: "/product" - additional_apk { package_name: "chrome_internal/third_party/google3/apks/gmscore/x86_64" - version: "8YCNotfbM5tOtTRFFJNfDpolC4TMZt2N61WY66WI4JwC" - dest_path: "generic_android32_foldable/gmscore_apks" + version: "yPyAJAHojVhJz8dfy28tCLyUidWpD95q2Zzj6JXJRkIC" + dest_path: "android_32_google_apis_x64_foldable/gmscore_apks" }
diff --git a/tools/android/avd/proto/creation/generic_android33.textpb b/tools/android/avd/proto/creation/android_33_google_apis_x64.textpb similarity index 64% rename from tools/android/avd/proto/creation/generic_android33.textpb rename to tools/android/avd/proto/creation/android_33_google_apis_x64.textpb index 3f556c6..15baae69 100644 --- a/tools/android/avd/proto/creation/generic_android33.textpb +++ b/tools/android/avd/proto/creation/android_33_google_apis_x64.textpb
@@ -2,26 +2,26 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -# Configuration for a generic x86_64 android-13 AVD (userdebug build). +# Configuration for an Android-13 (T, API 33) AVD on google_apis on x86_64 emulator_package { package_name: "chromium/third_party/android_sdk/public/emulator" version: "N2X90_ADQtGKgoxkXZH3-TM5dbrynU-zGC4mj0B5KMIC" # 32.1.15 - dest_path: "generic_android33" + dest_path: "android_33_google_apis_x64" } system_image_package { package_name: "chromium/third_party/android_sdk/public/system-images/android-33/google_apis/x86_64" version: "4c9il1xIZwca_xJABnQ1KstiU1kFqzOonoQGdweA77cC" # r15 - dest_path: "generic_android33" + dest_path: "android_33_google_apis_x64" } system_image_name: "system-images;android-33;google_apis;x86_64" avd_package { package_name: "chromium/third_party/android_sdk/public/avds/android-33/google_apis/x86_64" - dest_path: "generic_android33" + dest_path: "android_33_google_apis_x64" } -avd_name: "android_33_google_apis_x86_64" +avd_name: "android_33_google_apis_x64" avd_settings { screen { @@ -34,3 +34,10 @@ value: "on" } } + +min_sdk: 33 +additional_apk { + package_name: "chrome_internal/third_party/google3/apks/gmscore/x86_64" + version: "yPyAJAHojVhJz8dfy28tCLyUidWpD95q2Zzj6JXJRkIC" + dest_path: "android_33_google_apis_x64/gmscore_apks" +}
diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec index 233a028f..cd15fce 100644 --- a/tools/gritsettings/resource_ids.spec +++ b/tools/gritsettings/resource_ids.spec
@@ -506,7 +506,7 @@ "META": {"sizes": {"includes": [10],}}, "includes": [4300], }, - "<(SHARED_INTERMEDIATE_DIR)/chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog_resources.grd": { + "<(SHARED_INTERMEDIATE_DIR)/chrome/browser/resources/chromeos/internet_detail_dialog/resources.grd": { "META": {"sizes": {"includes": [10],}}, "includes": [4320], }, @@ -741,6 +741,10 @@ "META": {"sizes": {"includes": [100],}}, "includes": [5520], }, + "chromeos/ash/components/emoji/emoji.grd" : { + "META": {"sizes": {"includes": [15],}}, + "includes" : [5530], + }, "chromeos/ash/resources/ash_resources.grd": { "includes": [5540], },
diff --git a/tools/licenses/licenses.py b/tools/licenses/licenses.py index 7edafe6..30f81dd2b 100755 --- a/tools/licenses/licenses.py +++ b/tools/licenses/licenses.py
@@ -42,6 +42,10 @@ sys.path.insert(0, os.path.join(_REPOSITORY_ROOT, 'build')) import action_helpers +METADATA_FILE_NAMES = frozenset({ + "README.chromium", +}) + # Paths from the root of the tree to directories to skip. PRUNE_PATHS = set([ # Placeholder directory only, not third-party code. @@ -164,6 +168,7 @@ "URL": "https://code.google.com/p/nativeclient", "Shipped": "yes", "License": "BSD", + "License File": ["//native_client/LICENSE"], }, os.path.join('testing', 'gmock'): { "Name": "gmock", @@ -623,15 +628,15 @@ root: str, require_license_file: bool = True, enable_warnings: bool = False) -> List[str]: - """Process a single dependency's metadata in-place. This function will - update the given metadata to use fallback field values, and update - filepaths to absolute paths. + """Processes a single dependency's metadata and returns the updated + data if it passes validation. This function updates the given metadata + to use fallback fields and change any relative paths to absolute. Args: metadata: a single dependency's metadata. readme_path: the source of the metadata (either a metadata file or a SPECIAL_CASES entry). - path: the source directory for the metadata. + path: the source file for the metadata. root: the root directory of the repo. require_license_file: whether a license file is required. enable_warnings: whether warnings should be displayed. @@ -642,10 +647,10 @@ errors = [] # The dependency reference, for more precise error messages. - dep_ref = readme_path + dep_ref = os.path.relpath(readme_path, root) dep_name = metadata.get("Name") if dep_name: - dep_ref = f"{readme_path}>>{dep_name}" + dep_ref = f"{dep_ref}>>{dep_name}" # Set field values for fields with aliases. for alias, field in ALIAS_FIELDS.items(): @@ -700,6 +705,11 @@ "'License File:' line to README.chromium with the appropriate paths.") metadata["License File"] = license_paths + if errors: + # if there were any errors during parsing, clear all values from + # the dependenct metadata so no further processing occurs + metadata = {} + return errors @@ -707,51 +717,73 @@ root, require_license_file=True, optional_keys=[], - enable_warnings=False): + enable_warnings=False, + metadata_file_names=METADATA_FILE_NAMES): """Examine a third_party path and extract that directory's metadata. Note: directory metadata can contain metadata for multiple dependencies. + + Returns: A tuple with a list of directory metadata, and accrued parsing errors + """ if path in THIRD_PARTY_FOR_BUILD_FILES_ONLY: - return [] + return [], [] # Get the metadata values, from # (a) looking up the path in SPECIAL_CASES; or # (b) parsing the metadata from a README.chromium file. - readme_path = "" if path in SPECIAL_CASES: readme_path = f"licenses.py SPECIAL_CASES entry for {path}" - directory_metadata = [dict(SPECIAL_CASES[path])] - else: - # Try to find README.chromium. - readme_path = os.path.join(root, path, "README.chromium") - if not os.path.exists(readme_path): - raise LicenseError("missing README.chromium or licenses.py " - "SPECIAL_CASES entry in %s\n" % path) + directory_metadata = dict(SPECIAL_CASES[path]) + errors = ProcessMetadata(directory_metadata, + readme_path, + path, + root, + require_license_file=require_license_file, + enable_warnings=enable_warnings) - try: - directory_metadata = ParseMetadataFile(readme_path, - optional_fields=optional_keys) - except InvalidMetadata as e: - raise LicenseError(f"Invalid metadata file: {e}") + return [directory_metadata], errors errors = [] - for dependency_metadata in directory_metadata: - # Process the metadata for licensing info. - dependency_errors = ProcessMetadata( - dependency_metadata, - readme_path, - path, - root, - require_license_file=require_license_file, - enable_warnings=enable_warnings) - errors.extend(dependency_errors) + readmes_in_dir = False + valid_metadata = [] + directory_metadata = [] - if errors: - raise LicenseError("Errors in %s:\n %s\n" % (path, ";\n ".join(errors))) + for name in metadata_file_names: + for readme_path in (pathlib.Path(root) / path).glob(name): + readmes_in_dir = True - return directory_metadata + try: + file_metadata = ParseMetadataFile(str(readme_path), + optional_fields=optional_keys) + for dependency_metadata in file_metadata: + meta_errors = ProcessMetadata( + dependency_metadata, + readme_path, + path, + root, + require_license_file=require_license_file, + enable_warnings=enable_warnings) + + if meta_errors: + errors.append( + "Errors in %s:\n %s\n" % + (os.path.relpath(readme_path, root), ";\n ".join(meta_errors))) + continue + + if dependency_metadata: + valid_metadata.append(dependency_metadata) + + except InvalidMetadata as e: + errors.append(f"Invalid metadata file: {e}") + continue + + if not readmes_in_dir: + raise LicenseError(f"missing third party metadata file " + f"or licenses.py SPECIAL_CASES entry in {path}\n") + + return valid_metadata, errors def process_license_files( @@ -845,10 +877,6 @@ ProcessAdditionalReadmePathsJson(root, dirpath, third_party_dirs) - # Don't recurse into any subdirs from here. - dirs[:] = [] - continue - # Don't recurse into paths in ADDITIONAL_PATHS, like we do with regular # third_party/foo paths. if path in ADDITIONAL_PATHS: @@ -887,6 +915,14 @@ return os.path.join(_REPOSITORY_ROOT, 'buildtools', subdir, exe) +def LogParseDirErrors(errors): + """Provides a convenience method for printing out the errors resulting + from running ParseDir() over a directory.""" + + for error in sorted(errors): + print(error) + + def GetThirdPartyDepsFromGNDepsOutput( gn_deps: str, target_os: str, @@ -996,13 +1032,12 @@ errors = [] for path in sorted(third_party_dirs): try: - ParseDir(path, root, enable_warnings=True) + _, errors = ParseDir(path, root, enable_warnings=True) except LicenseError as e: - errors.append((path, e.args[0])) + errors.append(f"{path}: {e}") continue - for path, error in sorted(errors): - print(path + ": " + error) + LogParseDirErrors(errors) return len(errors) == 0 @@ -1089,9 +1124,9 @@ for path in third_party_dirs: try: # Directory metadata can be for multiple dependencies. - directory_metadata = ParseDir(path, - _REPOSITORY_ROOT, - enable_warnings=enable_warnings) + directory_metadata, _ = ParseDir(path, + _REPOSITORY_ROOT, + enable_warnings=enable_warnings) if not directory_metadata: continue except LicenseError: @@ -1208,10 +1243,11 @@ metadatas = {} for d in third_party_dirs: try: - directory_metadata = ParseDir(d, - _REPOSITORY_ROOT, - require_license_file=True, - enable_warnings=args.enable_warnings) + directory_metadata, errors = ParseDir( + d, + _REPOSITORY_ROOT, + require_license_file=True, + enable_warnings=args.enable_warnings) if directory_metadata: metadatas[d] = directory_metadata except LicenseError as lic_exp: @@ -1219,6 +1255,8 @@ print(f"Error: {lic_exp}") continue + LogParseDirErrors(errors) + if args.format == 'spdx': license_txt = GenerateLicenseFileSpdx(metadatas, args.spdx_link, args.spdx_root, args.spdx_doc_name,
diff --git a/tools/licenses/licenses_test.py b/tools/licenses/licenses_test.py index 7e17749..cb0221e 100755 --- a/tools/licenses/licenses_test.py +++ b/tools/licenses/licenses_test.py
@@ -12,6 +12,8 @@ import sys import unittest +from unittest import mock + REPOSITORY_ROOT = os.path.abspath( os.path.join(os.path.dirname(__file__), '..', '..')) sys.path.append(os.path.join(REPOSITORY_ROOT, 'tools', 'licenses')) @@ -80,8 +82,15 @@ } def test_parse_dir(self): + # No metadata file found in directory + test_path = os.path.join('tools', 'licenses', 'foo') + with self.assertRaisesRegex( + licenses.LicenseError, + "missing third party metadata file or licenses.py SPECIAL_CASES"): + licenses.ParseDir(test_path, REPOSITORY_ROOT) + test_path = os.path.join('tools', 'licenses', 'test_dir') - dir_metadata = licenses.ParseDir(test_path, REPOSITORY_ROOT) + dir_metadata, errors = licenses.ParseDir(test_path, REPOSITORY_ROOT) expected = [ { 'License File': [ @@ -102,6 +111,7 @@ 'Shipped': 'no', }, ] + self.assertListEqual(errors, []) self.assertListEqual(dir_metadata, expected) def test_get_third_party_deps_from_gn_deps_output(self):
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml index b54c860c..63a58f5 100644 --- a/tools/metrics/actions/actions.xml +++ b/tools/metrics/actions/actions.xml
@@ -32068,6 +32068,15 @@ </description> </action> +<action name="Settings.TrackingProtection.OpenedFromPrivacyPage"> + <owner>alvingo@google.com</owner> + <owner>koilos@google.com</owner> + <description> + Reported when user navigates to Tracking Protection Settings via the + Tracking Protection link row in the Privacy Page. + </description> +</action> + <action name="Settings.VoiceSearch"> <owner>rohitrao@chromium.org</owner> <owner>sczs@chromium.org</owner> @@ -40755,6 +40764,7 @@ label="For Web Feed successful follow operations after the UI update."/> <suffix name="WebUiHelpBubbleTest" label="For WebUiHelpBubbleTest feature."/> <suffix name="WebUITabStrip" label="For the WebUI tab strip."/> + <suffix name="WhatsNewUpdated" label="For what's new updated content."/> <affected-action name="InProductHelp.NotifyEvent.IPH"/> <affected-action name="InProductHelp.NotifyUsedEvent.IPH"/> <affected-action name="InProductHelp.ShouldTriggerHelpUI.IPH"/> @@ -41245,6 +41255,18 @@ <suffix name="HomeButton" label="Home button"/> <suffix name="MediaButton" label="Media button"/> <suffix name="NewTabButton" label="New tab button for thumbnail tab strip"/> + <suffix name="PinnedShowBookmarkSidePanelButton" + label="Pinned show bookmark side panel button"/> + <suffix name="PinnedShowHistorySidePanelButton" + label="Pinned show history side panel button"/> + <suffix name="PinnedShowReadAnythingSidePanelButton" + label="Pinned show read anything side panel button"/> + <suffix name="PinnedShowReadingListSidePanelButton" + label="Pinned show reading list side panel button"/> + <suffix name="PinnedShowSearchCompanionSidePanelButton" + label="Pinned show search companion side panel button"/> + <suffix name="ShowPerformanceSidePanelButton" + label="Show performance side panel button"/> <suffix name="SidePanelButton" label="Side Panel button"/> <affected-action name="ResponsiveToolbar.OverflowMenuItemActivated"/> </action-suffix>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index ecf03b1e..123ce3cb 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -12848,6 +12848,7 @@ <int value="14" label="ReviewDangerous"/> <int value="15" label="DeepScan"/> <int value="16" label="BypassDeepScan"/> + <int value="17" label="SaveSuspicious"/> </enum> <enum name="DownloadedFileAction"> @@ -16516,6 +16517,7 @@ <int value="1857" label="DOCUMENTSCAN_STARTSCAN"/> <int value="1858" label="DOCUMENTSCAN_CANCELSCAN"/> <int value="1859" label="DOCUMENTSCAN_READSCANDATA"/> + <int value="1860" label="DOCUMENTSCAN_SETOPTIONS"/> </enum> <enum name="ExtensionInProgressRequestState"> @@ -31482,6 +31484,8 @@ <int value="-781625651" label="DisruptiveNotificationPermissionRevocation:enabled"/> <int value="-780798969" label="disable-single-click-autofill"/> + <int value="-780646596" + label="CustomizeChromeWallpaperSearchInspirationCard:enabled"/> <int value="-778126349" label="DownloadsLocationChange:enabled"/> <int value="-778098896" label="EnableAggregatedMlSearchRanking:disabled"/> <int value="-778047974" label="CrostiniUseBusterImage:disabled"/> @@ -32465,6 +32469,8 @@ label="BrokerFileOperationsOnDiskCacheInNetworkService:enabled"/> <int value="-313812707" label="VideoTutorials:disabled"/> <int value="-312144677" label="TFLiteLanguageDetectionEnabled:disabled"/> + <int value="-311509777" + label="CustomizeChromeWallpaperSearchInspirationCard:disabled"/> <int value="-311148335" label="v8-pac-mojo-out-of-process"/> <int value="-310908854" label="new-wallpaper-picker"/> <int value="-310615515" label="EnableSuggestedFiles:disabled"/> @@ -33248,7 +33254,6 @@ <int value="54258707" label="NewTabstripAnimation:enabled"/> <int value="54571864" label="EnableDisplayZoomSetting:enabled"/> <int value="56072855" label="VaapiWebPImageDecodeAcceleration:disabled"/> - <int value="56605515" label="BookmarksImprovedSaveFlow:enabled"/> <int value="56723110" label="enable-webfonts-intervention"/> <int value="56900498" label="OmniboxOneClickUnelide:enabled"/> <int value="57255632" label="site-isolation-for-password-sites:disabled"/> @@ -36744,7 +36749,6 @@ <int value="1713509078" label="NewBaseUrlInheritanceBehavior:enabled"/> <int value="1714016217" label="EnableHeuristicPalmDetectionFilter:enabled"/> <int value="1714520147" label="MBIMode:disabled"/> - <int value="1714746366" label="BookmarksImprovedSaveFlow:disabled"/> <int value="1714751652" label="CaptivePortalErrorPage:disabled"/> <int value="1714922056" label="GlobalMediaControls:disabled"/> <int value="1715173626" label="SyncWebauthnCredentials:disabled"/> @@ -48705,6 +48709,7 @@ <int value="14" label="Opened from a link in side panel"/> <int value="15" label="Opened from Read Anything omnibox icon"/> <int value="16" label="Opened from Read Anything via address bar"/> + <int value="17" label="Opened from toolbar overflow menu"/> </enum> <enum name="SideSearchAvailabilityChangeType">
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml index 0805573..114ca323 100644 --- a/tools/metrics/histograms/metadata/ash/histograms.xml +++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -362,7 +362,7 @@ </histogram> <histogram name="Ash.AmbientMode.AnimationSmoothness.PhotoTransition" units="%" - expires_after="2023-12-01"> + expires_after="2024-12-01"> <owner>wutao@chromium.org</owner> <owner>xiaohuic@chromium.org</owner> <summary> @@ -472,7 +472,7 @@ </histogram> <histogram name="Ash.AmbientMode.PhotoOrientationMatch.{Settings}" units="%" - expires_after="2023-12-01"> + expires_after="2024-12-01"> <owner>esum@google.com</owner> <owner>xiaohuic@chromium.org</owner> <summary> @@ -543,7 +543,7 @@ </histogram> <histogram name="Ash.AmbientMode.TotalNumberOfAlbums" units="int" - expires_after="2023-12-01"> + expires_after="2024-12-01"> <owner>cowmoo@google.com</owner> <owner>xiaohuic@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/download/histograms.xml b/tools/metrics/histograms/metadata/download/histograms.xml index 93e8a7a..9d4a97e 100644 --- a/tools/metrics/histograms/metadata/download/histograms.xml +++ b/tools/metrics/histograms/metadata/download/histograms.xml
@@ -330,15 +330,23 @@ </summary> </histogram> -<histogram name="Download.DownloadDangerPrompt" +<histogram + name="Download.DownloadDangerPrompt.{DownloadDangerTypeString}.{Action}" enum="SBClientDownloadExtensions" expires_after="2024-05-19"> <owner>vakh@chromium.org</owner> <owner>chrome-counter-abuse-alerts@google.com</owner> <summary> - Records when user is shown the download danger prompt while attempting to - recover a blocked download from chrome://downloads, grouped by the type of - file. + Records when user {Action} while attempting to recover a blocked download + from chrome://downloads, for a file of type {DownloadDangerTypeString}. This + is logged from both old the native UI DownloadDangerPrompt as well as its + replacement WebUI prompt DownloadBypassWarningConfirmationDialog (under the + ImprovedDownloadPageWarnings feature). </summary> + <token key="Action"> + <variant name="Proceed" summary="decided to bypass warning and proceed"/> + <variant name="Shown" summary="was shown the dialog"/> + </token> + <token key="DownloadDangerTypeString" variants="DownloadDangerTypeString"/> </histogram> <histogram base="true" name="Download.DownloadSize" units="KB"
diff --git a/tools/metrics/histograms/metadata/enterprise/enums.xml b/tools/metrics/histograms/metadata/enterprise/enums.xml index 46afa25..7bd793e 100644 --- a/tools/metrics/histograms/metadata/enterprise/enums.xml +++ b/tools/metrics/histograms/metadata/enterprise/enums.xml
@@ -1898,7 +1898,6 @@ <int value="1095" label="InsecureHashesInTLSHandshakesEnabled"/> <int value="1096" label="DeviceLoginScreenGeolocationAccessLevel"/> <int value="1097" label="DeviceReportNetworkEvents"/> - <int value="1098" label="SafeBrowsingExtensionProtectionAllowed"/> <int value="1099" label="ShowDisplaySizeScreenEnabled"/> <int value="1100" label="EssentialSearchEnabled"/> <int value="1101" label="LegacyTechReportAllowlist"/>
diff --git a/tools/metrics/histograms/metadata/extensions/histograms.xml b/tools/metrics/histograms/metadata/extensions/histograms.xml index 9e2227f..8baa587 100644 --- a/tools/metrics/histograms/metadata/extensions/histograms.xml +++ b/tools/metrics/histograms/metadata/extensions/histograms.xml
@@ -4329,17 +4329,6 @@ <summary>Uninstalls grouped by Extension::HistogramType.</summary> </histogram> -<histogram name="Extensions.UsedMimeTypeHandler" enum="UsedMimeTypeHandler" - expires_after="2021-11-14"> - <owner>apotapchuk@chromium.org</owner> - <owner>anqing@chromium.org</owner> - <summary> - Tracks the usage of different MIME type handlers used to view files. It is - recorded when the browser intercepts navigation with one of the type - handlers. - </summary> -</histogram> - <histogram name="Extensions.WebRequest.BeforeRequestDeclarativeNetRequestEvaluationTime" units="ms" expires_after="2024-04-28">
diff --git a/tools/metrics/histograms/metadata/feature_engagement/histograms.xml b/tools/metrics/histograms/metadata/feature_engagement/histograms.xml index 5d568c81..86604cb 100644 --- a/tools/metrics/histograms/metadata/feature_engagement/histograms.xml +++ b/tools/metrics/histograms/metadata/feature_engagement/histograms.xml
@@ -479,6 +479,8 @@ <variant name="IPH_WebUiHelpBubbleTest" summary="testing the WebUI help bubble"/> <variant name="IPH_WebUITabStrip" summary="opening the WebUI tab strip"/> + <variant name="IPH_WhatsNewUpdated" + summary="educating user that what's new has new content"/> </variants> <variants name="TutorialID">
diff --git a/tools/metrics/histograms/metadata/histogram_suffixes_list.xml b/tools/metrics/histograms/metadata/histogram_suffixes_list.xml index af15fb7..0561d2e4 100644 --- a/tools/metrics/histograms/metadata/histogram_suffixes_list.xml +++ b/tools/metrics/histograms/metadata/histogram_suffixes_list.xml
@@ -1344,69 +1344,6 @@ <affected-histogram name="Download.Service.TaskScheduler.Status"/> </histogram_suffixes> -<histogram_suffixes name="DownloadDangerPromptResponse" separator="."> - <suffix name="Proceed" - label="The user clicked through and recovered the download."/> - <suffix name="Shown" label="The user was shown the prompt."/> - <affected-histogram - name="Download.DownloadDangerPrompt.AsyncLocalPasswordScanning"/> - <affected-histogram name="Download.DownloadDangerPrompt.AsyncScanning"/> - <affected-histogram - name="Download.DownloadDangerPrompt.BlockedPasswordProtected"/> - <affected-histogram name="Download.DownloadDangerPrompt.BlockedTooLarge"/> - <affected-histogram - name="Download.DownloadDangerPrompt.BlockedUnsupportedFiletype"/> - <affected-histogram - name="Download.DownloadDangerPrompt.DangerousAccountCompromise"/> - <affected-histogram name="Download.DownloadDangerPrompt.DangerousContent"/> - <affected-histogram name="Download.DownloadDangerPrompt.DangerousFile"/> - <affected-histogram name="Download.DownloadDangerPrompt.DangerousHost"/> - <affected-histogram name="Download.DownloadDangerPrompt.DangerousURL"/> - <affected-histogram - name="Download.DownloadDangerPrompt.DeepScannedOpenedDangerous"/> - <affected-histogram name="Download.DownloadDangerPrompt.DeepScannedSafe"/> - <affected-histogram name="Download.DownloadDangerPrompt.PotentiallyUnwanted"/> - <affected-histogram - name="Download.DownloadDangerPrompt.PromptForLocalPasswordScanning"/> - <affected-histogram name="Download.DownloadDangerPrompt.PromptForScanning"/> - <affected-histogram - name="Download.DownloadDangerPrompt.SensitiveContentBlock"/> - <affected-histogram - name="Download.DownloadDangerPrompt.SensitiveContentWarning"/> - <affected-histogram name="Download.DownloadDangerPrompt.UncommonContent"/> -</histogram_suffixes> - -<histogram_suffixes name="DownloadDangerPromptType" separator="."> - <suffix name="AsyncLocalPasswordScanning" - label="File marked ASYNC_LOCAL_PASSWORD_SCANNING"/> - <suffix name="AsyncScanning" label="File marked ASYNC_SCANNING"/> - <suffix name="BlockedPasswordProtected" - label="File marked BLOCKED_PASSWORD_PROTECTED"/> - <suffix name="BlockedTooLarge" label="File marked BLOCKED_TOO_LARGE"/> - <suffix name="BlockedUnsupportedFiletype" - label="File marked BLOCKED_UNSUPPORTED_FILETYPE"/> - <suffix name="DangerousAccountCompromise" - label="File marked DANGEROUS_ACCOUNT_COMPROMISE"/> - <suffix name="DangerousContent" label="File marked DANGEROUS_CONTENT"/> - <suffix name="DangerousFile" label="File marked DANGEROUS_FILE"/> - <suffix name="DangerousHost" label="File marked DANGEROUS_HOST"/> - <suffix name="DangerousURL" label="File marked DANGEROUS_URL"/> - <suffix name="DeepScannedFailed" label="File marked DEEP_SCANNED_FAILED"/> - <suffix name="DeepScannedOpenedDangerous" - label="File marked DEEP_SCANNED_OPENED_DANGEROUS"/> - <suffix name="DeepScannedSafe" label="File marked DEEP_SCANNED_SAFE"/> - <suffix name="PotentiallyUnwanted" label="File marked POTENTIALLY_UNWANTED"/> - <suffix name="PromptForLocalPasswordScanning" - label="File marked PROMPT_FOR_LOCAL_PASSWORD_SCANNING"/> - <suffix name="PromptForScanning" label="File marked PROMPT_FOR_SCANNING"/> - <suffix name="SensitiveContentBlock" - label="File marked SENSITIVE_CONTENT_BLOCK"/> - <suffix name="SensitiveContentWarning" - label="File marked SENSITIVE_CONTENT_WARNING"/> - <suffix name="UncommonContent" label="File marked UNCOMMON_CONTENT"/> - <affected-histogram name="Download.DownloadDangerPrompt"/> -</histogram_suffixes> - <histogram_suffixes name="DownloadDialogSource" separator="."> <suffix name="DownloadHome" label="Download home."/> <suffix name="Infobar" label="Download infobar."/> @@ -4564,8 +4501,6 @@ 2020, metrics expected to bump."/> <suffix name="WarmStartup" label="Startup was warm (almost no hard faults)."/> <affected-histogram - name="LibraryLoader.PercentageOfResidentCodeBeforePrefetch"/> - <affected-histogram name="ProfilePicker.StartupTime.FirstPaint.FromApplicationStart"/> <affected-histogram name="Startup.BrowserMessageLoopFirstIdle"/> <affected-histogram name="Startup.BrowserMessageLoopStart.To.NonEmptyPaint2"/>
diff --git a/tools/metrics/histograms/metadata/image/histograms.xml b/tools/metrics/histograms/metadata/image/histograms.xml index 7cfbd9a..3537dcb 100644 --- a/tools/metrics/histograms/metadata/image/histograms.xml +++ b/tools/metrics/histograms/metadata/image/histograms.xml
@@ -81,6 +81,9 @@ <variant name=".PasswordSharing" summary="Profile image fetcher of potential password recipients in the Password Sharing flow."/> + <variant name=".PriceChangeModule" + summary="Images fetched and used to render price change module on NTP + or StartSurface."/> <variant name=".PriceDropNotification" summary="Images fetched for the icon of price drop notification."/> <variant name=".QueryTiles" summary="Showing Query tiles images."/>
diff --git a/tools/metrics/histograms/metadata/others/histograms.xml b/tools/metrics/histograms/metadata/others/histograms.xml index ad959722..5e2d187 100644 --- a/tools/metrics/histograms/metadata/others/histograms.xml +++ b/tools/metrics/histograms/metadata/others/histograms.xml
@@ -5928,7 +5928,7 @@ </histogram> <histogram name="Gamepad.UnknownGamepadConnected" enum="GamepadSource" - expires_after="2024-01-21"> + expires_after="2024-05-12"> <owner>mattreynolds@chromium.org</owner> <owner>deviceapi-team@google.com</owner> <summary> @@ -6486,16 +6486,6 @@ </summary> </histogram> -<histogram base="true" - name="LibraryLoader.PercentageOfResidentCodeBeforePrefetch" units="%" - expires_after="M81"> - <owner>lizeb@chromium.org</owner> - <summary> - Percentage of the native library code pages resident in memory. Recorded - immediately before the library prefetching kicks in, only on Android. - </summary> -</histogram> - <histogram name="Linux.Distro.Debian" enum="LinuxDistroDebianVersion" expires_after="never"> <!-- expires-never: Needed to measure Linux ecosystem. --> @@ -11172,19 +11162,6 @@ <summary>The interval between ViewResourceAdapter#getBitmap calls.</summary> </histogram> -<histogram name="VirtualKeyboard.ControllerStateTransition" - enum="VirtualKeyboardControllerStateTransition" expires_after="M85"> - <owner>oka@chromium.org</owner> - <summary> - An integer representing a state transition from x to y in the form of x * - 1000 + y. If the transition is not expected, the value is negated. For - example an expected transition from SHOWING (= 2) to SHOWN (= 1) is denoted - as 2001, and an unexpected transition from SHOWING to SHOWING is denoted as - -2002. See KeyboardControllerState for the correspondence between the number - and the enum. - </summary> -</histogram> - <histogram name="VoiceInteraction.AudioPermissionEvent{Timing}" enum="AudioPermissionState" expires_after="2023-07-05"> <owner>basiaz@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/print/histograms.xml b/tools/metrics/histograms/metadata/print/histograms.xml index 4da09933..8a12d4d8 100644 --- a/tools/metrics/histograms/metadata/print/histograms.xml +++ b/tools/metrics/histograms/metadata/print/histograms.xml
@@ -47,6 +47,19 @@ </summary> </histogram> +<histogram name="PrintPreview.InitialDisplayTimeFirstPrint" units="ms" + expires_after="2024-03-14"> + <owner>thestig@chromium.org</owner> + <owner>awscreen@chromium.org</owner> + <summary> + Time from when print preview is initiated until the initial preview is sent + to the preview tab for rendering. Only captured for the very first print + preview request since the browser started. This metric will not be captured + if the user cancels out of the first print preview before the result is + ready for rendering. + </summary> +</histogram> + <histogram name="PrintPreview.InitializationTime" units="ms" expires_after="never"> <!-- expires-never: Monitors printing system health. -->
diff --git a/tools/metrics/histograms/metadata/sb_client/histograms.xml b/tools/metrics/histograms/metadata/sb_client/histograms.xml index 4f1c72f..b119193 100644 --- a/tools/metrics/histograms/metadata/sb_client/histograms.xml +++ b/tools/metrics/histograms/metadata/sb_client/histograms.xml
@@ -286,15 +286,19 @@ </summary> </histogram> -<histogram name="SBClientDownload.ServerRequestsDeepScanningPrompt" +<histogram name="SBClientDownload.ServerRequestsDeepScanningPrompt{Encryption}" enum="BooleanRequested" expires_after="2024-04-28"> <owner>drubery@chromium.org</owner> <owner>chrome-counter-abuse-alerts@google.com</owner> <summary> Records how often users in a population consented to deep scanning are - actually prompted for deep scanning. This is logged once per download by an - eligible user. + actually prompted for deep scanning of {Encryption}. This is logged once per + download by an eligible user. </summary> + <token key="Encryption"> + <variant name="" summary="any file"/> + <variant name="PasswordProtected" summary="encrypted archives"/> + </token> </histogram> <histogram name="SBClientDownload.ServerRequestsLocalDecryptionPrompt"
diff --git a/tools/metrics/histograms/metadata/security/histograms.xml b/tools/metrics/histograms/metadata/security/histograms.xml index bd90e047..e4e93338 100644 --- a/tools/metrics/histograms/metadata/security/histograms.xml +++ b/tools/metrics/histograms/metadata/security/histograms.xml
@@ -758,7 +758,7 @@ </histogram> <histogram name="SiteIsolation.BrowsingInstance.MaxCountPerProcess" - units="units" expires_after="2023-12-18"> + units="units" expires_after="2024-05-19"> <owner>wjmaclean@chromium.org</owner> <owner>creis@chromium.org</owner> <summary>
diff --git a/tools/perf/contrib/vr_benchmarks/BUILD.gn b/tools/perf/contrib/vr_benchmarks/BUILD.gn index 92c8526..962b42349 100644 --- a/tools/perf/contrib/vr_benchmarks/BUILD.gn +++ b/tools/perf/contrib/vr_benchmarks/BUILD.gn
@@ -26,12 +26,6 @@ data_deps = [ "//testing:run_perf_test" ] if (is_android) { - data += [ - "//chrome/android/shared_preference_files/test/", - "//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk", - "//third_party/gvr-android-sdk/test-apks/vr_keyboard/vr_keyboard_current.apk", - ] - data_deps += [ "//chrome/android:monochrome_public_bundle" ] }
diff --git a/tools/perf/contrib/vr_benchmarks/shared_vr_page_state.py b/tools/perf/contrib/vr_benchmarks/shared_vr_page_state.py index f8ae1d7..671f019 100644 --- a/tools/perf/contrib/vr_benchmarks/shared_vr_page_state.py +++ b/tools/perf/contrib/vr_benchmarks/shared_vr_page_state.py
@@ -2,22 +2,14 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import logging import os -import time from core import path_util path_util.AddAndroidPylibToPath() -from pylib.utils import shared_preference_utils from telemetry.core import android_platform from telemetry.core import util from telemetry.page import shared_page_state from contrib.vr_benchmarks.desktop_runtimes import openxr_runtimes - -CARDBOARD_PATH = os.path.join('chrome', 'android', 'shared_preference_files', - 'test', 'vr_cardboard_skipdon_setupcomplete.json') - - class SharedVrPageStateFactory(shared_page_state.SharedPageState): """"Factory" for picking the correct SharedVrPageState subclass. @@ -87,55 +79,7 @@ def __init__(self, test, finder_options, story_set, possible_browser=None): super(AndroidSharedVrPageState, self).__init__( test, finder_options, story_set, possible_browser) - if self._finder_options.remove_system_vrcore: - self._RemoveSystemVrCore() - if not self._finder_options.disable_vrcore_install: - self._InstallVrCore() - self._ConfigureVrCore(os.path.join(path_util.GetChromiumSrcDir(), - self._finder_options.shared_prefs_file)) self._InstallNfcApk() - if not self._finder_options.disable_keyboard_install: - self._InstallKeyboardApk() - - def _RemoveSystemVrCore(self): - # Import done here since importing Devil on Windows breaks the Telemetry - # unittests. - from devil.android import forwarder # pylint: disable=import-error,import-outside-toplevel - # Close the existing network controller since RemoveSystemPackages could - # potentially reboot the device, which breaks the existing port forwarding - # and makes it impossible to cleanly re-establish it if the network - # controller is still running. - self.platform.network_controller.Close() - self.platform.RemoveSystemPackages(['com.google.vr.vrcore']) - # Re-open the network controller, which in turn re-establishes the adb - # forwarding necessary for the local server to work. Since port forwarding - # often refuses to work for a short period after rebooting, try several - # times. - for _ in range(5): - try: - self.platform.network_controller.Open(self.wpr_mode) - break - except forwarder.HostForwarderError: - logging.error( - 'Failed to open network controller, will retry after a short nap') - time.sleep(5) - - def _InstallVrCore(self): - """Installs the VrCore APK.""" - self.platform.InstallApplication( - os.path.join(path_util.GetChromiumSrcDir(), 'third_party', - 'gvr-android-sdk', 'test-apks', 'vr_services', - 'vr_services_current.apk')) - - def _ConfigureVrCore(self, filepath): - """Configures VrCore using the provided settings file.""" - settings = shared_preference_utils.ExtractSettingsFromJson(filepath) - for setting in settings: - shared_pref = self.platform.GetSharedPrefs( - setting['package'], setting['filename'], - use_encrypted_path=setting.get('supports_encrypted_path', False)) - shared_preference_utils.ApplySharedPreferenceSetting( - shared_pref, setting) def _InstallNfcApk(self): """Installs the APK that allows VR tests to simulate a headset NFC scan.""" @@ -155,26 +99,11 @@ self.platform.InstallApplication( os.path.join(chromium_root, newest_apk_path)) - def _InstallKeyboardApk(self): - """Installs the VR Keyboard APK.""" - self.platform.InstallApplication( - os.path.join(path_util.GetChromiumSrcDir(), 'third_party', - 'gvr-android-sdk', 'test-apks', 'vr_keyboard', - 'vr_keyboard_current.apk')) - def WillRunStory(self, story): super(AndroidSharedVrPageState, self).WillRunStory(story) if not self._finder_options.disable_screen_reset: self._CycleScreen() - def TearDownState(self): - super(AndroidSharedVrPageState, self).TearDownState() - # Re-apply Cardboard as the viewer to leave the device in a consistent - # state after a benchmark run - # TODO(bsheedy): Remove this after crbug.com/772969 is fixed - self._ConfigureVrCore(os.path.join(path_util.GetChromiumSrcDir(), - CARDBOARD_PATH)) - def _CycleScreen(self): """Cycles the screen off then on.
diff --git a/tools/perf/contrib/vr_benchmarks/vr_benchmarks.py b/tools/perf/contrib/vr_benchmarks/vr_benchmarks.py index e65de1c..75535d6 100644 --- a/tools/perf/contrib/vr_benchmarks/vr_benchmarks.py +++ b/tools/perf/contrib/vr_benchmarks/vr_benchmarks.py
@@ -30,13 +30,6 @@ @classmethod def AddBenchmarkCommandLineArgs(cls, parser): parser.add_option( - '--shared-prefs-file', - help='The path relative to the Chromium source root ' - 'to a file containing a JSON list of shared ' - 'preference files to edit and how to do so. ' - 'See examples in //chrome/android/' - 'shared_preference_files/test/') - parser.add_option( '--disable-screen-reset', action='store_true', default=False, @@ -45,28 +38,6 @@ 'screen leads to locking the phone, which makes Telemetry ' 'not produce valid results.') parser.add_option( - '--disable-vrcore-install', - action='store_true', - default=False, - help='Disables the automatic installation of VrCore during pre-test ' - 'setup. This is useful for local testing on Pixel devices that ' - 'haven\'t had VrCore removed as a system app.') - parser.add_option( - '--disable-keyboard-install', - action='store_true', - default=False, - help='Disables the automatic installation of the VR keybaord during ' - 'pre-test setup. This is useful for local testing if you want ' - 'to use whatever version is already installed on the device ' - 'instead of installing whatever is in the test APKs directory.') - parser.add_option( - '--remove-system-vrcore', - action='store_true', - default=False, - help='Removes the system version of VrCore if it is installed. This ' - 'is required if the system version is not already removed and ' - '--disable-vrcore-install is not passed.') - parser.add_option( '--recording-wpr', action='store_true', default=False,
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json index 33546675..d4bb76c 100644 --- a/tools/perf/core/perfetto_binary_roller/binary_deps.json +++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -6,23 +6,23 @@ }, "win": { "hash": "88c5f875c7ce8c8ba796d9768aec9c0bdedb985e", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/3cee91476cdf8bb14facf7b8208fe2ba6a2ad5d8/trace_processor_shell.exe" + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/1817225b10713aae101b4eb5fe9ad89712402736/trace_processor_shell.exe" }, "linux_arm": { "hash": "8aa911491cd365131216862ae495e18424ebe1b2", "full_remote_path": "perfetto-luci-artifacts/3e53e144bee271ec558363df2e561a77d7e0b789/linux-arm/trace_processor_shell" }, "mac": { - "hash": "5a0aeeb52dcf65075d1df9e5f9628b2898fdb14f", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/3cee91476cdf8bb14facf7b8208fe2ba6a2ad5d8/trace_processor_shell" + "hash": "d7bd426ca1822cb7f18d13fb5b009324eead0fdd", + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/d6dd1afcbdccd18eff2a5992ad7eedaef4a6b4c6/trace_processor_shell" }, "mac_arm64": { "hash": "28d38c5eef93cf965ad3b3c656d4419f8e55f864", "full_remote_path": "perfetto-luci-artifacts/3e53e144bee271ec558363df2e561a77d7e0b789/mac-arm64/trace_processor_shell" }, "linux": { - "hash": "ef1efbb2642f7862bb60bad96835d96f68d6699a", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/3cee91476cdf8bb14facf7b8208fe2ba6a2ad5d8/trace_processor_shell" + "hash": "a63b8e4770a5bda0e4701c59461dda1454bcfa3b", + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/d6dd1afcbdccd18eff2a5992ad7eedaef4a6b4c6/trace_processor_shell" } }, "power_profile.sql": {
diff --git a/tools/perf/process_perf_results.pydeps b/tools/perf/process_perf_results.pydeps index 5809919..d30d042d 100644 --- a/tools/perf/process_perf_results.pydeps +++ b/tools/perf/process_perf_results.pydeps
@@ -6,7 +6,6 @@ ../../build/android/pylib/utils/__init__.py ../../build/android/pylib/utils/decorators.py ../../build/android/pylib/utils/logdog_helper.py -../../build/android/pylib/utils/shared_preference_utils.py ../../components/variations/service/generate_ui_string_overrider.py ../../third_party/catapult/common/py_trace_event/py_trace_event/__init__.py ../../third_party/catapult/common/py_trace_event/py_trace_event/trace_event.py
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml index f7dd60fa..a4d1e3f7 100644 --- a/tools/traffic_annotation/summary/annotations.xml +++ b/tools/traffic_annotation/summary/annotations.xml
@@ -74,7 +74,7 @@ <item id="drive_service" added_in_milestone="90" content_hash_code="059e2023" os_list="linux,windows,chromeos" file_path="chrome/browser/new_tab_page/modules/drive/drive_service.cc" /> <item id="early_hints_preload" added_in_milestone="91" content_hash_code="028fe27a" os_list="linux,windows,chromeos,android" file_path="content/browser/loader/navigation_early_hints_manager.cc" /> <item id="enterprise_safe_browsing_realtime_url_lookup" added_in_milestone="86" content_hash_code="00d66dca" os_list="linux,windows,chromeos" file_path="chrome/browser/safe_browsing/chrome_enterprise_url_lookup_service.cc" /> - <item id="extension_blacklist" added_in_milestone="62" content_hash_code="005cb431" os_list="linux,windows,chromeos" file_path="chrome/browser/extensions/blocklist_state_fetcher.cc" /> + <item id="extension_blacklist" added_in_milestone="62" content_hash_code="06f7911b" os_list="linux,windows,chromeos" file_path="chrome/browser/extensions/blocklist_state_fetcher.cc" /> <item id="extension_crx_fetcher" added_in_milestone="62" content_hash_code="05d3e86d" os_list="linux,windows,chromeos" file_path="extensions/browser/updater/extension_downloader.cc" /> <item id="extension_install_signer" added_in_milestone="62" content_hash_code="065c4bce" os_list="linux,windows,chromeos" file_path="chrome/browser/extensions/install_signer.cc" /> <item id="extension_manifest_fetcher" added_in_milestone="62" content_hash_code="05983aa9" os_list="linux,windows,chromeos" file_path="extensions/browser/updater/extension_downloader.cc" />
diff --git a/tools/typescript/definitions/autofill_private.d.ts b/tools/typescript/definitions/autofill_private.d.ts index dd8e367..011463c 100644 --- a/tools/typescript/definitions/autofill_private.d.ts +++ b/tools/typescript/definitions/autofill_private.d.ts
@@ -21,7 +21,7 @@ * This enum must be kept in sync with: * components/autofill/core/browser/field_types.h. */ - export enum ServerFieldType { + export enum FieldType { NO_SERVER_DATA, UNKNOWN_TYPE, EMPTY_TYPE, @@ -136,7 +136,7 @@ } export interface AddressField { - type: ServerFieldType; + type: FieldType; value: string|undefined; } @@ -155,7 +155,7 @@ } export interface AddressComponent { - field: ServerFieldType; + field: FieldType; fieldName: string; isLongField: boolean; isRequired: boolean;
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc index 9c41aa2..2442fb1 100644 --- a/ui/accessibility/platform/ax_platform_node_win.cc +++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -7954,6 +7954,8 @@ return UIA_SelectionItem_ElementAddedToSelectionEventId; case ax::mojom::Event::kSelectionRemove: return UIA_SelectionItem_ElementRemovedFromSelectionEventId; + case ax::mojom::Event::kTextSelectionChanged: + return UIA_Text_TextSelectionChangedEventId; case ax::mojom::Event::kTooltipClosed: return UIA_ToolTipClosedEventId; case ax::mojom::Event::kTooltipOpened:
diff --git a/ui/file_manager/file_manager/foreground/js/actions_model.ts b/ui/file_manager/file_manager/foreground/js/actions_model.ts index 35eba40..a6b6828 100644 --- a/ui/file_manager/file_manager/foreground/js/actions_model.ts +++ b/ui/file_manager/file_manager/foreground/js/actions_model.ts
@@ -17,7 +17,7 @@ import {constants} from './constants.js'; import type {FolderShortcutsDataModel} from './folder_shortcuts_data_model.js'; import type {MetadataModel} from './metadata/metadata_model.js'; -import type {ActionModelUI} from './ui/action_model_ui.js'; +import type {ActionModelUi} from './ui/action_model_ui.js'; type ActionsMap = Partial<Record<CommonActionId|InternalActionId|string, Action>>; @@ -106,12 +106,12 @@ class DriveToggleOfflineAction implements Action { constructor( private entries_: Array<Entry|FilesAppEntry>, - private metadataModel_: MetadataModel, private ui_: ActionModelUI, + private metadataModel_: MetadataModel, private ui_: ActionModelUi, private value_: boolean, private onExecute_: VoidCallback) {} static create( entries: Array<Entry|FilesAppEntry>, metadataModel: MetadataModel, - ui: ActionModelUI, value: boolean, onExecute: VoidCallback) { + ui: ActionModelUi, value: boolean, onExecute: VoidCallback) { const actionableEntries = entries.filter( entry => metadataModel.getCache([entry], ['pinned'])[0]?.pinned !== value); @@ -398,7 +398,7 @@ private volumeManager_: VolumeManager, private metadataModel_: MetadataModel, private shortcutsModel_: FolderShortcutsDataModel, - private ui_: ActionModelUI, + private ui_: ActionModelUi, private entries_: Array<Entry|FilesAppEntry>) { super(); }
diff --git a/ui/file_manager/file_manager/foreground/js/actions_model_unittest.ts b/ui/file_manager/file_manager/foreground/js/actions_model_unittest.ts index 935157aa..f8e4f38 100644 --- a/ui/file_manager/file_manager/foreground/js/actions_model_unittest.ts +++ b/ui/file_manager/file_manager/foreground/js/actions_model_unittest.ts
@@ -16,7 +16,7 @@ import {FolderShortcutsDataModel} from './folder_shortcuts_data_model.js'; import {MetadataModel} from './metadata/metadata_model.js'; import {MockMetadataModel} from './metadata/mock_metadata.js'; -import {ActionModelUI} from './ui/action_model_ui.js'; +import {ActionModelUi} from './ui/action_model_ui.js'; import {FilesAlertDialog} from './ui/files_alert_dialog.js'; import {ListContainer} from './ui/list_container.js'; @@ -64,7 +64,7 @@ return model as unknown as FolderShortcutsDataModel; } -class MockUi implements ActionModelUI { +class MockUi implements ActionModelUi { listContainer: ListContainer; alertDialog: FilesAlertDialog;
diff --git a/ui/file_manager/file_manager/foreground/js/fake_file_selection_handler.js b/ui/file_manager/file_manager/foreground/js/fake_file_selection_handler.js deleted file mode 100644 index a5c0df1..0000000 --- a/ui/file_manager/file_manager/foreground/js/fake_file_selection_handler.js +++ /dev/null
@@ -1,74 +0,0 @@ -// Copyright 2019 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import {NativeEventTarget as EventTarget} from 'chrome://resources/ash/common/event_target.js'; - -import {FilesAppEntry} from '../../externs/files_app_entry_interfaces.js'; -import {Store} from '../../externs/ts/store.js'; -import {updateDirectoryContent, updateSelection} from '../../state/ducks/current_directory.js'; - -// @ts-ignore: error TS6133: 'FileSelectionHandler' is declared but its value is -// never read. -import {FileSelection, FileSelectionHandler} from './file_selection.js'; - -/** - * Mock FileSelectionHandler. - * @extends {FileSelectionHandler} - */ -export class FakeFileSelectionHandler { - constructor() { - this.selection = /** @type {!FileSelection} */ ({}); - this.updateSelection([], []); - this.eventTarget_ = new EventTarget(); - } - - computeAdditionalCallback() {} - - /** - * @param entries {!Array<Entry|FilesAppEntry>} - * @param mimeTypes {!Array<string>} - * @param store {Store=} - */ - // @ts-ignore: error TS2322: Type 'null' is not assignable to type 'Store | - // undefined'. - updateSelection(entries, mimeTypes, store = null) { - this.selection = /** @type {!FileSelection} */ ({ - entries: entries, - mimeTypes: mimeTypes, - // @ts-ignore: error TS6133: 'metadataModel' is declared but its value is - // never read. - computeAdditional: (metadataModel) => { - this.computeAdditionalCallback(); - return new Promise((resolve) => { - // @ts-ignore: error TS2810: Expected 1 argument, but got 0. 'new - // Promise()' needs a JSDoc hint to produce a 'resolve' that can be - // called without arguments. - resolve(); - }); - }, - }); - - if (store) { - // Make sure that the entry is in the directory content. - store.dispatch(updateDirectoryContent({entries})); - // Mark the entry as selected. - store.dispatch(updateSelection({ - selectedKeys: entries.map(e => e.toURL()), - entries, - })); - } - } - - // @ts-ignore: error TS7019: Rest parameter 'args' implicitly has an 'any[]' - // type. - addEventListener(...args) { - // @ts-ignore: error TS2556: A spread argument must either have a tuple type - // or be passed to a rest parameter. - return this.eventTarget_.addEventListener(...args); - } - - isAvailable() { - return true; - } -}
diff --git a/ui/file_manager/file_manager/foreground/js/fake_file_selection_handler.ts b/ui/file_manager/file_manager/foreground/js/fake_file_selection_handler.ts new file mode 100644 index 0000000..1b6a5ae --- /dev/null +++ b/ui/file_manager/file_manager/foreground/js/fake_file_selection_handler.ts
@@ -0,0 +1,69 @@ +// 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 {NativeEventTarget as EventTarget} from 'chrome://resources/ash/common/event_target.js'; + +import {MockVolumeManager} from '../../background/js/mock_volume_manager.js'; +import {AllowedPaths} from '../../common/js/volume_manager_types.js'; +import type {FilesAppEntry} from '../../externs/files_app_entry_interfaces.js'; +import type {Store} from '../../externs/ts/store.js'; +import {updateDirectoryContent, updateSelection} from '../../state/ducks/current_directory.js'; + +import {type FileSelection, FileSelectionHandler} from './file_selection.js'; +import type {MetadataModel} from './metadata/metadata_model.js'; +import {MockMetadataModel} from './metadata/mock_metadata.js'; +import {createFakeDirectoryModel} from './mock_directory_model.js'; +import type {ListContainer} from './ui/list_container.js'; + +/** + * Mock FileSelectionHandler. + */ +export class FakeFileSelectionHandler extends FileSelectionHandler { + private eventTarget_ = new EventTarget(); + + constructor() { + super( + createFakeDirectoryModel(), + document.createElement('div') as unknown as ListContainer, + new MockMetadataModel({}) as unknown as MetadataModel, + new MockVolumeManager(), + AllowedPaths.ANY_PATH, + ); + this.selection = {} as FileSelection; + this.updateSelection([], []); + } + + computeAdditionalCallback() {} + + updateSelection( + entries: Array<Entry|FilesAppEntry>, mimeTypes: string[], store?: Store) { + this.selection = { + entries: entries, + mimeTypes: mimeTypes, + computeAdditional: async (_metadataModel) => { + this.computeAdditionalCallback(); + return Promise.resolve(true); + }, + } as FileSelection; + + if (store) { + // Make sure that the entry is in the directory content. + store.dispatch(updateDirectoryContent({entries})); + // Mark the entry as selected. + store.dispatch(updateSelection({ + selectedKeys: entries.map(e => e.toURL()), + entries, + })); + } + } + + override addEventListener(...args: any[]) { + return this.eventTarget_.addEventListener( + ...args as Parameters<EventTarget['addEventListener']>); + } + + override isAvailable() { + return true; + } +}
diff --git a/ui/file_manager/file_manager/foreground/js/file_selection.ts b/ui/file_manager/file_manager/foreground/js/file_selection.ts index 23b5b79..0947ea3 100644 --- a/ui/file_manager/file_manager/foreground/js/file_selection.ts +++ b/ui/file_manager/file_manager/foreground/js/file_selection.ts
@@ -2,10 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import {dispatchSimpleEvent} from 'chrome://resources/ash/common/cr_deprecated.js'; -import {NativeEventTarget as EventTarget} from 'chrome://resources/ash/common/event_target.js'; - import {isEncrypted} from '../../common/js/file_type.js'; +import {CustomEventMap, FilesEventTarget} from '../../common/js/files_event_target.js'; import {isDlpEnabled} from '../../common/js/flags.js'; import {AllowedPaths} from '../../common/js/volume_manager_types.js'; import type {FilesAppEntry} from '../../externs/files_app_entry_interfaces.js'; @@ -95,10 +93,19 @@ } } +export type FileSelectionChangeEvent = CustomEvent<{}>; +export type FileSelectionChangeThrottledEvent = CustomEvent<{}>; + +interface FileSelectionHandlerEventMap extends CustomEventMap { + [EventType.CHANGE]: FileSelectionChangeEvent; + [EventType.CHANGE_THROTTLED]: FileSelectionChangeThrottledEvent; +} + /** * This object encapsulates everything related to current selection. */ -export class FileSelectionHandler extends EventTarget { +export class FileSelectionHandler extends + FilesEventTarget<FileSelectionHandlerEventMap> { selection = new FileSelection([], [], this.volumeManager_); private selectionUpdateTimer_: number|null = 0; private store_: Store = getStore(); @@ -164,7 +171,7 @@ this.updateFileSelectionAsync_(selection); }, updateDelay); - dispatchSimpleEvent(this, EventType.CHANGE); + this.dispatchEvent(new CustomEvent(EventType.CHANGE)); } /** @@ -184,7 +191,7 @@ } this.nextThrottledEventTime_ = Date.now() + UPDATE_DELAY; - dispatchSimpleEvent(this, EventType.CHANGE_THROTTLED); + this.dispatchEvent(new CustomEvent(EventType.CHANGE_THROTTLED)); }); }
diff --git a/ui/file_manager/file_manager/foreground/js/mock_directory_model.ts b/ui/file_manager/file_manager/foreground/js/mock_directory_model.ts index 84c2f7d..2c547dc1 100644 --- a/ui/file_manager/file_manager/foreground/js/mock_directory_model.ts +++ b/ui/file_manager/file_manager/foreground/js/mock_directory_model.ts
@@ -59,20 +59,14 @@ return undefined; } - /** - */ getCurrentVolumeInfo(): VolumeInfo|null { return null; } - /** - */ getCurrentRootType(): RootType|null { return null; } - /** - */ getFileList(): FileListModel|null { return null; } @@ -93,6 +87,10 @@ isReadOnly() { return false; } + + getFileListSelection() { + return new EventTarget(); + } } return new FakeDirectoryModel() as unknown as DirectoryModel;
diff --git a/ui/file_manager/file_manager/foreground/js/ui/action_model_ui.js b/ui/file_manager/file_manager/foreground/js/ui/action_model_ui.js deleted file mode 100644 index 51b09b2..0000000 --- a/ui/file_manager/file_manager/foreground/js/ui/action_model_ui.js +++ /dev/null
@@ -1,17 +0,0 @@ -// Copyright 2019 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import {FilesAlertDialog} from './files_alert_dialog.js'; -import {ListContainer} from './list_container.js'; - -/** @interface */ -export class ActionModelUI { - constructor() { - /** @type {!FilesAlertDialog} */ - this.alertDialog; - - /** @type {!ListContainer} */ - this.listContainer; - } -}
diff --git a/ui/file_manager/file_manager/foreground/js/ui/action_model_ui.ts b/ui/file_manager/file_manager/foreground/js/ui/action_model_ui.ts new file mode 100644 index 0000000..71cddc3 --- /dev/null +++ b/ui/file_manager/file_manager/foreground/js/ui/action_model_ui.ts
@@ -0,0 +1,11 @@ +// 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 {FilesAlertDialog} from './files_alert_dialog.js'; +import {ListContainer} from './list_container.js'; + +export interface ActionModelUi { + alertDialog: FilesAlertDialog; + listContainer: ListContainer; +}
diff --git a/ui/file_manager/file_manager/foreground/js/ui/providers_menu.js b/ui/file_manager/file_manager/foreground/js/ui/providers_menu.js deleted file mode 100644 index 4fa0c155..0000000 --- a/ui/file_manager/file_manager/foreground/js/ui/providers_menu.js +++ /dev/null
@@ -1,118 +0,0 @@ -// Copyright 2015 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import {crInjectTypeAndInit} from '../../../common/js/cr_ui.js'; -import {iconSetToCSSBackgroundImageValue} from '../../../common/js/util.js'; -import {ProvidersModel} from '../providers_model.js'; - -import {FilesMenuItem} from './files_menu.js'; -import {Menu} from './menu.js'; - -/** - * Fills out the menu for mounting or installing new providers. - */ -export class ProvidersMenu { - /** - * @param {!ProvidersModel} model - * @param {!Menu} menu - */ - constructor(model, menu) { - /** - * @private @type {!ProvidersModel}} - * @const - */ - this.model_ = model; - - /** - * @private @type {!Menu} - * @const - */ - this.menu_ = menu; - - // @ts-ignore: error TS2339: Property 'addEventListener' does not exist on - // type 'Menu'. - this.menu_.addEventListener('update', this.onUpdate_.bind(this)); - } - - /** - * @private - */ - clearProviders_() { - // @ts-ignore: error TS2339: Property 'firstChild' does not exist on type - // 'Menu'. - while (this.menu_.firstChild) { - // @ts-ignore: error TS2339: Property 'lastChild' does not exist on type - // 'Menu'. - this.menu_.removeChild(this.menu_.lastChild); - } - } - - /** - * @return {!FilesMenuItem} - * @private - */ - addMenuItem_() { - // @ts-ignore: error TS2339: Property 'addMenuItem' does not exist on type - // 'Menu'. - const menuItem = this.menu_.addMenuItem({}); - crInjectTypeAndInit(/** @type {!HTMLElement} */ (menuItem), FilesMenuItem); - return /** @type {!FilesMenuItem} */ (menuItem); - } - - /** - * @param {string} providerId ID of the provider. - * @param {!chrome.fileManagerPrivate.IconSet} iconSet Set of icons for the - * provider. - * @param {string} name Already localized name of the provider. - * @private - */ - addProvider_(providerId, iconSet, name) { - const item = this.addMenuItem_(); - item.label = name; - - const iconImage = iconSetToCSSBackgroundImageValue(iconSet); - if (iconImage === 'none' && providerId === '@smb') { - item.iconStartFileType = 'smb'; - } else { - item.iconStartImage = iconImage; - } - - item.addEventListener( - 'activate', this.onItemActivate_.bind(this, providerId)); - } - - /** - * @param {!Event} event - * @private - */ - // @ts-ignore: error TS6133: 'event' is declared but its value is never read. - onUpdate_(event) { - this.model_.getMountableProviders().then(providers => { - this.clearProviders_(); - providers.forEach(provider => { - this.addProvider_(provider.providerId, provider.iconSet, provider.name); - }); - }); - } - - /** - * @param {string} providerId - * @param {!Event} event - * @private - */ - // @ts-ignore: error TS6133: 'event' is declared but its value is never read. - onItemActivate_(providerId, event) { - this.model_.requestMount(providerId); - } - - /** - * Sends an 'update' event to the sub menu to trigger - * a reload of its content. - */ - updateSubMenu() { - const updateEvent = new Event('update'); - // @ts-ignore - this.menu_.dispatchEvent(updateEvent); - } -}
diff --git a/ui/file_manager/file_manager/foreground/js/ui/providers_menu.ts b/ui/file_manager/file_manager/foreground/js/ui/providers_menu.ts new file mode 100644 index 0000000..102d42c --- /dev/null +++ b/ui/file_manager/file_manager/foreground/js/ui/providers_menu.ts
@@ -0,0 +1,72 @@ +// Copyright 2015 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import {crInjectTypeAndInit} from '../../../common/js/cr_ui.js'; +import {iconSetToCSSBackgroundImageValue} from '../../../common/js/util.js'; +import {ProvidersModel} from '../providers_model.js'; + +import {FilesMenuItem} from './files_menu.js'; +import {Menu} from './menu.js'; + +/** Fills out the menu for mounting or installing new providers. */ +export class ProvidersMenu { + constructor( + private readonly model_: ProvidersModel, private readonly menu_: Menu) { + this.menu_.addEventListener('update', this.onUpdate_.bind(this)); + } + + private clearProviders_() { + while (this.menu_.lastChild) { + this.menu_.removeChild(this.menu_.lastChild); + } + } + + private addMenuItem_(): FilesMenuItem { + const menuItem = this.menu_.addMenuItem({}); + crInjectTypeAndInit(menuItem, FilesMenuItem); + return menuItem as FilesMenuItem; + } + + /** + * @param providerId ID of the provider. + * @param iconSet Set of icons for the provider. + * @param name Already localized name of the provider. + */ + private addProvider_( + providerId: string, iconSet: chrome.fileManagerPrivate.IconSet, + name: string) { + const item = this.addMenuItem_(); + item.label = name; + + const iconImage = iconSetToCSSBackgroundImageValue(iconSet); + if (iconImage === 'none' && providerId === '@smb') { + item.iconStartFileType = 'smb'; + } else { + item.iconStartImage = iconImage; + } + + item.addEventListener( + 'activate', this.onItemActivate_.bind(this, providerId)); + } + + private onUpdate_(_event: Event) { + this.model_.getMountableProviders().then(providers => { + this.clearProviders_(); + providers.forEach(provider => { + this.addProvider_(provider.providerId, provider.iconSet, provider.name); + }); + }); + } + + private onItemActivate_(providerId: string, _event: Event) { + this.model_.requestMount(providerId); + } + + /** + * Sends an update event to the sub menu to trigger a reload of its content. + */ + updateSubMenu() { + this.menu_.dispatchEvent(new Event('update')); + } +}
diff --git a/ui/file_manager/file_names.gni b/ui/file_manager/file_names.gni index 15ecc59..7abe8daa 100644 --- a/ui/file_manager/file_names.gni +++ b/ui/file_manager/file_names.gni
@@ -31,7 +31,6 @@ # Files app Foreground: "file_manager/foreground/js/app_state_controller.js", "file_manager/foreground/js/constants.js", - "file_manager/foreground/js/fake_file_selection_handler.js", "file_manager/foreground/js/file_manager.js", "file_manager/foreground/js/metrics_start.js", "file_manager/foreground/js/mock_navigation_list_model.js", @@ -42,7 +41,6 @@ # Files app UI: "file_manager/foreground/js/ui/a11y_announce.js", - "file_manager/foreground/js/ui/action_model_ui.js", "file_manager/foreground/js/ui/actions_submenu.js", "file_manager/foreground/js/ui/context_menu_handler.js", "file_manager/foreground/js/ui/default_task_dialog.js", @@ -53,7 +51,6 @@ "file_manager/foreground/js/ui/file_tap_handler.js", "file_manager/foreground/js/ui/gear_menu.js", "file_manager/foreground/js/ui/install_linux_package_dialog.js", - "file_manager/foreground/js/ui/providers_menu.js", "file_manager/foreground/js/ui/tree.js", ] @@ -175,6 +172,7 @@ # Don't remove this. # These lines will be removed at the end of the TS migration. # Foreground UI. + "file_manager/foreground/js/ui/action_model_ui.ts", "file_manager/foreground/js/ui/dialogs.ts", "file_manager/foreground/js/ui/commandbutton.ts", "file_manager/foreground/js/ui/combobutton.ts", @@ -202,6 +200,7 @@ "file_manager/foreground/js/ui/multi_menu_button.ts", "file_manager/foreground/js/ui/position_util.ts", "file_manager/foreground/js/ui/progress_center_panel.ts", + "file_manager/foreground/js/ui/providers_menu.ts", "file_manager/foreground/js/ui/splitter.ts", "file_manager/foreground/js/ui/table/table_column.ts", "file_manager/foreground/js/ui/table/table_column_model.ts", @@ -507,8 +506,8 @@ # Don't remove this. # These lines will be removed at the end of the TS migration. # Foreground: - "file_manager/foreground/elements/files_tooltip_unittest.ts", "file_manager/foreground/elements/files_toast_unittest.ts", + "file_manager/foreground/elements/files_tooltip_unittest.ts", "file_manager/foreground/elements/files_xf_elements_unittest.ts", "file_manager/foreground/js/actions_model_unittest.ts", "file_manager/foreground/js/banner_controller_unittest.ts", @@ -516,17 +515,18 @@ "file_manager/foreground/js/directory_contents_unittest.ts", "file_manager/foreground/js/directory_model_unittest.ts", "file_manager/foreground/js/empty_folder_controller_unittest.ts", + "file_manager/foreground/js/fake_file_selection_handler.ts", "file_manager/foreground/js/file_list_model_unittest.ts", "file_manager/foreground/js/file_manager_commands_unittest.ts", "file_manager/foreground/js/file_tasks_unittest.ts", "file_manager/foreground/js/file_transfer_controller_unittest.ts", "file_manager/foreground/js/file_type_filters_controller_unittest.ts", "file_manager/foreground/js/list_thumbnail_loader_unittest.ts", - "file_manager/foreground/js/path_component_unittest.ts", - "file_manager/foreground/js/task_controller_unittest.ts", "file_manager/foreground/js/metadata/dlp_metadata_provider_unittest.ts", + "file_manager/foreground/js/path_component_unittest.ts", "file_manager/foreground/js/providers_model_unittest.ts", "file_manager/foreground/js/spinner_controller_unittest.ts", + "file_manager/foreground/js/task_controller_unittest.ts", "file_manager/foreground/js/thumbnail_loader_unittest.ts", # 3-line header to avoid conflict.
diff --git a/ui/file_manager/integration_tests/file_manager/page_objects/directory_tree.js b/ui/file_manager/integration_tests/file_manager/page_objects/directory_tree.js index b5a2f90..feb04d5 100644 --- a/ui/file_manager/integration_tests/file_manager/page_objects/directory_tree.js +++ b/ui/file_manager/integration_tests/file_manager/page_objects/directory_tree.js
@@ -137,6 +137,24 @@ } /** + * Wait for the tree item with the label to be focusable (aka "selected" in + * the old tree implementation). + * + * @param {string} label Label of the tree item + * @return {!Promise<!ElementObject>} + */ + async waitForFocusableItemByLabel(label) { + if (this.isNewTree) { + return this.remoteCall_.waitForElement( + // Go inside shadow DOM to check tabindex. + this.appId_, + [this.selectors_.itemByLabel(label), 'li[tabindex="0"]']); + } + return this.remoteCall_.waitForElement( + this.appId_, this.selectors_.itemByLabel(label, {focused: true})); + } + + /** * Wait for the tree item with the type to have focused (aka "selected" in the * old tree implementation) state. *
diff --git a/ui/file_manager/integration_tests/file_manager/recents.js b/ui/file_manager/integration_tests/file_manager/recents.js index 89e1f069..340c719 100644 --- a/ui/file_manager/integration_tests/file_manager/recents.js +++ b/ui/file_manager/integration_tests/file_manager/recents.js
@@ -523,9 +523,7 @@ // Check: The directory should be highlighted in the directory tree. const directoryTree = await DirectoryTreePageObject.create(appId, remoteCall); await directoryTree.waitForSelectedItemByLabel('C'); - // Focus on the tree first before using the ":focus" selector below. - await directoryTree.focusTree(); - await directoryTree.waitForFocusedItemByLabel('C'); + await directoryTree.waitForFocusableItemByLabel('C'); }; /**
diff --git a/ui/file_manager/integration_tests/file_manager/search.js b/ui/file_manager/integration_tests/file_manager/search.js index 1945bf0e..e880e11 100644 --- a/ui/file_manager/integration_tests/file_manager/search.js +++ b/ui/file_manager/integration_tests/file_manager/search.js
@@ -284,9 +284,7 @@ // directory that contains query-matched files (*.gdoc). const directoryTree = await DirectoryTreePageObject.create(appId, remoteCall); await directoryTree.waitForSelectedItemByLabel('My Drive'); - // Focus on the tree before using ":focus" to check the tree item focus. - await directoryTree.focusTree(); - await directoryTree.waitForFocusedItemByLabel('My Drive'); + await directoryTree.waitForFocusableItemByLabel('My Drive'); // Check: Query-matched files should be shown in the files list. await remoteCall.waitForFiles(appId, TestEntryInfo.getExpectedRows([
diff --git a/ui/gfx/win/window_impl.cc b/ui/gfx/win/window_impl.cc index e710e0c..6762902d 100644 --- a/ui/gfx/win/window_impl.cc +++ b/ui/gfx/win/window_impl.cc
@@ -8,6 +8,7 @@ #include "base/at_exit.h" #include "base/debug/alias.h" +#include "base/debug/dump_without_crashing.h" #include "base/functional/bind.h" #include "base/logging.h" #include "base/memory/singleton.h" @@ -137,6 +138,14 @@ ? class_info.class_name : std::wstring(WindowImpl::kBaseClassName) + base::NumberToWString(registered_count_++); + // We're not supposed to have many window classes, so if registered_count_ + // gets above a certain small threshold, we may as well have a resource leak + // caused by repeatedly registering a class with auto-generated name, which + // would eventually lead to user atom table exhaustion. + // TODO(crbug.com/1470483): remove when source of ATOM leak is found. + if (registered_count_ == 128) { + base::debug::DumpWithoutCrashing(); + } WNDCLASSEX window_class; base::win::InitializeWindowClass(
diff --git a/ui/message_center/views/notification_control_buttons_unittest.cc b/ui/message_center/views/notification_control_buttons_unittest.cc index 1a82421..129aba1 100644 --- a/ui/message_center/views/notification_control_buttons_unittest.cc +++ b/ui/message_center/views/notification_control_buttons_unittest.cc
@@ -79,8 +79,9 @@ bool MatchesIcon(views::ImageButton* button, const gfx::VectorIcon& icon, - SkColor color) { - SkBitmap expected = *gfx::CreateVectorIcon(icon, color).bitmap(); + SkColor color, + int size = 0) { + SkBitmap expected = *gfx::CreateVectorIcon(icon, size, color).bitmap(); SkBitmap actual = *button->GetImage(views::Button::STATE_NORMAL).bitmap(); return gfx::test::AreBitmapsEqual(expected, actual); } @@ -195,6 +196,50 @@ default_icon_color)); } +// Tests that the icon size can be specified. +TEST_F(NotificationControlButtonsTest, IconSize) { + // Set the control buttons to have a custom size. + int custom_size = 8; + buttons_view()->SetButtonIconSize(custom_size); + + // Show the control buttons and verify that they are using the custom size. + buttons_view()->ShowCloseButton(true); + buttons_view()->ShowSettingsButton(true); + buttons_view()->ShowSnoozeButton(true); + const SkColor default_icon_color = + buttons_view()->GetColorProvider()->GetColor(ui::kColorIcon); + EXPECT_TRUE(MatchesIcon(buttons_view()->close_button(), + NotificationControlButtonsView::kDefaultCloseIcon, + default_icon_color, custom_size)); + EXPECT_TRUE(MatchesIcon(buttons_view()->settings_button(), + NotificationControlButtonsView::kDefaultSettingsIcon, + default_icon_color, custom_size)); + EXPECT_TRUE(MatchesIcon(buttons_view()->snooze_button(), + NotificationControlButtonsView::kDefaultSnoozeIcon, + default_icon_color, custom_size)); + + // Show the same control buttons with a different custom size. + buttons_view()->ShowCloseButton(false); + buttons_view()->ShowSettingsButton(false); + buttons_view()->ShowSnoozeButton(false); + custom_size = 12; + buttons_view()->SetButtonIconSize(custom_size); + buttons_view()->ShowCloseButton(true); + buttons_view()->ShowSettingsButton(true); + buttons_view()->ShowSnoozeButton(true); + + // Verify that the control buttons are using the new custom size. + EXPECT_TRUE(MatchesIcon(buttons_view()->close_button(), + NotificationControlButtonsView::kDefaultCloseIcon, + default_icon_color, custom_size)); + EXPECT_TRUE(MatchesIcon(buttons_view()->settings_button(), + NotificationControlButtonsView::kDefaultSettingsIcon, + default_icon_color, custom_size)); + EXPECT_TRUE(MatchesIcon(buttons_view()->snooze_button(), + NotificationControlButtonsView::kDefaultSnoozeIcon, + default_icon_color, custom_size)); +} + // Tests spacing between control buttons. TEST_F(NotificationControlButtonsTest, BetweenButtonsSpacing) { // Show all the control buttons with default horizontal spacing.
diff --git a/ui/message_center/views/notification_control_buttons_view.cc b/ui/message_center/views/notification_control_buttons_view.cc index 10ec325..13276d1 100644 --- a/ui/message_center/views/notification_control_buttons_view.cc +++ b/ui/message_center/views/notification_control_buttons_view.cc
@@ -20,6 +20,7 @@ #include "ui/strings/grit/ui_strings.h" #include "ui/views/background.h" #include "ui/views/layout/box_layout.h" +#include "ui/views/view_class_properties.h" namespace message_center { @@ -53,8 +54,8 @@ if (GetWidget()) { close_button_->SetImageModel( views::Button::STATE_NORMAL, - ui::ImageModel::FromVectorIcon(GetCloseButtonIcon(), - DetermineButtonIconColor())); + ui::ImageModel::FromVectorIcon( + GetCloseButtonIcon(), DetermineButtonIconColor(), icon_size_)); } close_button_->SetAccessibleName(l10n_util::GetStringUTF16( IDS_MESSAGE_CENTER_CLOSE_NOTIFICATION_BUTTON_ACCESSIBLE_NAME)); @@ -82,8 +83,8 @@ if (GetWidget()) { settings_button_->SetImageModel( views::Button::STATE_NORMAL, - ui::ImageModel::FromVectorIcon(GetSettingsButtonIcon(), - DetermineButtonIconColor())); + ui::ImageModel::FromVectorIcon( + GetSettingsButtonIcon(), DetermineButtonIconColor(), icon_size_)); } settings_button_->SetAccessibleName(l10n_util::GetStringUTF16( IDS_MESSAGE_NOTIFICATION_SETTINGS_BUTTON_ACCESSIBLE_NAME)); @@ -110,8 +111,8 @@ if (GetWidget()) { snooze_button_->SetImageModel( views::Button::STATE_NORMAL, - ui::ImageModel::FromVectorIcon(GetSnoozeButtonIcon(), - DetermineButtonIconColor())); + ui::ImageModel::FromVectorIcon( + GetSnoozeButtonIcon(), DetermineButtonIconColor(), icon_size_)); } snooze_button_->SetAccessibleName(l10n_util::GetStringUTF16( IDS_MESSAGE_CENTER_NOTIFICATION_SNOOZE_BUTTON_TOOLTIP)); @@ -156,6 +157,10 @@ snooze_button_icon_ = &icon; } +void NotificationControlButtonsView::SetButtonIconSize(int size) { + icon_size_ = size; +} + void NotificationControlButtonsView::SetButtonIconColors(SkColor color) { if (color == icon_color_) return; @@ -203,17 +208,20 @@ if (close_button_) { close_button_->SetImageModel( views::Button::STATE_NORMAL, - ui::ImageModel::FromVectorIcon(GetCloseButtonIcon(), icon_color)); + ui::ImageModel::FromVectorIcon(GetCloseButtonIcon(), icon_color, + icon_size_)); } if (settings_button_) { settings_button_->SetImageModel( views::Button::STATE_NORMAL, - ui::ImageModel::FromVectorIcon(GetSettingsButtonIcon(), icon_color)); + ui::ImageModel::FromVectorIcon(GetSettingsButtonIcon(), icon_color, + icon_size_)); } if (snooze_button_) { snooze_button_->SetImageModel( views::Button::STATE_NORMAL, - ui::ImageModel::FromVectorIcon(GetSnoozeButtonIcon(), icon_color)); + ui::ImageModel::FromVectorIcon(GetSnoozeButtonIcon(), icon_color, + icon_size_)); } }
diff --git a/ui/message_center/views/notification_control_buttons_view.h b/ui/message_center/views/notification_control_buttons_view.h index 7c1206b..c1636600 100644 --- a/ui/message_center/views/notification_control_buttons_view.h +++ b/ui/message_center/views/notification_control_buttons_view.h
@@ -71,6 +71,13 @@ void SetSettingsButtonIcon(const gfx::VectorIcon& icon); void SetSnoozeButtonIcon(const gfx::VectorIcon& icon); + // Sets the icon size for the close, settings, and snooze buttons. Like + // `SetXYZButtonIcon()` above, this will only have an effect the next time the + // buttons are shown. Note that setting this to 0 (which is the default value) + // means `gfx::GetDefaultSizeOfVectorIcon()` is used to determine the icon + // size. + void SetButtonIconSize(int size); + // Sets the icon color for the close, settings, and snooze buttons. void SetButtonIconColors(SkColor color); @@ -125,6 +132,11 @@ // The horizontal spacing between buttons. int between_button_spacing_ = kDefaultBetweenButtonSpacing; + // The size of an icon within one of the control buttons. When set to 0, which + // is the default value, then `gfx::GetDefaultSizeOfVectorIcon()` is used to + // determine the icon size. Otherwise this value is used directly. + int icon_size_ = 0; + // Owned by this `views::View`: std::unique_ptr<NotificationControlButtonFactory> notification_control_button_factory_; @@ -143,6 +155,7 @@ VIEW_BUILDER_PROPERTY(const gfx::VectorIcon&, SnoozeButtonIcon, const gfx::VectorIcon&) +VIEW_BUILDER_PROPERTY(int, ButtonIconSize) VIEW_BUILDER_PROPERTY(SkColor, ButtonIconColors) VIEW_BUILDER_PROPERTY(int, BetweenButtonSpacing) VIEW_BUILDER_PROPERTY(std::unique_ptr<NotificationControlButtonFactory>,
diff --git a/ui/views/bubble/bubble_dialog_model_host.cc b/ui/views/bubble/bubble_dialog_model_host.cc index 3d7acf15..16dfffe4 100644 --- a/ui/views/bubble/bubble_dialog_model_host.cc +++ b/ui/views/bubble/bubble_dialog_model_host.cc
@@ -183,6 +183,24 @@ BEGIN_METADATA(CheckboxControl) END_METADATA +struct DialogModelHostField { + raw_ptr<ui::DialogModelField> dialog_model_field = nullptr; + + // View representing the entire field. + raw_ptr<View, DanglingUntriaged> field_view = nullptr; + + // Child view to |field_view|, if any, that's used for focus. For instance, + // a textfield row would be a container that contains both a + // views::Textfield and a descriptive label. In this case |focusable_view| + // would refer to the views::Textfield which is also what would gain focus. + raw_ptr<View, DanglingUntriaged> focusable_view = nullptr; +}; + +View* GetTargetView(const DialogModelHostField& field_view_info) { + return field_view_info.focusable_view ? field_view_info.focusable_view.get() + : field_view_info.field_view.get(); +} + } // namespace BubbleDialogModelHost::CustomView::CustomView(std::unique_ptr<View> view, @@ -228,9 +246,70 @@ RemoveAllChildViews(); parent_ = nullptr; contents_ = nullptr; + fields_.clear(); } - public: + void AddDialogModelHostField(std::unique_ptr<View> view, + const DialogModelHostField& field_view_info) { + CHECK(parent_); + DCHECK_EQ(view.get(), field_view_info.field_view); + + AddChildView(std::move(view)); + AddDialogModelHostFieldForExistingView(field_view_info); + } + + // TODO(pbos): Remove BubbleDialogModelHost direct dependency on this method + // then merge with AddDialogModelHostField, and presumably make private. Also + // remove calls to parent_ (due to buttons being hosted in the parent), they + // should be handled separately by BubbleDialogModelHost. + void AddDialogModelHostFieldForExistingView( + const DialogModelHostField& field_view_info) { + DCHECK(field_view_info.dialog_model_field); + DCHECK(field_view_info.field_view); + DCHECK(Contains(field_view_info.field_view) || + field_view_info.field_view == parent_->GetOkButton() || + field_view_info.field_view == parent_->GetCancelButton() || + field_view_info.field_view == parent_->GetExtraView()); +#if DCHECK_IS_ON() + // Make sure none of the info is already in use. + for (const auto& info : fields_) { + DCHECK_NE(info.field_view, field_view_info.field_view); + DCHECK_NE(info.dialog_model_field, field_view_info.dialog_model_field); + if (info.focusable_view) { + DCHECK_NE(info.focusable_view, field_view_info.focusable_view); + } + } +#endif // DCHECK_IS_ON() + fields_.push_back(field_view_info); + View* const target = GetTargetView(field_view_info); + target->SetProperty(kElementIdentifierKey, + field_view_info.dialog_model_field->id(GetPassKey())); + for (const auto& accelerator : + field_view_info.dialog_model_field->accelerators(GetPassKey())) { + target->AddAccelerator(accelerator); + } + } + + DialogModelHostField FindDialogModelHostField(ui::DialogModelField* field) { + for (const auto& info : fields_) { + if (info.dialog_model_field == field) { + return info; + } + } + // TODO(pbos): `field` could correspond to a button. + return {}; + } + + DialogModelHostField FindDialogModelHostField(View* view) { + for (const auto& info : fields_) { + if (info.field_view == view) { + return info; + } + } + NOTREACHED_NORETURN(); + } + + private: // TODO(pbos): These should be const as we should never outlive our parent or // DialogModelSection. Currently this isn't true because WidgetDelegate gets // destroyed by Widget in OnNativeWidgetDestroyed before the content gets @@ -239,6 +318,8 @@ raw_ptr<ui::DialogModelSection> contents_; const base::CallbackListSubscription on_field_added_subscription_; + + std::vector<DialogModelHostField> fields_; }; BEGIN_METADATA(BubbleDialogModelHost, ContentsView, BoxLayoutView) @@ -519,25 +600,25 @@ if (!unique_id) return BubbleDialogDelegate::GetInitiallyFocusedView(); - return GetTargetView( - FindDialogModelHostField(model_->GetFieldByUniqueId(unique_id))); + return GetTargetView(contents_view_->FindDialogModelHostField( + model_->GetFieldByUniqueId(unique_id))); } void BubbleDialogModelHost::OnWidgetInitialized() { // Dialog buttons are added on dialog initialization. if (GetOkButton()) { - AddDialogModelHostFieldForExistingView( + contents_view_->AddDialogModelHostFieldForExistingView( {model_->ok_button(GetPassKey()), GetOkButton(), nullptr}); } if (GetCancelButton()) { - AddDialogModelHostFieldForExistingView( + contents_view_->AddDialogModelHostFieldForExistingView( {model_->cancel_button(GetPassKey()), GetCancelButton(), nullptr}); } if (model_->extra_button(GetPassKey())) { DCHECK(GetExtraView()); - AddDialogModelHostFieldForExistingView( + contents_view_->AddDialogModelHostFieldForExistingView( {model_->extra_button(GetPassKey()), GetExtraView(), nullptr}); } @@ -577,7 +658,6 @@ // Detach ContentsView as it's referring to state that's about to be // destroyed. contents_view_->Detach(); - fields_.clear(); model_.reset(); } @@ -654,7 +734,7 @@ DCHECK(view); view->SetProperty(kElementIdentifierKey, field->id(GetPassKey())); DialogModelHostField info{field, view.get(), nullptr}; - AddDialogModelHostField(std::move(view), info); + contents_view_->AddDialogModelHostField(std::move(view), info); break; } UpdateSpacingAndMargins(); @@ -727,7 +807,7 @@ for (View* const view : children) { ui::DialogModelField* const field = - FindDialogModelHostField(view).dialog_model_field; + contents_view_->FindDialogModelHostField(view).dialog_model_field; FieldType field_type = GetFieldTypeForField(field, GetPassKey()); @@ -768,7 +848,8 @@ } void BubbleDialogModelHost::UpdateFieldVisibility(ui::DialogModelField* field) { - DialogModelHostField host_field = FindDialogModelHostField(field); + DialogModelHostField host_field = + contents_view_->FindDialogModelHostField(field); if (host_field.field_view) { host_field.field_view->SetVisible(field->is_visible()); @@ -795,7 +876,7 @@ model_field->header(GetPassKey())); DialogModelHostField info{model_field, view.get(), nullptr}; view->SetProperty(kElementIdentifierKey, model_field->id(GetPassKey())); - AddDialogModelHostField(std::move(view), info); + contents_view_->AddDialogModelHostField(std::move(view), info); } void BubbleDialogModelHost::AddOrUpdateCheckbox( @@ -825,7 +906,7 @@ model_field, GetPassKey(), checkbox.get())); DialogModelHostField info{model_field, checkbox.get(), nullptr}; - AddDialogModelHostField(std::move(checkbox), info); + contents_view_->AddDialogModelHostField(std::move(checkbox), info); } void BubbleDialogModelHost::AddOrUpdateCombobox( @@ -884,7 +965,7 @@ item->SetProperty(kElementIdentifierKey, model_field->id(GetPassKey())); DialogModelHostField info{model_field, item.get(), nullptr}; - AddDialogModelHostField(std::move(item), info); + contents_view_->AddDialogModelHostField(std::move(item), info); } void BubbleDialogModelHost::AddOrUpdateSeparator( @@ -894,7 +975,7 @@ auto separator = std::make_unique<Separator>(); DialogModelHostField info{model_field, separator.get(), nullptr}; - AddDialogModelHostField(std::move(separator), info); + contents_view_->AddDialogModelHostField(std::move(separator), info); } void BubbleDialogModelHost::AddOrUpdateTextfield( @@ -940,7 +1021,7 @@ SetButtonLabel(ui::DIALOG_BUTTON_CANCEL, label); } else if (model_field == model_->extra_button(GetPassKey())) { static_cast<MdTextButton*>( - GetTargetView(FindDialogModelHostField(model_field))) + GetTargetView(contents_view_->FindDialogModelHostField(model_field))) ->SetText(label); } else { NOTIMPLEMENTED(); @@ -970,68 +1051,7 @@ &textfield_second_column_group_, std::move(field))), 1); - AddDialogModelHostField(std::move(box_layout), info); -} - -void BubbleDialogModelHost::AddDialogModelHostField( - std::unique_ptr<View> view, - const DialogModelHostField& field_view_info) { - DCHECK_EQ(view.get(), field_view_info.field_view); - - contents_view_->AddChildView(std::move(view)); - AddDialogModelHostFieldForExistingView(field_view_info); -} - -void BubbleDialogModelHost::AddDialogModelHostFieldForExistingView( - const DialogModelHostField& field_view_info) { - DCHECK(field_view_info.dialog_model_field); - DCHECK(field_view_info.field_view); - DCHECK(contents_view_->Contains(field_view_info.field_view) || - field_view_info.field_view == GetOkButton() || - field_view_info.field_view == GetCancelButton() || - field_view_info.field_view == GetExtraView()); -#if DCHECK_IS_ON() - // Make sure none of the info is already in use. - for (const auto& info : fields_) { - DCHECK_NE(info.field_view, field_view_info.field_view); - DCHECK_NE(info.dialog_model_field, field_view_info.dialog_model_field); - if (info.focusable_view) - DCHECK_NE(info.focusable_view, field_view_info.focusable_view); - } -#endif // DCHECK_IS_ON() - fields_.push_back(field_view_info); - View* const target = GetTargetView(field_view_info); - target->SetProperty(kElementIdentifierKey, - field_view_info.dialog_model_field->id(GetPassKey())); - for (const auto& accelerator : - field_view_info.dialog_model_field->accelerators(GetPassKey())) { - target->AddAccelerator(accelerator); - } -} - -BubbleDialogModelHost::DialogModelHostField -BubbleDialogModelHost::FindDialogModelHostField(ui::DialogModelField* field) { - for (const auto& info : fields_) { - if (info.dialog_model_field == field) - return info; - } - // TODO(pbos): `field` could correspond to a button. - return {}; -} - -BubbleDialogModelHost::DialogModelHostField -BubbleDialogModelHost::FindDialogModelHostField(View* view) { - for (const auto& info : fields_) { - if (info.field_view == view) - return info; - } - NOTREACHED_NORETURN(); -} - -View* BubbleDialogModelHost::GetTargetView( - const DialogModelHostField& field_view_info) { - return field_view_info.focusable_view ? field_view_info.focusable_view.get() - : field_view_info.field_view.get(); + contents_view_->AddDialogModelHostField(std::move(box_layout), info); } bool BubbleDialogModelHost::DialogModelLabelRequiresStyledLabel(
diff --git a/ui/views/bubble/bubble_dialog_model_host.h b/ui/views/bubble/bubble_dialog_model_host.h index 0142875..e4debdb 100644 --- a/ui/views/bubble/bubble_dialog_model_host.h +++ b/ui/views/bubble/bubble_dialog_model_host.h
@@ -130,19 +130,6 @@ base::ScopedObservation<View, ViewObserver> observation_{this}; }; - struct DialogModelHostField { - raw_ptr<ui::DialogModelField> dialog_model_field = nullptr; - - // View representing the entire field. - raw_ptr<View, DanglingUntriaged> field_view = nullptr; - - // Child view to |field_view|, if any, that's used for focus. For instance, - // a textfield row would be a container that contains both a - // views::Textfield and a descriptive label. In this case |focusable_view| - // would refer to the views::Textfield which is also what would gain focus. - raw_ptr<View, DanglingUntriaged> focusable_view = nullptr; - }; - [[nodiscard]] ContentsView* InitContentsView( ui::DialogModelSection* contents); @@ -180,24 +167,12 @@ const ui::DialogModelLabel& dialog_label, const std::u16string header); - void AddDialogModelHostField(std::unique_ptr<View> view, - const DialogModelHostField& field_view_info); - void AddDialogModelHostFieldForExistingView( - const DialogModelHostField& field_view_info); - - DialogModelHostField FindDialogModelHostField( - ui::DialogModelField* model_field); - DialogModelHostField FindDialogModelHostField(View* view); - - static View* GetTargetView(const DialogModelHostField& field_view_info); - bool IsModalDialog() const; std::unique_ptr<ui::DialogModel> model_; const raw_ptr<ContentsView> contents_view_; ThemeChangedObserver theme_observer_; - std::vector<DialogModelHostField> fields_; std::vector<base::CallbackListSubscription> property_changed_subscriptions_; LayoutConsensusGroup textfield_first_column_group_;
diff --git a/ui/views/controls/button/button.cc b/ui/views/controls/button/button.cc index ad1dadaf..c994b37 100644 --- a/ui/views/controls/button/button.cc +++ b/ui/views/controls/button/button.cc
@@ -30,7 +30,6 @@ #include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_highlight.h" #include "ui/views/animation/ink_drop_impl.h" -#include "ui/views/animation/ink_drop_state.h" #include "ui/views/controls/button/button_controller.h" #include "ui/views/controls/button/button_controller_delegate.h" #include "ui/views/controls/button/checkbox.h" @@ -232,12 +231,6 @@ void Button::SetState(ButtonState state) { if (state == state_) { - if (anchor_count_ > 0) { - // Update the highlight for the |anchor_count_| even if the state hasn't - // changed. This catches cases where button visibility might have changed - // but the state hasn't. - SetHighlighted(true); - } return; } @@ -402,15 +395,10 @@ } void Button::SetHighlighted(bool highlighted) { - // Do nothing if the ink drop's target state matches what we are trying to set - // since same state transitions may restart animations. - InkDropState state = highlighted ? views::InkDropState::ACTIVATED - : views::InkDropState::DEACTIVATED; - if (InkDrop::Get(ink_drop_view_)->GetInkDrop()->GetTargetInkDropState() == - state) { - return; - } - InkDrop::Get(ink_drop_view_)->AnimateToState(state, nullptr); + InkDrop::Get(ink_drop_view_) + ->AnimateToState(highlighted ? views::InkDropState::ACTIVATED + : views::InkDropState::DEACTIVATED, + nullptr); } Button::ScopedAnchorHighlight Button::AddAnchorHighlight() { @@ -597,12 +585,8 @@ if (state_ != STATE_DISABLED) { SetState(STATE_NORMAL); } - if (anchor_count_ > 0) { - SetHighlighted(true); - } else { - InkDrop::Get(ink_drop_view_) - ->AnimateToState(InkDropState::HIDDEN, nullptr /* event */); - } + InkDrop::Get(ink_drop_view_) + ->AnimateToState(InkDropState::HIDDEN, nullptr /* event */); } void Button::OnPaint(gfx::Canvas* canvas) {
diff --git a/ui/views/controls/button/md_text_button_unittest.cc b/ui/views/controls/button/md_text_button_unittest.cc index 07c0a235..cac0c66e 100644 --- a/ui/views/controls/button/md_text_button_unittest.cc +++ b/ui/views/controls/button/md_text_button_unittest.cc
@@ -39,7 +39,7 @@ std::unique_ptr<Widget> widget = CreateTestWidget(); auto* button = widget->SetContentsView( std::make_unique<MdTextButton>(Button::PressedCallback(), u" ")); - button->SetProminent(true); + button->SetStyle(ui::ButtonStyle::kProminent); button->SetBounds(0, 0, 70, 20); widget->LayoutRootViewIfNecessary();
diff --git a/ui/views/examples/button_sticker_sheet.cc b/ui/views/examples/button_sticker_sheet.cc index 4a83d36..cb929c2 100644 --- a/ui/views/examples/button_sticker_sheet.cc +++ b/ui/views/examples/button_sticker_sheet.cc
@@ -62,7 +62,7 @@ const std::u16string button_text = u"Button"; auto primary = std::make_unique<views::MdTextButton>( Button::PressedCallback(), button_text); - primary->SetProminent(true); + primary->SetStyle(ui::ButtonStyle::kProminent); primary->SetState(state); buttons.push_back(std::move(primary));
diff --git a/ui/views/window/client_view.cc b/ui/views/window/client_view.cc index b2a47ca..e5a3977 100644 --- a/ui/views/window/client_view.cc +++ b/ui/views/window/client_view.cc
@@ -25,16 +25,18 @@ SetLayoutManager(std::make_unique<views::FillLayout>()); } -int ClientView::NonClientHitTest(const gfx::Point& point) { - return bounds().Contains(point) ? HTCLIENT : HTNOWHERE; -} - CloseRequestResult ClientView::OnWindowCloseRequested() { return CloseRequestResult::kCanClose; } void ClientView::WidgetClosing() {} +int ClientView::NonClientHitTest(const gfx::Point& point) { + return bounds().Contains(point) ? HTCLIENT : HTNOWHERE; +} + +void ClientView::UpdateWindowRoundedCorners() {} + /////////////////////////////////////////////////////////////////////////////// // ClientView, View overrides:
diff --git a/ui/views/window/client_view.h b/ui/views/window/client_view.h index 891fe25..7f46fff 100644 --- a/ui/views/window/client_view.h +++ b/ui/views/window/client_view.h
@@ -52,6 +52,14 @@ // corner of resizable dialog boxes. virtual int NonClientHitTest(const gfx::Point& point); + // Updates the rounded corners of the ClientView's contents as part of + // rounding the window. + // Some platforms, such as ChromeOS, do not have borders surrounding + // ClientView part of the NonClientFrameView. Therefore, the + // NonClientFrameView has to delegate part of the rounding logic to the + // ClientView. + virtual void UpdateWindowRoundedCorners(); + // Overridden from View: gfx::Size CalculatePreferredSize() const override; int GetHeightForWidth(int width) const override;
diff --git a/ui/webui/resources/cr_components/omnibox/realbox_match.html b/ui/webui/resources/cr_components/omnibox/realbox_match.html index 8abde328..e5b96325 100644 --- a/ui/webui/resources/cr_components/omnibox/realbox_match.html +++ b/ui/webui/resources/cr_components/omnibox/realbox_match.html
@@ -78,10 +78,16 @@ flex-grow: 1; flex-shrink: 0; padding-bottom: 0; - padding-inline-end: 8px; + padding-inline-end: 0px; + padding-inline-start: 0px; padding-top: 0; } + :host([has-action]) .actions.inlined { + padding-inline-end: 8px; + padding-inline-start: 4px; + } + #contents, #description { overflow: hidden; @@ -135,6 +141,10 @@ white-space: nowrap; } + :host([has-action]) #text-container { + padding-inline-end: 4px; + } + #text-container.simplified { flex-grow: 0; }
diff --git a/ui/webui/resources/cr_components/omnibox/realbox_match.ts b/ui/webui/resources/cr_components/omnibox/realbox_match.ts index cf8927ec..d4050b7 100644 --- a/ui/webui/resources/cr_components/omnibox/realbox_match.ts +++ b/ui/webui/resources/cr_components/omnibox/realbox_match.ts
@@ -81,10 +81,16 @@ value: () => loadTimeData.getBoolean('realboxCr23ExpandedStateLayout'), }, + hasAction: { + type: Boolean, + computed: `computeHasAction_(match.actions)`, + reflectToAttribute: true, + }, + /** Whether action chip will have an outset focus ring. */ hasOutsetActionFocusRing: { type: Boolean, - computed: `computeHasOutsetActionFocusRing_(match.actions)`, + computed: `computeHasOutsetActionFocusRing_(hasAction)`, reflectToAttribute: true, }, @@ -196,6 +202,7 @@ override ariaLabel: string; expandedStateIconsChromeRefresh: boolean; + hasAction: boolean; hasOutsetActionFocusRing: boolean; hasImage: boolean; match: AutocompleteMatch; @@ -354,9 +361,12 @@ .innerHTML); } + private computeHasAction_() { + return this.match?.actions?.length > 0; + } + private computeHasOutsetActionFocusRing_() { - return this.expandedStateIconsChromeRefresh && - this.match?.actions?.length > 0; + return this.expandedStateIconsChromeRefresh && this.hasAction; } private computeTailSuggestPrefix_(): string {
diff --git a/ui/webui/resources/cr_elements/chromeos/cros_color_overrides.css b/ui/webui/resources/cr_elements/chromeos/cros_color_overrides.css index 11d5b82..3ea327a1 100644 --- a/ui/webui/resources/cr_elements/chromeos/cros_color_overrides.css +++ b/ui/webui/resources/cr_elements/chromeos/cros_color_overrides.css
@@ -232,7 +232,8 @@ --cr-input-placeholder-color: var(--cros-sys-secondary); } -:host-context([cros][chrome-refresh-2023]) cr-input { +:host-context([cros][chrome-refresh-2023]) cr-input, +:host-context([cros][chrome-refresh-2023]) cr-search-field::part(searchInput) { --cr-input-background-color: var(--cros-sys-input_field_on_base); --cr-input-border: none; --cr-input-border-bottom: none; @@ -243,6 +244,8 @@ --cr-input-placeholder-color: var(--cros-sys-secondary); --cr-input-underline-display: none; + font: var(--cros-body-2-font); + /* Focused state */ --cr-input-focus-color: var(--cros-sys-primary); --cr-input-focus-label-color: var(--cros-sys-primary); @@ -354,6 +357,25 @@ border-radius: 4px; } +:host-context([cros][chrome-refresh-2023]) cr-search-field { + /* Search icon */ + --cr-search-field-search-icon-fill: var(--cros-sys-secondary); + --cr-search-field-search-icon-inline-margin-start: 0; + + /* Clear icon */ + --cr-search-field-clear-icon-fill: var(--cros-sys-secondary); + --cr-search-field-clear-icon-margin-end: 6px; + --cr-search-field-clear-icon-size: 16px; +} + +:host-context([cros][chrome-refresh-2023]) cr-search-field::part(searchInput) { + /* Modify the styles defined in "Input and Textarea" above. */ + --cr-input-padding-bottom: 10px; + --cr-input-padding-end: 28px; + --cr-input-padding-start: 8px; + --cr-input-padding-top: 10px; +} + /* Slider */ :host-context(body.jelly-enabled) cr-slider { --cr-slider-active-color: var(--cros-sys-primary);
diff --git a/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.html b/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.html index ded97bb..f16452a 100644 --- a/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.html +++ b/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.html
@@ -95,6 +95,6 @@ role="application" aria-roledescription$="[[roleDescription]]"> <div id="wrapper" class="item-wrapper" role="menu" tabindex="-1" aria-label$="[[accessibilityLabel]]"> - <slot id="contentNode"></slot> + <slot id="contentNode" on-slotchange="onSlotchange_"></slot> </div> </dialog>
diff --git a/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.ts b/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.ts index a03f391..81b2518 100644 --- a/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.ts +++ b/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.ts
@@ -10,7 +10,7 @@ import {focusWithoutInk} from '//resources/js/focus_without_ink.js'; import {isMac, isWindows} from '//resources/js/platform.js'; import {getDeepActiveElement} from '//resources/js/util.js'; -import {FlattenedNodesObserver, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {getTemplate} from './cr_action_menu.html.js'; @@ -158,7 +158,6 @@ roleDescription: string; private boundClose_: (() => void)|null = null; - private contentObserver_: FlattenedNodesObserver|null = null; private resizeObserver_: ResizeObserver|null = null; private hasMousemoveListener_: boolean = false; private anchorElement_: HTMLElement|null = null; @@ -193,10 +192,6 @@ private removeListeners_() { window.removeEventListener('resize', this.boundClose_!); window.removeEventListener('popstate', this.boundClose_!); - if (this.contentObserver_) { - this.contentObserver_.disconnect(); - this.contentObserver_ = null; - } if (this.resizeObserver_) { this.resizeObserver_.disconnect(); @@ -456,6 +451,15 @@ this.$.dialog.style.top = menuTop + 'px'; } + private onSlotchange_() { + for (const node of this.$.contentNode.assignedElements({flatten: true})) { + if (node.classList.contains(DROPDOWN_ITEM_CLASS) && + !node.getAttribute('role')) { + node.setAttribute('role', 'menuitem'); + } + } + } + private addListeners_() { this.boundClose_ = this.boundClose_ || (() => { if (this.$.dialog.open) { @@ -465,17 +469,6 @@ window.addEventListener('resize', this.boundClose_); window.addEventListener('popstate', this.boundClose_); - this.contentObserver_ = new FlattenedNodesObserver( - this.$.contentNode, (info: {addedNodes: Element[]}) => { - info.addedNodes.forEach(node => { - if (node.classList && - node.classList.contains(DROPDOWN_ITEM_CLASS) && - !node.getAttribute('role')) { - node.setAttribute('role', 'menuitem'); - } - }); - }); - if (this.autoReposition) { this.resizeObserver_ = new ResizeObserver(() => { if (this.lastConfig_) {
diff --git a/ui/webui/resources/cr_elements/cr_tabs/cr_tabs.html b/ui/webui/resources/cr_elements/cr_tabs/cr_tabs.html index 47af702..90ee49d 100644 --- a/ui/webui/resources/cr_elements/cr_tabs/cr_tabs.html +++ b/ui/webui/resources/cr_elements/cr_tabs/cr_tabs.html
@@ -60,13 +60,13 @@ } .tab-indicator { - background: var(--cr-tabs-selected-color, var(--google-blue-600)); + background: var(--cr-tabs-unselected-color, var(--google-blue-600)); border-top-left-radius: var(--cr-tabs-selection-bar-width, 2px); border-top-right-radius: var(--cr-tabs-selection-bar-width, 2px); bottom: 0; height: var(--cr-tabs-selection-bar-width, 2px); left: var(--cr-tabs-tab-inline-padding, 0); - opacity: 0; + opacity: var(--cr-tabs-selection-bar-unselected-opacity, 0); position: absolute; right: var(--cr-tabs-tab-inline-padding, 0); transform-origin: left center; @@ -74,6 +74,7 @@ } .selected .tab-indicator { + background: var(--cr-tabs-selected-color, var(--google-blue-600)); opacity: 1; }
diff --git a/v8 b/v8 index c392ada..279e031 160000 --- a/v8 +++ b/v8
@@ -1 +1 @@ -Subproject commit c392ada3b4a1af3a7a8be6ecd2dd45300cbd7a4f +Subproject commit 279e0319cb5e66dbed2cdd32ed1699a3b64a9695