diff --git a/BUILD.gn b/BUILD.gn index 92c06f2f..06d0f01 100644 --- a/BUILD.gn +++ b/BUILD.gn
@@ -1215,10 +1215,6 @@ "//testing/scripts/run_isolated_script_test.py", "//testing/xvfb.py", "//third_party/blink/tools/", - "//third_party/blink/web_tests/VirtualTestSuites", - "//third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json", - "//third_party/blink/web_tests/external/wpt/common/", - "//third_party/blink/web_tests/external/wpt/resources/", "//third_party/blink/web_tests/resources/", "//third_party/pywebsocket3/src/mod_pywebsocket/", "//third_party/test_fonts/test_fonts/", @@ -1540,7 +1536,10 @@ "//third_party/webgpu-cts", ] data = [ + "//third_party/blink/web_tests/external/wpt/common/", + "//third_party/blink/web_tests/external/wpt/resources/", "//third_party/blink/web_tests/FlagSpecificConfig", + "//third_party/blink/web_tests/VirtualTestSuites", "//third_party/blink/web_tests/WebGPUExpectations", "//third_party/blink/web_tests/wpt_internal/", "//third_party/webgpu-cts/scripts/",
diff --git a/DEPS b/DEPS index 301f7a6fe..8e5ae552 100644 --- a/DEPS +++ b/DEPS
@@ -297,11 +297,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': 'e9e06c11b7234a3e9e44bc73033aa64561c01fc2', + 'skia_revision': 'c5fb1f796056d9d6f7f72328d92f915fc6ca678d', # 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': 'c655393ae2edf28735aa458290e6fdf00319caf6', + 'v8_revision': '6850f6876e0046a78aaea1b27eaf1529baa5dd34', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. @@ -368,7 +368,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': '84a7988038ae00e1e861381fedf76e233337843f', + 'catapult_revision': '7e701fa6365e481bb9090ecd351c8f3cca8ee944', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -412,7 +412,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'dawn_revision': '6fe1f515d4b4411fb44bb656ab804b833d16526a', + 'dawn_revision': 'a4038bb1fda9b3e5b74619a37c07551af485539b', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -440,7 +440,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling nearby # and whatever else without interference from each other. - 'nearby_revision': 'a37a7b7a839b1f3c189662af6720b94e3eaa3280', + 'nearby_revision': '0d4964da7babe0a0ae01cd4950c5215dbd7dd8d1', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling securemessage # and whatever else without interference from each other. @@ -792,7 +792,7 @@ }, 'src/ios/third_party/material_components_ios/src': { - 'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + 'c2607a4213a6efd3e6ebf874ae3145d92ac0dead', + 'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '0937378683bd95ffda6ac42074922c2301f7d703', 'condition': 'checkout_ios', }, @@ -1573,7 +1573,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + '566ee6c9e7612dd409089bd64c11a793870c1ee4', + Var('android_git') + '/platform/external/perfetto.git' + '@' + '01993ba7f5a26a65af195c874e8a8ee3ca030fda', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3', @@ -1729,10 +1729,10 @@ Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '44e4c8770158c505b03ee7feafa4859d083b0912', 'src/third_party/webgpu-cts/src': - Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '7af1f6b276edb0adce2ad6c2426a5c10981bda3d', + Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '94fd83896c67bb1a995337c501bbed02bd63361f', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + 'eb8813b847b6859c4df972849eed19dd530edcb6', + Var('webrtc_git') + '/src.git' + '@' + '195b7ded1589960b14f37ddc3d2054fdc7c235b6', 'src/third_party/libgifcodec': Var('skia_git') + '/libgifcodec' + '@'+ Var('libgifcodec_revision'), @@ -1805,7 +1805,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@e46e4fc017c5cd8912c132cf8937529651d838c7', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@ca28931612a053dfc58e3c4d7b9489c4dbb050b0', 'condition': 'checkout_src_internal', }, @@ -1846,7 +1846,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/media_app/app', - 'version': 'kROfPmt7XUdSWZ-LmtJQqDEYhSmmwEjnr4EokFqphHUC', + 'version': 'qg8l0bKn_SqJM5CXus8trjrhts0XJ09OzUzRnR714d8C', }, ], 'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/android_webview/tools/system_webview_shell/apk/res/menu/main_menu.xml b/android_webview/tools/system_webview_shell/apk/res/menu/main_menu.xml index 03909212..3b3b12c 100644 --- a/android_webview/tools/system_webview_shell/apk/res/menu/main_menu.xml +++ b/android_webview/tools/system_webview_shell/apk/res/menu/main_menu.xml
@@ -21,6 +21,12 @@ <item android:id="@+id/menu_force_dark_on" android:title="@string/menu_force_dark_on"/> </group> + <item android:id="@+id/menu_night_mode_on" + android:checkable="true" + android:title="@string/menu_night_mode_on"/> + <item android:id="@+id/menu_algorithmic_darkening_on" + android:checkable="true" + android:title="@string/menu_algorithmic_darkening_on"/> <item android:id="@+id/menu_print" android:title="@string/menu_print"/> <item android:id="@+id/start_animation_activity"
diff --git a/android_webview/tools/system_webview_shell/apk/res/values/strings.xml b/android_webview/tools/system_webview_shell/apk/res/values/strings.xml index 125f35c..102f8fd3 100644 --- a/android_webview/tools/system_webview_shell/apk/res/values/strings.xml +++ b/android_webview/tools/system_webview_shell/apk/res/values/strings.xml
@@ -22,6 +22,8 @@ <string name="menu_force_dark_off">Force Dark Off</string> <string name="menu_force_dark_auto">Force Dark Auto</string> <string name="menu_force_dark_on">Force Dark On</string> + <string name="menu_algorithmic_darkening_on">Algorithmic Darkening ON</string> + <string name="menu_night_mode_on">Night Mode ON</string> <string name="menu_start_animation_activity">Animation test</string> <string name="menu_print">Print</string> <string name="menu_about">About WebView</string>
diff --git a/android_webview/tools/system_webview_shell/apk/src/org/chromium/webview_shell/WebViewBrowserActivity.java b/android_webview/tools/system_webview_shell/apk/src/org/chromium/webview_shell/WebViewBrowserActivity.java index 49be5a5..7d95825 100644 --- a/android_webview/tools/system_webview_shell/apk/src/org/chromium/webview_shell/WebViewBrowserActivity.java +++ b/android_webview/tools/system_webview_shell/apk/src/org/chromium/webview_shell/WebViewBrowserActivity.java
@@ -8,6 +8,7 @@ import android.annotation.SuppressLint; import android.app.Activity; import android.app.AlertDialog; +import android.app.UiModeManager; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; @@ -51,6 +52,7 @@ import androidx.activity.result.ActivityResultLauncher; import androidx.annotation.RequiresApi; import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatDelegate; import androidx.appcompat.widget.Toolbar; import androidx.webkit.TracingConfig; import androidx.webkit.TracingController; @@ -59,6 +61,7 @@ import androidx.webkit.WebViewCompat; import androidx.webkit.WebViewFeature; +import org.chromium.base.BuildInfo; import org.chromium.base.ContextUtils; import org.chromium.base.Log; import org.chromium.base.PackageManagerUtils; @@ -300,13 +303,18 @@ // * detectCleartextNetwork() to permit testing http:// URLs // * detectFileUriExposure() to permit testing file:// URLs // * detectLeakedClosableObjects() because of drag and drop (https://crbug.com/1090841#c40) - StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() - .detectActivityLeaks() - .detectLeakedRegistrationObjects() - .detectLeakedSqlLiteObjects() - .penaltyLog() - .penaltyDeath() - .build()); + StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + // WebViewBrowserActivity will have two instances when switching night mode back and + // forth for the 3rd times. Don't know the reason, this probably needs the investigation + // to rule out WebView holding the instance. (crbug.com/1348615) + builder = builder.detectActivityLeaks(); + } + StrictMode.setVmPolicy(builder.detectLeakedRegistrationObjects() + .detectLeakedSqlLiteObjects() + .penaltyLog() + .penaltyDeath() + .build()); } @Override @@ -368,6 +376,15 @@ } @Override + protected void onDestroy() { + super.onDestroy(); + ViewGroup viewGroup = (ViewGroup) (mWebView.getParent()); + viewGroup.removeView(mWebView); + mWebView.destroy(); + mWebView = null; + } + + @Override public void onSaveInstanceState(Bundle savedInstanceState) { super.onSaveInstanceState(savedInstanceState); // Deliberately don't catch TransactionTooLargeException here. @@ -600,11 +617,18 @@ if (!WebViewFeature.isFeatureSupported(WebViewFeature.TRACING_CONTROLLER_BASIC_USAGE)) { menu.findItem(R.id.menu_enable_tracing).setEnabled(false); } - if (!WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) { + if (!WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK) + || BuildInfo.targetsAtLeastT()) { menu.findItem(R.id.menu_force_dark_off).setEnabled(false); menu.findItem(R.id.menu_force_dark_auto).setEnabled(false); menu.findItem(R.id.menu_force_dark_on).setEnabled(false); } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + menu.findItem(R.id.menu_night_mode_on).setEnabled(false); + } + if (!BuildInfo.targetsAtLeastT()) { + menu.findItem(R.id.menu_algorithmic_darkening_on).setEnabled(false); + } return super.onCreateOptionsMenu(menu); } @@ -617,7 +641,8 @@ } else { menu.findItem(R.id.menu_enable_tracing).setEnabled(false); } - if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) { + if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK) + && !BuildInfo.targetsAtLeastT()) { int forceDarkState = WebSettingsCompat.getForceDark(mWebView.getSettings()); switch (forceDarkState) { case WebSettingsCompat.FORCE_DARK_OFF: @@ -631,6 +656,24 @@ break; } } + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { + boolean checked = + AppCompatDelegate.MODE_NIGHT_YES == AppCompatDelegate.getDefaultNightMode(); + int defaultNightMode = AppCompatDelegate.getDefaultNightMode(); + if (defaultNightMode == AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM + || defaultNightMode == AppCompatDelegate.MODE_NIGHT_UNSPECIFIED) { + UiModeManager uiModeManager = + (UiModeManager) this.getApplicationContext().getSystemService( + UI_MODE_SERVICE); + checked = UiModeManager.MODE_NIGHT_YES == uiModeManager.getNightMode(); + } + menu.findItem(R.id.menu_night_mode_on).setChecked(checked); + } + if (BuildInfo.targetsAtLeastT()) { + menu.findItem(R.id.menu_algorithmic_darkening_on) + .setChecked(WebSettingsCompat.isAlgorithmicDarkeningAllowed( + mWebView.getSettings())); + } return true; } @@ -691,6 +734,15 @@ WebSettingsCompat.setForceDark(mWebView.getSettings(), WebSettingsCompat.FORCE_DARK_ON); item.setChecked(true); return true; + } else if (itemId == R.id.menu_night_mode_on) { + AppCompatDelegate.setDefaultNightMode(item.isChecked() + ? AppCompatDelegate.MODE_NIGHT_NO + : AppCompatDelegate.MODE_NIGHT_YES); + return true; + } else if (itemId == R.id.menu_algorithmic_darkening_on) { + WebSettingsCompat.setAlgorithmicDarkeningAllowed(mWebView.getSettings(), + !WebSettingsCompat.isAlgorithmicDarkeningAllowed(mWebView.getSettings())); + return true; } else if (itemId == R.id.start_animation_activity) { startActivity(new Intent(this, WebViewAnimationTestActivity.class)); return true;
diff --git a/ash/app_list/views/app_drag_icon_proxy.cc b/ash/app_list/views/app_drag_icon_proxy.cc index 06c901a..149fa71 100644 --- a/ash/app_list/views/app_drag_icon_proxy.cc +++ b/ash/app_list/views/app_drag_icon_proxy.cc
@@ -8,6 +8,7 @@ #include "ash/drag_drop/drag_image_view.h" #include "ash/public/cpp/style/color_provider.h" +#include "ash/style/system_shadow.h" #include "ui/aura/window.h" #include "ui/base/dragdrop/mojom/drag_drop_types.mojom-shared.h" #include "ui/compositor/layer.h" @@ -21,6 +22,15 @@ namespace ash { +constexpr SystemShadow::Type kShadowType = SystemShadow::Type::kElevation12; + +// For all app icons, there is an intended transparent ring around the visible +// icon that makes the icon looks smaller than its actual size. The shadow is +// needed to resize to align with the visual icon. Note that this constant is +// the same as `kBackgroundCircleScale` in +// chrome/browser/apps/icon_standardizer.cc +constexpr float kShadowScaleFactor = 176.f / 192.f; + AppDragIconProxy::AppDragIconProxy( aura::Window* root_window, const gfx::ImageSkia& icon, @@ -36,6 +46,7 @@ drag_image->SetImage(icon); gfx::Size size = drag_image->GetPreferredSize(); + size.set_width(std::round(size.width() * scale_factor)); size.set_height(std::round(size.height() * scale_factor)); @@ -52,6 +63,19 @@ drag_image->SetPaintToLayer(); drag_image->layer()->SetFillsBoundsOpaquely(false); + // Create the shadow layer. + gfx::Size shadow_size = gfx::ScaleToFlooredSize(size, kShadowScaleFactor); + gfx::Point shadow_offset((size.width() - shadow_size.width()) / 2, + (size.height() - shadow_size.height()) / 2); + shadow_ = SystemShadow::CreateShadowOnTextureLayer(kShadowType); + shadow_->SetRoundedCornerRadius(shadow_size.width() / 2); + auto* shadow_layer = shadow_->GetLayer(); + auto* image_layer = drag_image->layer(); + + image_layer->Add(shadow_layer); + image_layer->StackAtBottom(shadow_layer); + shadow_->SetContentBounds(gfx::Rect(shadow_offset, shadow_size)); + if (use_blurred_background) { const float radius = size.width() / 2.0f; drag_image->layer()->SetRoundedCornerRadius(
diff --git a/ash/app_list/views/app_drag_icon_proxy.h b/ash/app_list/views/app_drag_icon_proxy.h index 14e898e2..8e3f207 100644 --- a/ash/app_list/views/app_drag_icon_proxy.h +++ b/ash/app_list/views/app_drag_icon_proxy.h
@@ -5,6 +5,7 @@ #ifndef ASH_APP_LIST_VIEWS_APP_DRAG_ICON_PROXY_H_ #define ASH_APP_LIST_VIEWS_APP_DRAG_ICON_PROXY_H_ +#include <memory> #include "base/callback.h" #include "ui/compositor/layer_animation_observer.h" #include "ui/gfx/geometry/vector2d.h" @@ -25,6 +26,7 @@ } // namespace ui namespace ash { +class SystemShadow; // Manages the drag image shown while an app is being dragged in app list or // shelf. It creates a DragImageView widget in a window container used for @@ -83,6 +85,8 @@ // progress. bool closing_widget_ = false; + std::unique_ptr<SystemShadow> shadow_; + // The widget used to display the drag image. views::UniqueWidgetPtr drag_image_widget_;
diff --git a/ash/components/phonehub/BUILD.gn b/ash/components/phonehub/BUILD.gn index c9cfd28..8e4dcb1 100644 --- a/ash/components/phonehub/BUILD.gn +++ b/ash/components/phonehub/BUILD.gn
@@ -37,6 +37,8 @@ "do_not_disturb_controller.h", "do_not_disturb_controller_impl.cc", "do_not_disturb_controller_impl.h", + "feature_setup_response_processor.cc", + "feature_setup_response_processor.h", "feature_status.cc", "feature_status.h", "feature_status_provider.cc", @@ -239,6 +241,7 @@ "connection_scheduler_impl_unittest.cc", "cros_state_sender_unittest.cc", "do_not_disturb_controller_impl_unittest.cc", + "feature_setup_response_processor_unittest.cc", "feature_status_provider_impl_unittest.cc", "find_my_device_controller_impl_unittest.cc", "icon_decoder_impl_unittest.cc",
diff --git a/ash/components/phonehub/combined_access_setup_operation.cc b/ash/components/phonehub/combined_access_setup_operation.cc index d781859..562d239c 100644 --- a/ash/components/phonehub/combined_access_setup_operation.cc +++ b/ash/components/phonehub/combined_access_setup_operation.cc
@@ -16,12 +16,18 @@ // Status values which are considered "final" - i.e., once the status of an // operation changes to one of these values, the operation has completed. These // status values indicate either a success or a fatal error. -constexpr std::array<CombinedAccessSetupOperation::Status, 4> +constexpr std::array<CombinedAccessSetupOperation::Status, 8> kOperationFinishedStatus{ CombinedAccessSetupOperation::Status::kTimedOutConnecting, CombinedAccessSetupOperation::Status::kConnectionDisconnected, CombinedAccessSetupOperation::Status::kCompletedSuccessfully, CombinedAccessSetupOperation::Status::kProhibitedFromProvidingAccess, + CombinedAccessSetupOperation::Status::kCompletedUserRejectedAllAccess, + CombinedAccessSetupOperation::Status::kOperationFailedOrCancelled, + CombinedAccessSetupOperation::Status:: + kCameraRollGrantedNotificationRejected, + CombinedAccessSetupOperation::Status:: + kCameraRollRejectedNotificationGranted, }; } // namespace @@ -73,6 +79,22 @@ case CombinedAccessSetupOperation::Status::kProhibitedFromProvidingAccess: stream << "[Prohibited from providing access]"; break; + case CombinedAccessSetupOperation::Status::kCompletedUserRejectedAllAccess: + stream << "[User rejected to grant access]"; + break; + case CombinedAccessSetupOperation::Status::kOperationFailedOrCancelled: + stream << "[Operation failed or cancelled]"; + break; + case CombinedAccessSetupOperation::Status:: + kCameraRollGrantedNotificationRejected: + stream << "[User granted access to Camera Roll but rejected access to " + "notification]"; + break; + case CombinedAccessSetupOperation::Status:: + kCameraRollRejectedNotificationGranted: + stream << "[User rejected access to Camera Roll but granted access to " + "notification]"; + break; } return stream;
diff --git a/ash/components/phonehub/combined_access_setup_operation.h b/ash/components/phonehub/combined_access_setup_operation.h index 5171ddb5..8a9d9dca 100644 --- a/ash/components/phonehub/combined_access_setup_operation.h +++ b/ash/components/phonehub/combined_access_setup_operation.h
@@ -56,7 +56,19 @@ // the user could be using a Work Profile). kProhibitedFromProvidingAccess = 6, - kMaxValue = kProhibitedFromProvidingAccess + // The user rejected all access during setup. + kCompletedUserRejectedAllAccess = 7, + + // The setup was interrupted. + kOperationFailedOrCancelled = 8, + + // Only camera roll access is granted. + kCameraRollGrantedNotificationRejected = 9, + + // Only notification access is granted. + kCameraRollRejectedNotificationGranted = 10, + + kMaxValue = kCameraRollRejectedNotificationGranted }; // Returns true if the provided status is the final one for this operation,
diff --git a/ash/components/phonehub/fake_message_receiver.h b/ash/components/phonehub/fake_message_receiver.h index ba15115..a07044ddb 100644 --- a/ash/components/phonehub/fake_message_receiver.h +++ b/ash/components/phonehub/fake_message_receiver.h
@@ -16,6 +16,7 @@ FakeMessageReceiver() = default; ~FakeMessageReceiver() override = default; + using MessageReceiver::NotifyFeatureSetupResponseReceived; using MessageReceiver::NotifyFetchCameraRollItemDataResponseReceived; using MessageReceiver::NotifyFetchCameraRollItemsResponseReceived; using MessageReceiver::NotifyPhoneStatusSnapshotReceived;
diff --git a/ash/components/phonehub/feature_setup_response_processor.cc b/ash/components/phonehub/feature_setup_response_processor.cc new file mode 100644 index 0000000..f3607920 --- /dev/null +++ b/ash/components/phonehub/feature_setup_response_processor.cc
@@ -0,0 +1,63 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/components/phonehub/feature_setup_response_processor.h" +#include "ash/components/multidevice/logging/logging.h" +#include "ash/components/phonehub/message_receiver.h" +#include "ash/components/phonehub/multidevice_feature_access_manager.h" +#include "ash/components/phonehub/proto/phonehub_api.pb.h" + +namespace ash { +namespace phonehub { + +FeatureSetupResponseProcessor::FeatureSetupResponseProcessor( + MessageReceiver* message_receiver, + MultideviceFeatureAccessManager* multidevice_feature_access_manager) + : message_receiver_(message_receiver), + multidevice_feature_access_manager_(multidevice_feature_access_manager) { + DCHECK(message_receiver_); + DCHECK(multidevice_feature_access_manager_); + + message_receiver_->AddObserver(this); +} + +FeatureSetupResponseProcessor::~FeatureSetupResponseProcessor() { + message_receiver_->RemoveObserver(this); +} + +void FeatureSetupResponseProcessor::OnFeatureSetupResponseReceived( + proto::FeatureSetupResponse response) { + if (response.camera_roll_setup_result() == + proto::FeatureSetupResult::RESULT_ERROR_ACTION_CANCELED || + response.notification_setup_result() == + proto::FeatureSetupResult::RESULT_ERROR_ACTION_CANCELED || + response.notification_setup_result() == + proto::FeatureSetupResult::RESULT_ERROR_ACTION_TIMEOUT) { + multidevice_feature_access_manager_->SetCombinedSetupOperationStatus( + CombinedAccessSetupOperation::Status::kOperationFailedOrCancelled); + } else if (response.camera_roll_setup_result() == + proto::FeatureSetupResult::RESULT_PERMISSION_GRANTED && + response.notification_setup_result() == + proto::FeatureSetupResult::RESULT_ERROR_USER_REJECT) { + multidevice_feature_access_manager_->SetCombinedSetupOperationStatus( + CombinedAccessSetupOperation::Status:: + kCameraRollGrantedNotificationRejected); + } else if (response.camera_roll_setup_result() == + proto::FeatureSetupResult::RESULT_ERROR_USER_REJECT && + response.notification_setup_result() == + proto::FeatureSetupResult::RESULT_PERMISSION_GRANTED) { + multidevice_feature_access_manager_->SetCombinedSetupOperationStatus( + CombinedAccessSetupOperation::Status:: + kCameraRollRejectedNotificationGranted); + } else if (response.camera_roll_setup_result() == + proto::FeatureSetupResult::RESULT_ERROR_USER_REJECT || + response.notification_setup_result() == + proto::FeatureSetupResult::RESULT_ERROR_USER_REJECT) { + multidevice_feature_access_manager_->SetCombinedSetupOperationStatus( + CombinedAccessSetupOperation::Status::kCompletedUserRejectedAllAccess); + } +} + +} // namespace phonehub +} // namespace ash
diff --git a/ash/components/phonehub/feature_setup_response_processor.h b/ash/components/phonehub/feature_setup_response_processor.h new file mode 100644 index 0000000..f859f989 --- /dev/null +++ b/ash/components/phonehub/feature_setup_response_processor.h
@@ -0,0 +1,41 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMPONENTS_PHONEHUB_FEATURE_SETUP_RESPONSE_PROCESSOR_H_ +#define ASH_COMPONENTS_PHONEHUB_FEATURE_SETUP_RESPONSE_PROCESSOR_H_ + +#include "ash/components/phonehub/message_receiver.h" +#include "ash/components/phonehub/proto/phonehub_api.pb.h" + +namespace ash { +namespace phonehub { + +class MultideviceFeatureAccessManager; + +class FeatureSetupResponseProcessor : public MessageReceiver::Observer { + public: + FeatureSetupResponseProcessor( + MessageReceiver* message_receiver, + MultideviceFeatureAccessManager* multidevice_feature_access_manager); + + ~FeatureSetupResponseProcessor() override; + + FeatureSetupResponseProcessor(const FeatureSetupResponseProcessor&) = delete; + FeatureSetupResponseProcessor& operator=( + const FeatureSetupResponseProcessor&) = delete; + + private: + friend class FeatureSetupResponseProcessorTest; + + // MessageReceiver::Observer: + void OnFeatureSetupResponseReceived( + proto::FeatureSetupResponse response) override; + + MessageReceiver* message_receiver_; + MultideviceFeatureAccessManager* multidevice_feature_access_manager_; +}; + +} // namespace phonehub +} // namespace ash +#endif \ No newline at end of file
diff --git a/ash/components/phonehub/feature_setup_response_processor_unittest.cc b/ash/components/phonehub/feature_setup_response_processor_unittest.cc new file mode 100644 index 0000000..0e3bd806 --- /dev/null +++ b/ash/components/phonehub/feature_setup_response_processor_unittest.cc
@@ -0,0 +1,274 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +#include "ash/components/phonehub/feature_setup_response_processor.h" + +#include <memory> +#include <utility> + +#include "ash/components/multidevice/logging/logging.h" +#include "ash/components/phonehub/combined_access_setup_operation.h" +#include "ash/components/phonehub/fake_message_receiver.h" +#include "ash/components/phonehub/fake_multidevice_feature_access_manager.h" +#include "ash/components/phonehub/proto/phonehub_api.pb.h" +#include "ash/constants/ash_features.h" +#include "base/test/scoped_feature_list.h" +#include "base/test/task_environment.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace ash { +namespace phonehub { +namespace { +class FakeCombinedAccessSetupOperationDelegate + : public CombinedAccessSetupOperation::Delegate { + public: + FakeCombinedAccessSetupOperationDelegate() = default; + ~FakeCombinedAccessSetupOperationDelegate() override = default; + + CombinedAccessSetupOperation::Status status() const { return status_; } + + // CombinedAccessSetupOperation::Delegate: + void OnCombinedStatusChange( + CombinedAccessSetupOperation::Status new_status) override { + status_ = new_status; + } + + private: + CombinedAccessSetupOperation::Status status_ = + CombinedAccessSetupOperation::Status::kConnecting; +}; +} // namespace + +class FeatureSetupResponseProcessorTest : public testing::Test { + protected: + FeatureSetupResponseProcessorTest() = default; + FeatureSetupResponseProcessorTest(const FeatureSetupResponseProcessorTest&) = + delete; + FeatureSetupResponseProcessorTest& operator=( + const FeatureSetupResponseProcessorTest&) = delete; + ~FeatureSetupResponseProcessorTest() override = default; + + void SetUp() override { + fake_message_receiver_ = std::make_unique<FakeMessageReceiver>(); + fake_multidevice_feature_access_manager_ = + std::make_unique<FakeMultideviceFeatureAccessManager>(); + fake_multidevice_feature_access_manager_ + ->SetFeatureSetupRequestSupportedInternal(true); + scoped_feature_list_.InitWithFeatures( + /*enabled_features=*/{features::kEcheSWA, features::kPhoneHubCameraRoll, + features::kPhoneHubFeatureSetupErrorHandling}, + /*disabled_features=*/{}); + } + + void CreateFeatureSetupResponseProcessor() { + feature_setup_response_processor_ = + std::make_unique<FeatureSetupResponseProcessor>( + fake_message_receiver_.get(), + fake_multidevice_feature_access_manager_.get()); + } + + CombinedAccessSetupOperation::Status GetCombinedSetupOperationStatus() { + return fake_combined_delegate_.status(); + } + + base::test::ScopedFeatureList scoped_feature_list_; + std::unique_ptr<FakeMessageReceiver> fake_message_receiver_; + std::unique_ptr<FakeMultideviceFeatureAccessManager> + fake_multidevice_feature_access_manager_; + std::unique_ptr<FeatureSetupResponseProcessor> + feature_setup_response_processor_; + FakeCombinedAccessSetupOperationDelegate fake_combined_delegate_; +}; + +TEST_F(FeatureSetupResponseProcessorTest, ResponseReceived_All_Access_Granted) { + auto operation = + fake_multidevice_feature_access_manager_->AttemptCombinedFeatureSetup( + true, true, &fake_combined_delegate_); + EXPECT_TRUE(operation); + CreateFeatureSetupResponseProcessor(); + proto::FeatureSetupResponse setupResponse; + setupResponse.set_camera_roll_setup_result( + proto::FeatureSetupResult::RESULT_PERMISSION_GRANTED); + setupResponse.set_notification_setup_result( + proto::FeatureSetupResult::RESULT_PERMISSION_GRANTED); + + fake_message_receiver_->NotifyFeatureSetupResponseReceived(setupResponse); + + // Success cases should not be handled by this processor + EXPECT_EQ(CombinedAccessSetupOperation::Status::kConnecting, + GetCombinedSetupOperationStatus()); + EXPECT_TRUE(fake_multidevice_feature_access_manager_ + ->IsCombinedSetupOperationInProgress()); +} + +TEST_F(FeatureSetupResponseProcessorTest, + ResponseReceived_All_Access_Declined) { + auto operation = + fake_multidevice_feature_access_manager_->AttemptCombinedFeatureSetup( + true, true, &fake_combined_delegate_); + EXPECT_TRUE(operation); + CreateFeatureSetupResponseProcessor(); + proto::FeatureSetupResponse setupResponse; + setupResponse.set_camera_roll_setup_result( + proto::FeatureSetupResult::RESULT_ERROR_USER_REJECT); + setupResponse.set_notification_setup_result( + proto::FeatureSetupResult::RESULT_ERROR_USER_REJECT); + + fake_message_receiver_->NotifyFeatureSetupResponseReceived(setupResponse); + + EXPECT_EQ( + CombinedAccessSetupOperation::Status::kCompletedUserRejectedAllAccess, + GetCombinedSetupOperationStatus()); + EXPECT_FALSE(fake_multidevice_feature_access_manager_ + ->IsCombinedSetupOperationInProgress()); +} + +TEST_F(FeatureSetupResponseProcessorTest, + ResponseReceived_All_Requested_Notification_Access_Decliend) { + auto operation = + fake_multidevice_feature_access_manager_->AttemptCombinedFeatureSetup( + true, true, &fake_combined_delegate_); + EXPECT_TRUE(operation); + CreateFeatureSetupResponseProcessor(); + proto::FeatureSetupResponse setupResponse; + setupResponse.set_camera_roll_setup_result( + proto::FeatureSetupResult::RESULT_PERMISSION_GRANTED); + setupResponse.set_notification_setup_result( + proto::FeatureSetupResult::RESULT_ERROR_USER_REJECT); + + fake_message_receiver_->NotifyFeatureSetupResponseReceived(setupResponse); + + EXPECT_EQ(CombinedAccessSetupOperation::Status:: + kCameraRollGrantedNotificationRejected, + GetCombinedSetupOperationStatus()); + EXPECT_FALSE(fake_multidevice_feature_access_manager_ + ->IsCombinedSetupOperationInProgress()); +} + +TEST_F(FeatureSetupResponseProcessorTest, + ResponseReceived_All_Requested_CameraRoll_Access_Decliend) { + auto operation = + fake_multidevice_feature_access_manager_->AttemptCombinedFeatureSetup( + true, true, &fake_combined_delegate_); + EXPECT_TRUE(operation); + CreateFeatureSetupResponseProcessor(); + proto::FeatureSetupResponse setupResponse; + setupResponse.set_camera_roll_setup_result( + proto::FeatureSetupResult::RESULT_ERROR_USER_REJECT); + setupResponse.set_notification_setup_result( + proto::FeatureSetupResult::RESULT_PERMISSION_GRANTED); + + fake_message_receiver_->NotifyFeatureSetupResponseReceived(setupResponse); + + EXPECT_EQ(CombinedAccessSetupOperation::Status:: + kCameraRollRejectedNotificationGranted, + GetCombinedSetupOperationStatus()); + EXPECT_FALSE(fake_multidevice_feature_access_manager_ + ->IsCombinedSetupOperationInProgress()); +} + +TEST_F(FeatureSetupResponseProcessorTest, + ResponseReceived_CameraRoll_Requested_Access_Decliend) { + auto operation = + fake_multidevice_feature_access_manager_->AttemptCombinedFeatureSetup( + true, false, &fake_combined_delegate_); + EXPECT_TRUE(operation); + CreateFeatureSetupResponseProcessor(); + proto::FeatureSetupResponse setupResponse; + setupResponse.set_camera_roll_setup_result( + proto::FeatureSetupResult::RESULT_ERROR_USER_REJECT); + + fake_message_receiver_->NotifyFeatureSetupResponseReceived(setupResponse); + + EXPECT_EQ( + CombinedAccessSetupOperation::Status::kCompletedUserRejectedAllAccess, + GetCombinedSetupOperationStatus()); + EXPECT_FALSE(fake_multidevice_feature_access_manager_ + ->IsCombinedSetupOperationInProgress()); +} + +TEST_F(FeatureSetupResponseProcessorTest, + ResponseReceived_Notification_Requested_Access_Decliend) { + auto operation = + fake_multidevice_feature_access_manager_->AttemptCombinedFeatureSetup( + false, true, &fake_combined_delegate_); + EXPECT_TRUE(operation); + CreateFeatureSetupResponseProcessor(); + proto::FeatureSetupResponse setupResponse; + setupResponse.set_notification_setup_result( + proto::FeatureSetupResult::RESULT_ERROR_USER_REJECT); + + fake_message_receiver_->NotifyFeatureSetupResponseReceived(setupResponse); + + EXPECT_EQ( + CombinedAccessSetupOperation::Status::kCompletedUserRejectedAllAccess, + GetCombinedSetupOperationStatus()); + EXPECT_FALSE(fake_multidevice_feature_access_manager_ + ->IsCombinedSetupOperationInProgress()); +} + +TEST_F(FeatureSetupResponseProcessorTest, + ResponseReceived_All_Requested_CameraRoll_Setup_Interrupted) { + auto operation = + fake_multidevice_feature_access_manager_->AttemptCombinedFeatureSetup( + true, true, &fake_combined_delegate_); + EXPECT_TRUE(operation); + CreateFeatureSetupResponseProcessor(); + proto::FeatureSetupResponse setupResponse; + setupResponse.set_camera_roll_setup_result( + proto::FeatureSetupResult::RESULT_ERROR_ACTION_CANCELED); + setupResponse.set_notification_setup_result( + proto::FeatureSetupResult::RESULT_ERROR_ACTION_CANCELED); + + fake_message_receiver_->NotifyFeatureSetupResponseReceived(setupResponse); + + EXPECT_EQ(CombinedAccessSetupOperation::Status::kOperationFailedOrCancelled, + GetCombinedSetupOperationStatus()); + EXPECT_FALSE(fake_multidevice_feature_access_manager_ + ->IsCombinedSetupOperationInProgress()); +} + +TEST_F(FeatureSetupResponseProcessorTest, + ResponseReceived_All_Requested_Notification_Setup_Interrupted) { + auto operation = + fake_multidevice_feature_access_manager_->AttemptCombinedFeatureSetup( + true, true, &fake_combined_delegate_); + EXPECT_TRUE(operation); + CreateFeatureSetupResponseProcessor(); + proto::FeatureSetupResponse setupResponse; + setupResponse.set_camera_roll_setup_result( + proto::FeatureSetupResult::RESULT_PERMISSION_GRANTED); + setupResponse.set_notification_setup_result( + proto::FeatureSetupResult::RESULT_ERROR_ACTION_CANCELED); + + fake_message_receiver_->NotifyFeatureSetupResponseReceived(setupResponse); + + EXPECT_EQ(CombinedAccessSetupOperation::Status::kOperationFailedOrCancelled, + GetCombinedSetupOperationStatus()); + EXPECT_FALSE(fake_multidevice_feature_access_manager_ + ->IsCombinedSetupOperationInProgress()); +} + +TEST_F(FeatureSetupResponseProcessorTest, + ResponseReceived_All_Requested_Notification_Setup_Timeout) { + auto operation = + fake_multidevice_feature_access_manager_->AttemptCombinedFeatureSetup( + true, true, &fake_combined_delegate_); + EXPECT_TRUE(operation); + CreateFeatureSetupResponseProcessor(); + proto::FeatureSetupResponse setupResponse; + setupResponse.set_camera_roll_setup_result( + proto::FeatureSetupResult::RESULT_ERROR_USER_REJECT); + setupResponse.set_notification_setup_result( + proto::FeatureSetupResult::RESULT_ERROR_ACTION_TIMEOUT); + + fake_message_receiver_->NotifyFeatureSetupResponseReceived(setupResponse); + + EXPECT_EQ(CombinedAccessSetupOperation::Status::kOperationFailedOrCancelled, + GetCombinedSetupOperationStatus()); + EXPECT_FALSE(fake_multidevice_feature_access_manager_ + ->IsCombinedSetupOperationInProgress()); +} + +} // namespace phonehub +} // namespace ash \ No newline at end of file
diff --git a/ash/components/phonehub/message_receiver.cc b/ash/components/phonehub/message_receiver.cc index 1282175..b1d7785e 100644 --- a/ash/components/phonehub/message_receiver.cc +++ b/ash/components/phonehub/message_receiver.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "ash/components/phonehub/message_receiver.h" +#include "ash/components/phonehub/proto/phonehub_api.pb.h" namespace ash { namespace phonehub { @@ -30,6 +31,12 @@ observer.OnPhoneStatusUpdateReceived(phone_status_update); } +void MessageReceiver::NotifyFeatureSetupResponseReceived( + proto::FeatureSetupResponse response) { + for (auto& observer : observer_list_) + observer.OnFeatureSetupResponseReceived(response); +} + void MessageReceiver::NotifyFetchCameraRollItemsResponseReceived( const proto::FetchCameraRollItemsResponse& response) { for (auto& observer : observer_list_)
diff --git a/ash/components/phonehub/message_receiver.h b/ash/components/phonehub/message_receiver.h index 593a65c2..73bf806b6 100644 --- a/ash/components/phonehub/message_receiver.h +++ b/ash/components/phonehub/message_receiver.h
@@ -30,6 +30,10 @@ virtual void OnPhoneStatusUpdateReceived( proto::PhoneStatusUpdate phone_status_update) {} + // Called when the remote feature setup is finished on the remote pohone. + virtual void OnFeatureSetupResponseReceived( + proto::FeatureSetupResponse feature_setup_response) {} + // Called when the remote phone sends the list of camera roll items that // should be displayed via FetchCameraRollItemsResponse. virtual void OnFetchCameraRollItemsResponseReceived( @@ -55,6 +59,7 @@ proto::PhoneStatusSnapshot phone_status_snapshot); void NotifyPhoneStatusUpdateReceived( proto::PhoneStatusUpdate phone_status_update); + void NotifyFeatureSetupResponseReceived(proto::FeatureSetupResponse response); void NotifyFetchCameraRollItemsResponseReceived( const proto::FetchCameraRollItemsResponse& response); void NotifyFetchCameraRollItemDataResponseReceived(
diff --git a/ash/components/phonehub/message_receiver_impl.cc b/ash/components/phonehub/message_receiver_impl.cc index c01f9c8..f306b49 100644 --- a/ash/components/phonehub/message_receiver_impl.cc +++ b/ash/components/phonehub/message_receiver_impl.cc
@@ -40,6 +40,8 @@ return "FETCH_CAMERA_ROLL_ITEMS_RESPONSE"; case proto::MessageType::FETCH_CAMERA_ROLL_ITEM_DATA_RESPONSE: return "FETCH_CAMERA_ROLL_ITEM_DATA_RESPONSE"; + case proto::MessageType::FEATURE_SETUP_RESPONSE: + return "FEATURE_SETUP_RESPONSE"; default: return "UNKOWN_MESSAGE"; } @@ -98,6 +100,18 @@ return; } + if (features::IsPhoneHubFeatureSetupErrorHandlingEnabled() && + message_type == proto::MessageType::FEATURE_SETUP_RESPONSE) { + proto::FeatureSetupResponse response; + // Serialized proto is after the first two bytes of |payload|. + if (!response.ParseFromString(payload.substr(2))) { + PA_LOG(ERROR) << "OnMessageReceived() could not deserialize the " + << "FeatureSetupResponse proto message."; + return; + } + NotifyFeatureSetupResponseReceived(response); + } + if (features::IsPhoneHubCameraRollEnabled() && message_type == proto::MessageType::FETCH_CAMERA_ROLL_ITEMS_RESPONSE) { proto::FetchCameraRollItemsResponse response;
diff --git a/ash/components/phonehub/message_receiver_unittest.cc b/ash/components/phonehub/message_receiver_unittest.cc index e70e91f..fccb601 100644 --- a/ash/components/phonehub/message_receiver_unittest.cc +++ b/ash/components/phonehub/message_receiver_unittest.cc
@@ -32,6 +32,10 @@ return phone_status_updated_num_calls_; } + size_t feature_setup_response_num_calls() const { + return feature_setup_response_num_calls_; + } + size_t fetch_camera_roll_items_response_calls() const { return fetch_camera_roll_items_response_calls_; } @@ -46,6 +50,10 @@ return last_status_update_; } + proto::FeatureSetupResponse last_feature_setup_response() const { + return last_feature_setup_response_; + } + proto::FetchCameraRollItemsResponse last_fetch_camera_roll_items_response() const { return last_fetch_camera_roll_items_response_; @@ -69,6 +77,12 @@ ++phone_status_updated_num_calls_; } + void OnFeatureSetupResponseReceived( + proto::FeatureSetupResponse feature_setup_response) override { + last_feature_setup_response_ = feature_setup_response; + ++feature_setup_response_num_calls_; + } + void OnFetchCameraRollItemsResponseReceived( const proto::FetchCameraRollItemsResponse& response) override { last_fetch_camera_roll_items_response_ = response; @@ -84,10 +98,12 @@ private: size_t phone_status_snapshot_updated_num_calls_ = 0; size_t phone_status_updated_num_calls_ = 0; + size_t feature_setup_response_num_calls_ = 0; size_t fetch_camera_roll_items_response_calls_ = 0; size_t fetch_camera_roll_item_data_response_calls_ = 0; proto::PhoneStatusSnapshot last_snapshot_; proto::PhoneStatusUpdate last_status_update_; + proto::FeatureSetupResponse last_feature_setup_response_; proto::FetchCameraRollItemsResponse last_fetch_camera_roll_items_response_; proto::FetchCameraRollItemDataResponse last_fetch_camera_roll_item_data_response_; @@ -134,6 +150,10 @@ return fake_observer_.status_updated_num_calls(); } + size_t GetNumFeatureSetupResponseCalls() const { + return fake_observer_.feature_setup_response_num_calls(); + } + size_t GetNumFetchCameraRollItemsResponseCalls() const { return fake_observer_.fetch_camera_roll_items_response_calls(); } @@ -150,6 +170,10 @@ return fake_observer_.last_status_update(); } + proto::FeatureSetupResponse GetLastFeatureSetupResponse() const { + return fake_observer_.last_feature_setup_response(); + } + proto::FetchCameraRollItemsResponse GetLastFetchCameraRollItemsResponse() const { return fake_observer_.last_fetch_camera_roll_items_response(); @@ -222,6 +246,56 @@ } TEST_F(MessageReceiverImplTest, + OnFeatrueSetupResponseReceivedWithFeatureEnabled) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature( + features::kPhoneHubFeatureSetupErrorHandling); + + proto::FeatureSetupResponse expected_response; + expected_response.set_camera_roll_setup_result( + proto::FeatureSetupResult::RESULT_PERMISSION_GRANTED); + expected_response.set_notification_setup_result( + proto::FeatureSetupResult::RESULT_PERMISSION_GRANTED); + + const std::string expected_message = + SerializeMessage(proto::FEATURE_SETUP_RESPONSE, &expected_response); + fake_connection_manager_->NotifyMessageReceived(expected_message); + + proto::FeatureSetupResponse actual_response = GetLastFeatureSetupResponse(); + + EXPECT_EQ(0u, GetNumPhoneStatusSnapshotCalls()); + EXPECT_EQ(0u, GetNumPhoneStatusUpdatedCalls()); + EXPECT_EQ(1u, GetNumFeatureSetupResponseCalls()); + EXPECT_EQ(proto::FeatureSetupResult::RESULT_PERMISSION_GRANTED, + actual_response.camera_roll_setup_result()); + EXPECT_EQ(proto::FeatureSetupResult::RESULT_PERMISSION_GRANTED, + actual_response.notification_setup_result()); +} + +TEST_F(MessageReceiverImplTest, + OnFeatrueSetupResponseReceivedWithFeatureDisabled) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature( + features::kPhoneHubFeatureSetupErrorHandling); + + proto::FeatureSetupResponse expected_response; + expected_response.set_camera_roll_setup_result( + proto::FeatureSetupResult::RESULT_PERMISSION_GRANTED); + expected_response.set_notification_setup_result( + proto::FeatureSetupResult::RESULT_PERMISSION_GRANTED); + + const std::string expected_message = + SerializeMessage(proto::FEATURE_SETUP_RESPONSE, &expected_response); + fake_connection_manager_->NotifyMessageReceived(expected_message); + + proto::FeatureSetupResponse actual_response = GetLastFeatureSetupResponse(); + + EXPECT_EQ(0u, GetNumPhoneStatusSnapshotCalls()); + EXPECT_EQ(0u, GetNumPhoneStatusUpdatedCalls()); + EXPECT_EQ(0u, GetNumFeatureSetupResponseCalls()); +} + +TEST_F(MessageReceiverImplTest, OnFetchCameraRollItemsResponseReceivedWthFeatureEnabled) { base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature(features::kPhoneHubCameraRoll); @@ -243,6 +317,7 @@ EXPECT_EQ(0u, GetNumPhoneStatusSnapshotCalls()); EXPECT_EQ(0u, GetNumPhoneStatusUpdatedCalls()); + EXPECT_EQ(0u, GetNumFeatureSetupResponseCalls()); EXPECT_EQ(1u, GetNumFetchCameraRollItemsResponseCalls()); EXPECT_EQ(1, actual_response.items_size()); EXPECT_EQ("key", actual_response.items(0).metadata().key()); @@ -269,6 +344,7 @@ EXPECT_EQ(0u, GetNumPhoneStatusSnapshotCalls()); EXPECT_EQ(0u, GetNumPhoneStatusUpdatedCalls()); + EXPECT_EQ(0u, GetNumFeatureSetupResponseCalls()); EXPECT_EQ(0u, GetNumFetchCameraRollItemsResponseCalls()); } @@ -293,6 +369,7 @@ EXPECT_EQ(0u, GetNumPhoneStatusSnapshotCalls()); EXPECT_EQ(0u, GetNumPhoneStatusUpdatedCalls()); + EXPECT_EQ(0u, GetNumFeatureSetupResponseCalls()); EXPECT_EQ(0u, GetNumFetchCameraRollItemsResponseCalls()); EXPECT_EQ(1u, GetNumFetchCameraRollItemDataResponseCalls()); EXPECT_EQ("key", actual_response.metadata().key()); @@ -319,6 +396,7 @@ EXPECT_EQ(0u, GetNumPhoneStatusSnapshotCalls()); EXPECT_EQ(0u, GetNumPhoneStatusUpdatedCalls()); + EXPECT_EQ(0u, GetNumFeatureSetupResponseCalls()); EXPECT_EQ(0u, GetNumFetchCameraRollItemsResponseCalls()); EXPECT_EQ(0u, GetNumFetchCameraRollItemDataResponseCalls()); }
diff --git a/ash/components/phonehub/multidevice_feature_access_manager.h b/ash/components/phonehub/multidevice_feature_access_manager.h index 7d46f8c..afcdb876 100644 --- a/ash/components/phonehub/multidevice_feature_access_manager.h +++ b/ash/components/phonehub/multidevice_feature_access_manager.h
@@ -8,6 +8,7 @@ #include <ostream> #include "ash/components/phonehub/combined_access_setup_operation.h" +#include "ash/components/phonehub/feature_setup_response_processor.h" #include "ash/components/phonehub/notification_access_setup_operation.h" #include "ash/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h" #include "base/containers/flat_map.h" @@ -171,6 +172,7 @@ private: friend class MultideviceFeatureAccessManagerImplTest; friend class PhoneStatusProcessor; + friend class FeatureSetupResponseProcessor; // Sets the internal AccessStatus but does not send a request for // a new status to the remote phone device.
diff --git a/ash/components/phonehub/phone_hub_manager_impl.cc b/ash/components/phonehub/phone_hub_manager_impl.cc index 7b7a5603c..9e780ec 100644 --- a/ash/components/phonehub/phone_hub_manager_impl.cc +++ b/ash/components/phonehub/phone_hub_manager_impl.cc
@@ -157,7 +157,13 @@ multidevice_setup_client, connection_manager_.get(), std::move(camera_roll_download_manager)) - : nullptr) {} + : nullptr), + feature_setup_response_processor_( + features::IsPhoneHubFeatureSetupErrorHandlingEnabled() + ? std::make_unique<FeatureSetupResponseProcessor>( + message_receiver_.get(), + multidevice_feature_access_manager_.get()) + : nullptr) {} PhoneHubManagerImpl::~PhoneHubManagerImpl() = default; @@ -232,6 +238,7 @@ // NOTE: These should be destroyed in the opposite order of how these objects // are initialized in the constructor. void PhoneHubManagerImpl::Shutdown() { + feature_setup_response_processor_.reset(); camera_roll_manager_.reset(); invalid_connection_disconnector_.reset(); multidevice_setup_state_updater_.reset();
diff --git a/ash/components/phonehub/phone_hub_manager_impl.h b/ash/components/phonehub/phone_hub_manager_impl.h index af06eb7..c34ab89 100644 --- a/ash/components/phonehub/phone_hub_manager_impl.h +++ b/ash/components/phonehub/phone_hub_manager_impl.h
@@ -7,6 +7,7 @@ #include <memory> +#include "ash/components/phonehub/feature_setup_response_processor.h" #include "ash/components/phonehub/phone_hub_manager.h" // TODO(https://crbug.com/1164001): move to forward declaration. #include "ash/services/secure_channel/public/cpp/client/connection_manager.h" @@ -111,6 +112,8 @@ std::unique_ptr<InvalidConnectionDisconnector> invalid_connection_disconnector_; std::unique_ptr<CameraRollManager> camera_roll_manager_; + std::unique_ptr<FeatureSetupResponseProcessor> + feature_setup_response_processor_; }; } // namespace phonehub
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc index 70dab32..bc6f0544 100644 --- a/ash/constants/ash_features.cc +++ b/ash/constants/ash_features.cc
@@ -581,7 +581,7 @@ // diagnostics app routines, network events, and system snapshot. // TODO(ashleydp): Remove this after the feature is launched. const base::Feature kEnableLogControllerForDiagnosticsApp{ - "EnableLogControllerForDiagnosticsApp", base::FEATURE_DISABLED_BY_DEFAULT}; + "EnableLogControllerForDiagnosticsApp", base::FEATURE_ENABLED_BY_DEFAULT}; // If enabled, the networking cards will be shown in the diagnostics app. const base::Feature kEnableNetworkingInDiagnosticsApp{ @@ -1277,6 +1277,11 @@ "ProjectorUseOAuthForGetVideoInfo", base::FEATURE_ENABLED_BY_DEFAULT); +// Controls whether to allow viewing screencast with local playback URL when +// screencast is being transcoded. +const base::Feature kProjectorLocalPlayback("ProjectorLocalPlayback", + base::FEATURE_DISABLED_BY_DEFAULT); + // Controls whether the quick dim prototype is enabled. const base::Feature kQuickDim{"QuickDim", base::FEATURE_ENABLED_BY_DEFAULT}; @@ -2192,6 +2197,10 @@ return base::FeatureList::IsEnabled(kPhoneHubMonochromeNotificationIcons); } +bool IsPhoneHubFeatureSetupErrorHandlingEnabled() { + return base::FeatureList::IsEnabled(kPhoneHubFeatureSetupErrorHandling); +} + bool IsPerformantSplitViewResizingEnabled() { return base::FeatureList::IsEnabled(kPerformantSplitViewResizing); } @@ -2281,6 +2290,10 @@ return base::FeatureList::IsEnabled(kProjectorUseOAuthForGetVideoInfo); } +bool IsProjectorLocalPlaybackEnabled() { + return base::FeatureList::IsEnabled(kProjectorLocalPlayback); +} + bool IsQuickDimEnabled() { return base::FeatureList::IsEnabled(kQuickDim) && ash::switches::HasHps(); }
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h index 407e7e6e..92d1d79 100644 --- a/ash/constants/ash_features.h +++ b/ash/constants/ash_features.h
@@ -514,6 +514,8 @@ COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kProjectorUseOAuthForGetVideoInfo; COMPONENT_EXPORT(ASH_CONSTANTS) +extern const base::Feature kProjectorLocalPlayback; +COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kQuickDim; COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kQuickSettingsNetworkRevamp; @@ -794,6 +796,8 @@ COMPONENT_EXPORT(ASH_CONSTANTS) bool IsPerDeskShelfEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsPhoneHubCameraRollEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) +bool IsPhoneHubFeatureSetupErrorHandlingEnabled(); +COMPONENT_EXPORT(ASH_CONSTANTS) bool IsPhoneHubMonochromeNotificationIconsEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsPerformantSplitViewResizingEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsPersonalizationHubEnabled(); @@ -813,6 +817,7 @@ COMPONENT_EXPORT(ASH_CONSTANTS) bool IsProjectorExcludeTranscriptEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsProjectorTutorialVideoViewEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsProjectorCustomThumbnailEnabled(); +COMPONENT_EXPORT(ASH_CONSTANTS) bool IsProjectorLocalPlaybackEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsProjectorManagedUserIgnorePolicyEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS)
diff --git a/ash/public/cpp/projector/projector_client.h b/ash/public/cpp/projector/projector_client.h index 656accf..33df33f 100644 --- a/ash/public/cpp/projector/projector_client.h +++ b/ash/public/cpp/projector/projector_client.h
@@ -13,7 +13,6 @@ namespace ash { -class AnnotatorMessageHandler; struct NewScreencastPrecondition; // Creates interface to access Browser side functionalities for the @@ -41,15 +40,6 @@ virtual void MinimizeProjectorApp() const = 0; // Closes Projector SWA. virtual void CloseProjectorApp() const = 0; - - // Registers the AnnotatorMessageHandler that is owned by the WebUI that - // contains the Projector annotator. - virtual void SetAnnotatorMessageHandler(AnnotatorMessageHandler* handler) = 0; - // Resets the stored AnnotatorMessageHandler if it matches the one that is - // passed in. - virtual void ResetAnnotatorMessageHandler( - AnnotatorMessageHandler* handler) = 0; - // Notifies the Projector SWA if it can trigger a new Projector session. virtual void OnNewScreencastPreconditionChanged( const NewScreencastPrecondition& precondition) const = 0;
diff --git a/ash/public/cpp/test/mock_projector_client.h b/ash/public/cpp/test/mock_projector_client.h index 4246c6f..43d07f1 100644 --- a/ash/public/cpp/test/mock_projector_client.h +++ b/ash/public/cpp/test/mock_projector_client.h
@@ -38,8 +38,6 @@ MOCK_CONST_METHOD0(CloseProjectorApp, void()); MOCK_CONST_METHOD1(OnNewScreencastPreconditionChanged, void(const NewScreencastPrecondition&)); - MOCK_METHOD1(SetAnnotatorMessageHandler, void(AnnotatorMessageHandler*)); - MOCK_METHOD1(ResetAnnotatorMessageHandler, void(AnnotatorMessageHandler*)); // ProjectorAnnotatorController: MOCK_METHOD1(SetTool, void(const AnnotatorTool&));
diff --git a/ash/shelf/shelf_app_button.cc b/ash/shelf/shelf_app_button.cc index f9e14d19..58ba72d 100644 --- a/ash/shelf/shelf_app_button.cc +++ b/ash/shelf/shelf_app_button.cc
@@ -408,20 +408,7 @@ } icon_image_ = image; - const int icon_size = shelf_view_->GetButtonIconSize() * icon_scale_; - - // Resize the image maintaining our aspect ratio. - float aspect_ratio = static_cast<float>(icon_image_.width()) / - static_cast<float>(icon_image_.height()); - int height = icon_size; - int width = static_cast<int>(aspect_ratio * height); - if (width > icon_size) { - width = icon_size; - height = static_cast<int>(width / aspect_ratio); - } - - const gfx::Size preferred_size(width, height); - + gfx::Size preferred_size = GetPreferredIconSize(); if (image.size() == preferred_size) { SetShadowedImage(image); return; @@ -435,6 +422,15 @@ return icon_view_->GetImage(); } +gfx::ImageSkia ShelfAppButton::GetIconImage() const { + const gfx::Size preferred_size = GetPreferredSize(); + if (icon_image_.size() == preferred_size) + return icon_image_; + + return gfx::ImageSkiaOperations::CreateResizedImage( + icon_image_, skia::ImageOperations::RESIZE_BEST, GetPreferredIconSize()); +} + void ShelfAppButton::AddState(State state) { if (!(state_ & state)) { state_ |= state; @@ -719,7 +715,6 @@ // Expand bounds to include shadows. gfx::Insets insets_shadows = gfx::ShadowValue::GetMargin(icon_shadows_); - // insets_shadows = insets_shadows.Scale(icon_scale); // Center icon with respect to the secondary axis. if (is_horizontal_shelf) x_offset = std::max(0.0f, button_bounds.width() - icon_width + 1) / 2; @@ -949,6 +944,22 @@ return gfx::TransformBetweenRects(target_bounds, pre_scaling_bounds); } +gfx::Size ShelfAppButton::GetPreferredIconSize() const { + const int icon_size = shelf_view_->GetButtonIconSize() * icon_scale_; + + // Resize the image maintaining our aspect ratio. + float aspect_ratio = static_cast<float>(icon_image_.width()) / + static_cast<float>(icon_image_.height()); + int height = icon_size; + int width = static_cast<int>(aspect_ratio * height); + if (width > icon_size) { + width = icon_size; + height = static_cast<int>(width / aspect_ratio); + } + + return gfx::Size(width, height); +} + void ShelfAppButton::ScaleAppIcon(bool scale_up) { StopObservingImplicitAnimations();
diff --git a/ash/shelf/shelf_app_button.h b/ash/shelf/shelf_app_button.h index 7c54c77d..862ad52 100644 --- a/ash/shelf/shelf_app_button.h +++ b/ash/shelf/shelf_app_button.h
@@ -74,6 +74,9 @@ // Retrieve the image to show proxy operations. gfx::ImageSkia GetImage() const; + // Gets the resized `icon_image_` without the shadow. + gfx::ImageSkia GetIconImage() const; + // |state| is or'd into the current state. void AddState(State state); void ClearState(State state); @@ -162,6 +165,9 @@ // Invoked when |ripple_activation_timer_| fires to activate the ink drop. void OnRippleTimer(); + // Calculates the preferred size of the icon. + gfx::Size GetPreferredIconSize() const; + // Scales up app icon if |scale_up| is true, otherwise scales it back to // normal size. void ScaleAppIcon(bool scale_up);
diff --git a/ash/shelf/shelf_view.cc b/ash/shelf/shelf_view.cc index a2f49c9..6676c7cb 100644 --- a/ash/shelf/shelf_view.cc +++ b/ash/shelf/shelf_view.cc
@@ -1519,8 +1519,8 @@ ? 1.0f : kDragAndDropProxyScale; drag_icon_proxy_ = std::make_unique<AppDragIconProxy>( - root_window, drag_view_->GetImage(), screen_location, gfx::Vector2d(), - scale_factor, /*use_blurred_background=*/false); + root_window, drag_view_->GetIconImage(), screen_location, + gfx::Vector2d(), scale_factor, /*use_blurred_background=*/false); if (pointer == MOUSE) { haptics_util::PlayHapticTouchpadEffect( @@ -1658,7 +1658,7 @@ if (GetBoundsForDragInsertInScreen().Contains(screen_location)) { if (!is_active_drag_and_drop_host_) { drag_icon_proxy_ = std::make_unique<AppDragIconProxy>( - root_window, drag_view_->GetImage(), screen_location, + root_window, drag_view_->GetIconImage(), screen_location, /*cursor_offset_from_center=*/gfx::Vector2d(), /*scale_factor=*/1.0f, /*use_blurred_background=*/false); @@ -1692,7 +1692,7 @@ const gfx::Point center = drag_view_->GetLocalBounds().CenterPoint(); const gfx::Vector2d cursor_offset_from_center = drag_origin_ - center; drag_icon_proxy_ = std::make_unique<AppDragIconProxy>( - root_window, drag_view_->GetImage(), screen_location, + root_window, drag_view_->GetIconImage(), screen_location, cursor_offset_from_center, /*scale_factor=*/1.0f, /*use_blurred_background=*/false); delegate_->CancelScrollForItemDrag();
diff --git a/ash/system/message_center/ash_notification_view.cc b/ash/system/message_center/ash_notification_view.cc index ebbfaae3..671faca 100644 --- a/ash/system/message_center/ash_notification_view.cc +++ b/ash/system/message_center/ash_notification_view.cc
@@ -184,16 +184,18 @@ .SetBetweenChildSpacing(ash::kGroupedCollapsedSummaryLabelSpacing) .SetOrientation(views::BoxLayout::Orientation::kHorizontal) .SetVisible(false) - .AddChild( - views::Builder<views::Label>() - .SetText(notification.title()) - .SetFontList(gfx::FontList({kGoogleSansFont}, gfx::Font::NORMAL, - message_center::kTitleFontSize, - gfx::Font::Weight::MEDIUM))) + .AddChild(views::Builder<views::Label>() + .SetText(notification.title()) + .SetFontList(gfx::FontList( + {kGoogleSansFont}, gfx::Font::NORMAL, kTitleLabelSize, + gfx::Font::Weight::MEDIUM))) .AddChild(views::Builder<views::Label>() .SetText(notification.message()) .SetTextContext(views::style::CONTEXT_DIALOG_BODY_TEXT) - .SetTextStyle(views::style::STYLE_SECONDARY)); + .SetTextStyle(views::style::STYLE_SECONDARY) + .SetFontList(gfx::FontList( + {kGoogleSansFont}, gfx::Font::NORMAL, kMessageLabelSize, + gfx::Font::Weight::MEDIUM))); } views::Builder<ash::AshNotificationView::GroupedNotificationsContainer> @@ -904,15 +906,11 @@ // are collapsed. bool use_expanded_padding = expanded || is_grouped_parent_view_; - bool is_single_expanded_notification = - !is_grouped_child_view_ && !is_grouped_parent_view_ && expanded; - header_row()->SetVisible(is_grouped_parent_view_ || - (is_single_expanded_notification)); + header_row()->SetVisible(is_grouped_parent_view_ || expanded); header_row()->SetTimestampVisible(!is_grouped_parent_view_ || !expanded); if (title_row_) { - title_row_->UpdateVisibility(is_grouped_child_view_ || - (IsExpandable() && !expanded)); + title_row_->UpdateVisibility(IsExpandable() && !expanded); title_row_->title_view()->SetMaxLines( expanded ? kTitleLabelExpandedMaxLines : kTitleLabelCollapsedMaxLines); title_row_->title_view()->SetMaximumWidth(GetExpandedTitleLabelWidth()); @@ -994,7 +992,7 @@ if (is_grouped_child_view_ && !is_nested()) SetIsNested(); - header_row()->SetVisible(!is_grouped_child_view_); + header_row()->SetIsInGroupChildNotification(is_grouped_child_view_); UpdateMessageLabelInExpandedState(notification); NotificationViewBase::UpdateWithNotification(notification);
diff --git a/ash/system/message_center/message_center_constants.h b/ash/system/message_center/message_center_constants.h index 4d258e0..d21ad541 100644 --- a/ash/system/message_center/message_center_constants.h +++ b/ash/system/message_center/message_center_constants.h
@@ -15,8 +15,8 @@ constexpr int kGroupedCollapsedSummaryMessageLength = 250; constexpr auto kGroupedCollapsedSummaryInsets = gfx::Insets::TLBR(0, 50, 0, 16); -constexpr int kGroupedNotificationsExpandedSpacing = 16; -constexpr int kGroupedNotificationsCollapsedSpacing = 12; +constexpr int kGroupedNotificationsExpandedSpacing = 0; +constexpr int kGroupedNotificationsCollapsedSpacing = 4; constexpr auto kGroupedNotificationContainerCollapsedInsets = gfx::Insets::TLBR(0, 0, 20, 0); constexpr auto kGroupedNotificationContainerExpandedInsets =
diff --git a/ash/system/time/calendar_view.cc b/ash/system/time/calendar_view.cc index 74bdb94..ed9b811 100644 --- a/ash/system/time/calendar_view.cc +++ b/ash/system/time/calendar_view.cc
@@ -1110,6 +1110,13 @@ gfx::Tween::FAST_OUT_SLOW_IN); } +void CalendarView::OnSelectedDateUpdated() { + // If the event list is already open and the date cell is focused, moves the + // focusing ring to the close button. + if (event_list_view_ && IsDateCellViewFocused()) + RequestFocusForEventListCloseButton(); +} + void CalendarView::ScrollUpOneMonth() { calendar_view_controller_->UpdateMonth( calendar_view_controller_->GetPreviousMonthFirstDayUTC(1)); @@ -1633,16 +1640,8 @@ // Moves focusing ring to the close button of the event list if it's opened // from the date cell view focus. - if (IsDateCellViewFocused()) { - auto* focus_manager = GetFocusManager(); - event_list_view_->RequestFocus(); - focus_manager->AdvanceFocus(/*reverse=*/false); - current_month_->DisableFocus(); - previous_month_->DisableFocus(); - next_month_->DisableFocus(); - next_next_month_->DisableFocus(); - content_view_->SetFocusBehavior(FocusBehavior::ALWAYS); - } + if (IsDateCellViewFocused()) + RequestFocusForEventListCloseButton(); up_button_->SetTooltipText(l10n_util::GetStringUTF16( IDS_ASH_CALENDAR_UP_BUTTON_EVENT_LIST_ACCESSIBLE_DESCRIPTION)); @@ -1677,6 +1676,18 @@ IDS_ASH_CALENDAR_DOWN_BUTTON_ACCESSIBLE_DESCRIPTION)); } +void CalendarView::RequestFocusForEventListCloseButton() { + DCHECK(event_list_view_); + auto* focus_manager = GetFocusManager(); + event_list_view_->RequestFocus(); + focus_manager->AdvanceFocus(/*reverse=*/false); + current_month_->DisableFocus(); + previous_month_->DisableFocus(); + next_month_->DisableFocus(); + next_next_month_->DisableFocus(); + content_view_->SetFocusBehavior(FocusBehavior::ALWAYS); +} + void CalendarView::OnResetToTodayAnimationComplete() { SetShouldMonthsAnimateAndScrollEnabled(/*enabled=*/true); ResetToToday();
diff --git a/ash/system/time/calendar_view.h b/ash/system/time/calendar_view.h index a621b82..4f81873 100644 --- a/ash/system/time/calendar_view.h +++ b/ash/system/time/calendar_view.h
@@ -90,6 +90,7 @@ void OnMonthChanged() override; void OpenEventList() override; void CloseEventList() override; + void OnSelectedDateUpdated() override; // views::ViewObserver: void OnViewBoundsChanged(views::View* observed_view) override; @@ -293,6 +294,9 @@ void OnOpenEventListAnimationComplete(); void OnCloseEventListAnimationComplete(); + // Requests the focusing ring to go to the close button of `event_list_view_`. + void RequestFocusForEventListCloseButton(); + // Animates the month and scrolls back to today and resets the // `scrolling_settled_timer_` to update the `on_screen_month_` map after the // resetting to today animation.
diff --git a/ash/system/time/calendar_view_unittest.cc b/ash/system/time/calendar_view_unittest.cc index 34d4632..4380c02a 100644 --- a/ash/system/time/calendar_view_unittest.cc +++ b/ash/system/time/calendar_view_unittest.cc
@@ -187,6 +187,10 @@ } void ResetToToday() { calendar_view_->ResetToToday(); } + void RequestFocusForEventListCloseButton() { + calendar_view_->RequestFocusForEventListCloseButton(); + } + void PressTab() { ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow()); generator.PressKey(ui::KeyboardCode::VKEY_TAB, ui::EF_NONE); @@ -787,6 +791,116 @@ EXPECT_EQ(todays_date_cell_view, focus_manager->GetFocusedView()); } +// Tests `RequestFocusForEventListCloseButton()`. +TEST_F(CalendarViewTest, CloseButtonFocusing) { + base::Time date; + // Create a monthview based on Jun,7th 2021. + ASSERT_TRUE(base::Time::FromString("7 Jun 2021 10:00 GMT", &date)); + + // Set time override. + SetFakeNow(date); + base::subtle::ScopedTimeClockOverrides time_override( + &CalendarViewTest::FakeTimeNow, /*time_ticks_override=*/nullptr, + /*thread_ticks_override=*/nullptr); + + CreateCalendarView(); + + auto* focus_manager = calendar_view()->GetFocusManager(); + // Todays DateCellView should be focused on open. + ASSERT_EQ(u"7", + static_cast<views::LabelButton*>(focus_manager->GetFocusedView()) + ->GetText()); + ASSERT_FALSE(event_list_view()); + + PressEnter(); + EXPECT_TRUE(event_list_view()); + + EXPECT_EQ(focus_manager->GetFocusedView(), close_button()); + + // Focus moves back to the date cell. + PressShiftTab(); + EXPECT_EQ(u"7", + static_cast<views::LabelButton*>(focus_manager->GetFocusedView()) + ->GetText()); + + // Manually moves the focus to the close button. + RequestFocusForEventListCloseButton(); + EXPECT_EQ(focus_manager->GetFocusedView(), close_button()); +} + +// Tests when the focus changes to another date cell with the event list opened, +// the focusing ring will go to the close button automatically. +TEST_F(CalendarViewTest, FocusingToCloseButtonWithEventListOpened) { + base::Time date; + // Create a monthview based on Jun,7th 2021. + ASSERT_TRUE(base::Time::FromString("7 Jun 2021 10:00 GMT", &date)); + + // Set time override. + SetFakeNow(date); + base::subtle::ScopedTimeClockOverrides time_override( + &CalendarViewTest::FakeTimeNow, /*time_ticks_override=*/nullptr, + /*thread_ticks_override=*/nullptr); + + CreateCalendarView(); + + auto* focus_manager = calendar_view()->GetFocusManager(); + // Todays DateCellView should be focused on open. + ASSERT_EQ(u"7", + static_cast<views::LabelButton*>(focus_manager->GetFocusedView()) + ->GetText()); + ASSERT_FALSE(event_list_view()); + + PressEnter(); + EXPECT_TRUE(event_list_view()); + + EXPECT_EQ(focus_manager->GetFocusedView(), close_button()); + + // Focus moves back to today's date cell. + PressShiftTab(); + EXPECT_EQ(u"7", + static_cast<views::LabelButton*>(focus_manager->GetFocusedView()) + ->GetText()); + + // Navigates to another date cell and focuses on it. The focusing ring should + // go to the close button automatically. + PressUp(); + EXPECT_EQ(u"31", + static_cast<views::LabelButton*>(focus_manager->GetFocusedView()) + ->GetText()); + PressEnter(); + EXPECT_TRUE(event_list_view()); + EXPECT_EQ(focus_manager->GetFocusedView(), close_button()); + + // Tests different date cells and expects the same focusing behavior. + PressShiftTab(); + PressLeft(); + EXPECT_EQ(u"29", + static_cast<views::LabelButton*>(focus_manager->GetFocusedView()) + ->GetText()); + PressEnter(); + EXPECT_TRUE(event_list_view()); + EXPECT_EQ(focus_manager->GetFocusedView(), close_button()); + + PressShiftTab(); + PressRight(); + PressRight(); + EXPECT_EQ(u"25", + static_cast<views::LabelButton*>(focus_manager->GetFocusedView()) + ->GetText()); + PressEnter(); + EXPECT_TRUE(event_list_view()); + EXPECT_EQ(focus_manager->GetFocusedView(), close_button()); + + PressShiftTab(); + PressDown(); + EXPECT_EQ(u"30", + static_cast<views::LabelButton*>(focus_manager->GetFocusedView()) + ->GetText()); + PressEnter(); + EXPECT_TRUE(event_list_view()); + EXPECT_EQ(focus_manager->GetFocusedView(), close_button()); +} + TEST_F(CalendarViewTest, MonthViewFocusing) { base::Time date; // Create a monthview based on Jun,7th 2021.
diff --git a/ash/wallpaper/wallpaper_controller_impl.cc b/ash/wallpaper/wallpaper_controller_impl.cc index 260bafc5..08ab9be 100644 --- a/ash/wallpaper/wallpaper_controller_impl.cc +++ b/ash/wallpaper/wallpaper_controller_impl.cc
@@ -100,6 +100,9 @@ namespace { +// Global to hold a WallpaperPrefManager for testing in `Create`. +std::unique_ptr<WallpaperPrefManager> g_test_pref_manager; + // The file name of the policy wallpaper. constexpr char kPolicyWallpaperFile[] = "policy-controlled.jpeg"; @@ -657,11 +660,23 @@ PrefService* local_state) { auto online_wallpaper_variant_fetcher = std::make_unique<OnlineWallpaperVariantInfoFetcher>(); + if (g_test_pref_manager) { + return std::make_unique<WallpaperControllerImpl>( + std::move(g_test_pref_manager), + std::move(online_wallpaper_variant_fetcher)); + } + auto pref_manager = WallpaperPrefManager::Create(local_state); return std::make_unique<WallpaperControllerImpl>( std::move(pref_manager), std::move(online_wallpaper_variant_fetcher)); } +// static +void WallpaperControllerImpl::SetWallpaperPrefManagerForTesting( + std::unique_ptr<WallpaperPrefManager> pref_manager) { + g_test_pref_manager.swap(pref_manager); +} + WallpaperControllerImpl::WallpaperControllerImpl( std::unique_ptr<WallpaperPrefManager> pref_manager, std::unique_ptr<OnlineWallpaperVariantInfoFetcher> online_fetcher)
diff --git a/ash/wallpaper/wallpaper_controller_impl.h b/ash/wallpaper/wallpaper_controller_impl.h index d3c7f6e..66694dc 100644 --- a/ash/wallpaper/wallpaper_controller_impl.h +++ b/ash/wallpaper/wallpaper_controller_impl.h
@@ -102,6 +102,9 @@ static std::unique_ptr<WallpaperControllerImpl> Create( PrefService* local_state); + static void SetWallpaperPrefManagerForTesting( + std::unique_ptr<WallpaperPrefManager> pref_manager); + // Prefer to use to obtain an new instance unless injecting non-production // members i.e. in tests. explicit WallpaperControllerImpl( @@ -201,11 +204,6 @@ bool SetUserWallpaperInfo(const AccountId& account_id, const WallpaperInfo& info); - // Gets wallpaper info of |account_id| from local state, or memory if the user - // is ephemeral. Returns false if wallpaper info is not found. - bool GetUserWallpaperInfo(const AccountId& account_id, - WallpaperInfo* info) const; - // Gets encoded wallpaper from cache. Returns true if success. bool GetWallpaperFromCache(const AccountId& account_id, gfx::ImageSkia* image); @@ -391,6 +389,11 @@ base::FilePath file_path; }; + // Gets wallpaper info of |account_id| from local state, or memory if the user + // is ephemeral. Returns false if wallpaper info is not found. + bool GetUserWallpaperInfo(const AccountId& account_id, + WallpaperInfo* info) const; + // Update a Wallpaper for |root_window|. void UpdateWallpaperForRootWindow(aura::Window* root_window, bool lock_state_changed,
diff --git a/ash/wallpaper/wallpaper_controller_unittest.cc b/ash/wallpaper/wallpaper_controller_unittest.cc index 64b44373..7fc155f 100644 --- a/ash/wallpaper/wallpaper_controller_unittest.cc +++ b/ash/wallpaper/wallpaper_controller_unittest.cc
@@ -262,85 +262,11 @@ } } -base::Value::Dict CreateWallpaperInfoDict(WallpaperInfo info) { - base::Value::Dict wallpaper_info_dict; - if (info.asset_id.has_value()) { - wallpaper_info_dict.Set(WallpaperPrefManager::kNewWallpaperAssetIdNodeName, - base::NumberToString(info.asset_id.value())); - } - if (info.dedup_key.has_value()) { - wallpaper_info_dict.Set(WallpaperPrefManager::kNewWallpaperDedupKeyNodeName, - info.dedup_key.value()); - } - if (info.unit_id.has_value()) { - wallpaper_info_dict.Set(WallpaperPrefManager::kNewWallpaperUnitIdNodeName, - base::NumberToString(info.unit_id.value())); - } - base::Value::List online_wallpaper_variant_list; - for (const auto& variant : info.variants) { - base::Value::Dict online_wallpaper_variant_dict; - online_wallpaper_variant_dict.Set( - WallpaperPrefManager::kNewWallpaperAssetIdNodeName, - base::NumberToString(variant.asset_id)); - online_wallpaper_variant_dict.Set( - WallpaperPrefManager::kOnlineWallpaperUrlNodeName, - variant.raw_url.spec()); - online_wallpaper_variant_dict.Set( - WallpaperPrefManager::kOnlineWallpaperTypeNodeName, - static_cast<int>(variant.type)); - online_wallpaper_variant_list.Append( - std::move(online_wallpaper_variant_dict)); - } - wallpaper_info_dict.Set( - WallpaperPrefManager::kNewWallpaperVariantListNodeName, - std::move(online_wallpaper_variant_list)); - wallpaper_info_dict.Set( - WallpaperPrefManager::kNewWallpaperCollectionIdNodeName, - info.collection_id); - wallpaper_info_dict.Set(WallpaperPrefManager::kNewWallpaperDateNodeName, - base::NumberToString(info.date.ToInternalValue())); - wallpaper_info_dict.Set(WallpaperPrefManager::kNewWallpaperLocationNodeName, - info.location); - wallpaper_info_dict.Set( - WallpaperPrefManager::kNewWallpaperUserFilePathNodeName, - info.user_file_path); - wallpaper_info_dict.Set(WallpaperPrefManager::kNewWallpaperLayoutNodeName, - info.layout); - wallpaper_info_dict.Set(WallpaperPrefManager::kNewWallpaperTypeNodeName, - static_cast<int>(info.type)); - return wallpaper_info_dict; -} - -PrefService* GetLocalPrefService() { - return Shell::Get()->local_state(); -} - PrefService* GetProfilePrefService(const AccountId& account_id) { return Shell::Get()->session_controller()->GetUserPrefServiceForUser( account_id); } -void PutWallpaperInfoInPrefs(AccountId account_id, - WallpaperInfo info, - PrefService* pref_service, - const std::string& pref_name) { - DictionaryPrefUpdate wallpaper_update(pref_service, pref_name); - base::Value::Dict wallpaper_info_dict = CreateWallpaperInfoDict(info); - wallpaper_update->SetKey(account_id.GetUserEmail(), - base::Value(std::move(wallpaper_info_dict))); -} - -void AssertWallpaperInfoInPrefs(const PrefService* pref_service, - const char pref_name[], - AccountId account_id, - WallpaperInfo info) { - const base::Value::Dict& pref_dict = pref_service->GetValueDict(pref_name); - const base::Value::Dict* stored_info_dict = - pref_dict.FindDict(account_id.GetUserEmail()); - base::Value::Dict expected_info_dict = CreateWallpaperInfoDict(info); - EXPECT_EQ(expected_info_dict, *stored_info_dict); -} - WallpaperInfo InfoWithType(WallpaperType type) { WallpaperInfo info(std::string(), WALLPAPER_LAYOUT_CENTER_CROPPED, type, base::Time::Now()); @@ -419,6 +345,13 @@ WallpaperControllerTest& operator=(const WallpaperControllerTest&) = delete; void SetUp() override { + auto pref_manager = WallpaperPrefManager::Create(local_state()); + pref_manager_ = pref_manager.get(); + // Override the pref manager that will be used to construct the + // WallpaperController. + WallpaperControllerImpl::SetWallpaperPrefManagerForTesting( + std::move(pref_manager)); + AshTestBase::SetUp(); TestSessionControllerClient* const client = GetSessionControllerClient(); @@ -568,13 +501,13 @@ WallpaperInfo info = {relative_path, WALLPAPER_LAYOUT_CENTER_CROPPED, WallpaperType::kCustomized, base::Time::Now().LocalMidnight()}; - ASSERT_TRUE(controller_->SetUserWallpaperInfo(account_id, info)); + ASSERT_TRUE(pref_manager_->SetUserWallpaperInfo(account_id, info)); } // Simulates setting a custom wallpaper by directly setting the wallpaper // info. void SimulateSettingCustomWallpaper(const AccountId& account_id) { - ASSERT_TRUE(controller_->SetUserWallpaperInfo( + ASSERT_TRUE(pref_manager_->SetUserWallpaperInfo( account_id, WallpaperInfo("dummy_file_location", WALLPAPER_LAYOUT_CENTER, WallpaperType::kCustomized, @@ -726,7 +659,8 @@ RunAllTasksUntilIdle(); } - WallpaperControllerImpl* controller_ = nullptr; // Not owned. + WallpaperControllerImpl* controller_; + WallpaperPrefManager* pref_manager_ = nullptr; // owned by controller base::ScopedTempDir user_data_dir_; base::ScopedTempDir online_wallpaper_dir_; @@ -1120,7 +1054,8 @@ WallpaperController::SetWallpaperCallback()); RunAllTasksUntilIdle(); // Verify that the user wallpaper info is updated. - EXPECT_TRUE(controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); + EXPECT_TRUE( + pref_manager_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); WallpaperInfo expected_wallpaper_info( kDummyUrl, WALLPAPER_LAYOUT_CENTER_CROPPED, WallpaperType::kOnline, base::Time::Now().LocalMidnight()); @@ -1142,7 +1077,8 @@ WallpaperController::SetWallpaperCallback()); RunAllTasksUntilIdle(); EXPECT_EQ(0, GetWallpaperCount()); - EXPECT_TRUE(controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); + EXPECT_TRUE( + pref_manager_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); WallpaperInfo expected_wallpaper_info_2( kDummyUrl2, WALLPAPER_LAYOUT_CENTER_CROPPED, WallpaperType::kOnline, base::Time::Now().LocalMidnight()); @@ -1176,7 +1112,8 @@ EXPECT_EQ(controller_->GetWallpaperType(), WallpaperType::kOnline); // Verify that the user wallpaper info is updated. WallpaperInfo wallpaper_info; - EXPECT_TRUE(controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); + EXPECT_TRUE( + pref_manager_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); WallpaperInfo expected_wallpaper_info(params); EXPECT_EQ(wallpaper_info, expected_wallpaper_info); // Verify that wallpaper & collection metrics are logged. @@ -1208,20 +1145,21 @@ // The user starts with no wallpaper info and is not controlled by policy. WallpaperInfo wallpaper_info; EXPECT_FALSE( - controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); EXPECT_FALSE(controller_->IsWallpaperControlledByPolicy(account_id_1)); // A default wallpaper is shown for the user. ClearWallpaperCount(); controller_->ShowUserWallpaper(account_id_1); EXPECT_EQ(1, GetWallpaperCount()); - EXPECT_EQ(controller_->GetWallpaperType(), WallpaperType::kDefault); + ASSERT_EQ(controller_->GetWallpaperType(), WallpaperType::kDefault); // Set a policy wallpaper. Verify that the user becomes policy controlled and // the wallpaper info is updated. ClearWallpaperCount(); controller_->SetPolicyWallpaper(account_id_1, std::string() /*data=*/); RunAllTasksUntilIdle(); - EXPECT_TRUE(controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); + EXPECT_TRUE( + pref_manager_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); WallpaperInfo policy_wallpaper_info(base::FilePath(wallpaper_files_id_1) .Append("policy-controlled.jpeg") .value(), @@ -1238,7 +1176,7 @@ ClearWallpaperCount(); controller_->ShowUserWallpaper(account_id_1); EXPECT_EQ(1, GetWallpaperCount()); - EXPECT_EQ(controller_->GetWallpaperType(), WallpaperType::kPolicy); + ASSERT_EQ(controller_->GetWallpaperType(), WallpaperType::kPolicy); // Clear the wallpaper and log out the user. Verify the policy wallpaper is // shown in the login screen. @@ -1254,7 +1192,8 @@ ClearWallpaperCount(); controller_->RemovePolicyWallpaper(account_id_1); WaitUntilCustomWallpapersDeleted(account_id_1); - EXPECT_TRUE(controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); + EXPECT_TRUE( + pref_manager_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); WallpaperInfo default_wallpaper_info( std::string(), WALLPAPER_LAYOUT_CENTER_CROPPED, WallpaperType::kDefault, base::Time::Now().LocalMidnight()); @@ -1288,7 +1227,8 @@ // Verify the wallpaper was set. WallpaperInfo wallpaper_info; - ASSERT_TRUE(controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); + ASSERT_TRUE( + pref_manager_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); ASSERT_EQ(WallpaperType::kCustomized, wallpaper_info.type); ASSERT_EQ("user1@test.com-hash/user1@test.com-file", wallpaper_info.location); @@ -1333,7 +1273,8 @@ // Verify the wallpaper was set. WallpaperInfo wallpaper_info; - ASSERT_TRUE(controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); + ASSERT_TRUE( + pref_manager_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); ASSERT_EQ(WallpaperType::kCustomized, wallpaper_info.type); ASSERT_EQ("user1@test.com-hash/user1@test.com-file", wallpaper_info.location); @@ -1360,7 +1301,7 @@ WallpaperInfo wallpaper_info; EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); WallpaperInfo expected_wallpaper_info( base::FilePath(wallpaper_files_id_1).Append(file_name_1).value(), WALLPAPER_LAYOUT_CENTER, WallpaperType::kCustomized, @@ -1394,7 +1335,7 @@ // Verify the user starts with no wallpaper info. WallpaperInfo wallpaper_info; EXPECT_FALSE( - controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); // Set a third-party wallpaper for |kUser1|. const WallpaperLayout layout = WALLPAPER_LAYOUT_CENTER; @@ -1405,7 +1346,8 @@ // Verify the wallpaper is shown. EXPECT_EQ(1, GetWallpaperCount()); // Verify the user wallpaper info is updated. - EXPECT_TRUE(controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); + EXPECT_TRUE( + pref_manager_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); WallpaperInfo expected_wallpaper_info( base::FilePath(wallpaper_files_id_1).Append(file_name_1).value(), layout, WallpaperType::kCustomized, base::Time::Now().LocalMidnight()); @@ -1422,7 +1364,8 @@ EXPECT_EQ(0, GetWallpaperCount()); // Verify the wallpaper info for |kUser1| is updated, because setting // wallpaper is still allowed for non-active users. - EXPECT_TRUE(controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); + EXPECT_TRUE( + pref_manager_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); WallpaperInfo expected_wallpaper_info_2( base::FilePath(wallpaper_files_id_1).Append(file_name_2).value(), layout, WallpaperType::kCustomized, base::Time::Now().LocalMidnight()); @@ -1446,7 +1389,8 @@ // info. EXPECT_TRUE(controller_->IsWallpaperControlledByPolicy(account_id_2)); EXPECT_TRUE(controller_->IsActiveUserWallpaperControlledByPolicy()); - EXPECT_TRUE(controller_->GetUserWallpaperInfo(account_id_2, &wallpaper_info)); + EXPECT_TRUE( + pref_manager_->GetUserWallpaperInfo(account_id_2, &wallpaper_info)); WallpaperInfo policy_wallpaper_info(base::FilePath(wallpaper_files_id_2) .Append("policy-controlled.jpeg") .value(), @@ -1463,7 +1407,8 @@ // First, simulate setting a user custom wallpaper. SimulateSettingCustomWallpaper(account_id_1); WallpaperInfo wallpaper_info; - EXPECT_TRUE(controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); + EXPECT_TRUE( + pref_manager_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); WallpaperInfo default_wallpaper_info( std::string(), WALLPAPER_LAYOUT_CENTER_CROPPED, WallpaperType::kDefault, base::Time::Now().LocalMidnight()); @@ -1485,7 +1430,8 @@ EXPECT_EQ(default_wallpaper_dir_.GetPath().Append(kDefaultLargeWallpaperName), GetDecodeFilePaths()[0]); - EXPECT_TRUE(controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); + EXPECT_TRUE( + pref_manager_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); // The user wallpaper info has been reset to the default value. EXPECT_EQ(wallpaper_info, default_wallpaper_info); @@ -1506,7 +1452,8 @@ EXPECT_EQ(default_wallpaper_dir_.GetPath().Append(kDefaultSmallWallpaperName), GetDecodeFilePaths()[0]); - EXPECT_TRUE(controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); + EXPECT_TRUE( + pref_manager_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); // The user wallpaper info has been reset to the default value. EXPECT_EQ(wallpaper_info, default_wallpaper_info); @@ -1527,7 +1474,8 @@ EXPECT_EQ(default_wallpaper_dir_.GetPath().Append(kDefaultSmallWallpaperName), GetDecodeFilePaths()[0]); - EXPECT_TRUE(controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); + EXPECT_TRUE( + pref_manager_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); // The user wallpaper info has been reset to the default value. EXPECT_EQ(wallpaper_info, default_wallpaper_info); } @@ -1602,7 +1550,7 @@ // guest session. EXPECT_EQ(1, GetWallpaperCount()); EXPECT_EQ(controller_->GetWallpaperType(), WallpaperType::kDefault); - EXPECT_TRUE(controller_->GetUserWallpaperInfo(guest_id, &wallpaper_info)); + EXPECT_TRUE(pref_manager_->GetUserWallpaperInfo(guest_id, &wallpaper_info)); EXPECT_EQ(wallpaper_info, default_wallpaper_info); ASSERT_EQ(1u, GetDecodeFilePaths().size()); EXPECT_EQ(default_wallpaper_dir_.GetPath().Append(kGuestLargeWallpaperName), @@ -1612,8 +1560,8 @@ // user and verifying that the policy has been applied successfully. WallpaperInfo policy_wallpaper_info; controller_->SetPolicyWallpaper(account_id_1, /*data=*/std::string()); - EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_1, &policy_wallpaper_info)); + EXPECT_TRUE(pref_manager_->GetUserWallpaperInfo(account_id_1, + &policy_wallpaper_info)); WallpaperInfo expected_policy_wallpaper_info( base::FilePath(wallpaper_files_id_1) .Append("policy-controlled.jpeg") @@ -1628,7 +1576,7 @@ EXPECT_EQ(1, GetWallpaperCount()); EXPECT_EQ(controller_->GetWallpaperType(), WallpaperType::kDefault); - EXPECT_TRUE(controller_->GetUserWallpaperInfo(guest_id, &wallpaper_info)); + EXPECT_TRUE(pref_manager_->GetUserWallpaperInfo(guest_id, &wallpaper_info)); EXPECT_EQ(wallpaper_info, default_wallpaper_info); ASSERT_EQ(1u, GetDecodeFilePaths().size()); EXPECT_EQ(default_wallpaper_dir_.GetPath().Append(kGuestLargeWallpaperName), @@ -1642,7 +1590,8 @@ SimulateUserLogin(account_id_1); SimulateSettingCustomWallpaper(account_id_1); WallpaperInfo wallpaper_info; - EXPECT_TRUE(controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); + EXPECT_TRUE( + pref_manager_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); WallpaperInfo default_wallpaper_info( std::string(), WALLPAPER_LAYOUT_CENTER_CROPPED, WallpaperType::kDefault, base::Time::Now().LocalMidnight()); @@ -1664,7 +1613,7 @@ RunAllTasksUntilIdle(); EXPECT_EQ(1, GetWallpaperCount()); EXPECT_EQ(controller_->GetWallpaperType(), WallpaperType::kDefault); - EXPECT_TRUE(controller_->GetUserWallpaperInfo(guest_id, &wallpaper_info)); + EXPECT_TRUE(pref_manager_->GetUserWallpaperInfo(guest_id, &wallpaper_info)); EXPECT_EQ(wallpaper_info, default_wallpaper_info); ASSERT_EQ(1u, GetDecodeFilePaths().size()); EXPECT_EQ(default_wallpaper_dir_.GetPath().Append(kGuestLargeWallpaperName), @@ -1691,7 +1640,8 @@ // First, simulate setting a user custom wallpaper. SimulateSettingCustomWallpaper(account_id_1); WallpaperInfo wallpaper_info; - EXPECT_TRUE(controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); + EXPECT_TRUE( + pref_manager_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); EXPECT_NE(wallpaper_info.type, WallpaperType::kDefault); TestWallpaperControllerObserver observer(controller_); @@ -1726,7 +1676,7 @@ EXPECT_EQ(0, GetWallpaperCount()); WallpaperInfo wallpaper_info; EXPECT_FALSE( - controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); // Verify that |SetOnlineWallpaperFromData| doesn't set wallpaper in kiosk // mode, and |account_id_1|'s wallpaper info is not updated. @@ -1747,7 +1697,7 @@ run_loop->Run(); EXPECT_EQ(0, GetWallpaperCount()); EXPECT_FALSE( - controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); // Verify that |SetDefaultWallpaper| doesn't set wallpaper in kiosk mode, and // |account_id_1|'s wallpaper info is not updated. @@ -1757,7 +1707,7 @@ RunAllTasksUntilIdle(); EXPECT_EQ(0, GetWallpaperCount()); EXPECT_FALSE( - controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); } // Disable the wallpaper setting for public session since it is ephemeral. @@ -1794,7 +1744,7 @@ RunAllTasksUntilIdle(); EXPECT_EQ(0, GetWallpaperCount()); EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); EXPECT_EQ(wallpaper_info, policy_wallpaper_info); } @@ -1813,7 +1763,7 @@ run_loop->Run(); EXPECT_EQ(0, GetWallpaperCount()); EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); EXPECT_EQ(wallpaper_info, policy_wallpaper_info); } @@ -1837,7 +1787,7 @@ run_loop->Run(); EXPECT_EQ(0, GetWallpaperCount()); EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); EXPECT_EQ(wallpaper_info, policy_wallpaper_info); } @@ -1860,7 +1810,7 @@ run_loop->Run(); EXPECT_EQ(0, GetWallpaperCount()); EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); EXPECT_EQ(wallpaper_info, policy_wallpaper_info); } @@ -1873,7 +1823,7 @@ RunAllTasksUntilIdle(); EXPECT_EQ(0, GetWallpaperCount()); EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); EXPECT_EQ(wallpaper_info, policy_wallpaper_info); } } @@ -2108,7 +2058,8 @@ EXPECT_EQ(1, GetWallpaperCount()); EXPECT_EQ(controller_->GetWallpaperLayout(), layout); WallpaperInfo wallpaper_info; - EXPECT_TRUE(controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); + EXPECT_TRUE( + pref_manager_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); WallpaperInfo expected_custom_wallpaper_info( base::FilePath(wallpaper_files_id_1).Append(file_name_1).value(), layout, WallpaperType::kCustomized, base::Time::Now().LocalMidnight()); @@ -2121,7 +2072,8 @@ RunAllTasksUntilIdle(); EXPECT_EQ(1, GetWallpaperCount()); EXPECT_EQ(controller_->GetWallpaperLayout(), new_layout); - EXPECT_TRUE(controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); + EXPECT_TRUE( + pref_manager_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); expected_custom_wallpaper_info.layout = new_layout; EXPECT_EQ(wallpaper_info, expected_custom_wallpaper_info); @@ -2144,7 +2096,7 @@ WallpaperType::kOnceGooglePhotos); EXPECT_EQ(controller_->GetWallpaperLayout(), layout); EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); EXPECT_EQ(wallpaper_info, WallpaperInfo(GooglePhotosWallpaperParams( account_id_1, "id", /*daily_refresh_enabled=*/false, layout, @@ -2158,7 +2110,7 @@ EXPECT_EQ(1, GetWallpaperCount()); EXPECT_EQ(controller_->GetWallpaperLayout(), new_layout); EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); EXPECT_EQ(wallpaper_info, WallpaperInfo(GooglePhotosWallpaperParams( account_id_1, "id", /*daily_refresh_enabled=*/false, @@ -2182,7 +2134,8 @@ EXPECT_EQ(1, GetWallpaperCount()); EXPECT_EQ(controller_->GetWallpaperType(), WallpaperType::kOnline); EXPECT_EQ(controller_->GetWallpaperLayout(), layout); - EXPECT_TRUE(controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); + EXPECT_TRUE( + pref_manager_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); WallpaperInfo expected_online_wallpaper_info( kDummyUrl, layout, WallpaperType::kOnline, base::Time::Now().LocalMidnight()); @@ -2196,7 +2149,8 @@ EXPECT_EQ(0, GetWallpaperCount()); EXPECT_EQ(controller_->GetWallpaperLayout(), layout); // The saved wallpaper info is not updated. - EXPECT_TRUE(controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); + EXPECT_TRUE( + pref_manager_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); EXPECT_EQ(wallpaper_info, expected_online_wallpaper_info); } @@ -2518,7 +2472,7 @@ std::string(), WALLPAPER_LAYOUT_CENTER_CROPPED, WallpaperType::kDefault, base::Time::Now().LocalMidnight()); EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); EXPECT_EQ(user_wallpaper_info, default_wallpaper_info); // Simulate opening the wallpaper picker window. @@ -2542,7 +2496,7 @@ EXPECT_EQ(kWallpaperColor, GetWallpaperColor()); // Verify that the user wallpaper info remains unchanged during the preview. EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); EXPECT_EQ(user_wallpaper_info, default_wallpaper_info); // Now enter overview mode. Verify the wallpaper changes back to the default, @@ -2572,7 +2526,7 @@ std::string(), WALLPAPER_LAYOUT_CENTER_CROPPED, WallpaperType::kDefault, base::Time::Now().LocalMidnight()); EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); EXPECT_EQ(user_wallpaper_info, default_wallpaper_info); // Simulate opening the wallpaper picker window. @@ -2596,7 +2550,7 @@ EXPECT_EQ(kWallpaperColor, GetWallpaperColor()); // Verify that the user wallpaper info remains unchanged during the preview. EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); EXPECT_EQ(user_wallpaper_info, default_wallpaper_info); // Now start window cycle. Verify the wallpaper changes back to the default, @@ -2627,7 +2581,7 @@ std::string(), WALLPAPER_LAYOUT_CENTER_CROPPED, WallpaperType::kDefault, base::Time::Now().LocalMidnight()); EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); EXPECT_EQ(user_wallpaper_info, default_wallpaper_info); // Simulate opening the wallpaper picker window. @@ -2651,7 +2605,7 @@ EXPECT_EQ(kWallpaperColor, GetWallpaperColor()); // Verify that the user wallpaper info remains unchanged during the preview. EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); EXPECT_EQ(user_wallpaper_info, default_wallpaper_info); // Now switch to another user. Verify the wallpaper changes back to the @@ -2665,7 +2619,7 @@ EXPECT_NE(kWallpaperColor, GetWallpaperColor()); EXPECT_EQ(controller_->GetWallpaperType(), WallpaperType::kDefault); EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_2, &user_wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_2, &user_wallpaper_info)); EXPECT_EQ(user_wallpaper_info, default_wallpaper_info); } @@ -2682,7 +2636,7 @@ std::string(), WALLPAPER_LAYOUT_CENTER_CROPPED, WallpaperType::kDefault, base::Time::Now().LocalMidnight()); EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); EXPECT_EQ(user_wallpaper_info, default_wallpaper_info); // Simulate opening the wallpaper picker window. @@ -2703,7 +2657,7 @@ EXPECT_EQ(kWallpaperColor, GetWallpaperColor()); // Verify that the user wallpaper info remains unchanged during the preview. EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); EXPECT_EQ(user_wallpaper_info, default_wallpaper_info); histogram_tester().ExpectTotalCount("Ash.Wallpaper.Preview.Show", 1); @@ -2721,7 +2675,7 @@ base::FilePath(wallpaper_files_id_1).Append(file_name_1).value(), layout, WallpaperType::kCustomized, base::Time::Now().LocalMidnight()); EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); EXPECT_EQ(user_wallpaper_info, custom_wallpaper_info); // Set an empty online wallpaper for the user, verify it fails. @@ -2761,7 +2715,7 @@ EXPECT_EQ(online_wallpaper_color, GetWallpaperColor()); // Verify that the user wallpaper info remains unchanged during the preview. EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); EXPECT_EQ(user_wallpaper_info, custom_wallpaper_info); // Now confirm the preview wallpaper, verify that there's no wallpaper change @@ -2782,7 +2736,7 @@ /*variants=*/ std::vector<OnlineWallpaperVariant>())); EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); EXPECT_EQ(user_wallpaper_info, online_wallpaper_info); } @@ -2799,7 +2753,7 @@ std::string(), WALLPAPER_LAYOUT_CENTER_CROPPED, WallpaperType::kDefault, base::Time::Now().LocalMidnight()); EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); EXPECT_EQ(user_wallpaper_info, default_wallpaper_info); // Simulate opening the wallpaper picker window. @@ -2820,7 +2774,7 @@ EXPECT_EQ(kWallpaperColor, GetWallpaperColor()); // Verify that the user wallpaper info remains unchanged during the preview. EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); EXPECT_EQ(user_wallpaper_info, default_wallpaper_info); // Now cancel the preview. Verify the wallpaper changes back to the default @@ -2851,7 +2805,7 @@ EXPECT_EQ(online_wallpaper_color, GetWallpaperColor()); // Verify that the user wallpaper info remains unchanged during the preview. EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); EXPECT_EQ(user_wallpaper_info, default_wallpaper_info); // Now cancel the preview. Verify the wallpaper changes back to the default @@ -2878,7 +2832,7 @@ std::string(), WALLPAPER_LAYOUT_CENTER_CROPPED, WallpaperType::kDefault, base::Time::Now().LocalMidnight()); EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); EXPECT_EQ(user_wallpaper_info, default_wallpaper_info); // Simulate opening the wallpaper picker window. @@ -2899,7 +2853,7 @@ EXPECT_EQ(kWallpaperColor, GetWallpaperColor()); // Verify that the user wallpaper info remains unchanged during the preview. EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); EXPECT_EQ(user_wallpaper_info, default_wallpaper_info); // Now set another custom wallpaper for the user and disable preview (this @@ -2921,7 +2875,7 @@ base::FilePath(wallpaper_files_id_1).Append(file_name_2).value(), layout, WallpaperType::kCustomized, base::Time::Now().LocalMidnight()); EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); EXPECT_EQ(user_wallpaper_info, synced_custom_wallpaper_info); // Now cancel the preview. Verify the synced custom wallpaper is shown instead @@ -2933,7 +2887,7 @@ EXPECT_EQ(1, GetWallpaperCount()); EXPECT_EQ(synced_custom_wallpaper_color, GetWallpaperColor()); EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); EXPECT_EQ(user_wallpaper_info, synced_custom_wallpaper_info); // Repeat the above steps for online wallpapers: set a online wallpaper for @@ -2954,7 +2908,7 @@ EXPECT_EQ(kWallpaperColor, GetWallpaperColor()); // Verify that the user wallpaper info remains unchanged during the preview. EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); EXPECT_EQ(user_wallpaper_info, synced_custom_wallpaper_info); // Now set another online wallpaper for the user and disable preview. Verify @@ -2984,7 +2938,7 @@ /*variants=*/ std::vector<OnlineWallpaperVariant>())); EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); EXPECT_EQ(user_wallpaper_info, synced_online_wallpaper_info); // Now cancel the preview. Verify the synced online wallpaper is shown instead @@ -2996,7 +2950,7 @@ EXPECT_EQ(1, GetWallpaperCount()); EXPECT_EQ(synced_online_wallpaper_color, GetWallpaperColor()); EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); EXPECT_EQ(user_wallpaper_info, synced_online_wallpaper_info); } @@ -3054,7 +3008,8 @@ base::FilePath(wallpaper_files_id_1).Append(file_name_1).value(), layout, WallpaperType::kCustomized, base::Time::Now().LocalMidnight()); WallpaperInfo wallpaper_info; - EXPECT_TRUE(controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); + EXPECT_TRUE( + pref_manager_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); EXPECT_EQ(expected_wallpaper_info, wallpaper_info); // Show a one-shot wallpaper. Verify it is shown successfully. @@ -3082,7 +3037,8 @@ // Verify the user wallpaper info is unaffected, and the one-shot wallpaper // can be replaced by the user wallpaper. - EXPECT_TRUE(controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); + EXPECT_TRUE( + pref_manager_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); EXPECT_EQ(expected_wallpaper_info, wallpaper_info); ClearWallpaperCount(); controller_->ShowUserWallpaper(account_id_1); @@ -3277,40 +3233,6 @@ ->is_animating()); } -TEST_F(WallpaperControllerTest, GetWallpaperInfo) { - WallpaperInfo expected_info = InfoWithType(WallpaperType::kDaily); - controller_->SetUserWallpaperInfo(account_id_1, expected_info); - - WallpaperInfo actual_info; - EXPECT_TRUE(controller_->GetUserWallpaperInfo(account_id_1, &actual_info)); - EXPECT_EQ(expected_info, actual_info); -} - -TEST_F(WallpaperControllerTest, GetWallpaperInfoNothingToGet) { - WallpaperInfo info; - EXPECT_FALSE(controller_->GetUserWallpaperInfo(account_id_1, &info)); -} - -TEST_F(WallpaperControllerTest, SetWallpaperInfoLocal) { - WallpaperInfo info( - GetDummyFileName(account_id_1), WALLPAPER_LAYOUT_CENTER_CROPPED, - WallpaperType::kThirdParty, base::Time::Now().LocalMidnight()); - EXPECT_TRUE(controller_->SetUserWallpaperInfo(account_id_1, info)); - AssertWallpaperInfoInPrefs(GetLocalPrefService(), prefs::kUserWallpaperInfo, - account_id_1, info); -} - -TEST_F(WallpaperControllerTest, SetWallpaperInfoLocalFromGooglePhotos) { - WallpaperInfo info( - GooglePhotosWallpaperParams{account_id_1, kFakeGooglePhotosPhotoId, - /*daily_refresh_enabled=*/false, - WallpaperLayout::WALLPAPER_LAYOUT_STRETCH, - /*preview_mode=*/false, "dedup_key"}); - EXPECT_TRUE(controller_->SetUserWallpaperInfo(account_id_1, info)); - AssertWallpaperInfoInPrefs(GetLocalPrefService(), prefs::kUserWallpaperInfo, - account_id_1, info); -} - TEST_F(WallpaperControllerTest, SetCustomWallpaper) { gfx::ImageSkia image = CreateImage(640, 480, kWallpaperColor); WallpaperLayout layout = WALLPAPER_LAYOUT_CENTER; @@ -3327,7 +3249,8 @@ EXPECT_EQ(kWallpaperColor, GetWallpaperColor()); EXPECT_EQ(controller_->GetWallpaperType(), WallpaperType::kCustomized); WallpaperInfo wallpaper_info; - EXPECT_TRUE(controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); + EXPECT_TRUE( + pref_manager_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); WallpaperInfo expected_wallpaper_info( base::FilePath(wallpaper_files_id_1).Append(file_name_1).value(), layout, WallpaperType::kCustomized, base::Time::Now().LocalMidnight()); @@ -3346,7 +3269,8 @@ RunAllTasksUntilIdle(); EXPECT_EQ(0, GetWallpaperCount()); EXPECT_EQ(kWallpaperColor, GetWallpaperColor()); - EXPECT_TRUE(controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); + EXPECT_TRUE( + pref_manager_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); EXPECT_EQ(wallpaper_info, expected_wallpaper_info); // Verify the updated wallpaper is shown after |kUser1| becomes active again. @@ -3358,53 +3282,6 @@ EXPECT_EQ(custom_wallpaper_color, GetWallpaperColor()); } -TEST_F(WallpaperControllerTest, SetWallpaperInfoSynced) { - WallpaperInfo info = InfoWithType(WallpaperType::kOnline); - EXPECT_TRUE(controller_->SetUserWallpaperInfo(account_id_1, info)); - AssertWallpaperInfoInPrefs(GetProfilePrefService(account_id_1), - prefs::kSyncableWallpaperInfo, account_id_1, info); -} - -TEST_F(WallpaperControllerTest, SetWallpaperInfoSyncedFromGooglePhotos) { - WallpaperInfo info = InfoWithType(WallpaperType::kOnceGooglePhotos); - EXPECT_TRUE(controller_->SetUserWallpaperInfo(account_id_1, info)); - AssertWallpaperInfoInPrefs(GetProfilePrefService(account_id_1), - prefs::kSyncableWallpaperInfo, account_id_1, info); -} - -TEST_F(WallpaperControllerTest, SetWallpaperInfoSyncDisabled) { - client_.set_wallpaper_sync_enabled(false); - - WallpaperInfo expected_info = InfoWithType(WallpaperType::kCustomized); - PutWallpaperInfoInPrefs(account_id_1, expected_info, - GetProfilePrefService(account_id_1), - prefs::kSyncableWallpaperInfo); - - WallpaperInfo info = InfoWithType(WallpaperType::kOnline); - EXPECT_TRUE(controller_->SetUserWallpaperInfo(account_id_1, info)); - - AssertWallpaperInfoInPrefs(GetProfilePrefService(account_id_1), - prefs::kSyncableWallpaperInfo, account_id_1, - expected_info); -} - -TEST_F(WallpaperControllerTest, SetWallpaperInfoCustom) { - WallpaperInfo synced_info = InfoWithType(WallpaperType::kOnline); - PutWallpaperInfoInPrefs(account_id_1, synced_info, - GetProfilePrefService(account_id_1), - prefs::kSyncableWallpaperInfo); - - WallpaperInfo info = InfoWithType(WallpaperType::kCustomized); - EXPECT_TRUE(controller_->SetUserWallpaperInfo(account_id_1, info)); - - // Custom wallpaper infos should not be propagated to synced preferences until - // the image is uploaded to drivefs. That is not done in - // |SetUserWallpaperInfo|. - AssertWallpaperInfoInPrefs(GetProfilePrefService(account_id_1), - prefs::kSyncableWallpaperInfo, account_id_1, - synced_info); -} - TEST_F(WallpaperControllerTest, OldOnlineInfoSynced_Discarded) { // Create a dictionary that looks like the preference from crrev.com/a040384. // DO NOT CHANGE as there are preferences like this in production. @@ -3434,27 +3311,25 @@ // Unmigrated synced wallpaper info are discarded. WallpaperInfo actual; - EXPECT_FALSE(controller_->GetUserWallpaperInfo(account_id_1, &actual)); + EXPECT_FALSE(pref_manager_->GetUserWallpaperInfo(account_id_1, &actual)); } -TEST_F(WallpaperControllerTest, MigrateWallpaperInfo) { +TEST_F(WallpaperControllerTest, MigrateWallpaperInfo_Online) { WallpaperInfo expected_info = InfoWithType(WallpaperType::kOnline); - PutWallpaperInfoInPrefs(account_id_1, expected_info, GetLocalPrefService(), - prefs::kUserWallpaperInfo); + pref_manager_->SetLocalWallpaperInfo(account_id_1, expected_info); SimulateUserLogin(account_id_1); - AssertWallpaperInfoInPrefs(GetProfilePrefService(account_id_1), - prefs::kSyncableWallpaperInfo, account_id_1, - expected_info); + WallpaperInfo info; + ASSERT_TRUE(pref_manager_->GetSyncedWallpaperInfo(account_id_1, &info)); + EXPECT_EQ(expected_info, info); } TEST_F(WallpaperControllerTest, MigrateWallpaperInfoCustomized) { WallpaperInfo expected_info = InfoWithType(WallpaperType::kCustomized); - PutWallpaperInfoInPrefs(account_id_1, expected_info, GetLocalPrefService(), - prefs::kUserWallpaperInfo); + pref_manager_->SetLocalWallpaperInfo(account_id_1, expected_info); SimulateUserLogin(account_id_1); - AssertWallpaperInfoInPrefs(GetProfilePrefService(account_id_1), - prefs::kSyncableWallpaperInfo, account_id_1, - expected_info); + WallpaperInfo info; + ASSERT_TRUE(pref_manager_->GetSyncedWallpaperInfo(account_id_1, &info)); + EXPECT_EQ(expected_info, info); } TEST_F(WallpaperControllerTest, MigrateWallpaperInfoDaily) { @@ -3464,12 +3339,11 @@ WALLPAPER_LAYOUT_CENTER, /*preview_mode=*/false, /*from_user=*/false, /*daily_refresh_enabled=*/false, kUnitId, std::vector<OnlineWallpaperVariant>())); - PutWallpaperInfoInPrefs(account_id_1, expected_info, GetLocalPrefService(), - prefs::kUserWallpaperInfo); + pref_manager_->SetLocalWallpaperInfo(account_id_1, expected_info); SimulateUserLogin(account_id_1); - AssertWallpaperInfoInPrefs(GetProfilePrefService(account_id_1), - prefs::kSyncableWallpaperInfo, account_id_1, - expected_info); + WallpaperInfo info; + ASSERT_TRUE(pref_manager_->GetSyncedWallpaperInfo(account_id_1, &info)); + EXPECT_EQ(expected_info, info); EXPECT_EQ(client_.migrate_collection_id_from_chrome_app_count(), 1u); } @@ -3489,15 +3363,13 @@ WALLPAPER_LAYOUT_CENTER, /*preview_mode=*/false, /*from_user=*/false, /*daily_refresh_enabled=*/false, kUnitId, std::vector<OnlineWallpaperVariant>())); - PutWallpaperInfoInPrefs(account_id_1, local_info, GetLocalPrefService(), - prefs::kUserWallpaperInfo); - PutWallpaperInfoInPrefs(account_id_1, synced_info, - GetProfilePrefService(account_id_1), - prefs::kSyncableWallpaperInfo); + pref_manager_->SetLocalWallpaperInfo(account_id_1, local_info); + pref_manager_->SetSyncedWallpaperInfo(account_id_1, synced_info); SimulateUserLogin(account_id_1); - AssertWallpaperInfoInPrefs(GetProfilePrefService(account_id_1), - prefs::kSyncableWallpaperInfo, account_id_1, - synced_info); + WallpaperInfo info; + ASSERT_TRUE(pref_manager_->GetSyncedWallpaperInfo(account_id_1, &info)); + // Synced info should be the same if local is the same age. + EXPECT_EQ(synced_info, info); } TEST_F(WallpaperControllerTest, @@ -3508,14 +3380,11 @@ WallpaperType::kOnline, base::Time::Now()}; synced_info.asset_id = kAssetId; synced_info.collection_id = TestWallpaperControllerClient::kDummyCollectionId; - PutWallpaperInfoInPrefs(account_id_1, synced_info, - GetProfilePrefService(account_id_1), - prefs::kSyncableWallpaperInfo); + pref_manager_->SetSyncedWallpaperInfo(account_id_1, synced_info); WallpaperInfo local_info = InfoWithType(WallpaperType::kThirdParty); local_info.date = DayBeforeYesterdayish(); - PutWallpaperInfoInPrefs(account_id_1, local_info, GetLocalPrefService(), - prefs::kUserWallpaperInfo); + pref_manager_->SetLocalWallpaperInfo(account_id_1, local_info); client_.ResetCounts(); @@ -3523,7 +3392,7 @@ GetProfilePrefService(account_id_1)); RunAllTasksUntilIdle(); WallpaperInfo actual_info; - EXPECT_TRUE(controller_->GetUserWallpaperInfo(account_id_1, &actual_info)); + EXPECT_TRUE(pref_manager_->GetUserWallpaperInfo(account_id_1, &actual_info)); EXPECT_EQ(WallpaperType::kOnline, actual_info.type); } @@ -3533,14 +3402,11 @@ WallpaperType::kOnline, base::Time::Now()}; synced_info.asset_id = kAssetId; synced_info.collection_id = TestWallpaperControllerClient::kDummyCollectionId; - PutWallpaperInfoInPrefs(account_id_1, synced_info, - GetProfilePrefService(account_id_1), - prefs::kSyncableWallpaperInfo); + pref_manager_->SetSyncedWallpaperInfo(account_id_1, synced_info); WallpaperInfo local_info = InfoWithType(WallpaperType::kThirdParty); local_info.date = DayBeforeYesterdayish(); - PutWallpaperInfoInPrefs(account_id_1, local_info, GetLocalPrefService(), - prefs::kUserWallpaperInfo); + pref_manager_->SetLocalWallpaperInfo(account_id_1, local_info); client_.ResetCounts(); @@ -3549,25 +3415,23 @@ controller_->OnActiveUserPrefServiceChanged( GetProfilePrefService(account_id_1)); WallpaperInfo actual_info; - EXPECT_TRUE(controller_->GetUserWallpaperInfo(account_id_1, &actual_info)); + EXPECT_TRUE(pref_manager_->GetUserWallpaperInfo(account_id_1, &actual_info)); EXPECT_EQ(WallpaperType::kThirdParty, actual_info.type); } TEST_F(WallpaperControllerTest, HandleWallpaperInfoSyncedLocalIsPolicy) { CacheOnlineWallpaper(kDummyUrl); - PutWallpaperInfoInPrefs(account_id_1, InfoWithType(WallpaperType::kPolicy), - GetLocalPrefService(), prefs::kUserWallpaperInfo); + pref_manager_->SetLocalWallpaperInfo(account_id_1, + InfoWithType(WallpaperType::kPolicy)); SimulateUserLogin(account_id_1); WallpaperInfo synced_info = {kDummyUrl, WALLPAPER_LAYOUT_CENTER_CROPPED, WallpaperType::kOnline, base::Time::Now()}; - PutWallpaperInfoInPrefs(account_id_1, synced_info, - GetProfilePrefService(account_id_1), - prefs::kSyncableWallpaperInfo); + pref_manager_->SetSyncedWallpaperInfo(account_id_1, synced_info); RunAllTasksUntilIdle(); WallpaperInfo actual_info; - EXPECT_TRUE(controller_->GetUserWallpaperInfo(account_id_1, &actual_info)); + EXPECT_TRUE(pref_manager_->GetUserWallpaperInfo(account_id_1, &actual_info)); EXPECT_NE(WallpaperType::kOnline, actual_info.type); } @@ -3577,44 +3441,36 @@ WallpaperInfo local_info = InfoWithType(WallpaperType::kThirdParty); local_info.date = DayBeforeYesterdayish(); - PutWallpaperInfoInPrefs(account_id_1, local_info, GetLocalPrefService(), - prefs::kUserWallpaperInfo); + pref_manager_->SetLocalWallpaperInfo(account_id_1, local_info); SimulateUserLogin(account_id_1); WallpaperInfo synced_info = {kDummyUrl, WALLPAPER_LAYOUT_CENTER_CROPPED, WallpaperType::kOnline, base::Time::Now()}; synced_info.asset_id = kAssetId; synced_info.collection_id = TestWallpaperControllerClient::kDummyCollectionId; - PutWallpaperInfoInPrefs(account_id_1, synced_info, - GetProfilePrefService(account_id_1), - prefs::kSyncableWallpaperInfo); + pref_manager_->SetSyncedWallpaperInfo(account_id_1, synced_info); RunAllTasksUntilIdle(); WallpaperInfo actual_info; - EXPECT_TRUE(controller_->GetUserWallpaperInfo(account_id_1, &actual_info)); + EXPECT_TRUE(pref_manager_->GetUserWallpaperInfo(account_id_1, &actual_info)); EXPECT_EQ(WallpaperType::kOnline, actual_info.type); } TEST_F(WallpaperControllerTest, HandleWallpaperInfoSyncedLocalIsThirdPartyAndNewer) { CacheOnlineWallpaper(kDummyUrl); - PutWallpaperInfoInPrefs(account_id_1, - InfoWithType(WallpaperType::kThirdParty), - GetLocalPrefService(), prefs::kUserWallpaperInfo); + pref_manager_->SetLocalWallpaperInfo( + account_id_1, InfoWithType(WallpaperType::kThirdParty)); WallpaperInfo synced_info = {kDummyUrl, WALLPAPER_LAYOUT_CENTER_CROPPED, WallpaperType::kOnline, DayBeforeYesterdayish()}; - PutWallpaperInfoInPrefs(account_id_1, synced_info, - GetProfilePrefService(account_id_1), - prefs::kSyncableWallpaperInfo); + pref_manager_->SetSyncedWallpaperInfo(account_id_1, synced_info); SimulateUserLogin(account_id_1); - PutWallpaperInfoInPrefs(account_id_1, synced_info, - GetProfilePrefService(account_id_1), - prefs::kSyncableWallpaperInfo); + pref_manager_->SetSyncedWallpaperInfo(account_id_1, synced_info); RunAllTasksUntilIdle(); WallpaperInfo actual_info; - EXPECT_TRUE(controller_->GetUserWallpaperInfo(account_id_1, &actual_info)); + EXPECT_TRUE(pref_manager_->GetUserWallpaperInfo(account_id_1, &actual_info)); EXPECT_EQ(WallpaperType::kThirdParty, actual_info.type); } @@ -3631,9 +3487,8 @@ WALLPAPER_LAYOUT_CENTER, /*preview_mode=*/false, /*from_user=*/false, /*daily_refresh_enabled=*/false, kUnitId, std::vector<OnlineWallpaperVariant>())); - PutWallpaperInfoInPrefs(account_id_1, info, - GetProfilePrefService(account_id_1), - prefs::kSyncableWallpaperInfo); + pref_manager_->SetSyncedWallpaperInfo(account_id_1, info); + RunAllTasksUntilIdle(); EXPECT_EQ(1, GetWallpaperCount()); EXPECT_EQ(controller_->GetWallpaperType(), WallpaperType::kOnline); @@ -3649,9 +3504,8 @@ // it succeeds this time because |SetOnlineWallpaperFromData| has saved the // file. ClearWallpaperCount(); - PutWallpaperInfoInPrefs(account_id_1, InfoWithType(WallpaperType::kOnline), - GetProfilePrefService(account_id_1), - prefs::kSyncableWallpaperInfo); + pref_manager_->SetSyncedWallpaperInfo(account_id_1, + InfoWithType(WallpaperType::kOnline)); RunAllTasksUntilIdle(); EXPECT_EQ(0, GetWallpaperCount()); EXPECT_NE(controller_->GetWallpaperType(), WallpaperType::kOnline); @@ -3665,7 +3519,7 @@ WallpaperType::kDaily, DayBeforeYesterdayish()}; info.asset_id = kAssetId; info.collection_id = expected; - controller_->SetUserWallpaperInfo(account_id_1, info); + pref_manager_->SetUserWallpaperInfo(account_id_1, info); controller_->UpdateDailyRefreshWallpaperForTesting(); EXPECT_EQ(expected, client_.get_fetch_daily_refresh_wallpaper_param()); @@ -3684,7 +3538,7 @@ /*daily_refresh_enabled=*/true, /*unit_id=*/absl::nullopt, /*variants=*/std::vector<OnlineWallpaperVariant>())); info.date = DayBeforeYesterdayish(); - controller_->SetUserWallpaperInfo(account_id_1, info); + pref_manager_->SetUserWallpaperInfo(account_id_1, info); ClearLogin(); SimulateUserLogin(account_id_1); @@ -3702,7 +3556,7 @@ WallpaperInfo info = {std::string(), WALLPAPER_LAYOUT_CENTER, WallpaperType::kOnline, DayBeforeYesterdayish()}; info.collection_id = "fun_collection"; - controller_->SetUserWallpaperInfo(account_id_1, info); + pref_manager_->SetUserWallpaperInfo(account_id_1, info); controller_->UpdateDailyRefreshWallpaperForTesting(); EXPECT_EQ(std::string(), client_.get_fetch_daily_refresh_wallpaper_param()); @@ -3710,7 +3564,7 @@ TEST_F(WallpaperControllerTest, UpdateDailyRefreshWallpaper_NoCollectionId) { SimulateUserLogin(account_id_1); - controller_->SetUserWallpaperInfo( + pref_manager_->SetUserWallpaperInfo( account_id_1, WallpaperInfo(std::string(), WALLPAPER_LAYOUT_CENTER, WallpaperType::kDaily, DayBeforeYesterdayish())); @@ -3728,7 +3582,7 @@ WallpaperType::kDaily, base::Time::Now().LocalMidnight()}; info.collection_id = "fun_collection"; - controller_->SetUserWallpaperInfo(account_id_1, info); + pref_manager_->SetUserWallpaperInfo(account_id_1, info); controller_->OnActiveUserPrefServiceChanged( GetProfilePrefService(account_id_1)); @@ -3755,7 +3609,7 @@ WallpaperInfo info = {std::string(), WALLPAPER_LAYOUT_CENTER, WallpaperType::kDaily, DayBeforeYesterdayish()}; info.collection_id = "fun_collection"; - controller_->SetUserWallpaperInfo(account_id_1, info); + pref_manager_->SetUserWallpaperInfo(account_id_1, info); controller_->UpdateDailyRefreshWallpaperForTesting(); Time run_time = @@ -3777,7 +3631,7 @@ WallpaperInfo info = {std::string(), WALLPAPER_LAYOUT_CENTER, WallpaperType::kDaily, DayBeforeYesterdayish()}; info.collection_id = "fun_collection"; - controller_->SetUserWallpaperInfo(account_id_1, info); + pref_manager_->SetUserWallpaperInfo(account_id_1, info); test_image_downloader_->set_should_fail(true); @@ -3812,8 +3666,7 @@ TEST_F(WallpaperControllerTest, OnGoogleDriveMounted) { WallpaperInfo local_info = InfoWithType(WallpaperType::kCustomized); - PutWallpaperInfoInPrefs(account_id_1, local_info, GetLocalPrefService(), - prefs::kUserWallpaperInfo); + pref_manager_->SetLocalWallpaperInfo(account_id_1, local_info); SimulateUserLogin(account_id_1); controller_->SyncLocalAndRemotePrefs(account_id_1); @@ -3822,8 +3675,7 @@ TEST_F(WallpaperControllerTest, OnGoogleDriveMounted_WallpaperIsntCustom) { WallpaperInfo local_info = InfoWithType(WallpaperType::kOnline); - PutWallpaperInfoInPrefs(account_id_1, local_info, GetLocalPrefService(), - prefs::kUserWallpaperInfo); + pref_manager_->SetLocalWallpaperInfo(account_id_1, local_info); controller_->SyncLocalAndRemotePrefs(account_id_1); EXPECT_TRUE(client_.get_save_wallpaper_to_drive_fs_account_id().empty()); @@ -3831,8 +3683,7 @@ TEST_F(WallpaperControllerTest, OnGoogleDriveMounted_AlreadySynced) { WallpaperInfo local_info = InfoWithType(WallpaperType::kCustomized); - PutWallpaperInfoInPrefs(account_id_1, local_info, GetLocalPrefService(), - prefs::kUserWallpaperInfo); + pref_manager_->SetLocalWallpaperInfo(account_id_1, local_info); SimulateUserLogin(account_id_1); @@ -3854,16 +3705,12 @@ WallpaperInfo local_info = WallpaperInfo("a_url", WALLPAPER_LAYOUT_CENTER_CROPPED, WallpaperType::kCustomized, DayBeforeYesterdayish()); - PutWallpaperInfoInPrefs(account_id_1, local_info, GetLocalPrefService(), - prefs::kUserWallpaperInfo); + pref_manager_->SetLocalWallpaperInfo(account_id_1, local_info); WallpaperInfo synced_info = WallpaperInfo( "b_url", WALLPAPER_LAYOUT_CENTER_CROPPED, WallpaperType::kCustomized, base::Time::Now().LocalMidnight()); - PutWallpaperInfoInPrefs(account_id_1, synced_info, - GetProfilePrefService(account_id_1), - prefs::kSyncableWallpaperInfo); - + pref_manager_->SetSyncedWallpaperInfo(account_id_1, synced_info); SimulateUserLogin(account_id_1); controller_->SyncLocalAndRemotePrefs(account_id_1); @@ -3877,15 +3724,12 @@ WallpaperInfo local_info = WallpaperInfo( "a_url", WALLPAPER_LAYOUT_CENTER_CROPPED, WallpaperType::kCustomized, base::Time::Now().LocalMidnight()); - PutWallpaperInfoInPrefs(account_id_1, local_info, GetLocalPrefService(), - prefs::kUserWallpaperInfo); + pref_manager_->SetLocalWallpaperInfo(account_id_1, local_info); WallpaperInfo synced_info = WallpaperInfo("b_url", WALLPAPER_LAYOUT_CENTER_CROPPED, WallpaperType::kCustomized, DayBeforeYesterdayish()); - PutWallpaperInfoInPrefs(account_id_1, synced_info, - GetProfilePrefService(account_id_1), - prefs::kSyncableWallpaperInfo); + pref_manager_->SetSyncedWallpaperInfo(account_id_1, synced_info); SimulateUserLogin(account_id_1); @@ -3894,7 +3738,7 @@ } TEST_F(WallpaperControllerTest, SetDailyRefreshCollectionId) { - controller_->SetUserWallpaperInfo( + pref_manager_->SetUserWallpaperInfo( account_id_1, WallpaperInfo(std::string(), WALLPAPER_LAYOUT_CENTER, WallpaperType::kOnline, DayBeforeYesterdayish())); @@ -3906,7 +3750,7 @@ expected.collection_id = collection_id; WallpaperInfo actual; - controller_->GetUserWallpaperInfo(account_id_1, &actual); + pref_manager_->GetUserWallpaperInfo(account_id_1, &actual); // Type should be `WallpaperType::kDaily` now, and collection_id should be // updated. EXPECT_EQ(expected, actual); @@ -3919,7 +3763,7 @@ WallpaperInfo info = {std::string(), WALLPAPER_LAYOUT_CENTER, WallpaperType::kDaily, DayBeforeYesterdayish()}; info.collection_id = collection_id; - controller_->SetUserWallpaperInfo(account_id_1, info); + pref_manager_->SetUserWallpaperInfo(account_id_1, info); controller_->SetDailyRefreshCollectionId(account_id_1, std::string()); WallpaperInfo expected = {std::string(), WALLPAPER_LAYOUT_CENTER, @@ -3927,7 +3771,7 @@ expected.collection_id = collection_id; WallpaperInfo actual; - controller_->GetUserWallpaperInfo(account_id_1, &actual); + pref_manager_->GetUserWallpaperInfo(account_id_1, &actual); // Type should be `WallpaperType::kOnline` now, and collection_id should be // `WallpaperType::EMPTY`. EXPECT_EQ(expected, actual); @@ -3939,7 +3783,7 @@ // WallpaperType isn't |WallpaperType::kDaily|. TEST_F(WallpaperControllerTest, SetDailyRefreshCollectionId_Empty_NotTypeDaily) { - controller_->SetUserWallpaperInfo( + pref_manager_->SetUserWallpaperInfo( account_id_1, WallpaperInfo(std::string(), WALLPAPER_LAYOUT_CENTER, WallpaperType::kCustomized, DayBeforeYesterdayish())); @@ -3950,7 +3794,7 @@ WallpaperType::kCustomized, DayBeforeYesterdayish()); WallpaperInfo actual; - controller_->GetUserWallpaperInfo(account_id_1, &actual); + pref_manager_->GetUserWallpaperInfo(account_id_1, &actual); EXPECT_EQ(expected, actual); EXPECT_EQ(std::string(), controller_->GetDailyRefreshCollectionId(account_id_1)); @@ -3981,7 +3825,7 @@ EXPECT_EQ(1, GetWallpaperCount()); EXPECT_EQ(controller_->GetWallpaperType(), WallpaperType::kOnline); - controller_->SetUserWallpaperInfo(account_id_1, WallpaperInfo(params)); + pref_manager_->SetUserWallpaperInfo(account_id_1, WallpaperInfo(params)); Shell::Get()->session_controller()->GetActivePrefService()->SetBoolean( prefs::kDarkModeEnabled, true); controller_->OnColorModeChanged(true); @@ -3995,7 +3839,7 @@ /*from_user=*/true, /*daily_refresh_enabled=*/false, kUnitId, variants)); WallpaperInfo actual; - EXPECT_TRUE(controller_->GetUserWallpaperInfo(account_id_1, &actual)); + EXPECT_TRUE(pref_manager_->GetUserWallpaperInfo(account_id_1, &actual)); EXPECT_EQ(expected, actual); } @@ -4022,7 +3866,7 @@ EXPECT_EQ(1, GetWallpaperCount()); EXPECT_EQ(controller_->GetWallpaperType(), WallpaperType::kOnline); - controller_->SetUserWallpaperInfo(account_id_1, WallpaperInfo(params)); + pref_manager_->SetUserWallpaperInfo(account_id_1, WallpaperInfo(params)); Shell::Get()->session_controller()->GetActivePrefService()->SetBoolean( prefs::kDarkModeEnabled, true); controller_->OnColorModeChanged(true); @@ -4041,7 +3885,7 @@ /*from_user=*/true, /*daily_refresh_enabled=*/false, kUnitId, variants)); WallpaperInfo actual; - EXPECT_TRUE(controller_->GetUserWallpaperInfo(account_id_1, &actual)); + EXPECT_TRUE(pref_manager_->GetUserWallpaperInfo(account_id_1, &actual)); EXPECT_EQ(expected, actual); } @@ -4062,10 +3906,10 @@ /*preview_mode=*/false, /*from_user=*/true, /*daily_refresh_enabled=*/false, kUnitId, variants); - controller_->SetUserWallpaperInfo(account_id_1, WallpaperInfo(params)); + pref_manager_->SetUserWallpaperInfo(account_id_1, WallpaperInfo(params)); WallpaperInfo expected = WallpaperInfo(params); WallpaperInfo actual; - controller_->GetUserWallpaperInfo(account_id_1, &actual); + pref_manager_->GetUserWallpaperInfo(account_id_1, &actual); EXPECT_EQ(expected, actual); } @@ -4107,7 +3951,8 @@ EXPECT_EQ(controller_->GetWallpaperType(), WallpaperType::kOnline); // Verify that the user wallpaper info is updated. WallpaperInfo wallpaper_info; - EXPECT_TRUE(controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); + EXPECT_TRUE( + pref_manager_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); WallpaperInfo expected_wallpaper_info = WallpaperInfo(params); EXPECT_EQ(wallpaper_info, expected_wallpaper_info); @@ -4161,8 +4006,7 @@ /*daily_refresh_enabled=*/false, absl::nullopt, variants); // local info doesn't have unit_id. const WallpaperInfo& local_info = WallpaperInfo(params); - PutWallpaperInfoInPrefs(account_id_1, local_info, GetLocalPrefService(), - prefs::kUserWallpaperInfo); + pref_manager_->SetLocalWallpaperInfo(account_id_1, local_info); const OnlineWallpaperParams& params2 = OnlineWallpaperParams(account_id_1, kAssetId2, GURL(kDummyUrl2), @@ -4172,13 +4016,11 @@ /*daily_refresh_enabled=*/false, kUnitId, variants); // synced info tracks dark variant. const WallpaperInfo& synced_info = WallpaperInfo(params2); - PutWallpaperInfoInPrefs(account_id_1, synced_info, - GetProfilePrefService(account_id_1), - prefs::kSyncableWallpaperInfo); + pref_manager_->SetSyncedWallpaperInfo(account_id_1, synced_info); RunAllTasksUntilIdle(); WallpaperInfo actual_info; - EXPECT_TRUE(controller_->GetUserWallpaperInfo(account_id_1, &actual_info)); + EXPECT_TRUE(pref_manager_->GetUserWallpaperInfo(account_id_1, &actual_info)); EXPECT_EQ(synced_info, actual_info); // Verify the wallpaper is set. EXPECT_EQ(1, GetWallpaperCount()); @@ -4203,8 +4045,7 @@ /*daily_refresh_enabled=*/false, kUnitId, variants); // local info tracks light variant. const WallpaperInfo& local_info = WallpaperInfo(params); - PutWallpaperInfoInPrefs(account_id_1, local_info, GetLocalPrefService(), - prefs::kUserWallpaperInfo); + pref_manager_->SetLocalWallpaperInfo(account_id_1, local_info); const OnlineWallpaperParams& params2 = OnlineWallpaperParams(account_id_1, kAssetId2, GURL(kDummyUrl2), @@ -4214,13 +4055,11 @@ /*daily_refresh_enabled=*/false, kUnitId, variants); // synced info tracks dark variant. const WallpaperInfo& synced_info = WallpaperInfo(params2); - PutWallpaperInfoInPrefs(account_id_1, synced_info, - GetProfilePrefService(account_id_1), - prefs::kSyncableWallpaperInfo); + pref_manager_->SetSyncedWallpaperInfo(account_id_1, synced_info); RunAllTasksUntilIdle(); WallpaperInfo actual_info; - EXPECT_TRUE(controller_->GetUserWallpaperInfo(account_id_1, &actual_info)); + EXPECT_TRUE(pref_manager_->GetUserWallpaperInfo(account_id_1, &actual_info)); EXPECT_EQ(local_info, synced_info); EXPECT_EQ(local_info, actual_info); // Verify the wallpaper is not set again. @@ -4313,7 +4152,8 @@ WallpaperType::kOnceGooglePhotos); WallpaperInfo wallpaper_info; - EXPECT_TRUE(controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); + EXPECT_TRUE( + pref_manager_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); WallpaperInfo expected_wallpaper_info(params); EXPECT_EQ(feature_enabled, wallpaper_info == expected_wallpaper_info); } @@ -4355,7 +4195,8 @@ EXPECT_NE(controller_->GetWallpaperType(), WallpaperType::kOnceGooglePhotos); WallpaperInfo wallpaper_info; - EXPECT_TRUE(controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); + EXPECT_TRUE( + pref_manager_->GetUserWallpaperInfo(account_id_1, &wallpaper_info)); WallpaperInfo expected_wallpaper_info(online_params); EXPECT_EQ(wallpaper_info, expected_wallpaper_info); } @@ -4416,7 +4257,7 @@ WallpaperInfo info = {kFakeGooglePhotosPhotoId, WALLPAPER_LAYOUT_CENTER, WallpaperType::kOnceGooglePhotos, DayBeforeYesterdayish()}; - controller_->SetUserWallpaperInfo(account_id_1, info); + pref_manager_->SetUserWallpaperInfo(account_id_1, info); client_.set_google_photo_has_been_deleted(true); // Trigger Google Photos wallpaper cache check. @@ -4520,7 +4361,7 @@ std::string(), WALLPAPER_LAYOUT_CENTER_CROPPED, WallpaperType::kDefault, base::Time::Now().LocalMidnight()); EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); EXPECT_EQ(user_wallpaper_info, default_wallpaper_info); // Simulate opening the wallpaper picker window. @@ -4548,7 +4389,7 @@ // Verify that the user wallpaper info remains unchanged during the preview. EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); EXPECT_EQ(user_wallpaper_info, default_wallpaper_info); histogram_tester().ExpectTotalCount("Ash.Wallpaper.Preview.Show", GooglePhotosEnabled() ? 1 : 0); @@ -4568,8 +4409,8 @@ WallpaperInfo google_photos_wallpaper_info( photo_id, layout, WallpaperType::kOnceGooglePhotos, base::Time::Now().LocalMidnight()); - EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); + EXPECT_TRUE(pref_manager_->GetUserWallpaperInfo(account_id_1, + &user_wallpaper_info)); EXPECT_EQ(user_wallpaper_info, google_photos_wallpaper_info); } } @@ -4587,7 +4428,7 @@ std::string(), WALLPAPER_LAYOUT_CENTER_CROPPED, WallpaperType::kDefault, base::Time::Now().LocalMidnight()); EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); EXPECT_EQ(user_wallpaper_info, default_wallpaper_info); // Simulate opening the wallpaper picker window. @@ -4614,7 +4455,7 @@ // Verify that the user wallpaper info remains unchanged during the preview. EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); EXPECT_EQ(user_wallpaper_info, default_wallpaper_info); histogram_tester().ExpectTotalCount("Ash.Wallpaper.Preview.Show", GooglePhotosEnabled() ? 1 : 0); @@ -4645,7 +4486,7 @@ std::string(), WALLPAPER_LAYOUT_CENTER_CROPPED, WallpaperType::kDefault, base::Time::Now().LocalMidnight()); EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); EXPECT_EQ(user_wallpaper_info, default_wallpaper_info); // Simulate opening the wallpaper picker window. @@ -4673,7 +4514,7 @@ // Verify that the user wallpaper info remains unchanged during the preview. EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); + pref_manager_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); EXPECT_EQ(user_wallpaper_info, default_wallpaper_info); histogram_tester().ExpectTotalCount("Ash.Wallpaper.Preview.Show", GooglePhotosEnabled() ? 1 : 0); @@ -4698,8 +4539,8 @@ WallpaperInfo synced_custom_wallpaper_info( base::FilePath(wallpaper_files_id_1).Append(file_name_1).value(), layout, WallpaperType::kCustomized, base::Time::Now().LocalMidnight()); - EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); + EXPECT_TRUE(pref_manager_->GetUserWallpaperInfo(account_id_1, + &user_wallpaper_info)); EXPECT_EQ(user_wallpaper_info, synced_custom_wallpaper_info); // Now cancel the preview. Verify the synced custom wallpaper is shown @@ -4710,8 +4551,8 @@ RunAllTasksUntilIdle(); EXPECT_EQ(GetWallpaperCount(), 1); EXPECT_EQ(controller_->GetWallpaperType(), WallpaperType::kCustomized); - EXPECT_TRUE( - controller_->GetUserWallpaperInfo(account_id_1, &user_wallpaper_info)); + EXPECT_TRUE(pref_manager_->GetUserWallpaperInfo(account_id_1, + &user_wallpaper_info)); EXPECT_EQ(user_wallpaper_info, synced_custom_wallpaper_info); } } @@ -4730,14 +4571,14 @@ /*daily_refresh_enabled=*/true, WALLPAPER_LAYOUT_CENTER_CROPPED, /*preview_mode=*/false, /*dedup_key=*/absl::nullopt); WallpaperInfo info(params); - controller_->SetUserWallpaperInfo(account_id_1, info); + pref_manager_->SetUserWallpaperInfo(account_id_1, info); controller_->UpdateDailyRefreshWallpaperForTesting(); RunAllTasksUntilIdle(); WallpaperInfo expected_info; bool success = - controller_->GetUserWallpaperInfo(account_id_1, &expected_info); + pref_manager_->GetUserWallpaperInfo(account_id_1, &expected_info); EXPECT_EQ(success, GooglePhotosEnabled()); if (success) { EXPECT_EQ(expected_photo_id, expected_info.location); @@ -4754,7 +4595,7 @@ /*daily_refresh_enabled=*/true, WALLPAPER_LAYOUT_CENTER_CROPPED, /*preview_mode=*/false, /*dedup_key=*/absl::nullopt); WallpaperInfo info(params); - controller_->SetUserWallpaperInfo(account_id_1, info); + pref_manager_->SetUserWallpaperInfo(account_id_1, info); controller_->UpdateDailyRefreshWallpaperForTesting(); RunAllTasksUntilIdle(); @@ -4782,7 +4623,7 @@ /*daily_refresh_enabled=*/true, WALLPAPER_LAYOUT_CENTER_CROPPED, /*preview_mode=*/false, /*dedup_key=*/absl::nullopt); WallpaperInfo info(params); - controller_->SetUserWallpaperInfo(account_id_1, info); + pref_manager_->SetUserWallpaperInfo(account_id_1, info); client_.set_fetch_google_photos_photo_fails(true); controller_->UpdateDailyRefreshWallpaperForTesting(); @@ -4820,7 +4661,7 @@ /*variants=*/std::vector<OnlineWallpaperVariant>()); WallpaperInfo online_info(online_params); - controller_->SetUserWallpaperInfo(account_id_1, online_info); + pref_manager_->SetUserWallpaperInfo(account_id_1, online_info); client_.set_fetch_google_photos_photo_fails(true); controller_->SetGooglePhotosWallpaper(daily_google_photos_params, @@ -4828,7 +4669,7 @@ RunAllTasksUntilIdle(); WallpaperInfo current_info; - controller_->GetUserWallpaperInfo(account_id_1, ¤t_info); + pref_manager_->GetUserWallpaperInfo(account_id_1, ¤t_info); EXPECT_EQ(online_info, current_info); } @@ -4847,7 +4688,7 @@ RunAllTasksUntilIdle(); WallpaperInfo current_info; - controller_->GetUserWallpaperInfo(account_id_1, ¤t_info); + pref_manager_->GetUserWallpaperInfo(account_id_1, ¤t_info); EXPECT_EQ(GooglePhotosEnabled(), WallpaperType::kDailyGooglePhotos == current_info.type); @@ -4859,7 +4700,7 @@ controller_->UpdateDailyRefreshWallpaperForTesting(); RunAllTasksUntilIdle(); - controller_->GetUserWallpaperInfo(account_id_1, ¤t_info); + pref_manager_->GetUserWallpaperInfo(account_id_1, ¤t_info); EXPECT_EQ(GooglePhotosEnabled(), WallpaperType::kDefault == current_info.type); @@ -4899,7 +4740,7 @@ WallpaperInfo info = {kFakeGooglePhotosPhotoId, WALLPAPER_LAYOUT_CENTER, type, base::Time::Now()}; - controller_->SetUserWallpaperInfo(account_id_1, info); + pref_manager_->SetUserWallpaperInfo(account_id_1, info); controller_->ShowUserWallpaper(account_id_1); RunAllTasksUntilIdle();
diff --git a/ash/wallpaper/wallpaper_pref_manager_unittest.cc b/ash/wallpaper/wallpaper_pref_manager_unittest.cc index 2aeca0d..b9e9e10f 100644 --- a/ash/wallpaper/wallpaper_pref_manager_unittest.cc +++ b/ash/wallpaper/wallpaper_pref_manager_unittest.cc
@@ -33,6 +33,8 @@ constexpr char kUser1[] = "user1@test.com"; const AccountId account_id_1 = AccountId::FromUserEmailGaiaId(kUser1, kUser1); +constexpr char kFakeGooglePhotosPhotoId[] = "fake_photo"; + WallpaperInfo InfoWithType(WallpaperType type) { return WallpaperInfo(std::string(), WALLPAPER_LAYOUT_CENTER_CROPPED, type, base::Time::Now()); @@ -91,6 +93,7 @@ WallpaperInfo info, PrefService* pref_service, const std::string& pref_name) { + DCHECK(pref_service); DictionaryPrefUpdate wallpaper_update(pref_service, pref_name); base::Value wallpaper_info_dict = CreateWallpaperInfoDict(info); wallpaper_update->SetKey(account_id.GetUserEmail(), @@ -100,9 +103,10 @@ void AssertWallpaperInfoInPrefs(const PrefService* pref_service, const char pref_name[], AccountId account_id, - WallpaperInfo info) { + const WallpaperInfo& info) { const base::Value::Dict* stored_info_dict = pref_service->GetValueDict(pref_name).FindDict(account_id.GetUserEmail()); + DCHECK(stored_info_dict); base::Value expected_info_dict = CreateWallpaperInfoDict(info); EXPECT_EQ(expected_info_dict, *stored_info_dict); } @@ -235,6 +239,17 @@ account_id_1, info); } +TEST_F(WallpaperPrefManagerTest, SetWallpaperInfoLocalFromGooglePhotos) { + WallpaperInfo info( + GooglePhotosWallpaperParams{account_id_1, kFakeGooglePhotosPhotoId, + /*daily_refresh_enabled=*/false, + WallpaperLayout::WALLPAPER_LAYOUT_STRETCH, + /*preview_mode=*/false, "dedup_key"}); + EXPECT_TRUE(pref_manager_->SetUserWallpaperInfo(account_id_1, info)); + AssertWallpaperInfoInPrefs(GetLocalPrefService(), prefs::kUserWallpaperInfo, + account_id_1, info); +} + TEST_F(WallpaperPrefManagerTest, SetWallpaperInfoSynced) { profile_helper_->RegisterPrefsForAccount(account_id_1); @@ -245,6 +260,16 @@ prefs::kSyncableWallpaperInfo, account_id_1, info); } +TEST_F(WallpaperPrefManagerTest, SetWallpaperInfoSyncedFromGooglePhotos) { + profile_helper_->RegisterPrefsForAccount(account_id_1); + + WallpaperInfo info = InfoWithType(WallpaperType::kOnceGooglePhotos); + EXPECT_TRUE(pref_manager_->SetUserWallpaperInfo(account_id_1, info)); + AssertWallpaperInfoInPrefs( + profile_helper_->GetUserPrefServiceSyncable(account_id_1), + prefs::kSyncableWallpaperInfo, account_id_1, info); +} + TEST_F(WallpaperPrefManagerTest, SetWallpaperInfoSyncDisabled) { profile_helper_->RegisterPrefsForAccount(account_id_1); // This needs to be saved before sync is disabled or we can't get a pref
diff --git a/ash/webui/diagnostics_ui/backend/session_log_handler_unittest.cc b/ash/webui/diagnostics_ui/backend/session_log_handler_unittest.cc index c0a2832..ea8fa7b 100644 --- a/ash/webui/diagnostics_ui/backend/session_log_handler_unittest.cc +++ b/ash/webui/diagnostics_ui/backend/session_log_handler_unittest.cc
@@ -47,7 +47,6 @@ namespace { constexpr char kHandlerFunctionName[] = "handlerFunctionName"; -constexpr char kRoutineLogFileName[] = "diagnostic_routine_log"; mojom::SystemInfoPtr CreateSystemInfoPtr(const std::string& board_name, const std::string& marketing_name, @@ -169,38 +168,49 @@ base::FilePath selected_path_; }; -class SessionLogHandlerTest : public testing::Test { +// Test class using NoSessionAshTestBase to ensure shell is available for +// tests requiring DiagnosticsLogController singleton. +class SessionLogHandlerTest : public NoSessionAshTestBase { public: SessionLogHandlerTest() - : task_environment_(), + : NoSessionAshTestBase( + base::test::TaskEnvironment::TimeSource::MOCK_TIME), task_runner_(new base::TestSimpleTaskRunner()), web_ui_(), - session_log_handler_() { + session_log_handler_() {} + ~SessionLogHandlerTest() override = default; + + void SetUp() override { EXPECT_TRUE(temp_dir_.CreateUniqueTempDir()); - base::FilePath routine_log_path = - temp_dir_.GetPath().AppendASCII(kRoutineLogFileName); - auto telemetry_log = std::make_unique<TelemetryLog>(); - auto routine_log = std::make_unique<RoutineLog>(routine_log_path); - auto networking_log = std::make_unique<NetworkingLog>(temp_dir_.GetPath()); - telemetry_log_ = telemetry_log.get(); - routine_log_ = routine_log.get(); - networking_log_ = networking_log.get(); + // Setup to ensure ash::Shell can configure for tests. + ui::ResourceBundle::CleanupSharedInstance(); + AshTestSuite::LoadTestResources(); + NoSessionAshTestBase::SetUp(); + DiagnosticsLogController::Initialize( + std::make_unique<FakeDiagnosticsBrowserDelegate>()); + auto* controller = DiagnosticsLogController::Get(); + telemetry_log_ = controller->GetTelemetryLog(); + routine_log_ = controller->GetRoutineLog(); + networking_log_ = controller->GetNetworkingLog(); session_log_handler_ = std::make_unique<diagnostics::SessionLogHandler>( base::BindRepeating(&CreateTestSelectFilePolicy), - std::move(telemetry_log), std::move(routine_log), - std::move(networking_log), &holding_space_client_); + /*telemetry_log*/ nullptr, /*routine_log*/ nullptr, + /*networking_log*/ nullptr, &holding_space_client_); session_log_handler_->SetWebUIForTest(&web_ui_); session_log_handler_->RegisterMessages(); session_log_handler_->SetTaskRunnerForTesting(task_runner_); + // Call handler to enable Javascript. base::ListValue args; web_ui_.HandleReceivedMessage("initialize", &args); } - ~SessionLogHandlerTest() override { + void TearDown() override { task_runner_.reset(); - task_environment_.RunUntilIdle(); + task_environment()->RunUntilIdle(); ui::SelectFileDialog::SetFactory(nullptr); + + NoSessionAshTestBase::TearDown(); } void RunTasks() { task_runner_->RunPendingTasks(); } @@ -214,18 +224,15 @@ } protected: - base::test::TaskEnvironment task_environment_{ - base::test::TaskEnvironment::TimeSource::MOCK_TIME}; // Task runner for tasks posted by save session log handler. scoped_refptr<base::TestSimpleTaskRunner> task_runner_; - content::TestWebUI web_ui_; - std::unique_ptr<diagnostics::SessionLogHandler> session_log_handler_; + std::unique_ptr<SessionLogHandler> session_log_handler_; + base::ScopedTempDir temp_dir_; TelemetryLog* telemetry_log_; RoutineLog* routine_log_; NetworkingLog* networking_log_; testing::NiceMock<ash::MockHoldingSpaceClient> holding_space_client_; - base::ScopedTempDir temp_dir_; }; // Flaky; see crbug.com/1336726 @@ -233,7 +240,7 @@ base::RunLoop run_loop; // Populate routine log routine_log_->LogRoutineStarted(mojom::RoutineType::kCpuStress); - task_environment_.RunUntilIdle(); + task_environment()->RunUntilIdle(); // Populate telemetry log const std::string expected_board_name = "board_name"; @@ -304,52 +311,8 @@ EXPECT_EQ("--- Network Events ---", log_lines[17]); } -// Test class using NoSessionAshTestBase to ensure shell is available for -// tests requiring DiagnosticsLogController singleton. -class SessionLogHandlerAshTest : public NoSessionAshTestBase { - public: - SessionLogHandlerAshTest() : task_runner_(new base::TestSimpleTaskRunner()) {} - ~SessionLogHandlerAshTest() override = default; - - void SetUp() override { - // Setup to ensure ash::Shell can configure for tests. - ui::ResourceBundle::CleanupSharedInstance(); - AshTestSuite::LoadTestResources(); - // Setup feature list before setting up ash::Shell. - feature_list_.InitAndEnableFeature( - ash::features::kEnableLogControllerForDiagnosticsApp); - NoSessionAshTestBase::SetUp(); - DiagnosticsLogController::Initialize( - std::make_unique<FakeDiagnosticsBrowserDelegate>()); - session_log_handler_ = std::make_unique<SessionLogHandler>( - base::BindRepeating(&CreateTestSelectFilePolicy), - /*telemetry_log*/ nullptr, - /*routine_log*/ nullptr, - /*networking_log*/ nullptr, - /*holding_space_client*/ &holding_space_client_); - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - session_log_handler_->SetWebUIForTest(&web_ui_); - session_log_handler_->RegisterMessages(); - session_log_handler_->SetTaskRunnerForTesting(task_runner_); - // Call handler to enable Javascript. - base::ListValue args; - web_ui_.HandleReceivedMessage("initialize", &args); - } - - void RunTasks() { task_runner_->RunPendingTasks(); } - - protected: - base::test::ScopedFeatureList feature_list_; - std::unique_ptr<SessionLogHandler> session_log_handler_; - content::TestWebUI web_ui_; - base::ScopedTempDir temp_dir_; - testing::NiceMock<ash::MockHoldingSpaceClient> holding_space_client_; - // Task runner for tasks posted by save session log handler. - scoped_refptr<base::TestSimpleTaskRunner> task_runner_; -}; - // Validates behavior when log controller is used to generate session log. -TEST_F(SessionLogHandlerAshTest, SaveSessionLogFlagEnabled) { +TEST_F(SessionLogHandlerTest, SaveHeaderOnlySessionLog) { base::RunLoop run_loop; // Simulate select file
diff --git a/ash/webui/os_feedback_ui/resources/os_feedback_shared_css.html b/ash/webui/os_feedback_ui/resources/os_feedback_shared_css.html index cad5ac6..42f9d1d 100644 --- a/ash/webui/os_feedback_ui/resources/os_feedback_shared_css.html +++ b/ash/webui/os_feedback_ui/resources/os_feedback_shared_css.html
@@ -11,8 +11,14 @@ background-color: var(--cros-bg-color); } - a[href] { + a { color: var(--cros-link-color); + text-decoration: none; + } + + a:focus, + a:hover { + text-decoration: underline; } #container {
diff --git a/ash/webui/os_feedback_ui/resources/share_data_page.html b/ash/webui/os_feedback_ui/resources/share_data_page.html index ada18c2..cee3c65 100644 --- a/ash/webui/os_feedback_ui/resources/share_data_page.html +++ b/ash/webui/os_feedback_ui/resources/share_data_page.html
@@ -1,10 +1,4 @@ <style include="os-feedback-shared"> - #legalHelpPageUrl, - #privacyPolicyUrl, - #termsOfServiceUrl { - text-decoration: none; - } - #privacyNote { color: var(--cros-color-secondary); font-size: 13px; @@ -44,6 +38,7 @@ #screenshotCheckLabel { flex: 1; + margin-inline-end: 12px; } #screenshotContainer > button { @@ -80,6 +75,7 @@ } .md-select { + --md-select-side-padding: 16px; height: 32px; width: 248px; } @@ -103,10 +99,6 @@ color: var(--cros-text-color-disabled); } - #sysInfoCheckboxLabel { - line-height: 20px; - } - #screenshotCheckbox { margin-inline-end: 10px; margin-inline-start: 12px; @@ -114,7 +106,6 @@ #screenshotCheckLabel { font-weight: 400; - line-height: 20px; } #imageButton { @@ -137,6 +128,7 @@ label { color: var(--cros-text-color-primary); + line-height: 20px; } </style> <div id="container">
diff --git a/ash/webui/projector_app/annotator_message_handler.cc b/ash/webui/projector_app/annotator_message_handler.cc index e4f40fc3..9c797590 100644 --- a/ash/webui/projector_app/annotator_message_handler.cc +++ b/ash/webui/projector_app/annotator_message_handler.cc
@@ -7,8 +7,8 @@ #include <memory> #include "ash/public/cpp/projector/annotator_tool.h" -#include "ash/public/cpp/projector/projector_client.h" #include "ash/public/cpp/projector/projector_controller.h" +#include "ash/webui/projector_app/projector_app_client.h" #include "base/check.h" #include "base/json/values_util.h" #include "base/values.h" @@ -17,11 +17,11 @@ namespace ash { AnnotatorMessageHandler::AnnotatorMessageHandler() { - ProjectorClient::Get()->SetAnnotatorMessageHandler(this); + ProjectorAppClient::Get()->SetAnnotatorMessageHandler(this); } AnnotatorMessageHandler::~AnnotatorMessageHandler() { - ProjectorClient::Get()->ResetAnnotatorMessageHandler(this); + ProjectorAppClient::Get()->ResetAnnotatorMessageHandler(this); }; void AnnotatorMessageHandler::RegisterMessages() {
diff --git a/ash/webui/projector_app/projector_app_client.h b/ash/webui/projector_app/projector_app_client.h index c952d49a..238b9a5b 100644 --- a/ash/webui/projector_app/projector_app_client.h +++ b/ash/webui/projector_app/projector_app_client.h
@@ -28,6 +28,9 @@ namespace ash { +class AnnotatorMessageHandler; + +struct AnnotatorTool; struct ProjectorScreencast; struct NewScreencastPrecondition; @@ -157,6 +160,21 @@ virtual void GetScreencast(const std::string& screencast_id, OnGetScreencastCallback callback) = 0; + // Registers the AnnotatorMessageHandler that is owned by the WebUI that + // contains the Projector annotator. + virtual void SetAnnotatorMessageHandler(AnnotatorMessageHandler* handler) = 0; + + // Resets the stored AnnotatorMessageHandler if it matches the one that is + // passed in. + virtual void ResetAnnotatorMessageHandler( + AnnotatorMessageHandler* handler) = 0; + + // Sets the tool inside the annotator WebUI. + virtual void SetTool(const AnnotatorTool& tool) = 0; + + // Clears the contents of the annotator canvas. + virtual void Clear() = 0; + protected: ProjectorAppClient(); virtual ~ProjectorAppClient();
diff --git a/ash/webui/projector_app/test/annotator_message_handler_unittest.cc b/ash/webui/projector_app/test/annotator_message_handler_unittest.cc index 580b19f..8f5b3c88 100644 --- a/ash/webui/projector_app/test/annotator_message_handler_unittest.cc +++ b/ash/webui/projector_app/test/annotator_message_handler_unittest.cc
@@ -5,8 +5,8 @@ #include "ash/webui/projector_app/annotator_message_handler.h" #include "ash/public/cpp/projector/annotator_tool.h" -#include "ash/public/cpp/test/mock_projector_client.h" #include "ash/public/cpp/test/mock_projector_controller.h" +#include "ash/webui/projector_app/test/mock_app_client.h" #include "base/test/task_environment.h" #include "base/values.h" #include "content/public/test/test_web_ui.h" @@ -70,7 +70,7 @@ std::unique_ptr<AnnotatorMessageHandler> message_handler_; content::TestWebUI web_ui_; MockProjectorController controller_; - MockProjectorClient client_; + MockAppClient client_; }; TEST_F(AnnotatorMessageHandlerTest, SetTool) {
diff --git a/ash/webui/projector_app/test/mock_app_client.h b/ash/webui/projector_app/test/mock_app_client.h index 45ad9db..30b28d5 100644 --- a/ash/webui/projector_app/test/mock_app_client.h +++ b/ash/webui/projector_app/test/mock_app_client.h
@@ -54,6 +54,10 @@ MOCK_METHOD2(GetScreencast, void(const std::string&, ProjectorAppClient::OnGetScreencastCallback)); + MOCK_METHOD1(SetAnnotatorMessageHandler, void(AnnotatorMessageHandler*)); + MOCK_METHOD1(ResetAnnotatorMessageHandler, void(AnnotatorMessageHandler*)); + MOCK_METHOD1(SetTool, void(const AnnotatorTool&)); + MOCK_METHOD0(Clear, void()); void SetAutomaticIssueOfAccessTokens(bool success); void WaitForAccessRequest(const std::string& account_email);
diff --git a/base/process/memory_unittest.cc b/base/process/memory_unittest.cc index f043c9e9..c8d374b 100644 --- a/base/process/memory_unittest.cc +++ b/base/process/memory_unittest.cc
@@ -119,6 +119,7 @@ !defined(MEMORY_TOOL_REPLACES_ALLOCATOR) namespace { + #if BUILDFLAG(IS_WIN) // Windows raises an exception in order to make the exit code unique to OOM. @@ -282,10 +283,13 @@ } #endif // BUILDFLAG(IS_WIN) -// OS X and Android have no 2Gb allocation limit. +// OS X has no 2Gb allocation limit. // See https://crbug.com/169327. -#if !BUILDFLAG(IS_MAC) && !BUILDFLAG(IS_ANDROID) +#if !BUILDFLAG(IS_MAC) TEST_F(OutOfMemoryDeathTest, SecurityNew) { + if (ShouldSkipTest()) { + return; + } ASSERT_OOM_DEATH({ SetUpInDeathAssert(); value_ = operator new(insecure_test_size_); @@ -293,6 +297,9 @@ } TEST_F(OutOfMemoryDeathTest, SecurityNewArray) { + if (ShouldSkipTest()) { + return; + } ASSERT_OOM_DEATH({ SetUpInDeathAssert(); value_ = new char[insecure_test_size_]; @@ -300,6 +307,9 @@ } TEST_F(OutOfMemoryDeathTest, SecurityMalloc) { + if (ShouldSkipTest()) { + return; + } ASSERT_OOM_DEATH({ SetUpInDeathAssert(); value_ = malloc(insecure_test_size_); @@ -307,6 +317,9 @@ } TEST_F(OutOfMemoryDeathTest, SecurityRealloc) { + if (ShouldSkipTest()) { + return; + } ASSERT_OOM_DEATH({ SetUpInDeathAssert(); value_ = realloc(nullptr, insecure_test_size_); @@ -314,6 +327,9 @@ } TEST_F(OutOfMemoryDeathTest, SecurityCalloc) { + if (ShouldSkipTest()) { + return; + } ASSERT_OOM_DEATH({ SetUpInDeathAssert(); value_ = calloc(1024, insecure_test_size_ / 1024L); @@ -321,6 +337,9 @@ } TEST_F(OutOfMemoryDeathTest, SecurityAlignedAlloc) { + if (ShouldSkipTest()) { + return; + } ASSERT_OOM_DEATH({ SetUpInDeathAssert(); value_ = base::AlignedAlloc(insecure_test_size_, 8); @@ -330,13 +349,16 @@ // POSIX does not define an aligned realloc function. #if BUILDFLAG(IS_WIN) TEST_F(OutOfMemoryDeathTest, SecurityAlignedRealloc) { + if (ShouldSkipTest()) { + return; + } ASSERT_OOM_DEATH({ SetUpInDeathAssert(); value_ = _aligned_realloc(nullptr, insecure_test_size_, 8); }); } #endif // BUILDFLAG(IS_WIN) -#endif // !BUILDFLAG(IS_MAC) && !BUILDFLAG(IS_ANDROID) +#endif // !BUILDFLAG(IS_MAC) #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
diff --git a/cc/base/synced_property.h b/cc/base/synced_property.h index f5173bc..8d29bc7 100644 --- a/cc/base/synced_property.h +++ b/cc/base/synced_property.h
@@ -5,7 +5,10 @@ #ifndef CC_BASE_SYNCED_PROPERTY_H_ #define CC_BASE_SYNCED_PROPERTY_H_ +#include <utility> + #include "base/memory/ref_counted.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace cc { @@ -39,8 +42,7 @@ // Sets the value on the impl thread, due to an impl-thread-originating // action. Returns true if this had any effect. This will remain // impl-thread-only information at first, and will get pulled back to the main - // thread on the next call of PullDeltaToMainThread (which happens right - // before the commit). + // thread on the next call of PullDeltaForMainThread. bool SetCurrent(BaseT current) { DeltaT delta = T::DeltaBetweenBases(current, active_base_); if (active_delta_ == delta) @@ -57,16 +59,27 @@ // Returns the latest active tree delta and also makes a note that this value // was sent to the main thread. DeltaT PullDeltaForMainThread() { - reflected_delta_in_main_tree_ = PendingDelta(); - return reflected_delta_in_main_tree_; + DCHECK(!next_reflected_delta_in_main_tree_.has_value()); + DeltaT result = UnsentDelta(); + if (reflected_delta_in_main_tree_.has_value()) { + next_reflected_delta_in_main_tree_.emplace(result); + } else { + reflected_delta_in_main_tree_.emplace(result); + } + return result; } // Push the latest value from the main thread onto pending tree-associated // state. Returns true if pushing the value results in different values // between the main layer tree and the pending tree. bool PushMainToPending(BaseT main_thread_value) { - reflected_delta_in_pending_tree_ = reflected_delta_in_main_tree_; - reflected_delta_in_main_tree_ = T::IdentityDelta(); + DCHECK(reflected_delta_in_main_tree_.has_value() || + !next_reflected_delta_in_main_tree_.has_value()); + reflected_delta_in_pending_tree_ = + reflected_delta_in_main_tree_.value_or(T::IdentityDelta()); + reflected_delta_in_main_tree_ = + std::move(next_reflected_delta_in_main_tree_); + next_reflected_delta_in_main_tree_.reset(); pending_base_ = main_thread_value; return Current(false) != main_thread_value; @@ -97,16 +110,52 @@ active_value_before_push != current_active_value; } - // This simulates the consequences of the sent value getting committed and - // activated. - void AbortCommit() { - pending_base_ = T::ApplyDelta(pending_base_, reflected_delta_in_main_tree_); - active_base_ = T::ApplyDelta(active_base_, reflected_delta_in_main_tree_); - active_delta_ = - T::DeltaBetweenDeltas(active_delta_, reflected_delta_in_main_tree_); - reflected_delta_in_main_tree_ = T::IdentityDelta(); + void AbortCommit(bool main_frame_applied_deltas) { + // Finish processing the delta that was sent to the main thread, and reset + // the corresponding the delta_in_main_tree_ variable. If + // main_frame_applied_deltas is true, we send the delta on to the active + // tree just as would happen for a successful commit. Otherwise, we treat + // the delta as never having been sent to the main thread and just drop it. + if (next_reflected_delta_in_main_tree_.has_value()) { + // If next_reflected_delta_in_main_tree_ is populated, we know two things: + // - This abort corresponds to next_reflected_delta_in_main_tree_, + // because we only send a "next" BeginMainFrame if the previous one + // has already signaled "ready to commit". + // - The previous main frame has not yet run commit. If it had, then + // PushMainToPending would have promoted + // next_reflected_delta_in_main_tree_ to reflected_delta_in_main_tree_ + // and next_reflected_delta_in_main_tree_ would be empty. + // In this case, if the main thread processed the delta from this aborted + // commit we can simply add the delta to reflected_delta_in_main_tree_. + if (main_frame_applied_deltas) { + reflected_delta_in_main_tree_ = + T::CombineDeltas(reflected_delta_in_main_tree_.value(), + next_reflected_delta_in_main_tree_.value()); + } + next_reflected_delta_in_main_tree_.reset(); + } else { + // There is no "next" main frame, this abort was for the primary. + if (main_frame_applied_deltas) { + DeltaT delta = + reflected_delta_in_main_tree_.value_or(T::IdentityDelta()); + // This simulates the consequences of the sent value getting committed + // and activated. + pending_base_ = T::ApplyDelta(pending_base_, delta); + active_base_ = T::ApplyDelta(active_base_, delta); + active_delta_ = T::DeltaBetweenDeltas(active_delta_, delta); + } + reflected_delta_in_main_tree_.reset(); + } } + // Values sent to the main thread and not yet resolved in the pending or + // active tree. + const absl::optional<DeltaT>& reflected_delta_in_main_tree() const { + return reflected_delta_in_main_tree_; + } + const absl::optional<DeltaT>& next_reflected_delta_in_main_tree() const { + return next_reflected_delta_in_main_tree_; + } // Values as last pushed to the pending or active tree respectively, with no // impl-thread delta applied. BaseT PendingBase() const { return pending_base_; } @@ -122,6 +171,12 @@ reflected_delta_in_pending_tree_); } + DeltaT UnsentDelta() const { + return T::DeltaBetweenDeltas( + PendingDelta(), + reflected_delta_in_main_tree_.value_or(T::IdentityDelta())); + } + void set_clobber_active_value() { clobber_active_value_ = true; } private: @@ -134,9 +189,13 @@ BaseT active_base_ = T::IdentityBase(); // The difference between |active_base_| and the user-perceived value. DeltaT active_delta_ = T::IdentityDelta(); - // The value sent to the main thread on the last BeginMainFrame. This is - // always identity outside of the BeginMainFrame to (aborted)commit interval. - DeltaT reflected_delta_in_main_tree_ = T::IdentityDelta(); + // A value sent to the main thread on a BeginMainFrame, but not yet applied to + // the resulting pending tree. + absl::optional<DeltaT> reflected_delta_in_main_tree_; + // A value sent to the main thread on a BeginMainFrame at a time when + // reflected_delta_in_main_tree_ is populated. This is used when a main frame + // is sent to the main thread before the previous one has committed. + absl::optional<DeltaT> next_reflected_delta_in_main_tree_; // The value that was sent to the main thread for BeginMainFrame for the // current pending tree. This is always identity outside of the // BeginMainFrame to activation interval. @@ -164,6 +223,7 @@ static BaseT ApplyDelta(BaseT v, DeltaT delta) { return v + delta; } static DeltaT DeltaBetweenBases(BaseT v1, BaseT v2) { return v1 - v2; } static DeltaT DeltaBetweenDeltas(DeltaT d1, DeltaT d2) { return d1 - d2; } + static DeltaT CombineDeltas(DeltaT d1, DeltaT d2) { return d1 + d2; } }; class ScaleGroup { @@ -175,6 +235,7 @@ static float ApplyDelta(float v, float delta) { return v * delta; } static float DeltaBetweenBases(float v1, float v2) { return v1 / v2; } static float DeltaBetweenDeltas(float d1, float d2) { return d1 / d2; } + static float CombineDeltas(float d1, float d2) { return d1 * d2; } }; } // namespace cc
diff --git a/cc/layers/layer_impl_unittest.cc b/cc/layers/layer_impl_unittest.cc index 095e57d..eb85e3a7 100644 --- a/cc/layers/layer_impl_unittest.cc +++ b/cc/layers/layer_impl_unittest.cc
@@ -417,7 +417,8 @@ scroll_tree(layer())->GetScrollOffsetBaseForTesting( layer()->element_id())); - scroll_tree(layer())->ApplySentScrollDeltasFromAbortedCommit(); + scroll_tree(layer())->ApplySentScrollDeltasFromAbortedCommit( + /*main_frame_applied_deltas=*/true); EXPECT_POINTF_EQ(scroll_offset + scroll_delta, CurrentScrollOffset(layer())); EXPECT_VECTOR2DF_EQ(scroll_delta - sent_scroll_delta, ScrollDelta(layer()));
diff --git a/cc/scheduler/commit_earlyout_reason.h b/cc/scheduler/commit_earlyout_reason.h index 7fe59e4..050da07 100644 --- a/cc/scheduler/commit_earlyout_reason.h +++ b/cc/scheduler/commit_earlyout_reason.h
@@ -32,7 +32,7 @@ return "???"; } -inline bool CommitEarlyOutHandledCommit(CommitEarlyOutReason reason) { +inline bool MainFrameAppliedDeltas(CommitEarlyOutReason reason) { return reason == CommitEarlyOutReason::FINISHED_NO_UPDATES; }
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index ac94526..6da2dc63 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc
@@ -567,8 +567,10 @@ // If the begin frame data was handled, then scroll and scale set was applied // by the main thread, so the active tree needs to be updated as if these sent // values were applied and committed. - if (CommitEarlyOutHandledCommit(reason)) { - active_tree_->ApplySentScrollAndScaleDeltasFromAbortedCommit(); + bool main_frame_applied_deltas = MainFrameAppliedDeltas(reason); + active_tree_->ApplySentScrollAndScaleDeltasFromAbortedCommit( + main_frame_applied_deltas); + if (main_frame_applied_deltas) { if (pending_tree_) { pending_tree_->AppendSwapPromises(std::move(swap_promises)); } else {
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc index 916c156b..d50ecc7 100644 --- a/cc/trees/layer_tree_host_impl_unittest.cc +++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -138,6 +138,11 @@ } }; +void ClearMainThreadDeltasForTesting(LayerTreeHostImpl* host) { + host->active_tree()->ApplySentScrollAndScaleDeltasFromAbortedCommit( + /*main_frame_applied_deltas=*/false); +} + } // namespace class LayerTreeHostImplTest : public testing::Test, @@ -360,6 +365,21 @@ size, host_impl_->active_tree()->device_scale_factor()); } + void PushScrollOffsetsToPendingTree( + const base::flat_map<ElementId, gfx::PointF>& offsets) { + PropertyTrees property_trees(*host_impl_); + for (auto& entry : offsets) { + property_trees.scroll_tree_mutable().SetBaseScrollOffset(entry.first, + entry.second); + } + host_impl_->sync_tree() + ->property_trees() + ->scroll_tree_mutable() + .PushScrollUpdatesFromMainThread( + property_trees, host_impl_->sync_tree(), + host_impl_->settings().commit_fractional_scroll_deltas); + } + static void ExpectClearedScrollDeltasRecursive(LayerImpl* root) { for (auto* layer : *root->layer_tree_impl()) ASSERT_EQ(ScrollDelta(layer), gfx::Vector2d()); @@ -1095,8 +1115,6 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, ScrollDeltaRepeatedScrolls) { gfx::PointF scroll_offset(20, 30); - gfx::Vector2dF scroll_delta(11, -15); - auto* root = SetupDefaultRootLayer(gfx::Size(110, 110)); root->SetHitTestable(true); CreateScrollNode(root, gfx::Size(10, 10)); @@ -1106,25 +1124,121 @@ .UpdateScrollOffsetBaseForTesting(root->element_id(), scroll_offset); UpdateDrawProperties(host_impl_->active_tree()); - std::unique_ptr<CompositorCommitData> commit_data; - + gfx::Vector2dF scroll_delta(11, -15); + std::unique_ptr<CompositorCommitData> commit_data1; root->ScrollBy(scroll_delta); - commit_data = host_impl_->ProcessCompositorDeltas(); - ASSERT_EQ(commit_data->scrolls.size(), 1u); + commit_data1 = host_impl_->ProcessCompositorDeltas(); + ASSERT_EQ(commit_data1->scrolls.size(), 1u); EXPECT_TRUE( - ScrollInfoContains(*commit_data, root->element_id(), scroll_delta)); + ScrollInfoContains(*commit_data1, root->element_id(), scroll_delta)); + + std::unique_ptr<CompositorCommitData> commit_data2; + gfx::Vector2dF scroll_delta2(-5, 27); + root->ScrollBy(scroll_delta2); + commit_data2 = host_impl_->ProcessCompositorDeltas(); + ASSERT_EQ(commit_data2->scrolls.size(), 1u); + EXPECT_TRUE( + ScrollInfoContains(*commit_data2, root->element_id(), scroll_delta2)); + + // Simulate first commit by pushing base scroll offsets to pending tree + PushScrollOffsetsToPendingTree( + {{root->element_id(), gfx::PointAtOffsetFromOrigin(scroll_delta)}}); + EXPECT_EQ(host_impl_->sync_tree() + ->property_trees() + ->scroll_tree() + .GetScrollOffsetDeltaForTesting(root->element_id()), + scroll_delta2); + + // Simulate second commit by pushing base scroll offsets to pending tree + PushScrollOffsetsToPendingTree( + {{root->element_id(), gfx::PointAtOffsetFromOrigin(scroll_delta2)}}); + EXPECT_EQ(host_impl_->sync_tree() + ->property_trees() + ->scroll_tree() + .GetScrollOffsetDeltaForTesting(root->element_id()), + gfx::Vector2dF(0, 0)); +} + +TEST_P(ScrollUnifiedLayerTreeHostImplTest, SyncedScrollAbortedCommit) { + LayerTreeSettings settings = DefaultSettings(); + settings.commit_to_active_tree = false; + CreateHostImpl(settings, CreateLayerTreeFrameSink()); + CreatePendingTree(); + gfx::PointF scroll_offset(20, 30); + auto* root = SetupDefaultRootLayer(gfx::Size(110, 110)); + auto& scroll_tree = + root->layer_tree_impl()->property_trees()->scroll_tree_mutable(); + root->SetHitTestable(true); + + // SyncedProperty should be created on the pending tree and then pushed to the + // active tree, to avoid bifurcation. Simulate commit by pushing base scroll + // offsets to pending tree. + PushScrollOffsetsToPendingTree({{root->element_id(), gfx::PointF(0, 0)}}); + host_impl_->active_tree() + ->property_trees() + ->scroll_tree_mutable() + .PushScrollUpdatesFromPendingTree( + host_impl_->pending_tree()->property_trees(), + host_impl_->active_tree()); + + CreateScrollNode(root, gfx::Size(10, 10)); + auto* synced_scroll = scroll_tree.GetSyncedScrollOffset(root->element_id()); + ASSERT_TRUE(synced_scroll); + scroll_tree.UpdateScrollOffsetBaseForTesting(root->element_id(), + scroll_offset); + UpdateDrawProperties(host_impl_->active_tree()); + + gfx::Vector2dF scroll_delta(11, -15); + root->ScrollBy(scroll_delta); + EXPECT_EQ(scroll_delta, synced_scroll->UnsentDelta()); + host_impl_->ProcessCompositorDeltas(); + EXPECT_TRUE(synced_scroll->reflected_delta_in_main_tree().has_value()); + EXPECT_FALSE(synced_scroll->next_reflected_delta_in_main_tree().has_value()); + EXPECT_EQ(scroll_delta, + synced_scroll->reflected_delta_in_main_tree().value()); gfx::Vector2dF scroll_delta2(-5, 27); root->ScrollBy(scroll_delta2); - commit_data = host_impl_->ProcessCompositorDeltas(); - ASSERT_EQ(commit_data->scrolls.size(), 1u); - EXPECT_TRUE(ScrollInfoContains(*commit_data, root->element_id(), - scroll_delta + scroll_delta2)); + EXPECT_EQ(scroll_delta2, synced_scroll->UnsentDelta()); + host_impl_->ProcessCompositorDeltas(); + EXPECT_TRUE(synced_scroll->reflected_delta_in_main_tree().has_value()); + EXPECT_TRUE(synced_scroll->next_reflected_delta_in_main_tree().has_value()); + EXPECT_EQ(scroll_delta, + synced_scroll->reflected_delta_in_main_tree().value()); + EXPECT_EQ(scroll_delta2, + synced_scroll->next_reflected_delta_in_main_tree().value()); - root->ScrollBy(gfx::Vector2d()); - commit_data = host_impl_->ProcessCompositorDeltas(); - EXPECT_TRUE(ScrollInfoContains(*commit_data, root->element_id(), - scroll_delta + scroll_delta2)); + // Simulate aborting the second main frame. Scroll deltas applied by the + // second frame should be combined with delta from first frame. + root->layer_tree_impl()->ApplySentScrollAndScaleDeltasFromAbortedCommit( + /*main_frame_applied_deltas=*/true); + EXPECT_TRUE(synced_scroll->reflected_delta_in_main_tree().has_value()); + EXPECT_FALSE(synced_scroll->next_reflected_delta_in_main_tree().has_value()); + EXPECT_EQ(scroll_delta + scroll_delta2, + synced_scroll->reflected_delta_in_main_tree().value()); + + // Send a third main frame, pipelined behind the first. + gfx::Vector2dF scroll_delta3(-2, -13); + root->ScrollBy(scroll_delta3); + EXPECT_EQ(scroll_delta3, synced_scroll->UnsentDelta()); + host_impl_->ProcessCompositorDeltas(); + EXPECT_TRUE(synced_scroll->reflected_delta_in_main_tree().has_value()); + EXPECT_TRUE(synced_scroll->next_reflected_delta_in_main_tree().has_value()); + EXPECT_EQ(scroll_delta + scroll_delta2, + synced_scroll->reflected_delta_in_main_tree().value()); + EXPECT_EQ(scroll_delta3, + synced_scroll->next_reflected_delta_in_main_tree().value()); + + // Simulate commit of the first frame + PushScrollOffsetsToPendingTree( + {{root->element_id(), scroll_offset + scroll_delta + scroll_delta2}}); + EXPECT_EQ(scroll_offset + scroll_delta + scroll_delta2, + synced_scroll->PendingBase()); + EXPECT_EQ(scroll_delta3, synced_scroll->PendingDelta()); + EXPECT_TRUE(synced_scroll->reflected_delta_in_main_tree().has_value()); + EXPECT_FALSE(synced_scroll->next_reflected_delta_in_main_tree().has_value()); + EXPECT_EQ(scroll_delta3, + synced_scroll->reflected_delta_in_main_tree().value()); } TEST_F(CommitToPendingTreeLayerTreeHostImplTest, @@ -3602,6 +3716,7 @@ EXPECT_EQ(commit_data->page_scale_delta, page_scale_delta); EXPECT_EQ(gfx::PointF(75.0, 75.0), MaxScrollOffset(scroll_layer)); + ClearMainThreadDeltasForTesting(host_impl_.get()); } // Scrolling after a pinch gesture should always be in local space. The @@ -4193,6 +4308,7 @@ std::unique_ptr<CompositorCommitData> commit_data = host_impl_->ProcessCompositorDeltas(); EXPECT_EQ(commit_data->page_scale_delta, page_scale_delta); + ClearMainThreadDeltasForTesting(host_impl_.get()); } // Zoom-in clamping @@ -4216,6 +4332,7 @@ std::unique_ptr<CompositorCommitData> commit_data = host_impl_->ProcessCompositorDeltas(); EXPECT_EQ(commit_data->page_scale_delta, max_page_scale); + ClearMainThreadDeltasForTesting(host_impl_.get()); } // Zoom-out clamping @@ -4227,6 +4344,7 @@ ->property_trees() ->scroll_tree_mutable() .CollectScrollDeltasForTesting(); + ClearMainThreadDeltasForTesting(host_impl_.get()); scroll_layer->layer_tree_impl() ->property_trees() ->scroll_tree_mutable() @@ -4249,6 +4367,7 @@ EXPECT_EQ(commit_data->page_scale_delta, min_page_scale); EXPECT_TRUE(commit_data->scrolls.empty()); + ClearMainThreadDeltasForTesting(host_impl_.get()); } // Two-finger panning should not happen based on pinch events only @@ -4260,6 +4379,7 @@ ->property_trees() ->scroll_tree_mutable() .CollectScrollDeltasForTesting(); + ClearMainThreadDeltasForTesting(host_impl_.get()); scroll_layer->layer_tree_impl() ->property_trees() ->scroll_tree_mutable() @@ -4283,6 +4403,7 @@ host_impl_->ProcessCompositorDeltas(); EXPECT_EQ(commit_data->page_scale_delta, page_scale_delta); EXPECT_TRUE(commit_data->scrolls.empty()); + ClearMainThreadDeltasForTesting(host_impl_.get()); } // Two-finger panning should work with interleaved scroll events @@ -4294,6 +4415,7 @@ ->property_trees() ->scroll_tree_mutable() .CollectScrollDeltasForTesting(); + ClearMainThreadDeltasForTesting(host_impl_.get()); scroll_layer->layer_tree_impl() ->property_trees() ->scroll_tree_mutable() @@ -4322,6 +4444,7 @@ EXPECT_EQ(commit_data->page_scale_delta, page_scale_delta); EXPECT_TRUE(ScrollInfoContains(*commit_data, scroll_layer->element_id(), gfx::Vector2dF(-10, -10))); + ClearMainThreadDeltasForTesting(host_impl_.get()); } // Two-finger panning should work when starting fully zoomed out. @@ -4332,6 +4455,7 @@ ->property_trees() ->scroll_tree_mutable() .CollectScrollDeltasForTesting(); + ClearMainThreadDeltasForTesting(host_impl_.get()); scroll_layer->layer_tree_impl() ->property_trees() ->scroll_tree_mutable() @@ -4383,6 +4507,7 @@ ->property_trees() ->scroll_tree_mutable() .CollectScrollDeltasForTesting(); + ClearMainThreadDeltasForTesting(host_impl_.get()); scroll_layer->layer_tree_impl() ->property_trees() ->scroll_tree_mutable() @@ -4435,6 +4560,7 @@ ->property_trees() ->scroll_tree_mutable() .CollectScrollDeltasForTesting(); + ClearMainThreadDeltasForTesting(host_impl_.get()); scroll_layer->layer_tree_impl() ->property_trees() ->scroll_tree_mutable() @@ -4530,6 +4656,7 @@ std::unique_ptr<CompositorCommitData> commit_data = host_impl_->ProcessCompositorDeltas(); EXPECT_EQ(commit_data->page_scale_delta, 1); + ClearMainThreadDeltasForTesting(host_impl_.get()); } start_time += base::Seconds(10); @@ -4661,6 +4788,7 @@ EXPECT_EQ(commit_data->page_scale_delta, 2); EXPECT_TRUE(ScrollInfoContains(*commit_data, scroll_layer->element_id(), gfx::Vector2dF(-50, -50))); + ClearMainThreadDeltasForTesting(host_impl_.get()); } start_time += base::Seconds(10); @@ -8424,16 +8552,19 @@ UpdateDrawProperties(host_impl_->active_tree()); host_impl_->active_tree()->DidBecomeActive(); + gfx::PointF grand_child_base(0, 2); + gfx::Vector2dF grand_child_delta; grand_child_layer->layer_tree_impl() ->property_trees() ->scroll_tree_mutable() .UpdateScrollOffsetBaseForTesting(grand_child_layer->element_id(), - gfx::PointF(0, 2)); + grand_child_base); + gfx::PointF child_base(0, 3); + gfx::Vector2dF child_delta; child_layer->layer_tree_impl() ->property_trees() ->scroll_tree_mutable() - .UpdateScrollOffsetBaseForTesting(child_layer->element_id(), - gfx::PointF(0, 3)); + .UpdateScrollOffsetBaseForTesting(child_layer->element_id(), child_base); DrawFrame(); { @@ -8455,13 +8586,20 @@ host_impl_->ProcessCompositorDeltas(); // The grand child should have scrolled up to its limit. + grand_child_delta = gfx::Vector2dF(0, -2); EXPECT_TRUE(ScrollInfoContains(*commit_data.get(), grand_child_layer->element_id(), - gfx::Vector2dF(0, -2))); + grand_child_delta)); // The child should not have scrolled. ExpectNone(*commit_data.get(), child_layer->element_id()); + grand_child_base += grand_child_delta; + child_base += child_delta; + PushScrollOffsetsToPendingTree( + {{child_layer->element_id(), child_base}, + {grand_child_layer->element_id(), grand_child_base}}); + // The next time we scroll we should only scroll the parent. scroll_delta = gfx::Vector2d(0, -3); EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, @@ -8481,16 +8619,23 @@ child_layer->scroll_tree_index()); GetInputHandler().ScrollEnd(); + ClearMainThreadDeltasForTesting(host_impl_.get()); commit_data = host_impl_->ProcessCompositorDeltas(); // The child should have scrolled up to its limit. - EXPECT_TRUE(ScrollInfoContains( - *commit_data.get(), child_layer->element_id(), gfx::Vector2dF(0, -3))); + child_delta = gfx::Vector2dF(0, -3); + EXPECT_TRUE(ScrollInfoContains(*commit_data.get(), + child_layer->element_id(), child_delta)); // The grand child should not have scrolled. - EXPECT_TRUE(ScrollInfoContains(*commit_data.get(), - grand_child_layer->element_id(), - gfx::Vector2dF(0, -2))); + grand_child_delta = gfx::Vector2dF(); + ExpectNone(*commit_data.get(), grand_child_layer->element_id()); + + child_base += child_delta; + grand_child_base += grand_child_delta; + PushScrollOffsetsToPendingTree( + {{grand_child_layer->element_id(), grand_child_base}, + {child_layer->element_id(), child_base}}); // After scrolling the parent, another scroll on the opposite direction // should still scroll the child. @@ -8512,16 +8657,24 @@ grand_child_layer->scroll_tree_index()); GetInputHandler().ScrollEnd(); + ClearMainThreadDeltasForTesting(host_impl_.get()); commit_data = host_impl_->ProcessCompositorDeltas(); // The grand child should have scrolled. + grand_child_delta = gfx::Vector2dF(0, 7); EXPECT_TRUE(ScrollInfoContains(*commit_data.get(), grand_child_layer->element_id(), - gfx::Vector2dF(0, 5))); + grand_child_delta)); // The child should not have scrolled. - EXPECT_TRUE(ScrollInfoContains( - *commit_data.get(), child_layer->element_id(), gfx::Vector2dF(0, -3))); + child_delta = gfx::Vector2dF(); + ExpectNone(*commit_data.get(), child_layer->element_id()); + + grand_child_base += grand_child_delta; + child_base += child_delta; + PushScrollOffsetsToPendingTree( + {{grand_child_layer->element_id(), grand_child_base}, + {child_layer->element_id(), child_base}}); // Scrolling should be adjusted from viewport space. host_impl_->active_tree()->PushPageScaleFromMainThread(2, 2, 2); @@ -8543,12 +8696,13 @@ .get()); GetInputHandler().ScrollEnd(); + ClearMainThreadDeltasForTesting(host_impl_.get()); commit_data = host_impl_->ProcessCompositorDeltas(); - // Should have scrolled by half the amount in layer space (5 - 2/2) + // Should have scrolled by half the amount in layer space (-2/2) EXPECT_TRUE(ScrollInfoContains(*commit_data.get(), grand_child_layer->element_id(), - gfx::Vector2dF(0, 4))); + gfx::Vector2dF(0, -1))); } } @@ -8691,6 +8845,10 @@ EXPECT_TRUE(ScrollInfoContains(*commit_data.get(), scroll_layer->element_id(), gfx::Vector2dF(0, gesture_scroll_delta.x()))); + // Push scrolls to pending tree + PushScrollOffsetsToPendingTree( + {{scroll_layer->element_id(), gfx::PointF(10, 0)}}); + // Reset and scroll down with the wheel. SetScrollOffsetDelta(scroll_layer, gfx::Vector2dF()); gfx::Vector2dF wheel_scroll_delta(0, 10); @@ -8773,6 +8931,10 @@ // The root scroll layer should not have scrolled, because the input delta // was close to the layer's axis of movement. EXPECT_EQ(commit_data->scrolls.size(), 1u); + + PushScrollOffsetsToPendingTree( + {{child_scroll_id, + gfx::PointAtOffsetFromOrigin(expected_scroll_delta)}}); } { // Now reset and scroll the same amount horizontally. @@ -8804,6 +8966,10 @@ // The root scroll layer shouldn't have scrolled. ExpectNone(*commit_data.get(), scroll_layer->element_id()); + + PushScrollOffsetsToPendingTree( + {{child_scroll_id, + gfx::PointAtOffsetFromOrigin(expected_scroll_delta)}}); } } @@ -8883,6 +9049,11 @@ // The root scroll layer should not have scrolled, because the input delta // was close to the layer's axis of movement. EXPECT_EQ(commit_data->scrolls.size(), 1u); + + PushScrollOffsetsToPendingTree( + {{child->element_id(), + gfx::PointAtOffsetFromOrigin(expected_scroll_deltas[i])}}); + ClearMainThreadDeltasForTesting(host_impl_.get()); } } @@ -8918,6 +9089,9 @@ host_impl_->ProcessCompositorDeltas(); EXPECT_TRUE(ScrollInfoContains(*commit_data.get(), scroll_layer->element_id(), gfx::Vector2dF(0, scroll_delta.y() / scale))); + PushScrollOffsetsToPendingTree( + {{scroll_layer->element_id(), gfx::PointAtOffsetFromOrigin(gfx::Vector2dF( + 0, scroll_delta.y() / scale))}}); // Reset and scroll down with the wheel. SetScrollOffsetDelta(scroll_layer, gfx::Vector2dF());
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc index dfd7e261..8f8b9293 100644 --- a/cc/trees/layer_tree_impl.cc +++ b/cc/trees/layer_tree_impl.cc
@@ -1483,19 +1483,21 @@ gfx::Rect(root_scroll_node->bounds)); } -void LayerTreeImpl::ApplySentScrollAndScaleDeltasFromAbortedCommit() { +void LayerTreeImpl::ApplySentScrollAndScaleDeltasFromAbortedCommit( + bool main_frame_applied_deltas) { DCHECK(IsActiveTree()); - page_scale_factor()->AbortCommit(); - top_controls_shown_ratio()->AbortCommit(); - elastic_overscroll()->AbortCommit(); + page_scale_factor()->AbortCommit(main_frame_applied_deltas); + top_controls_shown_ratio()->AbortCommit(main_frame_applied_deltas); + bottom_controls_shown_ratio()->AbortCommit(main_frame_applied_deltas); + elastic_overscroll()->AbortCommit(main_frame_applied_deltas); if (layer_list_.empty()) return; property_trees() ->scroll_tree_mutable() - .ApplySentScrollDeltasFromAbortedCommit(); + .ApplySentScrollDeltasFromAbortedCommit(main_frame_applied_deltas); } void LayerTreeImpl::SetViewportPropertyIds(const ViewportPropertyIds& ids) {
diff --git a/cc/trees/layer_tree_impl.h b/cc/trees/layer_tree_impl.h index c4602129..f1d2b0b 100644 --- a/cc/trees/layer_tree_impl.h +++ b/cc/trees/layer_tree_impl.h
@@ -360,7 +360,8 @@ void SetCurrentlyScrollingNode(const ScrollNode* node); void ClearCurrentlyScrollingNode(); - void ApplySentScrollAndScaleDeltasFromAbortedCommit(); + void ApplySentScrollAndScaleDeltasFromAbortedCommit( + bool main_frame_applied_deltas); SkColor4f background_color() const { return background_color_; } void set_background_color(SkColor4f color) { background_color_ = color; }
diff --git a/cc/trees/property_tree.cc b/cc/trees/property_tree.cc index d41648f5..b85b4b5 100644 --- a/cc/trees/property_tree.cc +++ b/cc/trees/property_tree.cc
@@ -1704,10 +1704,15 @@ for (auto map_entry = synced_scroll_offset_map_.begin(); map_entry != synced_scroll_offset_map_.end();) { ElementId id = map_entry->first; - if (main_scroll_offset_map.find(id) == main_scroll_offset_map.end()) + if (main_scroll_offset_map.find(id) == main_scroll_offset_map.end()) { + // This SyncedScrollOffset might still be used to send a delta from the + // active tree to the main thread, so we need to clear out the delta that + // was sent to the main thread for this commit. + map_entry->second->PushMainToPending(map_entry->second->Current(true)); map_entry = synced_scroll_offset_map_.erase(map_entry); - else + } else { map_entry++; + } } for (auto map_entry : main_scroll_offset_map) { @@ -1763,10 +1768,11 @@ } } -void ScrollTree::ApplySentScrollDeltasFromAbortedCommit() { +void ScrollTree::ApplySentScrollDeltasFromAbortedCommit( + bool main_frame_applied_deltas) { DCHECK(property_trees()->is_active()); for (auto& map_entry : synced_scroll_offset_map_) - map_entry.second->AbortCommit(); + map_entry.second->AbortCommit(main_frame_applied_deltas); } void ScrollTree::SetBaseScrollOffset(ElementId id,
diff --git a/cc/trees/property_tree.h b/cc/trees/property_tree.h index 7837efc..6c05ffe 100644 --- a/cc/trees/property_tree.h +++ b/cc/trees/property_tree.h
@@ -538,7 +538,7 @@ // Applies deltas sent in the previous main frame onto the impl thread state. // Should only be called on the impl thread side PropertyTrees. - void ApplySentScrollDeltasFromAbortedCommit(); + void ApplySentScrollDeltasFromAbortedCommit(bool main_frame_applied_deltas); // Pushes scroll updates from the ScrollTree on the main thread onto the // impl thread associated state.
diff --git a/chrome/VERSION b/chrome/VERSION index 555ef04..84d75ff 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=106 MINOR=0 -BUILD=5210 +BUILD=5211 PATCH=0
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 9e45963..d9bd868 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
@@ -2116,13 +2116,13 @@ if (mTabReparentingControllerSupplier.get() != null && didChangeTabletMode()) { onScreenLayoutSizeChange(); } - // We only handle VR UI mode and UI mode night changes. Any other changes should follow - // the default behavior of recreating the activity. Note that if UI mode night changes, - // with or without other changes, we will still recreate() until we get a callback from - // the ChromeBaseAppCompatActivity#onNightModeStateChanged or the overridden method in + // For UI mode type, we only need to recreate for TELEVISION to update refresh rate. + // Note that if UI mode night changes, with or without other changes, we will + // still recreate() when we get a callback from the + // ChromeBaseAppCompatActivity#onNightModeStateChanged or the overridden method in // sub-classes if necessary. - if (didChangeNonVrUiMode(mConfig.uiMode, newConfig.uiMode) - && !didChangeUiModeNight(mConfig.uiMode, newConfig.uiMode)) { + if (didChangeUiModeType( + mConfig.uiMode, newConfig.uiMode, Configuration.UI_MODE_TYPE_TELEVISION)) { recreate(); return; } @@ -2145,18 +2145,14 @@ mConfig = newConfig; } - private static boolean didChangeNonVrUiMode(int oldMode, int newMode) { - if (oldMode == newMode) return false; - return isInVrUiMode(oldMode) == isInVrUiMode(newMode); + // Checks whether the given uiModeTypes were present on oldUiMode or newUiMode but not the + // other. + private static boolean didChangeUiModeType(int oldUiMode, int newUiMode, int uiModeType) { + return isInUiModeType(oldUiMode, uiModeType) != isInUiModeType(newUiMode, uiModeType); } - private static boolean isInVrUiMode(int uiMode) { - return (uiMode & Configuration.UI_MODE_TYPE_MASK) == Configuration.UI_MODE_TYPE_VR_HEADSET; - } - - private static boolean didChangeUiModeNight(int oldMode, int newMode) { - return (oldMode & Configuration.UI_MODE_NIGHT_MASK) - != (newMode & Configuration.UI_MODE_NIGHT_MASK); + private static boolean isInUiModeType(int uiMode, int uiModeType) { + return (uiMode & Configuration.UI_MODE_TYPE_MASK) == uiModeType; } /**
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 7bf7260..19b298b 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
@@ -103,6 +103,9 @@ private static final int MIGRATE_TO_CRITICAL_PERSISTED_TAB_DATA_DEFAULT_BATCH_SIZE = 5; private static final String MIGRATE_TO_CRITICAL_PERSISTED_TAB_DATA_BATCH_SIZE_PARAM = "migrate_to_critical_persisted_tab_data_batch_size"; + private static final String SAVE_CRITICAL_PERSISTED_TAB_DATA_NO_RESTORE = + "save_critical_persisted_tab_data_no_restore"; + private TabModelObserver mTabModelObserver; @IntDef({ActiveTabState.OTHER, ActiveTabState.NTP, ActiveTabState.EMPTY}) @@ -1359,7 +1362,8 @@ if (mDestroyed || isCancelled()) return; if (mStateSaved) { if (!mTab.isDestroyed()) TabStateAttributes.from(mTab).setIsTabStateDirty(false); - mTab.setIsTabSaveEnabled(isCriticalPersistedTabDataEnabled()); + mTab.setIsTabSaveEnabled(isCriticalPersistedTabDataEnabled() + || isCriticalPersistedTabDataSavingEnabled()); migrateSomeRemainingTabsToCriticalPersistedTabData(); } mSaveTabTask = null; @@ -1666,6 +1670,15 @@ return ChromeFeatureList.sCriticalPersistedTabData.isEnabled(); } + private static boolean isCriticalPersistedTabDataSavingEnabled() { + if (FeatureList.isInitialized()) { + return ChromeFeatureList.getFieldTrialParamByFeatureAsBoolean( + ChromeFeatureList.CRITICAL_PERSISTED_TAB_DATA, + SAVE_CRITICAL_PERSISTED_TAB_DATA_NO_RESTORE, false); + } + return false; + } + private class LoadTabTask extends AsyncTask<TabState> { private final TabRestoreDetails mTabToRestore; private TabState mTabState; @@ -1939,7 +1952,9 @@ } private void migrateSomeRemainingTabsToCriticalPersistedTabData() { - if (!isCriticalPersistedTabDataEnabled()) return; + if (!isCriticalPersistedTabDataEnabled() && !isCriticalPersistedTabDataSavingEnabled()) { + return; + } int numMigrated = 0; while (numMigrated < getMigrateToCriticalPersistedTabDataBatchSize() && !mTabsToMigrate.isEmpty()) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxPedalsRenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxPedalsRenderTest.java index bc5550d..438f399 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxPedalsRenderTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxPedalsRenderTest.java
@@ -130,6 +130,7 @@ @Test @MediumTest @Feature("RenderTest") + @DisabledTest(message = "crbug.com/1348691") public void testRunChromeSafetyCheckPedal() throws IOException, InterruptedException { List<AutocompleteMatch> suggestionsList = new ArrayList<>(); suggestionsList.add(
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp index 891e82bc..c52b1ab 100644 --- a/chrome/app/chromeos_strings.grdp +++ b/chrome/app/chromeos_strings.grdp
@@ -3318,6 +3318,21 @@ <message name="IDS_NETWORK_UI_REFRESH_TETHERING_CAPABILITIES_BUTTON_TEXT" desc="Text for button which, when pressed, refreshing the tethering capabilities."> Refresh Tethering Capabilities </message> + <message name="IDS_NETWORK_UI_TETHERING_STATUS_LABEL" desc="Title for the section for displaying and refreshing tethering status."> + Tethering Status: + </message> + <message name="IDS_NETWORK_UI_REFRESH_TETHERING_STATUS_BUTTON_TEXT" desc="Text for button which, when pressed, refresh the tethering status."> + Refresh Tethering Status + </message> + <message name="IDS_NETWORK_UI_TETHERING_CONFIG_LABEL" desc="Title for the section for displaying and refreshing tethering configuration."> + Tethering Configuration: + </message> + <message name="IDS_NETWORK_UI_REFRESH_TETHERING_CONFIG_BUTTON_TEXT" desc="Text for button which, when pressed, refresh the tethering configuration."> + Refresh Tethering Configuration + </message> + <message name="IDS_NETWORK_UI_SET_TETHERING_CONFIG_BUTTON_TEXT" desc="Text for button which, when pressed, set the tethering configuration."> + Set Tethering Configuration + </message> <message name="IDS_DEVICE_LOG_LINK_TEXT" desc="Message preceeding link to chrome://device-log"> To view network UI logs, see: <ph name="DEVICE_LOG_LINK"><a href="chrome://device-log">chrome://device-log</a></ph>
diff --git a/chrome/app/chromeos_strings_grdp/IDS_NETWORK_UI_REFRESH_TETHERING_CONFIG_BUTTON_TEXT.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_NETWORK_UI_REFRESH_TETHERING_CONFIG_BUTTON_TEXT.png.sha1 new file mode 100644 index 0000000..ec3b0a35 --- /dev/null +++ b/chrome/app/chromeos_strings_grdp/IDS_NETWORK_UI_REFRESH_TETHERING_CONFIG_BUTTON_TEXT.png.sha1
@@ -0,0 +1 @@ +359e626996b055b45dd8d7cd89b05c5a52ba2aef \ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_NETWORK_UI_REFRESH_TETHERING_STATUS_BUTTON_TEXT.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_NETWORK_UI_REFRESH_TETHERING_STATUS_BUTTON_TEXT.png.sha1 new file mode 100644 index 0000000..742ce6c --- /dev/null +++ b/chrome/app/chromeos_strings_grdp/IDS_NETWORK_UI_REFRESH_TETHERING_STATUS_BUTTON_TEXT.png.sha1
@@ -0,0 +1 @@ +2644a711af3e49965af1874691b3d1adfc3a3c98 \ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_NETWORK_UI_SET_TETHERING_CONFIG_BUTTON_TEXT.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_NETWORK_UI_SET_TETHERING_CONFIG_BUTTON_TEXT.png.sha1 new file mode 100644 index 0000000..b4cec5ff --- /dev/null +++ b/chrome/app/chromeos_strings_grdp/IDS_NETWORK_UI_SET_TETHERING_CONFIG_BUTTON_TEXT.png.sha1
@@ -0,0 +1 @@ +159653b32be20880d5394f881922a9c92f823351 \ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_NETWORK_UI_TETHERING_CONFIG_LABEL.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_NETWORK_UI_TETHERING_CONFIG_LABEL.png.sha1 new file mode 100644 index 0000000..c92987f --- /dev/null +++ b/chrome/app/chromeos_strings_grdp/IDS_NETWORK_UI_TETHERING_CONFIG_LABEL.png.sha1
@@ -0,0 +1 @@ +f390396c9b9a6ab0b6ddc8a56f54c3257dce521d \ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_NETWORK_UI_TETHERING_STATUS_LABEL.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_NETWORK_UI_TETHERING_STATUS_LABEL.png.sha1 new file mode 100644 index 0000000..8d500f42 --- /dev/null +++ b/chrome/app/chromeos_strings_grdp/IDS_NETWORK_UI_TETHERING_STATUS_LABEL.png.sha1
@@ -0,0 +1 @@ +d1474e1d457a8ede1115e766c1447d8eed111552 \ No newline at end of file
diff --git a/chrome/app/os_settings_search_tag_strings.grdp b/chrome/app/os_settings_search_tag_strings.grdp index 456717b..ddb06a1 100644 --- a/chrome/app/os_settings_search_tag_strings.grdp +++ b/chrome/app/os_settings_search_tag_strings.grdp
@@ -229,6 +229,9 @@ <message name="IDS_OS_SETTINGS_TAG_FAST_PAIR_TURN_OFF_ALT1" desc="Text for search result item which, when clicked, navigates the user to Bluetooth settings, with a toggle to turn off Fast Pair. Alternate phrase for: 'Turn off Fast Pair'"> Disable Fast Pair </message> + <message name="IDS_OS_SETTINGS_TAG_FAST_PAIR_SAVED_DEVICES" desc="Text for search result item which, when clicked, navigates the user to Bluetooth settings Saved Devices subpage"> + Saved devices + </message> <!-- MultiDevice section. --> <message name="IDS_OS_SETTINGS_TAG_MULTIDEVICE" desc="Text for search result item which, when clicked, navigates the user to multi-device settings (connects Android phone to Chromebook). Alternate phrase for: 'Phone'">
diff --git a/chrome/app/os_settings_search_tag_strings_grdp/IDS_OS_SETTINGS_TAG_FAST_PAIR_SAVED_DEVICES.png.sha1 b/chrome/app/os_settings_search_tag_strings_grdp/IDS_OS_SETTINGS_TAG_FAST_PAIR_SAVED_DEVICES.png.sha1 new file mode 100644 index 0000000..214fc25a --- /dev/null +++ b/chrome/app/os_settings_search_tag_strings_grdp/IDS_OS_SETTINGS_TAG_FAST_PAIR_SAVED_DEVICES.png.sha1
@@ -0,0 +1 @@ +1f28e8cf4cfbbe5418c0a4a783636654d35d3029 \ No newline at end of file
diff --git a/chrome/app/os_settings_strings.grdp b/chrome/app/os_settings_strings.grdp index 523a6d2..928a9a6 100644 --- a/chrome/app/os_settings_strings.grdp +++ b/chrome/app/os_settings_strings.grdp
@@ -63,6 +63,9 @@ <message name="IDS_SETTINGS_ABOUT_PAGE_RELAUNCH_AND_POWERWASH" desc="The label for the button that relaunches and powerwashes the browser once update is complete"> Restart and reset </message> + <message name="IDS_SETTINGS_ABOUT_PAGE_RELAUNCH_AND_AUTO_UPDATE" desc="The label for the button that relaunches and enables automatic updates"> + Restart and get automatic updates + </message> <message name="IDS_SETTINGS_UPGRADE_SUCCESSFUL_RELAUNCH" desc="Status label: Successfully updated ChromiumOS/ChromeOS"> Nearly up to date! Restart your device to finish updating. </message>
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_ABOUT_PAGE_RELAUNCH_AND_AUTO_UPDATE.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_ABOUT_PAGE_RELAUNCH_AND_AUTO_UPDATE.png.sha1 new file mode 100644 index 0000000..f33f926e --- /dev/null +++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_ABOUT_PAGE_RELAUNCH_AND_AUTO_UPDATE.png.sha1
@@ -0,0 +1 @@ +b3fc98bbde3af98476650abb9416c1ea6e1a5d75 \ No newline at end of file
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp index 2e3a106..6f1c991 100644 --- a/chrome/app/settings_strings.grdp +++ b/chrome/app/settings_strings.grdp
@@ -1287,8 +1287,8 @@ <message name="IDS_SETTINGS_LANGUAGES_EXPAND_ACCESSIBILITY_LABEL" desc="Label for the button that toggles showing the language options. Only visible by screen reader software."> Show language options </message> - <message name="IDS_SETTINGS_LANGUAGES_BROWSER_LANGUAGES_LIST_ORDERING_INSTRUCTIONS" desc="Explanatory message about ordering the list of languages."> - Order languages based on your preference + <message name="IDS_SETTINGS_LANGUAGES_PREFERRED_LANGUAGES_DESC" desc="Explanatory message about the list of preferred languages."> + Websites will show content in your preferred languages, when possible </message> <message name="IDS_SETTINGS_LANGUAGES_OFFER_TO_TRANSLATE_IN_THIS_LANGUAGE" desc="The label for a checkbox which indicates whether or not pages in this language should be translated by default."> Offer to translate pages in this language
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_LANGUAGES_PREFERRED_LANGUAGES_DESC.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_LANGUAGES_PREFERRED_LANGUAGES_DESC.png.sha1 new file mode 100644 index 0000000..5b6c75e --- /dev/null +++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_LANGUAGES_PREFERRED_LANGUAGES_DESC.png.sha1
@@ -0,0 +1 @@ +98ffb44cda9e1e09e6f5a94faca77a641d7cdf09 \ No newline at end of file
diff --git a/chrome/browser/accessibility/ax_screen_ai_annotator.cc b/chrome/browser/accessibility/ax_screen_ai_annotator.cc index 22085df..bc458ef 100644 --- a/chrome/browser/accessibility/ax_screen_ai_annotator.cc +++ b/chrome/browser/accessibility/ax_screen_ai_annotator.cc
@@ -35,11 +35,25 @@ if (!native_view) return; +// TODO(https://crbug.com/1278249): Add UMA for screenshot timing to ensure +// the sync method is not blocking the browser process. +#if BUILDFLAG(IS_MAC) + gfx::Image snapshot; + if (!ui::GrabViewSnapshot(native_view, gfx::Rect(web_contents->GetSize()), + &snapshot)) { + VLOG(1) << "AxScreenAIAnnotator could not grab snapshot."; + return; + } + + AXScreenAIAnnotator::OnScreenshotReceived( + web_contents->GetPrimaryMainFrame()->GetAXTreeID(), std::move(snapshot)); +#else ui::GrabViewSnapshotAsync( native_view, gfx::Rect(web_contents->GetSize()), base::BindOnce(&AXScreenAIAnnotator::OnScreenshotReceived, weak_ptr_factory_.GetWeakPtr(), web_contents->GetPrimaryMainFrame()->GetAXTreeID())); +#endif } void AXScreenAIAnnotator::OnScreenshotReceived(const ui::AXTreeID& ax_tree_id,
diff --git a/chrome/browser/accessibility/ax_screen_ai_annotator.h b/chrome/browser/accessibility/ax_screen_ai_annotator.h index fe64d751..ef179ddd 100644 --- a/chrome/browser/accessibility/ax_screen_ai_annotator.h +++ b/chrome/browser/accessibility/ax_screen_ai_annotator.h
@@ -22,7 +22,7 @@ class AXScreenAIAnnotator { public: explicit AXScreenAIAnnotator(Browser* browser); - ~AXScreenAIAnnotator(); + virtual ~AXScreenAIAnnotator(); AXScreenAIAnnotator(const AXScreenAIAnnotator&) = delete; AXScreenAIAnnotator& operator=(const AXScreenAIAnnotator&) = delete; @@ -34,8 +34,8 @@ // Receives an screenshot and sends it to ScreenAI library for processing. // |ax_tree_id| represents the accessibility tree that is associated with the // snapshot at the time of triggering the request. - void OnScreenshotReceived(const ui::AXTreeID& ax_tree_id, - gfx::Image snapshot); + virtual void OnScreenshotReceived(const ui::AXTreeID& ax_tree_id, + gfx::Image snapshot); // Receives the annotations from ScreenAI service. |ax_tree_id| is the id of // the accessibility tree associated with the snapshot that was sent to
diff --git a/chrome/browser/accessibility/screen_ai_service_browsertest.cc b/chrome/browser/accessibility/screen_ai_service_browsertest.cc new file mode 100644 index 0000000..f5e840575 --- /dev/null +++ b/chrome/browser/accessibility/screen_ai_service_browsertest.cc
@@ -0,0 +1,61 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/accessibility/ax_screen_ai_annotator.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "content/public/test/browser_test.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/image/image.h" + +namespace screen_ai { + +namespace { + +class MockAXScreenAIAnnotator : public AXScreenAIAnnotator { + public: + explicit MockAXScreenAIAnnotator(Browser* browser) + : AXScreenAIAnnotator(browser) {} + MOCK_METHOD(void, + OnScreenshotReceived, + (const ui::AXTreeID& ax_tree_id, gfx::Image snapshot), + (override)); +}; + +} // namespace + +using ScreenAIServiceTest = InProcessBrowserTest; + +// https://crbug.com/1348280: Creating AXScreenAIAnnotator triggers the sandbox +// on Mac11 which is not implemented yet. +#if BUILDFLAG(IS_MAC) +#define MAYBE_ScreenshotTest DISABLED_ScreenshotTest +#else +#define MAYBE_ScreenshotTest ScreenshotTest +#endif +IN_PROC_BROWSER_TEST_F(ScreenAIServiceTest, MAYBE_ScreenshotTest) { + MockAXScreenAIAnnotator* annotator = new MockAXScreenAIAnnotator(browser()); + browser()->SetScreenAIAnnotatorForTesting( + std::unique_ptr<AXScreenAIAnnotator>(annotator)); + + base::RunLoop run_loop; + + EXPECT_CALL(*annotator, OnScreenshotReceived) + .WillOnce( + [&run_loop](const ui::AXTreeID& ax_tree_id, gfx::Image snapshot) { + EXPECT_FALSE(snapshot.IsEmpty()); + EXPECT_GT(snapshot.Size().width(), 0); + EXPECT_GT(snapshot.Size().height(), 0); + run_loop.Quit(); + }); + + browser()->RunScreenAIAnnotator(); + run_loop.Run(); + + // TODO(https://crbug.com/1278249): Expect OnAnnotationReceived once library + // binary is available for test. +} + +} // namespace screen_ai
diff --git a/chrome/browser/apps/app_service/publishers/extension_apps_chromeos.h b/chrome/browser/apps/app_service/publishers/extension_apps_chromeos.h index 333e1a0..2e83ec8 100644 --- a/chrome/browser/apps/app_service/publishers/extension_apps_chromeos.h +++ b/chrome/browser/apps/app_service/publishers/extension_apps_chromeos.h
@@ -51,8 +51,6 @@ // there are 2 ExtensionAppsChromeOs publishers for browser extensions and // Chrome apps(including hosted apps) separately. // -// In the future, desktop PWAs will be migrated to a new system. -// // See components/services/app_service/README.md. class ExtensionAppsChromeOs : public ExtensionAppsBase, public extensions::AppWindowRegistry::Observer,
diff --git a/chrome/browser/ash/login/lock/fingerprint_unlock_browsertest.cc b/chrome/browser/ash/login/lock/fingerprint_unlock_browsertest.cc index 4d19119..bebf6b7 100644 --- a/chrome/browser/ash/login/lock/fingerprint_unlock_browsertest.cc +++ b/chrome/browser/ash/login/lock/fingerprint_unlock_browsertest.cc
@@ -429,6 +429,8 @@ "Fingerprint.Unlock.AuthSuccessful"; constexpr char kFingerprintAttemptsCountBeforeSuccessHistogramName[] = "Fingerprint.Unlock.AttemptsCountBeforeSuccess"; +constexpr char kFingerprintRecentAttemptsCountBeforeSuccessHistogramName[] = + "Fingerprint.Unlock.RecentAttemptsCountBeforeSuccess"; constexpr char kFeatureUsageMetric[] = "ChromeOS.FeatureUsage.Fingerprint"; // Verifies that fingerprint auth success is recorded correctly. @@ -455,6 +457,8 @@ static_cast<int>(quick_unlock::FingerprintUnlockResult::kSuccess), 1); histogram_tester.ExpectTotalCount( kFingerprintAttemptsCountBeforeSuccessHistogramName, 1); + histogram_tester.ExpectTotalCount( + kFingerprintRecentAttemptsCountBeforeSuccessHistogramName, 1); histogram_tester.ExpectBucketCount( kFeatureUsageMetric, static_cast<int>(
diff --git a/chrome/browser/ash/login/lock/screen_locker.cc b/chrome/browser/ash/login/lock/screen_locker.cc index c1565b41..36b07cc 100644 --- a/chrome/browser/ash/login/lock/screen_locker.cc +++ b/chrome/browser/ash/login/lock/screen_locker.cc
@@ -27,6 +27,7 @@ #include "base/task/current_thread.h" #include "base/task/single_thread_task_runner.h" #include "base/threading/thread_task_runner_handle.h" +#include "base/time/time.h" #include "chrome/browser/ash/accessibility/accessibility_manager.h" #include "chrome/browser/ash/authpolicy/authpolicy_helper.h" #include "chrome/browser/ash/login/easy_unlock/easy_unlock_service.h" @@ -930,7 +931,8 @@ if (quick_unlock_storage && quick_unlock_storage->IsFingerprintAuthenticationAvailable( quick_unlock::Purpose::kUnlock)) { - quick_unlock_storage->fingerprint_storage()->AddUnlockAttempt(); + quick_unlock_storage->fingerprint_storage()->AddUnlockAttempt( + base::TimeTicks::Now()); if (quick_unlock_storage->fingerprint_storage()->ExceededUnlockAttempts()) { VLOG(1) << "Fingerprint unlock is disabled because it reached maximum" << " unlock attempt.";
diff --git a/chrome/browser/ash/login/quick_unlock/fingerprint_storage.cc b/chrome/browser/ash/login/quick_unlock/fingerprint_storage.cc index 93aa06c..37c2b439 100644 --- a/chrome/browser/ash/login/quick_unlock/fingerprint_storage.cc +++ b/chrome/browser/ash/login/quick_unlock/fingerprint_storage.cc
@@ -7,6 +7,7 @@ #include "ash/constants/ash_pref_names.h" #include "base/metrics/histogram_functions.h" +#include "base/time/time.h" #include "chrome/browser/ash/login/quick_unlock/quick_unlock_utils.h" #include "chrome/browser/ash/profiles/profile_helper.h" #include "chrome/browser/profiles/profile.h" @@ -88,6 +89,9 @@ if (success) { base::UmaHistogramCounts100("Fingerprint.Unlock.AttemptsCountBeforeSuccess", unlock_attempt_count()); + base::UmaHistogramCounts100( + "Fingerprint.Unlock.RecentAttemptsCountBeforeSuccess", + GetRecentUnlockAttemptCount(base::TimeTicks::Now())); } feature_usage_metrics_service_->RecordUsage(success); } @@ -102,18 +106,35 @@ prefs::kQuickUnlockFingerprintRecord) != 0; } -void FingerprintStorage::AddUnlockAttempt() { +void FingerprintStorage::AddUnlockAttempt(base::TimeTicks timestamp) { + DCHECK_GE(timestamp, last_unlock_attempt_timestamp_); + ++unlock_attempt_count_; + if (timestamp - last_unlock_attempt_timestamp_ < kRecentUnlockAttemptsDelta) + ++recent_unlock_attempt_count_; + else + recent_unlock_attempt_count_ = 1; + last_unlock_attempt_timestamp_ = timestamp; } void FingerprintStorage::ResetUnlockAttemptCount() { unlock_attempt_count_ = 0; + recent_unlock_attempt_count_ = 0; } bool FingerprintStorage::ExceededUnlockAttempts() const { return unlock_attempt_count() >= kMaximumUnlockAttempts; } +int FingerprintStorage::GetRecentUnlockAttemptCount(base::TimeTicks timestamp) { + DCHECK_GE(timestamp, last_unlock_attempt_timestamp_); + + if (timestamp - last_unlock_attempt_timestamp_ < kRecentUnlockAttemptsDelta) + return recent_unlock_attempt_count_; + else + return 0; +} + void FingerprintStorage::OnRestarted() { GetRecordsForUser(); }
diff --git a/chrome/browser/ash/login/quick_unlock/fingerprint_storage.h b/chrome/browser/ash/login/quick_unlock/fingerprint_storage.h index 17fc893..059feaf 100644 --- a/chrome/browser/ash/login/quick_unlock/fingerprint_storage.h +++ b/chrome/browser/ash/login/quick_unlock/fingerprint_storage.h
@@ -39,6 +39,8 @@ public device::mojom::FingerprintObserver { public: static const int kMaximumUnlockAttempts = 5; + static constexpr base::TimeDelta kRecentUnlockAttemptsDelta = + base::Seconds(3); // Registers profile prefs. static void RegisterProfilePrefs(PrefRegistrySimple* registry); @@ -70,8 +72,8 @@ // Returns true if the user has fingerprint record registered. bool HasRecord() const; - // Add a fingerprint unlock attempt count. - void AddUnlockAttempt(); + // Add a fingerprint unlock attempt count that happened at timestamp. + void AddUnlockAttempt(base::TimeTicks timestamp); // Reset the number of unlock attempts to 0. void ResetUnlockAttemptCount(); @@ -79,8 +81,15 @@ // Returns true if the user has exceeded fingerprint unlock attempts. bool ExceededUnlockAttempts() const; + // Returns the number of unlock attempts made before success, regardless of + // when they happened in time. int unlock_attempt_count() const { return unlock_attempt_count_; } + // Returns the number of recent unlock attempts made before success. + // Recent attempts are defined as happening within + // `kRecentUnlockAttemptsDelta` from each others. + int GetRecentUnlockAttemptCount(base::TimeTicks timestamp); + // device::mojom::FingerprintObserver: void OnRestarted() override; void OnEnrollScanDone(device::mojom::ScanResult scan_result, @@ -100,9 +109,16 @@ friend class QuickUnlockStorage; Profile* const profile_; - // Number of fingerprint unlock attempt. + // Number of fingerprint unlock attempts. int unlock_attempt_count_ = 0; + // Number of recent fingerprint unlock attempts, i.e. attempts happening + // within 3 seconds from each others. + int recent_unlock_attempt_count_ = 0; + + // Timestamps of the last fingerprint unlock attempt. + base::TimeTicks last_unlock_attempt_timestamp_ = base::TimeTicks::UnixEpoch(); + mojo::Remote<device::mojom::Fingerprint> fp_service_; mojo::Receiver<device::mojom::FingerprintObserver>
diff --git a/chrome/browser/ash/login/quick_unlock/fingerprint_storage_unittest.cc b/chrome/browser/ash/login/quick_unlock/fingerprint_storage_unittest.cc index ca6e943..6c387f2 100644 --- a/chrome/browser/ash/login/quick_unlock/fingerprint_storage_unittest.cc +++ b/chrome/browser/ash/login/quick_unlock/fingerprint_storage_unittest.cc
@@ -8,6 +8,7 @@ #include "ash/constants/ash_pref_names.h" #include "base/test/metrics/histogram_tester.h" +#include "base/time/time.h" #include "chrome/browser/ash/login/quick_unlock/quick_unlock_factory.h" #include "chrome/browser/ash/login/quick_unlock/quick_unlock_storage.h" #include "chrome/browser/ash/login/quick_unlock/quick_unlock_utils.h" @@ -83,15 +84,93 @@ EXPECT_EQ(0, fingerprint_storage->unlock_attempt_count()); - fingerprint_storage->AddUnlockAttempt(); - fingerprint_storage->AddUnlockAttempt(); - fingerprint_storage->AddUnlockAttempt(); + fingerprint_storage->AddUnlockAttempt(base::TimeTicks::Now()); + fingerprint_storage->AddUnlockAttempt(base::TimeTicks::Now()); + fingerprint_storage->AddUnlockAttempt(base::TimeTicks::Now()); EXPECT_EQ(3, fingerprint_storage->unlock_attempt_count()); fingerprint_storage->ResetUnlockAttemptCount(); EXPECT_EQ(0, fingerprint_storage->unlock_attempt_count()); } +// Verifies that initial repeated unlock attempt count is zero. +TEST_F(FingerprintStorageUnitTest, InitialRecentUnlockAttemptCountIsZero) { + FingerprintStorage* fingerprint_storage = + QuickUnlockFactory::GetForProfile(profile_.get())->fingerprint_storage(); + + EXPECT_EQ(0, fingerprint_storage->GetRecentUnlockAttemptCount( + base::TimeTicks::Now())); +} + +// Verify that recent unlock attempts correctly increases unlock attempt count. +TEST_F(FingerprintStorageUnitTest, + RecentUnlockAttemptCountIsOneAfterOneAttempt) { + FingerprintStorage* fingerprint_storage = + QuickUnlockFactory::GetForProfile(profile_.get())->fingerprint_storage(); + + base::TimeTicks test_start = base::TimeTicks::Now(); + fingerprint_storage->AddUnlockAttempt(test_start); + EXPECT_EQ(1, fingerprint_storage->GetRecentUnlockAttemptCount( + test_start + base::Seconds(2))); +} + +// Verify that recent unlock attempts correctly increases unlock attempt count. +TEST_F(FingerprintStorageUnitTest, + RecentUnlockAttemptCountIncreasesWithRepeatedAttempts) { + FingerprintStorage* fingerprint_storage = + QuickUnlockFactory::GetForProfile(profile_.get())->fingerprint_storage(); + + base::TimeTicks test_start = base::TimeTicks::Now(); + fingerprint_storage->AddUnlockAttempt(test_start); + fingerprint_storage->AddUnlockAttempt(test_start + base::Seconds(1)); + fingerprint_storage->AddUnlockAttempt(test_start + base::Seconds(2)); + EXPECT_EQ(3, fingerprint_storage->GetRecentUnlockAttemptCount( + test_start + base::Seconds(3))); +} + +// Verify that recent unlock attempts is zero after explicit reset call +TEST_F(FingerprintStorageUnitTest, RecentUnlockAttemptCountIsZeroAfterReset) { + FingerprintStorage* fingerprint_storage = + QuickUnlockFactory::GetForProfile(profile_.get())->fingerprint_storage(); + + base::TimeTicks test_start = base::TimeTicks::Now(); + fingerprint_storage->AddUnlockAttempt(test_start); + ASSERT_EQ(1, fingerprint_storage->GetRecentUnlockAttemptCount( + test_start + base::Seconds(1))); + + fingerprint_storage->ResetUnlockAttemptCount(); + EXPECT_EQ(0, fingerprint_storage->GetRecentUnlockAttemptCount( + test_start + base::Seconds(2))); +} + +// Verify that dated attempts are not counted in recent unlock attempt count. +TEST_F(FingerprintStorageUnitTest, + RecentUnlockAttemptCountExcludesDatedAttempts) { + FingerprintStorage* fingerprint_storage = + QuickUnlockFactory::GetForProfile(profile_.get())->fingerprint_storage(); + + base::TimeTicks test_start = base::TimeTicks::Now(); + fingerprint_storage->AddUnlockAttempt(test_start); + fingerprint_storage->AddUnlockAttempt(test_start + base::Seconds(1)); + fingerprint_storage->AddUnlockAttempt(test_start + base::Seconds(2)); + EXPECT_EQ(0, fingerprint_storage->GetRecentUnlockAttemptCount( + test_start + base::Seconds(10))); +} + +// Verify that dated attempts are not counted in recent unlock attempt count. +TEST_F(FingerprintStorageUnitTest, + RecentUnlockAttemptCountExcludesSomeAttempts) { + FingerprintStorage* fingerprint_storage = + QuickUnlockFactory::GetForProfile(profile_.get())->fingerprint_storage(); + + base::TimeTicks test_start = base::TimeTicks::Now(); + fingerprint_storage->AddUnlockAttempt(test_start); + fingerprint_storage->AddUnlockAttempt(test_start + base::Seconds(1)); + fingerprint_storage->AddUnlockAttempt(test_start + base::Seconds(5)); + EXPECT_EQ(1, fingerprint_storage->GetRecentUnlockAttemptCount( + test_start + base::Seconds(7))); +} + // Verifies that authentication is not available when // 1. No fingerprint records registered. // 2. Too many authentication attempts. @@ -117,7 +196,7 @@ // Too many authentication attempts make fingerprint authentication // unavailable. for (int i = 0; i < FingerprintStorage::kMaximumUnlockAttempts; ++i) { - fingerprint_storage->AddUnlockAttempt(); + fingerprint_storage->AddUnlockAttempt(base::TimeTicks::Now()); } EXPECT_FALSE(test_api.IsFingerprintAvailable()); fingerprint_storage->ResetUnlockAttemptCount();
diff --git a/chrome/browser/ash/policy/reporting/user_added_removed/user_added_removed_reporter_browsertest.cc b/chrome/browser/ash/policy/reporting/user_added_removed/user_added_removed_reporter_browsertest.cc new file mode 100644 index 0000000..94a6a19 --- /dev/null +++ b/chrome/browser/ash/policy/reporting/user_added_removed/user_added_removed_reporter_browsertest.cc
@@ -0,0 +1,391 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <memory> +#include <string> + +#include "ash/components/login/auth/public/user_context.h" +#include "ash/components/settings/cros_settings_names.h" +#include "ash/constants/ash_switches.h" +#include "ash/public/cpp/login_screen_test_api.h" +#include "base/auto_reset.h" +#include "base/run_loop.h" +#include "chrome/browser/ash/login/app_mode/kiosk_launch_controller.h" +#include "chrome/browser/ash/login/test/device_state_mixin.h" +#include "chrome/browser/ash/login/test/embedded_test_server_setup_mixin.h" +#include "chrome/browser/ash/login/test/fake_gaia_mixin.h" +#include "chrome/browser/ash/login/test/kiosk_apps_mixin.h" +#include "chrome/browser/ash/login/test/login_manager_mixin.h" +#include "chrome/browser/ash/login/test/session_manager_state_waiter.h" +#include "chrome/browser/ash/login/test/user_policy_mixin.h" +#include "chrome/browser/ash/policy/core/browser_policy_connector_ash.h" +#include "chrome/browser/ash/policy/core/device_local_account.h" +#include "chrome/browser/ash/policy/core/device_local_account_policy_service.h" +#include "chrome/browser/ash/policy/core/device_policy_cros_browser_test.h" +#include "chrome/browser/ash/settings/scoped_testing_cros_settings.h" +#include "chrome/browser/ash/settings/stub_cros_settings_provider.h" +#include "chrome/browser/extensions/browsertest_util.h" +#include "chrome/browser/policy/messaging_layer/proto/synced/add_remove_user_event.pb.h" +#include "chrome/test/base/mixin_based_in_process_browser_test.h" +#include "chrome/test/base/testing_browser_process.h" +#include "chromeos/ash/components/dbus/session_manager/fake_session_manager_client.h" +#include "chromeos/dbus/missive/missive_client.h" +#include "chromeos/dbus/missive/missive_client_test_observer.h" +#include "components/account_id/account_id.h" +#include "components/policy/core/common/cloud/mock_cloud_policy_store.h" +#include "components/policy/proto/chrome_device_policy.pb.h" +#include "components/policy/proto/device_management_backend.pb.h" +#include "components/reporting/proto/synced/record.pb.h" +#include "components/reporting/proto/synced/record_constants.pb.h" +#include "components/signin/public/identity_manager/identity_test_utils.h" +#include "components/user_manager/user_manager.h" +#include "content/public/test/browser_test.h" +#include "net/dns/mock_host_resolver.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/types/optional.h" + +using ::chromeos::MissiveClientTestObserver; +using ::enterprise_management::ChromeDeviceSettingsProto; +using ::enterprise_management::DeviceLocalAccountInfoProto; +using ::reporting::Destination; +using ::reporting::Priority; +using ::reporting::Record; +using ::testing::Eq; +using ::testing::InvokeWithoutArgs; +using ::testing::StrEq; + +namespace ash::reporting { +namespace { + +constexpr char kTestUserEmail[] = "test@example.com"; +constexpr char kTestAffiliationId[] = "test_affiliation_id"; +constexpr char kPublicSessionUserEmail[] = "public_session_user@localhost"; + +Record GetNextUserAddedRemovedRecord(MissiveClientTestObserver* observer) { + const std::tuple<Priority, Record>& enqueued_record = + observer->GetNextEnqueuedRecord(); + Priority priority = std::get<0>(enqueued_record); + Record record = std::get<1>(enqueued_record); + + EXPECT_THAT(priority, Eq(Priority::IMMEDIATE)); + return record; +} + +absl::optional<Record> MaybeGetEnqueuedUserAddedRemovedRecord() { + const std::vector<Record>& records = + MissiveClient::Get()->GetTestInterface()->GetEnqueuedRecords( + Priority::IMMEDIATE); + for (const Record& record : records) { + if (record.destination() == Destination::ADDED_REMOVED_EVENTS) { + return record; + } + } + return absl::nullopt; +} + +// Waiter used by tests during public session user creation. +class PublicSessionUserCreationWaiter + : public user_manager::UserManager::Observer { + public: + PublicSessionUserCreationWaiter() = default; + + PublicSessionUserCreationWaiter(const PublicSessionUserCreationWaiter&) = + delete; + PublicSessionUserCreationWaiter& operator=( + const PublicSessionUserCreationWaiter&) = delete; + + ~PublicSessionUserCreationWaiter() override = default; + + void Wait(const AccountId& public_session_account_id) { + if (user_manager::UserManager::Get()->IsKnownUser( + public_session_account_id)) { + return; + } + + local_state_changed_run_loop_ = std::make_unique<base::RunLoop>(); + user_manager::UserManager::Get()->AddObserver(this); + local_state_changed_run_loop_->Run(); + user_manager::UserManager::Get()->RemoveObserver(this); + } + + // user_manager::UserManager::Observer: + void LocalStateChanged(user_manager::UserManager* user_manager) override { + local_state_changed_run_loop_->Quit(); + } + + private: + std::unique_ptr<base::RunLoop> local_state_changed_run_loop_; +}; + +class UserAddedRemovedReporterBrowserTest + : public policy::DevicePolicyCrosBrowserTest { + protected: + UserAddedRemovedReporterBrowserTest() { + // Add unaffiliated user for testing purposes. + login_manager_mixin_.AppendRegularUsers(1); + + login_manager_mixin_.set_session_restore_enabled(); + scoped_testing_cros_settings_.device_settings()->SetBoolean( + kReportDeviceLoginLogout, true); + } + + void SetUpCommandLine(base::CommandLine* command_line) override { + command_line->AppendSwitch(switches::kLoginManager); + command_line->AppendSwitch(switches::kAllowFailedPolicyFetchForTest); + } + + void SetUpOnMainThread() override { + login_manager_mixin_.set_should_launch_browser(true); + FakeSessionManagerClient::Get()->set_supports_browser_restart(true); + policy::DevicePolicyCrosBrowserTest::SetUpOnMainThread(); + } + + void SetUpInProcessBrowserTestFixture() override { + policy::DevicePolicyCrosBrowserTest::SetUpInProcessBrowserTestFixture(); + + // Set up affiliation for the test user. + auto device_policy_update = device_state_.RequestDevicePolicyUpdate(); + auto user_policy_update = user_policy_mixin_.RequestPolicyUpdate(); + + device_policy_update->policy_data()->add_device_affiliation_ids( + kTestAffiliationId); + user_policy_update->policy_data()->add_user_affiliation_ids( + kTestAffiliationId); + } + + const AccountId test_account_id_ = AccountId::FromUserEmailGaiaId( + kTestUserEmail, + signin::GetTestGaiaIdForEmail(kTestUserEmail)); + UserPolicyMixin user_policy_mixin_{&mixin_host_, test_account_id_}; + + FakeGaiaMixin fake_gaia_mixin_{&mixin_host_}; + LoginManagerMixin login_manager_mixin_{ + &mixin_host_, LoginManagerMixin::UserList(), &fake_gaia_mixin_}; + + ScopedTestingCrosSettings scoped_testing_cros_settings_; +}; + +IN_PROC_BROWSER_TEST_F(UserAddedRemovedReporterBrowserTest, + ReportNewUnaffiliatedUser) { + MissiveClientTestObserver observer(Destination::ADDED_REMOVED_EVENTS); + login_manager_mixin_.LoginAsNewRegularUser(); + test::WaitForPrimaryUserSessionStart(); + + const Record& record = GetNextUserAddedRemovedRecord(&observer); + ::reporting::UserAddedRemovedRecord record_data; + ASSERT_TRUE(record_data.ParseFromString(record.data())); + EXPECT_TRUE(record_data.has_user_added_event()); + EXPECT_FALSE(record_data.has_affiliated_user()); +} + +IN_PROC_BROWSER_TEST_F(UserAddedRemovedReporterBrowserTest, + ReportRemovedUnaffiliatedUser) { + MissiveClientTestObserver observer(Destination::ADDED_REMOVED_EVENTS); + ASSERT_TRUE(LoginScreenTestApi::RemoveUser( + login_manager_mixin_.users()[0].account_id)); + + const Record& record = GetNextUserAddedRemovedRecord(&observer); + ::reporting::UserAddedRemovedRecord record_data; + ASSERT_TRUE(record_data.ParseFromString(record.data())); + ASSERT_TRUE(record_data.has_user_removed_event()); + EXPECT_THAT(record_data.user_removed_event().reason(), + Eq(::reporting::UserRemovalReason::LOCAL_USER_INITIATED)); + EXPECT_FALSE(record_data.has_affiliated_user()); +} + +IN_PROC_BROWSER_TEST_F(UserAddedRemovedReporterBrowserTest, + ReportNewAffiliatedUser) { + MissiveClientTestObserver observer(Destination::ADDED_REMOVED_EVENTS); + const LoginManagerMixin::TestUserInfo user_info(test_account_id_); + const auto& context = LoginManagerMixin::CreateDefaultUserContext(user_info); + login_manager_mixin_.LoginAsNewRegularUser(context); + test::WaitForPrimaryUserSessionStart(); + + const Record& record = GetNextUserAddedRemovedRecord(&observer); + ::reporting::UserAddedRemovedRecord record_data; + ASSERT_TRUE(record_data.ParseFromString(record.data())); + EXPECT_TRUE(record_data.has_user_added_event()); + EXPECT_TRUE(record_data.has_affiliated_user()); + EXPECT_TRUE(record_data.affiliated_user().has_user_email()); + EXPECT_THAT(record_data.affiliated_user().user_email(), + StrEq(kTestUserEmail)); +} + +IN_PROC_BROWSER_TEST_F(UserAddedRemovedReporterBrowserTest, + PRE_DoesNotReportGuestUser) { + base::RunLoop restart_job_waiter; + FakeSessionManagerClient::Get()->set_restart_job_callback( + restart_job_waiter.QuitClosure()); + + ASSERT_TRUE(LoginScreenTestApi::IsGuestButtonShown()); + ASSERT_TRUE(LoginScreenTestApi::ClickGuestButton()); + + restart_job_waiter.Run(); + EXPECT_TRUE(FakeSessionManagerClient::Get()->restart_job_argv().has_value()); +} + +IN_PROC_BROWSER_TEST_F(UserAddedRemovedReporterBrowserTest, + DoesNotReportGuestUser) { + test::WaitForPrimaryUserSessionStart(); + base::RunLoop().RunUntilIdle(); + + const user_manager::UserManager* const user_manager = + user_manager::UserManager::Get(); + ASSERT_TRUE(user_manager->IsLoggedInAsGuest()); + + const absl::optional<Record> record = + MaybeGetEnqueuedUserAddedRemovedRecord(); + ASSERT_FALSE(record.has_value()); +} + +class UserAddedRemovedReporterPublicSessionBrowserTest + : public policy::DevicePolicyCrosBrowserTest { + protected: + void SetUpOnMainThread() override { + policy::DevicePolicyCrosBrowserTest::SetUpOnMainThread(); + + // Wait for the public session user to be created. + PublicSessionUserCreationWaiter public_session_waiter; + public_session_waiter.Wait(public_session_account_id_); + EXPECT_TRUE(user_manager::UserManager::Get()->IsKnownUser( + public_session_account_id_)); + + // Wait for the device local account policy to be installed. + policy::CloudPolicyStore* const store = + TestingBrowserProcess::GetGlobal() + ->platform_part() + ->browser_policy_connector_ash() + ->GetDeviceLocalAccountPolicyService() + ->GetBrokerForUser(public_session_account_id_.GetUserEmail()) + ->core() + ->store(); + if (!store->has_policy()) { + policy::MockCloudPolicyStoreObserver observer; + + base::RunLoop loop; + store->AddObserver(&observer); + EXPECT_CALL(observer, OnStoreLoaded(store)) + .WillOnce(InvokeWithoutArgs(&loop, &base::RunLoop::Quit)); + loop.Run(); + store->RemoveObserver(&observer); + } + } + + void SetUpInProcessBrowserTestFixture() override { + policy::DevicePolicyCrosBrowserTest::SetUpInProcessBrowserTestFixture(); + + // Setup the device policy. + ChromeDeviceSettingsProto& proto(device_policy()->payload()); + DeviceLocalAccountInfoProto* account = + proto.mutable_device_local_accounts()->add_account(); + account->set_account_id(kPublicSessionUserEmail); + account->set_type(DeviceLocalAccountInfoProto::ACCOUNT_TYPE_PUBLIC_SESSION); + // Enable login/logout reporting. + proto.mutable_device_reporting()->set_report_login_logout(true); + RefreshDevicePolicy(); + + // Setup the device local account policy. + policy::UserPolicyBuilder device_local_account_policy; + device_local_account_policy.policy_data().set_username( + kPublicSessionUserEmail); + device_local_account_policy.policy_data().set_policy_type( + policy::dm_protocol::kChromePublicAccountPolicyType); + device_local_account_policy.policy_data().set_settings_entity_id( + kPublicSessionUserEmail); + device_local_account_policy.Build(); + session_manager_client()->set_device_local_account_policy( + kPublicSessionUserEmail, device_local_account_policy.GetBlob()); + } + + const AccountId public_session_account_id_ = + AccountId::FromUserEmail(policy::GenerateDeviceLocalAccountUserId( + kPublicSessionUserEmail, + policy::DeviceLocalAccount::TYPE_PUBLIC_SESSION)); + + const LoginManagerMixin login_manager_mixin_{&mixin_host_, + LoginManagerMixin::UserList()}; +}; + +IN_PROC_BROWSER_TEST_F(UserAddedRemovedReporterPublicSessionBrowserTest, + DoesNotReportPublicSessionUser) { + ASSERT_TRUE( + LoginScreenTestApi::ExpandPublicSessionPod(public_session_account_id_)); + LoginScreenTestApi::ClickPublicExpandedSubmitButton(); + test::WaitForPrimaryUserSessionStart(); + base::RunLoop().RunUntilIdle(); + + const user_manager::UserManager* const user_manager = + user_manager::UserManager::Get(); + ASSERT_TRUE(user_manager->IsLoggedInAsPublicAccount()); + + const absl::optional<Record> record = + MaybeGetEnqueuedUserAddedRemovedRecord(); + ASSERT_FALSE(record.has_value()); +} + +class UserAddedRemovedReporterKioskBrowserTest + : public MixinBasedInProcessBrowserTest { + protected: + void SetUp() override { + skip_splash_wait_override_ = + KioskLaunchController::SkipSplashScreenWaitForTesting(); + login_manager_mixin_.set_session_restore_enabled(); + + MixinBasedInProcessBrowserTest::SetUp(); + } + + void SetUpCommandLine(base::CommandLine* command_line) override { + MixinBasedInProcessBrowserTest::SetUpCommandLine(command_line); + + fake_cws_.Init(embedded_test_server()); + fake_cws_.SetUpdateCrx(GetTestAppId(), GetTestAppId() + ".crx", "1.0.0"); + } + + void SetUpInProcessBrowserTestFixture() override { + MixinBasedInProcessBrowserTest::SetUpInProcessBrowserTestFixture(); + + host_resolver()->AddRule("*", "127.0.0.1"); + SessionManagerClient::InitializeFakeInMemory(); + FakeSessionManagerClient::Get()->set_supports_browser_restart(true); + + ChromeDeviceSettingsProto& proto(policy_helper_.device_policy()->payload()); + KioskAppsMixin::AppendAutoLaunchKioskAccount(&proto); + proto.mutable_device_reporting()->set_report_login_logout(true); + policy_helper_.RefreshDevicePolicy(); + } + + void SetUpOnMainThread() override { + MixinBasedInProcessBrowserTest::SetUpOnMainThread(); + extensions::browsertest_util::CreateAndInitializeLocalCache(); + } + + std::string GetTestAppId() const { return KioskAppsMixin::kKioskAppId; } + + FakeCWS fake_cws_; + policy::DevicePolicyCrosTestHelper policy_helper_; + std::unique_ptr<base::AutoReset<bool>> skip_splash_wait_override_; + const EmbeddedTestServerSetupMixin embedded_test_server_{ + &mixin_host_, embedded_test_server()}; + + const DeviceStateMixin device_state_{ + &mixin_host_, DeviceStateMixin::State::OOBE_COMPLETED_CLOUD_ENROLLED}; + LoginManagerMixin login_manager_mixin_{&mixin_host_, + LoginManagerMixin::UserList()}; +}; + +IN_PROC_BROWSER_TEST_F(UserAddedRemovedReporterKioskBrowserTest, + DoesNotReportKioskUser) { + test::WaitForPrimaryUserSessionStart(); + const user_manager::UserManager* const user_manager = + user_manager::UserManager::Get(); + ASSERT_TRUE(user_manager->IsLoggedInAsKioskApp()); + + const absl::optional<Record> record = + MaybeGetEnqueuedUserAddedRemovedRecord(); + ASSERT_FALSE(record.has_value()); +} + +} // namespace +} // namespace ash::reporting
diff --git a/chrome/browser/ash/web_applications/projector_app/projector_app_integration_browsertest.cc b/chrome/browser/ash/web_applications/projector_app/projector_app_integration_browsertest.cc index 1824d02..5398a10 100644 --- a/chrome/browser/ash/web_applications/projector_app/projector_app_integration_browsertest.cc +++ b/chrome/browser/ash/web_applications/projector_app/projector_app_integration_browsertest.cc
@@ -4,14 +4,14 @@ #include "ash/capture_mode/capture_mode_controller.h" #include "ash/projector/projector_controller_impl.h" -#include "ash/public/cpp/projector/projector_client.h" #include "ash/webui/media_app_ui/buildflags.h" #include "ash/webui/media_app_ui/test/media_app_ui_browsertest.h" #include "ash/webui/projector_app/buildflags.h" +#include "ash/webui/projector_app/projector_app_client.h" #include "base/run_loop.h" #include "chrome/browser/ash/system_web_apps/system_web_app_manager.h" #include "chrome/browser/ash/system_web_apps/test_support/system_web_app_integration_test.h" -#include "chrome/browser/ui/ash/projector/projector_client_impl.h" +#include "chrome/browser/ui/ash/projector/projector_app_client_impl.h" #include "chrome/browser/ui/ash/system_web_apps/system_web_app_ui_utils.h" #include "content/public/test/browser_test.h" @@ -65,10 +65,10 @@ capture_mode_controller->PerformCapture(); run_loop.Run(); - ProjectorClientImpl* projector_client = - static_cast<ProjectorClientImpl*>(ash::ProjectorClient::Get()); + ProjectorAppClientImpl* projector_app_client = + static_cast<ProjectorAppClientImpl*>(ash::ProjectorAppClient::Get()); content::WebContents* annotator_embedder = - projector_client->get_annotator_message_handler_for_test() + projector_app_client->get_annotator_message_handler_for_test() ->get_web_ui_for_test() ->GetWebContents(); PrepareAppForTest(annotator_embedder);
diff --git a/chrome/browser/ash/web_applications/projector_app/untrusted_projector_ui_config.cc b/chrome/browser/ash/web_applications/projector_app/untrusted_projector_ui_config.cc index 9b4ee98c..850dd56 100644 --- a/chrome/browser/ash/web_applications/projector_app/untrusted_projector_ui_config.cc +++ b/chrome/browser/ash/web_applications/projector_app/untrusted_projector_ui_config.cc
@@ -35,6 +35,8 @@ source->AddBoolean( "isUseOAuthForGetVideoInfoEnabled", ash::features::IsProjectorUseOAuthForGetVideoInfoEnabled()); + source->AddBoolean("isLocalPlaybackEnabled", + ash::features::IsProjectorLocalPlaybackEnabled()); source->AddString("appLocale", g_browser_process->GetApplicationLocale()); }
diff --git a/chrome/browser/banners/android/java/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java b/chrome/browser/banners/android/java/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java index 6796cf8..a624b83 100644 --- a/chrome/browser/banners/android/java/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java +++ b/chrome/browser/banners/android/java/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java
@@ -156,7 +156,7 @@ "/chrome/test/data/banners/manifest_prefer_related_chrome_app.json"; private static final String WEB_APP_MANIFEST_FOR_BOTTOM_SHEET_INSTALL = - "/chrome/test/data/banners/manifest_bottom_sheet_install.json"; + "/chrome/test/data/banners/manifest_with_screenshots.json"; private static final String NATIVE_ICON_PATH = "/chrome/test/data/banners/launcher-icon-4x.png";
diff --git a/chrome/browser/extensions/api/debugger/debugger_api.cc b/chrome/browser/extensions/api/debugger/debugger_api.cc index 4b303f2..3c12e5cd 100644 --- a/chrome/browser/extensions/api/debugger/debugger_api.cc +++ b/chrome/browser/extensions/api/debugger/debugger_api.cc
@@ -824,6 +824,11 @@ base::Value::List result; Profile* profile = Profile::FromBrowserContext(browser_context()); for (auto& host : list) { + // TODO(crbug.com/1348385): hide all Tab targets for now to avoid + // compatibility problems. Consider exposing them later when they're fully + // supported, and compatibility considerations are better understood. + if (host->GetType() == DevToolsAgentHost::kTypeTab) + continue; if (!ExtensionMayAttachToTargetProfile( profile, include_incognito_information(), *host)) { continue;
diff --git a/chrome/browser/extensions/lazy_background_page_apitest.cc b/chrome/browser/extensions/lazy_background_page_apitest.cc index cb4209b8..029528d 100644 --- a/chrome/browser/extensions/lazy_background_page_apitest.cc +++ b/chrome/browser/extensions/lazy_background_page_apitest.cc
@@ -16,6 +16,7 @@ #include "base/threading/thread_restrictions.h" #include "build/build_config.h" #include "chrome/browser/bookmarks/bookmark_model_factory.h" +#include "chrome/browser/devtools/chrome_devtools_manager_delegate.h" #include "chrome/browser/devtools/devtools_window_testing.h" #include "chrome/browser/extensions/api/developer_private/developer_private_api.h" #include "chrome/browser/extensions/extension_action_test_util.h" @@ -347,6 +348,8 @@ content::DevToolsAgentHost::GetOrCreateAll(); scoped_refptr<content::DevToolsAgentHost> service_worker_host; for (const scoped_refptr<content::DevToolsAgentHost>& host : targets) { + if (host->GetType() != ChromeDevToolsManagerDelegate::kTypeBackgroundPage) + continue; if (host->GetURL() == BackgroundInfo::GetBackgroundURL(extension.get())) { EXPECT_FALSE(service_worker_host); service_worker_host = host;
diff --git a/chrome/browser/external_protocol/external_protocol_policy_browsertest.cc b/chrome/browser/external_protocol/external_protocol_policy_browsertest.cc index 129d363..277b353 100644 --- a/chrome/browser/external_protocol/external_protocol_policy_browsertest.cc +++ b/chrome/browser/external_protocol/external_protocol_policy_browsertest.cc
@@ -36,14 +36,14 @@ protocol_origins_map.SetStringKey(policy::external_protocol::kProtocolNameKey, kExampleScheme); // Set origins list with a wildcard origin matching pattern. - base::ListValue origins; + base::Value::List origins; origins.Append(kWildcardOrigin); protocol_origins_map.SetKey(policy::external_protocol::kOriginListKey, - std::move(origins)); + base::Value(std::move(origins))); PolicyMap policies; policies.Set(key::kAutoLaunchProtocolsFromOrigins, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, - protocol_origins_map.Clone(), nullptr); + base::Value(protocol_origins_map.Clone()), nullptr); UpdateProviderPolicy(policies); block_state = ExternalProtocolHandler::GetBlockState( @@ -56,22 +56,22 @@ const char kWildcardOrigin[] = "*"; const char kExampleScheme[] = "custom"; - base::ListValue protocol_origins_map_list; + base::Value::List protocol_origins_map_list; // Single dictionary in the list for this test case. base::DictionaryValue protocol_origins_map; // Set a protocol. protocol_origins_map.SetStringKey(policy::external_protocol::kProtocolNameKey, kExampleScheme); // Set an origins list with the wildcard origin matching pattern. - base::ListValue origins; + base::Value::List origins; origins.Append(kWildcardOrigin); protocol_origins_map.SetKey(policy::external_protocol::kOriginListKey, - std::move(origins)); + base::Value(std::move(origins))); protocol_origins_map_list.Append(std::move(protocol_origins_map)); PolicyMap policies; policies.Set(key::kAutoLaunchProtocolsFromOrigins, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, - protocol_origins_map_list.Clone(), nullptr); + base::Value(protocol_origins_map_list.Clone()), nullptr); UpdateProviderPolicy(policies); // Calling GetBlockState with a null initiating_origin should @@ -92,21 +92,21 @@ browser()->profile()); EXPECT_EQ(ExternalProtocolHandler::UNKNOWN, block_state); - base::ListValue protocol_origins_map_list; + base::Value::List protocol_origins_map_list; // Single dictionary in the list for this test case. base::DictionaryValue protocol_origins_map; // Set a protocol list with a matching protocol. protocol_origins_map.SetStringKey(policy::external_protocol::kProtocolNameKey, kExampleScheme); // Set an empty origins list. - base::ListValue origins; + base::Value::List origins; protocol_origins_map.SetKey(policy::external_protocol::kOriginListKey, - std::move(origins)); + base::Value(std::move(origins))); protocol_origins_map_list.Append(std::move(protocol_origins_map)); PolicyMap policies; policies.Set(key::kAutoLaunchProtocolsFromOrigins, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, - protocol_origins_map_list.Clone(), nullptr); + base::Value(protocol_origins_map_list.Clone()), nullptr); UpdateProviderPolicy(policies); block_state = ExternalProtocolHandler::GetBlockState( @@ -119,22 +119,22 @@ const char kWildcardOrigin[] = "*"; const char kExampleScheme[] = "custom"; - base::ListValue protocol_origins_map_list; + base::Value::List protocol_origins_map_list; // Single dictionary in the list for this test case. base::DictionaryValue protocol_origins_map; // Set a protocol to match the test. protocol_origins_map.SetStringKey(policy::external_protocol::kProtocolNameKey, kExampleScheme); // Set an origins list with the wildcard origin matching pattern. - base::ListValue origins; + base::Value::List origins; origins.Append(kWildcardOrigin); protocol_origins_map.SetKey(policy::external_protocol::kOriginListKey, - std::move(origins)); + base::Value(std::move(origins))); protocol_origins_map_list.Append(std::move(protocol_origins_map)); PolicyMap policies; policies.Set(key::kAutoLaunchProtocolsFromOrigins, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, - protocol_origins_map_list.Clone(), nullptr); + base::Value(protocol_origins_map_list.Clone()), nullptr); UpdateProviderPolicy(policies); url::Origin test_origin = url::Origin::Create(GURL("https://example.test")); @@ -152,7 +152,7 @@ const char kWildcardOrigin[] = "*"; const char kExampleScheme[] = "custom"; - base::ListValue protocol_origins_map_list; + base::Value::List protocol_origins_map_list; // Three dictionaries in the list for this test case. base::DictionaryValue protocol_origins_map1; @@ -162,32 +162,32 @@ // Set invalid protocols, each with the wildcard origin matching pattern. protocol_origins_map1.SetStringKey( policy::external_protocol::kProtocolNameKey, kInvalidProtocol1); - base::ListValue origins1; + base::Value::List origins1; origins1.Append(kWildcardOrigin); protocol_origins_map1.SetKey(policy::external_protocol::kOriginListKey, - std::move(origins1)); + base::Value(std::move(origins1))); protocol_origins_map_list.Append(std::move(protocol_origins_map1)); protocol_origins_map2.SetStringKey( policy::external_protocol::kProtocolNameKey, kInvalidProtocol2); - base::ListValue origins2; + base::Value::List origins2; origins2.Append(kWildcardOrigin); protocol_origins_map2.SetKey(policy::external_protocol::kOriginListKey, - std::move(origins2)); + base::Value(std::move(origins2))); protocol_origins_map_list.Append(std::move(protocol_origins_map2)); protocol_origins_map3.SetStringKey( policy::external_protocol::kProtocolNameKey, kInvalidProtocol3); - base::ListValue origins3; + base::Value::List origins3; origins3.Append(kWildcardOrigin); protocol_origins_map3.SetKey(policy::external_protocol::kOriginListKey, - std::move(origins3)); + base::Value(std::move(origins3))); protocol_origins_map_list.Append(std::move(protocol_origins_map3)); PolicyMap policies; policies.Set(key::kAutoLaunchProtocolsFromOrigins, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, - protocol_origins_map_list.Clone(), nullptr); + base::Value(protocol_origins_map_list.Clone()), nullptr); UpdateProviderPolicy(policies); url::Origin test_origin = url::Origin::Create(GURL("https://example.test")); @@ -202,7 +202,7 @@ const char kExampleScheme[] = "custom"; const char kHost[] = "www.example.test"; - base::ListValue protocol_origins_map_list; + base::Value::List protocol_origins_map_list; // Single dictionary in the list for this test case. base::DictionaryValue protocol_origins_map; // Set a protocol to match the test. @@ -210,15 +210,15 @@ kExampleScheme); // Set an origins list with an origin matching pattern that matches but is // only the host name. - base::ListValue origins; + base::Value::List origins; origins.Append(kHost); protocol_origins_map.SetKey(policy::external_protocol::kOriginListKey, - std::move(origins)); + base::Value(std::move(origins))); protocol_origins_map_list.Append(std::move(protocol_origins_map)); PolicyMap policies; policies.Set(key::kAutoLaunchProtocolsFromOrigins, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, - protocol_origins_map_list.Clone(), nullptr); + base::Value(protocol_origins_map_list.Clone()), nullptr); UpdateProviderPolicy(policies); // Test that secure origin matches. @@ -247,7 +247,7 @@ const char kExampleScheme[] = "custom"; const char kExactHostName[] = ".www.example.test"; - base::ListValue protocol_origins_map_list; + base::Value::List protocol_origins_map_list; // Single dictionary in the list for this test case. base::DictionaryValue protocol_origins_map; // Set a protocol to match the test. @@ -255,15 +255,15 @@ kExampleScheme); // Set an origins list with an origin matching pattern that matches exactly // but has no scheme. - base::ListValue origins; + base::Value::List origins; origins.Append(kExactHostName); protocol_origins_map.SetKey(policy::external_protocol::kOriginListKey, - std::move(origins)); + base::Value(std::move(origins))); protocol_origins_map_list.Append(std::move(protocol_origins_map)); PolicyMap policies; policies.Set(key::kAutoLaunchProtocolsFromOrigins, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, - protocol_origins_map_list.Clone(), nullptr); + base::Value(protocol_origins_map_list.Clone()), nullptr); UpdateProviderPolicy(policies); // Test that secure origin matches. @@ -292,7 +292,7 @@ const char kExampleScheme[] = "custom"; const char kParentDomain[] = "example.test"; - base::ListValue protocol_origins_map_list; + base::Value::List protocol_origins_map_list; // Single dictionary in the list for this test case. base::DictionaryValue protocol_origins_map; // Set a protocol to match the test. @@ -300,15 +300,15 @@ kExampleScheme); // Set an origins list with an origin matching pattern that is the parent // domain but should match subdomains. - base::ListValue origins; + base::Value::List origins; origins.Append(kParentDomain); protocol_origins_map.SetKey(policy::external_protocol::kOriginListKey, - std::move(origins)); + base::Value(std::move(origins))); protocol_origins_map_list.Append(std::move(protocol_origins_map)); PolicyMap policies; policies.Set(key::kAutoLaunchProtocolsFromOrigins, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, - protocol_origins_map_list.Clone(), nullptr); + base::Value(protocol_origins_map_list.Clone()), nullptr); UpdateProviderPolicy(policies); // Test that a subdomain matches. @@ -325,7 +325,7 @@ const char kExampleScheme[] = "custom"; const char kProtocolWithWildcardHostname[] = "https://*"; - base::ListValue protocol_origins_map_list; + base::Value::List protocol_origins_map_list; // Single dictionary in the list for this test case. base::DictionaryValue protocol_origins_map; // Set a protocol to match the test. @@ -333,15 +333,15 @@ kExampleScheme); // Set an origins list with an origin matching pattern that matches the scheme // and all hosts. - base::ListValue origins; + base::Value::List origins; origins.Append(kProtocolWithWildcardHostname); protocol_origins_map.SetKey(policy::external_protocol::kOriginListKey, - std::move(origins)); + base::Value(std::move(origins))); protocol_origins_map_list.Append(std::move(protocol_origins_map)); PolicyMap policies; policies.Set(key::kAutoLaunchProtocolsFromOrigins, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, - protocol_origins_map_list.Clone(), nullptr); + base::Value(protocol_origins_map_list.Clone()), nullptr); UpdateProviderPolicy(policies); // Test that secure origin matches. @@ -364,7 +364,7 @@ const char kExampleScheme[] = "custom"; const char kFullOrigin[] = "https://www.example.test:443"; - base::ListValue protocol_origins_map_list; + base::Value::List protocol_origins_map_list; // Single dictionary in the list for this test case. base::DictionaryValue protocol_origins_map; // Set a protocol to match the test. @@ -372,15 +372,15 @@ kExampleScheme); // Set an origins list with an origin matching pattern that matches the full // origin exactly. - base::ListValue origins; + base::Value::List origins; origins.Append(kFullOrigin); protocol_origins_map.SetKey(policy::external_protocol::kOriginListKey, - std::move(origins)); + base::Value(std::move(origins))); protocol_origins_map_list.Append(std::move(protocol_origins_map)); PolicyMap policies; policies.Set(key::kAutoLaunchProtocolsFromOrigins, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, - protocol_origins_map_list.Clone(), nullptr); + base::Value(protocol_origins_map_list.Clone()), nullptr); UpdateProviderPolicy(policies); // Test that default HTTPS port 443 matches. @@ -409,7 +409,7 @@ const char kExampleScheme[] = "custom"; const char kExactParentDomain[] = ".example.com"; - base::ListValue protocol_origins_map_list; + base::Value::List protocol_origins_map_list; // Single dictionary in the list for this test case. base::DictionaryValue protocol_origins_map; // Set a protocol to match the test. @@ -417,15 +417,15 @@ kExampleScheme); // Set an origins list with an origin matching pattern that doesn't match // because it is a parent domain that does not match subdomains. - base::ListValue origins; + base::Value::List origins; origins.Append(kExactParentDomain); protocol_origins_map.SetKey(policy::external_protocol::kOriginListKey, - std::move(origins)); + base::Value(std::move(origins))); protocol_origins_map_list.Append(std::move(protocol_origins_map)); PolicyMap policies; policies.Set(key::kAutoLaunchProtocolsFromOrigins, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, - protocol_origins_map_list.Clone(), nullptr); + base::Value(protocol_origins_map_list.Clone()), nullptr); UpdateProviderPolicy(policies); url::Origin test_origin = @@ -441,7 +441,7 @@ const char kExampleScheme[] = "custom"; const char kFullUrlWithPath[] = "https://example.test/home.html"; - base::ListValue protocol_origins_map_list; + base::Value::List protocol_origins_map_list; // Single dictionary in the list for this test case. base::DictionaryValue protocol_origins_map; // Set a protocol to match the test. @@ -449,15 +449,15 @@ kExampleScheme); // Set an origins list with an origin matching pattern that doesn't match // because it contains a [/path] element. - base::ListValue origins; + base::Value::List origins; origins.Append(kFullUrlWithPath); protocol_origins_map.SetKey(policy::external_protocol::kOriginListKey, - std::move(origins)); + base::Value(std::move(origins))); protocol_origins_map_list.Append(std::move(protocol_origins_map)); PolicyMap policies; policies.Set(key::kAutoLaunchProtocolsFromOrigins, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, - protocol_origins_map_list.Clone(), nullptr); + base::Value(protocol_origins_map_list.Clone()), nullptr); UpdateProviderPolicy(policies); url::Origin test_origin = url::Origin::Create(GURL(kFullUrlWithPath));
diff --git a/chrome/browser/installable/installable_manager_browsertest.cc b/chrome/browser/installable/installable_manager_browsertest.cc index 2d2dde0..777c0860 100644 --- a/chrome/browser/installable/installable_manager_browsertest.cc +++ b/chrome/browser/installable/installable_manager_browsertest.cc
@@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "components/webapps/browser/features.h" #include "components/webapps/browser/installable/installable_manager.h" #include <memory> @@ -258,6 +259,11 @@ class InstallableManagerBrowserTest : public InProcessBrowserTest { public: + InstallableManagerBrowserTest() { + scoped_feature_list_.InitAndEnableFeature( + webapps::features::kDesktopPWAsDetailedInstallDialog); + } + void SetUpOnMainThread() override { embedded_test_server()->ServeFilesFromSourceDirectory( "chrome/test/data/banners"); @@ -341,6 +347,9 @@ run_loop.Run(); return result; } + + private: + base::test::ScopedFeatureList scoped_feature_list_; }; class InstallableManagerAllowlistOriginBrowserTest @@ -1937,7 +1946,7 @@ NavigateAndRunInstallableManager( browser(), tester.get(), params, GetURLOfPageWithServiceWorkerAndManifest( - "/banners/manifest_bottom_sheet_install.json")); + "/banners/manifest_with_screenshots.json")); run_loop.Run(); @@ -1946,6 +1955,47 @@ EXPECT_FALSE(tester->valid_manifest()); EXPECT_EQ(1u, tester->screenshots().size()); + // Corresponding platform should filter out the screenshot with mismatched + // platform. +#if BUILDFLAG(IS_ANDROID) + EXPECT_LT(tester->screenshots()[0].width(), + tester->screenshots()[0].height()); +#else + EXPECT_GT(tester->screenshots()[0].width(), + tester->screenshots()[0].height()); +#endif + EXPECT_EQ(std::vector<InstallableStatusCode>{}, tester->errors()); +} + +IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest, + CheckScreenshotsPlatform) { + base::RunLoop run_loop; + std::unique_ptr<CallbackTester> tester( + new CallbackTester(run_loop.QuitClosure())); + + InstallableParams params = GetManifestParams(); + params.fetch_screenshots = true; + + // Check if only screenshots with mismatched platform are available, they are + // still used. +#if BUILDFLAG(IS_ANDROID) + NavigateAndRunInstallableManager( + browser(), tester.get(), params, + GetURLOfPageWithServiceWorkerAndManifest( + "/banners/manifest_with_only_wide_screenshots.json")); +#else + NavigateAndRunInstallableManager( + browser(), tester.get(), params, + GetURLOfPageWithServiceWorkerAndManifest( + "/banners/manifest_with_only_narrow_screenshots.json")); +#endif + run_loop.Run(); + + EXPECT_FALSE(blink::IsEmptyManifest(tester->manifest())); + EXPECT_FALSE(tester->manifest_url().is_empty()); + + EXPECT_FALSE(tester->valid_manifest()); + EXPECT_EQ(1u, tester->screenshots().size()); EXPECT_EQ(std::vector<InstallableStatusCode>{}, tester->errors()); }
diff --git a/chrome/browser/lookalikes/lookalike_url_navigation_throttle.cc b/chrome/browser/lookalikes/lookalike_url_navigation_throttle.cc index 889f36c1..fd16c69 100644 --- a/chrome/browser/lookalikes/lookalike_url_navigation_throttle.cc +++ b/chrome/browser/lookalikes/lookalike_url_navigation_throttle.cc
@@ -416,7 +416,8 @@ // TODO(crbug.com/1344981): Once the Combo Squatting heuristic is fully // launched, this console message should be removed. - if (match_type == LookalikeUrlMatchType::kComboSquatting) { + if (match_type == LookalikeUrlMatchType::kComboSquatting || + match_type == LookalikeUrlMatchType::kComboSquattingSiteEngagement) { GURL lookalike_url = first_is_lookalike ? first_url : last_url; navigation_handle()->GetRenderFrameHost()->AddMessageToConsole(
diff --git a/chrome/browser/lookalikes/lookalike_url_navigation_throttle_browsertest.cc b/chrome/browser/lookalikes/lookalike_url_navigation_throttle_browsertest.cc index 1d77529..cd20146 100644 --- a/chrome/browser/lookalikes/lookalike_url_navigation_throttle_browsertest.cc +++ b/chrome/browser/lookalikes/lookalike_url_navigation_throttle_browsertest.cc
@@ -1549,9 +1549,9 @@ embedded_test_server()->GetURL("example.net", "/")); } -// Test Combo Squatting heuristic. In this test, if kNavigatedUrl is -// Combo Squatting, the metrics should be recorded but no interstitial -// page (full page warning) is shown. +// Navigate to a URL that triggers combo squatting heuristic via the +// hard coded brand name list. This should record metrics but shouldn't show +// an interstitial. IN_PROC_BROWSER_TEST_P(LookalikeUrlNavigationThrottleBrowserTest, ComboSquatting_ShouldRecordMetricsWithoutUI) { base::HistogramTester histograms; @@ -1569,6 +1569,29 @@ CheckUkm({kNavigatedUrl}, "TriggeredByInitialUrl", false); } +// Navigate to a URL that triggers combo squatting heuristic via a +// brand name from engaged sites. This should record metrics but shouldn't show +// an interstitial. +IN_PROC_BROWSER_TEST_P( + LookalikeUrlNavigationThrottleBrowserTest, + ComboSquatting_EngagedSites_ShouldRecordMetricsWithoutUI) { + base::HistogramTester histograms; + SetEngagementScore(browser(), GURL("https://example.com"), kHighEngagement); + const GURL kNavigatedUrl = GetURL("example-login.com"); + SetEngagementScore(browser(), kNavigatedUrl, kLowEngagement); + + TestInterstitialNotShown(browser(), kNavigatedUrl); + + histograms.ExpectTotalCount(lookalikes::kHistogramName, 1); + histograms.ExpectBucketCount( + lookalikes::kHistogramName, + NavigationSuggestionEvent::kComboSquattingSiteEngagement, 1); + + CheckUkm({kNavigatedUrl}, "MatchType", + LookalikeUrlMatchType::kComboSquattingSiteEngagement); + CheckUkm({kNavigatedUrl}, "TriggeredByInitialUrl", false); +} + // Combo Squatting shouldn't trigger on allowlisted sites and no // UKM should be recorded. IN_PROC_BROWSER_TEST_P(LookalikeUrlNavigationThrottleBrowserTest,
diff --git a/chrome/browser/metrics/chrome_metrics_services_manager_client.cc b/chrome/browser/metrics/chrome_metrics_services_manager_client.cc index 4d4e33b..54ca655 100644 --- a/chrome/browser/metrics/chrome_metrics_services_manager_client.cc +++ b/chrome/browser/metrics/chrome_metrics_services_manager_client.cc
@@ -144,11 +144,10 @@ #if BUILDFLAG(IS_CHROMEOS_ASH) // Callback to update the metrics reporting state when the Chrome OS metrics // reporting setting changes. -void OnCrosMetricsReportingSettingChange() { +void OnCrosMetricsReportingSettingChange( + ChangeMetricsReportingStateCalledFrom called_from) { bool enable_metrics = ash::StatsReportingController::Get()->IsEnabled(); - ChangeMetricsReportingState( - enable_metrics, - ChangeMetricsReportingStateCalledFrom::kCrosMetricsSettingsChange); + ChangeMetricsReportingState(enable_metrics, called_from); // TODO(crbug.com/1234538): This call ensures that structured metrics' state // is deleted when the reporting state is disabled. Long-term this should @@ -243,11 +242,14 @@ #if BUILDFLAG(IS_CHROMEOS_ASH) void ChromeMetricsServicesManagerClient::OnCrosSettingsCreated() { + // Listen for changes to metrics reporting state. reporting_setting_subscription_ = - ash::StatsReportingController::Get()->AddObserver( - base::BindRepeating(&OnCrosMetricsReportingSettingChange)); + ash::StatsReportingController::Get()->AddObserver(base::BindRepeating( + &OnCrosMetricsReportingSettingChange, + ChangeMetricsReportingStateCalledFrom::kCrosMetricsSettingsChange)); // Invoke the callback once initially to set the metrics reporting state. - OnCrosMetricsReportingSettingChange(); + OnCrosMetricsReportingSettingChange( + ChangeMetricsReportingStateCalledFrom::kCrosMetricsSettingsCreated); } #endif
diff --git a/chrome/browser/metrics/metrics_reporting_state.cc b/chrome/browser/metrics/metrics_reporting_state.cc index 05a9ea2..e2407d8 100644 --- a/chrome/browser/metrics/metrics_reporting_state.cc +++ b/chrome/browser/metrics/metrics_reporting_state.cc
@@ -117,9 +117,14 @@ // Chrome OS manages metrics settings externally and changes to reporting // should be propagated to metrics service regardless if the policy is managed // or not. - if (IsMetricsReportingPolicyManaged() && - called_from != - ChangeMetricsReportingStateCalledFrom::kCrosMetricsSettingsChange) { + // TODO(crbug/1346321): Possibly change |is_chrome_os| to use + // BUILDFLAG(IS_CHROMEOS_ASH). + bool is_chrome_os = + (called_from == + ChangeMetricsReportingStateCalledFrom::kCrosMetricsSettingsChange) || + (called_from == + ChangeMetricsReportingStateCalledFrom::kCrosMetricsSettingsCreated); + if (IsMetricsReportingPolicyManaged() && !is_chrome_os) { if (!callback_fn.is_null()) { const bool metrics_enabled = ChromeMetricsServiceAccessor::IsMetricsAndCrashReportingEnabled(); @@ -145,6 +150,15 @@ void UpdateMetricsPrefsOnPermissionChange( bool metrics_enabled, ChangeMetricsReportingStateCalledFrom called_from) { + // On Chrome OS settings creation, nothing should be performed (the metrics + // service is simply being initialized). Otherwise, for users who have + // metrics reporting disabled, their client ID and low entropy sources would + // be cleared on each log in. For users who have metrics reporting enabled, + // their stability metrics and histogram data would be cleared. + if (called_from == + ChangeMetricsReportingStateCalledFrom::kCrosMetricsSettingsCreated) { + return; + } if (metrics_enabled) { // When a user opts in to the metrics reporting service, the previously // collected data should be cleared to ensure that nothing is reported
diff --git a/chrome/browser/metrics/metrics_reporting_state.h b/chrome/browser/metrics/metrics_reporting_state.h index 504d161..d5f1910 100644 --- a/chrome/browser/metrics/metrics_reporting_state.h +++ b/chrome/browser/metrics/metrics_reporting_state.h
@@ -23,6 +23,10 @@ // Called from Chrome OS settings change. Chrome OS manages settings // externally and metrics service listens for changes. kCrosMetricsSettingsChange, + + // Called from Chrome OS on settings creation/initialization. This happens + // once on each log in. + kCrosMetricsSettingsCreated, }; // Changes metrics reporting state without caring about the success of the
diff --git a/chrome/browser/printing/print_browsertest.cc b/chrome/browser/printing/print_browsertest.cc index 9d8d37f..169c73a 100644 --- a/chrome/browser/printing/print_browsertest.cc +++ b/chrome/browser/printing/print_browsertest.cc
@@ -100,8 +100,8 @@ using testing::_; #if BUILDFLAG(ENABLE_OOP_PRINTING) -using OnDidInvokeUseDefaultSettingsCallback = base::RepeatingCallback<void()>; -using OnDidInvokeGetSettingsWithUICallback = base::RepeatingCallback<void()>; +using OnUseDefaultSettingsCallback = base::RepeatingCallback<void()>; +using OnGetSettingsWithUICallback = base::RepeatingCallback<void()>; using ErrorCheckCallback = base::RepeatingCallback<void(mojom::ResultCode result)>; @@ -128,9 +128,8 @@ // Callbacks to run for overrides in `TestPrintJobWorker`. struct TestPrintCallbacks { - OnDidInvokeUseDefaultSettingsCallback - did_invoke_use_default_settings_callback; - OnDidInvokeGetSettingsWithUICallback did_invoke_get_settings_with_ui_callback; + OnUseDefaultSettingsCallback did_use_default_settings_callback; + OnGetSettingsWithUICallback did_get_settings_with_ui_callback; OnStopCallback did_stop_callback; }; @@ -2312,20 +2311,20 @@ ~TestPrintJobWorker() override = default; private: - void InvokeUseDefaultSettings(SettingsCallback callback) override { + void UseDefaultSettings(SettingsCallback callback) override { DVLOG(1) << "Observed: invoke use default settings"; - PrintJobWorker::InvokeUseDefaultSettings(std::move(callback)); - callbacks_->did_invoke_use_default_settings_callback.Run(); + PrintJobWorker::UseDefaultSettings(std::move(callback)); + callbacks_->did_use_default_settings_callback.Run(); } - void InvokeGetSettingsWithUI(uint32_t document_page_count, - bool has_selection, - bool is_scripted, - SettingsCallback callback) override { + void GetSettingsWithUI(uint32_t document_page_count, + bool has_selection, + bool is_scripted, + SettingsCallback callback) override { DVLOG(1) << "Observed: invoke get settings with UI"; - PrintJobWorker::InvokeGetSettingsWithUI(document_page_count, has_selection, - is_scripted, std::move(callback)); - callbacks_->did_invoke_get_settings_with_ui_callback.Run(); + PrintJobWorker::GetSettingsWithUI(document_page_count, has_selection, + is_scripted, std::move(callback)); + callbacks_->did_get_settings_with_ui_callback.Run(); } void Stop() override { @@ -2484,14 +2483,14 @@ &SystemAccessProcessPrintBrowserTestBase::OnDidStop, base::Unretained(this)); } else { - test_print_callbacks_.did_invoke_use_default_settings_callback = - base::BindRepeating(&SystemAccessProcessPrintBrowserTestBase:: - OnDidInvokeUseDefaultSettings, - base::Unretained(this)); - test_print_callbacks_.did_invoke_get_settings_with_ui_callback = - base::BindRepeating(&SystemAccessProcessPrintBrowserTestBase:: - OnDidInvokeGetSettingsWithUI, - base::Unretained(this)); + test_print_callbacks_.did_use_default_settings_callback = + base::BindRepeating( + &SystemAccessProcessPrintBrowserTestBase::OnUseDefaultSettings, + base::Unretained(this)); + test_print_callbacks_.did_get_settings_with_ui_callback = + base::BindRepeating( + &SystemAccessProcessPrintBrowserTestBase::OnGetSettingsWithUI, + base::Unretained(this)); test_print_callbacks_.did_stop_callback = base::BindRepeating( &SystemAccessProcessPrintBrowserTestBase::OnDidStop, base::Unretained(this)); @@ -2629,13 +2628,9 @@ /*cause_errors=*/true); } - bool did_invoke_use_default_settings() const { - return did_invoke_use_default_settings_; - } + bool did_use_default_settings() const { return did_use_default_settings_; } - bool did_invoke_get_settings_with_ui() const { - return did_invoke_get_settings_with_ui_; - } + bool did_get_settings_with_ui() const { return did_get_settings_with_ui_; } bool print_backend_service_use_detected() const { return print_backend_service_use_detected_; @@ -2780,14 +2775,14 @@ } #endif // BUILDFLAG(ENABLE_OOP_PRINTING) - void OnDidInvokeUseDefaultSettings() { - did_invoke_use_default_settings_ = true; + void OnUseDefaultSettings() { + did_use_default_settings_ = true; PrintBackendServiceDetectionCheck(); CheckForQuit(); } - void OnDidInvokeGetSettingsWithUI() { - did_invoke_get_settings_with_ui_ = true; + void OnGetSettingsWithUI() { + did_get_settings_with_ui_ = true; PrintBackendServiceDetectionCheck(); CheckForQuit(); } @@ -2881,8 +2876,8 @@ TestPrintCallbacks test_print_callbacks_; TestPrintOopCallbacks test_print_oop_callbacks_; CreatePrintJobWorkerCallback test_create_print_job_worker_callback_; - bool did_invoke_use_default_settings_ = false; - bool did_invoke_get_settings_with_ui_ = false; + bool did_use_default_settings_ = false; + bool did_get_settings_with_ui_ = false; bool print_backend_service_use_detected_ = false; bool simulate_spooling_memory_errors_ = false; mojo::Remote<mojom::PrintBackendService> test_remote_; @@ -3369,8 +3364,8 @@ WaitUntilCallbackReceived(); - EXPECT_TRUE(did_invoke_use_default_settings()); - EXPECT_TRUE(did_invoke_get_settings_with_ui()); + EXPECT_TRUE(did_use_default_settings()); + EXPECT_TRUE(did_get_settings_with_ui()); EXPECT_TRUE(stop_invoked()); // `PrintBackendService` should never be used when printing in-browser.
diff --git a/chrome/browser/printing/print_job_worker.cc b/chrome/browser/printing/print_job_worker.cc index d9ae000..ab2f824 100644 --- a/chrome/browser/printing/print_job_worker.cc +++ b/chrome/browser/printing/print_job_worker.cc
@@ -144,13 +144,13 @@ } void PrintJobWorker::GetDefaultSettings(SettingsCallback callback) { - DCHECK(task_runner_->RunsTasksInCurrentSequence()); + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_EQ(page_number_, PageNumber::npos()); printing_context_->set_margin_type( printing::mojom::MarginType::kDefaultMargins); - InvokeUseDefaultSettings(std::move(callback)); + UseDefaultSettings(std::move(callback)); } void PrintJobWorker::GetSettingsFromUser(uint32_t document_page_count, @@ -158,40 +158,27 @@ mojom::MarginType margin_type, bool is_scripted, SettingsCallback callback) { - DCHECK(task_runner_->RunsTasksInCurrentSequence()); + DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_EQ(page_number_, PageNumber::npos()); printing_context_->set_margin_type(margin_type); - InvokeGetSettingsWithUI(document_page_count, has_selection, is_scripted, - std::move(callback)); -} - -void PrintJobWorker::SetSettings(base::Value::Dict new_settings, - SettingsCallback callback) { - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - - content::GetUIThreadTaskRunner({})->PostTask( - FROM_HERE, base::BindOnce(&PrintJobWorker::UpdatePrintSettings, - base::Unretained(this), std::move(new_settings), - std::move(callback))); + GetSettingsWithUI(document_page_count, has_selection, is_scripted, + std::move(callback)); } #if BUILDFLAG(IS_CHROMEOS) void PrintJobWorker::SetSettingsFromPOD( std::unique_ptr<PrintSettings> new_settings, SettingsCallback callback) { - DCHECK(task_runner_->RunsTasksInCurrentSequence()); + DCHECK_CURRENTLY_ON(BrowserThread::UI); - content::GetUIThreadTaskRunner({})->PostTask( - FROM_HERE, base::BindOnce(&PrintJobWorker::UpdatePrintSettingsFromPOD, - base::Unretained(this), std::move(new_settings), - std::move(callback))); + UpdatePrintSettingsFromPOD(std::move(new_settings), std::move(callback)); } #endif -void PrintJobWorker::UpdatePrintSettings(base::Value::Dict new_settings, - SettingsCallback callback) { +void PrintJobWorker::SetSettings(base::Value::Dict new_settings, + SettingsCallback callback) { DCHECK_CURRENTLY_ON(BrowserThread::UI); std::unique_ptr<crash_keys::ScopedPrinterInfo> crash_key; @@ -250,23 +237,6 @@ std::move(callback).Run(printing_context_->TakeAndResetSettings(), result); } -void PrintJobWorker::InvokeUseDefaultSettings(SettingsCallback callback) { - content::GetUIThreadTaskRunner({})->PostTask( - FROM_HERE, base::BindOnce(&PrintJobWorker::UseDefaultSettings, - base::Unretained(this), std::move(callback))); -} - -void PrintJobWorker::InvokeGetSettingsWithUI(uint32_t document_page_count, - bool has_selection, - bool is_scripted, - SettingsCallback callback) { - content::GetUIThreadTaskRunner({})->PostTask( - FROM_HERE, - base::BindOnce(&PrintJobWorker::GetSettingsWithUI, base::Unretained(this), - document_page_count, has_selection, is_scripted, - std::move(callback))); -} - void PrintJobWorker::GetSettingsWithUI(uint32_t document_page_count, bool has_selection, bool is_scripted, @@ -312,6 +282,8 @@ } void PrintJobWorker::UseDefaultSettings(SettingsCallback callback) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + mojom::ResultCode result; { #if BUILDFLAG(IS_WIN)
diff --git a/chrome/browser/printing/print_job_worker.h b/chrome/browser/printing/print_job_worker.h index f52f4254..bfa621cf 100644 --- a/chrome/browser/printing/print_job_worker.h +++ b/chrome/browser/printing/print_job_worker.h
@@ -50,22 +50,26 @@ /* The following functions may only be called before calling SetPrintJob(). */ + // Initializes the default print settings. Must be called on the UI thread. void GetDefaultSettings(SettingsCallback callback); - // Initializes the print settings. A Print... dialog box will be shown to ask - // the user their preference. - // `is_scripted` should be true for calls coming straight from window.print(). + // Initializes the print settings. Must be called on the UI thread. A Print... + // dialog box will be shown to ask the user their preference. `is_scripted` + // should be true for calls coming straight from window.print(). void GetSettingsFromUser(uint32_t document_page_count, bool has_selection, mojom::MarginType margin_type, bool is_scripted, SettingsCallback callback); - // Set the new print settings from a dictionary value. - void SetSettings(base::Value::Dict new_settings, SettingsCallback callback); + // Set the new print settings from a dictionary value. Must be called on the + // UI thread. + virtual void SetSettings(base::Value::Dict new_settings, + SettingsCallback callback); #if BUILDFLAG(IS_CHROMEOS) - // Set the new print settings from a POD type. + // Set the new print settings from a POD type. Must be called on the UI + // thread. void SetSettingsFromPOD(std::unique_ptr<printing::PrintSettings> new_settings, SettingsCallback callback); #endif @@ -136,22 +140,23 @@ // Reports settings back to `callback`. void GetSettingsDone(SettingsCallback callback, mojom::ResultCode result); - // Helper functions to invoke the desired way of getting system print - // settings. - virtual void InvokeUseDefaultSettings(SettingsCallback callback); - virtual void InvokeGetSettingsWithUI(uint32_t document_page_count, - bool has_selection, - bool is_scripted, - SettingsCallback callback); - - // Called on the UI thread to update the print settings. - virtual void UpdatePrintSettings(base::Value::Dict new_settings, - SettingsCallback callback); - // Discards the current document, the current page and cancels the printing // context. virtual void OnFailure(); + // Asks the user for print settings. Must be called on the UI thread. + // Required on Mac and Linux. Windows can display UI from non-main threads, + // but sticks with this for consistency. + virtual void GetSettingsWithUI(uint32_t document_page_count, + bool has_selection, + bool is_scripted, + SettingsCallback callback); + + // Use the default settings. When using GTK+ or Mac, this can still end up + // displaying a dialog. So this needs to happen from the UI thread on these + // systems. + virtual void UseDefaultSettings(SettingsCallback callback); + PrintingContext* printing_context() { return printing_context_.get(); } PrintedDocument* document() { return document_.get(); } PrintJob* print_job() { return print_job_; } @@ -168,14 +173,6 @@ bool OnNewPageHelperGdi(); #endif // BUILDFLAG(IS_WIN) - // Asks the user for print settings. Must be called on the UI thread. - // Required on Mac and Linux. Windows can display UI from non-main threads, - // but sticks with this for consistency. - void GetSettingsWithUI(uint32_t document_page_count, - bool has_selection, - bool is_scripted, - SettingsCallback callback); - #if BUILDFLAG(IS_CHROMEOS) // Called on the UI thread to update the print settings. void UpdatePrintSettingsFromPOD( @@ -183,11 +180,6 @@ SettingsCallback callback); #endif - // Use the default settings. When using GTK+ or Mac, this can still end up - // displaying a dialog. So this needs to happen from the UI thread on these - // systems. - void UseDefaultSettings(SettingsCallback callback); - // Printing context delegate. const std::unique_ptr<PrintingContext::Delegate> printing_context_delegate_;
diff --git a/chrome/browser/printing/print_job_worker_oop.cc b/chrome/browser/printing/print_job_worker_oop.cc index 1e158ec..398d59a 100644 --- a/chrome/browser/printing/print_job_worker_oop.cc +++ b/chrome/browser/printing/print_job_worker_oop.cc
@@ -299,23 +299,17 @@ // PrintBackend service. } -void PrintJobWorkerOop::InvokeUseDefaultSettings(SettingsCallback callback) { - content::GetUIThreadTaskRunner({})->PostTask( - FROM_HERE, - base::BindOnce(&PrintJobWorkerOop::SendUseDefaultSettings, - ui_weak_factory_.GetWeakPtr(), std::move(callback))); +void PrintJobWorkerOop::UseDefaultSettings(SettingsCallback callback) { + SendUseDefaultSettings(std::move(callback)); } -void PrintJobWorkerOop::InvokeGetSettingsWithUI(uint32_t document_page_count, - bool has_selection, - bool is_scripted, - SettingsCallback callback) { +void PrintJobWorkerOop::GetSettingsWithUI(uint32_t document_page_count, + bool has_selection, + bool is_scripted, + SettingsCallback callback) { #if BUILDFLAG(IS_WIN) - content::GetUIThreadTaskRunner({})->PostTask( - FROM_HERE, - base::BindOnce(&PrintJobWorkerOop::SendAskUserForSettings, - ui_weak_factory_.GetWeakPtr(), document_page_count, - has_selection, is_scripted, std::move(callback))); + SendAskUserForSettings(document_page_count, has_selection, is_scripted, + std::move(callback)); #else // Invoke the browser version of getting settings with the system UI: // - macOS: It is impossible to invoke a system dialog UI from a service @@ -326,13 +320,13 @@ // browser process. // - Other platforms don't have a system print UI or do not use OOP // printing, so this does not matter. - PrintJobWorker::InvokeGetSettingsWithUI(document_page_count, has_selection, - is_scripted, std::move(callback)); + PrintJobWorker::GetSettingsWithUI(document_page_count, has_selection, + is_scripted, std::move(callback)); #endif } -void PrintJobWorkerOop::UpdatePrintSettings(base::Value::Dict new_settings, - SettingsCallback callback) { +void PrintJobWorkerOop::SetSettings(base::Value::Dict new_settings, + SettingsCallback callback) { DCHECK_CURRENTLY_ON(BrowserThread::UI); // Do not take a const reference, as `new_settings` will be modified below.
diff --git a/chrome/browser/printing/print_job_worker_oop.h b/chrome/browser/printing/print_job_worker_oop.h index fe03920..87d655ac 100644 --- a/chrome/browser/printing/print_job_worker_oop.h +++ b/chrome/browser/printing/print_job_worker_oop.h
@@ -68,13 +68,13 @@ #endif bool SpoolDocument() override; void OnDocumentDone() override; - void InvokeUseDefaultSettings(SettingsCallback callback) override; - void InvokeGetSettingsWithUI(uint32_t document_page_count, - bool has_selection, - bool is_scripted, - SettingsCallback callback) override; - void UpdatePrintSettings(base::Value::Dict new_settings, - SettingsCallback callback) override; + void UseDefaultSettings(SettingsCallback callback) override; + void GetSettingsWithUI(uint32_t document_page_count, + bool has_selection, + bool is_scripted, + SettingsCallback callback) override; + void SetSettings(base::Value::Dict new_settings, + SettingsCallback callback) override; void OnFailure() override; // Show the print error dialog, virtual to support testing.
diff --git a/chrome/browser/printing/printer_query.cc b/chrome/browser/printing/printer_query.cc index 9bee269b..d214a24 100644 --- a/chrome/browser/printing/printer_query.cc +++ b/chrome/browser/printing/printer_query.cc
@@ -122,13 +122,9 @@ // Real work is done in PrintJobWorker::GetDefaultSettings(). is_print_dialog_box_shown_ = false; // `this` is owned by `callback`, so `base::Unretained()` is safe. - worker_->PostTask( - FROM_HERE, - base::BindOnce(&PrintJobWorker::GetDefaultSettings, - base::Unretained(worker_.get()), - base::BindOnce(&PrinterQuery::PostSettingsDone, - base::Unretained(this), std::move(callback), - is_modifiable))); + worker_->GetDefaultSettings( + base::BindOnce(&PrinterQuery::PostSettingsDone, base::Unretained(this), + std::move(callback), is_modifiable)); } void PrinterQuery::GetSettingsFromUser(uint32_t expected_page_count, @@ -145,14 +141,10 @@ // Real work is done in PrintJobWorker::GetSettingsFromUser(). is_print_dialog_box_shown_ = true; // `this` is owned by `callback`, so `base::Unretained()` is safe. - worker_->PostTask( - FROM_HERE, - base::BindOnce(&PrintJobWorker::GetSettingsFromUser, - base::Unretained(worker_.get()), expected_page_count, - has_selection, margin_type, is_scripted, - base::BindOnce(&PrinterQuery::PostSettingsDone, - base::Unretained(this), std::move(callback), - is_modifiable))); + worker_->GetSettingsFromUser( + expected_page_count, has_selection, margin_type, is_scripted, + base::BindOnce(&PrinterQuery::PostSettingsDone, base::Unretained(this), + std::move(callback), is_modifiable)); } void PrinterQuery::SetSettings(base::Value::Dict new_settings, @@ -161,13 +153,11 @@ StartWorker(); // `this` is owned by `callback`, so `base::Unretained()` is safe. - worker_->PostTask( - FROM_HERE, - base::BindOnce(&PrintJobWorker::SetSettings, - base::Unretained(worker_.get()), std::move(new_settings), - base::BindOnce(&PrinterQuery::PostSettingsDone, - base::Unretained(this), std::move(callback), - /*maybe_is_modifiable=*/absl::nullopt))); + worker_->SetSettings( + std::move(new_settings), + base::BindOnce(&PrinterQuery::PostSettingsDone, base::Unretained(this), + std::move(callback), + /*maybe_is_modifiable=*/absl::nullopt)); } #if BUILDFLAG(IS_CHROMEOS) @@ -178,13 +168,11 @@ StartWorker(); // `this` is owned by `callback`, so `base::Unretained()` is safe. - worker_->PostTask( - FROM_HERE, - base::BindOnce(&PrintJobWorker::SetSettingsFromPOD, - base::Unretained(worker_.get()), std::move(new_settings), - base::BindOnce(&PrinterQuery::PostSettingsDone, - base::Unretained(this), std::move(callback), - /*maybe_is_modifiable=*/absl::nullopt))); + worker_->SetSettingsFromPOD( + std::move(new_settings), + base::BindOnce(&PrinterQuery::PostSettingsDone, base::Unretained(this), + std::move(callback), + /*maybe_is_modifiable=*/absl::nullopt)); } #endif
diff --git a/chrome/browser/reputation/local_heuristics.cc b/chrome/browser/reputation/local_heuristics.cc index 181581f..581267a 100644 --- a/chrome/browser/reputation/local_heuristics.cc +++ b/chrome/browser/reputation/local_heuristics.cc
@@ -111,6 +111,7 @@ reputation::HeuristicLaunchConfig::HEURISTIC_CHARACTER_SWAP_TOP_SITES, navigated_domain.domain_and_registry, chrome::GetChannel()); case LookalikeUrlMatchType::kComboSquatting: + case LookalikeUrlMatchType::kComboSquattingSiteEngagement: return false; case LookalikeUrlMatchType::kNone: NOTREACHED();
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/range_automation_handler.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/range_automation_handler.js index 21d26aa..9c38219 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/range_automation_handler.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/range_automation_handler.js
@@ -23,9 +23,7 @@ const RoleType = chrome.automation.RoleType; const StateType = chrome.automation.StateType; -/** - * @implements {ChromeVoxStateObserver} - */ +/** @implements {ChromeVoxStateObserver} */ export class RangeAutomationHandler extends BaseAutomationHandler { /** @private */ constructor() { @@ -113,9 +111,7 @@ this.addListener_(EventType.SORT_CHANGED, this.onAriaAttributeChanged); } - /** - * @param {!ChromeVoxEvent} evt - */ + /** @param {!ChromeVoxEvent} evt */ onEventIfInRange(evt) { if (BaseAutomationHandler.disallowEventFromAction(evt)) { return; @@ -161,9 +157,7 @@ } } - /** - * @param {!ChromeVoxEvent} evt - */ + /** @param {!ChromeVoxEvent} evt */ onAriaAttributeChanged(evt) { // Don't report changes on editable nodes since they interfere with text // selection changes. Users can query via Search+k for the current state
diff --git a/chrome/browser/resources/chromeos/network_ui/network_ui.html b/chrome/browser/resources/chromeos/network_ui/network_ui.html index df669e2..4e50692 100644 --- a/chrome/browser/resources/chromeos/network_ui/network_ui.html +++ b/chrome/browser/resources/chromeos/network_ui/network_ui.html
@@ -8,7 +8,9 @@ } #global-policy, - #tethering-capabilities-div { + #tethering-capabilities-div, + #tethering-status-div, + #tethering-config-div { white-space: pre-wrap; } @@ -22,6 +24,11 @@ margin: 10px 0 } + #tethering-config-input { + margin-bottom: 0; + margin-top: 10px; + } + iron-pages { flex: 1; position: relative; @@ -149,6 +156,28 @@ <cr-button class="action-button" on-click="getTetheringCapabilities_"> $i18n{refreshTetheringCapabilitiesButtonText} </cr-button> + + <h2>$i18n{tetheringStatusLabel}</h2> + <div id="tethering-status-div"></div> + <cr-button class="action-button" on-click="getTetheringStatus_"> + $i18n{refreshTetheringStatusButtonText} + </cr-button> + + <h2>$i18n{tetheringConfigLabel}</h2> + <div id="tethering-config-div"></div> + <cr-button class="action-button" on-click="getTetheringConfig_"> + $i18n{refreshTetheringConfigButtonText} + </cr-button> + <cr-input id="tethering-config-input" value="{{tetheringConfigToSet_}}" + placeholder="{}" type="text" on-input="validateJSON_" + error-message="Please enter valid JSON object" + invalid="[[invalidJSON_]]"> + </cr-input> + <cr-button class="action-button" on-click="setTetheringConfig_" + disabled="[[invalidJSON_]]"> + $i18n{setTetheringConfigButtonText} + </cr-button> + <div id="set-tethering-config-result"></div> </div> <template> </iron-pages>
diff --git a/chrome/browser/resources/chromeos/network_ui/network_ui.js b/chrome/browser/resources/chromeos/network_ui/network_ui.js index 11451c3..4eff0283 100644 --- a/chrome/browser/resources/chromeos/network_ui/network_ui.js +++ b/chrome/browser/resources/chromeos/network_ui/network_ui.js
@@ -74,6 +74,12 @@ }, /** @private */ + tetheringConfigToSet_: { + type: String, + value: '', + }, + + /** @private */ isGuestModeActive_: { type: Boolean, value() { @@ -90,6 +96,13 @@ loadTimeData.getBoolean('isHotspotEnabled'); }, }, + + /** @private */ + invalidJSON_: { + type: Boolean, + value: false, + }, + }, /** @type {?chromeos.networkConfig.mojom.CrosNetworkConfigRemote} */ @@ -116,6 +129,8 @@ this.requestGlobalPolicy_(); this.getTetheringCapabilities_(); + this.getTetheringConfig_(); + this.getTetheringStatus_(); this.getHostname_(); this.selectTabFromHash_(); window.addEventListener('hashchange', () => { @@ -123,6 +138,15 @@ }); }, + /** + * @param {*} result that need to stringify to JSON + * @return {string} + * @private + */ + stringifyJSON_(result) { + return JSON.stringify(result, null, '\t'); + }, + /** @private */ selectTabFromHash_() { const selectedTab = window.location.hash.substring(1); @@ -211,7 +235,7 @@ requestGlobalPolicy_() { this.networkConfig_.getGlobalPolicy().then(result => { this.$$('#global-policy').textContent = - JSON.stringify(result.result, null, '\t'); + this.stringifyJSON_(result.result); }); }, @@ -219,10 +243,63 @@ getTetheringCapabilities_() { this.browserProxy_.getTetheringCapabilities().then(result => { this.$$('#tethering-capabilities-div').textContent = - JSON.stringify(result, null, '\t'); + this.stringifyJSON_(result); }); }, + /** @private */ + getTetheringStatus_() { + this.browserProxy_.getTetheringStatus().then(result => { + this.$$('#tethering-status-div').textContent = + this.stringifyJSON_(result); + }); + }, + + /** @private */ + getTetheringConfig_() { + this.browserProxy_.getTetheringConfig().then(result => { + this.$$('#tethering-config-div').textContent = + this.stringifyJSON_(result); + }); + }, + + /** @private */ + setTetheringConfig_() { + this.browserProxy_.setTetheringConfig(this.tetheringConfigToSet_) + .then((result) => { + const success = result === 'success'; + const resultDiv = this.$$('#set-tethering-config-result'); + resultDiv.innerText = result; + resultDiv.classList.toggle('error', !success); + if (success) { + this.getTetheringConfig_(); + } + }); + }, + + /** + * Check if the input tethering config string is a valid JSON object. + * @private + */ + validateJSON_() { + if (this.tetheringConfigToSet_ === '') { + this.invalidJSON_ = false; + return; + } + + try { + const parsed = JSON.parse(this.tetheringConfigToSet_); + // Check if the parsed JSON is object type by its constructor + if (parsed.constructor === ({}).constructor) { + this.invalidJSON_ = false; + return; + } + this.invalidJSON_ = true; + } catch (e) { + this.invalidJSON_ = true; + } + }, + /** * @param {!Event} event * @private
diff --git a/chrome/browser/resources/chromeos/network_ui/network_ui_browser_proxy.js b/chrome/browser/resources/chromeos/network_ui/network_ui_browser_proxy.js index aaea2aa..01a74b7 100644 --- a/chrome/browser/resources/chromeos/network_ui/network_ui_browser_proxy.js +++ b/chrome/browser/resources/chromeos/network_ui/network_ui_browser_proxy.js
@@ -82,6 +82,22 @@ * @return {Promise<string>} */ getTetheringCapabilities() {} + + /** + * @return {Promise<string>} + */ + getTetheringStatus() {} + + /** + * @return {Promise<string>} + */ + getTetheringConfig() {} + + /** + * @param {string} config + * @return {Promise<string>} + */ + setTetheringConfig(config) {} } /** @@ -183,6 +199,28 @@ getTetheringCapabilities() { return sendWithPromise('getTetheringCapabilities'); } + + /** + * @return {Promise<string>} + */ + getTetheringStatus() { + return sendWithPromise('getTetheringStatus'); + } + + /** + * @return {Promise<string>} + */ + getTetheringConfig() { + return sendWithPromise('getTetheringConfig'); + } + + /** + * @param {string} config + * @return {Promise<string>} + */ + setTetheringConfig(config) { + return sendWithPromise('setTetheringConfig', config); + } } addSingletonGetter(NetworkUIBrowserProxyImpl);
diff --git a/chrome/browser/resources/settings/chromeos/BUILD.gn b/chrome/browser/resources/settings/chromeos/BUILD.gn index 45864fa..ff1a8398 100644 --- a/chrome/browser/resources/settings/chromeos/BUILD.gn +++ b/chrome/browser/resources/settings/chromeos/BUILD.gn
@@ -7,17 +7,19 @@ import("//tools/grit/grit_rule.gni") import("//tools/grit/preprocess_if_expr.gni") import("//tools/polymer/html_to_js.gni") +import("//tools/typescript/ts_library.gni") import("//ui/webui/resources/tools/generate_grd.gni") import("//ui/webui/webui_features.gni") import("../../tools/optimize_webui.gni") import("./os_settings.gni") -assert(is_chromeos_ash) +assert(is_chromeos_ash, "ChromeOS Settings is ChromeOS only") # root_gen_dir is "gen" # target_gen_dir is "gen/chrome/browser/resources/settings/chromeos" preprocessed_folder = "preprocessed" +preprocessed_ts_folder = "preprocessed_ts" web_components_manifest = "web_components_manifest.json" non_web_component_files_manifest = "non_web_component_files_manifest.json" browser_settings_tsc_manifest = "browser_settings_tsc_manifest.json" @@ -27,7 +29,7 @@ if (optimize_webui) { build_manifest_v3 = "build_v3_manifest.json" - optimize_webui("build_polymer3") { + optimize_webui("optimize_bundle") { host = "os-settings" input = rebase_path("$target_gen_dir/$preprocessed_folder", root_build_dir) js_module_in_files = [ @@ -42,6 +44,7 @@ out_manifest = "$target_gen_dir/$build_manifest_v3" deps = [ + ":build_ts", ":preprocess_browser_settings_tsc", ":preprocess_mojo_webui", ":preprocess_non_web_component_files", @@ -95,6 +98,42 @@ } } +# TypeScript Build Configuration +# TODO(crbug/1315757) Gradually remove JS files from preprocess_web_components +# and preprocess_non_web_component_files, and add them as input files here. +# Eventually, ts_library() will be the only build path for all JS/TS files. +# Any JS file in passed into this build rule is elligble to be converted to TS. +ts_library("build_ts") { + tsconfig_base = "tsconfig_base.json" + deps = [ + "//third_party/polymer/v3_0:library", + "//ui/webui/resources:library", + ] + extra_deps = [ + ":preprocess_ts_non_web_component_files", + ":preprocess_ts_web_components", + ] + definitions = [ "//tools/typescript/definitions/chrome_send.d.ts" ] + root_dir = "$target_gen_dir/$preprocessed_ts_folder" + in_files = ts_non_web_component_files + ts_web_component_files + out_dir = "$target_gen_dir/$preprocessed_folder" +} + +preprocess_if_expr("preprocess_ts_non_web_component_files") { + defines = chrome_grit_defines + in_folder = "../" + in_files = ts_non_web_component_files + out_folder = "$target_gen_dir/$preprocessed_ts_folder" +} + +preprocess_if_expr("preprocess_ts_web_components") { + defines = chrome_grit_defines + deps = [ ":generate_web_components" ] + in_folder = get_path_info("../", "gen_dir") + in_files = ts_web_component_files + out_folder = "$target_gen_dir/$preprocessed_ts_folder" +} + # Preprocess all WebUI mojom files, which are bundled in optimized builds. preprocess_if_expr("preprocess_mojo_webui") { deps = [ @@ -264,7 +303,7 @@ ] if (optimize_webui) { - deps += [ ":build_polymer3" ] + deps += [ ":optimize_bundle" ] manifest_files += [ "$target_gen_dir/$build_manifest_v3" ] input_files += [ "../../nearby_share/shared/nearby_shared_icons.html" ] resource_path_rewrites += [ @@ -276,6 +315,7 @@ ] } else { deps += [ + ":build_ts", ":preprocess_browser_settings_tsc", ":preprocess_mojo_webui", ":preprocess_non_web_component_files", @@ -289,6 +329,7 @@ "$target_gen_dir/$non_web_component_files_manifest", "$target_gen_dir/$browser_settings_tsc_manifest", "$target_gen_dir/$mojo_webui_manifest", + "$target_gen_dir/build_ts.manifest", ] resource_path_rewrites += [ "chromeos/os_settings.html|os_settings.html" ] } @@ -300,20 +341,8 @@ out_folder = "$target_gen_dir/$preprocessed_folder" out_manifest = "$target_gen_dir/$non_web_component_files_manifest" in_files = [ - "chromeos/deep_linking_behavior.js", - "chromeos/metrics_recorder.js", - "chromeos/os_settings_routes.js", - "chromeos/route_origin_behavior.js", - "chromeos/combined_search_handler.js", - "chromeos/personalization_search_handler.js", - "chromeos/settings_search_handler.js", - "chromeos/os_route.js", - "chromeos/os_page_visibility.js", "chromeos/os_people_page/lock_state_behavior.js", "chromeos/os_people_page/os_sync_browser_proxy.js", - "chromeos/pref_to_setting_metric_converter.js", - "chromeos/ensure_lazy_loaded.js", - "chromeos/lazy_load.js", "chromeos/crostini_page/crostini_browser_proxy.js", "chromeos/date_time_page/date_time_types.js", "chromeos/date_time_page/timezone_browser_proxy.js", @@ -321,7 +350,6 @@ "chromeos/device_page/device_page_browser_proxy.js", "chromeos/device_page/drag_behavior.js", "chromeos/device_page/layout_behavior.js", - "chromeos/global_scroll_target_behavior.js", "chromeos/google_assistant_page/google_assistant_browser_proxy.js", "chromeos/guest_os/guest_os_browser_proxy.js", "chromeos/os_privacy_page/privacy_hub_browser_proxy.js", @@ -377,19 +405,15 @@ "chromeos/os_about_page/device_name_browser_proxy.js", "chromeos/os_about_page/device_name_util.js", "chromeos/os_reset_page/os_reset_browser_proxy.js", - "chromeos/os_settings.js", "chromeos/parental_controls_page/parental_controls_browser_proxy.js", "chromeos/personalization_page/change_picture_browser_proxy.js", "chromeos/personalization_page/personalization_hub_browser_proxy.js", "chromeos/personalization_page/wallpaper_browser_proxy.js", - "chromeos/prefs_behavior.js", "chromeos/os_privacy_page/peripheral_data_access_browser_proxy.js", "chromeos/os_privacy_page/metrics_consent_browser_proxy.js", "chromeos/os_people_page/account_manager_browser_proxy.js", - "chromeos/route_observer_behavior.js", "chromeos/ambient_mode_page/ambient_mode_browser_proxy.js", "chromeos/ambient_mode_page/constants.js", - "router.js", ] } @@ -430,8 +454,8 @@ "site_favicon.js", ] + # Files that don't have a corresponding HTML file. in_files = [ - # Files that don't have a corresponding HTML file. "appearance_page/fonts_browser_proxy.js", "controls/cr_policy_pref_mixin.js", "controls/pref_control_mixin.js", @@ -619,7 +643,6 @@ "chromeos/os_bluetooth_page/settings_fast_pair_toggle.js", "chromeos/os_files_page/os_files_page.js", "chromeos/os_files_page/smb_shares_page.js", - "chromeos/os_icons.js", "chromeos/os_languages_page/add_input_methods_dialog.js", "chromeos/os_languages_page/add_items_dialog.js", "chromeos/os_languages_page/add_spellcheck_languages_dialog.js", @@ -671,7 +694,6 @@ "chromeos/os_search_page/os_search_selection_dialog.js", "chromeos/os_search_page/search_engine.js", "chromeos/os_search_page/search_subpage.js", - "chromeos/os_settings_icons_css.js", "chromeos/os_settings_main/os_settings_main.js", "chromeos/os_settings_menu/os_settings_menu.js", "chromeos/os_settings_page/os_settings_page.js",
diff --git a/chrome/browser/resources/settings/chromeos/device_page/audio.html b/chrome/browser/resources/settings/chromeos/device_page/audio.html index 1238065..a65bfd5 100644 --- a/chrome/browser/resources/settings/chromeos/device_page/audio.html +++ b/chrome/browser/resources/settings/chromeos/device_page/audio.html
@@ -1,4 +1,18 @@ <style include="settings-shared"> + .audio-mute-button { + margin-inline-end: var(--settings-control-label-spacing); + } + + .audio-mute-button-container { + border-inline-end: 1px solid var(--cros-app-shield-color); + margin-inline-end: var(--settings-control-label-spacing); + } + + .audio-output-options-container { + display: flex; + flex-direction: row; + } + .audio-output-slider { width: 100px; } @@ -25,6 +39,30 @@ padding-inline-end: 0; padding-inline-start: 0; } + + :host([is-output-muted_]) #outputVolumeSlider { + --cr-slider-active-color: var(--cros-slider-color-inactive); + --cr-slider-container-color: var(--cros-slider-track-color-inactive); + --cr-slider-knob-color-rgb: var(--cros-color-primary-rgb); + } + + :host([is-output-muted_]) #audioOutputMuteButton { + --cr-icon-button-fill-color: var(--cros-color-prominent); + background-color: var(--cros-ripple-color-prominent); + } + + :host([is-output-muted_]) #audioOutputMuteButton:hover { + --cr-icon-button-fill-color: var(--cros-color-prominent); + background-color: var(--cros-highlight-color); + } + + :host(:not([is-output-muted_])) #audioOutputMuteButton { + --cr-icon-button-fill-color: var(--cros-color-primary); + } + + :host(:not([is-output-muted_])) #audioOutputMuteButton:hover { + --cr-icon-button-fill-color: var(--cros-color-primary); + } </style> <!-- Output section --> @@ -36,22 +74,31 @@ <div class="start settings-box-text" id="audioOutputVolumeLabel"> $i18n{audioVolumeTitle} </div> - <div class="audio-slider-wrapper" id="audioOutputSliderWrapper"> - <iron-icon id="audioOutputSliderVolumeDownIcon" - icon="settings:volume-down"> - </iron-icon> - <cr-slider class="audio-output-slider" - id ="outputVolumeSlider" - min="0" - max="100" - disabled="[[isOutputVolumeSliderDisabled_( - audioSystemProperties_.outputMuteState - )]]" - value="[[audioSystemProperties_.outputVolumePercent]]"> - </cr-slider> - <iron-icon id="audioOutputSliderVolumeUpIcon" - icon="settings:volume-up"> - </iron-icon> + <!-- TODO(crbug.com/1092970): Update to new UI once approved. --> + <div class="audio-output-options-container"> + <div class="audio-mute-button-container"> + <cr-icon-button class="audio-mute-button" + id="audioOutputMuteButton" iron-icon="settings:volume-up-off"> + </cr-icon-button> + </div> + <div class="audio-slider-wrapper" id="audioOutputSliderWrapper"> + <!-- TODO(crbug.com/1092970): Change icons to buttons. --> + <iron-icon id="audioOutputSliderVolumeDownIcon" + icon="settings:volume-down"> + </iron-icon> + <cr-slider class="audio-output-slider" + id ="outputVolumeSlider" + min="0" + max="100" + disabled="[[isOutputVolumeSliderDisabled_( + audioSystemProperties_.outputMuteState + )]]" + value="[[audioSystemProperties_.outputVolumePercent]]"> + </cr-slider> + <iron-icon id="audioOutputSliderVolumeUpIcon" + icon="settings:volume-up"> + </iron-icon> + </div> </div> </div> </div>
diff --git a/chrome/browser/resources/settings/chromeos/device_page/audio.js b/chrome/browser/resources/settings/chromeos/device_page/audio.js index 2c41bd0..457f5fa6 100644 --- a/chrome/browser/resources/settings/chromeos/device_page/audio.js +++ b/chrome/browser/resources/settings/chromeos/device_page/audio.js
@@ -52,6 +52,12 @@ audioSystemProperties_: { type: Object, }, + + /** @protected */ + isOutputMuted_: { + type: Boolean, + reflectToAttribute: true, + }, }; } @@ -79,6 +85,19 @@ */ onPropertiesUpdated(properties) { this.audioSystemProperties_ = properties; + + // TODO(crbug.com/1092970): Create and show managed by policy badge if + // kMutedByPolicy. + this.isOutputMuted_ = + this.audioSystemProperties_.outputMuteState !== MuteState.kNotMuted; + } + + /** + * @public + * @return {boolean} + */ + getIsOutputMutedForTest() { + return this.isOutputMuted_; } /** @protected */ @@ -88,8 +107,11 @@ .bindNewPipeAndPassRemote()); } - // TODO(crbug.com/1092970): Create onCrSliderChanged method for setting output - // volume. + // TODO(crbug.com/1092970): Create onCrSliderChanged_ method for setting + // output volume. + + // TODO(crbug.com/1092970): Create onOutputMuteTap_ method for setting output + // mute state. /** * @protected
diff --git a/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_permissions_setup_dialog.js b/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_permissions_setup_dialog.js index f8e9ecbc02..f4ad5e29 100644 --- a/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_permissions_setup_dialog.js +++ b/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_permissions_setup_dialog.js
@@ -47,6 +47,8 @@ NOTIFICATION_ACCESS_PROHIBITED: 6, COMPLETED_USER_REJECTED: 7, FAILED_OR_CANCELLED: 8, + CAMERA_ROLL_GRANTED_NOTIFICATION_REJECTED: 9, + CAMERA_ROLL_REJECTED_NOTIFICATION_GRANTED: 10, }; /** @@ -409,9 +411,10 @@ // COMPLETED_USER_REJECTED we should continue on with the setup flow if // there are additional features, all other results will change the screen // that is shown and pause or terminate the setup flow. - if (combinedSetupResult !== PermissionsSetupStatus.COMPLETED_SUCCESSFULLY && - combinedSetupResult !== - PermissionsSetupStatus.COMPLETED_USER_REJECTED) { + if (this.terminateCombinedSetup_(combinedSetupResult)) { + if (combinedSetupResult === PermissionsSetupStatus.FAILED_OR_CANCELLED) { + this.updateCamearRollSetupResultIfNeeded_(); + } this.setupState_ = combinedSetupResult; return; } @@ -420,17 +423,18 @@ // this.completeMode_. Otherwise, we cannot use the final // this.completedMode_ to determine the completed title. if (combinedSetupResult === PermissionsSetupStatus.COMPLETED_SUCCESSFULLY) { - if (this.setupMode_ & CAMERA_ROLL_FEATURE && !this.showCameraRoll) { - this.completedMode_ |= CAMERA_ROLL_FEATURE; - this.browserProxy_.setFeatureEnabledState( - MultiDeviceFeature.PHONE_HUB_CAMERA_ROLL, true); - } + this.updateCamearRollSetupResultIfNeeded_(); + this.updateNotificationsSetupResultIfNeeded_(); + } - if (this.setupMode_ & NOTIFICATION_FEATURE && !this.showNotifications) { - this.completedMode_ |= NOTIFICATION_FEATURE; - this.browserProxy_.setFeatureEnabledState( - MultiDeviceFeature.PHONE_HUB_NOTIFICATIONS, true); - } + if (combinedSetupResult === + PermissionsSetupStatus.CAMERA_ROLL_GRANTED_NOTIFICATION_REJECTED) { + this.updateCamearRollSetupResultIfNeeded_(); + } + + if (combinedSetupResult === + PermissionsSetupStatus.CAMERA_ROLL_REJECTED_NOTIFICATION_GRANTED) { + this.updateNotificationsSetupResultIfNeeded_(); } if (this.showAppStreaming) { @@ -450,6 +454,54 @@ } /** + * @param {!PermissionsSetupStatus} combinedSetupResult + * @return {boolean} + * @private + */ + terminateCombinedSetup_(combinedSetupResult) { + switch (combinedSetupResult) { + case PermissionsSetupStatus.COMPLETED_SUCCESSFULLY: + case PermissionsSetupStatus.COMPLETED_USER_REJECTED: + case PermissionsSetupStatus.CAMERA_ROLL_GRANTED_NOTIFICATION_REJECTED: + case PermissionsSetupStatus.CAMERA_ROLL_REJECTED_NOTIFICATION_GRANTED: + return false; + case PermissionsSetupStatus.CONNECTION_REQUESTED: + case PermissionsSetupStatus.CONNECTING: + case PermissionsSetupStatus.TIMED_OUT_CONNECTING: + case PermissionsSetupStatus.CONNECTION_DISCONNECTED: + case PermissionsSetupStatus + .SENT_MESSAGE_TO_PHONE_AND_WAITING_FOR_RESPONSE: + case PermissionsSetupStatus.NOTIFICATION_ACCESS_PROHIBITED: + case PermissionsSetupStatus.FAILED_OR_CANCELLED: + return true; + default: + return true; + } + } + + /** + * @private + */ + updateCamearRollSetupResultIfNeeded_() { + if (this.setupMode_ & CAMERA_ROLL_FEATURE && !this.showCameraRoll) { + this.completedMode_ |= CAMERA_ROLL_FEATURE; + this.browserProxy_.setFeatureEnabledState( + MultiDeviceFeature.PHONE_HUB_CAMERA_ROLL, true); + } + } + + /** + * @private + */ + updateNotificationsSetupResultIfNeeded_() { + if (this.setupMode_ & NOTIFICATION_FEATURE && !this.showNotifications) { + this.completedMode_ |= NOTIFICATION_FEATURE; + this.browserProxy_.setFeatureEnabledState( + MultiDeviceFeature.PHONE_HUB_NOTIFICATIONS, true); + } + } + + /** * @return {boolean} * @private */ @@ -483,7 +535,11 @@ computeHasCompletedSetup_() { return this.setupState_ === PermissionsSetupStatus.COMPLETED_SUCCESSFULLY || this.setupState_ === PermissionsSetupStatus.COMPLETED_USER_REJECTED || - this.setupState_ === PermissionsSetupStatus.FAILED_OR_CANCELLED; + this.setupState_ === PermissionsSetupStatus.FAILED_OR_CANCELLED || + this.setupState_ === + PermissionsSetupStatus.CAMERA_ROLL_GRANTED_NOTIFICATION_REJECTED || + this.setupState_ === + PermissionsSetupStatus.CAMERA_ROLL_REJECTED_NOTIFICATION_GRANTED; } /** @@ -634,6 +690,8 @@ case Status.COMPLETED_SUCCESSFULLY: case Status.COMPLETED_USER_REJECTED: case Status.FAILED_OR_CANCELLED: + case Status.CAMERA_ROLL_GRANTED_NOTIFICATION_REJECTED: + case Status.CAMERA_ROLL_REJECTED_NOTIFICATION_GRANTED: return PhoneHubPermissionsSetupFlowScreens.CONNECTED; case Status.TIMED_OUT_CONNECTING: return PhoneHubPermissionsSetupFlowScreens.CONNECTION_TIME_OUT; @@ -666,6 +724,8 @@ case Status.COMPLETED_SUCCESSFULLY: case Status.COMPLETED_USER_REJECTED: case Status.FAILED_OR_CANCELLED: + case Status.CAMERA_ROLL_GRANTED_NOTIFICATION_REJECTED: + case Status.CAMERA_ROLL_REJECTED_NOTIFICATION_GRANTED: return this.getSetupCompleteTitle_(); case Status.TIMED_OUT_CONNECTING: return this.i18n( @@ -699,6 +759,8 @@ case Status.COMPLETED_SUCCESSFULLY: case Status.COMPLETED_USER_REJECTED: case Status.FAILED_OR_CANCELLED: + case Status.CAMERA_ROLL_GRANTED_NOTIFICATION_REJECTED: + case Status.CAMERA_ROLL_REJECTED_NOTIFICATION_GRANTED: return (this.setupMode_ === this.completedMode_) ? '' : this.i18n( @@ -740,7 +802,11 @@ this.setupState_ !== PermissionsSetupStatus.COMPLETED_USER_REJECTED && this.setupState_ !== PermissionsSetupStatus.FAILED_OR_CANCELLED && this.setupState_ !== - PermissionsSetupStatus.NOTIFICATION_ACCESS_PROHIBITED; + PermissionsSetupStatus.NOTIFICATION_ACCESS_PROHIBITED && + this.setupState_ !== + PermissionsSetupStatus.CAMERA_ROLL_GRANTED_NOTIFICATION_REJECTED && + this.setupState_ !== + PermissionsSetupStatus.CAMERA_ROLL_REJECTED_NOTIFICATION_GRANTED; } /**
diff --git a/chrome/browser/resources/settings/chromeos/os_about_page/about_page_browser_proxy.js b/chrome/browser/resources/settings/chromeos/os_about_page/about_page_browser_proxy.js index 88112f3..ab0498ed 100644 --- a/chrome/browser/resources/settings/chromeos/os_about_page/about_page_browser_proxy.js +++ b/chrome/browser/resources/settings/chromeos/os_about_page/about_page_browser_proxy.js
@@ -86,6 +86,7 @@ DISABLED: 'disabled', DISABLED_BY_ADMIN: 'disabled_by_admin', NEED_PERMISSION_TO_UPDATE: 'need_permission_to_update', + DEFERRED: 'deferred', }; /** @@ -146,6 +147,11 @@ /** @interface */ export class AboutPageBrowserProxy { /** + * Applies deferred update if it exists. + */ + applyDeferredUpdate() {} + + /** * Indicates to the browser that the page is ready. */ pageReady() {} @@ -270,6 +276,11 @@ } /** @override */ + applyDeferredUpdate() { + chrome.send('applyDeferredUpdate'); + } + + /** @override */ pageReady() { chrome.send('aboutPageReady'); }
diff --git a/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.html b/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.html index d929683..f84711d 100644 --- a/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.html +++ b/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.html
@@ -65,6 +65,11 @@ margin-inline-end: -4px; margin-inline-start: 12px; } + + #deferredUpdateButtons { + min-height: unset; + padding-bottom: 10px; + } </style> <iron-media-query query="(prefers-color-scheme: dark)" query-matches="{{isDarkModeActive_}}"> @@ -128,6 +133,18 @@ </cr-button> </span> </div> + <div id="deferredUpdateButtons" class="settings-box first" + hidden="[[!hasDeferredUpdate_]]"> + <div class="icon-container"></div> + <cr-button id="applyDeferredUpdate" + on-click="onApplyDeferredUpdateClick_"> + $i18n{aboutRelaunch} + </cr-button> + <cr-button id="applyAndSetAutoUpdate" + on-click="onApplyAndSetAutoUpdateClick_"> + $i18n{aboutRelaunchAndAutoUpdate} + </cr-button> + </div> <cr-link-row id="aboutTPMFirmwareUpdate" class="hr"
diff --git a/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.js b/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.js index 95e9936d..3ec8ebe 100644 --- a/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.js +++ b/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.js
@@ -147,6 +147,12 @@ }, /** @private */ + hasDeferredUpdate_: { + type: Boolean, + value: false, + }, + + /** @private */ eolMessageWithMonthAndYear_: { type: String, value: '', @@ -376,6 +382,7 @@ this.showUpdateWarningDialog_ = true; this.updateInfo_ = {version: event.version, size: event.size}; } + this.hasDeferredUpdate_ = (event.status === UpdateStatus.DEFERRED); this.currentUpdateStatusEvent_ = event; } @@ -541,6 +548,8 @@ return this.i18nAdvanced('aboutUpgradeDownloadError'); case UpdateStatus.DISABLED_BY_ADMIN: return this.i18nAdvanced('aboutUpgradeAdministrator'); + case UpdateStatus.DEFERRED: + return this.i18nAdvanced('aboutUpgradeRelaunch'); default: function formatMessage(msg) { return parseHtmlSubset('<b>' + msg + '</b>', ['br', 'pre']) @@ -579,6 +588,7 @@ return 'cr:error-outline'; case UpdateStatus.UPDATED: case UpdateStatus.NEARLY_UPDATED: + case UpdateStatus.DEFERRED: // TODO(crbug.com/986596): Don't use browser icons here. Fork them. return 'settings:check-circle'; default: @@ -671,6 +681,18 @@ this.$.updateStatusMessageInner.focus(); } + /** @private */ + onApplyDeferredUpdateClick_() { + this.aboutBrowserProxy_.applyDeferredUpdate(); + this.$.updateStatusMessageInner.focus(); + } + + /** @private */ + onApplyAndSetAutoUpdateClick_() { + this.aboutBrowserProxy_.setConsumerAutoUpdate(true); + this.onApplyDeferredUpdateClick_(); + } + /** * @return {boolean} * @private
diff --git a/chrome/browser/resources/settings/chromeos/os_settings.gni b/chrome/browser/resources/settings/chromeos/os_settings.gni index 3534eff..3f087da 100644 --- a/chrome/browser/resources/settings/chromeos/os_settings.gni +++ b/chrome/browser/resources/settings/chromeos/os_settings.gni
@@ -5,6 +5,31 @@ import("//third_party/closure_compiler/compile_js.gni") import("../settings.gni") +ts_web_component_files = [ + "chromeos/os_icons.js", + "chromeos/os_settings_icons_css.js", +] + +ts_non_web_component_files = [ + "chromeos/combined_search_handler.js", + "chromeos/deep_linking_behavior.js", + "chromeos/ensure_lazy_loaded.js", + "chromeos/global_scroll_target_behavior.js", + "chromeos/lazy_load.js", + "chromeos/metrics_recorder.js", + "chromeos/os_page_visibility.js", + "chromeos/os_route.js", + "chromeos/os_settings.js", + "chromeos/os_settings_routes.js", + "chromeos/personalization_search_handler.js", + "chromeos/pref_to_setting_metric_converter.js", + "chromeos/prefs_behavior.js", + "chromeos/route_observer_behavior.js", + "chromeos/route_origin_behavior.js", + "chromeos/settings_search_handler.js", + "router.js", +] + # TODO(crbug.com/1121865): browser_resolver_prefix_replacements allows path # from ../../shared/* to resolve to ../../../nearby_share/shared/* for closure # purposes.
diff --git a/chrome/browser/resources/settings/chromeos/tsconfig_base.json b/chrome/browser/resources/settings/chromeos/tsconfig_base.json new file mode 100644 index 0000000..3f69ccee --- /dev/null +++ b/chrome/browser/resources/settings/chromeos/tsconfig_base.json
@@ -0,0 +1,9 @@ +{ + "extends": "../../../../../tools/typescript/tsconfig_base.json", + "compilerOptions": { + "allowJs": true, + "noUncheckedIndexedAccess": false, + "noUnusedLocals": false, + "strictPropertyInitialization": false + } +}
diff --git a/chrome/browser/resources/settings/languages_page/languages_page.html b/chrome/browser/resources/settings/languages_page/languages_page.html index 574c53b..d824efb9 100644 --- a/chrome/browser/resources/settings/languages_page/languages_page.html +++ b/chrome/browser/resources/settings/languages_page/languages_page.html
@@ -64,7 +64,7 @@ hidden="[[isHelpTextHidden_(languages.enabled.*)]]"> <div class="cr-padded-text"> <span> - $i18n{orderBrowserLanguagesInstructions} + $i18n{preferredLanguagesDesc} </span> </div> </div> @@ -269,10 +269,8 @@ body="[[i18n('languageManagedDialogBody')]]"> </managed-dialog> </template> -<if expr="not chromeos_ash"> - <template is="dom-if" if="[[shouldShowRelaunchDialog]]" restamp> - <relaunch-confirmation-dialog restart-type="[[restartTypeEnum.RESTART]]" - on-close="onRelaunchDialogClose"> - </relaunch-confirmation-dialog> - </template> -</if> +<template is="dom-if" if="[[shouldShowRelaunchDialog]]" restamp> + <relaunch-confirmation-dialog restart-type="[[restartTypeEnum.RESTART]]" + on-close="onRelaunchDialogClose"> + </relaunch-confirmation-dialog> +</template>
diff --git a/chrome/browser/resources/settings/languages_page/languages_page.ts b/chrome/browser/resources/settings/languages_page/languages_page.ts index 0624a37..f8f6188 100644 --- a/chrome/browser/resources/settings/languages_page/languages_page.ts +++ b/chrome/browser/resources/settings/languages_page/languages_page.ts
@@ -24,9 +24,7 @@ import './languages.js'; import '../controls/settings_toggle_button.js'; import '../icons.html.js'; - // <if expr="not chromeos_ash"> import '../relaunch_confirmation_dialog.js'; - // </if> import '../settings_shared.css.js'; import '../settings_vars.css.js';
diff --git a/chrome/browser/resources/settings/system_page/system_page.html b/chrome/browser/resources/settings/system_page/system_page.html index ae67135..392f055b 100644 --- a/chrome/browser/resources/settings/system_page/system_page.html +++ b/chrome/browser/resources/settings/system_page/system_page.html
@@ -6,7 +6,7 @@ </settings-toggle-button> <div class="hr"></div> </if> -<if expr="not chromeos_ash and not chromeos_lacros"> +<if expr="not chromeos_lacros"> <settings-toggle-button id="hardwareAcceleration" pref="{{prefs.hardware_acceleration_mode.enabled}}" label="$i18n{hardwareAccelerationLabel}"> @@ -51,12 +51,10 @@ </div> </template> </if> - <if expr="not chromeos_ash"> - <template is="dom-if" if="[[shouldShowRelaunchDialog]]" restamp> - <relaunch-confirmation-dialog restart-type="[[restartTypeEnum.RESTART]]" - on-close="onRelaunchDialogClose"></relaunch-confirmation-dialog> - </template> - </if> + <template is="dom-if" if="[[shouldShowRelaunchDialog]]" restamp> + <relaunch-confirmation-dialog restart-type="[[restartTypeEnum.RESTART]]" + on-close="onRelaunchDialogClose"></relaunch-confirmation-dialog> + </template> <if expr="chromeos_lacros"> <template is="dom-if" if="[[isSecondaryUser_]]"> <settings-toggle-button id="useAshProxy"
diff --git a/chrome/browser/resources/settings/system_page/system_page.ts b/chrome/browser/resources/settings/system_page/system_page.ts index 5c1ddc2..21138b2 100644 --- a/chrome/browser/resources/settings/system_page/system_page.ts +++ b/chrome/browser/resources/settings/system_page/system_page.ts
@@ -14,9 +14,7 @@ import '../controls/extension_controlled_indicator.js'; import '../controls/settings_toggle_button.js'; import '../prefs/prefs.js'; -// <if expr="not chromeos_ash"> import '../relaunch_confirmation_dialog.js'; -// </if> import '../settings_shared.css.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc index c4c26eed..849cea05 100644 --- a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc +++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
@@ -145,6 +145,7 @@ const char kHTTPSPage[] = "/ssl/google.html"; const char kMaliciousPage[] = "/safe_browsing/malware.html"; const char kCrossSiteMaliciousPage[] = "/safe_browsing/malware2.html"; +const char kCrossSiteMaliciousEmbedPage[] = "/safe_browsing/malware4.html"; const char kPageWithCrossOriginMaliciousIframe[] = "/safe_browsing/malware3.html"; const char kCrossOriginMaliciousIframeHost[] = "malware.test"; @@ -535,6 +536,16 @@ ->AddDangerousUrl(url, threat_type); } + void SetURLThreatPatternType(const GURL& url, + ThreatPatternType threat_pattern_type) { + TestSafeBrowsingService* service = factory_.test_safe_browsing_service(); + ASSERT_TRUE(service); + + static_cast<FakeSafeBrowsingDatabaseManager*>( + service->database_manager().get()) + ->AddDangerousUrlPattern(url, threat_pattern_type); + } + void ClearBadURL(const GURL& url) { TestSafeBrowsingService* service = factory_.test_safe_browsing_service(); ASSERT_TRUE(service); @@ -1870,6 +1881,49 @@ EXPECT_EQ(bad_url, contents->GetLastCommittedURL()); } +// Regression test for https://crbug.com/1333623. +IN_PROC_BROWSER_TEST_P(SafeBrowsingBlockingPageBrowserTest, + EmbedElementMalwareLandingInterstitial) { + GURL url = embedded_test_server()->GetURL(kCrossSiteMaliciousEmbedPage); + GURL embed_url = embedded_test_server()->GetURL(kMaliciousIframe); + SetURLThreatType(embed_url, SB_THREAT_TYPE_URL_MALWARE); + SetURLThreatPatternType(embed_url, ThreatPatternType::MALWARE_LANDING); + + EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), url)); + base::RunLoop().RunUntilIdle(); + WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents(); + EXPECT_TRUE( + content::WaitForRenderFrameReady(contents->GetPrimaryMainFrame())); + // Show an interstitial when the malware landing page is loaded as an <embed> + // element, because it can cause similar harm as <iframe>. + EXPECT_TRUE(IsShowingInterstitial(contents)); +} + +IN_PROC_BROWSER_TEST_P(SafeBrowsingBlockingPageBrowserTest, + JsElementInterstitial) { + SBThreatType threat_type = GetThreatType(); + GURL url = embedded_test_server()->GetURL(kMaliciousJsPage); + GURL js_url = embedded_test_server()->GetURL(kMaliciousJs); + SetURLThreatType(js_url, threat_type); + if (threat_type == SB_THREAT_TYPE_URL_MALWARE) { + SetURLThreatPatternType(js_url, ThreatPatternType::MALWARE_LANDING); + } + + EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), url)); + base::RunLoop().RunUntilIdle(); + WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents(); + EXPECT_TRUE( + content::WaitForRenderFrameReady(contents->GetPrimaryMainFrame())); + if (threat_type == SB_THREAT_TYPE_URL_MALWARE || + threat_type == SB_THREAT_TYPE_URL_UNWANTED) { + // Do not show an interstitial when the malware landing page or UwS landing + // page is loaded as a subresource to avoid false positives. + EXPECT_FALSE(IsShowingInterstitial(contents)); + } else { + EXPECT_TRUE(IsShowingInterstitial(contents)); + } +} + class SafeBrowsingBlockingPageDelayedWarningBrowserTest : public InProcessBrowserTest, public testing::WithParamInterface<
diff --git a/chrome/browser/safe_browsing/tailored_security/chrome_tailored_security_service.cc b/chrome/browser/safe_browsing/tailored_security/chrome_tailored_security_service.cc index 59e8a9f..80504af 100644 --- a/chrome/browser/safe_browsing/tailored_security/chrome_tailored_security_service.cc +++ b/chrome/browser/safe_browsing/tailored_security/chrome_tailored_security_service.cc
@@ -56,7 +56,7 @@ void RecordEnabledNotificationResult( TailoredSecurityNotificationResult result) { base::UmaHistogramEnumeration( - "SafeBrowsing.TailoredSecurity.SyncPromptEnabledNotificationResult", + "SafeBrowsing.TailoredSecurity.SyncPromptEnabledNotificationResult2", result); } @@ -132,15 +132,19 @@ if (base::FeatureList::IsEnabled(kTailoredSecurityDesktopNotice)) { Browser* browser = chrome::FindBrowserWithProfile(profile_); if (!browser) { - RecordEnabledNotificationResult( - TailoredSecurityNotificationResult::kNoBrowserAvailable); + if (is_enabled) { + RecordEnabledNotificationResult( + TailoredSecurityNotificationResult::kNoBrowserAvailable); + } return; } content::WebContents* web_contents = browser->tab_strip_model()->GetActiveWebContents(); if (!web_contents) { - RecordEnabledNotificationResult( - TailoredSecurityNotificationResult::kNoWebContentsAvailable); + if (is_enabled) { + RecordEnabledNotificationResult( + TailoredSecurityNotificationResult::kNoWebContentsAvailable); + } return; } SetSafeBrowsingState(profile_->GetPrefs(),
diff --git a/chrome/browser/segmentation_platform/service_browsertest.cc b/chrome/browser/segmentation_platform/service_browsertest.cc index 88be3ceb..e9b222101 100644 --- a/chrome/browser/segmentation_platform/service_browsertest.cc +++ b/chrome/browser/segmentation_platform/service_browsertest.cc
@@ -60,10 +60,9 @@ } bool HasResultPref(base::StringPiece segmentation_key) { - const base::Value* dictionary = - browser()->profile()->GetPrefs()->GetDictionary( - kSegmentationResultPref); - return !!dictionary->FindPath(segmentation_key); + const base::Value::Dict& dictionary = + browser()->profile()->GetPrefs()->GetValueDict(kSegmentationResultPref); + return !!dictionary.FindByDottedPath(segmentation_key); } void OnResultPrefUpdated() {
diff --git a/chrome/browser/ssl/sct_reporting_service_browsertest.cc b/chrome/browser/ssl/sct_reporting_service_browsertest.cc index ad86cc7..b59ee6d 100644 --- a/chrome/browser/ssl/sct_reporting_service_browsertest.cc +++ b/chrome/browser/ssl/sct_reporting_service_browsertest.cc
@@ -331,15 +331,17 @@ auto http_response = std::make_unique<net::test_server::BasicHttpResponse>(); - if (error_count_ > 0) { - http_response->set_code(net::HTTP_TOO_MANY_REQUESTS); - --error_count_; - } else { - http_response->set_code(net::HTTP_OK); - } - if (request.relative_url.find("hashdance") == std::string::npos) { // Request is a report. + + // Check if the server should just return an error for the full report + // request, otherwise just return OK. + if (error_count_ > 0) { + http_response->set_code(net::HTTP_TOO_MANY_REQUESTS); + --error_count_; + } else { + http_response->set_code(net::HTTP_OK); + } return http_response; } @@ -422,7 +424,8 @@ base::OnceClosure requests_closure_; - // How many times the report server should return an error before succeeding. + // How many times the report server should return an error before succeeding, + // specific to full report requests. size_t error_count_ = 0; }; @@ -940,6 +943,34 @@ EXPECT_EQ(report_count, 1); } +// Test that report count isn't incremented when retrying a single audit report. +// Regression test for crbug.com/1348313. +IN_PROC_BROWSER_TEST_F(SCTHashdanceBrowserTest, + HashdanceReportCountNotIncrementedOnRetry) { + // Don't succeed for max_retries+1, for the *full report sending*, but the + // hashdance lookup query will always succeed. + set_error_count(16); + + // Visit an HTTPS page and wait for the report to be sent. + ASSERT_TRUE(ui_test_utils::NavigateToURL( + browser(), https_server()->GetURL("hashdance.test", "/"))); + + // Wait until the reporter completes 32 requests (16 lookup queries which + // succeed, and 16 full report requests which fail). + WaitForRequests(32); + + // Check that 32 requests were seen and contains the expected details. + EXPECT_EQ(32u, requests_seen()); + EXPECT_EQ( + "hashdance.test", + GetLastSeenReport().certificate_report(0).context().origin().hostname()); + + // Check that the report was only counted once towards the max-reports limit. + int report_count = g_browser_process->local_state()->GetInteger( + prefs::kSCTAuditingHashdanceReportCount); + EXPECT_EQ(report_count, 1); +} + IN_PROC_BROWSER_TEST_F(SCTHashdanceBrowserTest, HashdanceReportLimitReached) { // Override the report count to be the maximum. g_browser_process->local_state()->SetInteger(
diff --git a/chrome/browser/ui/app_list/search/search_controller_factory.cc b/chrome/browser/ui/app_list/search/search_controller_factory.cc index 8d77488b..4331ed8 100644 --- a/chrome/browser/ui/app_list/search/search_controller_factory.cc +++ b/chrome/browser/ui/app_list/search/search_controller_factory.cc
@@ -157,7 +157,7 @@ // true (the default). if (!ash::features::IsProductivityLauncherEnabled() || base::GetFieldTrialParamByFeatureAsBool( - ash::features::kProductivityLauncher, "enable_continue", true)) { + ash::features::kProductivityLauncher, "enable_continue", false)) { size_t zero_state_files_group_id = controller->AddGroup(kMaxZeroStateFileResults); controller->AddProvider(zero_state_files_group_id,
diff --git a/chrome/browser/ui/ash/projector/projector_app_client_impl.cc b/chrome/browser/ui/ash/projector/projector_app_client_impl.cc index 36739a8..7b0fa72 100644 --- a/chrome/browser/ui/ash/projector/projector_app_client_impl.cc +++ b/chrome/browser/ui/ash/projector/projector_app_client_impl.cc
@@ -8,7 +8,9 @@ #include "ash/constants/ash_features.h" #include "ash/constants/ash_pref_names.h" +#include "ash/public/cpp/projector/annotator_tool.h" #include "ash/public/cpp/projector/projector_controller.h" +#include "ash/webui/projector_app/annotator_message_handler.h" #include "ash/webui/projector_app/projector_screencast.h" #include "ash/webui/projector_app/public/cpp/projector_app_constants.h" #include "base/bind.h" @@ -166,3 +168,25 @@ ash::ProjectorAppClient::OnGetScreencastCallback callback) { screencast_manager_.GetScreencast(screencast_id, std::move(callback)); } + +void ProjectorAppClientImpl::SetAnnotatorMessageHandler( + ash::AnnotatorMessageHandler* handler) { + annotator_message_handler_ = handler; +} + +void ProjectorAppClientImpl::ResetAnnotatorMessageHandler( + ash::AnnotatorMessageHandler* handler) { + if (annotator_message_handler_ == handler) { + annotator_message_handler_ = nullptr; + } +} + +void ProjectorAppClientImpl::SetTool(const ash::AnnotatorTool& tool) { + DCHECK(annotator_message_handler_); + annotator_message_handler_->SetTool(tool); +} + +void ProjectorAppClientImpl::Clear() { + DCHECK(annotator_message_handler_); + annotator_message_handler_->Clear(); +}
diff --git a/chrome/browser/ui/ash/projector/projector_app_client_impl.h b/chrome/browser/ui/ash/projector/projector_app_client_impl.h index 857e1a32..30f8df55 100644 --- a/chrome/browser/ui/ash/projector/projector_app_client_impl.h +++ b/chrome/browser/ui/ash/projector/projector_app_client_impl.h
@@ -7,6 +7,8 @@ #include <memory> +#include "ash/public/cpp/projector/projector_annotator_controller.h" +#include "ash/webui/projector_app/annotator_message_handler.h" #include "ash/webui/projector_app/projector_app_client.h" #include "base/observer_list.h" #include "chrome/browser/ui/ash/projector/pending_screencast_manager.h" @@ -23,6 +25,10 @@ class PrefRegistrySyncable; } // namespace user_prefs +namespace ash { +class AnnotatorMessageHandler; +} // namespace ash + // Implements the interface for Projector App. class ProjectorAppClientImpl : public ash::ProjectorAppClient { public: @@ -50,6 +56,16 @@ void GetScreencast( const std::string& screencast_id, ash::ProjectorAppClient::OnGetScreencastCallback callback) override; + void SetAnnotatorMessageHandler( + ash::AnnotatorMessageHandler* handler) override; + void ResetAnnotatorMessageHandler( + ash::AnnotatorMessageHandler* handler) override; + void SetTool(const ash::AnnotatorTool& tool) override; + void Clear() override; + + ash::AnnotatorMessageHandler* get_annotator_message_handler_for_test() { + return annotator_message_handler_; + } private: void NotifyScreencastsPendingStatusChanged( @@ -64,6 +80,8 @@ PendingScreencastManager pending_screencast_manager_; ash::ScreencastManager screencast_manager_; + + ash::AnnotatorMessageHandler* annotator_message_handler_ = nullptr; }; #endif // CHROME_BROWSER_UI_ASH_PROJECTOR_PROJECTOR_APP_CLIENT_IMPL_H_
diff --git a/chrome/browser/ui/ash/projector/projector_client_impl.cc b/chrome/browser/ui/ash/projector/projector_client_impl.cc index 7414e7c..b74c8df4 100644 --- a/chrome/browser/ui/ash/projector/projector_client_impl.cc +++ b/chrome/browser/ui/ash/projector/projector_client_impl.cc
@@ -9,7 +9,6 @@ #include "ash/public/cpp/projector/annotator_tool.h" #include "ash/public/cpp/projector/projector_controller.h" #include "ash/public/cpp/projector/projector_new_screencast_precondition.h" -#include "ash/webui/projector_app/annotator_message_handler.h" #include "ash/webui/projector_app/projector_app_client.h" #include "ash/webui/projector_app/public/cpp/projector_app_constants.h" #include "base/bind.h" @@ -161,18 +160,6 @@ app_client->OnNewScreencastPreconditionChanged(precondition); } -void ProjectorClientImpl::SetAnnotatorMessageHandler( - ash::AnnotatorMessageHandler* handler) { - message_handler_ = handler; -} - -void ProjectorClientImpl::ResetAnnotatorMessageHandler( - ash::AnnotatorMessageHandler* handler) { - if (message_handler_ == handler) { - message_handler_ = nullptr; - } -} - void ProjectorClientImpl::OnSpeechResult( const std::u16string& text, bool is_final, @@ -205,8 +192,7 @@ } void ProjectorClientImpl::SetTool(const ash::AnnotatorTool& tool) { - DCHECK(message_handler_); - message_handler_->SetTool(tool); + ash::ProjectorAppClient::Get()->SetTool(tool); } // TODO(b/220202359): Implement undo. @@ -216,8 +202,7 @@ void ProjectorClientImpl::Redo() {} void ProjectorClientImpl::Clear() { - DCHECK(message_handler_); - message_handler_->Clear(); + ash::ProjectorAppClient::Get()->Clear(); } void ProjectorClientImpl::OnFileSystemMounted() {
diff --git a/chrome/browser/ui/ash/projector/projector_client_impl.h b/chrome/browser/ui/ash/projector/projector_client_impl.h index c5271ee..90da7a4 100644 --- a/chrome/browser/ui/ash/projector/projector_client_impl.h +++ b/chrome/browser/ui/ash/projector/projector_client_impl.h
@@ -10,7 +10,6 @@ #include "ash/public/cpp/projector/projector_annotator_controller.h" #include "ash/public/cpp/projector/projector_client.h" #include "ash/public/cpp/projector/projector_controller.h" -#include "ash/webui/projector_app/annotator_message_handler.h" #include "base/memory/weak_ptr.h" #include "base/scoped_observation.h" #include "chrome/browser/ash/drive/drive_integration_service.h" @@ -60,10 +59,6 @@ void CloseProjectorApp() const override; void OnNewScreencastPreconditionChanged( const ash::NewScreencastPrecondition& precondition) const override; - void SetAnnotatorMessageHandler( - ash::AnnotatorMessageHandler* handler) override; - void ResetAnnotatorMessageHandler( - ash::AnnotatorMessageHandler* handler) override; // SpeechRecognizerDelegate: void OnSpeechResult( @@ -94,10 +89,6 @@ // user_manager::UserManager::UserSessionStateObserver: void ActiveUserChanged(user_manager::User* active_user) override; - ash::AnnotatorMessageHandler* get_annotator_message_handler_for_test() { - return message_handler_; - } - private: // Maybe reset |drive_observation_| and observe the Drive integration service // of active profile when ActiveUserChanged and OnUserProfileLoaded. @@ -111,7 +102,6 @@ void SetAppIsDisabled(bool disabled); ash::ProjectorController* const controller_; - ash::AnnotatorMessageHandler* message_handler_ = nullptr; SpeechRecognizerStatus recognizer_status_ = SpeechRecognizerStatus::SPEECH_RECOGNIZER_OFF; std::unique_ptr<OnDeviceSpeechRecognizer> speech_recognizer_;
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc index b3ccd623..ecf7d1e 100644 --- a/chrome/browser/ui/browser.cc +++ b/chrome/browser/ui/browser.cc
@@ -3172,4 +3172,11 @@ } screen_ai_annotator_->Run(); } + +void Browser::SetScreenAIAnnotatorForTesting( + std::unique_ptr<screen_ai::AXScreenAIAnnotator> annotator) { + DCHECK(!screen_ai_annotator_); + screen_ai_annotator_.swap(annotator); +} + #endif
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h index dda5c5a..b0f70cfa 100644 --- a/chrome/browser/ui/browser.h +++ b/chrome/browser/ui/browser.h
@@ -759,6 +759,10 @@ #if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE) void RunScreenAIAnnotator(); + + // Ownership will be transferred to browser. + void SetScreenAIAnnotatorForTesting( + std::unique_ptr<screen_ai::AXScreenAIAnnotator> annotator); #endif private:
diff --git a/chrome/browser/ui/browser_commands_mac.mm b/chrome/browser/ui/browser_commands_mac.mm index 9d75502c..a215b3bb 100644 --- a/chrome/browser/ui/browser_commands_mac.mm +++ b/chrome/browser/ui/browser_commands_mac.mm
@@ -13,6 +13,7 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h" +#include "chrome/browser/ui/web_applications/app_browser_controller.h" #include "chrome/common/pref_names.h" #include "components/prefs/pref_service.h" @@ -21,7 +22,14 @@ void ToggleFullscreenToolbar(Browser* browser) { DCHECK(browser); - // Toggle the value of the preference. + // If this browser belongs to an app, toggle the value for that app. + web_app::AppBrowserController* app_controller = browser->app_controller(); + if (app_controller) { + app_controller->ToggleAlwaysShowToolbarInFullscreen(); + return; + } + + // Otherwise toggle the value of the preference. PrefService* prefs = browser->profile()->GetPrefs(); bool show_toolbar = prefs->GetBoolean(prefs::kShowFullscreenToolbar); prefs->SetBoolean(prefs::kShowFullscreenToolbar, !show_toolbar);
diff --git a/chrome/browser/ui/quick_answers/quick_answers_ui_controller.cc b/chrome/browser/ui/quick_answers/quick_answers_ui_controller.cc index bae349ef..1fb818f 100644 --- a/chrome/browser/ui/quick_answers/quick_answers_ui_controller.cc +++ b/chrome/browser/ui/quick_answers/quick_answers_ui_controller.cc
@@ -9,6 +9,7 @@ #include "base/strings/stringprintf.h" #include "build/chromeos_buildflags.h" #include "chrome/browser/ui/quick_answers/quick_answers_controller_impl.h" +#include "chromeos/components/quick_answers/public/cpp/quick_answers_state.h" #include "chromeos/components/quick_answers/quick_answers_model.h" #include "chromeos/strings/grit/chromeos_strings.h" #include "mojo/public/cpp/bindings/remote.h" @@ -38,8 +39,11 @@ using quick_answers::QuickAnswersExitPoint; constexpr char kGoogleSearchUrlPrefix[] = "https://www.google.com/search?q="; +constexpr char kGoogleTranslateUrlTemplate[] = + "https://translate.google.com/?sl=auto&tl=%s&text=%s&op=translate"; constexpr char kFeedbackDescriptionTemplate[] = "#QuickAnswers\nQuery:%s\n"; +constexpr char kTranslationQueryPrefix[] = "Translate:"; constexpr char kQuickAnswersSettingsUrl[] = "chrome://os-settings/osSearch/search"; @@ -97,8 +101,21 @@ // Route dismissal through |controller_| for logging impressions. controller_->DismissQuickAnswers(QuickAnswersExitPoint::kQuickAnswersClick); - OpenUrl(GURL(kGoogleSearchUrlPrefix + - base::EscapeUrlEncodedData(query_, /*use_plus=*/true))); + // TODO(b/240619915): Refactor so that we can access the request metadata + // instead of just the query itself. + if (base::StartsWith(query_, kTranslationQueryPrefix)) { + auto query_text = base::EscapeUrlEncodedData( + query_.substr(strlen(kTranslationQueryPrefix)), /*use_plus=*/true); + auto device_language = + l10n_util::GetLanguage(QuickAnswersState::Get()->application_locale()); + auto translate_url = + base::StringPrintf(kGoogleTranslateUrlTemplate, device_language.c_str(), + query_text.c_str()); + OpenUrl(GURL(translate_url)); + } else { + OpenUrl(GURL(kGoogleSearchUrlPrefix + + base::EscapeUrlEncodedData(query_, /*use_plus=*/true))); + } controller_->OnQuickAnswerClick(); }
diff --git a/chrome/browser/ui/tabs/existing_tab_group_sub_menu_model_unittest.cc b/chrome/browser/ui/tabs/existing_tab_group_sub_menu_model_unittest.cc index feff0e8..31cba4f4 100644 --- a/chrome/browser/ui/tabs/existing_tab_group_sub_menu_model_unittest.cc +++ b/chrome/browser/ui/tabs/existing_tab_group_sub_menu_model_unittest.cc
@@ -223,6 +223,13 @@ EXPECT_EQ(3u, menu_1.GetItemCount()); EXPECT_EQ(3u, menu_2.GetItemCount()); + EXPECT_FALSE(ExistingTabGroupSubMenuModel::ShouldShowSubmenu( + model_1, 0, delegate_1.get())); + EXPECT_TRUE(ExistingTabGroupSubMenuModel::ShouldShowSubmenu( + model_1, 1, delegate_1.get())); + EXPECT_TRUE(ExistingTabGroupSubMenuModel::ShouldShowSubmenu( + model_2, 0, delegate_1.get())); + new_browser.get()->tab_strip_model()->CloseAllTabs(); new_browser.reset(); }
diff --git a/chrome/browser/ui/views/bubble/webui_bubble_manager.h b/chrome/browser/ui/views/bubble/webui_bubble_manager.h index 5315003..4051e87 100644 --- a/chrome/browser/ui/views/bubble/webui_bubble_manager.h +++ b/chrome/browser/ui/views/bubble/webui_bubble_manager.h
@@ -40,6 +40,9 @@ bool bubble_using_cached_web_contents() const { return bubble_using_cached_web_contents_; } + + // Creates the persistent renderer process if the feature is enabled. + virtual void MaybeInitPersistentRenderer() = 0; virtual base::WeakPtr<WebUIBubbleDialogView> CreateWebUIBubbleDialog( const absl::optional<gfx::Rect>& anchor) = 0; @@ -100,7 +103,10 @@ : anchor_view_(anchor_view), profile_(profile), webui_url_(webui_url), - task_manager_string_id_(task_manager_string_id) { + task_manager_string_id_(task_manager_string_id) {} + ~WebUIBubbleManagerT() override = default; + + void MaybeInitPersistentRenderer() override { if (base::FeatureList::IsEnabled( features::kWebUIBubblePerProfilePersistence)) { auto* service = @@ -111,7 +117,6 @@ } } } - ~WebUIBubbleManagerT() override = default; base::WeakPtr<WebUIBubbleDialogView> CreateWebUIBubbleDialog( const absl::optional<gfx::Rect>& anchor) override { @@ -128,6 +133,7 @@ // If using per-profile WebContents persistence get the associated // BubbleContentsWrapper from the BubbleContentsWrapperService. + MaybeInitPersistentRenderer(); contents_wrapper = service->GetBubbleContentsWrapperFromURL(webui_url_); DCHECK(contents_wrapper);
diff --git a/chrome/browser/ui/views/bubble/webui_bubble_manager_unittest.cc b/chrome/browser/ui/views/bubble/webui_bubble_manager_unittest.cc index 6cd7d4c5..cb6c9dfc 100644 --- a/chrome/browser/ui/views/bubble/webui_bubble_manager_unittest.cc +++ b/chrome/browser/ui/views/bubble/webui_bubble_manager_unittest.cc
@@ -13,6 +13,7 @@ #include "chrome/test/base/testing_profile_manager.h" #include "chrome/test/views/chrome_views_test_base.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/views/test/widget_test.h" #include "ui/webui/mojo_bubble_web_ui_controller.h" namespace { @@ -82,17 +83,17 @@ anchor_widget->GetContentsView(), test_profile, GURL(kTestURL), 1); bubble_manager->DisableCloseBubbleHelperForTesting(); - // If using per-profile persistence the `contents_wrapper` should have been - // created before the bubble has been invoked. - // Owned by |service|. + // The per-profile persistent renderer will not have been created until the + // first time the bubble is invoked. BubbleContentsWrapper* contents_wrapper = service->GetBubbleContentsWrapperFromURL(GURL(kTestURL)); - EXPECT_NE(nullptr, contents_wrapper); + EXPECT_EQ(nullptr, contents_wrapper); - // Open the bubble, the `contents_wrapper` used should match the one returned - // from the BubbleContentsWrapperService. + // Open the bubble, this should create the persistent renderer-backed + // `contents_wrapper`. EXPECT_EQ(nullptr, bubble_manager->GetBubbleWidget()); bubble_manager->ShowBubble(); + contents_wrapper = service->GetBubbleContentsWrapperFromURL(GURL(kTestURL)); EXPECT_NE(nullptr, bubble_manager->GetBubbleWidget()); EXPECT_FALSE(bubble_manager->GetBubbleWidget()->IsClosed()); EXPECT_EQ(contents_wrapper, bubble_manager->bubble_view_for_testing() @@ -194,10 +195,37 @@ BubbleContentsWrapper* contents_wrapper_profile2 = service2->GetBubbleContentsWrapperFromURL(GURL(kTestURL)); - // content wrappers for the same WebUI URL should be different per profile. - ASSERT_NE(nullptr, contents_wrapper_profile1); - ASSERT_NE(nullptr, contents_wrapper_profile2); - ASSERT_NE(contents_wrapper_profile1, contents_wrapper_profile2); + // Content wrappers should be null until the first time the bubble is shown. + EXPECT_EQ(nullptr, contents_wrapper_profile1); + EXPECT_EQ(nullptr, contents_wrapper_profile2); + + // Show bubbles for each manager one at a time, manager1 and manager2 should + // leverage the same contents wrapper. manager3 should be using a unique + // contents wrapper as it is backed by a different profile. + auto show_bubble = [](WebUIBubbleManager* manager, + BubbleContentsWrapperService* service) { + // Open the bubble for the given bubble manager + EXPECT_EQ(nullptr, manager->GetBubbleWidget()); + + manager->ShowBubble(); + auto* contents_wrapper = + service->GetBubbleContentsWrapperFromURL(GURL(kTestURL)); + EXPECT_NE(nullptr, manager->GetBubbleWidget()); + EXPECT_NE(nullptr, contents_wrapper); + EXPECT_EQ( + contents_wrapper, + manager->bubble_view_for_testing()->get_contents_wrapper_for_testing()); + + manager->CloseBubble(); + EXPECT_TRUE(manager->GetBubbleWidget()->IsClosed()); + views::test::WidgetDestroyedWaiter destroyed_waiter( + manager->GetBubbleWidget()); + destroyed_waiter.Wait(); + return contents_wrapper; + }; + contents_wrapper_profile1 = show_bubble(manager1.get(), service1); + EXPECT_EQ(contents_wrapper_profile1, show_bubble(manager2.get(), service1)); + contents_wrapper_profile2 = show_bubble(manager3.get(), service2); auto test_manager = [](WebUIBubbleManager* manager, BubbleContentsWrapperService* service,
diff --git a/chrome/browser/ui/views/frame/browser_frame_mac.mm b/chrome/browser/ui/views/frame/browser_frame_mac.mm index 73c652c5..953ca19 100644 --- a/chrome/browser/ui/views/frame/browser_frame_mac.mm +++ b/chrome/browser/ui/views/frame/browser_frame_mac.mm
@@ -20,6 +20,7 @@ #include "chrome/browser/ui/views/frame/browser_frame.h" #include "chrome/browser/ui/views/frame/browser_non_client_frame_view.h" #include "chrome/browser/ui/views/frame/browser_view.h" +#include "chrome/browser/ui/web_applications/app_browser_controller.h" #include "chrome/common/pref_names.h" #include "chrome/grit/generated_resources.h" #include "components/bookmarks/common/bookmark_pref_names.h" @@ -231,9 +232,15 @@ break; } case IDC_TOGGLE_FULLSCREEN_TOOLBAR: { - PrefService* prefs = browser->profile()->GetPrefs(); - result->new_toggle_state = - prefs->GetBoolean(prefs::kShowFullscreenToolbar); + web_app::AppBrowserController* app_controller = browser->app_controller(); + if (app_controller) { + result->new_toggle_state = + app_controller->AlwaysShowToolbarInFullscreen(); + } else { + PrefService* prefs = browser->profile()->GetPrefs(); + result->new_toggle_state = + prefs->GetBoolean(prefs::kShowFullscreenToolbar); + } break; } case IDC_SHOW_FULL_URLS: {
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.h b/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.h index 16685bc..a059b06 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.h +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.h
@@ -12,6 +12,8 @@ #include "base/gtest_prod_util.h" #include "base/mac/scoped_nsobject.h" #include "chrome/browser/ui/views/frame/browser_non_client_frame_view.h" +#include "chrome/browser/web_applications/app_registrar_observer.h" +#include "chrome/browser/web_applications/web_app_registrar.h" #include "components/prefs/pref_member.h" namespace views { @@ -23,7 +25,8 @@ class CaptionButtonPlaceholderContainer; class WindowControlsOverlayInputRoutingMac; -class BrowserNonClientFrameViewMac : public BrowserNonClientFrameView { +class BrowserNonClientFrameViewMac : public BrowserNonClientFrameView, + public web_app::AppRegistrarObserver { public: // Mac implementation of BrowserNonClientFrameView. BrowserNonClientFrameViewMac(BrowserFrame* frame, BrowserView* browser_view); @@ -64,6 +67,10 @@ gfx::Size GetMinimumSize() const override; void AddedToWidget() override; + // web_app::AppRegistrarObserver + void OnAlwaysShowToolbarInFullscreenChanged(const web_app::AppId& app_id, + bool show) override; + protected: // views::View: void OnPaint(gfx::Canvas* canvas) override; @@ -112,8 +119,17 @@ // toolbar style is changed. void ToggleWebAppFrameToolbarViewVisibility(); + // Returns the current value of the "always show toolbar in fullscreen" + // preference, either reading the value from the kShowFullscreenToolbar + // preference or if this is a window for an app, from the settings for that + // app. + bool AlwaysShowToolbarInFullscreen() const; + // Used to keep track of the update of kShowFullscreenToolbar preference. BooleanPrefMember show_fullscreen_toolbar_; + base::ScopedObservation<web_app::WebAppRegistrar, + web_app::AppRegistrarObserver> + always_show_toolbar_in_fullscreen_observation_{this}; raw_ptr<views::Label> window_title_ = nullptr;
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.mm b/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.mm index ee9cbfa..025baa81 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.mm +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.mm
@@ -29,6 +29,7 @@ #include "chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_utils.h" #include "chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_view.h" #include "chrome/browser/ui/web_applications/app_browser_controller.h" +#include "chrome/browser/web_applications/web_app_provider.h" #include "chrome/common/chrome_features.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/pref_names.h" @@ -62,16 +63,24 @@ BrowserFrame* frame, BrowserView* browser_view) : BrowserNonClientFrameView(frame, browser_view) { - show_fullscreen_toolbar_.Init( - prefs::kShowFullscreenToolbar, browser_view->GetProfile()->GetPrefs(), - base::BindRepeating(&BrowserNonClientFrameViewMac::UpdateFullscreenTopUI, - base::Unretained(this))); + if (web_app::AppBrowserController::IsWebApp(browser_view->browser())) { + auto* provider = + web_app::WebAppProvider::GetForWebApps(browser_view->GetProfile()); + always_show_toolbar_in_fullscreen_observation_.Observe( + &provider->registrar()); + } else { + show_fullscreen_toolbar_.Init( + prefs::kShowFullscreenToolbar, browser_view->GetProfile()->GetPrefs(), + base::BindRepeating( + &BrowserNonClientFrameViewMac::UpdateFullscreenTopUI, + base::Unretained(this))); + } if (!base::FeatureList::IsEnabled(features::kImmersiveFullscreen)) { fullscreen_toolbar_controller_.reset( [[FullscreenToolbarController alloc] initWithBrowserView:browser_view]); [fullscreen_toolbar_controller_ setToolbarStyle:GetUserPreferredToolbarStyle( - *show_fullscreen_toolbar_)]; + AlwaysShowToolbarInFullscreen())]; } if (browser_view->GetIsWebAppType()) { @@ -212,7 +221,7 @@ browser_view()->HideDownloadShelf(); new_style = FullscreenToolbarStyle::TOOLBAR_NONE; } else { - new_style = GetUserPreferredToolbarStyle(*show_fullscreen_toolbar_); + new_style = GetUserPreferredToolbarStyle(AlwaysShowToolbarInFullscreen()); browser_view()->UnhideDownloadShelf(); } [fullscreen_toolbar_controller_ setToolbarStyle:new_style]; @@ -235,6 +244,15 @@ } } +void BrowserNonClientFrameViewMac::OnAlwaysShowToolbarInFullscreenChanged( + const web_app::AppId& app_id, + bool show) { + if (web_app::AppBrowserController::IsForWebApp(browser_view()->browser(), + app_id)) { + UpdateFullscreenTopUI(); + } +} + bool BrowserNonClientFrameViewMac::ShouldHideTopUIForFullscreen() const { if (frame()->IsFullscreen()) { return [fullscreen_toolbar_controller_ toolbarStyle] != @@ -599,3 +617,13 @@ remote_cocoa::mojom::WindowControlsOverlayNSViewType:: kWebAppFrameToolbar); } + +bool BrowserNonClientFrameViewMac::AlwaysShowToolbarInFullscreen() const { + if (web_app::AppBrowserController::IsWebApp(browser_view()->browser())) { + web_app::AppBrowserController* controller = + browser_view()->browser()->app_controller(); + return controller->AlwaysShowToolbarInFullscreen(); + } else { + return *show_fullscreen_toolbar_; + } +}
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc index 3cb9ddb..c770f782 100644 --- a/chrome/browser/ui/views/frame/browser_view.cc +++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -2351,8 +2351,16 @@ // This Mac-only preference disables display of the toolbar in fullscreen mode // so we need to take it into account when determining if the toolbar is // visible - especially as pertains to anchoring views. - if (IsFullscreen() && !browser()->profile()->GetPrefs()->GetBoolean( - prefs::kShowFullscreenToolbar)) { + bool show_fullscreen_toolbar = true; + if (web_app::AppBrowserController::IsWebApp(browser())) { + const web_app::AppBrowserController* controller = + browser()->app_controller(); + show_fullscreen_toolbar = controller->AlwaysShowToolbarInFullscreen(); + } else { + show_fullscreen_toolbar = browser()->profile()->GetPrefs()->GetBoolean( + prefs::kShowFullscreenToolbar); + } + if (IsFullscreen() && !show_fullscreen_toolbar) { return false; } #endif
diff --git a/chrome/browser/ui/views/lens/lens_region_search_controller_unittest.cc b/chrome/browser/ui/views/lens/lens_region_search_controller_unittest.cc index 6591632..d7af22d 100644 --- a/chrome/browser/ui/views/lens/lens_region_search_controller_unittest.cc +++ b/chrome/browser/ui/views/lens/lens_region_search_controller_unittest.cc
@@ -6,6 +6,7 @@ #include "base/feature_list.h" #include "base/test/metrics/histogram_tester.h" #include "chrome/browser/lens/metrics/lens_metrics.h" +#include "chrome/browser/ui/ui_features.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/frame/test_with_browser_view.h" #include "components/lens/lens_features.h" @@ -19,7 +20,8 @@ public: void SetUp() override { base::test::ScopedFeatureList features; - features.InitWithFeatures({features::kLensStandalone}, {}); + features.InitWithFeatures({features::kLensStandalone}, + {features::kUnifiedSidePanel}); TestWithBrowserView::SetUp(); // Create an active web contents.
diff --git a/chrome/browser/ui/views/lens/lens_side_panel_controller.cc b/chrome/browser/ui/views/lens/lens_side_panel_controller.cc index 4414b6a..f34661a 100644 --- a/chrome/browser/ui/views/lens/lens_side_panel_controller.cc +++ b/chrome/browser/ui/views/lens/lens_side_panel_controller.cc
@@ -17,7 +17,9 @@ #include "content/public/browser/navigation_handle.h" #include "net/base/url_util.h" #include "ui/base/l10n/l10n_util.h" +#include "ui/gfx/geometry/rect.h" #include "ui/views/controls/webview/webview.h" +#include "ui/views/view.h" namespace lens { @@ -34,13 +36,19 @@ base::BindRepeating(&LensSidePanelController::CloseButtonClicked, base::Unretained(this)), base::BindRepeating(&LensSidePanelController::LoadResultsInNewTab, - base::Unretained(this))))) { + base::Unretained(this))))), + side_panel_url_params_(nullptr) { side_panel_->SetVisible(false); Observe(side_panel_view_->GetWebContents()); side_panel_view_->GetWebContents()->SetDelegate(this); + + // Observe changes in the side_panel_view_ sizing. + side_panel_view_->AddObserver(this); } LensSidePanelController::~LensSidePanelController() { + side_panel_view_->RemoveObserver(this); + // check side_panel -> children() size for unit tests where all the children // are removed when side panel is destroyed. if (side_panel_view_ != nullptr && side_panel_->children().size() != 0) { @@ -66,8 +74,6 @@ browser_view_->MaybeClobberAllSideSearchSidePanels(); - side_panel_view_->GetWebContents()->GetController().LoadURLWithParams( - content::NavigationController::LoadURLParams(params)); if (side_panel_->GetVisible()) { // The user issued a follow-up Lens query. base::RecordAction( @@ -76,6 +82,9 @@ side_panel_->SetVisible(true); base::RecordAction(base::UserMetricsAction("LensSidePanel.Show")); } + + side_panel_url_params_ = std::make_unique<content::OpenURLParams>(params); + MaybeLoadURLWithParams(); } bool LensSidePanelController::IsShowing() const { @@ -149,6 +158,33 @@ Close(); } +void LensSidePanelController::MaybeLoadURLWithParams() { + // Ensure side panel has a width before loading URL. If side panel is still + // closed (width == 0), defer loading the URL to + // LensSidePanelController::OnViewBoundsChanged. The nullptr check ensures we + // don't rerender the same page on a unrelated resize event. + if (side_panel_view_->width() == 0 || !side_panel_url_params_) + return; + // Manually set web contents to the size of side panel view on initial load. + // This prevents a bug in Lens Web that renders the page as if it was 0px + // wide. + auto* web_contents = side_panel_view_->GetWebContents(); + web_contents->Resize(side_panel_view_->bounds()); + web_contents->GetController().LoadURLWithParams( + content::NavigationController::LoadURLParams(*side_panel_url_params_)); + + side_panel_url_params_.reset(); +} + +void LensSidePanelController::OnViewBoundsChanged(views::View* observed_view) { + // If side panel is closed when we first try to render the URL, we must wait + // until side panel is opened. This method is called once side panel view goes + // from 0px wide to ~320px wide. Rendering the page after it fully opens + // prevents a race condition which causes the page to load before side panel + // is open causing the page to render as if it were 0px wide. + MaybeLoadURLWithParams(); +} + void LensSidePanelController::LoadProgressChanged(double progress) { bool is_content_visible = progress == 1.0; side_panel_view_->SetContentVisible(is_content_visible);
diff --git a/chrome/browser/ui/views/lens/lens_side_panel_controller.h b/chrome/browser/ui/views/lens/lens_side_panel_controller.h index 07e97af4..9d1ac179 100644 --- a/chrome/browser/ui/views/lens/lens_side_panel_controller.h +++ b/chrome/browser/ui/views/lens/lens_side_panel_controller.h
@@ -10,6 +10,8 @@ #include "content/public/browser/navigation_handle.h" #include "content/public/browser/web_contents_delegate.h" #include "content/public/browser/web_contents_observer.h" +#include "ui/views/view.h" +#include "ui/views/view_observer.h" namespace content { struct OpenURLParams; @@ -22,7 +24,8 @@ // Controller for the Lens side panel. class LensSidePanelController : public content::WebContentsObserver, - public content::WebContentsDelegate { + public content::WebContentsDelegate, + public views::ViewObserver { public: LensSidePanelController(base::OnceClosure close_callback, SidePanel* side_panel, @@ -33,9 +36,15 @@ void LoadProgressChanged(double progress) override; + // views::ViewObserver: + void OnViewBoundsChanged(views::View* observed_view) override; + // Opens the Lens side panel with the given Lens results URL. void OpenWithURL(const content::OpenURLParams& params); + // Loads the Lens website if the side panel view is ready with a width. + void MaybeLoadURLWithParams(); + // Returns whether the Lens side panel is currently showing. bool IsShowing() const; @@ -67,6 +76,9 @@ raw_ptr<SidePanel> side_panel_; raw_ptr<BrowserView> browser_view_; raw_ptr<lens::LensSidePanelView> side_panel_view_; + + // Copy of the most recent URL params given to the controller. + std::unique_ptr<content::OpenURLParams> side_panel_url_params_; }; } // namespace lens
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc index 1088979f..f05cedf 100644 --- a/chrome/browser/ui/views/location_bar/location_bar_view.cc +++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -265,8 +265,14 @@ std::u16string(), ChromeTextContext::CONTEXT_OMNIBOX_DEEMPHASIZED, views::style::STYLE_LINK); omnibox_additional_text_view->SetHorizontalAlignment(gfx::ALIGN_LEFT); + int left_margin = + OmniboxFieldTrial::kRichAutocompletionAdditionalTextWithParenthesis + .Get() + ? 10 + : 0; omnibox_additional_text_view->SetBorder( - views::CreateEmptyBorder(gfx::Insets::TLBR(0, 10, 0, 0))); + views::CreateEmptyBorder(gfx::Insets::TLBR(0, left_margin, 0, 0))); + omnibox_additional_text_view->SetFontList(font_list); omnibox_additional_text_view->SetVisible(false); omnibox_additional_text_view_ = AddChildView(std::move(omnibox_additional_text_view)); @@ -433,11 +439,18 @@ DCHECK(OmniboxFieldTrial::IsRichAutocompletionEnabled() || text.empty()); if (!OmniboxFieldTrial::RichAutocompletionShowAdditionalText()) return; - auto wrapped_text = - text.empty() - ? text - // TODO(pkasting): This should use a localizable string constant. - : u"(" + text + u")"; + + // TODO(pkasting): This should use a localizable string constant. + // TODO(manukh): '-' separator doesn't play nice with RTL; results in + // 'input[autocompletion] URL -'. + std::u16string wrapped_text; + if (!text.empty()) { + wrapped_text = + OmniboxFieldTrial::kRichAutocompletionAdditionalTextWithParenthesis + .Get() + ? u"(" + text + u")" + : u" - " + text; + } SetOmniboxAdjacentText(omnibox_additional_text_view_, wrapped_text); }
diff --git a/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc b/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc index 4afcec3..95bdc100 100644 --- a/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc +++ b/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc
@@ -1326,7 +1326,7 @@ } // Test that a Safety Tips is not shown and metrics are recorded when -// a combo squatting url is flagged. +// a combo squatting url is flagged with a hard-coded brand name. IN_PROC_BROWSER_TEST_F(SafetyTipPageInfoBubbleViewBrowserTest, DoesntTriggerOnComboSquatting) { base::HistogramTester histograms; @@ -1341,12 +1341,36 @@ NavigationSuggestionEvent::kComboSquatting, 1); // TODO(crbug.com/1343630): keyword (embedded keyword) heuristic should - // be removed from the code. The last `false` value in + // be removed from the code. The second `false` value in // the input of CheckHeuristicsUkmRecord is correlated to this heuristic. CheckRecordedHeuristicsUkmCount(1); CheckHeuristicsUkmRecord({kNavigatedUrl, {false, false, true}}, 0); } +// Test that a Safety Tips is not shown and metrics are recorded when +// a combo squatting url is flagged with a brand name from engaged sites. +IN_PROC_BROWSER_TEST_F(SafetyTipPageInfoBubbleViewBrowserTest, + DoesntTriggerOnComboSquattingSiteEngagement) { + base::HistogramTester histograms; + const GURL kEngagedUrl = GetURL("example.com"); + const GURL kNavigatedUrl = GetURL("example-login.com"); + SetEngagementScore(browser(), kEngagedUrl, kHighEngagement); + SetEngagementScore(browser(), kNavigatedUrl, kLowEngagement); + + NavigateToURL(browser(), kNavigatedUrl, WindowOpenDisposition::CURRENT_TAB); + EXPECT_FALSE(IsUIShowing()); + + histograms.ExpectTotalCount(lookalikes::kHistogramName, 1); + histograms.ExpectBucketCount( + lookalikes::kHistogramName, + NavigationSuggestionEvent::kComboSquattingSiteEngagement, 1); + + // Heuristics with no UI don't record Safety Tips UKM. + CheckRecordedHeuristicsUkmCount(0); + // TODO(crbug.com/1337475): Add CheckHeuristicsUkmRecord after showing the + // safety tip for this heuristic. +} + // Tests for Digital Asset Links for lookalike checks. // TODO(meacer): Refactor the DAL code in LookalikeNavigationThrottle tests and // reuse here.
diff --git a/chrome/browser/ui/views/tabs/fake_tab_slot_controller.h b/chrome/browser/ui/views/tabs/fake_tab_slot_controller.h index 8eb6d6b3..7a5c364 100644 --- a/chrome/browser/ui/views/tabs/fake_tab_slot_controller.h +++ b/chrome/browser/ui/views/tabs/fake_tab_slot_controller.h
@@ -45,6 +45,9 @@ const tab_groups::TabGroupId group, ToggleTabGroupCollapsedStateOrigin origin = ToggleTabGroupCollapsedStateOrigin::kImplicitAction) override; + void NotifyTabGroupEditorBubbleOpened() override {} + void NotifyTabGroupEditorBubbleClosed() override {} + void ShowContextMenuForTab(Tab* tab, const gfx::Point& p, ui::MenuSourceType source_type) override {}
diff --git a/chrome/browser/ui/views/tabs/tab_container.h b/chrome/browser/ui/views/tabs/tab_container.h index d9e8b15..a7063da3 100644 --- a/chrome/browser/ui/views/tabs/tab_container.h +++ b/chrome/browser/ui/views/tabs/tab_container.h
@@ -63,6 +63,8 @@ virtual void OnGroupContentsChanged(const tab_groups::TabGroupId& group) = 0; virtual void OnGroupClosed(const tab_groups::TabGroupId& group) = 0; virtual void UpdateTabGroupVisuals(tab_groups::TabGroupId group_id) = 0; + virtual void NotifyTabGroupEditorBubbleOpened() = 0; + virtual void NotifyTabGroupEditorBubbleClosed() = 0; virtual int GetModelIndexOf(const TabSlotView* slot_view) const = 0;
diff --git a/chrome/browser/ui/views/tabs/tab_container_impl.cc b/chrome/browser/ui/views/tabs/tab_container_impl.cc index 95aec58..08bccd4 100644 --- a/chrome/browser/ui/views/tabs/tab_container_impl.cc +++ b/chrome/browser/ui/views/tabs/tab_container_impl.cc
@@ -421,6 +421,17 @@ group_views->second->UpdateBounds(); } +void TabContainerImpl::NotifyTabGroupEditorBubbleOpened() { + // Suppress the mouse watching behavior of tab closing mode. + RemoveMessageLoopObserver(); +} + +void TabContainerImpl::NotifyTabGroupEditorBubbleClosed() { + // Restore the mouse watching behavior of tab closing mode. + if (in_tab_close_) + AddMessageLoopObserver(); +} + // TODO(pkasting): This should really return an optional<size_t> int TabContainerImpl::GetModelIndexOf(const TabSlotView* slot_view) const { const absl::optional<size_t> index =
diff --git a/chrome/browser/ui/views/tabs/tab_container_impl.h b/chrome/browser/ui/views/tabs/tab_container_impl.h index ebf3655..e74a483 100644 --- a/chrome/browser/ui/views/tabs/tab_container_impl.h +++ b/chrome/browser/ui/views/tabs/tab_container_impl.h
@@ -67,6 +67,8 @@ void OnGroupContentsChanged(const tab_groups::TabGroupId& group) override; void OnGroupClosed(const tab_groups::TabGroupId& group) override; void UpdateTabGroupVisuals(tab_groups::TabGroupId group_id) override; + void NotifyTabGroupEditorBubbleOpened() override; + void NotifyTabGroupEditorBubbleClosed() override; int GetModelIndexOf(const TabSlotView* slot_view) const override;
diff --git a/chrome/browser/ui/views/tabs/tab_group_header.cc b/chrome/browser/ui/views/tabs/tab_group_header.cc index ce2ef54f..b368633 100644 --- a/chrome/browser/ui/views/tabs/tab_group_header.cc +++ b/chrome/browser/ui/views/tabs/tab_group_header.cc
@@ -87,7 +87,8 @@ TabGroupHeader::TabGroupHeader(TabSlotController* tab_slot_controller, const tab_groups::TabGroupId& group) - : tab_slot_controller_(tab_slot_controller) { + : tab_slot_controller_(tab_slot_controller), + editor_bubble_tracker_(tab_slot_controller) { DCHECK(tab_slot_controller); set_group(group); @@ -513,10 +514,15 @@ ADD_READONLY_PROPERTY_METADATA(int, DesiredWidth) END_METADATA +TabGroupHeader::EditorBubbleTracker::EditorBubbleTracker( + TabSlotController* tab_slot_controller) + : tab_slot_controller_(tab_slot_controller) {} + TabGroupHeader::EditorBubbleTracker::~EditorBubbleTracker() { if (is_open_) { widget_->RemoveObserver(this); widget_->CloseWithReason(views::Widget::ClosedReason::kUnspecified); + OnWidgetDestroyed(widget_); } CHECK(!IsInObserverList()); } @@ -527,9 +533,11 @@ widget_ = bubble_widget; is_open_ = true; bubble_widget->AddObserver(this); + tab_slot_controller_->NotifyTabGroupEditorBubbleOpened(); } void TabGroupHeader::EditorBubbleTracker::OnWidgetDestroyed( views::Widget* widget) { is_open_ = false; + tab_slot_controller_->NotifyTabGroupEditorBubbleClosed(); }
diff --git a/chrome/browser/ui/views/tabs/tab_group_header.h b/chrome/browser/ui/views/tabs/tab_group_header.h index 0dcf6f1..390b48b 100644 --- a/chrome/browser/ui/views/tabs/tab_group_header.h +++ b/chrome/browser/ui/views/tabs/tab_group_header.h
@@ -96,7 +96,7 @@ // at once. class EditorBubbleTracker : public views::WidgetObserver { public: - EditorBubbleTracker() = default; + explicit EditorBubbleTracker(TabSlotController* tab_slot_controller); ~EditorBubbleTracker() override; void Opened(views::Widget* bubble_widget); @@ -109,6 +109,9 @@ private: bool is_open_ = false; raw_ptr<views::Widget> widget_; + // Outlives this because it's a dependency inversion interface for the + // header's parent View. + raw_ptr<TabSlotController> tab_slot_controller_; }; EditorBubbleTracker editor_bubble_tracker_;
diff --git a/chrome/browser/ui/views/tabs/tab_slot_controller.h b/chrome/browser/ui/views/tabs/tab_slot_controller.h index 3afecb7..f8841b7 100644 --- a/chrome/browser/ui/views/tabs/tab_slot_controller.h +++ b/chrome/browser/ui/views/tabs/tab_slot_controller.h
@@ -95,6 +95,10 @@ ToggleTabGroupCollapsedStateOrigin origin = ToggleTabGroupCollapsedStateOrigin::kImplicitAction) = 0; + // Notify this controller of a tab group editor bubble opening/closing. + virtual void NotifyTabGroupEditorBubbleOpened() = 0; + virtual void NotifyTabGroupEditorBubbleClosed() = 0; + // Shows a context menu for the tab at the specified point in screen coords. virtual void ShowContextMenuForTab(Tab* tab, const gfx::Point& p,
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc index c3be9cd..6075a70 100644 --- a/chrome/browser/ui/views/tabs/tab_strip.cc +++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -1528,6 +1528,13 @@ return controller_->ToggleTabGroupCollapsedState(group, origin); } +void TabStrip::NotifyTabGroupEditorBubbleOpened() { + tab_container_->NotifyTabGroupEditorBubbleOpened(); +} +void TabStrip::NotifyTabGroupEditorBubbleClosed() { + tab_container_->NotifyTabGroupEditorBubbleClosed(); +} + void TabStrip::ShowContextMenuForTab(Tab* tab, const gfx::Point& p, ui::MenuSourceType source_type) {
diff --git a/chrome/browser/ui/views/tabs/tab_strip.h b/chrome/browser/ui/views/tabs/tab_strip.h index 7e43faf..4c13b305 100644 --- a/chrome/browser/ui/views/tabs/tab_strip.h +++ b/chrome/browser/ui/views/tabs/tab_strip.h
@@ -261,6 +261,8 @@ const tab_groups::TabGroupId group, ToggleTabGroupCollapsedStateOrigin origin = ToggleTabGroupCollapsedStateOrigin::kImplicitAction) override; + void NotifyTabGroupEditorBubbleOpened() override; + void NotifyTabGroupEditorBubbleClosed() override; void ShowContextMenuForTab(Tab* tab, const gfx::Point& p, ui::MenuSourceType source_type) override;
diff --git a/chrome/browser/ui/web_applications/app_browser_controller.cc b/chrome/browser/ui/web_applications/app_browser_controller.cc index 2300c37..e24b5b0 100644 --- a/chrome/browser/ui/web_applications/app_browser_controller.cc +++ b/chrome/browser/ui/web_applications/app_browser_controller.cc
@@ -387,6 +387,14 @@ return GetAppStartUrl(); } +#if BUILDFLAG(IS_MAC) +bool AppBrowserController::AlwaysShowToolbarInFullscreen() const { + return true; +} + +void AppBrowserController::ToggleAlwaysShowToolbarInFullscreen() {} +#endif + void AppBrowserController::OnTabStripModelChanged( TabStripModel* tab_strip_model, const TabStripModelChange& change,
diff --git a/chrome/browser/ui/web_applications/app_browser_controller.h b/chrome/browser/ui/web_applications/app_browser_controller.h index 456ad10..562f1a5 100644 --- a/chrome/browser/ui/web_applications/app_browser_controller.h +++ b/chrome/browser/ui/web_applications/app_browser_controller.h
@@ -149,6 +149,12 @@ // Determines whether the specified url is 'inside' the app |this| controls. virtual bool IsUrlInAppScope(const GURL& url) const = 0; +#if BUILDFLAG(IS_MAC) + // Whether the toolbar should always be shown when in fullscreen mode. + virtual bool AlwaysShowToolbarInFullscreen() const; + virtual void ToggleAlwaysShowToolbarInFullscreen(); +#endif + // Safe downcast: virtual WebAppBrowserController* AsWebAppBrowserController();
diff --git a/chrome/browser/ui/web_applications/web_app_browser_controller.cc b/chrome/browser/ui/web_applications/web_app_browser_controller.cc index 1d3e9261..f636988 100644 --- a/chrome/browser/ui/web_applications/web_app_browser_controller.cc +++ b/chrome/browser/ui/web_applications/web_app_browser_controller.cc
@@ -21,6 +21,8 @@ #include "chrome/browser/ui/web_applications/web_app_dialog_manager.h" #include "chrome/browser/ui/web_applications/web_app_launch_utils.h" #include "chrome/browser/ui/web_applications/web_app_ui_manager_impl.h" +#include "chrome/browser/web_applications/commands/callback_command.h" +#include "chrome/browser/web_applications/web_app_command_manager.h" #include "chrome/browser/web_applications/web_app_constants.h" #include "chrome/browser/web_applications/web_app_helpers.h" #include "chrome/browser/web_applications/web_app_icon_manager.h" @@ -176,6 +178,25 @@ } #endif // BUILDFLAG(IS_CHROMEOS_ASH) +#if BUILDFLAG(IS_MAC) +bool WebAppBrowserController::AlwaysShowToolbarInFullscreen() const { + // Reading this setting synchronously rather than going through the command + // manager greatly simplifies where this is read. This should be fine, since + // this is only persisted in the web app db. + return registrar().AlwaysShowToolbarInFullscreen(app_id()); +} + +void WebAppBrowserController::ToggleAlwaysShowToolbarInFullscreen() { + // base::Unretained is safe as the command manager won't execute the command + // if the provider no longer exists. + provider_.command_manager().ScheduleCommand(std::make_unique<CallbackCommand>( + WebAppCommandLock::CreateForAppLock({app_id()}), + base::BindOnce(&WebAppSyncBridge::SetAlwaysShowToolbarInFullscreen, + base::Unretained(&provider_.sync_bridge()), app_id(), + !registrar().AlwaysShowToolbarInFullscreen(app_id())))); +} +#endif + #if BUILDFLAG(IS_CHROMEOS) bool WebAppBrowserController::ShouldShowCustomTabBar() const { if (AppBrowserController::ShouldShowCustomTabBar())
diff --git a/chrome/browser/ui/web_applications/web_app_browser_controller.h b/chrome/browser/ui/web_applications/web_app_browser_controller.h index 0b3ed40..6a93110 100644 --- a/chrome/browser/ui/web_applications/web_app_browser_controller.h +++ b/chrome/browser/ui/web_applications/web_app_browser_controller.h
@@ -103,6 +103,11 @@ bool ShouldShowCustomTabBar() const override; #endif // BUILDFLAG(IS_CHROMEOS_ASH) +#if BUILDFLAG(IS_MAC) + bool AlwaysShowToolbarInFullscreen() const override; + void ToggleAlwaysShowToolbarInFullscreen() override; +#endif + // WebAppInstallManagerObserver: void OnWebAppUninstalled(const AppId& app_id) override; void OnWebAppInstallManagerDestroyed() override;
diff --git a/chrome/browser/ui/web_applications/web_app_dialog_utils.cc b/chrome/browser/ui/web_applications/web_app_dialog_utils.cc index 6c044a0b..cfac3b6a 100644 --- a/chrome/browser/ui/web_applications/web_app_dialog_utils.cc +++ b/chrome/browser/ui/web_applications/web_app_dialog_utils.cc
@@ -27,8 +27,8 @@ #include "chrome/browser/web_applications/web_app_install_utils.h" #include "chrome/browser/web_applications/web_app_provider.h" #include "chrome/browser/web_applications/web_app_utils.h" -#include "chrome/common/chrome_features.h" #include "components/webapps/browser/banners/app_banner_manager.h" +#include "components/webapps/browser/features.h" #include "components/webapps/browser/installable/installable_metrics.h" #include "content/public/browser/navigation_entry.h" @@ -49,7 +49,7 @@ case WebAppInstallFlow::kInstallSite: web_app_info->user_display_mode = UserDisplayMode::kStandalone; if (base::FeatureList::IsEnabled( - features::kDesktopPWAsDetailedInstallDialog) && + webapps::features::kDesktopPWAsDetailedInstallDialog) && webapps::AppBannerManager::FromWebContents(initiator_web_contents) ->screenshots() .size()) {
diff --git a/chrome/browser/ui/webui/browser_command/browser_command_handler.cc b/chrome/browser/ui/webui/browser_command/browser_command_handler.cc index 145b236..7f11b52 100644 --- a/chrome/browser/ui/webui/browser_command/browser_command_handler.cc +++ b/chrome/browser/ui/webui/browser_command/browser_command_handler.cc
@@ -178,7 +178,10 @@ if (!context) return; - tutorial_service->StartTutorial(kTabGroupTutorialId, context); + bool started_tutorial = + tutorial_service->StartTutorial(kTabGroupTutorialId, context); + tutorial_service->LogStartedFromWhatsNewPage(kTabGroupTutorialId, + started_tutorial); } void BrowserCommandHandler::OpenFeedbackForm() {
diff --git a/chrome/browser/ui/webui/browser_command/browser_command_handler_unittest.cc b/chrome/browser/ui/webui/browser_command/browser_command_handler_unittest.cc index 4660a3b..155c471 100644 --- a/chrome/browser/ui/webui/browser_command/browser_command_handler_unittest.cc +++ b/chrome/browser/ui/webui/browser_command/browser_command_handler_unittest.cc
@@ -21,6 +21,7 @@ #include "components/safe_browsing/core/common/safe_browsing_prefs.h" #include "components/sync_preferences/testing_pref_service_syncable.h" #include "components/user_education/common/help_bubble_factory_registry.h" +#include "components/user_education/common/tutorial_identifier.h" #include "components/user_education/common/tutorial_registry.h" #include "components/user_education/common/tutorial_service.h" #include "content/public/test/browser_task_environment.h" @@ -127,6 +128,8 @@ ui::ElementContext, base::OnceClosure, base::OnceClosure)); + MOCK_METHOD2(LogStartedFromWhatsNewPage, + void(user_education::TutorialIdentifier, bool)); }; class MockCommandHandler : public TestCommandHandler { @@ -426,7 +429,9 @@ // The StartTabGroupTutorial command should start the tab group tutorial. ClickInfoPtr info = ClickInfo::New(); EXPECT_CALL(service, StartTutorial(kTabGroupTutorialId, kTestContext1, - testing::_, testing::_)); + testing::_, testing::_)) + .WillOnce(testing::Return(true)); + EXPECT_CALL(service, LogStartedFromWhatsNewPage(kTabGroupTutorialId, true)); EXPECT_TRUE(ExecuteCommand(Command::kStartTabGroupTutorial, std::move(info))); }
diff --git a/chrome/browser/ui/webui/chromeos/network_ui.cc b/chrome/browser/ui/webui/chromeos/network_ui.cc index 2823384..a12b8381 100644 --- a/chrome/browser/ui/webui/chromeos/network_ui.cc +++ b/chrome/browser/ui/webui/chromeos/network_ui.cc
@@ -16,6 +16,7 @@ #include "ash/webui/network_ui/network_health_resource_provider.h" #include "ash/webui/network_ui/traffic_counters_resource_provider.h" #include "base/bind.h" +#include "base/json/json_reader.h" #include "base/memory/weak_ptr.h" #include "base/values.h" #include "chrome/browser/ash/net/network_health/network_health_service.h" @@ -81,6 +82,9 @@ constexpr char kGetHostname[] = "getHostname"; constexpr char kSetHostname[] = "setHostname"; constexpr char kGetTetheringCapabilities[] = "getTetheringCapabilities"; +constexpr char kGetTetheringStatus[] = "getTetheringStatus"; +constexpr char kGetTetheringConfig[] = "getTetheringConfig"; +constexpr char kSetTetheringConfig[] = "setTetheringConfig"; bool GetServicePathFromGuid(const std::string& guid, std::string* service_path) { @@ -527,6 +531,18 @@ base::BindRepeating( &HotspotConfigMessageHandler::GetTetheringCapabilities, base::Unretained(this))); + web_ui()->RegisterMessageCallback( + kGetTetheringStatus, + base::BindRepeating(&HotspotConfigMessageHandler::GetTetheringStatus, + base::Unretained(this))); + web_ui()->RegisterMessageCallback( + kGetTetheringConfig, + base::BindRepeating(&HotspotConfigMessageHandler::GetTetheringConfig, + base::Unretained(this))); + web_ui()->RegisterMessageCallback( + kSetTetheringConfig, + base::BindRepeating(&HotspotConfigMessageHandler::SetTetheringConfig, + base::Unretained(this))); } private: @@ -540,23 +556,85 @@ std::string callback_id = arg_list[0].GetString(); ShillManagerClient::Get()->GetProperties(base::BindOnce( - &HotspotConfigMessageHandler::OnGetShillTetheringCapabilities, - weak_ptr_factory_.GetWeakPtr(), callback_id)); + &HotspotConfigMessageHandler::OnGetShillManagerDictPropertiesByKey, + weak_ptr_factory_.GetWeakPtr(), callback_id, + shill::kTetheringCapabilitiesProperty)); } - void OnGetShillTetheringCapabilities(const std::string& callback_id, - absl::optional<base::Value> properties) { + void GetTetheringStatus(const base::Value::List& arg_list) { + CHECK_EQ(1u, arg_list.size()); + std::string callback_id = arg_list[0].GetString(); + + ShillManagerClient::Get()->GetProperties(base::BindOnce( + &HotspotConfigMessageHandler::OnGetShillManagerDictPropertiesByKey, + weak_ptr_factory_.GetWeakPtr(), callback_id, + shill::kTetheringStatusProperty)); + } + + void GetTetheringConfig(const base::Value::List& arg_list) { + CHECK_EQ(1u, arg_list.size()); + std::string callback_id = arg_list[0].GetString(); + + ShillManagerClient::Get()->GetProperties(base::BindOnce( + &HotspotConfigMessageHandler::OnGetShillManagerDictPropertiesByKey, + weak_ptr_factory_.GetWeakPtr(), callback_id, + shill::kTetheringConfigProperty)); + } + + void SetTetheringConfig(const base::Value::List& arg_list) { + CHECK_EQ(2u, arg_list.size()); + std::string callback_id = arg_list[0].GetString(); + std::string tethering_config = arg_list[1].GetString(); + absl::optional<base::Value> value = + base::JSONReader::Read(tethering_config); + + if (!value || !value->is_dict()) { + NET_LOG(ERROR) << "Invalid tethering configuration: " << tethering_config; + Respond(callback_id, base::Value("Invalid tethering configuration")); + return; + } + NET_LOG(USER) << "SetManagerProperty: " << shill::kTetheringConfigProperty + << ": " << *value; + ShillManagerClient::Get()->SetProperty( + shill::kTetheringConfigProperty, *value, + base::BindOnce( + &HotspotConfigMessageHandler::SetManagerPropertiesSuccessCallback, + weak_ptr_factory_.GetWeakPtr(), callback_id), + base::BindOnce( + &HotspotConfigMessageHandler::SetManagerPropertiesErrorCallback, + weak_ptr_factory_.GetWeakPtr(), callback_id, + shill::kTetheringConfigProperty)); + } + + void OnGetShillManagerDictPropertiesByKey( + const std::string& callback_id, + const std::string& dict_key, + absl::optional<base::Value> properties) { if (!properties) { - NET_LOG(ERROR) << "Error get tethering capabilities."; - Respond(callback_id, base::Value("Error get tethering capabilities.")); + NET_LOG(ERROR) << "Error getting Shill manager properties."; + Respond(callback_id, + base::Value("Error getting Shill manager properties.")); return; } - const base::Value* tethering_capabilities = - properties->FindDictKey(shill::kTetheringCapabilitiesProperty); - Respond(callback_id, tethering_capabilities - ? tethering_capabilities->Clone() - : base::Value(base::Value::Type::DICTIONARY)); + const base::Value* value = properties->FindDictKey(dict_key); + Respond(callback_id, value ? value->Clone() + : base::Value(base::Value::Type::DICTIONARY)); + } + + void SetManagerPropertiesErrorCallback( + const std::string& callback_id, + const std::string& property_name, + const std::string& dbus_error_name, + const std::string& dbus_error_message) { + NET_LOG(ERROR) << "Error setting Shill manager properties: " + << property_name << ", error: " << dbus_error_name + << ", message: " << dbus_error_message; + Respond(callback_id, base::Value(dbus_error_name)); + } + + void SetManagerPropertiesSuccessCallback(const std::string& callback_id) { + Respond(callback_id, base::Value("success")); } base::WeakPtrFactory<HotspotConfigMessageHandler> weak_ptr_factory_{this}; @@ -732,6 +810,23 @@ "refreshTetheringCapabilitiesButtonText", l10n_util::GetStringUTF16( IDS_NETWORK_UI_REFRESH_TETHERING_CAPABILITIES_BUTTON_TEXT)); + localized_strings.Set( + "tetheringStatusLabel", + l10n_util::GetStringUTF16(IDS_NETWORK_UI_TETHERING_STATUS_LABEL)); + localized_strings.Set( + "refreshTetheringStatusButtonText", + l10n_util::GetStringUTF16( + IDS_NETWORK_UI_REFRESH_TETHERING_STATUS_BUTTON_TEXT)); + localized_strings.Set( + "tetheringConfigLabel", + l10n_util::GetStringUTF16(IDS_NETWORK_UI_TETHERING_CONFIG_LABEL)); + localized_strings.Set( + "refreshTetheringConfigButtonText", + l10n_util::GetStringUTF16( + IDS_NETWORK_UI_REFRESH_TETHERING_CONFIG_BUTTON_TEXT)); + localized_strings.Set("setTetheringConfigButtonText", + l10n_util::GetStringUTF16( + IDS_NETWORK_UI_SET_TETHERING_CONFIG_BUTTON_TEXT)); return localized_strings; }
diff --git a/chrome/browser/ui/webui/help/test_version_updater.h b/chrome/browser/ui/webui/help/test_version_updater.h index ec8ca19..d2249021e 100644 --- a/chrome/browser/ui/webui/help/test_version_updater.h +++ b/chrome/browser/ui/webui/help/test_version_updater.h
@@ -43,6 +43,7 @@ void SetUpdateOverCellularOneTimePermission(StatusCallback callback, const std::string& update_version, int64_t update_size) override {} + void ApplyDeferredUpdate() override {} #endif private:
diff --git a/chrome/browser/ui/webui/help/version_updater.h b/chrome/browser/ui/webui/help/version_updater.h index 7eab1c2..2811138 100644 --- a/chrome/browser/ui/webui/help/version_updater.h +++ b/chrome/browser/ui/webui/help/version_updater.h
@@ -37,7 +37,8 @@ FAILED_HTTP, FAILED_DOWNLOAD, DISABLED, - DISABLED_BY_ADMIN + DISABLED_BY_ADMIN, + DEFERRED }; // Promotion state (Mac-only). @@ -127,6 +128,9 @@ StatusCallback callback, const std::string& update_version, int64_t update_size) = 0; + + // If an update is downloaded but deferred, apply the deferred update. + virtual void ApplyDeferredUpdate() = 0; #endif };
diff --git a/chrome/browser/ui/webui/help/version_updater_chromeos.cc b/chrome/browser/ui/webui/help/version_updater_chromeos.cc index e6f00e6b..9b6c008 100644 --- a/chrome/browser/ui/webui/help/version_updater_chromeos.cc +++ b/chrome/browser/ui/webui/help/version_updater_chromeos.cc
@@ -150,6 +150,15 @@ this->UpdateStatusChanged(update_engine_client->GetLastStatus()); } +void VersionUpdaterCros::ApplyDeferredUpdate() { + UpdateEngineClient* update_engine_client = UpdateEngineClient::Get(); + + DCHECK(update_engine_client->GetLastStatus().current_operation() == + update_engine::Operation::UPDATED_BUT_DEFERRED); + + update_engine_client->ApplyDeferredUpdate(base::DoNothing()); +} + void VersionUpdaterCros::CheckForUpdate(StatusCallback callback, PromoteCallback) { callback_ = std::move(callback); @@ -343,10 +352,12 @@ progress = 100; my_status = UPDATING; break; - case update_engine::Operation::UPDATED_BUT_DEFERRED: case update_engine::Operation::UPDATED_NEED_REBOOT: my_status = NEARLY_UPDATED; break; + case update_engine::Operation::UPDATED_BUT_DEFERRED: + my_status = DEFERRED; + break; default: NOTREACHED(); }
diff --git a/chrome/browser/ui/webui/help/version_updater_chromeos.h b/chrome/browser/ui/webui/help/version_updater_chromeos.h index 5af757a..5d65775 100644 --- a/chrome/browser/ui/webui/help/version_updater_chromeos.h +++ b/chrome/browser/ui/webui/help/version_updater_chromeos.h
@@ -33,6 +33,7 @@ void SetUpdateOverCellularOneTimePermission(StatusCallback callback, const std::string& update_version, int64_t update_size) override; + void ApplyDeferredUpdate() override; // Gets the last update status, without triggering a new check or download. void GetUpdateStatus(StatusCallback callback);
diff --git a/chrome/browser/ui/webui/help/version_updater_chromeos_unittest.cc b/chrome/browser/ui/webui/help/version_updater_chromeos_unittest.cc index 616ef54b..4efe354 100644 --- a/chrome/browser/ui/webui/help/version_updater_chromeos_unittest.cc +++ b/chrome/browser/ui/webui/help/version_updater_chromeos_unittest.cc
@@ -241,4 +241,15 @@ EXPECT_EQ(1, fake_update_engine_client_->is_feature_enabled_count()); } +TEST_F(VersionUpdaterCrosTest, ApplyDeferredUpdate) { + update_engine::StatusResult status; + status.set_current_operation(update_engine::Operation::UPDATED_BUT_DEFERRED); + fake_update_engine_client_->set_default_status(status); + fake_update_engine_client_->NotifyObserversThatStatusChanged(status); + + EXPECT_EQ(0, fake_update_engine_client_->apply_deferred_update_count()); + version_updater_cros_ptr_->ApplyDeferredUpdate(); + EXPECT_EQ(1, fake_update_engine_client_->apply_deferred_update_count()); +} + } // namespace chromeos
diff --git a/chrome/browser/ui/webui/reset_password/reset_password_ui.cc b/chrome/browser/ui/webui/reset_password/reset_password_ui.cc index ca61b25b..5e650603 100644 --- a/chrome/browser/ui/webui/reset_password/reset_password_ui.cc +++ b/chrome/browser/ui/webui/reset_password/reset_password_ui.cc
@@ -142,8 +142,11 @@ base::Value::Dict ResetPasswordUI::PopulateStrings() const { auto* service = safe_browsing::ChromePasswordProtectionService:: GetPasswordProtectionService(Profile::FromWebUI(web_ui())); - std::string org_name = service->GetOrganizationName( - service->reused_password_account_type_for_last_shown_warning()); + std::string org_name = + service + ? service->GetOrganizationName( + service->reused_password_account_type_for_last_shown_warning()) + : std::string(); bool known_password_type = password_type_ != PasswordType::PASSWORD_TYPE_UNKNOWN;
diff --git a/chrome/browser/ui/webui/settings/about_handler.cc b/chrome/browser/ui/webui/settings/about_handler.cc index ee7b1ea..670c647c 100644 --- a/chrome/browser/ui/webui/settings/about_handler.cc +++ b/chrome/browser/ui/webui/settings/about_handler.cc
@@ -251,6 +251,9 @@ case VersionUpdater::NEED_PERMISSION_TO_UPDATE: status_str = "need_permission_to_update"; break; + case VersionUpdater::DEFERRED: + status_str = "deferred"; + break; } return status_str; @@ -309,6 +312,10 @@ "setChannel", base::BindRepeating(&AboutHandler::HandleSetChannel, base::Unretained(this))); web_ui()->RegisterMessageCallback( + "applyDeferredUpdate", + base::BindRepeating(&AboutHandler::HandleApplyDeferredUpdate, + base::Unretained(this))); + web_ui()->RegisterMessageCallback( "requestUpdate", base::BindRepeating(&AboutHandler::HandleRequestUpdate, base::Unretained(this))); web_ui()->RegisterMessageCallback( @@ -605,6 +612,10 @@ ResolveJavascriptCallback(base::Value(callback_id), *channel_info); } +void AboutHandler::HandleApplyDeferredUpdate(const base::Value::List& args) { + version_updater_->ApplyDeferredUpdate(); +} + void AboutHandler::HandleRequestUpdate(const base::Value::List& args) { RequestUpdate(); }
diff --git a/chrome/browser/ui/webui/settings/about_handler.h b/chrome/browser/ui/webui/settings/about_handler.h index da737e2..090e1d0 100644 --- a/chrome/browser/ui/webui/settings/about_handler.h +++ b/chrome/browser/ui/webui/settings/about_handler.h
@@ -122,6 +122,9 @@ const std::string& current_channel, const std::string& target_channel); + // Applies deferred update, triggered by JS. + void HandleApplyDeferredUpdate(const base::Value::List& args); + // Checks for and applies update, triggered by JS. void HandleRequestUpdate(const base::Value::List& args);
diff --git a/chrome/browser/ui/webui/settings/about_handler_unittest.cc b/chrome/browser/ui/webui/settings/about_handler_unittest.cc index 424db6a..3d1ab9f 100644 --- a/chrome/browser/ui/webui/settings/about_handler_unittest.cc +++ b/chrome/browser/ui/webui/settings/about_handler_unittest.cc
@@ -129,6 +129,17 @@ EXPECT_EQ("", CallGetEndOfLifeInfoAndReturnString(false /*=has_eol_passed*/)); } +TEST_F(AboutHandlerTest, DeferredUpdateMessageInAboutPage) { + update_engine::StatusResult status; + status.set_current_operation(update_engine::Operation::UPDATED_BUT_DEFERRED); + fake_update_engine_client_->set_default_status(status); + fake_update_engine_client_->NotifyObserversThatStatusChanged(status); + + EXPECT_EQ(0, fake_update_engine_client_->apply_deferred_update_count()); + web_ui_.HandleReceivedMessage("applyDeferredUpdate", base::Value::List()); + EXPECT_EQ(1, fake_update_engine_client_->apply_deferred_update_count()); +} + } // namespace } // namespace settings
diff --git a/chrome/browser/ui/webui/settings/chromeos/about_section.cc b/chrome/browser/ui/webui/settings/chromeos/about_section.cc index 79cd42e..736865e7 100644 --- a/chrome/browser/ui/webui/settings/chromeos/about_section.cc +++ b/chrome/browser/ui/webui/settings/chromeos/about_section.cc
@@ -260,6 +260,8 @@ {"aboutEndOfLifeTitle", IDS_SETTINGS_ABOUT_PAGE_END_OF_LIFE_TITLE}, {"aboutDeviceName", IDS_SETTINGS_ABOUT_PAGE_DEVICE_NAME}, + {"aboutRelaunchAndAutoUpdate", + IDS_SETTINGS_ABOUT_PAGE_RELAUNCH_AND_AUTO_UPDATE}, {"aboutRelaunchAndPowerwash", IDS_SETTINGS_ABOUT_PAGE_RELAUNCH_AND_POWERWASH}, {"aboutRollbackInProgress", IDS_SETTINGS_UPGRADE_ROLLBACK_IN_PROGRESS},
diff --git a/chrome/browser/ui/webui/settings/chromeos/bluetooth_section.cc b/chrome/browser/ui/webui/settings/chromeos/bluetooth_section.cc index b267479b..ac59338 100644 --- a/chrome/browser/ui/webui/settings/chromeos/bluetooth_section.cc +++ b/chrome/browser/ui/webui/settings/chromeos/bluetooth_section.cc
@@ -153,6 +153,18 @@ return *tags; } +const std::vector<SearchConcept>& GetFastPairSavedDevicesSearchConcepts() { + static const base::NoDestructor<std::vector<SearchConcept>> tags({ + {IDS_OS_SETTINGS_TAG_FAST_PAIR_SAVED_DEVICES, + mojom::kBluetoothSavedDevicesSubpagePath, + mojom::SearchResultIcon::kBluetooth, + mojom::SearchResultDefaultRank::kMedium, + mojom::SearchResultType::kSetting, + {.setting = mojom::Setting::kFastPairSavedDevices}}, + }); + return *tags; +} + } // namespace BluetoothSection::BluetoothSection(Profile* profile, @@ -391,7 +403,8 @@ void BluetoothSection::AddHandlers(content::WebUI* web_ui) { web_ui->AddMessageHandler(std::make_unique<BluetoothHandler>()); - if (features::IsFastPairSavedDevicesEnabled()) { + if (ash::features::IsFastPairEnabled() && + features::IsFastPairSavedDevicesEnabled()) { web_ui->AddMessageHandler(std::make_unique<FastPairSavedDevicesHandler>()); } } @@ -433,7 +446,8 @@ mojom::kBluetoothDevicesSubpagePath); static constexpr mojom::Setting kBluetoothDevicesSettings[] = { mojom::Setting::kBluetoothOnOff, mojom::Setting::kBluetoothPairDevice, - mojom::Setting::kBluetoothUnpairDevice, mojom::Setting::kFastPairOnOff}; + mojom::Setting::kBluetoothUnpairDevice, mojom::Setting::kFastPairOnOff, + mojom::Setting::kFastPairSavedDevices}; static constexpr mojom::Setting kBluetoothDevicesSettingsLegacy[] = { mojom::Setting::kBluetoothConnectToDevice, mojom::Setting::kBluetoothDisconnectFromDevice, @@ -506,6 +520,7 @@ updater.RemoveSearchTags(GetBluetoothOffSearchConcepts()); updater.RemoveSearchTags(GetFastPairOnSearchConcepts()); updater.RemoveSearchTags(GetFastPairOffSearchConcepts()); + updater.RemoveSearchTags(GetFastPairSavedDevicesSearchConcepts()); updater.RemoveSearchTags(GetBluetoothConnectableSearchConcepts()); updater.RemoveSearchTags(GetBluetoothConnectedSearchConcepts()); updater.RemoveSearchTags(GetBluetoothPairableSearchConcepts()); @@ -523,6 +538,10 @@ } else { updater.AddSearchTags(GetFastPairOffSearchConcepts()); } + + if (features::IsFastPairSavedDevicesEnabled()) { + updater.AddSearchTags(GetFastPairSavedDevicesSearchConcepts()); + } } if (!bluetooth_adapter_->IsPowered()) {
diff --git a/chrome/browser/ui/webui/settings/chromeos/constants/setting.mojom b/chrome/browser/ui/webui/settings/chromeos/constants/setting.mojom index 0ebf9fb..b5d05d8b 100644 --- a/chrome/browser/ui/webui/settings/chromeos/constants/setting.mojom +++ b/chrome/browser/ui/webui/settings/chromeos/constants/setting.mojom
@@ -47,6 +47,7 @@ kBluetoothPairDevice = 103, kBluetoothUnpairDevice = 104, kFastPairOnOff = 105, + kFastPairSavedDevices= 106, // MultiDevice section. kSetUpMultiDevice = 200,
diff --git a/chrome/browser/ui/webui/settings/safety_check_handler.cc b/chrome/browser/ui/webui/settings/safety_check_handler.cc index fb609d77..b07c95e 100644 --- a/chrome/browser/ui/webui/settings/safety_check_handler.cc +++ b/chrome/browser/ui/webui/settings/safety_check_handler.cc
@@ -82,6 +82,7 @@ return SafetyCheckHandler::UpdateStatus::kUpdated; case VersionUpdater::UPDATING: return SafetyCheckHandler::UpdateStatus::kUpdating; + case VersionUpdater::DEFERRED: case VersionUpdater::NEED_PERMISSION_TO_UPDATE: case VersionUpdater::NEARLY_UPDATED: return SafetyCheckHandler::UpdateStatus::kRelaunch;
diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc index 0752171..e842fa4 100644 --- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -749,8 +749,8 @@ {"searchLanguages", IDS_SETTINGS_LANGUAGE_SEARCH}, {"languagesExpandA11yLabel", IDS_SETTINGS_LANGUAGES_EXPAND_ACCESSIBILITY_LABEL}, - {"orderBrowserLanguagesInstructions", - IDS_SETTINGS_LANGUAGES_BROWSER_LANGUAGES_LIST_ORDERING_INSTRUCTIONS}, + {"preferredLanguagesDesc", + IDS_SETTINGS_LANGUAGES_PREFERRED_LANGUAGES_DESC}, {"moveToTop", IDS_SETTINGS_LANGUAGES_LANGUAGES_LIST_MOVE_TO_TOP}, {"moveUp", IDS_SETTINGS_LANGUAGES_LANGUAGES_LIST_MOVE_UP}, {"moveDown", IDS_SETTINGS_LANGUAGES_LANGUAGES_LIST_MOVE_DOWN},
diff --git a/chrome/browser/web_applications/app_registrar_observer.h b/chrome/browser/web_applications/app_registrar_observer.h index 666ef50..2d6c7437 100644 --- a/chrome/browser/web_applications/app_registrar_observer.h +++ b/chrome/browser/web_applications/app_registrar_observer.h
@@ -63,6 +63,9 @@ // this event is also fired during browser startup after the policy has been // applied. virtual void OnWebAppSettingsPolicyChanged() {} + + virtual void OnAlwaysShowToolbarInFullscreenChanged(const AppId& app_id, + bool show) {} }; } // namespace web_app
diff --git a/chrome/browser/web_applications/proto/web_app.proto b/chrome/browser/web_applications/proto/web_app.proto index 639216e50..aa83652 100644 --- a/chrome/browser/web_applications/proto/web_app.proto +++ b/chrome/browser/web_applications/proto/web_app.proto
@@ -346,4 +346,8 @@ // Contains customisations to the web app tab strip. Only present when the // display_mode is tabbed. optional proto.TabStrip tab_strip = 57; + + // Only used on Mac OS, stores whether the app should always show the + // toolbar when in fullscreen mode. + optional bool always_show_toolbar_in_fullscreen = 58; }
diff --git a/chrome/browser/web_applications/test/web_app_test_utils.cc b/chrome/browser/web_applications/test/web_app_test_utils.cc index fdf1b2a8..369a0a4 100644 --- a/chrome/browser/web_applications/test/web_app_test_utils.cc +++ b/chrome/browser/web_applications/test/web_app_test_utils.cc
@@ -593,6 +593,8 @@ app->SetTabStrip(std::move(tab_strip)); } + app->SetAlwaysShowToolbarInFullscreen(random.next_bool()); + return app; }
diff --git a/chrome/browser/web_applications/web_app.cc b/chrome/browser/web_applications/web_app.cc index 0784091..df17573 100644 --- a/chrome/browser/web_applications/web_app.cc +++ b/chrome/browser/web_applications/web_app.cc
@@ -434,6 +434,10 @@ return removed; } +void WebApp::SetAlwaysShowToolbarInFullscreen(bool show) { + always_show_toolbar_in_fullscreen_ = show; +} + WebApp::ClientData::ClientData() = default; WebApp::ClientData::~ClientData() = default; @@ -558,7 +562,8 @@ app.app_size_in_bytes_, app.data_size_in_bytes_, app.management_to_external_config_map_, - app.tab_strip_ + app.tab_strip_, + app.always_show_toolbar_in_fullscreen_ // clang-format on ); }; @@ -869,6 +874,9 @@ root.SetKey("tab_strip", base::Value()); } + root.SetBoolKey("always_show_toolbar_in_fullscreen", + always_show_toolbar_in_fullscreen_); + return root; }
diff --git a/chrome/browser/web_applications/web_app.h b/chrome/browser/web_applications/web_app.h index 931ebe2f..e3597b8 100644 --- a/chrome/browser/web_applications/web_app.h +++ b/chrome/browser/web_applications/web_app.h
@@ -296,6 +296,11 @@ return tab_strip_; } + // Only used on Mac. + bool always_show_toolbar_in_fullscreen() const { + return always_show_toolbar_in_fullscreen_; + } + // A Web App can be installed from multiple sources simultaneously. Installs // add a source to the app. Uninstalls remove a source from the app. void AddSource(WebAppManagement::Type source); @@ -398,6 +403,10 @@ bool RemoveInstallUrlForSource(WebAppManagement::Type type, GURL install_url); + // Only used on Mac, determines if the toolbar should be permanently shown + // when in fullscreen. + void SetAlwaysShowToolbarInFullscreen(bool show); + // For logging and debug purposes. bool operator==(const WebApp&) const; bool operator!=(const WebApp&) const; @@ -493,12 +502,18 @@ absl::optional<blink::Manifest::TabStrip> tab_strip_; + // Only used on Mac. + bool always_show_toolbar_in_fullscreen_ = true; + // New fields must be added to: // - |operator==| // - AsDebugValue() // - WebAppDatabase::CreateWebApp() // - WebAppDatabase::CreateWebAppProto() // - CreateRandomWebApp() + // - WebAppTest.EmptyAppAsDebugValue + // - WebAppTest.SampleAppAsDebugValue + // - web_app.proto // If parsed from manifest, also add to: // - ManifestUpdateTask::IsUpdateNeededForManifest() // - SetWebAppManifestFields()
diff --git a/chrome/browser/web_applications/web_app_database.cc b/chrome/browser/web_applications/web_app_database.cc index f778a60e..d1250a3 100644 --- a/chrome/browser/web_applications/web_app_database.cc +++ b/chrome/browser/web_applications/web_app_database.cc
@@ -698,6 +698,9 @@ if (web_app.data_size_in_bytes().has_value()) local_data->set_data_size_in_bytes(web_app.data_size_in_bytes().value()); + local_data->set_always_show_toolbar_in_fullscreen( + web_app.always_show_toolbar_in_fullscreen()); + return local_data; } @@ -1296,6 +1299,11 @@ web_app->SetDataSizeInBytes(local_data.data_size_in_bytes()); } + if (local_data.has_always_show_toolbar_in_fullscreen()) { + web_app->SetAlwaysShowToolbarInFullscreen( + local_data.always_show_toolbar_in_fullscreen()); + } + return web_app; }
diff --git a/chrome/browser/web_applications/web_app_registrar.cc b/chrome/browser/web_applications/web_app_registrar.cc index 56d163e..41c8609 100644 --- a/chrome/browser/web_applications/web_app_registrar.cc +++ b/chrome/browser/web_applications/web_app_registrar.cc
@@ -493,6 +493,20 @@ return GetAppStartUrl(app_id); } +#if BUILDFLAG(IS_MAC) +bool WebAppRegistrar::AlwaysShowToolbarInFullscreen(const AppId& app_id) const { + auto* web_app = GetAppById(app_id); + return web_app ? web_app->always_show_toolbar_in_fullscreen() : true; +} + +void WebAppRegistrar::NotifyAlwaysShowToolbarInFullscreenChanged( + const AppId& app_id, + bool show) { + for (AppRegistrarObserver& observer : observers_) + observer.OnAlwaysShowToolbarInFullscreenChanged(app_id, show); +} +#endif + const WebApp* WebAppRegistrar::GetAppById(const AppId& app_id) const { if (registry_profile_being_deleted_) return nullptr;
diff --git a/chrome/browser/web_applications/web_app_registrar.h b/chrome/browser/web_applications/web_app_registrar.h index c072f015..07b84eb 100644 --- a/chrome/browser/web_applications/web_app_registrar.h +++ b/chrome/browser/web_applications/web_app_registrar.h
@@ -323,6 +323,12 @@ GURL GetAppNewTabUrl(const AppId& app_id) const; +#if BUILDFLAG(IS_MAC) + bool AlwaysShowToolbarInFullscreen(const AppId& app_id) const; + void NotifyAlwaysShowToolbarInFullscreenChanged(const AppId& app_id, + bool show); +#endif + void AddObserver(AppRegistrarObserver* observer); void RemoveObserver(AppRegistrarObserver* observer);
diff --git a/chrome/browser/web_applications/web_app_sync_bridge.cc b/chrome/browser/web_applications/web_app_sync_bridge.cc index 52d4041..685235f 100644 --- a/chrome/browser/web_applications/web_app_sync_bridge.cc +++ b/chrome/browser/web_applications/web_app_sync_bridge.cc
@@ -420,6 +420,20 @@ registrar_->NotifyWebAppProtocolSettingsChanged(); } +#if BUILDFLAG(IS_MAC) +void WebAppSyncBridge::SetAlwaysShowToolbarInFullscreen(const AppId& app_id, + bool show) { + if (!registrar_->IsInstalled(app_id)) + return; + { + ScopedRegistryUpdate(this) + ->UpdateApp(app_id) + ->SetAlwaysShowToolbarInFullscreen(show); + } + registrar_->NotifyAlwaysShowToolbarInFullscreenChanged(app_id, show); +} +#endif + void WebAppSyncBridge::SetAppFileHandlerApprovalState(const AppId& app_id, ApiApprovalState state) { {
diff --git a/chrome/browser/web_applications/web_app_sync_bridge.h b/chrome/browser/web_applications/web_app_sync_bridge.h index 0e35bdb..d270da46 100644 --- a/chrome/browser/web_applications/web_app_sync_bridge.h +++ b/chrome/browser/web_applications/web_app_sync_bridge.h
@@ -10,6 +10,7 @@ #include "base/callback_forward.h" #include "base/memory/raw_ptr.h" #include "base/memory/weak_ptr.h" +#include "build/build_config.h" #include "chrome/browser/web_applications/user_display_mode.h" #include "chrome/browser/web_applications/web_app.h" #include "chrome/browser/web_applications/web_app_constants.h" @@ -131,6 +132,10 @@ void RemoveDisallowedLaunchProtocol(const AppId& app_id, const std::string& protocol_scheme); +#if BUILDFLAG(IS_MAC) + void SetAlwaysShowToolbarInFullscreen(const AppId& app_id, bool show); +#endif + // An access to read-only registry. Does an upcast to read-only type. const WebAppRegistrar& registrar() const { return *registrar_; }
diff --git a/chrome/browser/web_applications/web_app_unittest.cc b/chrome/browser/web_applications/web_app_unittest.cc index 9c11d821..7906302 100644 --- a/chrome/browser/web_applications/web_app_unittest.cc +++ b/chrome/browser/web_applications/web_app_unittest.cc
@@ -172,6 +172,7 @@ "!name": "", "additional_search_terms": [ ], "allowed_launch_protocols": [ ], + "always_show_toolbar_in_fullscreen": true, "app_service_icon_url": "chrome://app-icon/empty_app/32", "app_size_in_bytes": "", "background_color": "none", @@ -249,6 +250,7 @@ "!name": "Name1234", "additional_search_terms": [ "Foo_1234_0" ], "allowed_launch_protocols": [ "web+test_1234_0", "web+test_1234_1" ], + "always_show_toolbar_in_fullscreen": false, "app_service_icon_url": "chrome://app-icon/eajjdjobhihlgobdfaehiiheinneagde/32", "app_size_in_bytes": "4226285750", "background_color": "rgba(77,188,194,0.9686274509803922)",
diff --git a/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc b/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc index ed46050d..e70f11f8 100644 --- a/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc +++ b/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
@@ -601,6 +601,10 @@ const device::FidoAuthenticator* authenticator, bool is_enterprise_attestation, base::OnceCallback<void(bool)> callback) { + if (disable_ui_ && IsVirtualEnvironmentEnabled()) { + std::move(callback).Run(true); + return; + } if (IsWebAuthnRPIDListedInSecurityKeyPermitAttestationPolicy( GetBrowserContext(), relying_party_id)) { // Enterprise attestations should have been approved already and not reach
diff --git a/chrome/browser/webauthn/chrome_authenticator_request_delegate_unittest.cc b/chrome/browser/webauthn/chrome_authenticator_request_delegate_unittest.cc index 904538e..e4c1c006 100644 --- a/chrome/browser/webauthn/chrome_authenticator_request_delegate_unittest.cc +++ b/chrome/browser/webauthn/chrome_authenticator_request_delegate_unittest.cc
@@ -7,7 +7,6 @@ #include <algorithm> #include <utility> -#include "base/logging.h" #include "base/memory/raw_ptr.h" #include "base/test/scoped_command_line.h" #include "base/test/scoped_feature_list.h" @@ -20,15 +19,15 @@ #include "components/prefs/pref_service.h" #include "content/public/browser/authenticator_request_client_delegate.h" #include "content/public/browser/browser_context.h" -#include "content/public/test/web_contents_tester.h" #include "device/fido/cable/cable_discovery_data.h" #include "device/fido/features.h" #include "device/fido/fido_constants.h" -#include "device/fido/fido_device_authenticator.h" #include "device/fido/fido_discovery_factory.h" #include "device/fido/fido_request_handler_base.h" #include "device/fido/fido_transport_protocol.h" #include "device/fido/test_callback_receiver.h" +#include "device/fido/virtual_ctap2_device.h" +#include "device/fido/virtual_fido_device_authenticator.h" #include "testing/gtest/include/gtest/gtest.h" #if BUILDFLAG(IS_WIN) @@ -43,6 +42,8 @@ namespace { +static constexpr char kRelyingPartyID[] = "example.com"; + class ChromeAuthenticatorRequestDelegateTest : public ChromeRenderViewHostTestHarness {}; @@ -369,6 +370,22 @@ } } +// Tests that attestation is returned if the virtual environment is enabled and +// the UI is disabled. +// Regression test for crbug.com/1342458 +TEST_F(ChromeAuthenticatorRequestDelegateTest, VirtualEnvironmentAttestation) { + ChromeAuthenticatorRequestDelegate delegate(main_rfh()); + delegate.DisableUI(); + delegate.SetVirtualEnvironment(true); + device::VirtualFidoDeviceAuthenticator authenticator( + std::make_unique<device::VirtualCtap2Device>()); + device::test::ValueCallbackReceiver<bool> cb; + delegate.ShouldReturnAttestation(kRelyingPartyID, &authenticator, + /*is_enterprise_attestation=*/false, + cb.callback()); + EXPECT_TRUE(cb.value()); +} + #if BUILDFLAG(IS_MAC) std::string TouchIdMetadataSecret(ChromeWebAuthenticationDelegate& delegate, content::BrowserContext* browser_context) { @@ -409,8 +426,6 @@ #if BUILDFLAG(IS_WIN) -static constexpr char kRelyingPartyID[] = "example.com"; - // Tests that ShouldReturnAttestation() returns with true if |authenticator| // is the Windows native WebAuthn API with WEBAUTHN_API_VERSION_2 or higher, // where Windows prompts for attestation in its own native UI.
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index 1981635c..481e60d 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-main-1659095877-4d884c7a5eab80e1488eaffa87e6dfe2615f1cc7.profdata +chrome-linux-main-1659138473-38b692a07c6ce1a9e17725128ff5ea0b6878b671.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt index 5e06170..a06cb03 100644 --- a/chrome/build/mac-arm.pgo.txt +++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@ -chrome-mac-arm-main-1659074243-b61fd94a7aa8173d343b06d6f45f007cad6197a4.profdata +chrome-mac-arm-main-1659138473-cc16a80f4ba8de55cf98b5d0f85d79799bf59297.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt index b05a0fe..8041ece 100644 --- a/chrome/build/mac.pgo.txt +++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@ -chrome-mac-main-1659095877-bda05a504638beafc29bcc2993195129fc7b488a.profdata +chrome-mac-main-1659153757-7ebdf5bcf7cc89e6723a56a54d19838510cac59a.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index b0c514d..b852cd8 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1659074243-dc49b02459ad7d6f98749c7a63f6c9be35c49af0.profdata +chrome-win32-main-1659128176-7637cbce5b324d6da821e88d23e87130667082a8.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index 2f3343a0..8c90204b 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1659106219-0c823a7058975bf5514fd2661071251279ca40fa.profdata +chrome-win64-main-1659138473-dbaa68631543e89de158ce4b4fa4f91274b41ced.profdata
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc index e515e65..7a5b212 100644 --- a/chrome/common/chrome_features.cc +++ b/chrome/common/chrome_features.cc
@@ -269,10 +269,6 @@ const base::Feature kDesktopPWAsEnforceWebAppSettingsPolicy{ "DesktopPWAsEnforceWebAppSettingsPolicy", base::FEATURE_ENABLED_BY_DEFAULT}; -// Enables showing a detailed install dialog for user installs. -const base::Feature kDesktopPWAsDetailedInstallDialog{ - "DesktopPWAsDetailedInstallDialog", base::FEATURE_DISABLED_BY_DEFAULT}; - // Enables or disables Desktop PWAs to be auto-started on OS login. const base::Feature kDesktopPWAsRunOnOsLogin { "DesktopPWAsRunOnOsLogin",
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h index d15760e..6472420 100644 --- a/chrome/common/chrome_features.h +++ b/chrome/common/chrome_features.h
@@ -195,9 +195,6 @@ extern const base::Feature kDesktopPWAsFlashAppNameInsteadOfOrigin; COMPONENT_EXPORT(CHROME_FEATURES) -extern const base::Feature kDesktopPWAsDetailedInstallDialog; - -COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kDesktopPWAsRunOnOsLogin; COMPONENT_EXPORT(CHROME_FEATURES)
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index edc01fd..dfff7a4a 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -31,6 +31,7 @@ import("//components/optimization_guide/features.gni") import("//components/os_crypt/features.gni") import("//components/safe_browsing/buildflags.gni") +import("//components/services/screen_ai/buildflags/features.gni") import("//components/signin/features.gni") import("//components/soda/buildflags.gni") import("//components/spellcheck/spellcheck_build_features.gni") @@ -2341,6 +2342,18 @@ sources += [ "../browser/net/reporting_browsertest.cc" ] } + if (enable_screen_ai_service) { + sources += [ + "../browser/accessibility/ax_screen_ai_annotator.cc", + "../browser/accessibility/ax_screen_ai_annotator.h", + "../browser/accessibility/screen_ai_service_browsertest.cc", + ] + deps += [ + "//components/services/screen_ai/public/cpp:screen_ai_service_router_factory", + "//components/services/screen_ai/public/mojom", + ] + } + if (!is_chromeos_lacros) { sources += [ # crbug.com/1230268 These tests need to be fixed for Lacros. @@ -3823,6 +3836,7 @@ "../browser/ash/policy/login/signin_profile_extensions_policy_browsertest.cc", "../browser/ash/policy/networking/network_policy_application_browsertest.cc", "../browser/ash/policy/networking/policy_certs_browsertest.cc", + "../browser/ash/policy/reporting/user_added_removed/user_added_removed_reporter_browsertest.cc", "../browser/ash/policy/status_collector/child_status_collector_browsertest.cc", "../browser/ash/policy/status_collector/device_status_collector_browsertest.cc", "../browser/ash/policy/status_collector/legacy_device_status_collector_browsertest.cc", @@ -4139,6 +4153,7 @@ "//chrome/browser/ash/system_web_apps/types:types", "//chrome/browser/ash/wilco_dtc_supportd:mojo_utils", "//chrome/browser/chromeos", + "//chrome/browser/chromeos:add_remove_user_event_proto", "//chrome/browser/chromeos:dlp_policy_event_proto", "//chrome/browser/chromeos:key_permissions_proto", "//chrome/browser/chromeos:test_support",
diff --git a/chrome/test/base/OWNERS b/chrome/test/base/OWNERS index e339a22..f0bdc0e 100644 --- a/chrome/test/base/OWNERS +++ b/chrome/test/base/OWNERS
@@ -20,3 +20,5 @@ per-file interactive_test_utils_mac.mm=tapted@chromium.org per-file v8sh.py=file:v8/v8:main:/INFRA_OWNERS + +per-file *devtools*=file://chrome/browser/devtools/OWNERS
diff --git a/chrome/test/base/devtools_listener_browsertest.cc b/chrome/test/base/devtools_listener_browsertest.cc index 8bba0ef..89e1ba9 100644 --- a/chrome/test/base/devtools_listener_browsertest.cc +++ b/chrome/test/base/devtools_listener_browsertest.cc
@@ -42,6 +42,10 @@ bool ShouldForceDevToolsAgentHostCreation() override { return true; } void DevToolsAgentHostCreated(content::DevToolsAgentHost* host) override { + if (host->GetType() != content::DevToolsAgentHost::kTypePage && + host->GetType() != content::DevToolsAgentHost::kTypeFrame) { + return; + } CHECK(devtools_agent_.find(host) == devtools_agent_.end()); devtools_agent_[host] = std::make_unique<DevToolsListener>(host, process_id_);
diff --git a/chrome/test/data/banners/manifest_bottom_sheet_install.json b/chrome/test/data/banners/manifest_with_only_narrow_screenshots.json similarity index 68% copy from chrome/test/data/banners/manifest_bottom_sheet_install.json copy to chrome/test/data/banners/manifest_with_only_narrow_screenshots.json index 7095b85..f76a96c 100644 --- a/chrome/test/data/banners/manifest_bottom_sheet_install.json +++ b/chrome/test/data/banners/manifest_with_only_narrow_screenshots.json
@@ -1,16 +1,12 @@ { - "name": "PWA Bottom Sheet", + "name": "PWA with only narrow screenshots", "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua", "screenshots": [ { - "src": "screenshot1.jpeg", + "src": "screenshot1-portrait.jpeg", "type": "image/jpeg", - "sizes": "728x409" - }, - { - "src": "screenshot2.jpeg", - "type": "image/jpeg", - "sizes": "551x541" + "sizes": "409x728", + "platform": "narrow" } ], "icons": [
diff --git a/chrome/test/data/banners/manifest_bottom_sheet_install.json b/chrome/test/data/banners/manifest_with_only_wide_screenshots.json similarity index 73% copy from chrome/test/data/banners/manifest_bottom_sheet_install.json copy to chrome/test/data/banners/manifest_with_only_wide_screenshots.json index 7095b85..2b434de 100644 --- a/chrome/test/data/banners/manifest_bottom_sheet_install.json +++ b/chrome/test/data/banners/manifest_with_only_wide_screenshots.json
@@ -1,16 +1,12 @@ { - "name": "PWA Bottom Sheet", + "name": "PWA with only wide screenshots", "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua", "screenshots": [ { "src": "screenshot1.jpeg", "type": "image/jpeg", - "sizes": "728x409" - }, - { - "src": "screenshot2.jpeg", - "type": "image/jpeg", - "sizes": "551x541" + "sizes": "728x409", + "platform": "wide" } ], "icons": [
diff --git a/chrome/test/data/banners/manifest_bottom_sheet_install.json b/chrome/test/data/banners/manifest_with_screenshots.json similarity index 75% rename from chrome/test/data/banners/manifest_bottom_sheet_install.json rename to chrome/test/data/banners/manifest_with_screenshots.json index 7095b85..a850181 100644 --- a/chrome/test/data/banners/manifest_bottom_sheet_install.json +++ b/chrome/test/data/banners/manifest_with_screenshots.json
@@ -3,9 +3,16 @@ "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua", "screenshots": [ { + "src": "screenshot1-portrait.jpeg", + "type": "image/jpeg", + "sizes": "409x728", + "platform": "narrow" + }, + { "src": "screenshot1.jpeg", "type": "image/jpeg", - "sizes": "728x409" + "sizes": "728x409", + "platform": "wide" }, { "src": "screenshot2.jpeg",
diff --git a/chrome/test/data/banners/manifest_with_too_many_screenshots.json b/chrome/test/data/banners/manifest_with_too_many_screenshots.json index 6b227ce..a1f15643 100644 --- a/chrome/test/data/banners/manifest_with_too_many_screenshots.json +++ b/chrome/test/data/banners/manifest_with_too_many_screenshots.json
@@ -1,5 +1,5 @@ { - "name": "PWA Bottom Sheet", + "name": "PWA with too many screenshots", "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua", "screenshots": [ {
diff --git a/chrome/test/data/banners/screenshot1-portrait.jpeg b/chrome/test/data/banners/screenshot1-portrait.jpeg new file mode 100644 index 0000000..6941c3a --- /dev/null +++ b/chrome/test/data/banners/screenshot1-portrait.jpeg Binary files differ
diff --git a/chrome/test/data/safe_browsing/malware4.html b/chrome/test/data/safe_browsing/malware4.html new file mode 100644 index 0000000..7006427 --- /dev/null +++ b/chrome/test/data/safe_browsing/malware4.html
@@ -0,0 +1,9 @@ +<html> +<body> +<div foo=1> +<div bar=1> +<embed src="malware_iframe.html"></iframe> +</div> +</div> +</body> +</html>
diff --git a/chrome/test/data/webui/cr_components/help_bubble_mixin_test.ts b/chrome/test/data/webui/cr_components/help_bubble_mixin_test.ts index 2ce3a78..ce99e3bf 100644 --- a/chrome/test/data/webui/cr_components/help_bubble_mixin_test.ts +++ b/chrome/test/data/webui/cr_components/help_bubble_mixin_test.ts
@@ -369,18 +369,18 @@ assertTrue(isVisible(bubble)); }); - const secondParams: HelpBubbleParams = new HelpBubbleParams(); - secondParams.nativeIdentifier = TITLE_NATIVE_ID; - secondParams.closeButtonAltText = CLOSE_BUTTON_ALT_TEXT; - secondParams.position = HelpBubblePosition.BELOW; - secondParams.bodyText = 'This is another help bubble.'; - secondParams.titleText = 'This is a title'; - secondParams.buttons = []; + const paramsWithTitle: HelpBubbleParams = new HelpBubbleParams(); + paramsWithTitle.nativeIdentifier = TITLE_NATIVE_ID; + paramsWithTitle.closeButtonAltText = CLOSE_BUTTON_ALT_TEXT; + paramsWithTitle.position = HelpBubblePosition.BELOW; + paramsWithTitle.bodyText = 'This is another help bubble.'; + paramsWithTitle.titleText = 'This is a title'; + paramsWithTitle.buttons = []; test('help bubble mixin shows multiple bubbles', async () => { testProxy.getCallbackRouterRemote().showHelpBubble(defaultParams); await waitAfterNextRender(container); - testProxy.getCallbackRouterRemote().showHelpBubble(secondParams); + testProxy.getCallbackRouterRemote().showHelpBubble(paramsWithTitle); await waitAfterNextRender(container); assertTrue(container.isHelpBubbleShowing()); const bubble1 = container.getHelpBubbleFor('title'); @@ -396,7 +396,7 @@ test('help bubble mixin shows bubbles with and without title', async () => { testProxy.getCallbackRouterRemote().showHelpBubble(defaultParams); await waitAfterNextRender(container); - testProxy.getCallbackRouterRemote().showHelpBubble(secondParams); + testProxy.getCallbackRouterRemote().showHelpBubble(paramsWithTitle); await waitAfterNextRender(container); assertTrue(container.isHelpBubbleShowing()); const titleBubble = container.getHelpBubbleFor('title')!; @@ -405,13 +405,37 @@ // correctly is present in help_bubble_test.ts, so it is sufficient to // verify that the property is set correctly. assertEquals('', paragraphBubble.titleText); - assertEquals(secondParams.titleText, titleBubble.titleText); + assertEquals(paramsWithTitle.titleText, titleBubble.titleText); }); + const paramsWithProgress: HelpBubbleParams = new HelpBubbleParams(); + paramsWithProgress.nativeIdentifier = LIST_NATIVE_ID; + paramsWithProgress.closeButtonAltText = CLOSE_BUTTON_ALT_TEXT; + paramsWithProgress.position = HelpBubblePosition.BELOW; + paramsWithProgress.bodyText = 'This is another help bubble.'; + paramsWithProgress.progress = {current: 1, total: 3}; + paramsWithProgress.buttons = []; + + test( + 'help bubble mixin shows bubbles with and without progress', async () => { + testProxy.getCallbackRouterRemote().showHelpBubble(defaultParams); + await waitAfterNextRender(container); + testProxy.getCallbackRouterRemote().showHelpBubble(paramsWithProgress); + await waitAfterNextRender(container); + assertTrue(container.isHelpBubbleShowing()); + const paragraphBubble = container.getHelpBubbleFor('p1')!; + const progressBubble = container.getHelpBubbleFor('bulletList')!; + // Testing that setting `progress` will cause the progress to display + // correctly is present in help_bubble_test.ts, so it is sufficient to + // verify that the property is set correctly. + assertFalse(!!paragraphBubble.progress); + assertDeepEquals({current: 1, total: 3}, progressBubble.progress); + }); + test('help bubble mixin hides multiple bubbles', async () => { testProxy.getCallbackRouterRemote().showHelpBubble(defaultParams); await waitAfterNextRender(container); - testProxy.getCallbackRouterRemote().showHelpBubble(secondParams); + testProxy.getCallbackRouterRemote().showHelpBubble(paramsWithTitle); await waitAfterNextRender(container); testProxy.getCallbackRouterRemote().hideHelpBubble( @@ -424,7 +448,7 @@ assertEquals(null, container.getHelpBubbleFor('p1')); testProxy.getCallbackRouterRemote().hideHelpBubble( - secondParams.nativeIdentifier); + paramsWithTitle.nativeIdentifier); await waitAfterNextRender(container); assertFalse(container.isHelpBubbleShowing()); assertEquals(null, container.getHelpBubbleFor('title')); @@ -463,6 +487,7 @@ test('help bubble mixin sends action button clicked event', async () => { container.showHelpBubble('p1', buttonParams); + await waitAfterNextRender(container); // Click one of the action buttons. const button =
diff --git a/chrome/test/data/webui/cr_components/help_bubble_test.ts b/chrome/test/data/webui/cr_components/help_bubble_test.ts index b08643c..490ba49c3 100644 --- a/chrome/test/data/webui/cr_components/help_bubble_test.ts +++ b/chrome/test/data/webui/cr_components/help_bubble_test.ts
@@ -7,13 +7,44 @@ import {CrButtonElement} from '//resources/cr_elements/cr_button/cr_button.m.js'; import {HELP_BUBBLE_DISMISSED_EVENT, HelpBubbleDismissedEvent, HelpBubbleElement} from 'chrome://resources/cr_components/help_bubble/help_bubble.js'; -import {HelpBubblePosition} from 'chrome://resources/cr_components/help_bubble/help_bubble.mojom-webui.js'; +import {HelpBubbleButtonParams, HelpBubblePosition} from 'chrome://resources/cr_components/help_bubble/help_bubble.mojom-webui.js'; import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js'; -import {isVisible} from 'chrome://webui-test/test_util.js'; +import {isVisible, waitAfterNextRender} from 'chrome://webui-test/test_util.js'; suite('CrComponentsHelpBubbleTest', () => { let helpBubble: HelpBubbleElement; + function getNumButtons() { + return helpBubble.$.buttons.querySelectorAll('[id*="action-button"').length; + } + + function getProgressIndicators() { + return helpBubble.$.progress.querySelectorAll('[class*="progress"]'); + } + + /** + * Finds and returns an element with class `name` that can be in the + * topContainer or in the main container of the HelpBubbleElement. If + * `inTopContainer` is true, will locate the element in the top container and + * fail the test if the element is (also) visible in the main body. If + * `inTopContainer` is false, the reverse applies. + */ + function getMovableElement( + name: string, inTopContainer: boolean): HTMLElement { + const query = `.${name}`; + const headerEl = + helpBubble.$.topContainer.querySelector<HTMLElement>(query); + const mainEl = helpBubble.$.main.querySelector<HTMLElement>(query); + assertTrue(!!headerEl); + assertTrue(!!mainEl); + if (inTopContainer) { + assertTrue(mainEl.hidden); + return headerEl; + } + assertTrue(headerEl.hidden); + return mainEl; + } + setup(() => { document.body.innerHTML = ` <div id='container'> @@ -47,7 +78,9 @@ assertEquals( document.querySelector<HTMLElement>('#p1'), helpBubble.getAnchorElement()); - assertEquals(HELP_BUBBLE_BODY, helpBubble.$.body.textContent); + const bodyElement = getMovableElement('body', true); + assertFalse(bodyElement.hidden); + assertEquals(HELP_BUBBLE_BODY, bodyElement.textContent!.trim()); assertTrue(isVisible(helpBubble)); }); @@ -59,8 +92,9 @@ helpBubble.show(); assertTrue(isVisible(helpBubble)); - const titleElement = helpBubble.$.title; - assertEquals(HELP_BUBBLE_TITLE, titleElement.textContent); + const titleElement = getMovableElement('title', true); + assertFalse(titleElement.hidden); + assertEquals(HELP_BUBBLE_TITLE, titleElement.textContent!.trim()); assertTrue(isVisible(titleElement)); }); @@ -71,8 +105,8 @@ helpBubble.show(); assertTrue(isVisible(helpBubble)); - const titleElement = helpBubble.$.title; - assertFalse(isVisible(titleElement)); + const titleElement = getMovableElement('title', true); + assertTrue(titleElement.hidden); }); test('help bubble closes', () => { @@ -100,7 +134,9 @@ assertEquals( document.querySelector<HTMLElement>('#title'), helpBubble.getAnchorElement()); - assertEquals(HELP_BUBBLE_BODY, helpBubble.$.body.textContent); + const bodyElement = getMovableElement('body', true); + assertFalse(bodyElement.hidden); + assertEquals(HELP_BUBBLE_BODY, bodyElement.textContent!.trim()); assertTrue(isVisible(helpBubble)); }); @@ -110,7 +146,7 @@ assertEquals(CLOSE_TEXT, helpBubble.$.close.getAttribute('aria-label')); }); - test('help bubble click close button generates event', () => { + test('help bubble click close button generates event', async () => { let clicked: number = 0; const callback = (e: HelpBubbleDismissedEvent) => { assertEquals('title', e.detail.anchorId); @@ -122,60 +158,73 @@ helpBubble.position = HelpBubblePosition.BELOW; helpBubble.bodyText = HELP_BUBBLE_BODY; helpBubble.show(); + await waitAfterNextRender(helpBubble); const closeButton = helpBubble.$.close; assertEquals(0, clicked); closeButton.click(); assertEquals(1, clicked); }); - test('help bubble adds one button', () => { + test('help bubble adds one button', async () => { helpBubble.anchorId = 'title'; helpBubble.position = HelpBubblePosition.BELOW; helpBubble.bodyText = HELP_BUBBLE_BODY; - helpBubble.buttons = ['button1']; + helpBubble.buttons = [{text: 'button1', isDefault: false}]; helpBubble.show(); - assertEquals(1, helpBubble.$.buttons.children.length); + await waitAfterNextRender(helpBubble); + assertEquals(1, getNumButtons()); const button = helpBubble.getButtonForTesting(0); assertTrue(!!button); - assertEquals(helpBubble.buttons[0], button.textContent); + assertEquals(helpBubble.buttons[0]!.text, button.textContent); assertFalse(button.classList.contains('default-button')); }); - test('help bubble adds several buttons', () => { + test('help bubble adds several buttons', async () => { helpBubble.anchorId = 'title'; helpBubble.position = HelpBubblePosition.BELOW; helpBubble.bodyText = HELP_BUBBLE_BODY; - helpBubble.buttons = ['button1', 'button2', 'button3']; + helpBubble.buttons = [ + {text: 'button1', isDefault: false}, + {text: 'button2', isDefault: false}, + {text: 'button3', isDefault: false}, + ]; helpBubble.show(); - assertEquals(3, helpBubble.$.buttons.children.length); + await waitAfterNextRender(helpBubble); + assertEquals(3, getNumButtons()); for (let i: number = 0; i < 3; ++i) { const button = helpBubble.getButtonForTesting(i); assertTrue(!!button); - assertEquals(helpBubble.buttons[i], button.textContent); + assertEquals(helpBubble.buttons[i]!.text, button.textContent); assertFalse(button.classList.contains('default-button')); } }); - test('help bubble adds default button', () => { + test('help bubble adds default button', async () => { helpBubble.anchorId = 'title'; helpBubble.position = HelpBubblePosition.BELOW; helpBubble.bodyText = HELP_BUBBLE_BODY; - helpBubble.buttons = ['button1']; - helpBubble.defaultButtonIndex = 0; + helpBubble.buttons = [{text: 'button1', isDefault: true}]; helpBubble.show(); + await waitAfterNextRender(helpBubble); const button = helpBubble.getButtonForTesting(0); assertTrue(!!button); assertTrue(button.classList.contains('default-button')); }); - test('help bubble adds default button among several', () => { + const THREE_BUTTONS_MIDDLE_DEFAULT: HelpBubbleButtonParams[] = [ + {text: 'button1', isDefault: false}, + {text: 'button2', isDefault: true}, + {text: 'button3', isDefault: false}, + ]; + + test('help bubble adds default button among several', async () => { helpBubble.anchorId = 'title'; helpBubble.position = HelpBubblePosition.BELOW; helpBubble.bodyText = HELP_BUBBLE_BODY; - helpBubble.buttons = ['button1', 'button2', 'button3']; - helpBubble.defaultButtonIndex = 1; + helpBubble.buttons = THREE_BUTTONS_MIDDLE_DEFAULT; helpBubble.show(); - assertEquals(3, helpBubble.$.buttons.children.length); + await waitAfterNextRender(helpBubble); + assertEquals(3, getNumButtons()); // Make sure all buttons were created as expected, including the default // button. @@ -183,8 +232,8 @@ for (let i: number = 0; i < 3; ++i) { const button = helpBubble.getButtonForTesting(i); assertTrue(!!button); - assertEquals(helpBubble.buttons[i], button.textContent); - const isDefault = (i === helpBubble.defaultButtonIndex); + assertEquals(helpBubble.buttons[i]!.text, button.textContent); + const isDefault = helpBubble.buttons[i]!.isDefault; assertEquals(isDefault, button.classList.contains('default-button')); if (isDefault) { defaultButton = button; @@ -198,7 +247,7 @@ defaultButton, helpBubble.$.buttons.children.item(expectedIndex)); }); - test('help bubble click action button generates event', () => { + test('help bubble click action button generates event', async () => { let clicked: boolean; let buttonIndex: number; const callback = (e: HelpBubbleDismissedEvent) => { @@ -212,13 +261,13 @@ helpBubble.anchorId = 'title'; helpBubble.position = HelpBubblePosition.BELOW; helpBubble.bodyText = HELP_BUBBLE_BODY; - helpBubble.buttons = ['button1', 'button2', 'button3']; - helpBubble.defaultButtonIndex = 1; + helpBubble.buttons = THREE_BUTTONS_MIDDLE_DEFAULT; for (let i: number = 0; i < 3; ++i) { clicked = false; buttonIndex = -1; helpBubble.show(); + await waitAfterNextRender(helpBubble); const button = helpBubble.getButtonForTesting(i); assertTrue(!!button); button.click(); @@ -227,4 +276,103 @@ helpBubble.hide(); } }); + + test('help bubble with no progress doesn\'t show progress', async () => { + helpBubble.anchorId = 'title'; + helpBubble.position = HelpBubblePosition.BELOW; + helpBubble.bodyText = HELP_BUBBLE_BODY; + helpBubble.buttons = THREE_BUTTONS_MIDDLE_DEFAULT; + + helpBubble.show(); + await waitAfterNextRender(helpBubble); + + assertEquals(0, getProgressIndicators().length); + const bodyElement = getMovableElement('body', true); + assertFalse(bodyElement.hidden); + }); + + test( + 'help bubble with no progress and title doesn\'t show progress', + async () => { + helpBubble.anchorId = 'title'; + helpBubble.position = HelpBubblePosition.BELOW; + helpBubble.bodyText = HELP_BUBBLE_BODY; + helpBubble.titleText = HELP_BUBBLE_TITLE; + helpBubble.buttons = THREE_BUTTONS_MIDDLE_DEFAULT; + + helpBubble.show(); + await waitAfterNextRender(helpBubble); + + assertEquals(0, getProgressIndicators().length); + assertFalse(getMovableElement('title', true).hidden); + assertFalse(getMovableElement('body', false).hidden); + }); + + test('help bubble with progress shows progress', async () => { + helpBubble.anchorId = 'title'; + helpBubble.position = HelpBubblePosition.BELOW; + helpBubble.bodyText = HELP_BUBBLE_BODY; + helpBubble.progress = {current: 1, total: 3}; + helpBubble.buttons = THREE_BUTTONS_MIDDLE_DEFAULT; + + helpBubble.show(); + await waitAfterNextRender(helpBubble); + + const elements = getProgressIndicators(); + assertEquals(3, elements.length); + assertTrue(elements.item(0)!.classList.contains('current-progress')); + assertTrue(elements.item(1)!.classList.contains('total-progress')); + assertTrue(elements.item(2)!.classList.contains('total-progress')); + assertFalse(getMovableElement('body', false).hidden); + }); + + test('help bubble with progress and title shows progress', async () => { + helpBubble.anchorId = 'title'; + helpBubble.position = HelpBubblePosition.BELOW; + helpBubble.bodyText = HELP_BUBBLE_BODY; + helpBubble.titleText = HELP_BUBBLE_TITLE; + helpBubble.progress = {current: 1, total: 2}; + helpBubble.buttons = THREE_BUTTONS_MIDDLE_DEFAULT; + + helpBubble.show(); + await waitAfterNextRender(helpBubble); + + const elements = getProgressIndicators(); + assertEquals(2, elements.length); + assertTrue(elements.item(0)!.classList.contains('current-progress')); + assertTrue(elements.item(1)!.classList.contains('total-progress')); + + assertFalse(getMovableElement('title', false).hidden); + assertFalse(getMovableElement('body', false).hidden); + }); + + test('help bubble with full progress', async () => { + helpBubble.anchorId = 'title'; + helpBubble.position = HelpBubblePosition.BELOW; + helpBubble.bodyText = HELP_BUBBLE_BODY; + helpBubble.progress = {current: 2, total: 2}; + + helpBubble.show(); + await waitAfterNextRender(helpBubble); + + const elements = getProgressIndicators(); + assertEquals(2, elements.length); + assertTrue(elements.item(0)!.classList.contains('current-progress')); + assertTrue(elements.item(1)!.classList.contains('current-progress')); + }); + + test('help bubble with empty progress', async () => { + helpBubble.anchorId = 'title'; + helpBubble.position = HelpBubblePosition.BELOW; + helpBubble.bodyText = HELP_BUBBLE_BODY; + helpBubble.progress = {current: 0, total: 2}; + + helpBubble.show(); + await waitAfterNextRender(helpBubble); + + const elements = getProgressIndicators(); + assertEquals(2, elements.length); + assertTrue(elements.item(0)!.classList.contains('total-progress')); + assertTrue(elements.item(1)!.classList.contains('total-progress')); + }); });
diff --git a/chrome/test/data/webui/settings/chromeos/device_page_tests.js b/chrome/test/data/webui/settings/chromeos/device_page_tests.js index d01fff9..fd01ab3 100644 --- a/chrome/test/data/webui/settings/chromeos/device_page_tests.js +++ b/chrome/test/data/webui/settings/chromeos/device_page_tests.js
@@ -715,13 +715,6 @@ let crosAudioConfig; // Static test audio system properties. - const mutedByPolicyFakeAudioSystemProperties = { - outputVolumePercent: 75, - - /** @type {!MuteState} */ - outputMuteState: crosAudioConfigMojomWebui.MuteState.kMutedByPolicy, - }; - const maxVolumePercentFakeAudioSystemProperties = { outputVolumePercent: 100, @@ -736,6 +729,27 @@ outputMuteState: crosAudioConfigMojomWebui.MuteState.kNotMuted, }; + const notMutedFakeAudioSystemProperties = { + outputVolumePercent: 75, + + /** @type {!MuteState} */ + outputMuteState: crosAudioConfigMojomWebui.MuteState.kNotMuted, + }; + + const mutedByUserFakeAudioSystemProperties = { + outputVolumePercent: 75, + + /** @type {!MuteState} */ + outputMuteState: crosAudioConfigMojomWebui.MuteState.kMutedByUser, + }; + + const mutedByPolicyFakeAudioSystemProperties = { + outputVolumePercent: 75, + + /** @type {!MuteState} */ + outputMuteState: crosAudioConfigMojomWebui.MuteState.kMutedByPolicy, + }; + setup(async function() { loadTimeData.overrideValues({ enableAudioSettingsPage: true, @@ -752,9 +766,7 @@ }); }); - test('output slider mojo test', async function() { - await flushTasks(); - + test('output volume mojo test', async function() { const outputVolumeSlider = audioPage.shadowRoot.querySelector('#outputVolumeSlider'); @@ -762,7 +774,6 @@ assertEquals( defaultFakeAudioSystemProperties.outputVolumePercent, outputVolumeSlider.value); - assertFalse(outputVolumeSlider.disabled); // Test max volume case. crosAudioConfig.setAudioSystemProperties( @@ -771,7 +782,6 @@ assertEquals( maxVolumePercentFakeAudioSystemProperties.outputVolumePercent, outputVolumeSlider.value); - assertFalse(outputVolumeSlider.disabled); // Test min volume case. crosAudioConfig.setAudioSystemProperties( @@ -780,15 +790,28 @@ assertEquals( minVolumePercentFakeAudioSystemProperties.outputVolumePercent, outputVolumeSlider.value); + }); + + test('output mute mojo test', async function() { + const outputVolumeSlider = + audioPage.shadowRoot.querySelector('#outputVolumeSlider'); + + // Test default properties. + assertFalse(audioPage.getIsOutputMutedForTest()); assertFalse(outputVolumeSlider.disabled); - // Test kMutedByPolicy case. + // Test muted by user case. + crosAudioConfig.setAudioSystemProperties( + mutedByUserFakeAudioSystemProperties); + await flushTasks(); + assertTrue(audioPage.getIsOutputMutedForTest()); + assertFalse(outputVolumeSlider.disabled); + + // Test muted by policy case. crosAudioConfig.setAudioSystemProperties( mutedByPolicyFakeAudioSystemProperties); await flushTasks(); - assertEquals( - mutedByPolicyFakeAudioSystemProperties.outputVolumePercent, - outputVolumeSlider.value); + assertTrue(audioPage.getIsOutputMutedForTest()); assertTrue(outputVolumeSlider.disabled); }); });
diff --git a/chrome/test/data/webui/settings/chromeos/multidevice_permissions_setup_dialog_tests.js b/chrome/test/data/webui/settings/chromeos/multidevice_permissions_setup_dialog_tests.js index 214b5b7..ad6f84d 100644 --- a/chrome/test/data/webui/settings/chromeos/multidevice_permissions_setup_dialog_tests.js +++ b/chrome/test/data/webui/settings/chromeos/multidevice_permissions_setup_dialog_tests.js
@@ -847,6 +847,72 @@ }); test( + 'Test Camera Roll, Notifications setup flow, notifications rejected', + async () => { + permissionsSetupDialog.setProperties({ + showCameraRoll: true, + showNotifications: true, + showAppStreaming: false, + combinedSetupSupported: true, + }); + flush(); + + assertTrue(!!dialogBody.querySelector('#start-setup-description')); + assertTrue(!!buttonContainer.querySelector('#learnMore')); + assertTrue(!!buttonContainer.querySelector('#cancelButton')); + assertTrue(!!buttonContainer.querySelector('#getStartedButton')); + assertFalse(!!buttonContainer.querySelector('#doneButton')); + assertFalse(!!buttonContainer.querySelector('#tryAgainButton')); + buttonContainer.querySelector('#getStartedButton').click(); + assertEquals( + browserProxy.getCallCount('attemptCombinedFeatureSetup'), 1); + assertArrayEquals( + [true, true], + browserProxy.getArgs('attemptCombinedFeatureSetup')[0]); + assertTrue( + isExpectedFlowState(SetupFlowStatus.WAIT_FOR_PHONE_COMBINED)); + + simulateCombinedStatusChanged( + PermissionsSetupStatus + .SENT_MESSAGE_TO_PHONE_AND_WAITING_FOR_RESPONSE); + assertFalse(!!dialogBody.querySelector('#start-setup-description')); + assertTrue(!!buttonContainer.querySelector('#learnMore')); + assertTrue(!!buttonContainer.querySelector('#cancelButton')); + assertFalse(!!buttonContainer.querySelector('#getStartedButton')); + assertTrue(!!buttonContainer.querySelector('#doneButton')); + assertTrue(buttonContainer.querySelector('#doneButton').disabled); + assertFalse(!!buttonContainer.querySelector('#tryAgainButton')); + assertEquals(browserProxy.getCallCount('setFeatureEnabledState'), 0); + + permissionsSetupDialog.setProperties({ + showCameraRoll: false, + showNotifications: true, + showAppStreaming: false, + combinedSetupSupported: true, + }); + flush(); + + simulateCombinedStatusChanged( + PermissionsSetupStatus.CAMERA_ROLL_GRANTED_NOTIFICATION_REJECTED); + assertFalse(!!dialogBody.querySelector('#start-setup-description')); + assertFalse(!!buttonContainer.querySelector('#learnMore')); + assertFalse(!!buttonContainer.querySelector('#cancelButton')); + assertFalse(!!buttonContainer.querySelector('#getStartedButton')); + assertTrue(!!buttonContainer.querySelector('#doneButton')); + assertFalse(buttonContainer.querySelector('#doneButton').disabled); + assertFalse(!!buttonContainer.querySelector('#tryAgainButton')); + + // Only Camera Roll is enabled. + assertEquals(browserProxy.getCallCount('setFeatureEnabledState'), 1); + + assertTrue( + permissionsSetupDialog.shadowRoot.querySelector('#dialog').open); + buttonContainer.querySelector('#doneButton').click(); + assertFalse( + permissionsSetupDialog.shadowRoot.querySelector('#dialog').open); + }); + + test( 'Test Camera Roll, Notifications and apps setup success flow', async () => { // Simulate all features are granted by the user @@ -1125,6 +1191,99 @@ permissionsSetupDialog.shadowRoot.querySelector('#dialog').open); }); + test( + 'Test all setup flow user granted others rejected cameraRoll permission', + async () => { + // Simulate user grants app permission only + permissionsSetupDialog.setProperties({ + showCameraRoll: true, + showNotifications: true, + showAppStreaming: true, + combinedSetupSupported: true, + }); + flush(); + + assertTrue(!!dialogBody.querySelector('#start-setup-description')); + assertTrue(!!buttonContainer.querySelector('#learnMore')); + assertTrue(!!buttonContainer.querySelector('#cancelButton')); + assertTrue(!!buttonContainer.querySelector('#getStartedButton')); + assertFalse(!!buttonContainer.querySelector('#doneButton')); + assertFalse(!!buttonContainer.querySelector('#tryAgainButton')); + buttonContainer.querySelector('#getStartedButton').click(); + assertEquals( + browserProxy.getCallCount('attemptCombinedFeatureSetup'), 1); + assertArrayEquals( + [true, true], + browserProxy.getArgs('attemptCombinedFeatureSetup')[0]); + assertTrue( + isExpectedFlowState(SetupFlowStatus.WAIT_FOR_PHONE_COMBINED)); + + simulateCombinedStatusChanged( + PermissionsSetupStatus + .SENT_MESSAGE_TO_PHONE_AND_WAITING_FOR_RESPONSE); + assertFalse(!!dialogBody.querySelector('#start-setup-description')); + assertTrue(!!buttonContainer.querySelector('#learnMore')); + assertTrue(!!buttonContainer.querySelector('#cancelButton')); + assertFalse(!!buttonContainer.querySelector('#getStartedButton')); + assertTrue(!!buttonContainer.querySelector('#doneButton')); + assertTrue(buttonContainer.querySelector('#doneButton').disabled); + assertFalse(!!buttonContainer.querySelector('#tryAgainButton')); + assertEquals(browserProxy.getCallCount('setFeatureEnabledState'), 0); + + // Because user rejected, Camera Roll and Notification permissions not + // granted. + permissionsSetupDialog.setProperties({ + showCameraRoll: true, + showNotifications: false, + showAppStreaming: true, + combinedSetupSupported: true, + }); + flush(); + + simulateCombinedStatusChanged( + PermissionsSetupStatus.CAMERA_ROLL_REJECTED_NOTIFICATION_GRANTED); + assertFalse(!!dialogBody.querySelector('#start-setup-description')); + assertFalse(!!buttonContainer.querySelector('#learnMore')); + assertTrue(!!buttonContainer.querySelector('#cancelButton')); + assertFalse(!!buttonContainer.querySelector('#getStartedButton')); + assertFalse(!!buttonContainer.querySelector('#doneButton')); + assertFalse(!!buttonContainer.querySelector('#tryAgainButton')); + + // Should not enabled phone hub camera roll and notification feature + assertEquals(browserProxy.getCallCount('setFeatureEnabledState'), 1); + + assertEquals(browserProxy.getCallCount('attemptAppsSetup'), 1); + assertTrue(isExpectedFlowState(SetupFlowStatus.WAIT_FOR_PHONE_APPS)); + + permissionsSetupDialog.setProperties({ + showCameraRoll: true, + showNotifications: false, + showAppStreaming: false, + combinedSetupSupported: true, + }); + flush(); + + simulateAppsStatusChanged( + PermissionsSetupStatus.COMPLETED_SUCCESSFULLY); + assertFalse(!!dialogBody.querySelector('#start-setup-description')); + assertFalse(!!buttonContainer.querySelector('#learnMore')); + assertFalse(!!buttonContainer.querySelector('#cancelButton')); + assertFalse(!!buttonContainer.querySelector('#getStartedButton')); + assertTrue(!!buttonContainer.querySelector('#doneButton')); + assertFalse(buttonContainer.querySelector('#doneButton').disabled); + assertFalse(!!buttonContainer.querySelector('#tryAgainButton')); + + // The apps feature become enabled when the status becomes + // PermissionsSetupStatus.COMPLETED_SUCCESSFULLY. + assertEquals(browserProxy.getCallCount('setFeatureEnabledState'), 2); + + assertTrue( + permissionsSetupDialog.shadowRoot.querySelector('#dialog').open); + buttonContainer.querySelector('#doneButton').click(); + assertFalse( + permissionsSetupDialog.shadowRoot.querySelector('#dialog').open); + }); + test('Test all setup flow, operation failed or cancelled', async () => { permissionsSetupDialog.setProperties({ showCameraRoll: true,
diff --git a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastContentWindowAndroid.java b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastContentWindowAndroid.java index 489130a4..1653dc8c 100644 --- a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastContentWindowAndroid.java +++ b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastContentWindowAndroid.java
@@ -111,16 +111,6 @@ mComponent.stop(mContext); } - @SuppressWarnings("unused") - @CalledByNative - private void setHostContext(int interactionId, String conversationId) { - if (DEBUG) { - Log.d(TAG, "setInteractionid interactionId=%s; conversationID=%s", interactionId, - conversationId); - } - mComponent.setHostContext(interactionId, conversationId); - } - @Override public void onComponentClosed() { if (DEBUG) Log.d(TAG, "onComponentClosed");
diff --git a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsComponent.java b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsComponent.java index b8e8360..2abb4fbe 100644 --- a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsComponent.java +++ b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsComponent.java
@@ -267,15 +267,6 @@ sendIntentSync(CastWebContentsIntentUtils.enableTouchInput(mSessionId, enabled)); } - public void setHostContext(int interactionId, String conversationId) { - if (DEBUG) { - Log.d(TAG, "setInteractionid interactionId=%s; conversationID=%s", interactionId, - conversationId); - } - sendIntentSync(CastWebContentsIntentUtils.setHostContext( - mSessionId, interactionId, conversationId)); - } - public static void onComponentClosed(String sessionId) { if (DEBUG) Log.d(TAG, "onComponentClosed"); sendIntentSync(CastWebContentsIntentUtils.onActivityStopped(sessionId));
diff --git a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsIntentUtils.java b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsIntentUtils.java index 1431f7c..b9ed112 100644 --- a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsIntentUtils.java +++ b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsIntentUtils.java
@@ -42,32 +42,12 @@ "com.google.android.apps.castshell.intent.action.ON_VISIBILITY_CHANGE"; /** - * Action type of intent from cast app to android to request for a visibility priority change. - */ - public static final String ACTION_REQUEST_VISIBILITY_PRIORITY = - "com.google.android.apps.castshell.intent.action.REQUEST_VISIBILITY_PRIORITY"; - - /** - * Action type of intent from cast app to android to request to move the cast view out of - * screen. - */ - public static final String ACTION_REQUEST_MOVE_OUT = - "com.google.android.apps.castshell.intent.action.REQUEST_MOVE_OUT"; - - /** * Action type of intent from CastWebContentsComponent to notify CastWebContentsActivity that * touch should be enabled. */ public static final String ACTION_ENABLE_TOUCH_INPUT = "com.google.android.apps.castshell.intent.action.ENABLE_TOUCH_INPUT"; - /** - * Action type of intent from CastWebContentsComponent to set interaction ID and conversation ID - * to cast window host. - */ - public static final String ACTION_SET_HOST_CONTEXT = - "com.google.android.apps.castshell.intent.action.SET_HOST_CONTEXT"; - /** Key of extra value in an intent, the value is a URI of cast://webcontents/<instanceId> */ static final String INTENT_EXTRA_URI = "content_uri"; @@ -113,20 +93,6 @@ private static final String INTENT_EXTRA_VISIBILITY_TYPE = "com.google.android.apps.castshell.intent.extra.VISIBILITY_TYPE"; - /** - * Key of extra value of the intent ACTION_SET_HOST_CONTEXT, value is an int of - * interaction ID. - */ - private static final String INTENT_EXTRA_INTERACTION_ID = - "com.google.android.apps.castshell.intent.extra.INTERACTION_ID"; - - /** - * Key of extra value of the intent ACTION_SET_HOST_CONTEXT, value is a string of - * conversation ID. - */ - private static final String INTENT_EXTRA_CONVERSATION_ID = - "com.google.android.apps.castshell.intent.extra.CONVERSATION_ID"; - @VisibilityType static final int VISIBITY_TYPE_UNKNOWN = VisibilityType.UNKNOWN; @VisibilityType @@ -164,16 +130,6 @@ return in.getIntExtra(INTENT_EXTRA_VISIBILITY_TYPE, 0); } - // Used by intent of ACTION_SET_HOST_CONTEXT - public static int getInteractionId(Intent in) { - return in.getIntExtra(INTENT_EXTRA_INTERACTION_ID, 0); - } - - // Used by intent of ACTION_SET_HOST_CONTEXT - public static String getConversationId(Intent in) { - return in.getStringExtra(INTENT_EXTRA_CONVERSATION_ID); - } - public static boolean isIntentOfActivityStopped(Intent in) { return in.getAction().equals(ACTION_ACTIVITY_STOPPED); } @@ -288,20 +244,6 @@ return intent; } - // CastWebContentsComponent -> CastWindowManager - public static Intent setHostContext( - String instanceId, int interactionId, String conversationId) { - if (DEBUG) { - Log.d(TAG, "setInteractionid interactionId=%s; conversationID=%s", interactionId, - conversationId); - } - Intent intent = new Intent(ACTION_SET_HOST_CONTEXT); - intent.putExtra(INTENT_EXTRA_URI, getInstanceUri(instanceId).toString()); - intent.putExtra(INTENT_EXTRA_INTERACTION_ID, interactionId); - intent.putExtra(INTENT_EXTRA_CONVERSATION_ID, conversationId); - return intent; - } - public static Uri getInstanceUri(String instanceId) { Uri instanceUri = new Uri.Builder() .scheme(ACTION_DATA_SCHEME)
diff --git a/chromecast/browser/android/cast_content_window_android.cc b/chromecast/browser/android/cast_content_window_android.cc index 0ef159f9..02fd17b 100644 --- a/chromecast/browser/android/cast_content_window_android.cc +++ b/chromecast/browser/android/cast_content_window_android.cc
@@ -9,7 +9,6 @@ #include "base/android/jni_android.h" #include "base/android/jni_string.h" #include "base/android/scoped_java_ref.h" -#include "base/logging.h" #include "chromecast/browser/jni_headers/CastContentWindowAndroid_jni.h" #include "content/public/browser/web_contents.h" @@ -31,9 +30,6 @@ turn_on_screen, ConvertUTF8ToJavaString(env, session_id)); } -constexpr char kContextInteractionId[] = "interactionId"; -constexpr char kContextConversationId[] = "conversationId"; - } // namespace CastContentWindowAndroid::CastContentWindowAndroid( @@ -98,20 +94,7 @@ void CastContentWindowAndroid::SetActivityContext( base::Value activity_context) {} -void CastContentWindowAndroid::SetHostContext(base::Value host_context) { - auto* found_interaction_id = host_context.FindKey(kContextInteractionId); - auto* found_conversation_id = host_context.FindKey(kContextConversationId); - if (found_interaction_id && found_conversation_id) { - int interaction_id = found_interaction_id->GetInt(); - std::string& conversation_id = found_conversation_id->GetString(); - JNIEnv* env = base::android::AttachCurrentThread(); - Java_CastContentWindowAndroid_setHostContext( - env, java_window_, static_cast<int>(interaction_id), - ConvertUTF8ToJavaString(env, conversation_id)); - } else { - LOG(ERROR) << "Interaction ID or Conversation ID is not found"; - } -} +void CastContentWindowAndroid::SetHostContext(base::Value host_context) {} void CastContentWindowAndroid::RequestMoveOut() {}
diff --git a/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/CastWebContentsIntentUtilsTest.java b/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/CastWebContentsIntentUtilsTest.java index 3050da1..781a4352 100644 --- a/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/CastWebContentsIntentUtilsTest.java +++ b/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/CastWebContentsIntentUtilsTest.java
@@ -139,15 +139,4 @@ Assert.assertNotNull(uri); Assert.assertEquals(EXPECTED_URI, uri); } - - @Test - public void testSetHostContext() { - Intent in = CastWebContentsIntentUtils.setHostContext(SESSION_ID, 123, "foo"); - String uri = CastWebContentsIntentUtils.getUriString(in); - Assert.assertNotNull(uri); - Assert.assertEquals(EXPECTED_URI, uri); - Assert.assertEquals(CastWebContentsIntentUtils.ACTION_SET_HOST_CONTEXT, in.getAction()); - Assert.assertEquals(CastWebContentsIntentUtils.getInteractionId(in), 123); - Assert.assertEquals(CastWebContentsIntentUtils.getConversationId(in), "foo"); - } }
diff --git a/chromeos/ash/components/dbus/update_engine/fake_update_engine_client.cc b/chromeos/ash/components/dbus/update_engine/fake_update_engine_client.cc index 447c094..20d6054 100644 --- a/chromeos/ash/components/dbus/update_engine/fake_update_engine_client.cc +++ b/chromeos/ash/components/dbus/update_engine/fake_update_engine_client.cc
@@ -122,7 +122,9 @@ } void FakeUpdateEngineClient::ApplyDeferredUpdate( - base::OnceClosure failure_callback) {} + base::OnceClosure failure_callback) { + apply_deferred_update_count_++; +} void FakeUpdateEngineClient::set_default_status( const update_engine::StatusResult& status) {
diff --git a/chromeos/ash/components/dbus/update_engine/fake_update_engine_client.h b/chromeos/ash/components/dbus/update_engine/fake_update_engine_client.h index fc9e378..2c19558f 100644 --- a/chromeos/ash/components/dbus/update_engine/fake_update_engine_client.h +++ b/chromeos/ash/components/dbus/update_engine/fake_update_engine_client.h
@@ -128,6 +128,11 @@ // Returns how many times |IsFeatureEnabled()| is called. int is_feature_enabled_count() const { return is_feature_enabled_count_; } + // Returns how many times |ApplyDeferredUpdate()| is called. + int apply_deferred_update_count() const { + return apply_deferred_update_count_; + } + void SetToggleFeature(const std::string& feature, absl::optional<bool> opt_enabled); @@ -147,6 +152,7 @@ int update_over_cellular_one_time_permission_count_ = 0; int toggle_feature_count_ = 0; int is_feature_enabled_count_ = 0; + int apply_deferred_update_count_ = 0; std::map<std::string, absl::optional<bool>> features_; base::Time eol_date_; };
diff --git a/components/exo/shell_surface_base.cc b/components/exo/shell_surface_base.cc index d036c7e..0495942 100644 --- a/components/exo/shell_surface_base.cc +++ b/components/exo/shell_surface_base.cc
@@ -1350,8 +1350,12 @@ // Start tracking changes to window bounds and window state. window->AddObserver(this); - // `window_state` can be null when the window type is menu. - if (!is_menu_) + ash::WindowState* window_state = ash::WindowState::Get(window); + // Skip initializing window state when it is menu. + // TODO(crbug.com/1338597): Remove `window_state` condition when tooltip fix + // is done. Without the fix, window_state can be null when it is tooltip and + // the parent window is menu, so add null check of `window_state` here. + if (!is_menu_ && window_state) InitializeWindowState(ash::WindowState::Get(window)); SetShellUseImmersiveForFullscreen(window, immersive_implied_by_fullscreen_);
diff --git a/components/lookalikes/core/lookalike_url_util.cc b/components/lookalikes/core/lookalike_url_util.cc index dd5f853e..3f4e73f3 100644 --- a/components/lookalikes/core/lookalike_url_util.cc +++ b/components/lookalikes/core/lookalike_url_util.cc
@@ -543,6 +543,59 @@ return 0; } +// Brand names with length of 4 or less should not be checked in domains for +// Combo Squatting. Short brand names can cause false positives in results. +bool IsComboSquattingCandidate(const std::string& brand) { + return brand.size() > kMinBrandNameLengthForComboSquatting; +} + +// Extract brand names from engaged sites to be checked for Combo Squatting, if +// the brand is not one of the hard coded brand names. +std::vector<std::string> GetBrandNamesFromEngagedSites( + const std::vector<DomainInfo>& engaged_sites) { + std::vector<std::string> output; + + for (const DomainInfo& engaged_site : engaged_sites) { + std::string domain_without_registry = engaged_site.domain_without_registry; + if (IsComboSquattingCandidate(domain_without_registry)) { + output.emplace_back(domain_without_registry); + } + } + return output; +} + +// Returns true if the navigated_domain is flagged as Combo Squatting. +// matched_domain is the suggested domain that will be shown to the user +// instead of the navigated_domain in the warning UI. +bool IsComboSquatting(const std::vector<std::string>& brand_names, + const ComboSquattingParams& combo_squatting_params, + const DomainInfo& navigated_domain, + std::string* matched_domain) { + // Check if the domain has any brand name and any popular keyword. + for (auto& brand : brand_names) { + DCHECK(IsComboSquattingCandidate(brand)); + + if (navigated_domain.domain_without_registry.size() == brand.size() || + navigated_domain.domain_without_registry.find(brand) == + std::string::npos) { + continue; + } + + for (size_t j = 0; j < combo_squatting_params.num_popular_keywords; j++) { + auto* const keyword = combo_squatting_params.popular_keywords[j]; + if (navigated_domain.domain_without_registry.find(keyword) != + std::string::npos && + std::string(brand).find(keyword) == std::string::npos && + std::string(keyword).find(brand) == std::string::npos) { + // TODO(crbug.com/1341320): Compute a better matched_domain. + *matched_domain = std::string(brand) + ".com"; + return true; + } + } + } + return false; +} + } // namespace DomainInfo::DomainInfo(const std::string& arg_hostname, @@ -842,13 +895,20 @@ } // If none of the previous heuristics work, check it for Combo Squatting. - if (IsComboSquatting(navigated_domain, matched_domain)) { + ComboSquattingType combo_squatting_type = + GetComboSquattingType(navigated_domain, engaged_sites, matched_domain); + if (combo_squatting_type == ComboSquattingType::kHardCoded) { *match_type = LookalikeUrlMatchType::kComboSquatting; DCHECK(!matched_domain->empty()); return true; + } else if (combo_squatting_type == ComboSquattingType::kSiteEngagement) { + *match_type = LookalikeUrlMatchType::kComboSquattingSiteEngagement; + DCHECK(!matched_domain->empty()); + return true; } DCHECK(embedding_type == TargetEmbeddingType::kNone); + DCHECK(combo_squatting_type == ComboSquattingType::kNone); return false; } @@ -888,6 +948,9 @@ case LookalikeUrlMatchType::kComboSquatting: RecordEvent(NavigationSuggestionEvent::kComboSquatting); break; + case LookalikeUrlMatchType::kComboSquattingSiteEngagement: + RecordEvent(NavigationSuggestionEvent::kComboSquattingSiteEngagement); + break; case LookalikeUrlMatchType::kNone: break; } @@ -1224,34 +1287,29 @@ kPopularKeywordsforCSQ, std::size(kPopularKeywordsforCSQ)}; } -bool IsComboSquatting(const DomainInfo& navigated_domain, - std::string* matched_domain) { - // TODO(crbug.com/1341023): We should check the domain in allowlist once we - // start getting metrics in future iterations. - ComboSquattingParams* combo_squatting_params = GetComboSquattingParams(); - // Check if the domain has any brand name and any popular keyword. +ComboSquattingType GetComboSquattingType( + const DomainInfo& navigated_domain, + const std::vector<DomainInfo>& engaged_sites, + std::string* matched_domain) { + const ComboSquattingParams* combo_squatting_params = + GetComboSquattingParams(); + + // First check Combo Squatting with hard coded brand names. + std::vector<std::string> brand_names; for (size_t i = 0; i < combo_squatting_params->num_brand_names; i++) { - auto* const brand = combo_squatting_params->brand_names[i]; - DCHECK(std::string(brand).size() > kMinBrandNameLengthForComboSquatting); - - if (!(navigated_domain.domain_without_registry.find(brand) != - std::string::npos && - navigated_domain.domain_without_registry.size() != strlen(brand))) { - continue; - } - - for (size_t j = 0; j < combo_squatting_params->num_popular_keywords; j++) { - auto* const keyword = combo_squatting_params->popular_keywords[j]; - if (navigated_domain.domain_without_registry.find(keyword) != - std::string::npos && - std::string(brand).find(keyword) == std::string::npos && - std::string(keyword).find(brand) == std::string::npos) { - // TODO(crbug.com/1341320): In future cls we will compute a better - // suggestion for each domain. - *matched_domain = std::string(brand) + ".com"; - return true; - } - } + brand_names.emplace_back(combo_squatting_params->brand_names[i]); } - return false; + if (IsComboSquatting(brand_names, *combo_squatting_params, navigated_domain, + matched_domain)) { + return ComboSquattingType::kHardCoded; + } + + // Then check Combo Squatting with brand names in engaged sites. + brand_names = GetBrandNamesFromEngagedSites(engaged_sites); + if (IsComboSquatting(brand_names, *combo_squatting_params, navigated_domain, + matched_domain)) { + return ComboSquattingType::kSiteEngagement; + } + + return ComboSquattingType::kNone; }
diff --git a/components/lookalikes/core/lookalike_url_util.h b/components/lookalikes/core/lookalike_url_util.h index facc8f2..e4be994 100644 --- a/components/lookalikes/core/lookalike_url_util.h +++ b/components/lookalikes/core/lookalike_url_util.h
@@ -43,6 +43,15 @@ kSafetyTip = 2, }; +// Used for |GetComboSquattingType| return value. +// It shows if the brand name in the flagged domain +// comes from the hard-coded brand names or from site engagements. +enum class ComboSquattingType { + kNone = 0, + kHardCoded = 1, + kSiteEngagement = 2, +}; + // Used for UKM. There is only a single LookalikeUrlMatchType per navigation. enum class LookalikeUrlMatchType { kNone = 0, @@ -64,15 +73,17 @@ kCharacterSwapSiteEngagement = 10, kCharacterSwapTop500 = 11, - // In contrast to other heuristics that use - // Top500 and SiteEngagement domains, Combo Squatting uses manually - // curated lists of brand names and keywords that are hardcoded as - // kBrandNamesforCSQ and kPopularKeywordsforCSQ in lookalike_url_util.cc. + // Combo Squatting uses manually + // curated lists of hard-coded keywords (kPopularKeywordsforCSQ in + // lookalike_url_util.cc) and both manually curated hard-coded brand names + // (kBrandNamesforCSQ in lookalike_url_util.cc) and brand names from + // SiteEngagement to flag domains. kComboSquatting = 12, + kComboSquattingSiteEngagement = 13, // Append new items to the end of the list above; do not modify or replace // existing values. Comment out obsolete items. - kMaxValue = kComboSquatting, + kMaxValue = kComboSquattingSiteEngagement, }; // Used for UKM. There is only a single LookalikeUrlBlockingPageUserAction per @@ -107,10 +118,11 @@ kMatchCharacterSwapSiteEngagement = 12, kMatchCharacterSwapTop500 = 13, kComboSquatting = 14, + kComboSquattingSiteEngagement = 15, // Append new items to the end of the list above; do not modify or // replace existing values. Comment out obsolete items. - kMaxValue = kComboSquatting, + kMaxValue = kComboSquattingSiteEngagement, }; struct Top500DomainsParams { @@ -277,10 +289,13 @@ // Reset brand names and keywords after testing Combo Squatting heuristic. void ResetComboSquattingParamsForTesting(); -// Returns true if the navigated_domain is flagged as Combo Squatting. -// matched_domain is the suggested domain that will be shown to the user -// instead of the navigated_domain in the warning UI. -bool IsComboSquatting(const DomainInfo& navigated_domain, - std::string* matched_domain); +// Check if |navigated_domain| is Combo Squatting lookalike. +// It gets |engaged_sites| to use its brand names in addition to hard coded +// brand names. The function sets |matched_domain| to suggest to the user +// instead of the Combo Squatting domain. +ComboSquattingType GetComboSquattingType( + const DomainInfo& navigated_domain, + const std::vector<DomainInfo>& engaged_sites, + std::string* matched_domain); #endif // COMPONENTS_LOOKALIKES_CORE_LOOKALIKE_URL_UTIL_H_
diff --git a/components/lookalikes/core/lookalike_url_util_unittest.cc b/components/lookalikes/core/lookalike_url_util_unittest.cc index 028e1b6b..104c23762 100644 --- a/components/lookalikes/core/lookalike_url_util_unittest.cc +++ b/components/lookalikes/core/lookalike_url_util_unittest.cc
@@ -611,66 +611,86 @@ // Test for Combo Squatting check of domains. TEST_F(ComboSquattingTest, IsComboSquatting) { + const std::vector<DomainInfo> kEngagedSites = { + // An engaged site which is not in the hard coded brand names. + GetDomainInfo(GURL("https://engagedsite.com")), + // An engaged site which is duplicate with a hard coded brand name. + GetDomainInfo(GURL("https://subdomain.google.com")), + // An engaged site with length less than threshold (4) for + // consideration. + GetDomainInfo(GURL("https://len.com")), + }; const struct TestCase { const char* domain; const char* expected_suggested_domain; - bool expected_result; + const ComboSquattingType expected_type; + ; } kTestCases[] = { // Not Combo Squatting (CSQ). - {"google.com", "", false}, - {"youtube.ca", "", false}, + {"google.com", "", ComboSquattingType::kNone}, + {"youtube.ca", "", ComboSquattingType::kNone}, // Not CSQ, contains subdomains. - {"login.google.com", "", false}, + {"login.google.com", "", ComboSquattingType::kNone}, // Not CSQ, non registrable domains. - {"google-login.test", "", false}, + {"google-login.test", "", ComboSquattingType::kNone}, // CSQ with "-". - {"google-online.com", "google.com", true}, + {"google-online.com", "google.com", ComboSquattingType::kHardCoded}, // CSQ with more than one keyword (login, online) with "-". - {"google-login-online.com", "google.com", true}, + {"google-login-online.com", "google.com", ComboSquattingType::kHardCoded}, // CSQ with one keyword (online) and one random word (one) with "-". - {"one-sample-online.com", "sample.com", true}, + {"one-sample-online.com", "sample.com", ComboSquattingType::kHardCoded}, // Not CSQ, with a keyword (test) as TLD. - {"www.example.test", "", false}, + {"www.example.test", "", ComboSquattingType::kNone}, // CSQ with more than one brand (google, youtube) with "-". - {"google-youtube-account.com", "google.com", true}, + {"google-youtube-account.com", "google.com", + ComboSquattingType::kHardCoded}, // CSQ without separator. - {"loginsample.com", "sample.com", true}, + {"loginsample.com", "sample.com", ComboSquattingType::kHardCoded}, // Not CSQ with a keyword (ample) inside brand name (sample). - {"sample.com", "", false}, + {"sample.com", "", ComboSquattingType::kNone}, // Current version of the heuristic cannot flag this kind of CSQ // with a keyword (ample) inside brand name (sample) and as an added // keyword to the domain. - {"sample-ample.com", "", false}, + {"sample-ample.com", "", ComboSquattingType::kNone}, // CSQ with more than one keyword (account, online) without separator. - {"accountexampleonline.com", "example.com", true}, + {"accountexampleonline.com", "example.com", + ComboSquattingType::kHardCoded}, // CSQ with one keyword (login) and one random word (one) without "-". - {"oneyoutubelogin.com", "youtube.com", true}, + {"oneyoutubelogin.com", "youtube.com", ComboSquattingType::kHardCoded}, // Not CSQ, google is a public TLD. - {"online.google", "", false}, + {"online.google", "", ComboSquattingType::kNone}, // Not CSQ, brand name (vice) is part of keyword (service). - {"keyservices.com", "", false}, + {"keyservices.com", "", ComboSquattingType::kNone}, + + // CSQ, brand name (engagedsite) is from engaged sites list. + {"engagedsite-login.com", "engagedsite.com", + ComboSquattingType::kSiteEngagement}, + + // Not CSQ, brand name (len) is from engaged sites list but it is short. + {"len-online.com", "", ComboSquattingType::kNone}, }; for (const TestCase& test_case : kTestCases) { auto navigated = GetDomainInfo(GURL(std::string(url::kHttpsScheme) + url::kStandardSchemeSeparator + test_case.domain)); std::string matched_domain; - bool result = IsComboSquatting(navigated, &matched_domain); + ComboSquattingType type = + GetComboSquattingType(navigated, kEngagedSites, &matched_domain); EXPECT_EQ(std::string(test_case.expected_suggested_domain), matched_domain); - EXPECT_EQ(test_case.expected_result, result); + EXPECT_EQ(test_case.expected_type, type); } } \ No newline at end of file
diff --git a/components/omnibox/browser/omnibox_field_trial.cc b/components/omnibox/browser/omnibox_field_trial.cc index c4712a2..c9e15056 100644 --- a/components/omnibox/browser/omnibox_field_trial.cc +++ b/components/omnibox/browser/omnibox_field_trial.cc
@@ -907,6 +907,11 @@ "RichAutocompletionAutocompleteShowAdditionalText", true); +const base::FeatureParam<bool> kRichAutocompletionAdditionalTextWithParenthesis( + &omnibox::kRichAutocompletion, + "RichAutocompletionAdditionalTextWithParenthesis", + false); + const base::FeatureParam<bool> kRichAutocompletionAutocompleteShortcutText( &omnibox::kRichAutocompletion, "RichAutocompletionAutocompleteShortcutText",
diff --git a/components/omnibox/browser/omnibox_field_trial.h b/components/omnibox/browser/omnibox_field_trial.h index 7c7509e..918ae7f 100644 --- a/components/omnibox/browser/omnibox_field_trial.h +++ b/components/omnibox/browser/omnibox_field_trial.h
@@ -563,6 +563,8 @@ kRichAutocompletionAutocompleteNonPrefixMinChar; extern const base::FeatureParam<bool> kRichAutocompletionShowAdditionalText; extern const base::FeatureParam<bool> + kRichAutocompletionAdditionalTextWithParenthesis; +extern const base::FeatureParam<bool> kRichAutocompletionAutocompleteShortcutText; extern const base::FeatureParam<int> kRichAutocompletionAutocompleteShortcutTextMinChar;
diff --git a/components/optimization_guide/core/hints_processing_util.cc b/components/optimization_guide/core/hints_processing_util.cc index 0f62f13..2c0cae1 100644 --- a/components/optimization_guide/core/hints_processing_util.cc +++ b/components/optimization_guide/core/hints_processing_util.cc
@@ -67,6 +67,8 @@ return "HistoryClusters"; case proto::OptimizationType::THANK_CREATOR_ELIGIBLE: return "ThankCreatorEligible"; + case proto::OptimizationType::IBAN_AUTOFILL_BLOCKED: + return "IBANAutofillBlocked"; } // The returned string is used to record histograms for the optimization type.
diff --git a/components/optimization_guide/proto/hints.proto b/components/optimization_guide/proto/hints.proto index ffef327..5a0ece2d 100644 --- a/components/optimization_guide/proto/hints.proto +++ b/components/optimization_guide/proto/hints.proto
@@ -163,6 +163,9 @@ HISTORY_CLUSTERS = 23; // Determines if a page is eligible for 'Thank creator' functionality. THANK_CREATOR_ELIGIBLE = 24; + // This optimization provides information about hosts that are blocked for + // IBAN autofill. + IBAN_AUTOFILL_BLOCKED = 25; } // Presents semantics for how page load URLs should be matched.
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json index e31a8c47..d5b2027 100644 --- a/components/policy/resources/policy_templates.json +++ b/components/policy/resources/policy_templates.json
@@ -10254,6 +10254,16 @@ 'dynamic_refresh': True, 'per_profile': True, }, + 'items': [ + { + 'value': True, + 'caption': 'Enable policy atomic groups', + }, + { + 'value': False, + 'caption': 'Disable policy atomic groups', + }, + ], 'example_value': True, 'id': 584, 'caption': '''Enables the concept of policy atomic groups''', @@ -10707,6 +10717,16 @@ 'dynamic_refresh': True, 'per_profile': True, }, + 'items': [ + { + 'value': True, + 'caption': 'Enable submission of documents to <ph name="CLOUD_PRINT_NAME">Google Cloud Print</ph>', + }, + { + 'value': False, + 'caption': 'Disable submission of documents to <ph name="CLOUD_PRINT_NAME">Google Cloud Print</ph>', + }, + ], 'deprecated': True, 'example_value': True, 'id': 109, @@ -10762,6 +10782,16 @@ 'dynamic_refresh': False, 'per_profile': True, }, + 'items': [ + { + 'value': True, + 'caption': 'Disable print preview', + }, + { + 'value': False, + 'caption': 'Enable print preview', + }, + ], 'example_value': False, 'id': 117, 'caption': '''Disable Print Preview''', @@ -10781,6 +10811,21 @@ 'dynamic_refresh': True, 'per_profile': True, }, + 'items': [ + { + 'value': True, + 'caption': 'Show headers and footers in print preview', + }, + { + 'value': False, + 'caption': 'Hide headers and footers in print preview', + }, + { + 'value': None, + 'caption': 'Allow the user to decide', + }, + ], + 'default': None, 'example_value': False, 'id': 480, 'caption': '''Print Headers and Footers''', @@ -10859,6 +10904,16 @@ 'dynamic_refresh': True, 'per_profile': False, }, + 'items': [ + { + 'value': True, + 'caption': 'Allow online <ph name="OCSP_CRL_LABEL">OCSP/CRL</ph> checks to be performed', + }, + { + 'value': False, + 'caption': 'Prevent online <ph name="OCSP_CRL_LABEL">OCSP/CRL</ph> checks from being performed', + }, + ], 'example_value': False, 'id': 129, 'caption': '''Enable online OCSP/CRL checks''', @@ -10908,6 +10963,16 @@ 'dynamic_refresh': True, 'per_profile': False, }, + 'items': [ + { + 'value': True, + 'caption': 'Allow SHA-1 signed certificates issued by local trust anchors', + }, + { + 'value': False, + 'caption': 'Disallow SHA-1 signed certificates', + }, + ], 'deprecated': True, 'example_value': False, 'id': 340, @@ -10929,6 +10994,16 @@ 'dynamic_refresh': True, 'per_profile': False, }, + 'items': [ + { + 'value': True, + 'caption': 'Allow certificates lacking a subjectAlternativeName extension when issued by local trust anchors', + }, + { + 'value': False, + 'caption': 'Disallow certificates lacking a subjectAlternativeName extension', + }, + ], 'deprecated': True, 'example_value': False, 'id': 366,
diff --git a/components/reporting/client/report_queue_impl.cc b/components/reporting/client/report_queue_impl.cc index 9f564c8..d39544c 100644 --- a/components/reporting/client/report_queue_impl.cc +++ b/components/reporting/client/report_queue_impl.cc
@@ -11,18 +11,15 @@ #include "base/bind.h" #include "base/callback.h" -#include "base/json/json_writer.h" +#include "base/check.h" #include "base/memory/ptr_util.h" -#include "base/memory/ref_counted.h" #include "base/memory/scoped_refptr.h" #include "base/notreached.h" #include "base/sequence_checker.h" -#include "base/strings/strcat.h" #include "base/task/bind_post_task.h" #include "base/task/task_traits.h" #include "base/task/thread_pool.h" #include "base/time/time.h" -#include "base/values.h" #include "components/reporting/client/report_queue_configuration.h" #include "components/reporting/proto/synced/record.pb.h" #include "components/reporting/proto/synced/record_constants.pb.h" @@ -179,12 +176,18 @@ return; } DCHECK_CALLED_ON_VALID_SEQUENCE(self->sequence_checker_); - if (!self->report_queue_) { + if (!self->status_or_report_queue_.has_value()) { std::move(callback).Run(Status(error::FAILED_PRECONDITION, "ReportQueue is not ready yet.")); return; } - self->report_queue_->Flush(priority, std::move(callback)); + if (!self->status_or_report_queue_->ok()) { + std::move(callback).Run(self->status_or_report_queue_->status()); + return; + } + const std::unique_ptr<ReportQueue>& report_queue = + self->status_or_report_queue_->ValueOrDie(); + report_queue->Flush(priority, std::move(callback)); }, priority, std::move(callback), weak_ptr_factory_.GetWeakPtr())); } @@ -207,18 +210,23 @@ EnqueueCallback callback, RecordProducer record_producer) const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (!report_queue_) { - // Queue is not ready yet, store the record in the memory - // queue. + if (!status_or_report_queue_.has_value()) { + // Queue is not ready yet, store the record in the memory queue. pending_record_producers_.emplace(std::move(record_producer), priority); std::move(callback).Run(Status::StatusOK()); return; } - // Queue is ready. If memory queue is empty, just forward the - // record. + if (!status_or_report_queue_->ok()) { + // Queue creation failed. + std::move(callback).Run(status_or_report_queue_->status()); + return; + } + // Queue is ready. If memory queue is empty, just forward the record. if (pending_record_producers_.empty()) { - report_queue_->AddProducedRecord(std::move(record_producer), priority, - std::move(callback)); + const std::unique_ptr<ReportQueue>& report_queue = + status_or_report_queue_->ValueOrDie(); + report_queue->AddProducedRecord(std::move(record_producer), priority, + std::move(callback)); return; } // If memory queue is not empty, attach the new record at the @@ -230,21 +238,24 @@ void SpeculativeReportQueueImpl::EnqueuePendingRecordProducers( EnqueueCallback callback) const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(report_queue_); + DCHECK(status_or_report_queue_.has_value()); + DCHECK(status_or_report_queue_->ok()); if (pending_record_producers_.empty()) { std::move(callback).Run(Status::StatusOK()); return; } + const std::unique_ptr<ReportQueue>& report_queue = + status_or_report_queue_->ValueOrDie(); auto head = std::move(pending_record_producers_.front()); pending_record_producers_.pop(); if (pending_record_producers_.empty()) { // Last of the pending records. - report_queue_->AddProducedRecord(std::move(head.record_producer), - head.record_priority, std::move(callback)); + report_queue->AddProducedRecord(std::move(head.record_producer), + head.record_priority, std::move(callback)); return; } - report_queue_->AddProducedRecord( + report_queue->AddProducedRecord( std::move(head.record_producer), head.record_priority, base::BindPostTask( sequenced_task_runner_, @@ -278,34 +289,36 @@ if (!speculative_queue) { return; // Speculative queue was destructed in a meantime. } - if (!actual_queue_result.ok()) { - return; // Actual queue creation failed. - } // Set actual queue for the speculative queue to use // (asynchronously). speculative_queue->AttachActualQueue( - std::move(actual_queue_result.ValueOrDie())); + std::move(std::move(actual_queue_result))); }, weak_ptr_factory_.GetWeakPtr())); } void SpeculativeReportQueueImpl::AttachActualQueue( - std::unique_ptr<ReportQueue> actual_queue) { + StatusOr<std::unique_ptr<ReportQueue>> status_or_actual_queue) { sequenced_task_runner_->PostTask( FROM_HERE, base::BindOnce( [](base::WeakPtr<SpeculativeReportQueueImpl> self, - std::unique_ptr<ReportQueue> actual_queue) { + StatusOr<std::unique_ptr<ReportQueue>> status_or_actual_queue) { if (!self) { return; } DCHECK_CALLED_ON_VALID_SEQUENCE(self->sequence_checker_); - if (self->report_queue_) { + if (self->status_or_report_queue_.has_value()) { // Already attached, do nothing. return; } - self->report_queue_ = std::move(actual_queue); - if (!self->pending_record_producers_.empty()) { + self->status_or_report_queue_ = std::move(status_or_actual_queue); + // TODO(b/239583016): remove the ok status check once the enqueue + // callbacks are stored along with the records in a pending queue + // instead of only the records, and run the callbacks with the + // failure status if creation failed. + if (self->status_or_report_queue_->ok() && + !self->pending_record_producers_.empty()) { self->EnqueuePendingRecordProducers( base::BindOnce([](Status enqueue_status) { if (!enqueue_status.ok()) { @@ -315,7 +328,7 @@ })); } }, - weak_ptr_factory_.GetWeakPtr(), std::move(actual_queue))); + weak_ptr_factory_.GetWeakPtr(), std::move(status_or_actual_queue))); } } // namespace reporting
diff --git a/components/reporting/client/report_queue_impl.h b/components/reporting/client/report_queue_impl.h index 3cee147..47950e7 100644 --- a/components/reporting/client/report_queue_impl.h +++ b/components/reporting/client/report_queue_impl.h
@@ -11,12 +11,10 @@ #include <utility> #include "base/callback.h" -#include "base/memory/ref_counted.h" #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" #include "base/sequence_checker.h" #include "base/task/sequenced_task_runner.h" -#include "base/values.h" #include "components/reporting/client/report_queue.h" #include "components/reporting/client/report_queue_configuration.h" #include "components/reporting/proto/synced/record.pb.h" @@ -24,7 +22,7 @@ #include "components/reporting/storage/storage_module_interface.h" #include "components/reporting/util/status.h" #include "components/reporting/util/statusor.h" -#include "third_party/protobuf/src/google/protobuf/message_lite.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace reporting { @@ -92,7 +90,8 @@ // Substitutes actual queue to the speculative, when ready. // Initiates processesing of all pending records. - void AttachActualQueue(std::unique_ptr<ReportQueue> actual_queue); + void AttachActualQueue( + StatusOr<std::unique_ptr<ReportQueue>> status_or_actual_queue); private: // Moveable, non-copyable struct holding a pending record producer for the @@ -132,8 +131,9 @@ const scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner_; SEQUENCE_CHECKER(sequence_checker_); - // Actual |ReportQueue|, once created. - std::unique_ptr<ReportQueue> report_queue_ + // Creation status of |ReportQueue| and actual |ReportQueue| if successfully + // created. + absl::optional<StatusOr<std::unique_ptr<ReportQueue>>> status_or_report_queue_ GUARDED_BY_CONTEXT(sequence_checker_); // Queue of the pending record producers, collected before actual queue has
diff --git a/components/reporting/client/report_queue_impl_unittest.cc b/components/reporting/client/report_queue_impl_unittest.cc index d369f228..7bfa8b29 100644 --- a/components/reporting/client/report_queue_impl_unittest.cc +++ b/components/reporting/client/report_queue_impl_unittest.cc
@@ -257,6 +257,48 @@ EXPECT_EQ(test_storage_module()->record().data(), kTestString); } +TEST_F(ReportQueueImplTest, SpeculativeQueueMultipleRecordsAfterCreation) { + constexpr char kTestString1[] = "record1"; + constexpr char kTestString2[] = "record2"; + auto speculative_report_queue = SpeculativeReportQueueImpl::Create(); + + speculative_report_queue->AttachActualQueue(std::move(report_queue_)); + // Let everything ongoing to finish. + task_environment_.RunUntilIdle(); + + test::TestEvent<Status> test_event1; + speculative_report_queue->Enqueue(kTestString1, Priority::IMMEDIATE, + test_event1.cb()); + const auto result1 = test_event1.result(); + ASSERT_TRUE(result1.ok()); + EXPECT_EQ(test_storage_module()->priority(), Priority::IMMEDIATE); + EXPECT_EQ(test_storage_module()->record().data(), kTestString1); + + test::TestEvent<Status> test_event2; + speculative_report_queue->Enqueue(kTestString2, Priority::SLOW_BATCH, + test_event2.cb()); + const auto result2 = test_event2.result(); + ASSERT_TRUE(result2.ok()); + EXPECT_EQ(test_storage_module()->priority(), Priority::SLOW_BATCH); + EXPECT_EQ(test_storage_module()->record().data(), kTestString2); +} + +TEST_F(ReportQueueImplTest, SpeculativeQueueCreationFailed) { + constexpr char kTestString[] = "record"; + auto speculative_report_queue = SpeculativeReportQueueImpl::Create(); + + auto attach_cb = speculative_report_queue->PrepareToAttachActualQueue(); + std::move(attach_cb).Run(Status(error::UNKNOWN, "error msg")); + task_environment_.RunUntilIdle(); + + test::TestEvent<Status> test_event; + speculative_report_queue->Enqueue(kTestString, Priority::IMMEDIATE, + test_event.cb()); + const auto result = test_event.result(); + ASSERT_FALSE(result.ok()); + EXPECT_EQ(result.code(), error::UNKNOWN); +} + TEST_F(ReportQueueImplTest, OverlappingStringRecords) { constexpr char kTestString1[] = "record1"; constexpr char kTestString2[] = "record2"; @@ -358,6 +400,21 @@ EXPECT_EQ(result.error_code(), error::FAILED_PRECONDITION); } +TEST_F(ReportQueueImplTest, FlushFailedSpeculativeReportQueue) { + test::TestEvent<Status> event; + + auto speculative_report_queue = SpeculativeReportQueueImpl::Create(); + auto attach_cb = speculative_report_queue->PrepareToAttachActualQueue(); + std::move(attach_cb).Run(Status(error::UNKNOWN, "error msg")); + task_environment_.RunUntilIdle(); + + speculative_report_queue->Flush(priority_, event.cb()); + + const auto result = event.result(); + ASSERT_FALSE(result.ok()); + EXPECT_EQ(result.error_code(), error::UNKNOWN); +} + TEST_F(ReportQueueImplTest, AsyncProcessingReportQueue) { auto mock_queue = std::make_unique<MockReportQueue>(); EXPECT_CALL(*mock_queue, AddProducedRecord)
diff --git a/components/safe_browsing/content/browser/base_ui_manager.cc b/components/safe_browsing/content/browser/base_ui_manager.cc index bee0584..f19a46f 100644 --- a/components/safe_browsing/content/browser/base_ui_manager.cc +++ b/components/safe_browsing/content/browser/base_ui_manager.cc
@@ -21,6 +21,7 @@ #include "content/public/browser/navigation_entry.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_user_data.h" +#include "services/network/public/mojom/fetch_api.mojom-shared.h" using content::BrowserThread; using content::NavigationEntry; @@ -207,12 +208,19 @@ void BaseUIManager::DisplayBlockingPage(const UnsafeResource& resource) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - if (resource.is_subresource && !resource.is_subframe) { + bool is_frame = resource.is_subframe || + resource.request_destination == + network::mojom::RequestDestination::kEmbed || + resource.request_destination == + network::mojom::RequestDestination::kObject; + if (resource.is_subresource && !is_frame) { // Sites tagged as serving Unwanted Software should only show a warning for - // main-frame or sub-frame resource. Similar warning restrictions should be - // applied to malware sites tagged as "landing sites" (see "Types of - // Malware sites" under - // https://developers.google.com/safe-browsing/developers_guide_v3#UserWarnings). + // main-frame or frame-like (subframe, embed, object) resource. Similar + // warning restrictions should be applied to malware sites tagged as + // "landing sites" (see "Types of Malware sites" under + // https://developers.google.com/safe-browsing/v4/metadata#malware-sites). + // This is to avoid false positives on benign sites that load resources + // from landing sites. if (resource.threat_type == SB_THREAT_TYPE_URL_UNWANTED || (resource.threat_type == SB_THREAT_TYPE_URL_MALWARE && resource.threat_metadata.threat_pattern_type ==
diff --git a/components/safe_browsing/core/browser/db/BUILD.gn b/components/safe_browsing/core/browser/db/BUILD.gn index 9a8e6b8..b66f4347 100644 --- a/components/safe_browsing/core/browser/db/BUILD.gn +++ b/components/safe_browsing/core/browser/db/BUILD.gn
@@ -79,6 +79,7 @@ ] deps = [ ":database_manager", + ":util", ":v4_protocol_manager_util", "//base:base", "//net",
diff --git a/components/safe_browsing/core/browser/db/fake_database_manager.cc b/components/safe_browsing/core/browser/db/fake_database_manager.cc index 24fab78..f0ca9d9 100644 --- a/components/safe_browsing/core/browser/db/fake_database_manager.cc +++ b/components/safe_browsing/core/browser/db/fake_database_manager.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "components/safe_browsing/core/browser/db/fake_database_manager.h" +#include "components/safe_browsing/core/browser/db/util.h" namespace safe_browsing { @@ -20,6 +21,12 @@ dangerous_urls_[dangerous_url] = threat_type; } +void FakeSafeBrowsingDatabaseManager::AddDangerousUrlPattern( + const GURL& dangerous_url, + ThreatPatternType pattern_type) { + dangerous_patterns_[dangerous_url] = pattern_type; +} + void FakeSafeBrowsingDatabaseManager::ClearDangerousUrl( const GURL& dangerous_url) { dangerous_urls_.erase(dangerous_url); @@ -46,10 +53,16 @@ if (result_threat_type == SB_THREAT_TYPE_SAFE) return true; + ThreatPatternType pattern_type = ThreatPatternType::NONE; + const auto it1 = dangerous_patterns_.find(url); + if (it1 != dangerous_patterns_.end()) { + pattern_type = it1->second; + } + io_task_runner()->PostTask( FROM_HERE, base::BindOnce(&FakeSafeBrowsingDatabaseManager::CheckBrowseURLAsync, url, - result_threat_type, client)); + result_threat_type, pattern_type, client)); return false; } @@ -98,9 +111,11 @@ void FakeSafeBrowsingDatabaseManager::CheckBrowseURLAsync( GURL url, SBThreatType result_threat_type, + ThreatPatternType pattern_type, Client* client) { - client->OnCheckBrowseUrlResult(url, result_threat_type, - safe_browsing::ThreatMetadata()); + ThreatMetadata metadata; + metadata.threat_pattern_type = pattern_type; + client->OnCheckBrowseUrlResult(url, result_threat_type, metadata); } // static
diff --git a/components/safe_browsing/core/browser/db/fake_database_manager.h b/components/safe_browsing/core/browser/db/fake_database_manager.h index cca57095..83e2ddee 100644 --- a/components/safe_browsing/core/browser/db/fake_database_manager.h +++ b/components/safe_browsing/core/browser/db/fake_database_manager.h
@@ -7,6 +7,7 @@ #include "base/containers/flat_map.h" #include "components/safe_browsing/core/browser/db/test_database_manager.h" +#include "components/safe_browsing/core/browser/db/util.h" #include "url/gurl.h" namespace safe_browsing { @@ -20,6 +21,8 @@ scoped_refptr<base::SequencedTaskRunner> io_task_runner); void AddDangerousUrl(const GURL& dangerous_url, SBThreatType threat_type); + void AddDangerousUrlPattern(const GURL& dangerous_url, + ThreatPatternType pattern_type); void ClearDangerousUrl(const GURL& dangerous_url); // TestSafeBrowsingDatabaseManager implementation: @@ -42,12 +45,14 @@ static void CheckBrowseURLAsync(GURL url, SBThreatType result_threat_type, + ThreatPatternType pattern_type, Client* client); static void CheckDownloadURLAsync(const std::vector<GURL>& url_chain, SBThreatType result_threat_type, Client* client); base::flat_map<GURL, SBThreatType> dangerous_urls_; + base::flat_map<GURL, ThreatPatternType> dangerous_patterns_; }; } // namespace safe_browsing
diff --git a/components/user_education/common/tutorial_description.h b/components/user_education/common/tutorial_description.h index bbecc1aa..3dbc494 100644 --- a/components/user_education/common/tutorial_description.h +++ b/components/user_education/common/tutorial_description.h
@@ -40,6 +40,10 @@ // Records whether, when an IPH offered the tutorial, the user opted into // seeing the tutorial or not. virtual void RecordIphLinkClicked(bool value) = 0; + + // Records whether, when an IPH offered the tutorial, the user opted into + // seeing the tutorial or not. + virtual void RecordStartedFromWhatsNewPage(bool value) = 0; }; namespace internal { @@ -55,8 +59,10 @@ ".Completion"), aborted_name_(kTutorialHistogramPrefix + histogram_name_ + ".AbortStep"), - link_clicked_name_(kTutorialHistogramPrefix + histogram_name_ + - ".IPHLinkClicked"), + iph_link_clicked_name_(kTutorialHistogramPrefix + histogram_name_ + + ".IPHLinkClicked"), + whats_new_page_name_(kTutorialHistogramPrefix + histogram_name_ + + ".StartedFromWhatsNewPage"), max_steps_(max_steps) {} ~TutorialHistogramsImpl() override = default; @@ -70,14 +76,19 @@ } void RecordIphLinkClicked(bool value) override { - UMA_HISTOGRAM_BOOLEAN(link_clicked_name_, value); + UMA_HISTOGRAM_BOOLEAN(iph_link_clicked_name_, value); + } + + void RecordStartedFromWhatsNewPage(bool value) override { + UMA_HISTOGRAM_BOOLEAN(whats_new_page_name_, value); } private: const std::string histogram_name_; const std::string completed_name_; const std::string aborted_name_; - const std::string link_clicked_name_; + const std::string iph_link_clicked_name_; + const std::string whats_new_page_name_; const int max_steps_; };
diff --git a/components/user_education/common/tutorial_service.cc b/components/user_education/common/tutorial_service.cc index 50a839e..7ed0b6b 100644 --- a/components/user_education/common/tutorial_service.cc +++ b/components/user_education/common/tutorial_service.cc
@@ -77,6 +77,16 @@ description->histograms->RecordIphLinkClicked(iph_link_was_clicked); } +void TutorialService::LogStartedFromWhatsNewPage(TutorialIdentifier id, + bool success) { + TutorialDescription* description = + tutorial_registry_->GetTutorialDescription(id); + CHECK(description); + + if (description->histograms) + description->histograms->RecordStartedFromWhatsNewPage(success); +} + bool TutorialService::RestartTutorial() { DCHECK(running_tutorial_ && running_tutorial_creation_params_); base::AutoReset<bool> resetter(&is_restarting_, true);
diff --git a/components/user_education/common/tutorial_service.h b/components/user_education/common/tutorial_service.h index 5e8d84c..86e8097 100644 --- a/components/user_education/common/tutorial_service.h +++ b/components/user_education/common/tutorial_service.h
@@ -55,6 +55,8 @@ AbortedCallback aborted_callback = base::DoNothing()); void LogIPHLinkClicked(TutorialIdentifier id, bool iph_link_was_clicked); + virtual void LogStartedFromWhatsNewPage(TutorialIdentifier id, + bool iph_link_was_clicked); // Uses the stored tutorial creation params to restart a tutorial. Replaces // the current_tutorial with a newly generated tutorial.
diff --git a/components/user_education/webui/help_bubble_handler.cc b/components/user_education/webui/help_bubble_handler.cc index 2dd59490..2ff377a 100644 --- a/components/user_education/webui/help_bubble_handler.cc +++ b/components/user_education/webui/help_bubble_handler.cc
@@ -126,6 +126,11 @@ mojom_params->close_button_alt_text = base::UTF16ToUTF8(data.params->close_button_alt_text); mojom_params->position = HelpBubbleArrowToPosition(data.params->arrow); + if (data.params->progress) { + mojom_params->progress = help_bubble::mojom::Progress::New(); + mojom_params->progress->current = data.params->progress->first; + mojom_params->progress->total = data.params->progress->second; + } if (!data.params->title_text.empty()) { mojom_params->title_text = base::UTF16ToUTF8(data.params->title_text); }
diff --git a/components/user_education/webui/help_bubble_handler_unittest.cc b/components/user_education/webui/help_bubble_handler_unittest.cc index 3d9c9a4d..f55c2db 100644 --- a/components/user_education/webui/help_bubble_handler_unittest.cc +++ b/components/user_education/webui/help_bubble_handler_unittest.cc
@@ -92,6 +92,11 @@ EXPECT_EQ(expected->native_identifier, arg->native_identifier); EXPECT_EQ(expected->position, arg->position); EXPECT_EQ(expected->title_text, arg->title_text); + EXPECT_EQ(!!expected->progress, !!arg->progress); + if (expected->progress && arg->progress) { + EXPECT_EQ(expected->progress->current, arg->progress->current); + EXPECT_EQ(expected->progress->total, arg->progress->total); + } EXPECT_EQ(expected->buttons.size(), arg->buttons.size()); if (expected->buttons.size() == arg->buttons.size()) { @@ -239,6 +244,59 @@ EXPECT_FALSE(help_bubble->is_open()); } +TEST_F(HelpBubbleHandlerTest, ShowHelpBubbleWithButtonsAndProgress) { + handler()->HelpBubbleAnchorVisibilityChanged( + kHelpBubbleHandlerTestElementIdentifier.GetName(), true); + auto* const element = + ui::ElementTracker::GetElementTracker()->GetUniqueElement( + kHelpBubbleHandlerTestElementIdentifier, test_handler_->context()); + ASSERT_NE(nullptr, element); + HelpBubbleParams params; + params.body_text = u"Help bubble body."; + params.close_button_alt_text = u"Close button alt text."; + params.arrow = HelpBubbleArrow::kTopCenter; + params.progress = std::make_pair(1, 3); + + HelpBubbleButtonParams button; + button.is_default = true; + button.text = u"button1"; + params.buttons.emplace_back(std::move(button)); + + // Check the parameters passed to the ShowHelpBubble mojo method. + help_bubble::mojom::HelpBubbleParamsPtr expected = + help_bubble::mojom::HelpBubbleParams::New(); + expected->native_identifier = element->identifier().GetName(); + expected->body_text = base::UTF16ToUTF8(params.body_text); + expected->close_button_alt_text = + base::UTF16ToUTF8(params.close_button_alt_text); + expected->position = help_bubble::mojom::HelpBubblePosition::BELOW; + + auto expected_button = help_bubble::mojom::HelpBubbleButtonParams::New(); + expected_button->text = "button1"; + expected_button->is_default = true; + expected->buttons.emplace_back(std::move(expected_button)); + + auto expected_progress = help_bubble::mojom::Progress::New(); + expected_progress->current = 1; + expected_progress->total = 3; + expected->progress = std::move(expected_progress); + + EXPECT_CALL(test_handler_->mock(), + ShowHelpBubble(MatchesHelpBubbleParams(expected.get()))); + auto help_bubble = help_bubble_factory_registry_.CreateHelpBubble( + element, std::move(params)); + + EXPECT_TRUE(help_bubble); + EXPECT_TRUE(help_bubble->is_open()); + + EXPECT_CALL( + test_handler_->mock(), + HideHelpBubble(kHelpBubbleHandlerTestElementIdentifier.GetName())); + EXPECT_TRUE(help_bubble->Close()); + + EXPECT_FALSE(help_bubble->is_open()); +} + TEST_F(HelpBubbleHandlerTest, FocusHelpBubble) { handler()->HelpBubbleAnchorVisibilityChanged( kHelpBubbleHandlerTestElementIdentifier.GetName(), true);
diff --git a/components/webapps/browser/android/shortcut_info.cc b/components/webapps/browser/android/shortcut_info.cc index 5dbb3fd..7acb828d 100644 --- a/components/webapps/browser/android/shortcut_info.cc +++ b/components/webapps/browser/android/shortcut_info.cc
@@ -149,7 +149,7 @@ // Set the screenshots urls based on the screenshots in the manifest, if any. screenshot_urls.clear(); for (const auto& screenshot : manifest.screenshots) - screenshot_urls.push_back(screenshot.src); + screenshot_urls.push_back(screenshot->image.src); if (manifest.share_target) { share_target = ShareTarget();
diff --git a/components/webapps/browser/features.cc b/components/webapps/browser/features.cc index 4216d25..dd89664 100644 --- a/components/webapps/browser/features.cc +++ b/components/webapps/browser/features.cc
@@ -53,6 +53,10 @@ const base::Feature kSkipServiceWorkerCheckInstallOnly{ "SkipServiceWorkerCheckInstallOnly", base::FEATURE_DISABLED_BY_DEFAULT}; +// Enables showing a detailed install dialog for user installs. +const base::Feature kDesktopPWAsDetailedInstallDialog{ + "DesktopPWAsDetailedInstallDialog", base::FEATURE_DISABLED_BY_DEFAULT}; + bool SkipBannerServiceWorkerCheck() { return base::FeatureList::IsEnabled(kSkipServiceWorkerCheckAll); }
diff --git a/components/webapps/browser/features.h b/components/webapps/browser/features.h index 0304beb..04edc6a 100644 --- a/components/webapps/browser/features.h +++ b/components/webapps/browser/features.h
@@ -27,6 +27,7 @@ extern const base::Feature kCreateShortcutIgnoresManifest; extern const base::Feature kSkipServiceWorkerCheckAll; extern const base::Feature kSkipServiceWorkerCheckInstallOnly; +extern const base::Feature kDesktopPWAsDetailedInstallDialog; bool SkipBannerServiceWorkerCheck(); bool SkipInstallServiceWorkerCheck();
diff --git a/components/webapps/browser/installable/installable_manager.cc b/components/webapps/browser/installable/installable_manager.cc index 50db3ef..8af8c3d6 100644 --- a/components/webapps/browser/installable/installable_manager.cc +++ b/components/webapps/browser/installable/installable_manager.cc
@@ -16,6 +16,7 @@ #include "base/threading/sequenced_task_runner_handle.h" #include "build/build_config.h" #include "components/security_state/core/security_state.h" +#include "components/webapps/browser/features.h" #include "components/webapps/browser/installable/installable_metrics.h" #include "components/webapps/browser/webapps_client.h" #include "components/webapps/common/constants.h" @@ -36,6 +37,7 @@ #include "third_party/blink/public/common/manifest/manifest_util.h" #include "third_party/blink/public/common/storage_key/storage_key.h" #include "third_party/blink/public/mojom/manifest/display_mode.mojom.h" +#include "third_party/skia/include/core/SkBitmap.h" #include "url/origin.h" #if BUILDFLAG(IS_ANDROID) @@ -186,7 +188,7 @@ (display_mode == blink::mojom::DisplayMode::kBorderless && base::FeatureList::IsEnabled(blink::features::kWebAppBorderless)) || (display_mode == blink::mojom::DisplayMode::kTabbed && - base::FeatureList::IsEnabled(features::kDesktopPWAsTabStrip))); + base::FeatureList::IsEnabled(::features::kDesktopPWAsTabStrip))); } void OnDidCompleteGetAllErrors( @@ -602,7 +604,12 @@ IconUsage::kPrimary); } else if (params.fetch_screenshots && !screenshots_downloading_ && !is_screenshots_fetch_complete_) { - CheckAndFetchScreenshots(); + if (base::FeatureList::IsEnabled( + webapps::features::kDesktopPWAsDetailedInstallDialog)) { + CheckAndFetchScreenshots(); + } else { + CheckAndFetchScreenshots(/*check_platform=*/false); + } } else if (params.has_worker && !worker_->fetched) { CheckServiceWorker(); } else if (params.valid_splash_icon && params.prefer_maskable_icon && @@ -887,7 +894,7 @@ WorkOnTask(); } -void InstallableManager::CheckAndFetchScreenshots() { +void InstallableManager::CheckAndFetchScreenshots(bool check_platform) { DCHECK(!blink::IsEmptyManifest(manifest())); DCHECK(!is_screenshots_fetch_complete_); @@ -896,32 +903,50 @@ int num_of_screenshots = 0; for (const auto& url : manifest().screenshots) { - if (++num_of_screenshots > kMaximumNumOfScreenshots) - break; - // A screenshot URL that's in the map is already taken care of. - if (downloaded_screenshots_.count(url.src) > 0) +#if BUILDFLAG(IS_ANDROID) + auto reject_platform = blink::mojom::ManifestScreenshot::Platform::kWide; +#else + auto reject_platform = blink::mojom::ManifestScreenshot::Platform::kNarrow; +#endif // BUILDFLAG(IS_ANDROID) + if (check_platform && url->platform == reject_platform) continue; - int ideal_size_in_px = url.sizes.empty() ? kMinimumScreenshotSizeInPx - : std::max(url.sizes[0].width(), - url.sizes[0].height()); + if (++num_of_screenshots > kMaximumNumOfScreenshots) + break; + + // A screenshot URL that's in the map is already taken care of. + if (downloaded_screenshots_.count(url->image.src) > 0) + continue; + + int ideal_size_in_px = url->image.sizes.empty() + ? kMinimumScreenshotSizeInPx + : std::max(url->image.sizes[0].width(), + url->image.sizes[0].height()); // Do not pass in a maximum icon size so that screenshots larger than // kMaximumScreenshotSizeInPx are not downscaled to the maximum size by // `ManifestIconDownloader::Download`. Screenshots with size larger than // kMaximumScreenshotSizeInPx get filtered out by OnScreenshotFetched. bool can_download = content::ManifestIconDownloader::Download( - GetWebContents(), url.src, ideal_size_in_px, kMinimumScreenshotSizeInPx, + GetWebContents(), url->image.src, ideal_size_in_px, + kMinimumScreenshotSizeInPx, /*maximum_icon_size_in_px=*/0, base::BindOnce(&InstallableManager::OnScreenshotFetched, - weak_factory_.GetWeakPtr(), url.src), + weak_factory_.GetWeakPtr(), url->image.src), /*square_only=*/false); if (can_download) ++screenshots_downloading_; } if (!screenshots_downloading_) { - is_screenshots_fetch_complete_ = true; - WorkOnTask(); + // If there is no screenshot that matches all the criteria, populate again + // without checking platform to fallback to screenshots with mismatching + // platform instead of showing nothing. + if (screenshots_.size() == 0 && check_platform) { + CheckAndFetchScreenshots(/*check_platform=*/false); + } else { + is_screenshots_fetch_complete_ = true; + WorkOnTask(); + } } } @@ -943,7 +968,7 @@ if (++num_of_screenshots > kMaximumNumOfScreenshots) break; - auto iter = downloaded_screenshots_.find(url.src); + auto iter = downloaded_screenshots_.find(url->image.src); if (iter == downloaded_screenshots_.end()) continue; @@ -953,7 +978,6 @@ continue; } - // TODO(crbug.com/1146450): Filter out screenshots by platform. // Screenshots must have the same aspect ratio. Cross-multiplying // dimensions checks portrait vs landscape mode (1:2 vs 2:1 for instance). if (screenshots_.size() && @@ -971,6 +995,7 @@ screenshots_.push_back(screenshot); } + downloaded_screenshots_.clear(); is_screenshots_fetch_complete_ = true;
diff --git a/components/webapps/browser/installable/installable_manager.h b/components/webapps/browser/installable/installable_manager.h index 8788b853..12f21edc 100644 --- a/components/webapps/browser/installable/installable_manager.h +++ b/components/webapps/browser/installable/installable_manager.h
@@ -241,8 +241,10 @@ IconUsage usage); void OnIconFetched(GURL icon_url, IconUsage usage, const SkBitmap& bitmap); - void CheckAndFetchScreenshots(); + void CheckAndFetchScreenshots(bool check_platform = true); + void OnScreenshotFetched(GURL screenshot_url, const SkBitmap& bitmap); + void PopulateScreenshots(bool check_platform); // content::ServiceWorkerContextObserver overrides void OnRegistrationCompleted(const GURL& pattern) override;
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index b0e3eb97..917b7f696 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -845,6 +845,8 @@ "devtools/shared_worker_devtools_agent_host.h", "devtools/shared_worker_devtools_manager.cc", "devtools/shared_worker_devtools_manager.h", + "devtools/web_contents_devtools_agent_host.cc", + "devtools/web_contents_devtools_agent_host.h", "devtools/worker_devtools_agent_host.cc", "devtools/worker_devtools_agent_host.h", "devtools/worker_devtools_manager.cc",
diff --git a/content/browser/back_forward_cache_internal_browsertest.cc b/content/browser/back_forward_cache_internal_browsertest.cc index 83429ec..e02c20a 100644 --- a/content/browser/back_forward_cache_internal_browsertest.cc +++ b/content/browser/back_forward_cache_internal_browsertest.cc
@@ -3555,8 +3555,14 @@ // Verify that the page will be evicted upon accessibility events if the // flag to evict on ax events is off, and evicted otherwise. +#if BUILDFLAG(IS_WIN) +#define MAYBE_EvictOnAccessibilityEventsOrNot \ + DISABLED_EvictOnAccessibilityEventsOrNot +#else +#define MAYBE_EvictOnAccessibilityEventsOrNot EvictOnAccessibilityEventsOrNot +#endif IN_PROC_BROWSER_TEST_P(BackForwardCacheBrowserTestWithFlagForAXEvents, - EvictOnAccessibilityEventsOrNot) { + MAYBE_EvictOnAccessibilityEventsOrNot) { ASSERT_TRUE(embedded_test_server()->Start()); GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html")); GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
diff --git a/content/browser/devtools/devtools_agent_host_impl.cc b/content/browser/devtools/devtools_agent_host_impl.cc index e6c47fdd..55c8eb91 100644 --- a/content/browser/devtools/devtools_agent_host_impl.cc +++ b/content/browser/devtools/devtools_agent_host_impl.cc
@@ -25,6 +25,7 @@ #include "content/browser/devtools/service_worker_devtools_manager.h" #include "content/browser/devtools/shared_worker_devtools_agent_host.h" #include "content/browser/devtools/shared_worker_devtools_manager.h" +#include "content/browser/devtools/web_contents_devtools_agent_host.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/content_browser_client.h" #include "content/public/browser/devtools_external_agent_proxy_delegate.h" @@ -61,6 +62,7 @@ } // namespace +const char DevToolsAgentHost::kTypeTab[] = "tab"; const char DevToolsAgentHost::kTypePage[] = "page"; const char DevToolsAgentHost::kTypeFrame[] = "iframe"; const char DevToolsAgentHost::kTypeDedicatedWorker[] = "worker"; @@ -101,6 +103,7 @@ // TODO(dgozman): we should add dedicated workers here, but clients are not // ready. RenderFrameDevToolsAgentHost::AddAllAgentHosts(&result); + WebContentsDevToolsAgentHost::AddAllAgentHosts(&result); AuctionWorkletDevToolsAgentHostManager::GetInstance().GetAll(&result);
diff --git a/content/browser/devtools/devtools_http_handler.cc b/content/browser/devtools/devtools_http_handler.cc index b75e19e7..f096136 100644 --- a/content/browser/devtools/devtools_http_handler.cc +++ b/content/browser/devtools/devtools_http_handler.cc
@@ -714,8 +714,12 @@ DevToolsAgentHost::List agent_hosts = std::move(hosts); std::sort(agent_hosts.begin(), agent_hosts.end(), TimeComparator); base::ListValue list_value; - for (auto& agent_host : agent_hosts) - list_value.Append(SerializeDescriptor(agent_host, host)); + for (auto& agent_host : agent_hosts) { + // TODO(caseq): figure out if it makes sense exposing tab target to + // HTTP clients and potentially compatibility risks involved. + if (agent_host->GetType() != DevToolsAgentHost::kTypeTab) + list_value.Append(SerializeDescriptor(agent_host, host)); + } SendJson(connection_id, net::HTTP_OK, &list_value, std::string()); }
diff --git a/content/browser/devtools/protocol/target_handler.cc b/content/browser/devtools/protocol/target_handler.cc index 9899aff..06507a1 100644 --- a/content/browser/devtools/protocol/target_handler.cc +++ b/content/browser/devtools/protocol/target_handler.cc
@@ -614,6 +614,11 @@ .SetExclude(true) .SetType(DevToolsAgentHost::kTypeBrowser) .Build()); + // - Exclude `tab`. + default_filter.push_back(protocol::Target::FilterEntry::Create() + .SetExclude(true) + .SetType(DevToolsAgentHost::kTypeTab) + .Build()); // - Allow everything else. default_filter.push_back(protocol::Target::FilterEntry::Create().Build()); return base::WrapUnique(new TargetFilter(std::move(default_filter)));
diff --git a/content/browser/devtools/site_per_process_devtools_browsertest.cc b/content/browser/devtools/site_per_process_devtools_browsertest.cc index d502798e..540abd8e 100644 --- a/content/browser/devtools/site_per_process_devtools_browsertest.cc +++ b/content/browser/devtools/site_per_process_devtools_browsertest.cc
@@ -60,6 +60,18 @@ bool waiting_for_reply_; }; +DevToolsAgentHost::List ExtractPageOrFrameTargets( + DevToolsAgentHost::List list) { + DevToolsAgentHost::List result; + for (auto& entry : list) { + if (entry->GetType() == DevToolsAgentHost::kTypePage || + entry->GetType() == DevToolsAgentHost::kTypeFrame) { + result.push_back(std::move(entry)); + } + } + return result; +} + // Fails on Android, http://crbug.com/464993. #if BUILDFLAG(IS_ANDROID) #define MAYBE_CrossSiteIframeAgentHost DISABLED_CrossSiteIframeAgentHost @@ -77,7 +89,7 @@ ->GetPrimaryFrameTree() .root(); - list = DevToolsAgentHost::GetOrCreateAll(); + list = ExtractPageOrFrameTargets(DevToolsAgentHost::GetOrCreateAll()); EXPECT_EQ(1U, list.size()); EXPECT_EQ(DevToolsAgentHost::kTypePage, list[0]->GetType()); EXPECT_EQ(main_url.spec(), list[0]->GetURL().spec()); @@ -87,7 +99,7 @@ GURL http_url(embedded_test_server()->GetURL("/title1.html")); EXPECT_TRUE(NavigateToURLFromRenderer(child, http_url)); - list = DevToolsAgentHost::GetOrCreateAll(); + list = ExtractPageOrFrameTargets(DevToolsAgentHost::GetOrCreateAll()); EXPECT_EQ(1U, list.size()); EXPECT_EQ(DevToolsAgentHost::kTypePage, list[0]->GetType()); EXPECT_EQ(main_url.spec(), list[0]->GetURL().spec()); @@ -99,7 +111,7 @@ cross_site_url = cross_site_url.ReplaceComponents(replace_host); EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), cross_site_url)); - list = DevToolsAgentHost::GetOrCreateAll(); + list = ExtractPageOrFrameTargets(DevToolsAgentHost::GetOrCreateAll()); EXPECT_EQ(2U, list.size()); EXPECT_EQ(DevToolsAgentHost::kTypePage, list[0]->GetType()); EXPECT_EQ(main_url.spec(), list[0]->GetURL().spec()); @@ -128,7 +140,7 @@ // Load back same-site page into iframe. EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), http_url)); - list = DevToolsAgentHost::GetOrCreateAll(); + list = ExtractPageOrFrameTargets(DevToolsAgentHost::GetOrCreateAll()); EXPECT_EQ(1U, list.size()); EXPECT_EQ(DevToolsAgentHost::kTypePage, list[0]->GetType()); EXPECT_EQ(main_url.spec(), list[0]->GetURL().spec());
diff --git a/content/browser/devtools/web_contents_devtools_agent_host.cc b/content/browser/devtools/web_contents_devtools_agent_host.cc new file mode 100644 index 0000000..9f1270f4 --- /dev/null +++ b/content/browser/devtools/web_contents_devtools_agent_host.cc
@@ -0,0 +1,247 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/devtools/web_contents_devtools_agent_host.h" + +#include "base/unguessable_token.h" +#include "content/browser/devtools/protocol/target_auto_attacher.h" +#include "content/browser/devtools/protocol/target_handler.h" +#include "content/browser/devtools/render_frame_devtools_agent_host.h" +#include "content/browser/web_contents/web_contents_impl.h" + +namespace content { + +namespace { +using WebContentsDevToolsMap = + std::map<WebContents*, WebContentsDevToolsAgentHost*>; +base::LazyInstance<WebContentsDevToolsMap>::Leaky g_agent_host_instances = + LAZY_INSTANCE_INITIALIZER; + +WebContentsDevToolsAgentHost* FindAgentHost(WebContents* wc) { + if (!g_agent_host_instances.IsCreated()) + return nullptr; + auto it = g_agent_host_instances.Get().find(wc); + return it == g_agent_host_instances.Get().end() ? nullptr : it->second; +} + +bool ShouldCreateDevToolsAgentHost(WebContents* wc) { + return wc == wc->GetResponsibleWebContents(); +} +} // namespace + +class WebContentsDevToolsAgentHost::AutoAttacher + : public protocol::TargetAutoAttacher { + public: + explicit AutoAttacher(WebContents* web_contents) + : web_contents_(web_contents) {} + + private: + void UpdateAutoAttach(base::OnceClosure callback) override { + if (auto_attach()) + UpdateAssociatedFrames(); + protocol::TargetAutoAttacher::UpdateAutoAttach(std::move(callback)); + } + + void UpdateAssociatedFrames() { + // TODO: This needs to cover: + // - portals + // - pre-renders + // - BF-cache + DevToolsAgentHost::List hosts; + FrameTreeNode* primary_root = static_cast<WebContentsImpl*>(web_contents_) + ->GetPrimaryFrameTree() + .root(); + hosts.push_back(RenderFrameDevToolsAgentHost::GetOrCreateFor(primary_root)); + DispatchSetAttachedTargetsOfType(hosts, DevToolsAgentHost::kTypePage); + } + + WebContents* const web_contents_; +}; + +// static +WebContentsDevToolsAgentHost* WebContentsDevToolsAgentHost::GetFor( + WebContents* web_contents) { + return FindAgentHost(web_contents->GetResponsibleWebContents()); +} + +// static +WebContentsDevToolsAgentHost* WebContentsDevToolsAgentHost::GetOrCreateFor( + WebContents* web_contents) { + web_contents = web_contents->GetResponsibleWebContents(); + if (auto* host = FindAgentHost(web_contents)) + return host; + return new WebContentsDevToolsAgentHost(web_contents); +} + +// static +void WebContentsDevToolsAgentHost::AddAllAgentHosts( + DevToolsAgentHost::List* result) { + for (WebContentsImpl* wc : WebContentsImpl::GetAllWebContents()) { + if (ShouldCreateDevToolsAgentHost(wc)) + result->push_back(GetOrCreateFor(wc)); + } +} + +WebContentsDevToolsAgentHost::WebContentsDevToolsAgentHost(WebContents* wc) + : DevToolsAgentHostImpl(base::UnguessableToken::Create().ToString()), + WebContentsObserver(wc), + auto_attacher_(std::make_unique<AutoAttacher>(wc)) { + DCHECK(web_contents()); + bool inserted = + g_agent_host_instances.Get().insert(std::make_pair(wc, this)).second; + DCHECK(inserted); + // Once created, persist till underlying WC is destroyed, so that + // the target id is retained. + AddRef(); + NotifyCreated(); +} + +WebContentsDevToolsAgentHost::~WebContentsDevToolsAgentHost() { + DCHECK(!web_contents()); +} + +void WebContentsDevToolsAgentHost::DisconnectWebContents() { + NOTREACHED(); +} + +void WebContentsDevToolsAgentHost::ConnectWebContents( + WebContents* web_contents) { + NOTREACHED(); +} + +BrowserContext* WebContentsDevToolsAgentHost::GetBrowserContext() { + return web_contents()->GetBrowserContext(); +} + +WebContents* WebContentsDevToolsAgentHost::GetWebContents() { + return web_contents(); +} + +std::string WebContentsDevToolsAgentHost::GetParentId() { + return std::string(); +} + +std::string WebContentsDevToolsAgentHost::GetOpenerId() { + if (DevToolsAgentHost* host = GetPrimaryFrameAgent()) + return host->GetOpenerId(); + return ""; +}; + +std::string WebContentsDevToolsAgentHost::GetOpenerFrameId() { + if (DevToolsAgentHost* host = GetPrimaryFrameAgent()) + return host->GetOpenerFrameId(); + return ""; +} + +bool WebContentsDevToolsAgentHost::CanAccessOpener() { + if (DevToolsAgentHost* host = GetPrimaryFrameAgent()) + return host->CanAccessOpener(); + return false; +} + +std::string WebContentsDevToolsAgentHost::GetType() { + return kTypeTab; +} + +std::string WebContentsDevToolsAgentHost::GetTitle() { + if (DevToolsAgentHost* host = GetPrimaryFrameAgent()) + return host->GetTitle(); + return ""; +} + +std::string WebContentsDevToolsAgentHost::GetDescription() { + if (DevToolsAgentHost* host = GetPrimaryFrameAgent()) + return host->GetDescription(); + return ""; +} + +GURL WebContentsDevToolsAgentHost::GetURL() { + if (DevToolsAgentHost* host = GetPrimaryFrameAgent()) + return host->GetURL(); + return GURL(); +} + +GURL WebContentsDevToolsAgentHost::GetFaviconURL() { + if (DevToolsAgentHost* host = GetPrimaryFrameAgent()) + return host->GetFaviconURL(); + return GURL(); +} + +bool WebContentsDevToolsAgentHost::Activate() { + if (DevToolsAgentHost* host = GetPrimaryFrameAgent()) + return host->Activate(); + return false; +} + +void WebContentsDevToolsAgentHost::Reload() { + if (DevToolsAgentHost* host = GetPrimaryFrameAgent()) + host->Reload(); +} + +bool WebContentsDevToolsAgentHost::Close() { + if (DevToolsAgentHost* host = GetPrimaryFrameAgent()) + return host->Close(); + return false; +} + +base::TimeTicks WebContentsDevToolsAgentHost::GetLastActivityTime() { + if (DevToolsAgentHost* host = GetPrimaryFrameAgent()) + return host->GetLastActivityTime(); + return base::TimeTicks(); +} + +absl::optional<network::CrossOriginEmbedderPolicy> +WebContentsDevToolsAgentHost::cross_origin_embedder_policy( + const std::string& id) { + NOTREACHED(); + return absl::nullopt; +} + +absl::optional<network::CrossOriginOpenerPolicy> +WebContentsDevToolsAgentHost::cross_origin_opener_policy( + const std::string& id) { + NOTREACHED(); + return absl::nullopt; +} + +DevToolsAgentHostImpl* WebContentsDevToolsAgentHost::GetPrimaryFrameAgent() { + if (WebContents* wc = web_contents()) { + return RenderFrameDevToolsAgentHost::GetFor( + static_cast<RenderFrameHostImpl*>(wc->GetPrimaryMainFrame())); + } + return nullptr; +} + +void WebContentsDevToolsAgentHost::WebContentsDestroyed() { + DCHECK_EQ(this, FindAgentHost(web_contents())); + ForceDetachAllSessions(); + auto_attacher_.reset(); + g_agent_host_instances.Get().erase(web_contents()); + Observe(nullptr); + // We may or may not be destruced here, depending on embedders + // potentially retaining references. + Release(); +} + +// DevToolsAgentHostImpl overrides. +bool WebContentsDevToolsAgentHost::AttachSession(DevToolsSession* session, + bool acquire_wake_lock) { + // TODO(caseq): figure out if this can be a CHECK(). + if (!web_contents()) + return false; + const bool may_attach_to_brower = session->GetClient()->IsTrusted(); + session->CreateAndAddHandler<protocol::TargetHandler>( + may_attach_to_brower + ? protocol::TargetHandler::AccessMode::kRegular + : protocol::TargetHandler::AccessMode::kAutoAttachOnly, + GetId(), auto_attacher_.get(), session->GetRootSession()); + return true; +} + +protocol::TargetAutoAttacher* WebContentsDevToolsAgentHost::auto_attacher() { + DCHECK(!!auto_attacher_ == !!web_contents()); + return auto_attacher_.get(); +} + +} // namespace content
diff --git a/content/browser/devtools/web_contents_devtools_agent_host.h b/content/browser/devtools/web_contents_devtools_agent_host.h new file mode 100644 index 0000000..278ac79 --- /dev/null +++ b/content/browser/devtools/web_contents_devtools_agent_host.h
@@ -0,0 +1,77 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_DEVTOOLS_WEB_CONTENTS_DEVTOOLS_AGENT_HOST_H_ +#define CONTENT_BROWSER_DEVTOOLS_WEB_CONTENTS_DEVTOOLS_AGENT_HOST_H_ + +#include "content/browser/devtools/devtools_agent_host_impl.h" +#include "content/common/content_export.h" +#include "content/public/browser/render_process_host_observer.h" +#include "content/public/browser/web_contents_observer.h" +#include "third_party/abseil-cpp/absl/types/optional.h" + +namespace content { + +class CONTENT_EXPORT WebContentsDevToolsAgentHost + : public DevToolsAgentHostImpl, + public WebContentsObserver { + public: + // Returns appropriate agent host for given Web Contents + static WebContentsDevToolsAgentHost* GetFor(WebContents* web_contents); + // Similar to GetFor(), but creates a host if it doesn't exist yet. + static WebContentsDevToolsAgentHost* GetOrCreateFor( + WebContents* web_contents); + + WebContentsDevToolsAgentHost(const WebContentsDevToolsAgentHost&) = delete; + WebContentsDevToolsAgentHost& operator=(const WebContentsDevToolsAgentHost&) = + delete; + + static void AddAllAgentHosts(DevToolsAgentHost::List* result); + + private: + class AutoAttacher; + + explicit WebContentsDevToolsAgentHost(WebContents* wc); + ~WebContentsDevToolsAgentHost() override; + + // DevToolsAgentHost overrides. + void DisconnectWebContents() override; + void ConnectWebContents(WebContents* web_contents) override; + BrowserContext* GetBrowserContext() override; + WebContents* GetWebContents() override; + std::string GetParentId() override; + std::string GetOpenerId() override; + std::string GetOpenerFrameId() override; + bool CanAccessOpener() override; + std::string GetType() override; + std::string GetTitle() override; + std::string GetDescription() override; + GURL GetURL() override; + GURL GetFaviconURL() override; + bool Activate() override; + void Reload() override; + + bool Close() override; + base::TimeTicks GetLastActivityTime() override; + + absl::optional<network::CrossOriginEmbedderPolicy> + cross_origin_embedder_policy(const std::string& id) override; + absl::optional<network::CrossOriginOpenerPolicy> cross_origin_opener_policy( + const std::string& id) override; + + // DevToolsAgentHostImpl overrides. + bool AttachSession(DevToolsSession* session, bool acquire_wake_lock) override; + protocol::TargetAutoAttacher* auto_attacher() override; + + // WebContentsObserver overrides. + void WebContentsDestroyed() override; + + DevToolsAgentHostImpl* GetPrimaryFrameAgent(); + + std::unique_ptr<AutoAttacher> auto_attacher_; +}; + +} // namespace content + +#endif // CONTENT_BROWSER_DEVTOOLS_WEB_CONTENTS_DEVTOOLS_AGENT_HOST_H_
diff --git a/content/public/browser/devtools_agent_host.h b/content/public/browser/devtools_agent_host.h index daf9aa2f..96c4d77 100644 --- a/content/public/browser/devtools_agent_host.h +++ b/content/public/browser/devtools_agent_host.h
@@ -45,6 +45,7 @@ class CONTENT_EXPORT DevToolsAgentHost : public base::RefCounted<DevToolsAgentHost> { public: + static const char kTypeTab[]; static const char kTypePage[]; static const char kTypeFrame[]; static const char kTypeDedicatedWorker[];
diff --git a/infra/config/generated/luci/commit-queue.cfg b/infra/config/generated/luci/commit-queue.cfg index c62ec07..3a4f88623 100644 --- a/infra/config/generated/luci/commit-queue.cfg +++ b/infra/config/generated/luci/commit-queue.cfg
@@ -276,6 +276,10 @@ includable_only: true } builders { + name: "chromium/codesearch/gen-webview-try" + includable_only: true + } + builders { name: "chromium/codesearch/gen-win-try" includable_only: true }
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg index 197ccff..c422cd6 100644 --- a/infra/config/generated/luci/cr-buildbucket.cfg +++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -44455,6 +44455,83 @@ } } builders { + name: "gen-webview-try" + swarming_host: "chromium-swarm.appspot.com" + dimensions: "builderless:1" + dimensions: "cores:8" + dimensions: "cpu:x86-64" + dimensions: "os:Ubuntu-18.04" + dimensions: "pool:luci.chromium.try" + dimensions: "ssd:0" + exe { + cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" + cipd_version: "refs/heads/main" + cmd: "luciexe" + } + properties: + '{' + ' "$build/goma": {' + ' "enable_ats": true,' + ' "rpc_extra_params": "?prod",' + ' "server_host": "goma.chromium.org",' + ' "use_luci_auth": true' + ' },' + ' "$recipe_engine/resultdb/test_presentation": {' + ' "column_keys": [],' + ' "grouping_keys": [' + ' "status",' + ' "v.test_suite"' + ' ]' + ' },' + ' "builder_group": "tryserver.chromium.codesearch",' + ' "recipe": "chromium_codesearch"' + '}' + execution_timeout_secs: 32400 + expiration_secs: 7200 + caches { + name: "win_toolchain" + path: "win_toolchain" + } + build_numbers: YES + service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com" + experiments { + key: "luci.recipes.use_python3" + value: 100 + } + resultdb { + enable: true + bq_exports { + project: "chrome-luci-data" + dataset: "chromium" + table: "try_test_results" + test_results {} + } + bq_exports { + project: "chrome-luci-data" + dataset: "chromium" + table: "gpu_try_test_results" + test_results { + predicate { + test_id_regexp: "ninja://chrome/test:telemetry_gpu_integration_test[^/]*/.+" + } + } + } + bq_exports { + project: "chrome-luci-data" + dataset: "chromium" + table: "blink_web_tests_try_test_results" + test_results { + predicate { + test_id_regexp: "ninja://[^/]*blink_web_tests/.+" + } + } + } + history_options { + use_invocation_timestamp: true + } + } + } + builders { name: "gen-win-try" swarming_host: "chromium-swarm.appspot.com" dimensions: "builderless:1" @@ -52431,7 +52508,7 @@ } experiments { key: "enable_weetbix_queries" - value: 50 + value: 100 } experiments { key: "luci.recipes.use_python3"
diff --git a/infra/config/generated/luci/luci-milo.cfg b/infra/config/generated/luci/luci-milo.cfg index 0929794d..863a919 100644 --- a/infra/config/generated/luci/luci-milo.cfg +++ b/infra/config/generated/luci/luci-milo.cfg
@@ -17482,6 +17482,9 @@ name: "buildbucket/luci.chromium.codesearch/gen-mac-try" } builders { + name: "buildbucket/luci.chromium.codesearch/gen-webview-try" + } + builders { name: "buildbucket/luci.chromium.codesearch/gen-win-try" } builder_view_only: true
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.android.star b/infra/config/subprojects/chromium/try/tryserver.chromium.android.star index 434851d..aeaa0e6 100644 --- a/infra/config/subprojects/chromium/try/tryserver.chromium.android.star +++ b/infra/config/subprojects/chromium/try/tryserver.chromium.android.star
@@ -286,7 +286,7 @@ coverage_test_types = ["unit", "overall"], tryjob = try_.job(), experiments = { - "enable_weetbix_queries": 50, + "enable_weetbix_queries": 100, }, )
diff --git a/infra/config/subprojects/codesearch/codesearch.star b/infra/config/subprojects/codesearch/codesearch.star index a051259..567d85c 100644 --- a/infra/config/subprojects/codesearch/codesearch.star +++ b/infra/config/subprojects/codesearch/codesearch.star
@@ -76,6 +76,10 @@ ) try_.builder( + name = "gen-webview-try", +) + +try_.builder( name = "gen-win-try", os = os.WINDOWS_10, )
diff --git a/infra/orchestrator/BUILD.gn b/infra/orchestrator/BUILD.gn index de3dada..b007180f 100644 --- a/infra/orchestrator/BUILD.gn +++ b/infra/orchestrator/BUILD.gn
@@ -18,6 +18,10 @@ ":standard_isolated_script_merge_py", ] + if (is_android) { + data_deps += [ "//build/android:test_result_presentations_py" ] + } + data = [ # Various merge/collect scripts will likely need a venv specified in # the root vpython spec files. @@ -35,10 +39,7 @@ if (use_jacoco_coverage) { data += [ "//third_party/jacoco/lib/jacococli.jar" ] - data_deps += [ - "//build/android:test_result_presentations_py", - "//third_party/jdk:java_data", - ] + data_deps += [ "//third_party/jdk:java_data" ] } write_runtime_deps = "$root_out_dir/orchestrator_all.runtime_deps" }
diff --git a/ios/chrome/app/BUILD.gn b/ios/chrome/app/BUILD.gn index 3bd1481..052ebaa 100644 --- a/ios/chrome/app/BUILD.gn +++ b/ios/chrome/app/BUILD.gn
@@ -279,7 +279,10 @@ "//ios/chrome/browser/discover_feed:discover_feed_factory", "//ios/chrome/browser/ntp:features", ] - frameworks = [ "BackgroundTasks.framework" ] + frameworks = [ + "BackgroundTasks.framework", + "UserNotifications.framework", + ] } source_set("app_internal") {
diff --git a/ios/chrome/app/feed_app_agent.mm b/ios/chrome/app/feed_app_agent.mm index 5b26efc..b223b10 100644 --- a/ios/chrome/app/feed_app_agent.mm +++ b/ios/chrome/app/feed_app_agent.mm
@@ -5,6 +5,7 @@ #import "ios/chrome/app/feed_app_agent.h" #import <BackgroundTasks/BackgroundTasks.h> +#import <UserNotifications/UserNotifications.h> #import "ios/chrome/app/application_delegate/app_state.h" #import "ios/chrome/browser/discover_feed/discover_feed_service.h" @@ -22,26 +23,26 @@ - (void)appState:(AppState*)appState didTransitionFromInitStage:(InitStage)previousInitStage { - if (IsFeedBackgroundRefreshEnabled()) { - if (appState.initStage == InitStageBrowserBasic) { - // Apple docs say that background tasks must be registered before the - // end of `application:didFinishLaunchingWithOptions:`. - // InitStageBrowserBasic fulfills that requirement. - [self registerBackgroundRefreshTask]; - } else if (appState.initStage == - InitStageBrowserObjectsForBackgroundHandlers) { - // Save the value of the feature flag now since 'base::FeatureList' was - // not available in `InitStageBrowserBasic`. - // IsFeedBackgroundRefreshEnabled() simply reads the saved value saved by - // SaveFeedBackgroundRefreshEnabledForNextColdStart(). Do not wrap this in - // IsFeedBackgroundRefreshEnabled() -- in this case, a new value would - // never be saved again once we save NO, since the NO codepath would not - // execute saving a new value. - SaveFeedBackgroundRefreshEnabledForNextColdStart(); - } - } - - if (appState.initStage == InitStageNormalUI && IsWebChannelsEnabled()) { + if (appState.initStage == InitStageBrowserBasic) { + // Apple docs say that background tasks must be registered before the + // end of `application:didFinishLaunchingWithOptions:`. + // InitStageBrowserBasic fulfills that requirement. + [self maybeRegisterBackgroundRefreshTask]; + // This is a provisional permission, which does not prompt the user at this + // point. + [self maybeRequestUserNotificationPermissions]; + } else if (appState.initStage == + InitStageBrowserObjectsForBackgroundHandlers) { + // Save the value of the feature flag now since 'base::FeatureList' was + // not available in `InitStageBrowserBasic`. + // IsFeedBackgroundRefreshEnabled() simply reads the saved value saved by + // SaveFeedBackgroundRefreshEnabledForNextColdStart(). Do not wrap this in + // IsFeedBackgroundRefreshEnabled() -- in this case, a new value would + // never be saved again once we save NO, since the NO codepath would not + // execute saving a new value. + SaveFeedBackgroundRefreshEnabledForNextColdStart(); + } else if (appState.initStage == InitStageNormalUI && + IsWebChannelsEnabled()) { // Starting the DiscoverFeedService is required before users are able to // interact with any tab because following a web channel (part of the // Following Feed feature which depends on the DiscoverFeedService) is @@ -86,7 +87,7 @@ // Registers handler for the background refresh task. According to // documentation, this must complete before the end of // `applicationDidFinishLaunching`. -- (void)registerBackgroundRefreshTask { +- (void)maybeRegisterBackgroundRefreshTask { if (!IsFeedBackgroundRefreshEnabled()) { return; } @@ -115,15 +116,30 @@ } BGAppRefreshTaskRequest* request = [[BGAppRefreshTaskRequest alloc] initWithIdentifier:kFeedBackgroundRefreshTaskIdentifier]; - // This is expected to crash if FeedService is not available. - request.earliestBeginDate = - [self feedService]->GetEarliestBackgroundRefreshBeginDate(); + request.earliestBeginDate = [self earliestBackgroundRefreshBeginDate]; // Error in scheduling is intentionally not handled since the fallback is that // the user will just refresh in the foreground. // TODO(crbug.com/1343695): Consider logging error in histogram. [BGTaskScheduler.sharedScheduler submitTaskRequest:request error:nil]; } +// Returns the earliest begin date to set on the refresh task. Either returns a +// date from DiscoverFeedService or an override date created with the override +// interval in Experimental Settings. +- (NSDate*)earliestBackgroundRefreshBeginDate { + NSDate* earliestBeginDate = nil; + NSTimeInterval intervalOverride = + GetBackgroundRefreshIntervalOverrideInSeconds(); + if (intervalOverride > 0) { + earliestBeginDate = [NSDate dateWithTimeIntervalSinceNow:intervalOverride]; + } else { + // This is expected to crash if FeedService is not available. + earliestBeginDate = + [self feedService]->GetEarliestBackgroundRefreshBeginDate(); + } + return earliestBeginDate; +} + // This method is called when the app is in the background. - (void)handleBackgroundRefreshTask:(BGTask*)task { // Do not DCHECK IsFeedBackgroundRefreshEnabled() because the value could have @@ -137,11 +153,83 @@ task.expirationHandler = ^{ // This is expected to crash if FeedService is not available. [self feedService]->HandleBackgroundRefreshTaskExpiration(); + [self maybeNotifyRefreshSuccess:NO]; }; - // This is expected to crash if FeedService is not available. - [self feedService]->PerformBackgroundRefreshes(^(BOOL success) { - [task setTaskCompletedWithSuccess:success]; - }); + if (IsAttemptFeedBackgroundRefreshEnabled()) { + // This is expected to crash if FeedService is not available. + [self feedService]->PerformBackgroundRefreshes(^(BOOL success) { + [self maybeNotifyRefreshSuccess:success]; + [task setTaskCompletedWithSuccess:success]; + }); + } else { + [self maybeNotifyFetchTriggered]; + [task setTaskCompletedWithSuccess:YES]; + } +} + +#pragma mark - Non-release only - Refresh Completion Notifications + +// Request provisional permission, which does not explicitly prompt the user for +// permission. Instead, the OS delivers provisional notifications quietly and +// are visible in the notification center's history. For active debugging, the +// tester can go to the Settings App and turn on full permissions for banners +// and sounds. +- (void)maybeRequestUserNotificationPermissions { + if (!IsFeedBackgroundRefreshCompletedNotificationEnabled()) { + return; + } + UNUserNotificationCenter* center = + UNUserNotificationCenter.currentNotificationCenter; + [center requestAuthorizationWithOptions:(UNAuthorizationOptionProvisional | + UNAuthorizationOptionAlert | + UNAuthorizationOptionSound) + completionHandler:^(BOOL granted, NSError* error){ + }]; +} + +// Requests OS to send a local user notification with `title`. +- (void)maybeRequestNotification:(NSString*)title { + if (!IsFeedBackgroundRefreshCompletedNotificationEnabled()) { + return; + } + UNMutableNotificationContent* content = + [[UNMutableNotificationContent alloc] init]; + content.title = title; + content.body = @"This is compiled only into non-release versions."; + UNTimeIntervalNotificationTrigger* trigger = + [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:(1) + repeats:NO]; + UNNotificationRequest* request = + [UNNotificationRequest requestWithIdentifier:[[NSUUID UUID] UUIDString] + content:content + trigger:trigger]; + UNUserNotificationCenter* center = + UNUserNotificationCenter.currentNotificationCenter; + [center addNotificationRequest:request withCompletionHandler:nil]; +} + +// Requests OS to send a local user notification when a background fetch is +// triggered, but an actual feed refresh is not attempted. +- (void)maybeNotifyFetchTriggered { + // Disable triggering notification if actual refresh attempt is enabled so + // that user doesn't get unnecessary notifications. + if (IsAttemptFeedBackgroundRefreshEnabled()) { + return; + } + [self maybeRequestNotification:@"Background Fetch Triggered"]; +} + +// Requests OS to send a local user notification that a feed refresh has been +// attempted in the background. The notification title says 'success' or +// 'failure' based on `success`. +- (void)maybeNotifyRefreshSuccess:(BOOL)success { + NSString* title = nil; + if (success) { + title = @"Feed Bg Refresh Success"; + } else { + title = @"Feed Bg Refresh Failure"; + } + [self maybeRequestNotification:title]; } @end
diff --git a/ios/chrome/browser/infobars/overlays/permissions_overlay_tab_helper_unittest.mm b/ios/chrome/browser/infobars/overlays/permissions_overlay_tab_helper_unittest.mm index 83c6f19..9ddfd64 100644 --- a/ios/chrome/browser/infobars/overlays/permissions_overlay_tab_helper_unittest.mm +++ b/ios/chrome/browser/infobars/overlays/permissions_overlay_tab_helper_unittest.mm
@@ -4,7 +4,6 @@ #import "ios/chrome/browser/infobars/overlays/permissions_overlay_tab_helper.h" -#include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" #include "base/threading/platform_thread.h" #include "base/time/time.h" @@ -41,7 +40,6 @@ ~PermissionsOverlayTabHelperTest() override { InfoBarManagerImpl::FromWebState(&web_state_)->ShutDown(); - // Observer should be removed before |scoped_feature_list_| is reset. web_state_.RemoveObserver( PermissionsOverlayTabHelper::FromWebState(&web_state_)); } @@ -70,7 +68,6 @@ } base::test::TaskEnvironment task_environment_; - base::test::ScopedFeatureList scoped_feature_list_; web::FakeWebState web_state_; };
diff --git a/ios/chrome/browser/ntp/features.h b/ios/chrome/browser/ntp/features.h index 97a77ff..c9b36f0 100644 --- a/ios/chrome/browser/ntp/features.h +++ b/ios/chrome/browser/ntp/features.h
@@ -48,10 +48,20 @@ // buildflag is not defined. bool IsFeedBackgroundRefreshEnabled(); +// Whether feed background refresh is attempted, if background refresh is +// enabled. Disabling this value allows for testing the background fetch +// capability independent of the feed background refresh codepaths. +bool IsAttemptFeedBackgroundRefreshEnabled(); + // Saves the current value for feature `kEnableFeedBackgroundRefresh`. This call // DCHECKs on the availability of `base::FeatureList`. void SaveFeedBackgroundRefreshEnabledForNextColdStart(); +// Returns true if the user should receive a local notification when a feed +// background refresh is completed. Background refresh completion notifications +// are only compiled into non-release versions. +bool IsFeedBackgroundRefreshCompletedNotificationEnabled(); + // Whether the Following feed should also be refreshed in the background. bool IsFollowingFeedBackgroundRefreshEnabled(); @@ -62,9 +72,14 @@ // background refresh. bool IsRecurringBackgroundRefreshScheduleEnabled(); -// The earliest interval to refresh if server value is not used. +// The earliest interval to refresh if server value is not used. This value is +// an input into the DiscoverFeedService. double GetBackgroundRefreshIntervalInSeconds(); +// If greater than zero, this value should be used to completely override the +// earliest begin date provided by the DiscoverFeedService. +double GetBackgroundRefreshIntervalOverrideInSeconds(); + // Returns the background refresh max age in seconds. double GetBackgroundRefreshMaxAgeInSeconds();
diff --git a/ios/chrome/browser/ntp/features.mm b/ios/chrome/browser/ntp/features.mm index 893b85f..a983d58 100644 --- a/ios/chrome/browser/ntp/features.mm +++ b/ios/chrome/browser/ntp/features.mm
@@ -35,7 +35,8 @@ const char kEnableFollowingFeedBackgroundRefresh[] = "EnableFollowingFeedBackgroundRefresh"; - +const char kEnableAttemptFeedBackgroundRefresh[] = + "EnableAttemptFeedBackgroundRefresh"; const char kEnableServerDrivenBackgroundRefreshSchedule[] = "EnableServerDrivenBackgroundRefreshSchedule"; const char kEnableRecurringBackgroundRefreshSchedule[] = @@ -60,6 +61,15 @@ #endif // BUILDFLAG(IOS_BACKGROUND_MODE_ENABLED) } +bool IsAttemptFeedBackgroundRefreshEnabled() { + if (!IsFeedBackgroundRefreshEnabled()) { + return false; + } + return base::GetFieldTrialParamByFeatureAsBool( + kEnableFeedBackgroundRefresh, kEnableAttemptFeedBackgroundRefresh, + /*default=*/false); +} + void SaveFeedBackgroundRefreshEnabledForNextColdStart() { DCHECK(base::FeatureList::GetInstance()); [[NSUserDefaults standardUserDefaults] @@ -67,6 +77,11 @@ forKey:kEnableFeedBackgroundRefreshForNextColdStart]; } +bool IsFeedBackgroundRefreshCompletedNotificationEnabled() { + return IsFeedBackgroundRefreshEnabled() && + experimental_flags::IsRefreshCompletedNotificationEnabled(); +} + bool IsFollowingFeedBackgroundRefreshEnabled() { if (experimental_flags::IsForceBackgroundRefreshForFollowingFeedEnabled()) { return true; @@ -94,6 +109,10 @@ /*default=*/60 * 60); } +double GetBackgroundRefreshIntervalOverrideInSeconds() { + return experimental_flags::GetBackgroundRefreshIntervalOverrideInSeconds(); +} + double GetBackgroundRefreshMaxAgeInSeconds() { if (experimental_flags::GetBackgroundRefreshMaxAgeInSeconds() > 0) { return experimental_flags::GetBackgroundRefreshMaxAgeInSeconds();
diff --git a/ios/chrome/browser/resources/Settings.bundle/Experimental.plist b/ios/chrome/browser/resources/Settings.bundle/Experimental.plist index 652a1ab..eb303b1 100644 --- a/ios/chrome/browser/resources/Settings.bundle/Experimental.plist +++ b/ios/chrome/browser/resources/Settings.bundle/Experimental.plist
@@ -74,6 +74,16 @@ <key>Type</key> <string>PSToggleSwitchSpecifier</string> <key>Title</key> + <string>Refresh Completed Notification Enabled</string> + <key>Key</key> + <string>RefreshCompletedNotificationEnabled</string> + <key>DefaultValue</key> + <false/> + </dict> + <dict> + <key>Type</key> + <string>PSToggleSwitchSpecifier</string> + <key>Title</key> <string>Force Background Refresh for Following Feed</string> <key>Key</key> <string>ForceBackgroundRefreshForFollowingFeedEnabled</string> @@ -84,6 +94,18 @@ <key>Type</key> <string>PSTextFieldSpecifier</string> <key>Title</key> + <string>Refresh Interval Override In Seconds</string> + <key>Key</key> + <string>BackgroundRefreshIntervalOverrideInSeconds</string> + <key>DefaultValue</key> + <string></string> + <key>KeyboardType</key> + <string>NumberPad</string> + </dict> + <dict> + <key>Type</key> + <string>PSTextFieldSpecifier</string> + <key>Title</key> <string>Feed Max Age In Seconds</string> <key>Key</key> <string>BackgroundRefreshMaxAgeInSeconds</string>
diff --git a/ios/chrome/browser/system_flags.h b/ios/chrome/browser/system_flags.h index fb16fb98..e7bfbf9 100644 --- a/ios/chrome/browser/system_flags.h +++ b/ios/chrome/browser/system_flags.h
@@ -64,10 +64,19 @@ // TODO(crbug.com/1340154): Remove after launch. bool ShouldAlwaysShowFollowIPH(); +// Returns true if the user should receive a local notification when a +// background refresh is completed. +bool IsRefreshCompletedNotificationEnabled(); + // Returns true if background refresh should also be used for the Following // feed. If false, the default value or finch feature flag value should be used. bool IsForceBackgroundRefreshForFollowingFeedEnabled(); +// Returns an interval that can be used to set the background refresh earliest +// begin date. Any value greater than zero should be used to override the +// earliest begin date provided by the DiscoverFeedService. +double GetBackgroundRefreshIntervalOverrideInSeconds(); + // The maximum age a response can be before it is refreshed in the background. // This check is done when the background task is executed. The default value of // 0 means the age check is ignored.
diff --git a/ios/chrome/browser/system_flags.mm b/ios/chrome/browser/system_flags.mm index 2bc2ff5..507fe494 100644 --- a/ios/chrome/browser/system_flags.mm +++ b/ios/chrome/browser/system_flags.mm
@@ -37,8 +37,12 @@ const base::Feature kEnableThirdPartyKeyboardWorkaround{ "EnableThirdPartyKeyboardWorkaround", base::FEATURE_ENABLED_BY_DEFAULT}; +NSString* const kRefreshCompletedNotificationEnabled = + @"RefreshCompletedNotificationEnabled"; NSString* const kForceBackgroundRefreshForFollowingFeedEnabled = @"ForceBackgroundRefreshForFollowingFeedEnabled"; +NSString* const kBackgroundRefreshIntervalOverrideInSeconds = + @"BackgroundRefreshIntervalOverrideInSeconds"; NSString* const kBackgroundRefreshMaxAgeInSeconds = @"BackgroundRefreshMaxAgeInSeconds"; @@ -97,11 +101,21 @@ [[NSUserDefaults standardUserDefaults] boolForKey:@"AlwaysShowFollowIPH"]; } +bool IsRefreshCompletedNotificationEnabled() { + return [[NSUserDefaults standardUserDefaults] + boolForKey:kRefreshCompletedNotificationEnabled]; +} + bool IsForceBackgroundRefreshForFollowingFeedEnabled() { return [[NSUserDefaults standardUserDefaults] boolForKey:kForceBackgroundRefreshForFollowingFeedEnabled]; } +double GetBackgroundRefreshIntervalOverrideInSeconds() { + return [[NSUserDefaults standardUserDefaults] + doubleForKey:kBackgroundRefreshIntervalOverrideInSeconds]; +} + double GetBackgroundRefreshMaxAgeInSeconds() { return [[NSUserDefaults standardUserDefaults] doubleForKey:kBackgroundRefreshMaxAgeInSeconds];
diff --git a/ios/chrome/browser/ui/page_info/page_info_permissions_mediator_unittest.mm b/ios/chrome/browser/ui/page_info/page_info_permissions_mediator_unittest.mm index d00c6a9d..a7fd81240 100644 --- a/ios/chrome/browser/ui/page_info/page_info_permissions_mediator_unittest.mm +++ b/ios/chrome/browser/ui/page_info/page_info_permissions_mediator_unittest.mm
@@ -4,7 +4,6 @@ #import "ios/chrome/browser/ui/page_info/page_info_permissions_mediator.h" -#include "base/test/scoped_feature_list.h" #import "ios/chrome/browser/ui/permissions/permission_info.h" #import "ios/web/public/permissions/permissions.h" #import "ios/web/public/test/fakes/fake_web_state.h" @@ -50,7 +49,6 @@ web::WebState* web_state() { return fake_web_state_.get(); } private: - base::test::ScopedFeatureList feature_list_; std::unique_ptr<web::FakeWebState> fake_web_state_; PageInfoPermissionsMediator* mediator_ API_AVAILABLE(ios(15.0)); };
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 index d83721c..e43c3af 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -7c4d5c6e9f1182f9ad9734019de71b014d87f3e6 \ No newline at end of file +3a2733efb290c5e61feab6553cc8b3d99c6f88a9 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 index ffbca6ed..bb094e5 100644 --- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -78e5b229ec9ee45fe9872db9209d7e57d3cd041f \ No newline at end of file +24a733a5131e008997b1fd843b7c8252f4b27034 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 index 9e8130c2..3cb04b6 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -075a43a3d70fd1898d3195bc370ed52872fe9ee5 \ No newline at end of file +d781d3ba036a437dcf69ed5ed36a2584b225ff4e \ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 index 5ca08da..e5e12056 100644 --- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -b03b01724e36e134fe7ec37c85d47b36fb5814c6 \ No newline at end of file +09856a0ba2de799aa988c44fc92e6c4f7eea6779 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 index 79a9e9ce..829f117 100644 --- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -6b6a82c1810376b3ce8891b68ea7ae7a50b1a978 \ No newline at end of file +5a34a1b729ae1a2418009c76f568926f45edfc6a \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 index 2b9a7ae..2562cf8 100644 --- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -cfd0f19b181d39cfe0b45c6dc898da7e2d342602 \ No newline at end of file +4014c0ced2e51ec21ea4bd3e5f80d8aebabd7278 \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 index 4902416..1415951a 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -0fdff4b920cbf6c4bb7ed2c1bfe14099bac6b4e4 \ No newline at end of file +a231280d77561372f93503182f3468eb63dd861b \ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 index d892d31..abe8b0f 100644 --- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -aa062a1a45d3e43d11838423b843a834583c942e \ No newline at end of file +616eb7482a752fda61a47e26342d9d2f5a76b47c \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 index df668ada..0fefa9e 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@ -02099026bfbc43b621b22506c3ce5b2f5d7b6377 \ No newline at end of file +d5ee80f988e539019e812e7ae31c095d79a1b6db \ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 index 38256c33..6f209aa4 100644 --- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 +++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@ -289fedfab2f388899eae6fbeeddaa8daf70bf41e \ No newline at end of file +4e59880b1d969ec7d89bae72265d6639c1763d96 \ No newline at end of file
diff --git a/ios/web/find_in_page/resources/find_in_page.ts b/ios/web/find_in_page/resources/find_in_page.ts index 28d0d41..8e3f86a 100644 --- a/ios/web/find_in_page/resources/find_in_page.ts +++ b/ios/web/find_in_page/resources/find_in_page.ts
@@ -3,6 +3,179 @@ // found in the LICENSE file. /** + * Class name of CSS element that selects a highlighted match with orange. + * @type {string} + */ +const CSS_CLASS_NAME_SELECT = 'find_selected'; + +/** + * Returns the width of the document.body. Sometimes though the body lies to + * try to make the page not break rails, so attempt to find those as well. + * An example: wikipedia pages for the ipad. + * @return {number} Width of the document body. + */ +function getBodyWidth_(): number { + let body = document.body; + let documentElement = document.documentElement; + return Math.max( + body.scrollWidth, documentElement.scrollWidth, body.offsetWidth, + documentElement.offsetWidth, body.clientWidth, + documentElement.clientWidth); +}; + +/** + * Returns the height of the document.body. Sometimes though the body lies to + * try to make the page not break rails, so attempt to find those as well. + * An example: wikipedia pages for the ipad. + * @return {number} Height of the document body. + */ +function getBodyHeight_(): number { + let body = document.body; + let documentElement = document.documentElement; + return Math.max( + body.scrollHeight, documentElement.scrollHeight, body.offsetHeight, + documentElement.offsetHeight, body.clientHeight, + documentElement.clientHeight); +}; + +/** + * Helper function that determines if an element is visible. + * @param {Element} elem Element to check. + * @return {boolean} Whether elem is visible or not. + */ +function isElementVisible_(elem: HTMLElement): boolean { + if (!elem) { + return false; + } + let top = 0; + let left = 0; + let bottom = Infinity; + let right = Infinity; + + let originalElement = elem; + let nextOffsetParent = originalElement.offsetParent; + + // We are currently handling all scrolling through the app, which means we can + // only scroll the window, not any scrollable containers in the DOM itself. So + // for now this function returns false if the element is scrolled outside the + // viewable area of its ancestors. + // TODO(crbug.com/915357): handle scrolling within the DOM. + let bodyHeight = getBodyHeight_(); + let bodyWidth = getBodyWidth_(); + + while (elem && elem.nodeName.toUpperCase() !== 'BODY') { + if (elem.style.display === 'none' || elem.style.visibility === 'hidden') { + return false; + } + + // Check that there is a value set before converting to a Number, otherwise + // and empty string will convert to opacity zero and a visible item will be + // assumed hidden. + if (elem.style.opacity.length) { + const opacity = Number(elem.style.opacity); + if (!isNaN(opacity) && opacity === 0) { + return false; + } + } + + if (elem.ownerDocument && elem.ownerDocument.defaultView) { + const computedStyle = + elem.ownerDocument.defaultView.getComputedStyle(elem, null); + if (computedStyle.display === 'none' || + computedStyle.visibility === 'hidden') { + return false; + } + + // Check that there is a value set before converting to a Number, + // otherwise and empty string will convert to opacity zero and a visible + // item will be assumed hidden. + if (computedStyle.opacity.length) { + const opacity = Number(computedStyle.opacity); + if (!isNaN(opacity) && opacity === 0) { + return false; + } + } + } + + // For the original element and all ancestor offsetParents, trim down the + // visible area of the original element. + if (elem.isSameNode(originalElement) || elem.isSameNode(nextOffsetParent)) { + let visible = elem.getBoundingClientRect(); + if (elem.style.overflow === 'hidden' && + (visible.width === 0 || visible.height === 0)) + return false; + + top = Math.max(top, visible.top + window.pageYOffset); + bottom = Math.min(bottom, visible.bottom + window.pageYOffset); + left = Math.max(left, visible.left + window.pageXOffset); + right = Math.min(right, visible.right + window.pageXOffset); + + // The element is not within the original viewport. + let notWithinViewport = top < 0 || left < 0; + + // The element is flowing off the boundary of the page. Note this is + // not comparing to the size of the window, but the calculated offset + // size of the document body. This can happen if the element is within + // a scrollable container in the page. + let offPage = right > bodyWidth || bottom > bodyHeight; + if (notWithinViewport || offPage) { + return false; + } + nextOffsetParent = elem.offsetParent; + } + + if (!(elem.parentNode instanceof HTMLElement)) { + break; + } + + elem = elem.parentNode; + } + return true; +}; + + +/** + * A Match represents a match result in the document. |this.nodes| stores all + * the <chrome_find> Nodes created for highlighting the matched text. If it + * contains only one Node, it means the match is found within one HTML TEXT + * Node, otherwise the match involves multiple HTML TEXT Nodes. + */ +class Match { + nodes: HTMLElement[] = []; + + /** + * Returns if all <chrome_find> Nodes of this match are visible. + * @return {Boolean} If the Match is visible. + */ + visible(): boolean { + for (const node of this.nodes) { + if (!isElementVisible_(node)) + return false; + } + return true; + } + + /** + * Adds orange color highlight for "selected match result", over the yellow + * color highlight for "normal match result". + */ + addSelectHighlight(): void { + for (const node of this.nodes) { + node.classList.add(CSS_CLASS_NAME_SELECT); + } + } + + /** + * Clears the orange color highlight. + */ + removeSelectHighlight(): void { + for (const node of this.nodes) { + node.classList.remove(CSS_CLASS_NAME_SELECT); + } + } +} + +/** * A Section contains the info of one TEXT node in the |allText_|. The node's * textContent is [begin, end) of |allText_|. */ @@ -23,4 +196,4 @@ } } -export {Section} +export {CSS_CLASS_NAME_SELECT, Match, Section}
diff --git a/ios/web/find_in_page/resources/find_in_page_native_api.js b/ios/web/find_in_page/resources/find_in_page_native_api.js index dfb5c753..881e913 100644 --- a/ios/web/find_in_page/resources/find_in_page_native_api.js +++ b/ios/web/find_in_page/resources/find_in_page_native_api.js
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import {Section} from '//ios/web/find_in_page/resources/find_in_page.js'; +import {CSS_CLASS_NAME_SELECT, Match, Section} from '//ios/web/find_in_page/resources/find_in_page.js'; /** * Based on code from the Google iOS app. @@ -63,51 +63,6 @@ } /** - * A Match represents a match result in the document. |this.nodes| stores all - * the <chrome_find> Nodes created for highlighting the matched text. If it - * contains only one Node, it means the match is found within one HTML TEXT - * Node, otherwise the match involves multiple HTML TEXT Nodes. - */ -class Match { - constructor() { - this.nodes = []; - } - - /** - * Returns if all <chrome_find> Nodes of this match are visible. - * @return {Boolean} If the Match is visible. - */ - visible() { - for (let i = 0; i < this.nodes.length; ++i) { - if (!isElementVisible_(this.nodes[i])) - return false; - } - return true; - } - - /** - * Adds orange color highlight for "selected match result", over the yellow - * color highlight for "normal match result". - * @return {undefined} - */ - addSelectHighlight() { - for (let i = 0; i < this.nodes.length; ++i) { - this.nodes[i].classList.add(CSS_CLASS_NAME_SELECT); - } - } - - /** - * Clears the orange color highlight. - * @return {undefined} - */ - removeSelectHighlight() { - for (let i = 0; i < this.nodes.length; ++i) { - this.nodes[i].classList.remove(CSS_CLASS_NAME_SELECT); - } - } -} - -/** * The list of all the matches in current page. * @type {Array<Match>} */ @@ -326,12 +281,6 @@ const CSS_CLASS_NAME = 'find_in_page'; /** - * Class name of CSS element that selects a highlighted match with orange. - * @type {string} - */ -const CSS_CLASS_NAME_SELECT = 'find_selected'; - -/** * ID of CSS style. * @type {string} */ @@ -770,103 +719,6 @@ }; /** - * Returns the width of the document.body. Sometimes though the body lies to - * try to make the page not break rails, so attempt to find those as well. - * An example: wikipedia pages for the ipad. - * @return {number} Width of the document body. - */ -function getBodyWidth_() { - let body = document.body; - let documentElement = document.documentElement; - return Math.max( - body.scrollWidth, documentElement.scrollWidth, body.offsetWidth, - documentElement.offsetWidth, body.clientWidth, - documentElement.clientWidth); -}; - -/** - * Returns the height of the document.body. Sometimes though the body lies to - * try to make the page not break rails, so attempt to find those as well. - * An example: wikipedia pages for the ipad. - * @return {number} Height of the document body. - */ -function getBodyHeight_() { - let body = document.body; - let documentElement = document.documentElement; - return Math.max( - body.scrollHeight, documentElement.scrollHeight, body.offsetHeight, - documentElement.offsetHeight, body.clientHeight, - documentElement.clientHeight); -}; - -/** - * Helper function that determines if an element is visible. - * @param {Element} elem Element to check. - * @return {boolean} Whether elem is visible or not. - */ -function isElementVisible_(elem) { - if (!elem) { - return false; - } - let top = 0; - let left = 0; - let bottom = Infinity; - let right = Infinity; - - let originalElement = elem; - let nextOffsetParent = originalElement.offsetParent; - - // We are currently handling all scrolling through the app, which means we can - // only scroll the window, not any scrollable containers in the DOM itself. So - // for now this function returns false if the element is scrolled outside the - // viewable area of its ancestors. - // TODO(crbug.com/915357): handle scrolling within the DOM. - let bodyHeight = getBodyHeight_(); - let bodyWidth = getBodyWidth_(); - - while (elem && elem.nodeName.toUpperCase() != 'BODY') { - let computedStyle = - elem.ownerDocument.defaultView.getComputedStyle(elem, null); - - if (elem.style.display === 'none' || elem.style.visibility === 'hidden' || - elem.style.opacity === 0 || computedStyle.display === 'none' || - computedStyle.visibility === 'hidden' || computedStyle.opacity === 0) { - return false; - } - - // For the original element and all ancestor offsetParents, trim down the - // visible area of the original element. - if (elem.isSameNode(originalElement) || elem.isSameNode(nextOffsetParent)) { - let visible = elem.getBoundingClientRect(); - if (elem.style.overflow === 'hidden' && - (visible.width === 0 || visible.height === 0)) - return false; - - top = Math.max(top, visible.top + window.pageYOffset); - bottom = Math.min(bottom, visible.bottom + window.pageYOffset); - left = Math.max(left, visible.left + window.pageXOffset); - right = Math.min(right, visible.right + window.pageXOffset); - - // The element is not within the original viewport. - let notWithinViewport = top < 0 || left < 0; - - // The element is flowing off the boundary of the page. Note this is - // not comparing to the size of the window, but the calculated offset - // size of the document body. This can happen if the element is within - // a scrollable container in the page. - let offPage = right > bodyWidth || bottom > bodyHeight; - if (notWithinViewport || offPage) { - return false; - } - nextOffsetParent = elem.offsetParent; - } - - elem = elem.parentNode; - } - return true; -}; - -/** * Helper function to find the absolute position of an element on the page. * @param {Element} elem Element to check. * @return {Array<number>} [x, y] positions.
diff --git a/ios/web/web_state/permissions_inttest.mm b/ios/web/web_state/permissions_inttest.mm index 0cbcdef..1118dbc 100644 --- a/ios/web/web_state/permissions_inttest.mm +++ b/ios/web/web_state/permissions_inttest.mm
@@ -3,7 +3,6 @@ // found in the LICENSE file. #import "base/test/ios/wait_util.h" -#include "base/test/scoped_feature_list.h" #include "ios/testing/scoped_block_swizzler.h" #import "ios/web/public/navigation/navigation_manager.h" #include "ios/web/public/navigation/reload_type.h" @@ -117,7 +116,6 @@ } protected: - base::test::ScopedFeatureList scoped_feature_list_; std::unique_ptr<ScopedBlockSwizzler> swizzler_; std::unique_ptr<net::EmbeddedTestServer> test_server_; testing::NiceMock<WebStateObserverMock> observer_;
diff --git a/media/cdm/cdm_paths_unittest.cc b/media/cdm/cdm_paths_unittest.cc index 5113620..3a7d9d9b3 100644 --- a/media/cdm/cdm_paths_unittest.cc +++ b/media/cdm/cdm_paths_unittest.cc
@@ -4,8 +4,11 @@ #include "media/cdm/cdm_paths.h" -#include "base/strings/string_split.h" +#include <string> + +#include "base/files/file_path.h" #include "base/strings/string_util.h" +#include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" @@ -16,9 +19,6 @@ namespace { -// Special path used in chrome components. -const char kPlatformSpecific[] = "_platform_specific"; - // Name of the component platform. const char kComponentPlatform[] = #if BUILDFLAG(IS_MAC) @@ -47,24 +47,10 @@ "unsupported_arch"; #endif -base::FilePath GetExpectedPlatformSpecificDirectory( - const std::string& base_path) { - base::FilePath path; - const std::string kPlatformArch = - std::string(kComponentPlatform) + "_" + kComponentArch; - return path.AppendASCII(base_path) - .AppendASCII(kPlatformSpecific) - .AppendASCII(kPlatformArch); -} - -std::string GetFlag() { - return BUILDFLAG(CDM_PLATFORM_SPECIFIC_PATH); -} - } // namespace TEST(CdmPathsTest, FlagSpecified) { - EXPECT_FALSE(GetFlag().empty()); + EXPECT_FALSE(std::string(BUILDFLAG(CDM_PLATFORM_SPECIFIC_PATH)).empty()); } TEST(CdmPathsTest, Prefix) { @@ -76,9 +62,17 @@ } TEST(CdmPathsTest, Expected) { - const char kPrefix[] = "cdm"; - EXPECT_EQ(GetExpectedPlatformSpecificDirectory(kPrefix), - GetPlatformSpecificDirectory(kPrefix)); + // The same prefix that will be passed to the function under test followed by + // the special path used by Chrome's component updater. + std::string expected_path = base::StringPrintf( + "SomeCdm/_platform_specific/%s_%s", kComponentPlatform, kComponentArch); + +#if BUILDFLAG(IS_WIN) + EXPECT_TRUE(base::ReplaceChars(expected_path, "/", "\\", &expected_path)); +#endif + + EXPECT_EQ(base::FilePath::FromUTF8Unsafe(expected_path), + GetPlatformSpecificDirectory("SomeCdm")); } } // namespace media
diff --git a/media/gpu/v4l2/test/av1_decoder.cc b/media/gpu/v4l2/test/av1_decoder.cc index 76e459d..09f128953 100644 --- a/media/gpu/v4l2/test/av1_decoder.cc +++ b/media/gpu/v4l2/test/av1_decoder.cc
@@ -114,6 +114,172 @@ v4l2_seq_params->max_frame_height_minus_1 = seq_header->max_frame_height - 1; } +// 5.9.2. Uncompressed header syntax +void FillFrameParams(struct v4l2_ctrl_av1_frame_header* v4l2_frame_params, + const libgav1::ObuFrameHeader& frm_header) { + conditionally_set_u32_flags(&v4l2_frame_params->flags, frm_header.show_frame, + V4L2_AV1_FRAME_HEADER_FLAG_SHOW_FRAME); + conditionally_set_u32_flags(&v4l2_frame_params->flags, + frm_header.showable_frame, + V4L2_AV1_FRAME_HEADER_FLAG_SHOWABLE_FRAME); + conditionally_set_u32_flags(&v4l2_frame_params->flags, + frm_header.error_resilient_mode, + V4L2_AV1_FRAME_HEADER_FLAG_ERROR_RESILIENT_MODE); + // libgav1 header has |enable_cdf_update| instead of |disable_cdf_update|. + conditionally_set_u32_flags(&v4l2_frame_params->flags, + !frm_header.enable_cdf_update, + V4L2_AV1_FRAME_HEADER_FLAG_DISABLE_CDF_UPDATE); + conditionally_set_u32_flags( + &v4l2_frame_params->flags, frm_header.allow_screen_content_tools, + V4L2_AV1_FRAME_HEADER_FLAG_ALLOW_SCREEN_CONTENT_TOOLS); + conditionally_set_u32_flags(&v4l2_frame_params->flags, + frm_header.force_integer_mv, + V4L2_AV1_FRAME_HEADER_FLAG_FORCE_INTEGER_MV); + conditionally_set_u32_flags(&v4l2_frame_params->flags, + frm_header.allow_intrabc, + V4L2_AV1_FRAME_HEADER_FLAG_ALLOW_INTRABC); + conditionally_set_u32_flags(&v4l2_frame_params->flags, + frm_header.use_superres, + V4L2_AV1_FRAME_HEADER_FLAG_USE_SUPERRES); + conditionally_set_u32_flags( + &v4l2_frame_params->flags, frm_header.allow_high_precision_mv, + V4L2_AV1_FRAME_HEADER_FLAG_ALLOW_HIGH_PRECISION_MV); + conditionally_set_u32_flags( + &v4l2_frame_params->flags, frm_header.is_motion_mode_switchable, + V4L2_AV1_FRAME_HEADER_FLAG_IS_MOTION_MODE_SWITCHABLE); + conditionally_set_u32_flags(&v4l2_frame_params->flags, + frm_header.use_ref_frame_mvs, + V4L2_AV1_FRAME_HEADER_FLAG_USE_REF_FRAME_MVS); + // libgav1 header has |enable_frame_end_update_cdf| instead. + conditionally_set_u32_flags( + &v4l2_frame_params->flags, !frm_header.enable_frame_end_update_cdf, + V4L2_AV1_FRAME_HEADER_FLAG_DISABLE_FRAME_END_UPDATE_CDF); + conditionally_set_u32_flags(&v4l2_frame_params->flags, + frm_header.tile_info.uniform_spacing, + V4L2_AV1_FRAME_HEADER_FLAG_UNIFORM_TILE_SPACING); + conditionally_set_u32_flags(&v4l2_frame_params->flags, + frm_header.allow_warped_motion, + V4L2_AV1_FRAME_HEADER_FLAG_ALLOW_WARPED_MOTION); + conditionally_set_u32_flags(&v4l2_frame_params->flags, + frm_header.reference_mode_select, + V4L2_AV1_FRAME_HEADER_FLAG_REFERENCE_SELECT); + conditionally_set_u32_flags(&v4l2_frame_params->flags, + frm_header.reduced_tx_set, + V4L2_AV1_FRAME_HEADER_FLAG_REDUCED_TX_SET); + conditionally_set_u32_flags(&v4l2_frame_params->flags, + frm_header.skip_mode_frame[0] > 0, + V4L2_AV1_FRAME_HEADER_FLAG_SKIP_MODE_ALLOWED); + conditionally_set_u32_flags(&v4l2_frame_params->flags, + frm_header.skip_mode_present, + V4L2_AV1_FRAME_HEADER_FLAG_SKIP_MODE_PRESENT); + conditionally_set_u32_flags(&v4l2_frame_params->flags, + frm_header.frame_size_override_flag, + V4L2_AV1_FRAME_HEADER_FLAG_FRAME_SIZE_OVERRIDE); + // libgav1 header doesn't have |buffer_removal_time_present_flag|. + conditionally_set_u32_flags( + &v4l2_frame_params->flags, frm_header.buffer_removal_time[0] > 0, + V4L2_AV1_FRAME_HEADER_FLAG_BUFFER_REMOVAL_TIME_PRESENT); + conditionally_set_u32_flags( + &v4l2_frame_params->flags, frm_header.frame_refs_short_signaling, + V4L2_AV1_FRAME_HEADER_FLAG_FRAME_REFS_SHORT_SIGNALING); + + switch (frm_header.frame_type) { + case libgav1::kFrameKey: + v4l2_frame_params->frame_type = V4L2_AV1_KEY_FRAME; + break; + case libgav1::kFrameInter: + v4l2_frame_params->frame_type = V4L2_AV1_INTER_FRAME; + break; + case libgav1::kFrameIntraOnly: + v4l2_frame_params->frame_type = V4L2_AV1_INTRA_ONLY_FRAME; + break; + case libgav1::kFrameSwitch: + v4l2_frame_params->frame_type = V4L2_AV1_SWITCH_FRAME; + break; + default: + NOTREACHED() << "Invalid frame type, " << frm_header.frame_type; + } + + v4l2_frame_params->order_hint = frm_header.order_hint; + v4l2_frame_params->superres_denom = frm_header.superres_scale_denominator; + v4l2_frame_params->upscaled_width = frm_header.upscaled_width; + + switch (frm_header.interpolation_filter) { + case libgav1::kInterpolationFilterEightTap: + v4l2_frame_params->interpolation_filter = + V4L2_AV1_INTERPOLATION_FILTER_EIGHTTAP; + break; + case libgav1::kInterpolationFilterEightTapSmooth: + v4l2_frame_params->interpolation_filter = + V4L2_AV1_INTERPOLATION_FILTER_EIGHTTAP_SMOOTH; + break; + case libgav1::kInterpolationFilterEightTapSharp: + v4l2_frame_params->interpolation_filter = + V4L2_AV1_INTERPOLATION_FILTER_EIGHTTAP_SHARP; + break; + case libgav1::kInterpolationFilterBilinear: + v4l2_frame_params->interpolation_filter = + V4L2_AV1_INTERPOLATION_FILTER_BILINEAR; + break; + case libgav1::kInterpolationFilterSwitchable: + v4l2_frame_params->interpolation_filter = + V4L2_AV1_INTERPOLATION_FILTER_SWITCHABLE; + break; + default: + NOTREACHED() << "Invalid interpolation filter, " + << frm_header.interpolation_filter; + } + + switch (frm_header.tx_mode) { + case libgav1::kTxModeOnly4x4: + v4l2_frame_params->tx_mode = V4L2_AV1_TX_MODE_ONLY_4X4; + break; + case libgav1::kTxModeLargest: + v4l2_frame_params->tx_mode = V4L2_AV1_TX_MODE_LARGEST; + break; + case libgav1::kTxModeSelect: + v4l2_frame_params->tx_mode = V4L2_AV1_TX_MODE_SELECT; + break; + default: + NOTREACHED() << "Invalid tx mode, " << frm_header.tx_mode; + } + + v4l2_frame_params->frame_width_minus_1 = frm_header.width - 1; + v4l2_frame_params->frame_height_minus_1 = frm_header.height - 1; + v4l2_frame_params->render_width_minus_1 = frm_header.render_width - 1; + v4l2_frame_params->render_height_minus_1 = frm_header.render_height - 1; + + v4l2_frame_params->current_frame_id = frm_header.current_frame_id; + v4l2_frame_params->primary_ref_frame = frm_header.primary_reference_frame; + SafeArrayMemcpy(v4l2_frame_params->buffer_removal_time, + frm_header.buffer_removal_time); + v4l2_frame_params->refresh_frame_flags = frm_header.refresh_frame_flags; + + static_assert(std::size(decltype(v4l2_frame_params->order_hints){}) == + libgav1::kNumReferenceFrameTypes, + "Invalid size of |order_hints| array"); + for (size_t i = 0; i < libgav1::kNumReferenceFrameTypes; i++) + v4l2_frame_params->order_hints[i] = + base::checked_cast<__u32>(frm_header.reference_order_hint[i]); + + v4l2_frame_params->last_frame_idx = + frm_header.reference_frame_index[libgav1::kReferenceFrameLast]; + v4l2_frame_params->gold_frame_idx = + frm_header.reference_frame_index[libgav1::kReferenceFrameGolden]; + + static_assert(std::size(decltype(v4l2_frame_params->ref_frame_idx){}) == + libgav1::kNumInterReferenceFrameTypes, + "Invalid size of |ref_frame_idx| array"); + for (size_t i = 0; i < libgav1::kNumInterReferenceFrameTypes; i++) + v4l2_frame_params->ref_frame_idx[i] = + base::checked_cast<__u64>(frm_header.reference_frame_index[i]); + + v4l2_frame_params->skip_mode_frame[0] = + base::checked_cast<__u8>(frm_header.skip_mode_frame[0]); + v4l2_frame_params->skip_mode_frame[1] = + base::checked_cast<__u8>(frm_header.skip_mode_frame[1]); +} + // Section 5.9.11. Loop filter params syntax. // Note that |update_ref_delta| and |update_mode_delta| flags in the spec // are not needed for V4L2 AV1 API. @@ -733,6 +899,8 @@ FillGlobalMotionParams(&v4l2_frame_params.global_motion, current_frame_header.global_motion); + FillFrameParams(&v4l2_frame_params, current_frame_header); + // TODO(stevecho): V4L2_CID_STATELESS_AV1_FRAME_HEADER is trending to be // changed to V4L2_CID_STATELESS_AV1_FRAME ext_ctrl_vectors.push_back({.id = V4L2_CID_STATELESS_AV1_FRAME_HEADER,
diff --git a/net/cookies/cookie_access_delegate.h b/net/cookies/cookie_access_delegate.h index 71878fad..76b4d59 100644 --- a/net/cookies/cookie_access_delegate.h +++ b/net/cookies/cookie_access_delegate.h
@@ -108,19 +108,6 @@ const CookieAccessDelegate* delegate, const CookiePartitionKey& cookie_partition_key, base::OnceCallback<void(CookiePartitionKey)> callback); - - // Computes the First-Party Sets. - // - // This may return a result synchronously, or asynchronously invoke `callback` - // with the result. The callback will be invoked iff the return value is - // nullopt; i.e. a result will be provided via return value or callback, but - // not both, and not neither. - [[nodiscard]] virtual absl::optional< - base::flat_map<net::SchemefulSite, std::set<net::SchemefulSite>>> - RetrieveFirstPartySets( - base::OnceCallback<void( - base::flat_map<net::SchemefulSite, std::set<net::SchemefulSite>>)> - callback) const = 0; }; } // namespace net
diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc index 644e5fc..b44e3eba 100644 --- a/net/cookies/cookie_monster.cc +++ b/net/cookies/cookie_monster.cc
@@ -59,6 +59,7 @@ #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "base/ranges/algorithm.h" +#include "base/strings/strcat.h" #include "base/strings/string_piece.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" @@ -82,6 +83,7 @@ #include "url/origin.h" #include "url/third_party/mozilla/url_parse.h" #include "url/url_canon.h" +#include "url/url_constants.h" using base::Time; using base::TimeTicks; @@ -2238,8 +2240,20 @@ base::UmaHistogramCounts100000("Cookie.Count2", cookies_.size()); if (cookie_access_delegate()) { - absl::optional<base::flat_map<SchemefulSite, std::set<SchemefulSite>>> - maybe_sets = cookie_access_delegate()->RetrieveFirstPartySets( + std::vector<SchemefulSite> sites; + for (const auto& entry : cookies_) { + sites.emplace_back( + GURL(base::StrCat({url::kHttpsScheme, "://", entry.first}))); + } + for (const auto& [partition_key, cookie_map] : partitioned_cookies_) { + for (const auto& [domain, unused_cookie] : *cookie_map) { + sites.emplace_back( + GURL(base::StrCat({url::kHttpsScheme, "://", domain}))); + } + } + absl::optional<base::flat_map<SchemefulSite, SchemefulSite>> maybe_sets = + cookie_access_delegate()->FindFirstPartySetOwners( + sites, base::BindOnce(&CookieMonster::RecordPeriodicFirstPartySetsStats, weak_ptr_factory_.GetWeakPtr())); if (maybe_sets.has_value()) @@ -2264,8 +2278,12 @@ } void CookieMonster::RecordPeriodicFirstPartySetsStats( - base::flat_map<SchemefulSite, std::set<SchemefulSite>> sets) const { - for (const auto& set : sets) { + base::flat_map<SchemefulSite, SchemefulSite> sets) const { + base::flat_map<SchemefulSite, std::set<SchemefulSite>> grouped_by_owner; + for (const auto& [site, owner] : sets) { + grouped_by_owner[owner].insert(site); + } + for (const auto& set : grouped_by_owner) { int sample = std::accumulate( set.second.begin(), set.second.end(), 0, [this](int acc, const net::SchemefulSite& site) -> int {
diff --git a/net/cookies/cookie_monster.h b/net/cookies/cookie_monster.h index d2cfebf..278c842 100644 --- a/net/cookies/cookie_monster.h +++ b/net/cookies/cookie_monster.h
@@ -688,10 +688,8 @@ // First-Party Sets presents a potentially asynchronous interface, these stats // may be collected asynchronously w.r.t. the rest of the stats collected by // `RecordPeriodicStats`. - // TODO(https://crbug.com/1266014): don't assume that the sets can all fit in - // memory at once. void RecordPeriodicFirstPartySetsStats( - base::flat_map<SchemefulSite, std::set<SchemefulSite>> sets) const; + base::flat_map<SchemefulSite, SchemefulSite> sets) const; // Defers the callback until the full coookie database has been loaded. If // it's already been loaded, runs the callback synchronously.
diff --git a/net/cookies/cookie_monster_unittest.cc b/net/cookies/cookie_monster_unittest.cc index 2d0595e1..2fd523d6 100644 --- a/net/cookies/cookie_monster_unittest.cc +++ b/net/cookies/cookie_monster_unittest.cc
@@ -5337,8 +5337,11 @@ base::HistogramTester histogram_tester; EXPECT_TRUE(cm()->DoRecordPeriodicStatsForTesting()); EXPECT_THAT(histogram_tester.GetAllSamples("Cookie.PerFirstPartySetCount"), - testing::ElementsAre(base::Bucket(2 /* min */, 1 /* samples */), - base::Bucket(3 /* min */, 1 /* samples */))); + testing::ElementsAre( // + // owner2.test & member3.test + base::Bucket(2 /* min */, 1 /* samples */), + // owner1.test, member1.test, & member2.test + base::Bucket(3 /* min */, 1 /* samples */))); } TEST_F(CookieMonsterTest, GetAllCookiesForURLNonce) {
diff --git a/net/cookies/test_cookie_access_delegate.cc b/net/cookies/test_cookie_access_delegate.cc index 5b751f26..1bf7de1d 100644 --- a/net/cookies/test_cookie_access_delegate.cc +++ b/net/cookies/test_cookie_access_delegate.cc
@@ -101,14 +101,6 @@ mapping, std::move(callback)); } -absl::optional<base::flat_map<SchemefulSite, std::set<SchemefulSite>>> -TestCookieAccessDelegate::RetrieveFirstPartySets( - base::OnceCallback< - void(base::flat_map<SchemefulSite, std::set<SchemefulSite>>)> callback) - const { - return RunMaybeAsync(first_party_sets_, std::move(callback)); -} - template <class T> absl::optional<T> TestCookieAccessDelegate::RunMaybeAsync( T result,
diff --git a/net/cookies/test_cookie_access_delegate.h b/net/cookies/test_cookie_access_delegate.h index 969447f..5293a416 100644 --- a/net/cookies/test_cookie_access_delegate.h +++ b/net/cookies/test_cookie_access_delegate.h
@@ -55,11 +55,6 @@ const base::flat_set<SchemefulSite>& sites, base::OnceCallback<void(base::flat_map<SchemefulSite, SchemefulSite>)> callback) const override; - absl::optional<base::flat_map<SchemefulSite, std::set<SchemefulSite>>> - RetrieveFirstPartySets( - base::OnceCallback<void( - base::flat_map<SchemefulSite, std::set<SchemefulSite>>)> callback) - const override; // Sets the expected return value for any cookie whose Domain // matches |cookie_domain|. Pass the value of |cookie.Domain()| and any
diff --git a/services/network/cookie_access_delegate_impl.cc b/services/network/cookie_access_delegate_impl.cc index e58d9a8..18acdee 100644 --- a/services/network/cookie_access_delegate_impl.cc +++ b/services/network/cookie_access_delegate_impl.cc
@@ -96,13 +96,4 @@ std::move(callback)); } -absl::optional<FirstPartySetsAccessDelegate::SetsByOwner> -CookieAccessDelegateImpl::RetrieveFirstPartySets( - base::OnceCallback<void(FirstPartySetsAccessDelegate::SetsByOwner)> - callback) const { - if (!first_party_sets_access_delegate_) - return {{}}; - return first_party_sets_access_delegate_->Sets(std::move(callback)); -} - } // namespace network
diff --git a/services/network/cookie_access_delegate_impl.h b/services/network/cookie_access_delegate_impl.h index 15461367..022a370 100644 --- a/services/network/cookie_access_delegate_impl.h +++ b/services/network/cookie_access_delegate_impl.h
@@ -72,10 +72,6 @@ const base::flat_set<net::SchemefulSite>& sites, base::OnceCallback<void(FirstPartySetsAccessDelegate::OwnersResult)> callback) const override; - [[nodiscard]] absl::optional<FirstPartySetsAccessDelegate::SetsByOwner> - RetrieveFirstPartySets( - base::OnceCallback<void(FirstPartySetsAccessDelegate::SetsByOwner)> - callback) const override; private: const mojom::CookieAccessDelegateType type_;
diff --git a/services/network/cookie_access_delegate_impl_unittest.cc b/services/network/cookie_access_delegate_impl_unittest.cc index 55262b2..8c0c9405a 100644 --- a/services/network/cookie_access_delegate_impl_unittest.cc +++ b/services/network/cookie_access_delegate_impl_unittest.cc
@@ -63,10 +63,6 @@ {site}, base::BindOnce([](FirstPartySetsManager::OwnersResult) { FAIL(); })), Optional(IsEmpty())); - - EXPECT_THAT(delegate().RetrieveFirstPartySets(base::BindOnce( - [](FirstPartySetsManager::SetsByOwner) { FAIL(); })), - Optional(IsEmpty())); } } // namespace
diff --git a/services/network/first_party_sets/first_party_sets_access_delegate.cc b/services/network/first_party_sets/first_party_sets_access_delegate.cc index a5e9bd7..5354341 100644 --- a/services/network/first_party_sets/first_party_sets_access_delegate.cc +++ b/services/network/first_party_sets/first_party_sets_access_delegate.cc
@@ -65,24 +65,6 @@ context_config_, std::move(callback)); } -absl::optional<FirstPartySetsAccessDelegate::SetsByOwner> -FirstPartySetsAccessDelegate::Sets( - base::OnceCallback<void(FirstPartySetsAccessDelegate::SetsByOwner)> - callback) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (pending_queries_) { - // base::Unretained() is safe because `this` owns `pending_queries_` and - // `pending_queries_` will not run the enqueued callbacks after `this` is - // destroyed. - EnqueuePendingQuery( - base::BindOnce(&FirstPartySetsAccessDelegate::SetsAndInvoke, - base::Unretained(this), std::move(callback))); - return absl::nullopt; - } - - return manager_->Sets(context_config_, std::move(callback)); -} - absl::optional<FirstPartySetsAccessDelegate::OwnerResult> FirstPartySetsAccessDelegate::FindOwner( const net::SchemefulSite& site, @@ -140,21 +122,6 @@ std::move(callbacks.second).Run(std::move(sync_result.value())); } -void FirstPartySetsAccessDelegate::SetsAndInvoke( - base::OnceCallback<void(FirstPartySetsAccessDelegate::SetsByOwner)> - callback) const { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - std::pair<base::OnceCallback<void(FirstPartySetsAccessDelegate::SetsByOwner)>, - base::OnceCallback<void(FirstPartySetsAccessDelegate::SetsByOwner)>> - callbacks = base::SplitOnceCallback(std::move(callback)); - - absl::optional<FirstPartySetsAccessDelegate::SetsByOwner> sync_result = - manager_->Sets(context_config_, std::move(callbacks.first)); - - if (sync_result.has_value()) - std::move(callbacks.second).Run(std::move(sync_result.value())); -} - void FirstPartySetsAccessDelegate::FindOwnerAndInvoke( const net::SchemefulSite& site, base::OnceCallback<void(FirstPartySetsAccessDelegate::OwnerResult)>
diff --git a/services/network/first_party_sets/first_party_sets_access_delegate.h b/services/network/first_party_sets/first_party_sets_access_delegate.h index ed68355..91a1fd4 100644 --- a/services/network/first_party_sets/first_party_sets_access_delegate.h +++ b/services/network/first_party_sets/first_party_sets_access_delegate.h
@@ -30,8 +30,6 @@ class FirstPartySetsAccessDelegate : public mojom::FirstPartySetsAccessDelegate { public: - using SetsByOwner = - base::flat_map<net::SchemefulSite, std::set<net::SchemefulSite>>; using OwnerResult = absl::optional<net::SchemefulSite>; using OwnersResult = base::flat_map<net::SchemefulSite, net::SchemefulSite>; using FlattenedSets = base::flat_map<net::SchemefulSite, net::SchemefulSite>; @@ -70,16 +68,6 @@ const std::set<net::SchemefulSite>& party_context, base::OnceCallback<void(net::FirstPartySetMetadata)> callback); - // Computes a mapping from owner to set members. For convenience of iteration, - // the members of the set includes the owner. - // - // This may return a result synchronously, or asynchronously invoke `callback` - // with the result. The callback will be invoked iff the return value is - // nullopt; i.e. a result will be provided via return value or callback, but - // not both, and not neither. - [[nodiscard]] absl::optional<SetsByOwner> Sets( - base::OnceCallback<void(SetsByOwner)> callback); - // Returns optional(nullopt) if First-Party Sets is disabled or if the input // is not in a nontrivial set. // If FPS is enabled and the input site is in a nontrivial set, then this @@ -121,10 +109,6 @@ const std::set<net::SchemefulSite>& party_context, base::OnceCallback<void(net::FirstPartySetMetadata)> callback) const; - // Same as `Sets`, but plumbs the result into the callback. Must only be - // called once the instance is fully initialized. - void SetsAndInvoke(base::OnceCallback<void(SetsByOwner)> callback) const; - // Same as `FindOwner`, but plumbs the result into the callback. Must only be // called once the instance is fully initialized. void FindOwnerAndInvoke(const net::SchemefulSite& site,
diff --git a/services/network/first_party_sets/first_party_sets_access_delegate_unittest.cc b/services/network/first_party_sets/first_party_sets_access_delegate_unittest.cc index b0120385..de20ff54 100644 --- a/services/network/first_party_sets/first_party_sets_access_delegate_unittest.cc +++ b/services/network/first_party_sets/first_party_sets_access_delegate_unittest.cc
@@ -32,13 +32,13 @@ namespace { -const net::SchemefulSite kSet1Owner(GURL("https://example.test")); -const net::SchemefulSite kSet1Member1(GURL("https://member1.test")); -const net::SchemefulSite kSet1Member2(GURL("https://member3.test")); -const net::SchemefulSite kSet2Owner(GURL("https://foo.test")); -const net::SchemefulSite kSet2Member1(GURL("https://member2.test")); -const net::SchemefulSite kSet3Owner(GURL("https://bar.test")); -const net::SchemefulSite kSet3Member1(GURL("https://member4.test")); +const net::SchemefulSite kSet1Owner(GURL("https://set1owner.test")); +const net::SchemefulSite kSet1Member1(GURL("https://set1member1.test")); +const net::SchemefulSite kSet1Member2(GURL("https://set1member2.test")); +const net::SchemefulSite kSet2Owner(GURL("https://set2owner.test")); +const net::SchemefulSite kSet2Member1(GURL("https://set2member1.test")); +const net::SchemefulSite kSet3Owner(GURL("https://set3owner.test")); +const net::SchemefulSite kSet3Member1(GURL("https://set3member1.test")); mojom::FirstPartySetsAccessDelegateParamsPtr CreateFirstPartySetsAccessDelegateParams(bool enabled) { @@ -95,14 +95,6 @@ net::SamePartyContext(Type::kSameParty)); } -TEST_F(NoopFirstPartySetsAccessDelegateTest, Sets) { - EXPECT_THAT(delegate().Sets(base::NullCallback()), - FirstPartySetsAccessDelegate::SetsByOwner({ - {kSet1Owner, {kSet1Owner, kSet1Member1, kSet1Member2}}, - {kSet2Owner, {kSet2Owner, kSet2Member1}}, - })); -} - TEST_F(NoopFirstPartySetsAccessDelegateTest, FindOwner) { EXPECT_THAT(delegate().FindOwner(kSet1Owner, base::NullCallback()), absl::make_optional(kSet1Owner)); @@ -146,13 +138,6 @@ return result.has_value() ? std::move(result).value() : future.Take(); } - FirstPartySetsAccessDelegate::SetsByOwner SetsAndWait() { - base::test::TestFuture<FirstPartySetsAccessDelegate::SetsByOwner> future; - absl::optional<FirstPartySetsAccessDelegate::SetsByOwner> result = - delegate_.Sets(future.GetCallback()); - return result.has_value() ? result.value() : future.Get(); - } - FirstPartySetsAccessDelegate::OwnerResult FindOwnerAndWait( const net::SchemefulSite& site) { base::test::TestFuture<FirstPartySetsAccessDelegate::OwnerResult> future; @@ -197,10 +182,6 @@ Type::kSameParty)); } -TEST_F(FirstPartySetsAccessDelegateDisabledTest, Sets_IsEmpty) { - EXPECT_THAT(SetsAndWait(), IsEmpty()); -} - TEST_F(FirstPartySetsAccessDelegateDisabledTest, FindOwner) { EXPECT_FALSE(FindOwnerAndWait(kSet1Owner)); EXPECT_FALSE(FindOwnerAndWait(kSet1Member1)); @@ -236,19 +217,6 @@ &kSet1Owner, &kSet1Owner)); } -TEST_F(AsyncFirstPartySetsAccessDelegateTest, QueryBeforeReady_Sets) { - base::test::TestFuture<FirstPartySetsAccessDelegate::SetsByOwner> future; - EXPECT_FALSE(delegate().Sets(future.GetCallback())); - - delegate_remote()->NotifyReady(mojom::FirstPartySetsReadyEvent::New()); - - EXPECT_THAT(future.Get(), - FirstPartySetsAccessDelegate::SetsByOwner({ - {kSet1Owner, {kSet1Owner, kSet1Member1, kSet1Member2}}, - {kSet2Owner, {kSet2Owner, kSet2Member1}}, - })); -} - TEST_F(AsyncFirstPartySetsAccessDelegateTest, QueryBeforeReady_FindOwner) { base::test::TestFuture<FirstPartySetsAccessDelegate::OwnerResult> future; EXPECT_FALSE(delegate().FindOwner(kSet1Member1, future.GetCallback())); @@ -294,9 +262,19 @@ &kSet3Owner, &kSet3Owner)); } -TEST_F(AsyncFirstPartySetsAccessDelegateTest, OverrideSets_Sets) { - base::test::TestFuture<FirstPartySetsAccessDelegate::SetsByOwner> future; - EXPECT_FALSE(delegate().Sets(future.GetCallback())); +TEST_F(AsyncFirstPartySetsAccessDelegateTest, OverrideSets_MemberIsOwner) { + base::test::TestFuture<FirstPartySetsAccessDelegate::OwnersResult> future; + EXPECT_FALSE(delegate().FindOwners( + { + kSet1Member1, + kSet1Member2, + kSet1Owner, + kSet2Member1, + kSet2Owner, + kSet3Member1, + kSet3Owner, + }, + future.GetCallback())); // The member of an override set is also an owner of an existing set as an // addition. delegate_remote()->NotifyReady(CreateFirstPartySetsReadyEvent({ @@ -307,13 +285,16 @@ {kSet3Owner, {kSet3Owner}}, })); - EXPECT_THAT( - future.Get(), - FirstPartySetsAccessDelegate::SetsByOwner({ - {kSet2Owner, {kSet2Owner, kSet2Member1}}, - {kSet3Owner, - {kSet3Owner, kSet3Member1, kSet1Owner, kSet1Member1, kSet1Member2}}, - })); + EXPECT_EQ(future.Get(), FirstPartySetsAccessDelegate::OwnersResult({ + {kSet2Owner, kSet2Owner}, + {kSet2Member1, kSet2Owner}, + {kSet3Owner, kSet3Owner}, + {kSet2Member1, kSet3Owner}, + {kSet1Owner, kSet3Owner}, + {kSet1Member1, kSet3Owner}, + {kSet1Member2, kSet3Owner}, + {kSet3Member1, kSet3Owner}, + })); } TEST_F(AsyncFirstPartySetsAccessDelegateTest, OverrideSets_FindOwner) { @@ -366,15 +347,6 @@ &kSet1Owner, &kSet1Owner)); } -TEST_F(SyncFirstPartySetsAccessDelegateTest, Sets) { - EXPECT_THAT(SetsAndWait(), - FirstPartySetsAccessDelegate::SetsByOwner({ - {kSet1Owner, {kSet1Owner, kSet1Member1, kSet1Member2}}, - {kSet2Owner, {kSet2Owner, kSet2Member1}}, - {kSet3Owner, {kSet3Owner, kSet3Member1}}, - })); -} - TEST_F(SyncFirstPartySetsAccessDelegateTest, FindOwner) { EXPECT_THAT(FindOwnerAndWait(kSet1Member1), absl::make_optional(kSet1Owner)); }
diff --git a/services/network/first_party_sets/first_party_sets_manager.cc b/services/network/first_party_sets/first_party_sets_manager.cc index 9e7acd48..4f16dcb 100644 --- a/services/network/first_party_sets/first_party_sets_manager.cc +++ b/services/network/first_party_sets/first_party_sets_manager.cc
@@ -12,7 +12,6 @@ #include "base/check.h" #include "base/containers/circular_deque.h" -#include "base/containers/contains.h" #include "base/containers/flat_map.h" #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" @@ -278,68 +277,6 @@ return sites_to_owners; } -absl::optional<FirstPartySetsManager::SetsByOwner> FirstPartySetsManager::Sets( - const FirstPartySetsContextConfig& fps_context_config, - base::OnceCallback<void(FirstPartySetsManager::SetsByOwner)> callback) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - if (!sets_.has_value()) { - EnqueuePendingQuery(base::BindOnce( - &FirstPartySetsManager::SetsAndInvoke, weak_factory_.GetWeakPtr(), - fps_context_config, std::move(callback), base::TimeTicks::Now())); - return absl::nullopt; - } - - return SetsInternal(fps_context_config); -} - -void FirstPartySetsManager::SetsAndInvoke( - const FirstPartySetsContextConfig& fps_context_config, - base::OnceCallback<void(FirstPartySetsManager::SetsByOwner)> callback, - base::TimeTicks enqueued_at) const { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(sets_.has_value()); - - UMA_HISTOGRAM_TIMES("Cookie.FirstPartySets.EnqueueingDelay.Sets", - base::TimeTicks::Now() - enqueued_at); - - std::move(callback).Run(SetsInternal(fps_context_config)); -} - -FirstPartySetsManager::SetsByOwner FirstPartySetsManager::SetsInternal( - const FirstPartySetsContextConfig& fps_context_config) const { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(sets_.has_value()); - - if (!fps_context_config.is_enabled() || !is_enabled()) - return {}; - - FirstPartySetsManager::SetsByOwner sets; - // Go over `sets_` to add entries that are not modified by the customizations. - for (const auto& pair : *sets_) { - const net::SchemefulSite& member = pair.first; - const net::SchemefulSite& owner = pair.second; - if (!base::Contains(fps_context_config.customizations(), member)) { - auto set = sets.emplace(owner, std::set<net::SchemefulSite>()).first; - set->second.insert(member); - } - } - - // Then go over the customizations to add entries that are not deleted. - for (const auto& pair : fps_context_config.customizations()) { - const net::SchemefulSite& member = pair.first; - const absl::optional<net::SchemefulSite>& owner = pair.second; - if (owner.has_value()) { - auto set = - sets.emplace(std::move(owner.value()), std::set<net::SchemefulSite>()) - .first; - set->second.insert(member); - } - } - - return sets; -} - void FirstPartySetsManager::InvokePendingQueries() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(sets_.has_value());
diff --git a/services/network/first_party_sets/first_party_sets_manager.h b/services/network/first_party_sets/first_party_sets_manager.h index 8be54191..600b306 100644 --- a/services/network/first_party_sets/first_party_sets_manager.h +++ b/services/network/first_party_sets/first_party_sets_manager.h
@@ -28,8 +28,6 @@ // answers queries about First-Party Sets after they've been loaded. class FirstPartySetsManager { public: - using SetsByOwner = - base::flat_map<net::SchemefulSite, std::set<net::SchemefulSite>>; using OwnerResult = absl::optional<net::SchemefulSite>; using OwnersResult = base::flat_map<net::SchemefulSite, net::SchemefulSite>; using FlattenedSets = base::flat_map<net::SchemefulSite, net::SchemefulSite>; @@ -58,17 +56,6 @@ const FirstPartySetsContextConfig& fps_context_config, base::OnceCallback<void(net::FirstPartySetMetadata)> callback); - // Computes a mapping from owner to set members. For convenience of iteration, - // the members of the set includes the owner. - // - // This may return a result synchronously, or asynchronously invoke `callback` - // with the result. The callback will be invoked iff the return value is - // nullopt; i.e. a result will be provided via return value or callback, but - // not both, and not neither. - [[nodiscard]] absl::optional<SetsByOwner> Sets( - const FirstPartySetsContextConfig& fps_context_config, - base::OnceCallback<void(SetsByOwner)> callback); - // Stores the First-Party Sets data. // // Only the first call to SetCompleteSets can have any effect; subsequent @@ -177,17 +164,6 @@ const base::flat_set<net::SchemefulSite>& sites, const FirstPartySetsContextConfig& fps_context_config) const; - // Same as `Sets`, but plumbs the result into the callback. Must only be - // called once the instance is fully initialized. - void SetsAndInvoke(const FirstPartySetsContextConfig& fps_context_config, - base::OnceCallback<void(SetsByOwner)> callback, - base::TimeTicks enqueued_at) const; - - // Synchronous version of `Sets`, to be run only once the instance is - // initialized. - SetsByOwner SetsInternal( - const FirstPartySetsContextConfig& fps_context_config) const; - // Enqueues a query to be answered once the instance is fully initialized. void EnqueuePendingQuery(base::OnceClosure run_query);
diff --git a/services/network/first_party_sets/first_party_sets_manager_unittest.cc b/services/network/first_party_sets/first_party_sets_manager_unittest.cc index 46e7fef..762f026b 100644 --- a/services/network/first_party_sets/first_party_sets_manager_unittest.cc +++ b/services/network/first_party_sets/first_party_sets_manager_unittest.cc
@@ -11,7 +11,6 @@ #include "base/test/task_environment.h" #include "base/test/test_future.h" #include "net/base/schemeful_site.h" -#include "net/base/test_completion_callback.h" #include "net/cookies/cookie_constants.h" #include "net/cookies/first_party_set_metadata.h" #include "net/cookies/same_party_context.h" @@ -47,13 +46,6 @@ manager_.SetCompleteSets(content); } - FirstPartySetsManager::SetsByOwner SetsAndWait() { - base::test::TestFuture<FirstPartySetsManager::SetsByOwner> future; - absl::optional<FirstPartySetsManager::SetsByOwner> result = - manager_.Sets(fps_context_config_, future.GetCallback()); - return result.has_value() ? result.value() : future.Get(); - } - net::FirstPartySetMetadata ComputeMetadataAndWait( const net::SchemefulSite& site, const net::SchemefulSite* top_frame_site, @@ -115,7 +107,11 @@ {net::SchemefulSite(GURL("https://example.test")), net::SchemefulSite(GURL("https://example.test"))}}); - EXPECT_THAT(SetsAndWait(), IsEmpty()); + EXPECT_THAT(FindOwnersAndWait({ + net::SchemefulSite(GURL("https://aaaa.test")), + net::SchemefulSite(GURL("https://example.test")), + }), + IsEmpty()); } TEST_F(FirstPartySetsManagerDisabledTest, FindOwners) { @@ -188,27 +184,12 @@ FindOwnerAndWait(net::SchemefulSite(GURL("https://member.test")))); } -TEST_F(FirstPartySetsManagerDisabledTest, Sets_IsEmpty) { - SetFirstPartySetsContextConfig( - true, {{net::SchemefulSite(GURL("https://aaaa.test")), - {net::SchemefulSite(GURL("https://example.test"))}}, - {net::SchemefulSite(GURL("https://example.test")), - {net::SchemefulSite(GURL("https://example.test"))}}}); - - EXPECT_THAT(SetsAndWait(), IsEmpty()); -} - class FirstPartySetsEnabledTest : public FirstPartySetsManagerTest { public: FirstPartySetsEnabledTest() : FirstPartySetsManagerTest(/*enabled=*/true, /*context_enabled=*/true) {} }; -TEST_F(FirstPartySetsEnabledTest, Sets_IsEmpty) { - SetCompleteSets({}); - EXPECT_THAT(SetsAndWait(), IsEmpty()); -} - TEST_F(FirstPartySetsEnabledTest, SetCompleteSets) { SetCompleteSets(base::flat_map<net::SchemefulSite, net::SchemefulSite>( {{net::SchemefulSite(GURL("https://aaaa.test")), @@ -216,23 +197,30 @@ {net::SchemefulSite(GURL("https://example.test")), net::SchemefulSite(GURL("https://example.test"))}})); - EXPECT_THAT(SetsAndWait(), - UnorderedElementsAre(Pair( - SerializesTo("https://example.test"), - UnorderedElementsAre(SerializesTo("https://example.test"), - SerializesTo("https://aaaa.test"))))); + EXPECT_THAT(FindOwnersAndWait({ + net::SchemefulSite(GURL("https://aaaa.test")), + net::SchemefulSite(GURL("https://example.test")), + }), + UnorderedElementsAre(Pair(SerializesTo("https://example.test"), + SerializesTo("https://example.test")), + Pair(SerializesTo("https://aaaa.test"), + SerializesTo("https://example.test")))); } TEST_F(FirstPartySetsEnabledTest, SetCompleteSets_Idempotent) { SetCompleteSets({}); - EXPECT_THAT(SetsAndWait(), IsEmpty()); + EXPECT_THAT(FindOwnersAndWait({}), IsEmpty()); // The second call to SetCompleteSets should have no effect. SetCompleteSets({{net::SchemefulSite(GURL("https://aaaa.test")), net::SchemefulSite(GURL("https://example.test"))}, {net::SchemefulSite(GURL("https://example.test")), net::SchemefulSite(GURL("https://example.test"))}}); - EXPECT_THAT(SetsAndWait(), IsEmpty()); + EXPECT_THAT(FindOwnersAndWait({ + net::SchemefulSite(GURL("https://aaaa.test")), + net::SchemefulSite(GURL("https://example.test")), + }), + IsEmpty()); } // Test fixture that allows precise control over when the instance gets FPS @@ -328,24 +316,6 @@ SerializesTo("https://foo.test")))); } -TEST_F(AsyncPopulatedFirstPartySetsManagerTest, QueryBeforeReady_Sets) { - base::test::TestFuture<FirstPartySetsManager::SetsByOwner> future; - EXPECT_FALSE(manager().Sets(fps_context_config(), future.GetCallback())); - - Populate(); - - EXPECT_THAT( - future.Get(), - UnorderedElementsAre( - Pair(SerializesTo("https://example.test"), - UnorderedElementsAre(SerializesTo("https://example.test"), - SerializesTo("https://member1.test"), - SerializesTo("https://member3.test"))), - Pair(SerializesTo("https://foo.test"), - UnorderedElementsAre(SerializesTo("https://foo.test"), - SerializesTo("https://member2.test"))))); -} - class PopulatedFirstPartySetsManagerTest : public AsyncPopulatedFirstPartySetsManagerTest { public: @@ -936,19 +906,6 @@ SerializesTo("https://foo.test")))); } -TEST_F(PopulatedFirstPartySetsManagerTest, Sets_NonEmpty) { - EXPECT_THAT( - SetsAndWait(), - UnorderedElementsAre( - Pair(SerializesTo("https://example.test"), - UnorderedElementsAre(SerializesTo("https://example.test"), - SerializesTo("https://member1.test"), - SerializesTo("https://member3.test"))), - Pair(SerializesTo("https://foo.test"), - UnorderedElementsAre(SerializesTo("https://foo.test"), - SerializesTo("https://member2.test"))))); -} - class DisabledContextFirstPartySetsManagerTest : public PopulatedFirstPartySetsManagerTest { public: @@ -979,10 +936,6 @@ FindOwnerAndWait(net::SchemefulSite(GURL("https://member.test")))); } -TEST_F(DisabledContextFirstPartySetsManagerTest, Sets_IsEmpty) { - EXPECT_THAT(SetsAndWait(), IsEmpty()); -} - TEST_F(DisabledContextFirstPartySetsManagerTest, ComputeMetadata) { net::SchemefulSite member(GURL("https://member1.test")); net::SchemefulSite example(GURL("https://example.test")); @@ -1180,7 +1133,7 @@ net::SchemefulSite(GURL("https://foo.test"))); } -TEST_F(OverrideSetsFirstPartySetsManagerTest, Sets_NoIntersection) { +TEST_F(OverrideSetsFirstPartySetsManagerTest, NoIntersection) { SetFirstPartySetsContextConfig( true, { {net::SchemefulSite(GURL("https://member3.test")), @@ -1190,21 +1143,28 @@ {net::SchemefulSite(GURL("https://foo.test"))}}, }); - EXPECT_THAT( - SetsAndWait(), - UnorderedElementsAre( - Pair(SerializesTo("https://example.test"), - UnorderedElementsAre(SerializesTo("https://example.test"), - SerializesTo("https://member1.test"), - SerializesTo("https://member2.test"))), - Pair(SerializesTo("https://foo.test"), - UnorderedElementsAre(SerializesTo("https://foo.test"), - SerializesTo("https://member3.test"))))); + EXPECT_THAT(FindOwnersAndWait({ + net::SchemefulSite(GURL("https://foo.test")), + net::SchemefulSite(GURL("https://example.test")), + net::SchemefulSite(GURL("https://member1.test")), + net::SchemefulSite(GURL("https://member2.test")), + net::SchemefulSite(GURL("https://member3.test")), + }), + UnorderedElementsAre(Pair(SerializesTo("https://foo.test"), + SerializesTo("https://foo.test")), + Pair(SerializesTo("https://example.test"), + SerializesTo("https://example.test")), + Pair(SerializesTo("https://member1.test"), + SerializesTo("https://example.test")), + Pair(SerializesTo("https://member2.test"), + SerializesTo("https://example.test")), + Pair(SerializesTo("https://member3.test"), + SerializesTo("https://foo.test")))); } // The member of a override set is also a member of an existing set as a // replacement. -TEST_F(OverrideSetsFirstPartySetsManagerTest, Sets_ReplacesExistingMember) { +TEST_F(OverrideSetsFirstPartySetsManagerTest, ReplacesExistingMember) { // The owner of the existing set is mapped to nullopt since it gets removed // after its member is replaced to an override set and it becomes a singleton. SetFirstPartySetsContextConfig( @@ -1219,16 +1179,21 @@ {net::SchemefulSite(GURL("https://foo.test"))}}, }); - EXPECT_THAT(SetsAndWait(), - UnorderedElementsAre(Pair( - SerializesTo("https://foo.test"), - UnorderedElementsAre(SerializesTo("https://foo.test"), - SerializesTo("https://member1.test"))))); + EXPECT_THAT(FindOwnersAndWait({ + net::SchemefulSite(GURL("https://foo.test")), + net::SchemefulSite(GURL("https://example.test")), + net::SchemefulSite(GURL("https://member1.test")), + net::SchemefulSite(GURL("https://member2.test")), + }), + UnorderedElementsAre(Pair(SerializesTo("https://foo.test"), + SerializesTo("https://foo.test")), + Pair(SerializesTo("https://member1.test"), + SerializesTo("https://foo.test")))); } // The owner of a override set is also an owner of an existing set as a // replacement. -TEST_F(OverrideSetsFirstPartySetsManagerTest, Sets_ReplacesExistingOwner) { +TEST_F(OverrideSetsFirstPartySetsManagerTest, ReplacesExistingOwner) { // The member of the existing set is mapped to nullopt since it gets removed // after its owner is replaced to an override set and it becomes a singleton. SetFirstPartySetsContextConfig( @@ -1243,16 +1208,21 @@ {net::SchemefulSite(GURL("https://example.test"))}}, }); - EXPECT_THAT(SetsAndWait(), - UnorderedElementsAre(Pair( - SerializesTo("https://example.test"), - UnorderedElementsAre(SerializesTo("https://example.test"), - SerializesTo("https://member3.test"))))); + EXPECT_THAT(FindOwnersAndWait({ + net::SchemefulSite(GURL("https://example.test")), + net::SchemefulSite(GURL("https://member1.test")), + net::SchemefulSite(GURL("https://member2.test")), + net::SchemefulSite(GURL("https://member3.test")), + }), + UnorderedElementsAre(Pair(SerializesTo("https://example.test"), + SerializesTo("https://example.test")), + Pair(SerializesTo("https://member3.test"), + SerializesTo("https://example.test")))); } // The owner of an override set is also an owner of an existing set as an // addition. -TEST_F(OverrideSetsFirstPartySetsManagerTest, Sets_AdditionMutualOwner) { +TEST_F(OverrideSetsFirstPartySetsManagerTest, AdditionMutualOwner) { SetFirstPartySetsContextConfig( true, { {net::SchemefulSite(GURL("https://member3.test")), @@ -1262,17 +1232,24 @@ {net::SchemefulSite(GURL("https://example.test"))}}, }); - EXPECT_THAT(SetsAndWait(), - UnorderedElementsAre(Pair( - SerializesTo("https://example.test"), - UnorderedElementsAre(SerializesTo("https://example.test"), - SerializesTo("https://member1.test"), - SerializesTo("https://member2.test"), - SerializesTo("https://member3.test"))))); + EXPECT_THAT(FindOwnersAndWait({ + net::SchemefulSite(GURL("https://example.test")), + net::SchemefulSite(GURL("https://member1.test")), + net::SchemefulSite(GURL("https://member2.test")), + net::SchemefulSite(GURL("https://member3.test")), + }), + UnorderedElementsAre(Pair(SerializesTo("https://example.test"), + SerializesTo("https://example.test")), + Pair(SerializesTo("https://member1.test"), + SerializesTo("https://example.test")), + Pair(SerializesTo("https://member2.test"), + SerializesTo("https://example.test")), + Pair(SerializesTo("https://member3.test"), + SerializesTo("https://example.test")))); } // The owner of a override set is a member of an existing set as an addition. -TEST_F(OverrideSetsFirstPartySetsManagerTest, Sets_AdditionOwnerIsMember) { +TEST_F(OverrideSetsFirstPartySetsManagerTest, AdditionOwnerIsMember) { // All the sites in the existing set are reparented to the new owner. SetFirstPartySetsContextConfig( true, { @@ -1287,18 +1264,25 @@ {net::SchemefulSite(GURL("https://member1.test"))}}, }); - EXPECT_THAT(SetsAndWait(), - UnorderedElementsAre(Pair( - SerializesTo("https://member1.test"), - UnorderedElementsAre(SerializesTo("https://member1.test"), - SerializesTo("https://example.test"), - SerializesTo("https://member2.test"), - SerializesTo("https://member3.test"))))); + EXPECT_THAT(FindOwnersAndWait({ + net::SchemefulSite(GURL("https://example.test")), + net::SchemefulSite(GURL("https://member1.test")), + net::SchemefulSite(GURL("https://member2.test")), + net::SchemefulSite(GURL("https://member3.test")), + }), + UnorderedElementsAre(Pair(SerializesTo("https://example.test"), + SerializesTo("https://member1.test")), + Pair(SerializesTo("https://member1.test"), + SerializesTo("https://member1.test")), + Pair(SerializesTo("https://member2.test"), + SerializesTo("https://member1.test")), + Pair(SerializesTo("https://member3.test"), + SerializesTo("https://member1.test")))); } // The member of a override set is also an owner of an existing set as an // addition. -TEST_F(OverrideSetsFirstPartySetsManagerTest, Sets_AdditionMemberIsOwner) { +TEST_F(OverrideSetsFirstPartySetsManagerTest, AdditionMemberIsOwner) { // The member of the existing set for that owner is reparented to the new // owner as addition. SetFirstPartySetsContextConfig( @@ -1314,13 +1298,20 @@ {net::SchemefulSite(GURL("https://foo.test"))}}, }); - EXPECT_THAT(SetsAndWait(), - UnorderedElementsAre(Pair( - SerializesTo("https://foo.test"), - UnorderedElementsAre(SerializesTo("https://foo.test"), - SerializesTo("https://example.test"), - SerializesTo("https://member1.test"), - SerializesTo("https://member2.test"))))); + EXPECT_THAT(FindOwnersAndWait({ + net::SchemefulSite(GURL("https://foo.test")), + net::SchemefulSite(GURL("https://example.test")), + net::SchemefulSite(GURL("https://member1.test")), + net::SchemefulSite(GURL("https://member2.test")), + }), + UnorderedElementsAre(Pair(SerializesTo("https://foo.test"), + SerializesTo("https://foo.test")), + Pair(SerializesTo("https://example.test"), + SerializesTo("https://foo.test")), + Pair(SerializesTo("https://member1.test"), + SerializesTo("https://foo.test")), + Pair(SerializesTo("https://member2.test"), + SerializesTo("https://foo.test")))); } } // namespace network \ No newline at end of file
diff --git a/services/network/network_context.cc b/services/network/network_context.cc index cb42918..33264a4 100644 --- a/services/network/network_context.cc +++ b/services/network/network_context.cc
@@ -1583,6 +1583,14 @@ void NetworkContext::CanSendSCTAuditingReport( base::OnceCallback<void(bool)> callback) { + // If the NetworkContextClient hasn't been set yet or has disconnected for + // some reason, just return `false`. (One case where this could occur is when + // restarting SCTAuditingReporter instances loaded form disk at startup -- see + // crbug.com/1347180 for more details on that case.) + if (!client_) { + std::move(callback).Run(false); + return; + } client_->OnCanSendSCTAuditingReport(std::move(callback)); }
diff --git a/services/network/sct_auditing/sct_auditing_handler.cc b/services/network/sct_auditing/sct_auditing_handler.cc index 5afcf31..489379d 100644 --- a/services/network/sct_auditing/sct_auditing_handler.cc +++ b/services/network/sct_auditing/sct_auditing_handler.cc
@@ -55,6 +55,7 @@ const char kBackoffEntryKey[] = "backoff_entry"; const char kReportKey[] = "report"; const char kSCTHashdanceMetadataKey[] = "sct_metadata"; +const char kAlreadyCountedKey[] = "counted_towards_report_limit"; void RecordPopularSCTSkippedMetrics(bool popular_sct_skipped) { base::UmaHistogramBoolean("Security.SCTAuditing.OptOut.PopularSCTSkipped", @@ -214,6 +215,8 @@ net::BackoffEntrySerializer::SerializeToValue( *reporter->backoff_entry(), base::Time::Now()); report_entry.Set(kBackoffEntryKey, std::move(backoff_entry_value)); + report_entry.Set(kAlreadyCountedKey, + reporter->counted_towards_report_limit()); std::string serialized_report; reporter->report()->SerializeToString(&serialized_report); @@ -248,6 +251,8 @@ const absl::optional<base::Value> sct_metadata_value = entry_dict->Extract(kSCTHashdanceMetadataKey); const base::Value* backoff_entry_value = entry_dict->Find(kBackoffEntryKey); + const absl::optional<bool> counted_towards_report_limit = + entry_dict->FindBool(kAlreadyCountedKey); if (!reporter_key_string || !report_string || !backoff_entry_value) { continue; @@ -296,7 +301,8 @@ } AddReporter(cache_key, std::move(audit_report), std::move(sct_metadata), - std::move(backoff_entry)); + std::move(backoff_entry), + counted_towards_report_limit.value_or(false)); ++num_reporters_deserialized; } base::UmaHistogramCounts100("Security.SCTAuditing.NumPersistedReportsLoaded", @@ -318,7 +324,8 @@ net::HashValue reporter_key, std::unique_ptr<sct_auditing::SCTClientReport> report, absl::optional<SCTAuditingReporter::SCTHashdanceMetadata> sct_metadata, - std::unique_ptr<net::BackoffEntry> backoff_entry) { + std::unique_ptr<net::BackoffEntry> backoff_entry, + bool already_counted) { DCHECK(foreground_runner_->RunsTasksInCurrentSequence()); if (mode_ == mojom::SCTAuditingMode::kDisabled) { return; @@ -334,7 +341,7 @@ base::BindRepeating(&SCTAuditingHandler::OnReporterStateUpdated, GetWeakPtr()), base::BindOnce(&SCTAuditingHandler::OnReporterFinished, GetWeakPtr()), - std::move(backoff_entry)); + std::move(backoff_entry), already_counted); reporter->Start(); pending_reporters_.Put(reporter->key(), std::move(reporter));
diff --git a/services/network/sct_auditing/sct_auditing_handler.h b/services/network/sct_auditing/sct_auditing_handler.h index 9a34f7f..0b44a6c 100644 --- a/services/network/sct_auditing/sct_auditing_handler.h +++ b/services/network/sct_auditing/sct_auditing_handler.h
@@ -88,13 +88,15 @@ // this will call SCTAuditingReporter::Start() to initiate sending the report. // If the report is a hashdance report, |leaf_hash| should be set to the // Merkle tree leaf hash of a randomly selected SCT. - // Optionally takes in a BackoffEntry for recreating reporter state from - // persisted storage. + // Optionally takes in a BackoffEntry and a bool for whether the report has + // already been counted towards the max-reports limit, for recreating reporter + // state from persisted storage. void AddReporter( net::HashValue reporter_key, std::unique_ptr<sct_auditing::SCTClientReport> report, absl::optional<SCTAuditingReporter::SCTHashdanceMetadata> sct_metadata, - std::unique_ptr<net::BackoffEntry> backoff_entry = nullptr); + std::unique_ptr<net::BackoffEntry> backoff_entry = nullptr, + bool already_counted = false); // Loads serialized reports from `serialized` and creates a new // SCTAuditingReporter for each (if a reporter for that report does not yet
diff --git a/services/network/sct_auditing/sct_auditing_handler_unittest.cc b/services/network/sct_auditing/sct_auditing_handler_unittest.cc index a24c9ce..7af3722 100644 --- a/services/network/sct_auditing/sct_auditing_handler_unittest.cc +++ b/services/network/sct_auditing/sct_auditing_handler_unittest.cc
@@ -1056,6 +1056,102 @@ "sha256/qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqo=")); } +// Test that the "counted_towards_report_limit" flag is correctly reapplied when +// deserialize a persisted reporter. See crbug.com/1348313. +TEST_F(SCTAuditingHandlerTest, PersistedDataWithReportAlreadyCounted) { + // Set up previously persisted data on disk: + // - Default-initialized net::HashValue(net::HASH_VALUE_SHA256) + // - Empty SCTClientReport for origin "example.test:443". + // - A simple BackoffEntry. + // - A simple SCTHashdanceMetadata value. + // - The "already counted toward report limit" flag set to `true`. + std::string persisted_report = + R"( + [{ + "reporter_key": + "sha256/qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqo=", + "report": "EhUKExIRCgxleGFtcGxlLnRlc3QQuwM=", + "backoff_entry": [2,0,"30000000","11644578625551798"], + "sct_metadata": { + "leaf_hash": "ZmFrZS1sZWFmLWhhc2g=", + "issued": "1659045681000000", + "log_id": "ZmFrZS1sb2ctaWQ=", + "log_mmd": "86400000000", + "cert_expiry": "1661724081000000" + }, + "counted_towards_report_limit": true + }] + )"; + ASSERT_TRUE(base::WriteFile(persistence_path_, persisted_report)); + + mojo::PendingRemote<network::mojom::URLLoaderFactory> factory_remote; + url_loader_factory_.Clone(factory_remote.InitWithNewPipeAndPassReceiver()); + + SCTAuditingHandler handler(network_context_.get(), persistence_path_); + handler.SetMode(mojom::SCTAuditingMode::kHashdance); + handler.SetURLLoaderFactoryForTesting(std::move(factory_remote)); + + // Wait for a lookup query request to be sent to ensure the persisted report + // has been deserialized and a new SCTAuditingReporter created. + WaitForRequests(1u); + + auto* pending_reporters = handler.GetPendingReportersForTesting(); + ASSERT_EQ(pending_reporters->size(), 1u); + // Reporter should have the `counted_toward_report_limit` flag set to `true`. + for (const auto& reporter : *pending_reporters) { + EXPECT_TRUE(reporter.second->counted_towards_report_limit()); + } +} + +// Test that when a persisted reporter is deserialized that does not have the +// "counted_towards_report_limit" flag set, it gets defaulted to `false` in the +// newly created SCTAuditingReporter. (This covers the case for existing +// serialized data from versions before the flag was added.) +// See crbug.com/1348313. +TEST_F(SCTAuditingHandlerTest, PersistedDataWithoutReportAlreadyCounted) { + // Set up previously persisted data on disk: + // - Default-initialized net::HashValue(net::HASH_VALUE_SHA256) + // - Empty SCTClientReport for origin "example.test:443". + // - A simple BackoffEntry. + // - A simple SCTHashdanceMetadata value. + // - The "already counted toward report limit" not set. + std::string persisted_report = + R"( + [{ + "reporter_key": + "sha256/qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqo=", + "report": "EhUKExIRCgxleGFtcGxlLnRlc3QQuwM=", + "backoff_entry": [2,0,"30000000","11644578625551798"], + "sct_metadata": { + "leaf_hash": "ZmFrZS1sZWFmLWhhc2g=", + "issued": "1659045681000000", + "log_id": "ZmFrZS1sb2ctaWQ=", + "log_mmd": "86400000000", + "cert_expiry": "1661724081000000" + } + }] + )"; + ASSERT_TRUE(base::WriteFile(persistence_path_, persisted_report)); + + mojo::PendingRemote<network::mojom::URLLoaderFactory> factory_remote; + url_loader_factory_.Clone(factory_remote.InitWithNewPipeAndPassReceiver()); + + SCTAuditingHandler handler(network_context_.get(), persistence_path_); + handler.SetMode(mojom::SCTAuditingMode::kHashdance); + handler.SetURLLoaderFactoryForTesting(std::move(factory_remote)); + + // Wait for a lookup query request to be sent to ensure the persisted report + // has been deserialized and a new SCTAuditingReporter created. + WaitForRequests(1u); + + auto* pending_reporters = handler.GetPendingReportersForTesting(); + ASSERT_EQ(pending_reporters->size(), 1u); + // Reporter should have the `counted_toward_report_limit` flag set to `false`. + for (const auto& reporter : *pending_reporters) { + EXPECT_FALSE(reporter.second->counted_towards_report_limit()); + } +} + class NoPersistenceSCTAuditingHandlerTest : public SCTAuditingHandlerTest { public: void SetUp() override {
diff --git a/services/network/sct_auditing/sct_auditing_reporter.cc b/services/network/sct_auditing/sct_auditing_reporter.cc index b2ea41d..3ba7eca 100644 --- a/services/network/sct_auditing/sct_auditing_reporter.cc +++ b/services/network/sct_auditing/sct_auditing_reporter.cc
@@ -214,7 +214,8 @@ mojom::URLLoaderFactory* url_loader_factory, ReporterUpdatedCallback update_callback, ReporterDoneCallback done_callback, - std::unique_ptr<net::BackoffEntry> persisted_backoff_entry) + std::unique_ptr<net::BackoffEntry> persisted_backoff_entry, + bool counted_towards_report_limit) : owner_network_context_(owner_network_context), reporter_key_(reporter_key), report_(std::move(report)), @@ -223,7 +224,8 @@ configuration_(std::move(configuration)), update_callback_(std::move(update_callback)), done_callback_(std::move(done_callback)), - max_retries_(kMaxRetries) { + max_retries_(kMaxRetries), + counted_towards_report_limit_(counted_towards_report_limit) { // Clone the URLLoaderFactory to avoid any dependencies on its lifetime. The // Reporter instance can maintain its own copy. // Relatively few Reporters are expected to exist at a time (due to sampling @@ -266,16 +268,17 @@ } // Entrypoint for checking whether the max-reports limit has been reached. - // This should only get called once for the lifetime of the Reporter. - // TODO(crbug.com/1144205): Once reports are persisted to disk, the Reporter - // state should include whether it has been "counted" yet, otherwise if a - // Reporter gets persisted and restored many times it would cause the report - // cap to trigger. This can likely just be a boolean flag on the Reporter and - // the persisted state -- if `true`, this check (and incrementing the report - // count) can be skipped. - owner_network_context_->CanSendSCTAuditingReport( - base::BindOnce(&SCTAuditingReporter::OnCheckReportAllowedStatusComplete, - weak_factory_.GetWeakPtr())); + // This should only get called once for the lifetime of the Reporter. If the + // report has already been counted towards the max-reports limit, we skip the + // check (and don't increment the report count later when trying to send the + // full report). + if (counted_towards_report_limit_) { + OnCheckReportAllowedStatusComplete(true); + } else { + owner_network_context_->CanSendSCTAuditingReport( + base::BindOnce(&SCTAuditingReporter::OnCheckReportAllowedStatusComplete, + weak_factory_.GetWeakPtr())); + } } void SCTAuditingReporter::OnCheckReportAllowedStatusComplete(bool allowed) { @@ -495,8 +498,16 @@ } // The server does not know about this SCT, and it should. Notify the - // embedder and start sending the full report. - owner_network_context_->OnNewSCTAuditingReportSent(); + // embedder (ensuring we only do this once per report) and then start sending + // the full report. + if (!counted_towards_report_limit_) { + owner_network_context_->OnNewSCTAuditingReportSent(); + // Mark this reporter as already counted towards the max report limit. This + // prevents counting the same report multiple times in case of retries (and + // retries across browser restarts with persisted reports). + counted_towards_report_limit_ = true; + } + RecordLookupQueryResult(LookupQueryResult::kSCTSuffixNotFound); SendReport(); }
diff --git a/services/network/sct_auditing/sct_auditing_reporter.h b/services/network/sct_auditing/sct_auditing_reporter.h index e5b51727..eb97a9c 100644 --- a/services/network/sct_auditing/sct_auditing_reporter.h +++ b/services/network/sct_auditing/sct_auditing_reporter.h
@@ -143,7 +143,8 @@ mojom::URLLoaderFactory* url_loader_factory, ReporterUpdatedCallback update_callback, ReporterDoneCallback done_callback, - std::unique_ptr<net::BackoffEntry> backoff_entry = nullptr); + std::unique_ptr<net::BackoffEntry> backoff_entry = nullptr, + bool counted_towards_report_limit = false); ~SCTAuditingReporter(); SCTAuditingReporter(const SCTAuditingReporter&) = delete; @@ -159,6 +160,7 @@ const absl::optional<SCTHashdanceMetadata>& sct_hashdance_metadata() { return sct_hashdance_metadata_; } + bool counted_towards_report_limit() { return counted_towards_report_limit_; } static void SetRetryDelayForTesting(absl::optional<base::TimeDelta> delay); @@ -195,6 +197,13 @@ int max_retries_; + // Whether the report has been counted towards the max-reports limit. This is + // used to determine whether to notify the embedder that a new report is being + // sent by the client, to avoid overcounting how many unique reports have been + // sent. (Without this flag, this could happen on retries if the hashdance + // lookup query succeeds but then the full report upload fails.) + bool counted_towards_report_limit_; + base::WeakPtrFactory<SCTAuditingReporter> weak_factory_{this}; };
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 9b6c2edb..312cfb7 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -10250,6 +10250,25 @@ ] } ], + "WebUIBubblePersistentRendererStudy": [ + { + "platforms": [ + "chromeos", + "chromeos_lacros", + "linux", + "mac", + "windows" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "WebUIBubblePerProfilePersistence" + ] + } + ] + } + ], "WebUICodeCache": [ { "platforms": [
diff --git a/third_party/blink/public/devtools_protocol/browser_protocol.pdl b/third_party/blink/public/devtools_protocol/browser_protocol.pdl index a541e0e..28fcb0c 100644 --- a/third_party/blink/public/devtools_protocol/browser_protocol.pdl +++ b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
@@ -9346,13 +9346,16 @@ experimental type FilterEntry extends object properties # If set, causes exclusion of mathcing targets from the list. - # The remainder of filter entries in the filter arrat are ignored. optional boolean exclude # If not present, matches any type. optional string type - # If filter is not specified, the one assumed is [{type: "browser", exclude: true}, {}] - # (i.e. include everything but browser). + # The entries in TargetFilter are matched sequentially against targets and + # the first entry that matches determines if the target is included or not, + # depending on the value of `exclude` field in the entry. + # If filter is not specified, the one assumed is + # [{type: "browser", exclude: true}, {type: "tab", exclude: true}, {}] + # (i.e. include everything but `browser` and `tab`). experimental type TargetFilter extends array of FilterEntry experimental type RemoteLocation extends object
diff --git a/third_party/blink/public/mojom/manifest/manifest.mojom b/third_party/blink/public/mojom/manifest/manifest.mojom index 2014b31b..be336ec 100644 --- a/third_party/blink/public/mojom/manifest/manifest.mojom +++ b/third_party/blink/public/mojom/manifest/manifest.mojom
@@ -40,7 +40,7 @@ array<ManifestImageResource> icons; - array<ManifestImageResource> screenshots; + array<ManifestScreenshot> screenshots; array<ManifestShortcutItem> shortcuts; @@ -171,6 +171,22 @@ array<Purpose> purpose; }; +// Structure representing a screenshot as per the Manifest specification, see: +// https://www.w3.org/TR/manifest-app-info/#screenshots-member. This includes +// a ImageResource with some additional members. +struct ManifestScreenshot { + enum Platform { + kUnknown = 0, + kWide, + kNarrow, + }; + + ManifestImageResource image; + + // The distribution platform for which a given screenshot applies. + Platform platform; +}; + // Structure representing a share target file. struct ManifestFileFilter { mojo_base.mojom.String16? name;
diff --git a/third_party/blink/renderer/bindings/generated_in_core.gni b/third_party/blink/renderer/bindings/generated_in_core.gni index 48bf8d98..1074ce7c 100644 --- a/third_party/blink/renderer/bindings/generated_in_core.gni +++ b/third_party/blink/renderer/bindings/generated_in_core.gni
@@ -203,6 +203,8 @@ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_get_root_node_options.h", "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_hash_change_event_init.cc", "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_hash_change_event_init.h", + "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_highlight_pointer_event_init.cc", + "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_highlight_pointer_event_init.h", "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_idle_request_options.cc", "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_idle_request_options.h", "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_image_bitmap_options.cc", @@ -829,6 +831,8 @@ "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_headers.h", "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_highlight.cc", "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_highlight.h", + "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_highlight_pointer_event.cc", + "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_highlight_pointer_event.h", "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_highlight_registry.cc", "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_highlight_registry.h", "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_history.cc",
diff --git a/third_party/blink/renderer/bindings/idl_in_core.gni b/third_party/blink/renderer/bindings/idl_in_core.gni index a8ba436f0..eababe1 100644 --- a/third_party/blink/renderer/bindings/idl_in_core.gni +++ b/third_party/blink/renderer/bindings/idl_in_core.gni
@@ -334,6 +334,7 @@ "//third_party/blink/renderer/core/geometry/dom_rect_read_only.idl", "//third_party/blink/renderer/core/highlight/css_highlight_registry.idl", "//third_party/blink/renderer/core/highlight/highlight.idl", + "//third_party/blink/renderer/core/highlight/highlight_pointer_event.idl", "//third_party/blink/renderer/core/highlight/highlight_registry.idl", "//third_party/blink/renderer/core/html/assigned_nodes_options.idl", "//third_party/blink/renderer/core/html/canvas/baselines.idl",
diff --git a/third_party/blink/renderer/core/animation/animation.cc b/third_party/blink/renderer/core/animation/animation.cc index a460769..84b7de1 100644 --- a/third_party/blink/renderer/core/animation/animation.cc +++ b/third_party/blink/renderer/core/animation/animation.cc
@@ -726,8 +726,8 @@ // matches the specification for composite ordering if (priority1 == PseudoPriority::kOther && pseudo1 != pseudo2) { return CodeUnitCompareLessThan( - PseudoElement::PseudoElementNameForEvents(pseudo1), - PseudoElement::PseudoElementNameForEvents(pseudo2)); + PseudoElement::PseudoElementNameForEvents(owning_element1), + PseudoElement::PseudoElementNameForEvents(owning_element2)); } if (anim_priority1 == kCssAnimationPriority) { // When comparing two CSSAnimations with the same owning element, we sort
diff --git a/third_party/blink/renderer/core/animation/css/css_animations.cc b/third_party/blink/renderer/core/animation/css/css_animations.cc index 2fcbea1d..1d4bb5e6 100644 --- a/third_party/blink/renderer/core/animation/css/css_animations.cc +++ b/third_party/blink/renderer/core/animation/css/css_animations.cc
@@ -1774,8 +1774,8 @@ const AtomicString& event_name, const AnimationTimeDelta& elapsed_time) { if (animation_target_->GetDocument().HasListenerType(listener_type)) { - String pseudo_element_name = PseudoElement::PseudoElementNameForEvents( - animation_target_->GetPseudoId()); + String pseudo_element_name = + PseudoElement::PseudoElementNameForEvents(animation_target_); AnimationEvent* event = AnimationEvent::Create( event_name, name_, elapsed_time, pseudo_element_name); event->SetTarget(GetEventTarget()); @@ -1950,7 +1950,7 @@ ? property_.CustomPropertyName() : property_.GetCSSProperty().GetPropertyNameString(); String pseudo_element = - PseudoElement::PseudoElementNameForEvents(GetPseudoId()); + PseudoElement::PseudoElementNameForEvents(transition_target_); TransitionEvent* event = TransitionEvent::Create( type, property_name, elapsed_time, pseudo_element); event->SetTarget(GetEventTarget());
diff --git a/third_party/blink/renderer/core/animation/css/css_animations.h b/third_party/blink/renderer/core/animation/css/css_animations.h index 2161793..9b8d35df 100644 --- a/third_party/blink/renderer/core/animation/css/css_animations.h +++ b/third_party/blink/renderer/core/animation/css/css_animations.h
@@ -303,7 +303,6 @@ const Element& TransitionTarget() const { return *transition_target_; } EventTarget* GetEventTarget() const; - PseudoId GetPseudoId() const { return transition_target_->GetPseudoId(); } Document& GetDocument() const { return transition_target_->GetDocument(); } Member<Element> transition_target_;
diff --git a/third_party/blink/renderer/core/dom/events/event.cc b/third_party/blink/renderer/core/dom/events/event.cc index 1821c3a7..707d8c3e 100644 --- a/third_party/blink/renderer/core/dom/events/event.cc +++ b/third_party/blink/renderer/core/dom/events/event.cc
@@ -195,6 +195,10 @@ return false; } +bool Event::IsHighlightPointerEvent() const { + return false; +} + bool Event::IsInputEvent() const { return false; }
diff --git a/third_party/blink/renderer/core/dom/events/event.h b/third_party/blink/renderer/core/dom/events/event.h index 96fd605..d0b7670c 100644 --- a/third_party/blink/renderer/core/dom/events/event.h +++ b/third_party/blink/renderer/core/dom/events/event.h
@@ -220,6 +220,7 @@ virtual bool IsGestureEvent() const; virtual bool IsWheelEvent() const; virtual bool IsPointerEvent() const; + virtual bool IsHighlightPointerEvent() const; virtual bool IsInputEvent() const; virtual bool IsCompositionEvent() const;
diff --git a/third_party/blink/renderer/core/dom/pseudo_element.cc b/third_party/blink/renderer/core/dom/pseudo_element.cc index 5c065db..c7196ff 100644 --- a/third_party/blink/renderer/core/dom/pseudo_element.cc +++ b/third_party/blink/renderer/core/dom/pseudo_element.cc
@@ -133,12 +133,29 @@ return name; } -const AtomicString& PseudoElement::PseudoElementNameForEvents( - PseudoId pseudo_id) { - if (pseudo_id == kPseudoIdNone) - return g_null_atom; - else - return PseudoElementTagName(pseudo_id).LocalName(); +AtomicString PseudoElement::PseudoElementNameForEvents(Element* element) { + DCHECK(element); + auto pseudo_id = element->GetPseudoId(); + switch (pseudo_id) { + case kPseudoIdNone: + return g_null_atom; + case kPseudoIdPageTransitionContainer: + case kPseudoIdPageTransitionImageWrapper: + case kPseudoIdPageTransitionIncomingImage: + case kPseudoIdPageTransitionOutgoingImage: { + auto* pseudo = To<PseudoElement>(element); + DCHECK(pseudo); + StringBuilder builder; + builder.Append(PseudoElementTagName(pseudo_id).LocalName()); + builder.Append("("); + builder.Append(pseudo->document_transition_tag()); + builder.Append(")"); + return AtomicString(builder.ReleaseString()); + } + default: + break; + } + return PseudoElementTagName(pseudo_id).LocalName(); } bool PseudoElement::IsWebExposed(PseudoId pseudo_id, const Node* parent) { @@ -147,14 +164,6 @@ if (parent && parent->IsPseudoElement()) return RuntimeEnabledFeatures::CSSMarkerNestedPseudoElementEnabled(); return true; - case kPseudoIdPageTransition: - case kPseudoIdPageTransitionContainer: - case kPseudoIdPageTransitionImageWrapper: - case kPseudoIdPageTransitionIncomingImage: - case kPseudoIdPageTransitionOutgoingImage: - // These elements are generated only when DocumentTransition feature is - // enabled. - return true; default: return true; }
diff --git a/third_party/blink/renderer/core/dom/pseudo_element.h b/third_party/blink/renderer/core/dom/pseudo_element.h index 268a4d7..9716e3b 100644 --- a/third_party/blink/renderer/core/dom/pseudo_element.h +++ b/third_party/blink/renderer/core/dom/pseudo_element.h
@@ -66,7 +66,7 @@ scoped_refptr<ComputedStyle> LayoutStyleForDisplayContents( const ComputedStyle&); - static const AtomicString& PseudoElementNameForEvents(PseudoId); + static AtomicString PseudoElementNameForEvents(Element*); static bool IsWebExposed(PseudoId, const Node*); // Pseudo element are not allowed to be the inner node for hit testing. Find
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc index 5d02678..1bd0569 100644 --- a/third_party/blink/renderer/core/frame/local_frame_view.cc +++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -288,17 +288,7 @@ unique_id_(NewUniqueObjectId()), layout_shift_tracker_(MakeGarbageCollected<LayoutShiftTracker>(this)), paint_timing_detector_(MakeGarbageCollected<PaintTimingDetector>(this)), - mobile_friendliness_checker_( - // Only run the mobile friendliness checker for the outermost main - // frame. The checker will iterate through all local frames in the - // current blink::Page. Also skip the mobile friendliness checks for - // "non-ordinary" pages by checking IsLocalFrameClientImpl(), since - // it's not useful to generate mobile friendliness metrics for - // devtools, svg, etc. - GetFrame().Client()->IsLocalFrameClientImpl() && - GetFrame().IsOutermostMainFrame() - ? MakeGarbageCollected<MobileFriendlinessChecker>(*this) - : nullptr) + mobile_friendliness_checker_(MobileFriendlinessChecker::Create(*this)) #if DCHECK_IS_ON() , is_updating_descendant_dependent_flags_(false),
diff --git a/third_party/blink/renderer/core/highlight/build.gni b/third_party/blink/renderer/core/highlight/build.gni index 8d22062..4bd4883 100644 --- a/third_party/blink/renderer/core/highlight/build.gni +++ b/third_party/blink/renderer/core/highlight/build.gni
@@ -7,6 +7,8 @@ "css_highlight_registry.h", "highlight.cc", "highlight.h", + "highlight_pointer_event.cc", + "highlight_pointer_event.h", "highlight_registry.cc", "highlight_registry.h", "highlight_registry_map_entry.h",
diff --git a/third_party/blink/renderer/core/highlight/highlight.cc b/third_party/blink/renderer/core/highlight/highlight.cc index 4c019d3d..54d7b33 100644 --- a/third_party/blink/renderer/core/highlight/highlight.cc +++ b/third_party/blink/renderer/core/highlight/highlight.cc
@@ -25,7 +25,7 @@ void Highlight::Trace(blink::Visitor* visitor) const { visitor->Trace(highlight_ranges_); visitor->Trace(containing_highlight_registries_); - ScriptWrappable::Trace(visitor); + EventTargetWithInlineData::Trace(visitor); } void Highlight::ScheduleRepaintsInContainingHighlightRegistries() const { @@ -80,6 +80,18 @@ return highlight_ranges_.Contains(range); } +const AtomicString& Highlight::InterfaceName() const { + // TODO(crbug.com/1346693) + NOTIMPLEMENTED(); + return g_null_atom; +} + +ExecutionContext* Highlight::GetExecutionContext() const { + // TODO(crbug.com/1346693) + NOTIMPLEMENTED(); + return nullptr; +} + void Highlight::RegisterIn(HighlightRegistry* highlight_registry) { auto map_iterator = containing_highlight_registries_.find(highlight_registry); if (map_iterator == containing_highlight_registries_.end()) {
diff --git a/third_party/blink/renderer/core/highlight/highlight.h b/third_party/blink/renderer/core/highlight/highlight.h index ff23ac8f..bb4a1b0a 100644 --- a/third_party/blink/renderer/core/highlight/highlight.h +++ b/third_party/blink/renderer/core/highlight/highlight.h
@@ -8,7 +8,7 @@ #include "third_party/blink/renderer/bindings/core/v8/iterable.h" #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/dom/abstract_range.h" -#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" +#include "third_party/blink/renderer/core/dom/events/event_target.h" #include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h" #include "third_party/blink/renderer/platform/heap/collection_support/heap_linked_hash_set.h" #include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h" @@ -20,7 +20,7 @@ SetlikeIterable<Member<AbstractRange>, AbstractRange>; class HighlightRegistry; -class CORE_EXPORT Highlight : public ScriptWrappable, +class CORE_EXPORT Highlight : public EventTargetWithInlineData, public HighlightSetIterable { DEFINE_WRAPPERTYPEINFO(); @@ -46,6 +46,11 @@ bool Contains(AbstractRange*) const; + // EventTarget + const AtomicString& InterfaceName() const override; + ExecutionContext* GetExecutionContext() const override; + + // HighlightSetIterable class IterationSource final : public HighlightSetIterable::IterationSource { public: explicit IterationSource(const Highlight& highlight);
diff --git a/third_party/blink/renderer/core/highlight/highlight.idl b/third_party/blink/renderer/core/highlight/highlight.idl index 2272698..1111d21 100644 --- a/third_party/blink/renderer/core/highlight/highlight.idl +++ b/third_party/blink/renderer/core/highlight/highlight.idl
@@ -16,4 +16,8 @@ setlike<AbstractRange>; attribute long priority; attribute HighlightType type; + // TODO(crbug.com/1344319): Inherit from EventTarget + [RuntimeEnabled = HighlightPointerEvents] void addEventListener(DOMString type, EventListener? listener, optional (AddEventListenerOptions or boolean) options); + [RuntimeEnabled = HighlightPointerEvents] void removeEventListener(DOMString type, EventListener? listener, optional (EventListenerOptions or boolean) options); + [ImplementedAs=dispatchEventForBindings, RaisesException, RuntimeCallStatsCounter=EventTargetDispatchEvent, RuntimeEnabled = HighlightPointerEvents] boolean dispatchEvent(Event event); };
diff --git a/third_party/blink/renderer/core/highlight/highlight_pointer_event.cc b/third_party/blink/renderer/core/highlight/highlight_pointer_event.cc new file mode 100644 index 0000000..6ec023d --- /dev/null +++ b/third_party/blink/renderer/core/highlight/highlight_pointer_event.cc
@@ -0,0 +1,32 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/core/highlight/highlight_pointer_event.h" + +#include "third_party/blink/renderer/bindings/core/v8/v8_highlight_pointer_event_init.h" + +namespace blink { + +HighlightPointerEvent::HighlightPointerEvent( + const AtomicString& type, + const HighlightPointerEventInit* initializer, + base::TimeTicks platform_time_stamp, + MouseEvent::SyntheticEventType synthetic_event_type, + WebMenuSourceType menu_source_type) + : PointerEvent(type, + initializer, + platform_time_stamp, + synthetic_event_type, + menu_source_type) {} + +bool HighlightPointerEvent::IsHighlightPointerEvent() const { + return true; +} + +void HighlightPointerEvent::Trace(blink::Visitor* visitor) const { + visitor->Trace(range_); + PointerEvent::Trace(visitor); +} + +} // namespace blink
diff --git a/third_party/blink/renderer/core/highlight/highlight_pointer_event.h b/third_party/blink/renderer/core/highlight/highlight_pointer_event.h new file mode 100644 index 0000000..7c6718f --- /dev/null +++ b/third_party/blink/renderer/core/highlight/highlight_pointer_event.h
@@ -0,0 +1,57 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HIGHLIGHT_HIGHLIGHT_POINTER_EVENT_H_ +#define THIRD_PARTY_BLINK_RENDERER_CORE_HIGHLIGHT_HIGHLIGHT_POINTER_EVENT_H_ + +#include "third_party/blink/renderer/core/dom/range.h" +#include "third_party/blink/renderer/core/events/pointer_event.h" + +namespace blink { + +class HighlightPointerEventInit; + +class CORE_EXPORT HighlightPointerEvent : public PointerEvent { + DEFINE_WRAPPERTYPEINFO(); + + public: + static HighlightPointerEvent* Create( + const AtomicString& type, + const HighlightPointerEventInit* initializer, + base::TimeTicks platform_time_stamp = base::TimeTicks::Now(), + MouseEvent::SyntheticEventType synthetic_event_type = + kRealOrIndistinguishable, + WebMenuSourceType menu_source_type = kMenuSourceNone) { + return MakeGarbageCollected<HighlightPointerEvent>( + type, initializer, platform_time_stamp, synthetic_event_type, + menu_source_type); + } + + explicit HighlightPointerEvent( + const AtomicString&, + const HighlightPointerEventInit*, + base::TimeTicks platform_time_stamp, + MouseEvent::SyntheticEventType synthetic_event_type, + WebMenuSourceType menu_source_type = kMenuSourceNone); + + Range* range() const { return range_; } + + bool IsHighlightPointerEvent() const override; + + void Trace(blink::Visitor*) const override; + + private: + Member<Range> range_; +}; + +template <> +struct DowncastTraits<HighlightPointerEvent> { + static bool AllowFrom(const Event& event) { + return event.IsHighlightPointerEvent(); + } +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HIGHLIGHT_HIGHLIGHT_POINTER_EVENT_H_
diff --git a/third_party/blink/renderer/core/highlight/highlight_pointer_event.idl b/third_party/blink/renderer/core/highlight/highlight_pointer_event.idl new file mode 100644 index 0000000..85a119b6 --- /dev/null +++ b/third_party/blink/renderer/core/highlight/highlight_pointer_event.idl
@@ -0,0 +1,14 @@ +// Copyright 2022 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +dictionary HighlightPointerEventInit : PointerEventInit { + Range? range = null; +}; + +[ + RuntimeEnabled = HighlightPointerEvents, + Exposed = Window +] interface HighlightPointerEvent : PointerEvent { + readonly attribute Range? range; +};
diff --git a/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.cc index 01377d6..0c24f1d 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.cc
@@ -134,6 +134,14 @@ std::make_unique<NGTableFragmentData::CollapsedBordersGeometry>( *table_collapsed_borders_geometry)); } + } else if (physical_fragment.IsTableNGSection()) { + if (const auto section_start_row_index = + physical_fragment.TableSectionStartRowIndex()) { + Vector<LayoutUnit> section_row_offsets = + *physical_fragment.TableSectionRowOffsets(); + container_builder_.SetTableSectionCollapsedBordersGeometry( + *section_start_row_index, std::move(section_row_offsets)); + } } if (physical_fragment.IsGridNG()) {
diff --git a/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker.cc b/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker.cc index ddad2c1..3847efb2 100644 --- a/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker.cc +++ b/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker.cc
@@ -15,6 +15,7 @@ #include "third_party/blink/renderer/core/frame/local_frame_view.h" #include "third_party/blink/renderer/core/frame/page_scale_constraints_set.h" #include "third_party/blink/renderer/core/frame/root_frame_viewport.h" +#include "third_party/blink/renderer/core/frame/settings.h" #include "third_party/blink/renderer/core/frame/visual_viewport.h" #include "third_party/blink/renderer/core/html/forms/html_form_control_element.h" #include "third_party/blink/renderer/core/html/html_anchor_element.h" @@ -399,6 +400,23 @@ } // namespace +MobileFriendlinessChecker* MobileFriendlinessChecker::Create( + LocalFrameView& frame_view) { + // Only run the mobile friendliness checker for the outermost main + // frame. The checker will iterate through all local frames in the + // current blink::Page. Also skip the mobile friendliness checks for + // "non-ordinary" pages by checking IsLocalFrameClientImpl(), since + // it's not useful to generate mobile friendliness metrics for + // devtools, svg, etc. + if (!frame_view.GetFrame().Client()->IsLocalFrameClientImpl() || + !frame_view.GetFrame().IsOutermostMainFrame() || + !frame_view.GetPage()->GetSettings().GetViewportEnabled() || + !frame_view.GetPage()->GetSettings().GetViewportMetaEnabled()) { + return nullptr; + } + return MakeGarbageCollected<MobileFriendlinessChecker>(frame_view); +} + MobileFriendlinessChecker* MobileFriendlinessChecker::From( const Document& document) { DCHECK(document.GetFrame());
diff --git a/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker.h b/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker.h index 933fa67..d309be4 100644 --- a/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker.h +++ b/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker.h
@@ -29,6 +29,7 @@ public: explicit MobileFriendlinessChecker(LocalFrameView& frame_view); virtual ~MobileFriendlinessChecker(); + static MobileFriendlinessChecker* Create(LocalFrameView& frame_view); static MobileFriendlinessChecker* From(const Document&); // LocalFrameView::LifecycleNotificationObserver implementation
diff --git a/third_party/blink/renderer/core/paint/scoped_paint_state.cc b/third_party/blink/renderer/core/paint/scoped_paint_state.cc index 8d151d8a..04e3a902 100644 --- a/third_party/blink/renderer/core/paint/scoped_paint_state.cc +++ b/third_party/blink/renderer/core/paint/scoped_paint_state.cc
@@ -145,15 +145,16 @@ if (input_paint_info_.phase == PaintPhase::kForeground) { // We treat horizontal-scrollable scrollers like replaced objects. if (auto* scrollable_area = box.GetScrollableArea()) { - if (scrollable_area->HasHorizontalScrollbar()) { - if (auto* mf_checker = - MobileFriendlinessChecker::From(box.GetDocument())) { - PhysicalRect content_rect = box.LocalVisualRect(); - content_rect.Move(paint_offset_); - content_rect.Intersect( - PhysicalRect(input_paint_info_.GetCullRect().Rect())); - mf_checker->NotifyPaintReplaced(content_rect); - mf_ignore_scope_.emplace(*mf_checker); + if (scrollable_area->MaximumScrollOffset().x() > 0) { + if (!box.IsLayoutView()) { + if (auto* mf_checker = + MobileFriendlinessChecker::From(box.GetDocument())) { + PhysicalRect content_rect = box.OverflowClipRect(paint_offset_); + content_rect.Intersect( + PhysicalRect(input_paint_info_.GetCullRect().Rect())); + mf_checker->NotifyPaintReplaced(content_rect); + mf_ignore_scope_.emplace(*mf_checker); + } } } }
diff --git a/third_party/blink/renderer/modules/manifest/manifest_parser.cc b/third_party/blink/renderer/modules/manifest/manifest_parser.cc index 87d653a..708add0 100644 --- a/third_party/blink/renderer/modules/manifest/manifest_parser.cc +++ b/third_party/blink/renderer/modules/manifest/manifest_parser.cc
@@ -17,6 +17,7 @@ #include "third_party/blink/public/common/permissions_policy/permissions_policy.h" #include "third_party/blink/public/common/security/protocol_handler_security_level.h" #include "third_party/blink/public/mojom/manifest/manifest.mojom-blink-forward.h" +#include "third_party/blink/public/mojom/manifest/manifest.mojom-blink.h" #include "third_party/blink/public/mojom/permissions_policy/permissions_policy.mojom-blink.h" #include "third_party/blink/public/platform/url_conversion.h" #include "third_party/blink/public/platform/web_icon_sizes_parser.h" @@ -26,6 +27,7 @@ #include "third_party/blink/renderer/modules/manifest/manifest_uma_util.h" #include "third_party/blink/renderer/modules/navigatorcontentutils/navigator_content_utils.h" #include "third_party/blink/renderer/platform/json/json_parser.h" +#include "third_party/blink/renderer/platform/json/json_values.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" #include "third_party/blink/renderer/platform/weborigin/kurl.h" #include "third_party/blink/renderer/platform/weborigin/security_origin.h" @@ -661,19 +663,69 @@ return purposes; } -Vector<mojom::blink::ManifestImageResourcePtr> ManifestParser::ParseIcons( - const JSONObject* object) { - return ParseImageResource("icons", object); +mojom::blink::ManifestScreenshot::Platform +ManifestParser::ParseScreenshotPlatform(const JSONObject* screenshot) { + absl::optional<String> platform_str = + ParseString(screenshot, "platform", Trim(false)); + + if (!platform_str.has_value()) { + return mojom::blink::ManifestScreenshot::Platform::kUnknown; + } + + String platform = platform_str.value(); + + if (EqualIgnoringASCIICase(platform, "wide")) { + return mojom::blink::ManifestScreenshot::Platform::kWide; + } else if (EqualIgnoringASCIICase(platform, "narrow")) { + return mojom::blink::ManifestScreenshot::Platform::kNarrow; + } + + AddErrorInfo( + "property 'platform' on screenshots has an invalid value, ignoring it."); + + return mojom::blink::ManifestScreenshot::Platform::kUnknown; } -Vector<mojom::blink::ManifestImageResourcePtr> ManifestParser::ParseScreenshots( +Vector<mojom::blink::ManifestImageResourcePtr> ManifestParser::ParseIcons( const JSONObject* object) { - return ParseImageResource("screenshots", object); + return ParseImageResourceArray("icons", object); +} + +Vector<mojom::blink::ManifestScreenshotPtr> ManifestParser::ParseScreenshots( + const JSONObject* object) { + Vector<mojom::blink::ManifestScreenshotPtr> screenshots; + JSONValue* json_value = object->Get("screenshots"); + if (!json_value) + return screenshots; + + JSONArray* screenshots_list = object->GetArray("screenshots"); + if (!screenshots_list) { + AddErrorInfo("property 'screenshots' ignored, type array expected."); + return screenshots; + } + + for (wtf_size_t i = 0; i < screenshots_list->size(); ++i) { + JSONObject* screenshot_object = JSONObject::Cast(screenshots_list->at(i)); + if (!screenshot_object) + continue; + + auto screenshot = mojom::blink::ManifestScreenshot::New(); + auto image = ParseImageResource(screenshot_object); + if (!image.has_value()) + continue; + + screenshot->image = std::move(*image); + screenshot->platform = ParseScreenshotPlatform(screenshot_object); + + screenshots.push_back(std::move(screenshot)); + } + + return screenshots; } Vector<mojom::blink::ManifestImageResourcePtr> -ManifestParser::ParseImageResource(const String& key, - const JSONObject* object) { +ManifestParser::ParseImageResourceArray(const String& key, + const JSONObject* object) { Vector<mojom::blink::ManifestImageResourcePtr> icons; JSONValue* json_value = object->Get(key); if (!json_value) @@ -686,30 +738,36 @@ } for (wtf_size_t i = 0; i < icons_list->size(); ++i) { - JSONObject* icon_object = JSONObject::Cast(icons_list->at(i)); - if (!icon_object) - continue; - - auto icon = mojom::blink::ManifestImageResource::New(); - icon->src = ParseIconSrc(icon_object); - // An icon MUST have a valid src. If it does not, it MUST be ignored. - if (!icon->src.IsValid()) - continue; - - icon->type = ParseIconType(icon_object); - icon->sizes = ParseIconSizes(icon_object); - auto purpose = ParseIconPurpose(icon_object); - if (!purpose) - continue; - - icon->purpose = std::move(*purpose); - - icons.push_back(std::move(icon)); + auto icon = ParseImageResource(icons_list->at(i)); + if (icon.has_value()) + icons.push_back(std::move(*icon)); } return icons; } +absl::optional<mojom::blink::ManifestImageResourcePtr> +ManifestParser::ParseImageResource(const JSONValue* object) { + const JSONObject* icon_object = JSONObject::Cast(object); + if (!icon_object) + return absl::nullopt; + + auto icon = mojom::blink::ManifestImageResource::New(); + icon->src = ParseIconSrc(icon_object); + // An icon MUST have a valid src. If it does not, it MUST be ignored. + if (!icon->src.IsValid()) + return absl::nullopt; + + icon->type = ParseIconType(icon_object); + icon->sizes = ParseIconSizes(icon_object); + auto purpose = ParseIconPurpose(icon_object); + if (!purpose) + return absl::nullopt; + + icon->purpose = std::move(*purpose); + return icon; +} + String ManifestParser::ParseShortcutName(const JSONObject* shortcut) { absl::optional<String> name = ParseStringForMember(shortcut, "shortcut", "name", true, Trim(true));
diff --git a/third_party/blink/renderer/modules/manifest/manifest_parser.h b/third_party/blink/renderer/modules/manifest/manifest_parser.h index 1ca975f..92e786cc 100644 --- a/third_party/blink/renderer/modules/manifest/manifest_parser.h +++ b/third_party/blink/renderer/modules/manifest/manifest_parser.h
@@ -10,6 +10,7 @@ #include "base/types/strong_alias.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/public/common/permissions_policy/permissions_policy.h" +#include "third_party/blink/public/mojom/manifest/manifest.mojom-blink-forward.h" #include "third_party/blink/public/mojom/manifest/manifest.mojom-blink.h" #include "third_party/blink/public/mojom/permissions_policy/permissions_policy.mojom-blink.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" @@ -216,17 +217,25 @@ const JSONObject* object); // Parses the 'screenshots' field of a Manifest, as defined in: - // https://w3c.github.io/manifest/#screenshots-member + // https://www.w3.org/TR/manifest-app-info/#screenshots-member // Returns a vector of ManifestImageResourcePtr with the successfully parsed // screenshots, if any. An empty vector if the field was not present or empty. - Vector<mojom::blink::ManifestImageResourcePtr> ParseScreenshots( + Vector<mojom::blink::ManifestScreenshotPtr> ParseScreenshots( const JSONObject* object); + // Parse the 'platform' field of 'screenshots' as defined in: + // https://www.w3.org/TR/manifest-app-info/#platform-member + mojom::blink::ManifestScreenshot::Platform ParseScreenshotPlatform( + const JSONObject* screenshot); + // A helper function for parsing ImageResources under |key| in the manifest. - Vector<mojom::blink::ManifestImageResourcePtr> ParseImageResource( + Vector<mojom::blink::ManifestImageResourcePtr> ParseImageResourceArray( const String& key, const JSONObject* object); + absl::optional<mojom::blink::ManifestImageResourcePtr> ParseImageResource( + const JSONValue* object); + // Parses the 'name' field of a shortcut, as defined in: // https://w3c.github.io/manifest/#shortcuts-member // Returns the parsed string if any, a null string if the parsing failed.
diff --git a/third_party/blink/renderer/modules/manifest/manifest_parser_unittest.cc b/third_party/blink/renderer/modules/manifest/manifest_parser_unittest.cc index 40d9d85..ac634104 100644 --- a/third_party/blink/renderer/modules/manifest/manifest_parser_unittest.cc +++ b/third_party/blink/renderer/modules/manifest/manifest_parser_unittest.cc
@@ -13,6 +13,7 @@ #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/public/common/features.h" #include "third_party/blink/public/common/permissions_policy/permissions_policy.h" +#include "third_party/blink/public/mojom/manifest/manifest.mojom-blink.h" #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h" #include "third_party/blink/renderer/platform/weborigin/kurl.h" #include "third_party/blink/renderer/platform/weborigin/security_origin.h" @@ -1147,7 +1148,8 @@ auto& screenshots = manifest->screenshots; EXPECT_EQ(screenshots.size(), 1u); - EXPECT_EQ(screenshots[0]->src.GetString(), "http://foo.com/manifest.json"); + EXPECT_EQ(screenshots[0]->image->src.GetString(), + "http://foo.com/manifest.json"); EXPECT_FALSE(IsManifestEmpty(manifest)); EXPECT_EQ(0u, GetErrorCount()); } @@ -1160,12 +1162,70 @@ auto& screenshots = manifest->screenshots; EXPECT_EQ(screenshots.size(), 1u); - EXPECT_EQ(screenshots[0]->src.GetString(), "http://foo.com/foo.jpg"); + EXPECT_EQ(screenshots[0]->image->src.GetString(), "http://foo.com/foo.jpg"); EXPECT_FALSE(IsManifestEmpty(manifest)); EXPECT_EQ(0u, GetErrorCount()); } } +TEST_F(ManifestParserTest, ScreenshotPlatformParseRules) { + // Smoke test. + { + auto& manifest = ParseManifest( + R"({ "screenshots": [{ "src": "foo.jpg", "platform": "narrow" }] })"); + EXPECT_FALSE(manifest->screenshots.IsEmpty()); + + auto& screenshots = manifest->screenshots; + EXPECT_EQ(screenshots.size(), 1u); + EXPECT_EQ(screenshots[0]->platform, + mojom::blink::ManifestScreenshot::Platform::kNarrow); + EXPECT_FALSE(IsManifestEmpty(manifest)); + EXPECT_EQ(0u, GetErrorCount()); + } + + // Unspecified. + { + auto& manifest = + ParseManifest(R"({ "screenshots": [{ "src": "foo.jpg"}] })"); + EXPECT_FALSE(manifest->screenshots.IsEmpty()); + + auto& screenshots = manifest->screenshots; + EXPECT_EQ(screenshots.size(), 1u); + EXPECT_EQ(screenshots[0]->platform, + mojom::blink::ManifestScreenshot::Platform::kUnknown); + EXPECT_FALSE(IsManifestEmpty(manifest)); + EXPECT_EQ(0u, GetErrorCount()); + } + + // Invalid type. + { + auto& manifest = ParseManifest( + R"({ "screenshots": [{ "src": "foo.jpg", "platform": 1}] })"); + EXPECT_FALSE(manifest->screenshots.IsEmpty()); + + auto& screenshots = manifest->screenshots; + EXPECT_EQ(screenshots.size(), 1u); + EXPECT_EQ(screenshots[0]->platform, + mojom::blink::ManifestScreenshot::Platform::kUnknown); + EXPECT_FALSE(IsManifestEmpty(manifest)); + EXPECT_EQ(1u, GetErrorCount()); + } + + // Unrecognized string. + { + auto& manifest = ParseManifest( + R"({ "screenshots": [{ "src": "foo.jpg", "platform": "windows"}] })"); + EXPECT_FALSE(manifest->screenshots.IsEmpty()); + + auto& screenshots = manifest->screenshots; + EXPECT_EQ(screenshots.size(), 1u); + EXPECT_EQ(screenshots[0]->platform, + mojom::blink::ManifestScreenshot::Platform::kUnknown); + EXPECT_FALSE(IsManifestEmpty(manifest)); + EXPECT_EQ(1u, GetErrorCount()); + } +} + TEST_F(ManifestParserTest, IconSrcParseRules) { // Smoke test. {
diff --git a/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_transform_cache.cc b/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_transform_cache.cc index b8661f7..61ee04e0 100644 --- a/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_transform_cache.cc +++ b/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_transform_cache.cc
@@ -47,6 +47,9 @@ has_sticky_ = node.RequiresCompositingForStickyPosition() || parent.has_sticky_; + is_backface_hidden_ = + node.IsBackfaceHiddenInternal(parent.is_backface_hidden_); + nearest_scroll_translation_ = node.ScrollNode() ? &node : parent.nearest_scroll_translation_;
diff --git a/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_transform_cache.h b/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_transform_cache.h index 23d5dfe..ac26d1a 100644 --- a/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_transform_cache.h +++ b/third_party/blink/renderer/platform/graphics/paint/geometry_mapper_transform_cache.h
@@ -118,6 +118,8 @@ bool has_fixed() const { return has_fixed_; } bool has_sticky() const { return has_sticky_; } + bool is_backface_hidden() const { return is_backface_hidden_; } + const TransformPaintPropertyNode& nearest_scroll_translation() const { DCHECK(nearest_scroll_translation_); return *nearest_scroll_translation_; @@ -224,6 +226,8 @@ // Whether or not there is a sticky translation to the root. bool has_sticky_ = false; + bool is_backface_hidden_ = false; + const TransformPaintPropertyNode* nearest_scroll_translation_ = nullptr; const TransformPaintPropertyNode* nearest_directly_composited_ancestor_ = nullptr;
diff --git a/third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.h b/third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.h index d001b15..0717a03c 100644 --- a/third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.h +++ b/third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.h
@@ -320,6 +320,10 @@ return state_.backface_visibility; } + bool IsBackfaceHidden() const { + return GetTransformCache().is_backface_hidden(); + } + // Returns true if the backface visibility for this node is the same as that // of its parent. This will be true for the Root node. bool BackfaceVisibilitySameAsParent() const { @@ -342,19 +346,6 @@ Parent()->Unalias().state_.flags.flattens_inherited_transform; } - // Returns the first non-inherited BackefaceVisibility value along the - // transform node ancestor chain, including this node's value if it is - // non-inherited. TODO(wangxianzhu): Let PaintPropertyTreeBuilder calculate - // the value instead of walking up the tree. - bool IsBackfaceHidden() const { - const auto* node = this; - while (node && - node->state_.backface_visibility == BackfaceVisibility::kInherited) - node = node->UnaliasedParent(); - return node && - node->state_.backface_visibility == BackfaceVisibility::kHidden; - } - bool HasDirectCompositingReasons() const { return DirectCompositingReasons() != CompositingReason::kNone; } @@ -452,6 +443,12 @@ return state_.direct_compositing_reasons; } + bool IsBackfaceHiddenInternal(bool parent_backface_hidden) const { + if (state_.backface_visibility == BackfaceVisibility::kInherited) + return parent_backface_hidden; + return state_.backface_visibility == BackfaceVisibility::kHidden; + } + void Validate() const { #if DCHECK_IS_ON() if (state_.scroll) {
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index 374f441..8843256 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -1171,6 +1171,10 @@ status: "stable", }, { + name: "HighlightPointerEvents", + depends_on: ["HighlightAPI"], + }, + { name: "HrefTranslate", depends_on: ["TranslateService"], origin_trial_feature_name: "HrefTranslate",
diff --git a/third_party/blink/tools/build_wpt_metadata.py b/third_party/blink/tools/build_wpt_metadata.py index ff70a9e..da54577 100755 --- a/third_party/blink/tools/build_wpt_metadata.py +++ b/third_party/blink/tools/build_wpt_metadata.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env vpython +#!/usr/bin/env vpython3 # Copyright 2019 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file.
diff --git a/third_party/blink/tools/check_testharness_expected_pass.py b/third_party/blink/tools/check_testharness_expected_pass.py index fc64df7..7664046 100755 --- a/third_party/blink/tools/check_testharness_expected_pass.py +++ b/third_party/blink/tools/check_testharness_expected_pass.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env vpython +#!/usr/bin/env vpython3 # # Copyright 2014 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be
diff --git a/third_party/blink/tools/compile_devtools_frontend.py b/third_party/blink/tools/compile_devtools_frontend.py index 5589d451..bc3a9b97 100755 --- a/third_party/blink/tools/compile_devtools_frontend.py +++ b/third_party/blink/tools/compile_devtools_frontend.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env vpython +#!/usr/bin/env vpython3 # Copyright 2017 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file.
diff --git a/third_party/blink/tools/diff_wpt_results.py b/third_party/blink/tools/diff_wpt_results.py index 2f9a366..6ad5187d 100755 --- a/third_party/blink/tools/diff_wpt_results.py +++ b/third_party/blink/tools/diff_wpt_results.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env vpython +#!/usr/bin/env vpython3 # Copyright (C) 2021 Google Inc. All rights reserved. #
diff --git a/third_party/blink/tools/diff_wpt_results_unittest.py b/third_party/blink/tools/diff_wpt_results_unittest.py index 48a3e7d..0d46473 100755 --- a/third_party/blink/tools/diff_wpt_results_unittest.py +++ b/third_party/blink/tools/diff_wpt_results_unittest.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env vpython +#!/usr/bin/env vpython3 # Copyright (C) 2021 Google Inc. All rights reserved. #
diff --git a/third_party/blink/tools/merge_web_test_results.py b/third_party/blink/tools/merge_web_test_results.py index c9f542b..0702d67 100755 --- a/third_party/blink/tools/merge_web_test_results.py +++ b/third_party/blink/tools/merge_web_test_results.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env vpython +#!/usr/bin/env vpython3 # # Copyright 2017 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be
diff --git a/third_party/blink/tools/print_stale_test_expectations_entries.py b/third_party/blink/tools/print_stale_test_expectations_entries.py index 9870a4a..141184e 100755 --- a/third_party/blink/tools/print_stale_test_expectations_entries.py +++ b/third_party/blink/tools/print_stale_test_expectations_entries.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env vpython +#!/usr/bin/env vpython3 # # Copyright (C) 2013 Google Inc. All rights reserved. # @@ -33,9 +33,9 @@ import datetime import json import optparse -import StringIO +from six import StringIO import sys -import urllib2 +from six.moves import urllib from blinkpy.common.host import Host from blinkpy.web_tests.models.test_expectations import TestExpectationParser @@ -105,22 +105,23 @@ self.populate_bug_info(bug_link, test_name) # Return the stale bug's information. if all(self.is_stale(bug_link) for bug_link in bug_links): - print line.original_string.strip() + print(line.original_string.strip()) return [ bug_links[0], self.bug_info[bug_links[0]].filename, self.bug_info[bug_links[0]].days_since_last_update, self.bug_info[bug_links[0]].owner, self.bug_info[bug_links[0]].status ] - except urllib2.HTTPError as error: + except urllib.error.HTTPError as error: if error.code == 404: message = 'got 404, bug does not exist.' elif error.code == 403: message = 'got 403, not accessible. Not able to tell if it\'s stale.' else: message = str(error) - print >> sys.stderr, 'Error when checking %s: %s' % ( - ','.join(bug_links), message) + print( + 'Error when checking %s: %s' % (','.join(bug_links), message), + sys.stderr) return None def populate_bug_info(self, bug_link, test_name): @@ -129,7 +130,7 @@ # In case there's an error in the request, don't make the same request again. bug_number = bug_link.strip(CRBUG_PREFIX) url = GOOGLE_CODE_URL % bug_number - response = urllib2.urlopen(url) + response = urllib.urlopen(url) parsed = json.loads(response.read()) parsed_time = datetime.datetime.strptime( parsed['updated'].split(".")[0] + "UTC", "%Y-%m-%dT%H:%M:%S%Z")
diff --git a/third_party/blink/tools/read_checksum_from_png.py b/third_party/blink/tools/read_checksum_from_png.py index fe972610..448a542 100755 --- a/third_party/blink/tools/read_checksum_from_png.py +++ b/third_party/blink/tools/read_checksum_from_png.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env vpython +#!/usr/bin/env vpython3 # Copyright (c) 2011 Google Inc. All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -34,6 +34,6 @@ if '__main__' == __name__: for filename in sys.argv[1:]: - with open(filename, 'r') as filehandle: - print "%s: %s" % (read_checksum_from_png.read_checksum(filehandle), - filename) + with open(filename, 'rb') as filehandle: + print("%s: %s" % + (read_checksum_from_png.read_checksum(filehandle), filename))
diff --git a/third_party/blink/tools/run_bindings_tests.py b/third_party/blink/tools/run_bindings_tests.py index 003d6d4..3dcc27d 100755 --- a/third_party/blink/tools/run_bindings_tests.py +++ b/third_party/blink/tools/run_bindings_tests.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env vpython +#!/usr/bin/env vpython3 # Copyright (C) 2010 Google Inc. All rights reserved. # # Redistribution and use in source and binary forms, with or without
diff --git a/third_party/blink/tools/run_blink_httpd.py b/third_party/blink/tools/run_blink_httpd.py index eae1ddb7..f3610de 100755 --- a/third_party/blink/tools/run_blink_httpd.py +++ b/third_party/blink/tools/run_blink_httpd.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env vpython +#!/usr/bin/env vpython3 # Copyright (C) 2010 Google Inc. All rights reserved. # # Redistribution and use in source and binary forms, with or without
diff --git a/third_party/blink/tools/run_blink_websocketserver.py b/third_party/blink/tools/run_blink_websocketserver.py index ba0d9f7..25a9f614 100755 --- a/third_party/blink/tools/run_blink_websocketserver.py +++ b/third_party/blink/tools/run_blink_websocketserver.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env vpython +#!/usr/bin/env vpython3 # Copyright (C) 2012 Google Inc. All rights reserved. # # Redistribution and use in source and binary forms, with or without
diff --git a/third_party/blink/tools/try_flag.py b/third_party/blink/tools/try_flag.py index fa2594a8..b6a1411 100755 --- a/third_party/blink/tools/try_flag.py +++ b/third_party/blink/tools/try_flag.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env vpython +#!/usr/bin/env vpython3 # Copyright 2017 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file.
diff --git a/third_party/blink/tools/update_expectations.py b/third_party/blink/tools/update_expectations.py index 9294f8acd..69e9b3c 100755 --- a/third_party/blink/tools/update_expectations.py +++ b/third_party/blink/tools/update_expectations.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env vpython +#!/usr/bin/env vpython3 # # Copyright 2016 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be
diff --git a/third_party/blink/tools/wpt_cleanup.py b/third_party/blink/tools/wpt_cleanup.py index d00af8e6..d0b7c4c 100755 --- a/third_party/blink/tools/wpt_cleanup.py +++ b/third_party/blink/tools/wpt_cleanup.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env vpython +#!/usr/bin/env vpython3 # Copyright 2017 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file.
diff --git a/third_party/blink/tools/wpt_update_expectations.py b/third_party/blink/tools/wpt_update_expectations.py index 3acac28d..0db81d83 100755 --- a/third_party/blink/tools/wpt_update_expectations.py +++ b/third_party/blink/tools/wpt_update_expectations.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env vpython +#!/usr/bin/env vpython3 # Copyright 2016 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file.
diff --git a/third_party/blink/web_tests/FlagExpectations/disable-site-isolation-trials b/third_party/blink/web_tests/FlagExpectations/disable-site-isolation-trials index 25ff7619..f385e117 100644 --- a/third_party/blink/web_tests/FlagExpectations/disable-site-isolation-trials +++ b/third_party/blink/web_tests/FlagExpectations/disable-site-isolation-trials
@@ -33,6 +33,7 @@ http/tests/inspector-protocol/target/target-setAutoAttach-oopif-multisession-wait.js [ Skip ] http/tests/inspector-protocol/target/auto-attach-sub-sub-frame.js [ Skip ] http/tests/inspector-protocol/target/message-to-detached-session.js [ Skip ] +http/tests/inspector-protocol/target/tab-target.js [ Skip ] http/tests/inspector-protocol/target/target-filter.js [ Skip ] virtual/fenced-frame-mparch/http/tests/inspector-protocol/fenced-frame/fenced-frame-in-oopif-auto-attach.js [ Skip ]
diff --git a/third_party/blink/web_tests/external/wpt/css/css-tables/border-collapse-dynamic-oof.html b/third_party/blink/web_tests/external/wpt/css/css-tables/border-collapse-dynamic-oof.html new file mode 100644 index 0000000..6699fba --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-tables/border-collapse-dynamic-oof.html
@@ -0,0 +1,15 @@ +<!DOCTYPE html> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1348154"> +<link rel="match" href="../reference/ref-filled-green-100px-square.xht"> +<p>Test passes if there is a filled green square and <strong>no red</strong>.</p> +<div style="width: 100px; height: 100px; background: red;"> + <div style="display: table; border-collapse: collapse; border: solid green 50px; width: 0; height: 0;"> + <div style="display: table-cell; position: relative;"> + <div id="target" style="position: absolute;"></div> + </div> + </div> +</div> +<script> +document.body.offsetTop; +document.getElementById('target').style.top = '10px'; +</script>
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/resources/inspector-protocol-test.js b/third_party/blink/web_tests/http/tests/inspector-protocol/resources/inspector-protocol-test.js index 6ee6693..832fff629 100644 --- a/third_party/blink/web_tests/http/tests/inspector-protocol/resources/inspector-protocol-test.js +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/resources/inspector-protocol-test.js
@@ -185,6 +185,10 @@ }) }; + browserSession() { + return this._browserSession; + } + browserP() { return this._browserSession.protocol; }
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/target/tab-target.js b/third_party/blink/web_tests/http/tests/inspector-protocol/target/tab-target.js new file mode 100644 index 0000000..d25a6a73 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/target/tab-target.js
@@ -0,0 +1,45 @@ +(async function(testRunner) { + const pageURL = 'http://127.0.0.1:8000/inspector-protocol/resources/inspector-protocol-page.html'; + const {session, dp} = await testRunner.startURL(pageURL, + 'Tests basic functionality of tab target.'); + + const bp = testRunner.browserP(); + const {targetInfos} = (await bp.Target.getTargets({filter: [{type: "tab"}]})).result; + const tabTargets = targetInfos.sort((a, b) => a.url.localeCompare(b.url)); + testRunner.log(tabTargets); + const targetUnderTest = tabTargets.find(target => target.url === pageURL); + + const tabSessionId = (await bp.Target.attachToTarget({targetId: targetUnderTest.targetId, flatten: true})).result.sessionId; + const tabSession = testRunner.browserSession().createChild(tabSessionId); + const tp = tabSession.protocol; + const tabTargetInfo = (await tp.Target.getTargetInfo()); + testRunner.log(tabTargetInfo, "Tab target info, as obtained from target"); + + const autoAttachCompletePromise = tp.Target.setAutoAttach({autoAttach: true, waitForDebuggerOnStart: false, flatten: true}); + const autoAttachedTargets = []; + tp.Target.onAttachedToTarget(target => { + autoAttachedTargets.push(target.params); + }); + // All auto-attaches should be complete before we return. + await autoAttachCompletePromise; + testRunner.log(autoAttachedTargets, "Auto-attached targets (there should be exactly 1): "); + if (autoAttachedTargets.length !== 1) { + testRunner.completeTest(); + return; + } + const frameSession = tabSession.createChild(autoAttachedTargets[0].sessionId); + testRunner.log(`Attached to page ${await frameSession.evaluate('location.href')}`); + // Now create a cross-process subframe and make sure it only gets attached to the + // frame target, not to the tab one. + await frameSession.protocol.Target.setAutoAttach({autoAttach: true, waitForDebuggerOnStart: false, flatten: true}); + const subframePromise = frameSession.protocol.Target.onceAttachedToTarget(); + await frameSession.evaluateAsync(`new Promise(resolve => { + const frame = document.createElement('iframe'); + frame.src = 'http://devtools.oopif-a.test:8000/inspector-protocol/resources/inspector-protocol-page.html'; + frame.onload = resolve; + document.body.appendChild(frame); + })`); + testRunner.log(await subframePromise, `Auto-attached subframe target`); + testRunner.log(`Number of auto-attached tab sessions (should be 1): ${autoAttachedTargets.length}`); + testRunner.completeTest(); +});
diff --git a/third_party/blink/web_tests/platform/generic/http/tests/inspector-protocol/target/tab-target-expected.txt b/third_party/blink/web_tests/platform/generic/http/tests/inspector-protocol/target/tab-target-expected.txt new file mode 100644 index 0000000..04cb1f5 --- /dev/null +++ b/third_party/blink/web_tests/platform/generic/http/tests/inspector-protocol/target/tab-target-expected.txt
@@ -0,0 +1,71 @@ +Tests basic functionality of tab target. +[ + [0] : { + attached : false + browserContextId : <string> + canAccessOpener : false + targetId : <string> + title : 127.0.0.1:8000/inspector-protocol/resources/inspector-protocol-page.html + type : tab + url : http://127.0.0.1:8000/inspector-protocol/resources/inspector-protocol-page.html + } + [1] : { + attached : false + browserContextId : <string> + canAccessOpener : false + targetId : <string> + title : 127.0.0.1:8000/inspector-protocol/resources/inspector-protocol-test.html?test=http://127.0.0.1:8000/inspector-protocol/target/tab-target.js + type : tab + url : http://127.0.0.1:8000/inspector-protocol/resources/inspector-protocol-test.html?test=http://127.0.0.1:8000/inspector-protocol/target/tab-target.js + } +] +Tab target info, as obtained from target{ + id : <number> + result : { + targetInfo : { + attached : true + browserContextId : <string> + canAccessOpener : false + targetId : <string> + title : 127.0.0.1:8000/inspector-protocol/resources/inspector-protocol-page.html + type : tab + url : http://127.0.0.1:8000/inspector-protocol/resources/inspector-protocol-page.html + } + } + sessionId : <string> +} +Auto-attached targets (there should be exactly 1): [ + [0] : { + sessionId : <string> + targetInfo : { + attached : true + browserContextId : <string> + canAccessOpener : false + targetId : <string> + title : 127.0.0.1:8000/inspector-protocol/resources/inspector-protocol-page.html + type : page + url : http://127.0.0.1:8000/inspector-protocol/resources/inspector-protocol-page.html + } + waitingForDebugger : false + } +] +Attached to page http://127.0.0.1:8000/inspector-protocol/resources/inspector-protocol-page.html +Auto-attached subframe target{ + method : Target.attachedToTarget + params : { + sessionId : <string> + targetInfo : { + attached : true + browserContextId : <string> + canAccessOpener : false + targetId : <string> + title : + type : iframe + url : + } + waitingForDebugger : false + } + sessionId : <string> +} +Number of auto-attached tab sessions (should be 1): 1 +
diff --git a/third_party/blink/web_tests/platform/generic/http/tests/inspector-protocol/target/target-filter-expected.txt b/third_party/blink/web_tests/platform/generic/http/tests/inspector-protocol/target/target-filter-expected.txt index d2a9b2c..0f2e55c 100644 --- a/third_party/blink/web_tests/platform/generic/http/tests/inspector-protocol/target/target-filter-expected.txt +++ b/third_party/blink/web_tests/platform/generic/http/tests/inspector-protocol/target/target-filter-expected.txt
@@ -78,6 +78,24 @@ type : shared_worker url : http://127.0.0.1:8000/inspector-protocol/fetch/resources/shared-worker.js } + [4] : { + attached : false + browserContextId : <string> + canAccessOpener : false + targetId : <string> + title : 127.0.0.1:8000/inspector-protocol/resources/inspector-protocol-test.html?test=http://127.0.0.1:8000/inspector-protocol/target/target-filter.js + type : tab + url : http://127.0.0.1:8000/inspector-protocol/resources/inspector-protocol-test.html?test=http://127.0.0.1:8000/inspector-protocol/target/target-filter.js + } + [5] : { + attached : false + browserContextId : <string> + canAccessOpener : false + targetId : <string> + title : 127.0.0.1:8000/inspector-protocol/resources/inspector-protocol-page.html + type : tab + url : http://127.0.0.1:8000/inspector-protocol/resources/inspector-protocol-page.html + } ] default filter [ [0] : { @@ -172,6 +190,24 @@ type : shared_worker url : http://127.0.0.1:8000/inspector-protocol/fetch/resources/shared-worker.js } + [5] : { + attached : false + browserContextId : <string> + canAccessOpener : false + targetId : <string> + title : 127.0.0.1:8000/inspector-protocol/resources/inspector-protocol-test.html?test=http://127.0.0.1:8000/inspector-protocol/target/target-filter.js + type : tab + url : http://127.0.0.1:8000/inspector-protocol/resources/inspector-protocol-test.html?test=http://127.0.0.1:8000/inspector-protocol/target/target-filter.js + } + [6] : { + attached : false + browserContextId : <string> + canAccessOpener : false + targetId : <string> + title : 127.0.0.1:8000/inspector-protocol/resources/inspector-protocol-page.html + type : tab + url : http://127.0.0.1:8000/inspector-protocol/resources/inspector-protocol-page.html + } ] Discovered targets with type = shared_worker [ [0] : {
diff --git a/third_party/blink/web_tests/wpt_internal/document-transition/event-pseudo-name.html b/third_party/blink/web_tests/wpt_internal/document-transition/event-pseudo-name.html new file mode 100644 index 0000000..325cfcc5 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/document-transition/event-pseudo-name.html
@@ -0,0 +1,53 @@ +<!DOCTYPE html> +<title>Shared transitions: event pseudo name</title> +<link rel="help" href="https://github.com/WICG/shared-element-transitions"> +<link rel="author" href="mailto:vmpstr@chromium.org"> +<link rel="match" href="web-animations-api-ref.html"> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<style> +:root { page-transition-tag: none; } +#first { + background: blue; + width: 100px; + height: 100px; + contain: paint; + page-transition-tag: shared; +} + +html::page-transition-container(*), +html::page-transition-image-wrapper(*), +html::page-transition-incoming-image(*), +html::page-transition-outgoing-image(*) { + animation-duration: 600s; +} + +@keyframes fade-in { + from { opacity: 0; } +} +html::page-transition-image-wrapper(*) { + animation: fade-in 600s both; +} + +</style> +<div id=first></div> +<script> +async_test(t => { + let names = []; + document.documentElement.addEventListener("animationstart", (e) => { + names.push(e.pseudoElement); + if (names.length == 4) { + t.step(() => assert_true(names.includes("::page-transition-container(shared)"))); + t.step(() => assert_true(names.includes("::page-transition-image-wrapper(shared)"))); + t.step(() => assert_true(names.includes("::page-transition-incoming-image(shared)"))); + t.step(() => assert_true(names.includes("::page-transition-outgoing-image(shared)"))); + t.done(); + } + }); + document.createDocumentTransition().start(); +}, "verifies pseudo name includes a tag"); + +</script> +
diff --git a/third_party/nearby/README.chromium b/third_party/nearby/README.chromium index e2e0e09..47871ffe 100644 --- a/third_party/nearby/README.chromium +++ b/third_party/nearby/README.chromium
@@ -1,7 +1,7 @@ Name: Nearby Connections Library Short Name: Nearby URL: https://github.com/google/nearby -Version: a37a7b7a839b1f3c189662af6720b94e3eaa3280 +Version: 0d4964da7babe0a0ae01cd4950c5215dbd7dd8d1 License: Apache 2.0 License File: LICENSE Security Critical: yes
diff --git a/third_party/widevine/cdm/BUILD.gn b/third_party/widevine/cdm/BUILD.gn index be63a99..94d5d07 100644 --- a/third_party/widevine/cdm/BUILD.gn +++ b/third_party/widevine/cdm/BUILD.gn
@@ -12,6 +12,8 @@ import("//media/media_options.gni") import("//third_party/widevine/cdm/widevine.gni") +assert(!bundle_widevine_cdm || (enable_widevine && enable_library_cdms)) + buildflag_header("buildflags") { header = "buildflags.h" @@ -23,13 +25,9 @@ ] } -# No branding, use the default one. -widevine_cdm_version_h_file = "widevine_cdm_version.h" -widevine_cdm_binary_files = [] -widevine_cdm_manifest_and_license_files = [] - # TODO(xhwang): widevine_cdm_version.h is only used in few places. Clean this up # so we don't need to copy it in most cases. +# Also, merge the bundle_widevine_cdm blocks as much as possible. if (bundle_widevine_cdm) { widevine_arch = target_cpu @@ -47,6 +45,9 @@ assert(is_win || is_mac) widevine_cdm_binary_files += [ "${widevine_cdm_root}/${cdm_file_name}.sig" ] } +} else { + # The CDM is not bundled. Use the default file. + widevine_cdm_version_h_file = "widevine_cdm_version.h" } copy("version_h") { @@ -69,18 +70,12 @@ ] } -if (widevine_cdm_manifest_and_license_files != []) { +if (bundle_widevine_cdm) { copy("widevine_cdm_manifest_and_license") { sources = widevine_cdm_manifest_and_license_files outputs = [ "${root_out_dir}/WidevineCdm/{{source_file_part}}" ] } -} else { - group("widevine_cdm_manifest_and_license") { - # NOP - } -} -if (widevine_cdm_binary_files != []) { copy("widevine_cdm_binary") { sources = widevine_cdm_binary_files outputs = [ "${root_out_dir}/${widevine_cdm_path}/{{source_file_part}}" ] @@ -88,27 +83,27 @@ # TODO(jrummell) # 'COPY_PHASE_STRIP': 'NO', } + + group("cdm") { + # Needed at run time by tests, e.g. swarming tests to generate isolate. + # See https://crbug.com/824493 for context. + data_deps = [ + ":widevine_cdm_binary", + ":widevine_cdm_manifest_and_license", + ] + + # Needed at build time e.g. for mac bundle (//chrome:chrome_framework). + public_deps = [ + ":widevine_cdm_binary", + ":widevine_cdm_manifest_and_license", + ] + } } else { - group("widevine_cdm_binary") { + group("cdm") { # NOP } } -group("cdm") { - # Needed at run time by tests, e.g. swarming tests to generate isolate. - # See https://crbug.com/824493 for context. - data_deps = [ - ":widevine_cdm_binary", - ":widevine_cdm_manifest_and_license", - ] - - # Needed at build time e.g. for mac bundle (//chrome:chrome_framework). - public_deps = [ - ":widevine_cdm_binary", - ":widevine_cdm_manifest_and_license", - ] -} - # This target exists for tests to depend on that pulls in a runtime dependency # on the license server. group("widevine_test_license_server") {
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl index 638ce7a..03454f5 100644 --- a/tools/mb/mb_config.pyl +++ b/tools/mb/mb_config.pyl
@@ -585,6 +585,7 @@ 'codesearch-gen-chromium-lacros': 'codesearch_gen_chromium_lacros_bot', 'codesearch-gen-chromium-linux': 'codesearch_gen_chromium_bot', 'codesearch-gen-chromium-mac': 'codesearch_gen_chromium_mac_bot', + 'codesearch-gen-chromium-webview': 'codesearch_gen_chromium_webview_bot', 'codesearch-gen-chromium-win': 'codesearch_gen_chromium_bot', }, @@ -1076,6 +1077,7 @@ 'gen-lacros-try': 'codesearch_gen_chromium_lacros_bot', 'gen-linux-try': 'codesearch_gen_chromium_bot', 'gen-mac-try': 'codesearch_gen_chromium_mac_bot', + 'gen-webview-try': 'codesearch_gen_chromium_webview_bot', 'gen-win-try': 'codesearch_gen_chromium_bot', }, @@ -2385,6 +2387,10 @@ 'codesearch', 'mac', ], + 'codesearch_gen_chromium_webview_bot': [ + 'codesearch', 'android_without_codecs', 'static', 'goma', + ], + 'dawn_tests_asan_release_bot_dcheck_always_on_reclient': [ 'dawn_tests', 'asan', 'release_trybot_minimal_symbols_reclient', ],
diff --git a/tools/mb/mb_config_expectations/chromium.infra.codesearch.json b/tools/mb/mb_config_expectations/chromium.infra.codesearch.json index 4c62306..6f8190a 100644 --- a/tools/mb/mb_config_expectations/chromium.infra.codesearch.json +++ b/tools/mb/mb_config_expectations/chromium.infra.codesearch.json
@@ -76,6 +76,19 @@ "use_goma": true } }, + "codesearch-gen-chromium-webview": { + "gn_args": { + "blink_enable_generated_code_formatting": true, + "clang_use_chrome_plugins": false, + "enable_kythe_annotations": true, + "is_clang": true, + "is_component_build": false, + "is_debug": true, + "symbol_level": 1, + "target_os": "android", + "use_goma": true + } + }, "codesearch-gen-chromium-win": { "gn_args": { "blink_enable_generated_code_formatting": true,
diff --git a/tools/mb/mb_config_expectations/tryserver.chromium.codesearch.json b/tools/mb/mb_config_expectations/tryserver.chromium.codesearch.json index 621a59fc7b..a31fb47 100644 --- a/tools/mb/mb_config_expectations/tryserver.chromium.codesearch.json +++ b/tools/mb/mb_config_expectations/tryserver.chromium.codesearch.json
@@ -76,6 +76,19 @@ "use_goma": true } }, + "gen-webview-try": { + "gn_args": { + "blink_enable_generated_code_formatting": true, + "clang_use_chrome_plugins": false, + "enable_kythe_annotations": true, + "is_clang": true, + "is_component_build": false, + "is_debug": true, + "symbol_level": 1, + "target_os": "android", + "use_goma": true + } + }, "gen-win-try": { "gn_args": { "blink_enable_generated_code_formatting": true,
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 74795981..901f2fc 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -72890,6 +72890,7 @@ <int value="22" label="PAGE_ENTITIES"/> <int value="23" label="HISTORY_CLUSTERS"/> <int value="24" label="THANK_CREATOR_ELIGIBLE"/> + <int value="25" label="IBAN_AUTOFILL_BLOCKED"/> </enum> <enum name="OptOutBlacklistReason"> @@ -73026,6 +73027,7 @@ <int value="103" label="Bluetooth: Pair Device"/> <int value="104" label="Bluetooth: Unpair Device"/> <int value="105" label="Bluetooth: Fast Pair On/Off"/> + <int value="106" label="Bluetooth: Fast Pair Saved Devices"/> <int value="200" label="Set Up MultiDevice"/> <int value="201" label="Verify MultiDevice Setup"/> <int value="202" label="MultiDevice On/Off"/>
diff --git a/tools/metrics/histograms/metadata/feature_engagement/histograms.xml b/tools/metrics/histograms/metadata/feature_engagement/histograms.xml index 1ae8ac7..ba94cdb 100644 --- a/tools/metrics/histograms/metadata/feature_engagement/histograms.xml +++ b/tools/metrics/histograms/metadata/feature_engagement/histograms.xml
@@ -465,6 +465,18 @@ <token key="TutorialID" variants="TutorialID"/> </histogram> +<histogram name="Tutorial{TutorialID}.StartedFromWhatsNewPage" + enum="BooleanSuccess" expires_after="2022-12-31"> + <owner>dpenning@chromium.org</owner> + <owner>dfried@chromium.org</owner> + <summary> + The count of successful starts of the tutorial when {TutorialID} button is + clicked on the whats new page (called by the Tutorial BrowserCommand). A + false value correlates to a failure to start the tutorial. + </summary> + <token key="TutorialID" variants="TutorialID"/> +</histogram> + </histograms> </histogram-configuration>
diff --git a/tools/metrics/histograms/metadata/fingerprint/histograms.xml b/tools/metrics/histograms/metadata/fingerprint/histograms.xml index 3c7103d..ae961496 100644 --- a/tools/metrics/histograms/metadata/fingerprint/histograms.xml +++ b/tools/metrics/histograms/metadata/fingerprint/histograms.xml
@@ -245,6 +245,18 @@ </summary> </histogram> +<histogram name="Fingerprint.Unlock.RecentAttemptsCountBeforeSuccess" + units="attempts" expires_after="2023-04-05"> + <owner>agrandi@google.com</owner> + <owner>chromeos-fingerprint@google.com</owner> + <summary> + Counts the number of recent fingerprint attempts until successful screen + unlock. Recent attempts are defined as happening within 3 seconds from each + others. The goal is to count intentional attempt to unlock the device and + exclude incidental touches of the fingerprint sensor. + </summary> +</histogram> + <histogram name="Fingerprint.Unlock.RecordFormatVersion" enum="FingerprintRecordFormatVersion" expires_after="2023-04-05"> <owner>hesling@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/optimization/histograms.xml b/tools/metrics/histograms/metadata/optimization/histograms.xml index 9317286b..a60a770 100644 --- a/tools/metrics/histograms/metadata/optimization/histograms.xml +++ b/tools/metrics/histograms/metadata/optimization/histograms.xml
@@ -68,6 +68,9 @@ <variant name="HistoryClusters" summary="This optimization provides information for whether a page should be included in a history cluster."/> + <variant name="IBANAutofillBlocked" + summary="This optimization provides information for whether a page + should be blocked for IBAN autofill feature."/> <variant name="LinkPerformance" summary="Provides aggregated performance information for links on the page"/>
diff --git a/tools/metrics/histograms/metadata/safe_browsing/histograms.xml b/tools/metrics/histograms/metadata/safe_browsing/histograms.xml index d8facc1..b82e151 100644 --- a/tools/metrics/histograms/metadata/safe_browsing/histograms.xml +++ b/tools/metrics/histograms/metadata/safe_browsing/histograms.xml
@@ -1989,6 +1989,26 @@ name="SafeBrowsing.TailoredSecurity.SyncPromptEnabledNotificationResult" enum="SafeBrowsingTailoredSecurityNotificationResult" expires_after="2022-12-11"> + <obsolete> + This metric was useful until 2022-07-29, when the experiment for + TailoredSecurityDesktopNotice began and values for NoBrowserAvailable and + NoWebContentsAvailable could also contain results from showing the disabled + modal (due to crbug/1348654). + </obsolete> + <owner>jacastro@chromium.org</owner> + <owner>chrome-counter-abuse-alerts@google.com</owner> + <summary> + Records the result of trying to show the Chrome enhanced protection + opt-in/enabled notification to sync users. It is logged once each time + Chrome is informed that the account level enhanced protection bit has been + enabled. + </summary> +</histogram> + +<histogram + name="SafeBrowsing.TailoredSecurity.SyncPromptEnabledNotificationResult2" + enum="SafeBrowsingTailoredSecurityNotificationResult" + expires_after="2022-12-11"> <owner>jacastro@chromium.org</owner> <owner>chrome-counter-abuse-alerts@google.com</owner> <summary>
diff --git a/tools/perf/chrome-health-presets.yaml b/tools/perf/chrome-health-presets.yaml index 7d1690c..3d0c0c5 100644 --- a/tools/perf/chrome-health-presets.yaml +++ b/tools/perf/chrome-health-presets.yaml
@@ -138,6 +138,17 @@ - android-pixel4-perf stories: - Speedometer2 + speedometer2_pgo: + telemetry_batch_experiment: + - benchmark: speedometer2-chrome-health + configs: + - mac-laptop_low_end-perf-pgo + - mac-m1_mini_2020-perf-pgo + - linux-perf-pgo + - win-10-perf-pgo + - android-pixel4-perf + stories: + - Speedometer2 motionmark: telemetry_batch_experiment: - benchmark: rendering.desktop @@ -182,6 +193,50 @@ - android-pixel4-perf stories: - motionmark_ramp_composite + motionmark_pgo: + telemetry_batch_experiment: + - benchmark: rendering.desktop + configs: + - mac-laptop_low_end-perf-pgo + - mac-m1_mini_2020-perf-pgo + - linux-perf-pgo + - win-10-perf-pgo + stories: + - motionmark_ramp_canvas_arcs + - motionmark_ramp_canvas_lines + - motionmark_ramp_design + - motionmark_ramp_focus + - motionmark_ramp_images + - motionmark_ramp_leaves + - motionmark_ramp_multiply + - motionmark_ramp_paths + - motionmark_ramp_suits + - benchmark: rendering.mobile + configs: + - android-pixel4-perf + stories: + - motionmark_ramp_canvas_arcs + - motionmark_ramp_canvas_lines + - motionmark_ramp_design + - motionmark_ramp_focus + - motionmark_ramp_images + - motionmark_ramp_leaves + - motionmark_ramp_multiply + - motionmark_ramp_paths + - motionmark_ramp_suits + - benchmark: rendering.desktop.notracing + configs: + - mac-laptop_low_end-perf-pgo + - mac-m1_mini_2020-perf-pgo + - linux-perf-pgo + - win-10-perf-pgo + stories: + - motionmark_ramp_composite + - benchmark: rendering.mobile.notracing + configs: + - android-pixel4-perf + stories: + - motionmark_ramp_composite jetstream2: telemetry_batch_experiment: - benchmark: jetstream2 @@ -193,7 +248,7 @@ - android-pixel4-perf stories: - JetStream2 - jetstream2-pgo: + jetstream2_pgo: telemetry_batch_experiment: - benchmark: jetstream2 configs:
diff --git a/tools/perf/chrome-health-run-daily.sh b/tools/perf/chrome-health-run-daily.sh index a9616bb6..54f4be29b 100644 --- a/tools/perf/chrome-health-run-daily.sh +++ b/tools/perf/chrome-health-run-daily.sh
@@ -28,6 +28,6 @@ headOfMain=`git whatchanged --grep="Updating trunk VERSION" --format="%H" -1 | head -n 1` # M vs. M-1 -~/depot_tools/pinpoint experiment-telemetry-start --base-commit=$pinnedReleaseMinusOne --exp-commit=$headOfRelease --presets-file ~/chromium/src/tools/perf/chrome-health-presets.yaml --preset=chrome_health --attempts=40 +~/depot_tools/pinpoint experiment-telemetry-start --base-commit=$pinnedReleaseMinusOne --exp-commit=$headOfRelease --presets-file ~/chromium/src/tools/perf/chrome-health-presets.yaml --preset=chrome_health_pgo --attempts=40 # Main ~/depot_tools/pinpoint experiment-telemetry-start --base-commit=$pinnedMain --exp-commit=$headOfMain --presets-file ~/chromium/src/tools/perf/chrome-health-presets.yaml --preset=chrome_health_pgo --attempts=40 \ No newline at end of file
diff --git a/tools/perf/chrome-health-run-weekly.sh b/tools/perf/chrome-health-run-weekly.sh new file mode 100644 index 0000000..3b536241 --- /dev/null +++ b/tools/perf/chrome-health-run-weekly.sh
@@ -0,0 +1,29 @@ +# Copyright 2022 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +#!/bin/sh + +# BEFORE YOU RUN THIS - In your ~ directory, execute the following. Note - this is named health_chromium so that cd chr<tab> works. +# mkdir health_chromium +# cd health_chromium +# fetch --nohooks chromium + +# Script to run weekly A/A tests + +releaseBranchNo=5112 #M104 + +cd ~/health_chromium/src +git fetch + +# Current release branch +git checkout -b branch_$releaseBranchNo branch-heads/$releaseBranchNo +git checkout -f branch_$releaseBranchNo +git pull +headOfRelease=`git whatchanged --grep="Incrementing VERSION" --format="%H" -1 | head -n 1` +echo $headOfRelease + +# M vs. M-1 +for i in {1..200} +do + ~/depot_tools/pinpoint experiment-telemetry-start --base-commit=$headOfRelease --exp-commit=$headOfRelease --presets-file ~/chromium/src/tools/perf/chrome-health-presets.yaml --preset=speedometer2_pgo --attempts=40; +done \ No newline at end of file
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc index 50c41ed4..d59e1fb 100644 --- a/ui/accessibility/platform/ax_platform_node_win.cc +++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -1023,8 +1023,8 @@ L"document"}; case ax::mojom::Role::kGraphicsObject: - return {UIALocalizationStrategy::kSupply, UIA_PaneControlTypeId, - L"region"}; + return {UIALocalizationStrategy::kSupply, UIA_GroupControlTypeId, + L"group"}; case ax::mojom::Role::kGraphicsSymbol: return {UIALocalizationStrategy::kSupply, UIA_ImageControlTypeId, L"img"};
diff --git a/ui/accessibility/platform/ax_platform_node_win_unittest.cc b/ui/accessibility/platform/ax_platform_node_win_unittest.cc index b4675e5..906bf06 100644 --- a/ui/accessibility/platform/ax_platform_node_win_unittest.cc +++ b/ui/accessibility/platform/ax_platform_node_win_unittest.cc
@@ -5806,7 +5806,12 @@ child6.role = ax::mojom::Role::kDialog; root.child_ids.push_back(child6.id); - Init(root, child1, child2, child3, child4, child5, child6); + AXNodeData child7; + child7.id = 8; + child7.role = ax::mojom::Role::kGraphicsObject; + root.child_ids.push_back(child7.id); + + Init(root, child1, child2, child3, child4, child5, child6, child7); EXPECT_UIA_INT_EQ( QueryInterfaceFromNodeId<IRawElementProviderSimple>(child1.id), @@ -5826,6 +5831,9 @@ EXPECT_UIA_INT_EQ( QueryInterfaceFromNodeId<IRawElementProviderSimple>(child6.id), UIA_ControlTypePropertyId, int{UIA_WindowControlTypeId}); + EXPECT_UIA_INT_EQ( + QueryInterfaceFromNodeId<IRawElementProviderSimple>(child7.id), + UIA_ControlTypePropertyId, int{UIA_GroupControlTypeId}); } TEST_F(AXPlatformNodeWinTest, UIALandmarkType) {
diff --git a/ui/message_center/views/notification_header_view.cc b/ui/message_center/views/notification_header_view.cc index 40de6f8..0f7fd0c 100644 --- a/ui/message_center/views/notification_header_view.cc +++ b/ui/message_center/views/notification_header_view.cc
@@ -276,20 +276,20 @@ summary_text_view_->SetText(l10n_util::GetStringFUTF16Int( IDS_MESSAGE_CENTER_NOTIFICATION_PROGRESS_PERCENTAGE, progress)); has_progress_ = true; - UpdateSummaryTextVisibility(); + UpdateSummaryTextAndTimestampVisibility(); } void NotificationHeaderView::SetSummaryText(const std::u16string& text) { summary_text_view_->SetText(text); has_progress_ = false; - UpdateSummaryTextVisibility(); + UpdateSummaryTextAndTimestampVisibility(); } void NotificationHeaderView::SetOverflowIndicator(int count) { summary_text_view_->SetText(l10n_util::GetStringFUTF16Int( IDS_MESSAGE_CENTER_LIST_NOTIFICATION_HEADER_OVERFLOW_INDICATOR, count)); has_progress_ = false; - UpdateSummaryTextVisibility(); + UpdateSummaryTextAndTimestampVisibility(); } void NotificationHeaderView::GetAccessibleNodeData(ui::AXNodeData* node_data) { @@ -317,7 +317,7 @@ timestamp_view_->SetText(relative_time); timestamp_ = timestamp; - UpdateSummaryTextVisibility(); + UpdateSummaryTextAndTimestampVisibility(); // Unretained is safe as the timer cancels the task on destruction. timestamp_update_timer_.Start( @@ -334,7 +334,7 @@ else timestamp_update_timer_.Stop(); - UpdateSummaryTextVisibility(); + UpdateSummaryTextAndTimestampVisibility(); } void NotificationHeaderView::SetExpandButtonEnabled(bool enabled) { @@ -381,7 +381,7 @@ } void NotificationHeaderView::SetTimestampVisible(bool visible) { - timestamp_divider_->SetVisible(visible); + timestamp_divider_->SetVisible(!is_in_group_child_notification_ && visible); timestamp_view_->SetVisible(visible); } @@ -398,6 +398,20 @@ SetPreferredSize(gfx::Size(kNotificationWidth, kHeaderHeightInAsh)); } +void NotificationHeaderView::SetIsInGroupChildNotification( + bool is_in_group_child_notification) { + if (is_in_group_child_notification_ == is_in_group_child_notification) + return; + is_in_group_child_notification_ = is_in_group_child_notification; + + app_name_view_->SetVisible(!is_in_group_child_notification_); + app_icon_view_->SetVisible(!is_in_ash_notification_ && + !is_in_group_child_notification_); + expand_button_->SetVisible(!is_in_ash_notification_ && + !is_in_group_child_notification_); + UpdateSummaryTextAndTimestampVisibility(); +} + const std::u16string& NotificationHeaderView::app_name_for_testing() const { return app_name_view_->GetText(); } @@ -406,14 +420,14 @@ return app_icon_view_->GetImage(); } -void NotificationHeaderView::UpdateSummaryTextVisibility() { - const bool summary_visible = !summary_text_view_->GetText().empty(); +void NotificationHeaderView::UpdateSummaryTextAndTimestampVisibility() { + const bool summary_visible = !is_in_group_child_notification_ && + !summary_text_view_->GetText().empty(); summary_text_divider_->SetVisible(summary_visible); summary_text_view_->SetVisible(summary_visible); const bool timestamp_visible = !has_progress_ && timestamp_; - timestamp_divider_->SetVisible(timestamp_visible); - timestamp_view_->SetVisible(timestamp_visible); + SetTimestampVisible(timestamp_visible); // TODO(crbug.com/991492): this should not be necessary. detail_views_->InvalidateLayout();
diff --git a/ui/message_center/views/notification_header_view.h b/ui/message_center/views/notification_header_view.h index cb413a96..0d967a0c 100644 --- a/ui/message_center/views/notification_header_view.h +++ b/ui/message_center/views/notification_header_view.h
@@ -79,6 +79,9 @@ void SetIsInAshNotificationView(bool is_in_ash_notification); + // The header only shows timestamp if it is in a group child notification. + void SetIsInGroupChildNotification(bool is_in_group_child_notification); + // views::View: void GetAccessibleNodeData(ui::AXNodeData* node_data) override; void OnThemeChanged() override; @@ -105,9 +108,11 @@ private: FRIEND_TEST_ALL_PREFIXES(NotificationHeaderViewTest, SettingsMode); + FRIEND_TEST_ALL_PREFIXES(NotificationHeaderViewTest, + GroupChildNotificationVisibility); // Update visibility for both |summary_text_view_| and |timestamp_view_|. - void UpdateSummaryTextVisibility(); + void UpdateSummaryTextAndTimestampVisibility(); void UpdateColors(); @@ -134,6 +139,9 @@ // Whether this view is used for an ash notification view. bool is_in_ash_notification_ = false; + + // Whether this view is used for a group child notification. + bool is_in_group_child_notification_ = false; }; BEGIN_VIEW_BUILDER(MESSAGE_CENTER_EXPORT, NotificationHeaderView, views::Button)
diff --git a/ui/message_center/views/notification_header_view_unittest.cc b/ui/message_center/views/notification_header_view_unittest.cc index 935dbb4..c1c61017 100644 --- a/ui/message_center/views/notification_header_view_unittest.cc +++ b/ui/message_center/views/notification_header_view_unittest.cc
@@ -230,6 +230,48 @@ EXPECT_FALSE(notification_header_view->expand_button()->GetVisible()); } +TEST_F(NotificationHeaderViewTest, GroupChildNotificationVisibility) { + notification_header_view_->SetSummaryText(u"summary"); + notification_header_view_->SetTimestamp(base::Time::Now()); + + EXPECT_TRUE( + notification_header_view_->app_icon_view_for_testing()->GetVisible()); + EXPECT_TRUE(notification_header_view_->expand_button()->GetVisible()); + EXPECT_TRUE( + notification_header_view_->summary_text_for_testing()->GetVisible()); + EXPECT_TRUE(notification_header_view_->summary_text_divider_->GetVisible()); + EXPECT_TRUE( + notification_header_view_->timestamp_view_for_testing()->GetVisible()); + EXPECT_TRUE(notification_header_view_->timestamp_divider_->GetVisible()); + + // For group child notification, all the views except `timestamp_view_` should + // not be visible. + notification_header_view_->SetIsInGroupChildNotification( + /*is_in_group_child_notification=*/true); + EXPECT_FALSE( + notification_header_view_->app_icon_view_for_testing()->GetVisible()); + EXPECT_FALSE(notification_header_view_->expand_button()->GetVisible()); + EXPECT_FALSE( + notification_header_view_->summary_text_for_testing()->GetVisible()); + EXPECT_FALSE(notification_header_view_->summary_text_divider_->GetVisible()); + EXPECT_FALSE(notification_header_view_->timestamp_divider_->GetVisible()); + EXPECT_TRUE( + notification_header_view_->timestamp_view_for_testing()->GetVisible()); + + // Switching back. + notification_header_view_->SetIsInGroupChildNotification( + /*is_in_group_child_notification=*/false); + EXPECT_TRUE( + notification_header_view_->app_icon_view_for_testing()->GetVisible()); + EXPECT_TRUE(notification_header_view_->expand_button()->GetVisible()); + EXPECT_TRUE( + notification_header_view_->summary_text_for_testing()->GetVisible()); + EXPECT_TRUE(notification_header_view_->summary_text_divider_->GetVisible()); + EXPECT_TRUE( + notification_header_view_->timestamp_view_for_testing()->GetVisible()); + EXPECT_TRUE(notification_header_view_->timestamp_divider_->GetVisible()); +} + TEST_F(NotificationHeaderViewTest, MetadataTest) { views::test::TestViewMetadata(notification_header_view_); }
diff --git a/ui/webui/resources/cr_components/help_bubble/help_bubble.html b/ui/webui/resources/cr_components/help_bubble/help_bubble.html index a9e48532..4faa986 100644 --- a/ui/webui/resources/cr_components/help_bubble/help_bubble.html +++ b/ui/webui/resources/cr_components/help_bubble/help_bubble.html
@@ -1,48 +1,70 @@ -<style> +<style include="cr-hidden-style"> :host { position: absolute; z-index: 1; } - .arrow { + /* HelpBubblePosition.ABOVE */ + :host([position='0']) { + transform: translateY(-100%); + } + + /* HelpBubblePosition.BELOW */ + :host([position='1']) { + transform: none; + } + + /* HelpBubblePosition.LEFT */ + :host([position='2']) { + transform: translate(-100%, -50%); + } + + /* HelpBubblePosition.RIGHT */ + :host([position='3']) { + transform: translateY(-50%); + } + + #arrow { + --help-bubble-arrow-size: 16px; + --help-bubble-arrow-offset: calc(var(--help-bubble-arrow-size) / 2); background-color: var(--help-bubble-background); - height: 16px; + height: var(--help-bubble-arrow-size); position: absolute; transform: rotate(-45deg); - width: 16px; + width: var(--help-bubble-arrow-size); z-index: -1; } /* Turns the arrow direction downwards, when the bubble is placed above * the anchor element */ - :host([position=above]) .arrow { + #arrow.above { border-bottom-left-radius: 2px; - bottom: -8px; - left: calc(50% - 8px); + bottom: calc(0 - var(--help-bubble-arrow-offset)); + left: calc(50% - var(--help-bubble-arrow-offset)); } /* Turns the arrow direction upwards, when the bubble is placed below * the anchor element */ - :host([position=below]) .arrow { + #arrow.below { border-top-right-radius: 2px; - left: calc(50% - 8px); - top: -8px; + left: calc(50% - var(--help-bubble-arrow-offset)); + top: calc(0 - var(--help-bubble-arrow-offset)); } /* Turns the arrow direction to the right, when the bubble is placed to the * left of the anchor element */ - :host([position=left]) .arrow { + #arrow.left { border-bottom-right-radius: 2px; - right: -8px; - top: calc(50% - 8px); + right: calc(0 - var(--help-bubble-arrow-offset)); + top: calc(50% - var(--help-bubble-arrow-offset)); } /* Turns the arrow direction to the left, when the bubble is placed to the * right of the anchor element */ - :host([position=right]) .arrow { + #arrow.right { border-top-left-radius: 2px; - left: -8px; - top: calc(50% - 8px); + left: calc(0 - var(--help-bubble-arrow-offset)); + top: calc(50% - var(--help-bubble-arrow-offset)); } #topContainer { @@ -50,24 +72,50 @@ display: flex; } - #body { + #progress { + display: inline-block; + flex: auto; + } + + #progress div { + --help-bubble-progress-size: 8px; + border: 1px solid var(--help-bubble-text-color); + border-radius: 50%; + display: inline-block; + height: var(--help-bubble-progress-size); + margin-bottom: var(--help-bubble-element-spacing); + margin-inline-end: var(--help-bubble-element-spacing); + margin-top: 4px; + width: var(--help-bubble-progress-size); + } + + .total-progress { + background-color: var(--help-bubble-text-color); + } + + div.body { flex: auto; font-size: 14px; } - #title { + div.title { flex: auto; font-size: 16px; font-weight: bold; margin-bottom: 8px; } + div.hidden { + display: none; + } + /* Note: help bubbles have the same color treatment in both light and dark * themes, which is why the values below do not change based on theme * preference. */ .help-bubble { --help-bubble-background: var(--google-blue-700); + --help-bubble-element-spacing: 8px; --help-bubble-text-color: var(--google-grey-200); background-color: var(--help-bubble-background); border-radius: 8px; @@ -103,8 +151,8 @@ cr-button { --text-color: var(--help-bubble-text-color); border-color: var(--help-bubble-text-color); - margin-inline-start: 8px; - margin-top: 8px; + margin-inline-start: var(--help-bubble-element-spacing); + margin-top: var(--help-bubble-element-spacing); } cr-button:focus { @@ -127,12 +175,39 @@ <div class="help-bubble"> <div id="topContainer"> <cr-icon-button id="close" iron-icon="cr:close" - aria-label="[[closeText]]" on-click="dismiss_"> + aria-label$="[[closeText]]" on-click="dismiss_"> </cr-icon-button> - <div id="title"></div> - <div id="body"></div> + <div id="progress" hidden$="[[!progress]]"> + <template is="dom-repeat" items="[[progressData_]]"> + <div class$="[[getProgressClass_(index)]]"></div> + </template> + </div> + <div class="title" + hidden$="[[!shouldShowTitleInTopContainer_(progress, titleText)]]"> + [[titleText]] + </div> + <div class="body" + hidden$="[[!shouldShowBodyInTopContainer_(progress, titleText)]]"> + [[bodyText]] + </div> </div> - <div id="main"></div> - <div id="buttons"></div> - <div class="arrow"></div> + <div id="main"> + <div class="title" + hidden$="[[!shouldShowTitleInMain_(progress, titleText)]]"> + [[titleText]] + </div> + <div class="body" + hidden$="[[!shouldShowBodyInMain_(progress, titleText)]]"> + [[bodyText]] + </div> + </div> + <div id="buttons" hidden$="[[!buttons.length]]"> + <template is="dom-repeat" items="[[buttons]]" sort="buttonSortFunc_"> + <cr-button id$="[[getButtonId_(itemsIndex)]]" + tabindex$="[[getButtonTabIndex_(itemsIndex, item.isDefault)]]" + class$="[[getButtonClass_(item.isDefault)]]" + on-click="onButtonClick_">[[item.text]]</cr-button> + </template> + </div> + <div id="arrow" class$="[[getArrowClass_(position)]]"></div> </div>
diff --git a/ui/webui/resources/cr_components/help_bubble/help_bubble.mojom b/ui/webui/resources/cr_components/help_bubble/help_bubble.mojom index c749af0..40c2f18 100644 --- a/ui/webui/resources/cr_components/help_bubble/help_bubble.mojom +++ b/ui/webui/resources/cr_components/help_bubble/help_bubble.mojom
@@ -28,6 +28,12 @@ bool is_default = false; }; +// Progress indicator for tutorial bubbles. +struct Progress { + uint8 current; + uint8 total; +}; + // Simplified version of user_education::HelpBubbleParams. struct HelpBubbleParams { // Holds the name of the ElementIdentifier used to identify the help bubble's @@ -39,6 +45,7 @@ string? title_text; string body_text; string close_button_alt_text; + Progress? progress; array<HelpBubbleButtonParams> buttons; };
diff --git a/ui/webui/resources/cr_components/help_bubble/help_bubble.ts b/ui/webui/resources/cr_components/help_bubble/help_bubble.ts index bc71291..b22443d 100644 --- a/ui/webui/resources/cr_components/help_bubble/help_bubble.ts +++ b/ui/webui/resources/cr_components/help_bubble/help_bubble.ts
@@ -10,17 +10,17 @@ */ import 'chrome://resources/cr_elements/cr_button/cr_button.m.js'; import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.m.js'; +import 'chrome://resources/cr_elements/hidden_style_css.m.js'; import 'chrome://resources/cr_elements/icons.m.js'; import {CrButtonElement} from '//resources/cr_elements/cr_button/cr_button.m.js'; import {CrIconButtonElement} from '//resources/cr_elements/cr_icon_button/cr_icon_button.m.js'; import {assert, assertNotReached} from '//resources/js/assert_ts.js'; import {isWindows} from '//resources/js/cr.m.js'; -import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; -import {EventTracker} from 'chrome://resources/js/event_tracker.m.js'; +import {DomRepeatEvent, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {getTemplate} from './help_bubble.html.js'; -import {HelpBubblePosition} from './help_bubble.mojom-webui.js'; +import {HelpBubbleButtonParams, HelpBubblePosition, Progress} from './help_bubble.mojom-webui.js'; const ANCHOR_HIGHLIGHT_CLASS = 'help-anchor-highlight'; @@ -36,11 +36,11 @@ export interface HelpBubbleElement { $: { - body: HTMLElement, + arrow: HTMLElement, buttons: HTMLElement, close: CrIconButtonElement, main: HTMLElement, - title: HTMLElement, + progress: HTMLElement, topContainer: HTMLElement, }; } @@ -61,7 +61,14 @@ value: '', reflectToAttribute: true, }, + closeText: String, + + position: { + type: HelpBubblePosition, + value: HelpBubblePosition.BELOW, + reflectToAttribute: true, + }, }; } @@ -70,33 +77,30 @@ titleText: string; closeText: string; position: HelpBubblePosition; - buttons: string[] = []; - defaultButtonIndex: number; + buttons: HelpBubbleButtonParams[] = []; + progress: Progress|null = null; /** * HTMLElement corresponding to |this.anchorId|. */ private anchorElement_: HTMLElement|null = null; - private buttonEventTracker_: EventTracker = new EventTracker(); + /** + * Backing data for the dom-repeat that generates progress indicators. + * The elements are placeholders only. + */ + private progressData_: void[] = []; /** * Shows the bubble. */ show() { - // If there is no title, the body element should be in the top container - // with the close button, else it should be in the main container. - if (this.titleText) { - this.$.title.style.display = 'block'; - this.$.title.innerText = this.titleText; - this.$.main.appendChild(this.$.body); + // Set up the progress track. + if (this.progress) { + this.progressData_ = new Array(this.progress.total); } else { - this.$.title.style.display = 'none'; - this.$.topContainer.appendChild(this.$.body); + this.progressData_ = []; } - this.$.body.innerText = this.bodyText; - - this.addButtons_(); this.anchorElement_ = this.parentElement!.querySelector<HTMLElement>(`#${this.anchorId}`)!; @@ -122,7 +126,6 @@ * bubble will go away on hide. */ hide() { - this.removeButtons_(); this.style.display = 'none'; this.setAttribute('aria-hidden', 'true'); this.setAnchorHighlight_(false); @@ -141,12 +144,8 @@ * Returns the button with the given `buttonIndex`, or null if not found. */ getButtonForTesting(buttonIndex: number): CrButtonElement|null { - for (const button of this.$.buttons.children) { - if (button.id === ACTION_BUTTON_ID_PREFIX + buttonIndex) { - return button as CrButtonElement; - } - } - return null; + return this.$.buttons.querySelector<CrButtonElement>( + `[id="${ACTION_BUTTON_ID_PREFIX + buttonIndex}"]`); } /** @@ -167,71 +166,85 @@ })); } - private onButtonClicked_(buttonIndex: number, _e: Event) { + private getProgressClass_(index: number): string { + return index < this.progress!.current ? 'current-progress' : + 'total-progress'; + } + + private shouldShowTitleInTopContainer_( + progress: Progress|null, titleText: string): boolean { + return !!titleText && !progress; + } + + private shouldShowTitleInMain_(progress: Progress|null, titleText: string): + boolean { + return !!titleText && !!progress; + } + + private shouldShowBodyInTopContainer_( + progress: Progress|null, titleText: string): boolean { + return !progress && !titleText; + } + + private shouldShowBodyInMain_(progress: Progress|null, titleText: string): + boolean { + return !!progress || !!titleText; + } + + private onButtonClick_(e: DomRepeatEvent<HelpBubbleButtonParams>) { assert( this.anchorId, 'Action button clicked: expected help bubble to have an anchor.'); + // There is no access to the model index here due to limitations of + // dom-repeat. However, the index is stored in the node's identifier. + const index: number = parseInt( + (e.target as Element).id.substring(ACTION_BUTTON_ID_PREFIX.length)); this.dispatchEvent(new CustomEvent(HELP_BUBBLE_DISMISSED_EVENT, { detail: { anchorId: this.anchorId, fromActionButton: true, - buttonIndex: buttonIndex, + buttonIndex: index, }, })); } - /** - * Removes button elements and listeners, if any are present. - */ - private removeButtons_() { - while (this.$.buttons.firstChild) { - this.buttonEventTracker_.remove(this.$.buttons.firstChild, 'click'); - this.$.buttons.removeChild(this.$.buttons.firstChild); - } + private getButtonId_(index: number): string { + return ACTION_BUTTON_ID_PREFIX + index; } - /** - * Adds any buttons required by `this.buttons` with their on-click listeners. - */ - private addButtons_() { - assert( - !this.$.buttons.firstChild, - 'Add buttons: expected button list to be empty.'); + private getButtonClass_(isDefault: boolean): string { + return isDefault ? 'default-button' : ''; + } - // If there are no buttons to add, hide the container and return. - if (!this.buttons.length) { - return; + private getButtonTabIndex_(index: number, isDefault: boolean): number { + return isDefault ? 1 : index + 2; + } + + private buttonSortFunc_( + button1: HelpBubbleButtonParams, + button2: HelpBubbleButtonParams): number { + // Default button is leading on Windows, trailing on other platforms. + if (button1.isDefault) { + return isWindows ? -1 : 1; } - - let defaultButton: HTMLElement|null = null; - for (let i: number = 0; i < this.buttons.length; ++i) { - const button = document.createElement('cr-button'); - button.innerText = this.buttons[i]; - button.id = ACTION_BUTTON_ID_PREFIX + i; - this.buttonEventTracker_.add( - button, 'click', this.onButtonClicked_.bind(this, i)); - if (i === this.defaultButtonIndex) { - defaultButton = button; - // Default button should always be first in tab order. - button.tabIndex = 1; - button.classList.add('default-button'); - } else { - // Tab index for non-default buttons starts at 2, since default button - // gets 1. - button.tabIndex = i + 2; - this.$.buttons.appendChild(button); - } + if (button2.isDefault) { + return isWindows ? 1 : -1; } + return 0; + } - // Place the default button in the correct order; either leading or - // trailing based on platform. - if (defaultButton) { - if (HelpBubbleElement.isDefaultButtonLeading() && - this.$.buttons.firstChild) { - this.$.buttons.insertBefore(defaultButton, this.$.buttons.firstChild); - } else { - this.$.buttons.appendChild(defaultButton); - } + private getArrowClass_(position: HelpBubblePosition): string { + switch (position) { + case HelpBubblePosition.ABOVE: + return 'above'; + case HelpBubblePosition.BELOW: + return 'below'; + case HelpBubblePosition.LEFT: + return 'left'; + case HelpBubblePosition.RIGHT: + return 'right'; + default: + assertNotReached('Unknown help bubble position: ' + position); } } @@ -244,44 +257,44 @@ this.anchorElement_, 'Update position: expected valid anchor element.'); // Inclusive of 8px visible arrow and 8px margin. - const offset = 16; const parentRect = this.offsetParent!.getBoundingClientRect(); const anchorRect = this.anchorElement_.getBoundingClientRect(); const anchorLeft = anchorRect.left - parentRect.left; + const anchorHorizontalCenter = anchorLeft + anchorRect.width / 2; const anchorTop = anchorRect.top - parentRect.top; + const ARROW_OFFSET = 16; + const LEFT_MARGIN = 8; + const HELP_BUBBLE_WIDTH = 362; let helpLeft: string = ''; let helpTop: string = ''; - let helpTransform: string = ''; switch (this.position) { case HelpBubblePosition.ABOVE: // Anchor the help bubble to the top center of the anchor element. - helpTop = `${anchorTop - offset}px`; - helpLeft = `${anchorLeft + anchorRect.width / 2}px`; - // Horizontally center the help bubble. - helpTransform = 'translate(-50%, -100%)'; + helpTop = `${anchorTop - ARROW_OFFSET}px`; + helpLeft = `${ + Math.max( + LEFT_MARGIN, + anchorHorizontalCenter - HELP_BUBBLE_WIDTH / 2)}px`; break; case HelpBubblePosition.BELOW: // Anchor the help bubble to the bottom center of the anchor element. - helpTop = `${anchorTop + anchorRect.height + offset}px`; - helpLeft = `${anchorLeft + anchorRect.width / 2}px`; - // Horizontally center the help bubble. - helpTransform = 'translateX(-50%)'; + helpTop = `${anchorTop + anchorRect.height + ARROW_OFFSET}px`; + helpLeft = `${ + Math.max( + LEFT_MARGIN, + anchorHorizontalCenter - HELP_BUBBLE_WIDTH / 2)}px`; break; case HelpBubblePosition.LEFT: // Anchor the help bubble to the center left of the anchor element. helpTop = `${anchorTop + anchorRect.height / 2}px`; - helpLeft = `${anchorLeft - offset}px`; - // Vertically center the help bubble. - helpTransform = 'translate(-100%, -50%)'; + helpLeft = `${anchorLeft - ARROW_OFFSET}px`; break; case HelpBubblePosition.RIGHT: // Anchor the help bubble to the center right of the anchor element. helpTop = `${anchorTop + anchorRect.height / 2}px`; - helpLeft = `${anchorLeft + anchorRect.width + offset}px`; - // Vertically center the help bubble. - helpTransform = 'translateY(-50%)'; + helpLeft = `${anchorLeft + anchorRect.width + ARROW_OFFSET}px`; break; default: assertNotReached(); @@ -289,7 +302,6 @@ this.style.top = helpTop; this.style.left = helpLeft; - this.style.transform = helpTransform; } /**
diff --git a/ui/webui/resources/cr_components/help_bubble/help_bubble_mixin.ts b/ui/webui/resources/cr_components/help_bubble/help_bubble_mixin.ts index eae87cea..9aa24dfe1 100644 --- a/ui/webui/resources/cr_components/help_bubble/help_bubble_mixin.ts +++ b/ui/webui/resources/cr_components/help_bubble/help_bubble_mixin.ts
@@ -170,14 +170,11 @@ bubble.position = params.position; bubble.bodyText = params.bodyText; bubble.titleText = params.titleText || ''; - bubble.buttons = []; - bubble.defaultButtonIndex = -1; - for (let i: number = 0; i < params.buttons.length; ++i) { - bubble.buttons.push(params.buttons[i].text); - if (params.buttons[i].isDefault) { - bubble.defaultButtonIndex = i; - } - } + bubble.progress = params.progress || null; + assert( + !bubble.progress || + bubble.progress.total >= bubble.progress.current); + bubble.buttons = params.buttons; bubble.show(); anchor!.focus(); }
diff --git a/ui/webui/resources/cr_elements/BUILD.gn b/ui/webui/resources/cr_elements/BUILD.gn index a4e6150..d23e67e 100644 --- a/ui/webui/resources/cr_elements/BUILD.gn +++ b/ui/webui/resources/cr_elements/BUILD.gn
@@ -193,7 +193,6 @@ "cr_input:closure_compile", "cr_lottie:closure_compile", "cr_radio_button:closure_compile", - "cr_radio_group:closure_compile", "cr_toggle:closure_compile", "policy:closure_compile", @@ -218,6 +217,7 @@ deps += [ "cr_button:closure_compile", "cr_expand_button:closure_compile", + "cr_radio_group:closure_compile", ] } }
diff --git a/ui/webui/resources/cr_elements/cr_radio_group/BUILD.gn b/ui/webui/resources/cr_elements/cr_radio_group/BUILD.gn index b1805b2..6b44fc4 100644 --- a/ui/webui/resources/cr_elements/cr_radio_group/BUILD.gn +++ b/ui/webui/resources/cr_elements/cr_radio_group/BUILD.gn
@@ -2,19 +2,22 @@ # 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("//third_party/closure_compiler/compile_js.gni") import("//tools/polymer/polymer.gni") -js_type_check("closure_compile") { - uses_legacy_modules = true - deps = [ ":cr_radio_group" ] -} +if (is_chromeos_ash) { + js_type_check("closure_compile") { + uses_legacy_modules = true + deps = [ ":cr_radio_group" ] + } -js_library("cr_radio_group") { - deps = [ - "//ui/webui/resources/cr_elements/cr_radio_button:cr_radio_button", - "//ui/webui/resources/js:event_tracker", - ] + js_library("cr_radio_group") { + deps = [ + "//ui/webui/resources/cr_elements/cr_radio_button:cr_radio_button", + "//ui/webui/resources/js:event_tracker", + ] + } } # Targets for auto-generating and typechecking Polymer 3 JS modules
diff --git a/ui/webui/resources/js/BUILD.gn b/ui/webui/resources/js/BUILD.gn index da422c5..233d69a1 100644 --- a/ui/webui/resources/js/BUILD.gn +++ b/ui/webui/resources/js/BUILD.gn
@@ -164,31 +164,34 @@ js_type_check("js_resources") { uses_legacy_modules = true deps = [ - ":action_link", ":assert", ":cr", - ":event_tracker", - ":i18n_template_no_process", ":load_time_data", - ":parse_html_subset", ":promise_resolver", ":util", ":webui_resource_test", ] + if (is_ios) { deps += [ "ios:web_ui" ] } if (is_chromeos_ash) { deps += [ + ":action_link", + ":event_tracker", ":i18n_behavior", + ":i18n_template_no_process", ":list_property_update_behavior", + ":parse_html_subset", ":web_ui_listener_behavior", ] } } -js_library("action_link") { +if (is_chromeos_ash) { + js_library("action_link") { + } } js_library("assert") { @@ -202,15 +205,14 @@ externs_list = [ "$externs_path/chrome_send.js" ] } -js_library("event_tracker") { - deps = [ ":cr" ] -} - -js_library("i18n_template_no_process") { - deps = [ ":load_time_data" ] -} - if (is_chromeos_ash) { + js_library("event_tracker") { + deps = [ ":cr" ] + } + + js_library("i18n_template_no_process") { + deps = [ ":load_time_data" ] + } js_library("i18n_behavior") { deps = [ ":load_time_data", @@ -227,7 +229,9 @@ extra_deps = [ ":unmodulize" ] } -js_library("parse_html_subset") { +if (is_chromeos_ash) { + js_library("parse_html_subset") { + } } js_library("promise_resolver") {